Quickstart
This walks through wiring up subscriptions against Metera — the order of calls and the exact payloads. Metera is a self-hosted subscription / entitlement backend: the app makes the store purchase, sends the transaction to Metera, and Metera verifies it with Apple / Google server-side and tracks who has access to what.
Prefer a wrapped client? The official iOS and Android SDKs make exactly these calls. This page covers the underlying REST flow.
Authentication
Every request carries Authorization: Bearer <app API key> (the per-app key, looks like app_…, created in the dashboard). The key identifies the app; the App User ID — any stable string you choose — identifies the user within it.
Prerequisite (one-time, server-side)
Before receipts can verify, the app's billing account needs store credentials in the dashboard: the Apple .p8 (Issuer ID + Key ID) and/or the Google Play service account JSON, the app's bundleId and numeric Apple App ID, plus entitlements, plans (one per store product, linked to entitlements) and a current offering. Until plans are linked to entitlements, purchases verify but grant nothing.
The flow
launch ─► identify ─► getOfferings ─► (user taps buy)
│
StoreKit 2 / Play Billing purchase
│
▼
POST /v1/receipts/ios|android ◄── the critical step
│
Metera verifies with Apple/Google,
creates the subscription, grants entitlements
│
▼
GET /v1/users/{appUserId}/entitlements ─► gate features1. Identify the user
Call on first launch (anonymous) and again on login. On login it merges the anonymous identity into the real account.
POST /v1/users/identify
Authorization: Bearer app_…
Content-Type: application/json
{ "appUserId": "user@example.com", "anonymousId": "device-uuid-or-null" }2. Fetch the paywall
GET /v1/offerings returns the current offering and its packages. Each package's productId is what you hand to StoreKit / Play Billing. Offerings are edited server-side — no app release needed to change the paywall.
3. Make the store purchase (client-side)
Run the native StoreKit 2 / Play Billing purchase. Pass a stable per-install token (appAccountToken on iOS, obfuscatedAccountId on Android) so store server notifications can be attributed to the user.
4. Sync the purchase
This is the step that activates the subscription. Metera independently re-verifies the transaction with the App Store Server API (or Play Developer API) — the client is never trusted.
POST /v1/receipts/ios
Authorization: Bearer app_…
Content-Type: application/json
{ "appUserId": "user@example.com", "transactionId": "2000000812345678" }| Status | Meaning |
|---|---|
200 | Verified. Subscription created/updated, entitlements granted. |
422 | Store could not verify the transaction. Do not grant access. |
400 | Config problem (credentials missing, or no matching plan). |
On iOS, only call transaction.finish() after this succeeds — if the sync fails, leave it unfinished and StoreKit redelivers it on the next launch. Android is identical: POST /v1/receipts/android with a purchaseToken.
5. Gate features
The canonical "does this user have Pro" check. Call at launch and after any purchase or restore.
GET /v1/users/user%40example.com/entitlements
Authorization: Bearer app_…Gate on entitlements["pro"].isActive === true. URL-encode appUserId in the path. Returns 400 if the user does not exist yet — call identify first.
Renewals, cancellations, refunds
These happen without the app running. Metera receives them via store webhooks (Apple ASN v2 / Google RTDN) and via client re-sync (StoreKit Transaction.updates / "Restore"), so your app never implements renewal logic — it just reads entitlements. Want your own backend notified? Metera can push signed outbound webhooks to a URL you configure.
Next
See the REST API reference for every endpoint, or drop in the iOS / Android SDK to skip the HTTP plumbing.