REST API reference
Base URL https://entitlehub.com/v1. JSON in, JSON out. Authenticate every request with Authorization: Bearer <key> — see API keys. Reads accept a pk_ key; writes require an sk_ key.
POST /v1/check
Authoritative single-entitlement check. Any key.
POST /v1/check
Authorization: Bearer pk_live_…
{ "app_user_id": "user_123", "entitlement": "pro", "sandbox": false }
200 OK
{
"app_user_id": "user_123", "entitlement": "pro", "active": true,
"status": "active", "store": "play", "product": "app_pro_monthly",
"expires_at": "2026-08-01T00:00:00Z", "will_renew": true, "since": "2026-07-01T00:00:00Z"
}
// not entitled → { "active": false, "reason": "no_active_grant" }GET /v1/subscribers/{app_user_id}
A subscriber's active entitlements (the "customer info"). Any key.
GET /v1/subscribers/user_123
Authorization: Bearer pk_live_…
200 OK
{
"app_user_id": "user_123",
"active_entitlements": [
{ "entitlement": "premium", "status": "active", "store": "play",
"product": "app_premium_lifetime", "expires_at": null, "will_renew": false, "since": "…" },
{ "entitlement": "pro", "status": "active", "store": "play",
"product": "app_pro_monthly", "expires_at": "2026-08-01T00:00:00Z", "will_renew": true, "since": "…" }
]
}Only currently-active entitlements are returned; an unknown user returns an empty list (not an error).
POST /v1/subscribers/{app_user_id}/purchases
Record a store purchase → maps product to entitlement(s) and writes a grant. Secret key required. Three input modes:
Google Play (validated)
POST /v1/subscribers/user_123/purchases
Authorization: Bearer sk_live_…
{ "store": "play", "store_product_id": "app_pro_monthly",
"purchase_token": "…", "is_subscription": true }Apple StoreKit 2 (validated)
POST /v1/subscribers/user_123/purchases
Authorization: Bearer sk_live_…
{ "signed_transaction": "<StoreKit2 JWS>" }
// store + product are read from the verified JWSStripe (validated)
POST /v1/subscribers/user_123/purchases
Authorization: Bearer sk_live_…
{ "store": "stripe", "stripe_subscription_id": "sub_1P…" }
// validated via the project's Stripe secret key; store_product_id ← the Stripe Price idTrusted server-report (no store validation)
POST /v1/subscribers/user_123/purchases
Authorization: Bearer sk_live_…
{ "store": "play", "store_product_id": "app_premium_lifetime" }
// only when you've already validated the receipt elsewhere — call server-side onlyAll three return the updated customer-info object (same shape as the subscribers endpoint).
POST /v1/subscribers/{app_user_id}/grant
Grant an entitlement directly — promos, comps, redemption codes. Secret key required.
POST /v1/subscribers/user_123/grant
Authorization: Bearer sk_live_…
{ "entitlement": "premium", "duration_days": 0 }
// duration_days: 0 = lifetime, N = expires in N days. is_sandbox optional.GET /v1/offerings
Your catalog — entitlements and products — for building a paywall. Any key.
GET /v1/offerings
Authorization: Bearer pk_live_…
200 OK
{ "entitlements": [ { "key": "pro", "name": "Pro", ... } ],
"products": [ { "store_product_id": "app_pro_monthly", "type": "subscription",
"price_micros": 2990000, "currency": "USD", "entitlements": ["pro"] } ] }Errors
| Status | Meaning |
|---|---|
401 | Missing / invalid / revoked key. |
403 | Used a pk_ key on a write endpoint (needs sk_). |
400 | Invalid token, unknown/unmapped product, or no Play credential configured. |
A check or subscriber read for a user with no grants returns an inactive/empty result, not an error.
