/api/v1/entitlements/{user_id}Retrieve entitlement
Ask Fictura whether a user is currently entitled, instead of maintaining your own billing table. Derived from Stripe's and the stores' own webhooks; fails closed.
Authorization
Send your SDK app key in the x-api-key header. The key selects your app, and the lookup can only see that app's users.
Path parameters
Any identifier you've given Fictura for the user — your account id (the one that rode the checkout URL), the RevenueCat app user id, or the device id; the lookup matches all three. An unknown user answers status: "none" with a 200, so one code path handles everyone. The check is read-only — it never creates a user.
Response fields
Whether the user should see paid features right now. Trials and grace periods count as active.
One of active, trialing, grace_period, expired, none, unknown. unknown means a granting event arrived with no expiry to reason about — deliberately not treated as active.
The plan — a Stripe price id for web purchases, a store product id otherwise.
Where the money moved: STRIPE, RC_BILLING, APP_STORE, PLAY_STORE.
NORMAL, TRIAL, or INTRO.
False once the user has cancelled but before the period ends — the window a win-back has to land in.
End of the paid period. Null when the user has never been entitled — and in the unknown case, where a granting event carried no expiry.
PRODUCTION or SANDBOX. The verdict follows the user's most recent granting event's environment — a sandbox test purchase answers is_active: true with environment: "SANDBOX". Check this field before granting anything paid in production.
curl https://api.fictura.co/api/v1/entitlements/8f14e45f \
-H "x-api-key: gk_..."{
"ok": true,
"user_id": "8f14e45f-…",
"is_active": true,
"status": "active",
"product_id": "price_1TmKgS…",
"store": "STRIPE",
"period_type": "NORMAL",
"will_renew": true,
"expires_at": "2026-09-10T18:22:41.000Z",
"environment": "PRODUCTION"
}{
"ok": true,
"user_id": "someone-new",
"is_active": false,
"status": "none",
"product_id": null,
"store": null,
"period_type": null,
"will_renew": false,
"expires_at": null,
"environment": null
}Client checks are hints
Growth.isSubscribed() on the client is a rendering hint — a modified client can lie to itself. Anything that costs you money should check here, server-side.
Semantics worth knowing: cancellation only flips will_renew — access runs to expires_at, and only an expiration event ends it; a failed payment yields grace_period, still active, while the card retries; the verdict is recomputed on every billing webhook and the clock is re-checked on every read.