Reference
REST API
Base URL: https://api.stubkit.com. Every response is a JSON envelope: { success: true, data: ... } on 2xx and { success: false, error: { code, message } } on 4xx/5xx.
Client API
GET /v1/entitlement/:app_id/:user_id
Read current entitlement list. Requires a tenant JWT via Authorization: Bearer. The sub claim must equal :user_id.
{
"success": true,
"data": {
"app_id": "your-app",
"user_id": "user-123",
"entitlements": [
{
"id": "pro",
"status": "active",
"expires_at": "2026-05-11T00:00:00.000Z",
"source": "iap",
"platform": "ios",
"product_id": "com.example.pro.monthly"
}
]
}
}POST /v1/entitlement/:app_id/:user_id/refresh
Force a fresh read and bust the 30-second edge cache. Same auth as the read. Returns the same envelope.
POST /v1/purchases
Sync a freshly completed in-app purchase receipt from the client. Required body:
{
"app_id": "your-app",
"platform": "ios",
"product_id": "com.example.pro.monthly",
"transaction_id": "1000000123456789",
"user_id": "user-123"
}Returns 201 with the updated entitlement list for the user.
Admin API
Requires an API key with the appropriate scope in Authorization: Bearer sk_live_....
POST /v1/admin/apps
Create a tenant. Scope: admin:apps. Credentials in the body are encrypted at rest before storage.
GET /v1/admin/apps/:app_id
Read tenant config. Encrypted columns are not returned — only has_* flags.
PATCH /v1/admin/apps/:app_id
Partial update. Same encryption rules apply to secret fields.
POST /v1/admin/grants
Single-user grant. Scope: admin:grants. Body:
{
"app_id": "your-app",
"user_id": "user-123",
"entitlement": "pro",
"duration_days": 30,
"reason": "Goodwill gift",
"send_email": true
}POST /v1/admin/grants/bulk
Campaign grant. Target selector: all, non-premium, active-30d, since:<iso-date>, or user-ids:csv. Requires confirm: true to prevent accidents.
GET /v1/admin/users
Query params: app_id, q, limit, offset. Scope: admin:users.
GET /v1/admin/events
Query params: app_id, type, user_id, from, to, limit, offset. Scope: admin:events.
GET /v1/admin/analytics/mrr
Snapshot MRR, active subs, and active users. Optional app_id. Scope: admin:analytics.
GET /v1/admin/cron/runs
Scheduled-job run history. Optional job_name filter. Scope: admin:cron.
POST /v1/admin/api-keys
Generate a new key. The raw key is returned exactly once — copy it immediately. Scope: admin:api-keys.
DELETE /v1/admin/api-keys/:id
Revoke. Idempotent.
Webhook receivers
POST /v1/webhooks/apple— Apple App Store Server Notifications v2POST /v1/webhooks/google/:app_id— Google Play Real-time Developer NotificationsPOST /v1/webhooks/stripe/:app_id— Stripe webhook
Misc
GET /v1/health
Unauthenticated health check. Returns service name, version, and timestamp.