Skip to content

Commit 7df4f19

Browse files
author
Chris Ballinger
committed
Add CLI tool for uploading retention messages
Add environment to output
1 parent e3c2c66 commit 7df4f19

File tree

3 files changed

+636
-0
lines changed

3 files changed

+636
-0
lines changed

cli/README.md

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
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.

cli/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copyright (c) 2023 Apple Inc. Licensed under MIT License.
2+
3+
"""
4+
CLI tools for the App Store Server Library.
5+
"""
6+
7+
__version__ = "1.0.0"

0 commit comments

Comments
 (0)