|
| 1 | +# CLI Tools for App Store Server Library |
| 2 | + |
| 3 | +This directory contains command-line tools for interacting with the App Store Server API. |
| 4 | + |
| 5 | +## Retention Message Tool |
| 6 | + |
| 7 | +The `retention_message.py` tool allows you to manage retention messages that can be displayed to users to encourage app re-engagement. |
| 8 | + |
| 9 | +### Prerequisites |
| 10 | + |
| 11 | +1. **App Store Connect Credentials**: You need: |
| 12 | + - Private Key ID (`key_id`) from App Store Connect |
| 13 | + - Issuer ID (`issuer_id`) from App Store Connect |
| 14 | + - Your app's Bundle ID (`bundle_id`) |
| 15 | + - Private key file (`.p8` format) downloaded from App Store Connect |
| 16 | + |
| 17 | +2. **Python Dependencies**: Make sure the app-store-server-library is installed: |
| 18 | + ```bash |
| 19 | + pip install -r ../requirements.txt |
| 20 | + ``` |
| 21 | + |
| 22 | +### Usage |
| 23 | + |
| 24 | +#### Upload a Retention Message |
| 25 | + |
| 26 | +Upload a new retention message with auto-generated ID: |
| 27 | +```bash |
| 28 | +python retention_message.py \ |
| 29 | + --key-id "ABCDEFGHIJ" \ |
| 30 | + --issuer-id "12345678-1234-1234-1234-123456789012" \ |
| 31 | + --bundle-id "com.example.myapp" \ |
| 32 | + --p8-file "/path/to/SubscriptionKey_ABCDEFGHIJ.p8" \ |
| 33 | + --header "Welcome back!" \ |
| 34 | + --body "Check out our new features" |
| 35 | +``` |
| 36 | + |
| 37 | +Upload with a specific message ID: |
| 38 | +```bash |
| 39 | +python retention_message.py \ |
| 40 | + --key-id "ABCDEFGHIJ" \ |
| 41 | + --issuer-id "12345678-1234-1234-1234-123456789012" \ |
| 42 | + --bundle-id "com.example.myapp" \ |
| 43 | + --p8-file "/path/to/key.p8" \ |
| 44 | + --message-id "my-campaign-001" \ |
| 45 | + --header "Limited Time Sale!" \ |
| 46 | + --body "50% off premium features this week" |
| 47 | +``` |
| 48 | + |
| 49 | +Upload with an image: |
| 50 | +```bash |
| 51 | +python retention_message.py \ |
| 52 | + --key-id "ABCDEFGHIJ" \ |
| 53 | + --issuer-id "12345678-1234-1234-1234-123456789012" \ |
| 54 | + --bundle-id "com.example.myapp" \ |
| 55 | + --p8-file "/path/to/key.p8" \ |
| 56 | + --header "New Update!" \ |
| 57 | + --body "Amazing new features await" \ |
| 58 | + --image-id "banner-v2" \ |
| 59 | + --image-alt-text "App update banner showing new features" |
| 60 | +``` |
| 61 | + |
| 62 | +#### List All Messages |
| 63 | + |
| 64 | +```bash |
| 65 | +python retention_message.py \ |
| 66 | + --key-id "ABCDEFGHIJ" \ |
| 67 | + --issuer-id "12345678-1234-1234-1234-123456789012" \ |
| 68 | + --bundle-id "com.example.myapp" \ |
| 69 | + --p8-file "/path/to/key.p8" \ |
| 70 | + --action list |
| 71 | +``` |
| 72 | + |
| 73 | +#### Delete a Message |
| 74 | + |
| 75 | +```bash |
| 76 | +python retention_message.py \ |
| 77 | + --key-id "ABCDEFGHIJ" \ |
| 78 | + --issuer-id "12345678-1234-1234-1234-123456789012" \ |
| 79 | + --bundle-id "com.example.myapp" \ |
| 80 | + --p8-file "/path/to/key.p8" \ |
| 81 | + --action delete \ |
| 82 | + --message-id "my-campaign-001" |
| 83 | +``` |
| 84 | + |
| 85 | +### Environment Options |
| 86 | + |
| 87 | +By default, the tool uses the **SANDBOX** environment. For production: |
| 88 | + |
| 89 | +```bash |
| 90 | +python retention_message.py \ |
| 91 | + --environment PRODUCTION \ |
| 92 | + # ... other parameters |
| 93 | +``` |
| 94 | + |
| 95 | +### Output Formats |
| 96 | + |
| 97 | +#### Human-Readable (default) |
| 98 | +``` |
| 99 | +✓ Message uploaded successfully! |
| 100 | + Message ID: abc-123-def |
| 101 | + Header: Welcome back! |
| 102 | + Body: Check out our new features |
| 103 | +``` |
| 104 | + |
| 105 | +#### JSON Format |
| 106 | +Use `--json` for programmatic usage: |
| 107 | +```bash |
| 108 | +python retention_message.py --json --action list # ... other params |
| 109 | +``` |
| 110 | + |
| 111 | +Output: |
| 112 | +```json |
| 113 | +{ |
| 114 | + "status": "success", |
| 115 | + "messages": [ |
| 116 | + { |
| 117 | + "message_id": "abc-123-def", |
| 118 | + "state": "PENDING" |
| 119 | + } |
| 120 | + ], |
| 121 | + "total_count": 1 |
| 122 | +} |
| 123 | +``` |
| 124 | + |
| 125 | +### Message States |
| 126 | + |
| 127 | +Messages can be in one of three states: |
| 128 | +- **PENDING**: Message uploaded and awaiting Apple's review |
| 129 | +- **APPROVED**: Message approved and can be shown to users |
| 130 | +- **REJECTED**: Message rejected and cannot be used |
| 131 | + |
| 132 | +### Constraints and Limits |
| 133 | + |
| 134 | +- **Header text**: Maximum 66 characters |
| 135 | +- **Body text**: Maximum 144 characters |
| 136 | +- **Image alt text**: Maximum 150 characters |
| 137 | +- **Message ID**: Must be unique (UUIDs recommended) |
| 138 | +- **Total messages**: Limited number per app (see Apple's documentation) |
| 139 | + |
| 140 | +### Error Handling |
| 141 | + |
| 142 | +The tool provides clear error messages for common issues: |
| 143 | + |
| 144 | +| Error Code | Description | Solution | |
| 145 | +|------------|-------------|----------| |
| 146 | +| 4010001 | Header text too long | Reduce header to ≤66 characters | |
| 147 | +| 4010002 | Body text too long | Reduce body to ≤144 characters | |
| 148 | +| 4010003 | Alt text too long | Reduce alt text to ≤150 characters | |
| 149 | +| 4010004 | Maximum messages reached | Delete old messages first | |
| 150 | +| 4040001 | Message not found | Check message ID spelling | |
| 151 | +| 4090001 | Message ID already exists | Use a different message ID | |
| 152 | + |
| 153 | +### Security Notes |
| 154 | + |
| 155 | +- **Never commit** your `.p8` private key files to version control |
| 156 | +- Store credentials securely (consider using environment variables) |
| 157 | +- Use sandbox environment for testing |
| 158 | +- Be cautious with production environment operations |
| 159 | + |
| 160 | +### Troubleshooting |
| 161 | + |
| 162 | +1. **"Private key file not found"** |
| 163 | + - Verify the path to your `.p8` file is correct |
| 164 | + - Ensure the file exists and is readable |
| 165 | + |
| 166 | +2. **"Invalid app identifier"** |
| 167 | + - Check that your bundle ID matches exactly |
| 168 | + - Verify the bundle ID is configured in App Store Connect |
| 169 | + |
| 170 | +3. **Authentication errors** |
| 171 | + - Verify your Key ID and Issuer ID are correct |
| 172 | + - Ensure your private key corresponds to the Key ID |
| 173 | + - Check that the key has appropriate permissions |
| 174 | + |
| 175 | +4. **"Message not found" when deleting** |
| 176 | + - List messages first to see available IDs |
| 177 | + - Ensure you're using the correct environment (sandbox vs production) |
| 178 | + |
| 179 | +### Examples for Different Use Cases |
| 180 | + |
| 181 | +#### A/B Testing Messages |
| 182 | +```bash |
| 183 | +# Upload message A |
| 184 | +python retention_message.py --message-id "test-a-v1" \ |
| 185 | + --header "Come back!" --body "We miss you" # ... other params |
| 186 | + |
| 187 | +# Upload message B |
| 188 | +python retention_message.py --message-id "test-b-v1" \ |
| 189 | + --header "New features!" --body "Check out what's new" # ... other params |
| 190 | +``` |
| 191 | + |
| 192 | +#### Seasonal Campaigns |
| 193 | +```bash |
| 194 | +# Holiday campaign |
| 195 | +python retention_message.py --message-id "holiday-2023" \ |
| 196 | + --header "Holiday Sale!" --body "Limited time: 40% off premium" # ... other params |
| 197 | + |
| 198 | +# Back to school |
| 199 | +python retention_message.py --message-id "back-to-school-2023" \ |
| 200 | + --header "Ready to learn?" --body "New study tools available" # ... other params |
| 201 | +``` |
| 202 | + |
| 203 | +### Integration with CI/CD |
| 204 | + |
| 205 | +For automated deployments, use JSON output: |
| 206 | + |
| 207 | +```bash |
| 208 | +#!/bin/bash |
| 209 | +RESULT=$(python retention_message.py --json --action upload \ |
| 210 | + --key-id "$KEY_ID" --issuer-id "$ISSUER_ID" \ |
| 211 | + --bundle-id "$BUNDLE_ID" --p8-file "$P8_FILE" \ |
| 212 | + --header "Auto-deployed message" --body "Latest features") |
| 213 | + |
| 214 | +if echo "$RESULT" | jq -e '.status == "success"' > /dev/null; then |
| 215 | + echo "Message deployed successfully" |
| 216 | + MESSAGE_ID=$(echo "$RESULT" | jq -r '.message_id') |
| 217 | + echo "Message ID: $MESSAGE_ID" |
| 218 | +else |
| 219 | + echo "Deployment failed" |
| 220 | + exit 1 |
| 221 | +fi |
| 222 | +``` |
| 223 | + |
| 224 | +## Future Tools |
| 225 | + |
| 226 | +This directory is designed to be expanded with additional CLI tools for other App Store Server API functionality as needed. |
0 commit comments