Total rebrand across all Go API source files: - Go module path: casera-api -> honeydue-api - All imports updated (130+ files) - Docker: containers, images, networks renamed - Email templates: support email, noreply, icon URL - Domains: casera.app/mycrib.treytartt.com -> honeyDue.treytartt.com - Bundle IDs: com.tt.casera -> com.tt.honeyDue - IAP product IDs updated - Landing page, admin panel, config defaults - Seeds, CI workflows, Makefile, docs - Database table names preserved (no migration needed) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
8.7 KiB
Subscription Webhook Setup
This document explains how to configure Apple App Store Server Notifications and Google Real-time Developer Notifications for server-to-server subscription status updates.
Overview
The webhook endpoints allow Apple and Google to notify your server when subscription events occur:
- New subscriptions
- Renewals
- Cancellations
- Refunds
- Expirations
- Grace period events
Webhook Endpoints:
- Apple:
POST /api/subscription/webhook/apple/ - Google:
POST /api/subscription/webhook/google/
Apple App Store Server Notifications v2
1. Configure in App Store Connect
- Log in to App Store Connect
- Navigate to My Apps > Select your app
- Go to App Information (under General)
- Scroll to App Store Server Notifications
- Enter your webhook URLs:
- Production Server URL:
https://your-domain.com/api/subscription/webhook/apple/ - Sandbox Server URL:
https://your-domain.com/api/subscription/webhook/apple/(or separate staging URL)
- Production Server URL:
- Select Version 2 for the notification version
2. Environment Variables
Set these environment variables on your server:
# Apple IAP Configuration (optional but recommended for validation)
APPLE_IAP_KEY_PATH=/path/to/AuthKey_XXXXX.p8 # Your App Store Connect API key
APPLE_IAP_KEY_ID=XXXXXXXXXX # Key ID from App Store Connect
APPLE_IAP_ISSUER_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx # Issuer ID from App Store Connect
APPLE_IAP_BUNDLE_ID=com.your.app.bundleid # Your app's bundle ID
APPLE_IAP_SANDBOX=true # Set to false for production
3. Generate App Store Connect API Key
To enable server-side receipt validation:
- Go to App Store Connect > Users and Access > Keys
- Click Generate API Key
- Give it a name (e.g., "honeyDue IAP Server")
- Select App Manager role (minimum required for IAP)
- Download the
.p8file - you can only download it once! - Note the Key ID and Issuer ID
4. Apple Notification Types
Your server will receive these notification types:
| Type | Description | Action |
|---|---|---|
SUBSCRIBED |
New subscription | Upgrade user to Pro |
DID_RENEW |
Subscription renewed | Extend expiry date |
DID_CHANGE_RENEWAL_STATUS |
Auto-renew toggled | Update auto_renew flag |
DID_FAIL_TO_RENEW |
Billing failed | User may be in grace period |
EXPIRED |
Subscription expired | Downgrade to Free |
REFUND |
User got refund | Downgrade to Free |
REVOKE |
Access revoked | Downgrade to Free |
GRACE_PERIOD_EXPIRED |
Grace period ended | Downgrade to Free |
Google Real-time Developer Notifications
Google uses Cloud Pub/Sub to deliver subscription notifications. Setup requires creating a Pub/Sub topic and subscription.
1. Create a Pub/Sub Topic
- Go to Google Cloud Console
- Select your project (or create one)
- Navigate to Pub/Sub > Topics
- Click Create Topic
- Name it (e.g.,
honeydue-subscriptions) - Note the full topic name:
projects/your-project-id/topics/honeydue-subscriptions
2. Create a Push Subscription
- In the Pub/Sub Topics list, click on your topic
- Click Create Subscription
- Configure:
- Subscription ID:
honeydue-subscription-webhook - Delivery type: Push
- Endpoint URL:
https://your-domain.com/api/subscription/webhook/google/ - Acknowledgment deadline: 60 seconds
- Subscription ID:
- Click Create
3. Link to Google Play Console
- Go to Google Play Console
- Select your app
- Navigate to Monetization > Monetization setup
- Under Real-time developer notifications:
- Enter your topic name:
projects/your-project-id/topics/honeydue-subscriptions
- Enter your topic name:
- Click Save
- Click Send test notification to verify the connection
4. Create a Service Account for Validation
- Go to Google Cloud Console > IAM & Admin > Service Accounts
- Click Create Service Account
- Name it (e.g.,
honeydue-iap-validator) - Grant roles:
Pub/Sub Subscriber(for webhook handling)
- Click Done
- Click on the service account > Keys > Add Key > Create new key
- Select JSON and download the key file
5. Link Play Console to Cloud Project
- Go to Google Play Console > Setup > API access
- Link your Google Cloud project
- Under Service accounts, grant your service account access:
View financial data(for subscription validation)
6. Environment Variables
# Google IAP Configuration
GOOGLE_IAP_SERVICE_ACCOUNT_PATH=/path/to/service-account.json
GOOGLE_IAP_PACKAGE_NAME=com.your.app.packagename
7. Google Notification Types
Your server will receive these notification types:
| Type Code | Type | Description | Action |
|---|---|---|---|
| 1 | SUBSCRIPTION_RECOVERED |
Recovered from hold | Re-upgrade to Pro |
| 2 | SUBSCRIPTION_RENEWED |
Subscription renewed | Extend expiry date |
| 3 | SUBSCRIPTION_CANCELED |
User canceled | Mark as canceled, will expire |
| 4 | SUBSCRIPTION_PURCHASED |
New purchase | Upgrade to Pro |
| 5 | SUBSCRIPTION_ON_HOLD |
Account hold | User may lose access soon |
| 6 | SUBSCRIPTION_IN_GRACE_PERIOD |
In grace period | User still has access |
| 7 | SUBSCRIPTION_RESTARTED |
User resubscribed | Re-upgrade to Pro |
| 12 | SUBSCRIPTION_REVOKED |
Subscription revoked | Downgrade to Free |
| 13 | SUBSCRIPTION_EXPIRED |
Subscription expired | Downgrade to Free |
Testing
Test Apple Webhooks
- Use the Sandbox environment in App Store Connect
- Create a Sandbox tester account
- Make test purchases on a test device
- Monitor your server logs for webhook events
Test Google Webhooks
- In Google Play Console > Monetization setup
- Click Send test notification
- Your server should receive a test notification
- Check server logs for:
"Google Webhook: Received test notification"
Local Development Testing
For local testing, use a tunnel service like ngrok:
# Start ngrok
ngrok http 8000
# Use the ngrok URL for webhook configuration
# e.g., https://abc123.ngrok.io/api/subscription/webhook/apple/
Security Considerations
Apple Webhook Verification
The webhook handler includes optional JWS signature verification. Apple signs all notifications using their certificate chain. While the current implementation decodes the payload without full verification, you can enable verification by:
- Downloading Apple's root certificates from https://www.apple.com/certificateauthority/
- Calling
VerifyAppleSignature()before processing
Google Webhook Security
Options for securing Google webhooks:
- IP Whitelisting: Google publishes Pub/Sub IP ranges
- Push Authentication: Configure your Pub/Sub subscription to include an authentication header
- OIDC Token: Have Pub/Sub include an OIDC token that your server verifies
General Security
- Always use HTTPS for webhook endpoints
- Validate the bundle ID / package name in each notification
- Log all webhook events for debugging and audit
- Return 200 OK even if processing fails (to prevent retries flooding your server)
Troubleshooting
Apple Webhooks Not Arriving
- Verify the URL is correct in App Store Connect
- Check your server is reachable from the internet
- Ensure you're testing with a Sandbox account
- Check server logs for any processing errors
Google Webhooks Not Arriving
- Verify the topic name format:
projects/PROJECT_ID/topics/TOPIC_NAME - Check the Pub/Sub subscription is active
- Test with "Send test notification" in Play Console
- Check Cloud Logging for Pub/Sub delivery errors
User Not Found for Webhook
This typically means:
- The user made a purchase but the receipt/token wasn't stored
- The transaction ID or purchase token doesn't match any stored data
The handler logs these cases but returns success to prevent Apple/Google from retrying.
Database Schema
Relevant fields in user_subscriptions table:
apple_receipt_data TEXT -- Stores receipt/transaction ID for Apple
google_purchase_token TEXT -- Stores purchase token for Google
cancelled_at TIMESTAMP -- When user canceled (will expire at end of period)
auto_renew BOOLEAN -- Whether subscription will auto-renew
These fields are used by webhook handlers to:
- Find the user associated with a transaction
- Track cancellation state
- Update renewal preferences