1
Sell
POST /checkout/sessions with your subscription offer’s id, redirect the
buyer to the returned url.2
Gate
Check
GET /subscriptions/subscribers/{id} (optionally ?live=true)
before serving paid content.3
React
Verify and handle
customer.subscription.* / invoice.* webhooks to keep
your records in sync.1. Authentication and base URL
Every request goes tohttps://api.pocketsflow.com with your API key in the
Authorization header — pk_live_… for live mode, pk_test_… for sandbox
data. Create keys in the dashboard under Developers → API keys, and keep
them server-side only. Details:
Authentication & security.
Create a subscription offer
UsePOST /subscriptions to create the recurring product before creating a
checkout session. The endpoint accepts JSON for API clients and
multipart/form-data when you also need to upload offer assets.
cURL
price is in USD. frequency must be weekly, monthly, or yearly;
trialPeriod is the number of trial days. The endpoint returns the created
offer with 201 Created.
The same operation is available through the official Node.js/TypeScript SDK:
npm install pocketsflow. See the SDK guide
for configuration, resource methods, and error handling. The SDK source’s
current v1.2.0 release includes subscriptionOffers.create; if your installed
npm version predates that release, use the REST request above until you upgrade.
2. Create a checkout session for a subscription offer
POST /checkout/sessions accepts a subscription offer id in productId
(the same field used for one-time products — pass either kind of id). Redirect
the buyer to the url in the response; Pocketsflow hosts the checkout and the
recurring billing.
201 with:
successUrl/cancelUrl must be absolute http(s) URLs; clientReferenceId
(max 256 chars) and metadata are captured at activation and replayed on every
customer.subscription.* / invoice.* webhook, so you can bind events back to
your own user records. The full field table is in the
custom platforms guide.
3. List your subscription offers
GET /subscriptions returns your offers (the recurring products), newest
first, scoped to your account and the key’s test/live mode. Use it to find the
_id to sell in step 2.
frequency is weekly, monthly, or yearly. A single offer is available at
GET /subscriptions/{id} (404 if it doesn’t exist or isn’t yours).
4. List subscribers (filter by status)
GET /subscriptions/subscribers is the paginated roster of buyers across your
offers. Filters: status, buyerEmail (alias email), subscriptionId,
page (default 1), pageSize (default 20).
status values include active, trialing, past_due, paused, and
canceled (full list in the
API reference).
portalUrl is the subscriber’s self-service portal — share it so buyers can
manage their own membership.
5. Verify one subscriber’s live status (the access gate)
Before serving paid content, look the subscriber up by their_id (the 24-hex
Mongo id from step 4 or from webhooks — not a mem_… id here). Add
?live=true to also fetch the authoritative membership from the payment
processor as whopMembership; if that live lookup fails, whopMembership is
null and the stored status still applies, so the request never fails.
payments is the full history for this membership — the initial charge plus
every renewal. For hot paths, gate on the stored status (kept fresh by
webhooks) and reserve ?live=true for the moments that matter, like restoring
account access after a failed payment.
6. Cancel, pause, or resume a subscriber
Three lifecycle actions, allPOST with an empty body. {id} is the
subscriber’s _id or their processor membership id (mem_…).
cancel and resume respond with:
pause adds a paused boolean to the same shape. Pause is provider-first: if
the processor refuses, you get a 502 and no local state changes — and a
subscriber with no membership on record returns 400. Cancelling also fires
the customer.subscription.updated webhook (and customer.subscription.deleted
when the membership actually ends); pausing/resuming fire
customer.subscription.pause / customer.subscription.resumed.
7. Receive and verify subscription webhooks
Register an endpoint (dashboard, orPOST /webhooks) and subscribe to the
subscription events. Every delivery is a POST with these headers:
Subscription-related events:
customer.subscription.created,
customer.subscription.updated, customer.subscription.deleted,
customer.subscription.pause, customer.subscription.resumed,
customer.subscription.trial_will_end, invoice.created, invoice.upcoming,
invoice.payment_succeeded, invoice.payment_failed,
payment_intent.succeeded, and payment_intent.payment_failed. Every payload
carries a top-level subscriptionCustomerId (the subscriber _id from steps
4–6) and your clientReferenceId/metadata from checkout. Payload shapes:
Webhook events.
Always verify the signature over the raw body (never re-serialize the
parsed JSON) with a constant-time comparison:
Each event is delivered with a single attempt and a 5-second timeout
— acknowledge with a
2xx immediately and do the real work asynchronously.
If a delivery is missed, reconcile via
GET /subscriptions/subscribers (step 4).Example repository
Prefer runnable code? The subscriptions example on GitHub has everything on this page as a clone-and-run project: a checkout embed (hosted link, popup, and inline) plus a Node/Express webhook receiver that verifies the signature and handles the full subscription lifecycle.Related topics
- Subscriptions example repo — runnable embed + webhook code
- Webhook events — every payload, field by field
- Authentication & security
- Consuming webhooks
- API reference
- Subscriptions guide — creating offers in the dashboard
- Custom platforms — the generic checkout + webhook pattern