Subscription Plans
Charge your app's users a recurring price through Hypery and give each payment credit grants that can only be spent in your app — price and grants configured independently.
Overview
Subscription plans let your app sell a recurring subscription (a monthly price, plus an optional annual price) and give subscribers credit grants to spend on AI inside your app.
- You're the merchant of record. Payments go to your Stripe Connect account. Hypery takes its platform fee.
- Price and grants are separate. A plan can charge $10/month and grant $5, $25, several grants of different types, or nothing at all.
- Grants stay in your app. A grant can only pay for requests made through your app. Other apps, and the user's own direct API usage, can't spend it.
- Grants expire and never roll over. Subscribers get fresh grants every month, and each grant expires after the number of days you set.
- Annual billing, monthly grants. Annual subscribers pay once a year but still receive the plan's grants every month, so credits never land all at once.
- Usage keeps working when a grant runs out. Once a grant is used up or expired, the user's usage bills the normal way (their balance or card).
- No re-entering a card. Subscribing uses a card the user already gave Hypery: their wallet card, or the card they added when they set up billing.
Authentication:
- Plan management: your personal API key (
ak_...) or a session/OAuth token withwrite(readfor GET). Only the app's owner or a billing admin can manage plans. - Subscribing: an OAuth token for your app with the
billing:chargescope.
Plans require Stripe Connect onboarding to be complete for the app
(chargesEnabled). Until then, creating a plan returns 409 MARKETPLACE_NOT_ONBOARDED.
Grant types
Every grant on a plan is one of two types:
How each type is spent:
- Hypery grants:
- A request is paid from the grant first; anything left over is charged to the user's balance.
- A request normally billed through Vercel AI Gateway is routed through the credit ledger instead, but only when the grant covers the whole request's estimate.
- Hypery grants don't cover
/v1/ai(the Vercel AI Gateway protocol endpoint) or predictions.
- Stripe grants:
- While the grant has value left, your app's metered usage is billed to the dedicated customer, where the credit grant offsets it.
- Once it's spent, usage goes back to the user's regular Stripe customer.
Funding: you pay for every grant.
- When a grant is issued, its USD value is debited from your team's Hypery balance.
- If the balance can't cover it, the amount is added to your team's Stripe invoice instead.
- If neither works, the grant is marked
funding_failed(not spendable) and retried automatically.
Plans
List plans
Endpoint: GET /api/apps/{appId}/plans
curl https://hypery.ai/api/apps/{appId}/plans \
-H "Authorization: Bearer ak_your_key"{
"success": true,
"data": {
"connectReady": true,
"plans": [
{
"_id": "66f…",
"name": "Pro",
"status": "active",
"priceCents": 1000,
"interval": "month",
"prices": [
{ "interval": "month", "priceCents": 1000, "stripePriceId": "price_…", "active": true },
{ "interval": "year", "priceCents": 10000, "stripePriceId": "price_…", "active": true }
],
"grants": [
{ "id": "g_1a2b…", "type": "hypery", "amountUsd": 10, "expiresAfterDays": 31, "issueOn": "each_payment" }
],
"activeSubscribers": 42,
"economics": {
"priceUsd": 10, "monthlyPriceUsd": 10, "annualPriceUsd": 100, "annualEffectiveMonthlyUsd": 8.33,
"annualSavingsPct": 17, "recurringGrantUsd": 10, "firstPaymentGrantUsd": 10, "grantsExceedPrice": true
}
}
]
}
}Create a plan
Endpoint: POST /api/apps/{appId}/plans
curl -X POST https://hypery.ai/api/apps/{appId}/plans \
-H "Authorization: Bearer ak_your_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Pro",
"monthlyPriceCents": 1000,
"annualPriceCents": 10000,
"grants": [
{ "type": "hypery", "amountUsd": 10, "expiresAfterDays": 31, "issueOn": "each_payment" },
{ "type": "hypery", "amountUsd": 5, "expiresAfterDays": 7, "issueOn": "first_payment_only" }
]
}'plans[].priceCents / stripePriceId / interval mirror the monthly price, for
older clients; read prices[] for both.
Update a plan
Endpoint: PATCH /api/apps/{appId}/plans/{planId}
All fields are optional: name, description, monthlyPriceCents,
annualPriceCents, grants, status (active / archived).
- Price changes create a new Stripe price. Existing subscribers on that interval move to it at their next renewal, with no proration.
annualPriceCents: nullremoves the annual option for new subscribers. Existing annual subscribers keep renewing until they cancel or switch.monthlyPriceCents: null(only when an annual price exists) makes the plan annual-only. Existing monthly subscribers keep renewing; clients that don't sendintervalget400 INTERVAL_NOT_OFFERED, so update them to send"year".- Grant changes apply from the next grant issued (including the next
monthly grant of annual subscribers). Grants already issued
keep their original amount and expiry.
- To keep an existing grant, send its
idback. - A grant without an
idis treated as new. - A grant you leave out is removed.
- To keep an existing grant, send its
- Archiving hides the plan from new subscribers. Existing subscriptions keep renewing until they're canceled.
Plan details
Endpoint: GET /api/apps/{appId}/plans/{planId}
Returns the plan, its economics, and grant totals grouped by status: grants issued, credits issued, used, and remaining.
Subscribing (from your app)
With @hyperyai/sdk, useAppSubscription(appId)
and <SubscribeButton planId interval> handle
the whole flow: sign-in, subscribe, and card entry only if the user has no card
on Hypery. The endpoints below are what they call.
Show available plans
Endpoint: GET /api/marketplace/plans (scope read)
With an OAuth token, this returns the plans of the app the token belongs to. Session or API-key callers pass ?appId={appId}.
{
"plans": [
{
"id": "66f…",
"appId": "66e…",
"name": "Pro",
"priceCents": 1000,
"currency": "usd",
"interval": "month",
"prices": [{ "interval": "month", "priceCents": 1000 }, { "interval": "year", "priceCents": 10000 }],
"grants": [{ "type": "hypery", "amountUsd": 10, "expiresAfterDays": 31, "issueOn": "each_payment" }]
}
]
}Subscribe
Endpoint: POST /api/marketplace/subscribe (scope billing:charge)
curl -X POST https://hypery.ai/api/marketplace/subscribe \
-H "Authorization: Bearer <user OAuth token>" \
-H "Content-Type: application/json" \
-d '{ "planId": "66f…", "interval": "year", "idempotencyKey": "sub-7f3c9a1e" }'Responses:
The grants go to the user's billing team: their personal team, or the
organization selected with x-hypery-active-organization-id.
Status and remaining grants
Endpoint: GET /api/marketplace/subscriptions?appId={appId} (scope read)
{
"subscriptions": [
{
"id": "670…",
"appId": "66e…",
"plan": { "id": "66f…", "name": "Pro", "priceCents": 1000, "interval": "month", "grants": [] },
"status": "active",
"cancelAtPeriodEnd": false,
"interval": "year",
"pendingInterval": null,
"currentPeriodEnd": "2027-09-15T12:00:00.000Z",
"nextGrantAt": "2026-10-15T12:00:00.000Z",
"grants": [
{ "type": "hypery", "amountUsd": 10, "remainingUsd": 6.42, "expiresAt": "2026-10-15T12:00:00.000Z" }
]
}
]
}Cancel and resume
POST /api/marketplace/subscriptions/{id}/cancel: stops renewal at the end of the current period. Grants already issued stay usable until they expire.POST /api/marketplace/subscriptions/{id}/resume: undoes a pending cancellation.
Switch between monthly and annual
Endpoint: POST /api/marketplace/subscriptions/{id}/interval with { "interval": "year" | "month" }
- Monthly → annual happens immediately. The unused part of the current
month is credited, the year is charged now, and a new yearly period starts. The
current month's grants aren't issued twice. A declined card returns
402 PAYMENT_DECLINEDand nothing changes. - Annual → monthly happens at the end of the paid year (
effective: "period_end",pendingInterval: "month"). Monthly grants continue until then. Calling it again withyearkeeps annual billing. - Switching to annual is refused on an archived plan (
409 PLAN_ARCHIVED).
All three require billing:charge, and an OAuth token can only manage subscriptions
for its own app.