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 v2
  • POST /v1/webhooks/google/:app_id — Google Play Real-time Developer Notifications
  • POST /v1/webhooks/stripe/:app_id — Stripe webhook

Misc

GET /v1/health

Unauthenticated health check. Returns service name, version, and timestamp.