access: false with status: "none". The 404 is about the slug, never about them.plan out to get every plan of the project the customer has anything on.access is false from the plan's end on and access_until is never later, whatever period was paid for. The subscription turns ended within minutes of it, so status can still read active or unpaid for that long with access false. Gate on access.blocked_since and blocked_reason, both null otherwise. status and payment_status stay as they were, and Mesub keeps trying. access is never true past access_until on a blocked subscription. Lifecycle says what each reason asks of you.Limit: 1,000 calls a minute per API key.Guide: Check access.
The version of this contract the call is written against. Without it, the call is served as the first version, 2026-10-02. Any other value is refused with 400 unsupported_version.
One of2026-10-02
Your own id for the customer, as you gave it when the subscription was created. It follows the person whichever wallet pays. Name the customer by exactly one of wallet, external_id and email.
Limits:1 to 255 characters
Example:user_42
The wallet that pays, a base58 Solana address. Name the customer by exactly one of wallet, external_id and email.
Example:9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin
The email given when the subscription was created. Never verified by Mesub. Found however it was typed: it is trimmed and lowercased. Name the customer by exactly one of wallet, external_id and email.
Limits:at most 254 characters
Example:[email protected]
The plan's slug, resolved inside the project the key belongs to. Left out, the answer lists every plan the customer has anything on.
Example:pro
Whether to send the last charges back, five at most. Takes true, 1, false or 0.
Default:false
The answer for one plan when plan is given, the list of plans otherwise.
The version the answer is written in: the one asked for, or 2026-10-02 when the call named none, or one this API does not serve.
One of2026-10-02
The id Mesub gave this request, on every answer, errors included, and in request_id on an error body. Quote it to Mesub support to find the request in our logs. Written by Mesub on each request: one sent with the request is ignored.
The calls this route allows the API key in a minute, or the IP of a call without a valid key. Sent on every answer the rate limit counted.
Limits:at least 1
What is left of them in the current minute.
Limits:at least 0
Seconds until the count starts again.
Limits:at least 0
The wallet the answer is about. Asked by wallet, that wallet. Asked by external_id or email, the one that pays, or null when the customer has nothing on this plan.
The plan's slug.
The subscription this answer is about: the one whose status, access and dates these are. Use it to cancel, resume, close or retry it without listing the customer's subscriptions first. When the customer has several on the plan, the one in force: among their wallets, the most recent that grants access, else the most recent; on one wallet, its latest, never a checkout left pending beside a subscription that runs, nor one left to expire. Null when the customer has nothing on this plan, with status none.
The only field a guard needs. False from the plan's end date on, whatever period was paid for.
Where the subscription stands. none for a customer who never subscribed to this plan. Mesub may add a status later: keep a default branch. For a few minutes after a plan's end date it can still read active or unpaid with access false, never ended with access true: gate on access.
One ofnonependingactiveunpaidcancelledstoppedendedfailedsuperseded
True on a seat parked over the project's subscriber limit: the status stays as it was, nothing is charged, and access runs to the end of the period already paid.
Why it ended. Set only when status is ended. Null on every other status, and on an old subscription that ended with no reason recorded.
One ofcancelledplan_removedplan_replacedplan_endedclosed_elsewhereclosed
Why a payment is late, as the last failed charge found it. Set only when status is unpaid, or stopped for the payment it stopped on. Null on every other status, and when Mesub cannot name the cause.
One ofinsufficient_balanceapproval_revokedauthority_closed
Why it stopped. Set only when status is stopped. Null on every other status, and on a subscription that stopped before Mesub recorded why.
- out_of_retries: every retry of the missed payment failed. The subscription stays open on Solana: the subscriber can come back, or cancel it and close it once the period ends.
- retry_deadline_passed: on the Free tier, the last day to pay the missed payment passed.
- authority_closed: the wallet closed the account that lets Mesub charge it, for good. Nobody can charge this subscription again, and the subscriber cannot come back on it. They can close it now (closable) to get its deposit back.
One ofout_of_retriesretry_deadline_passedauthority_closed
late while a charge missed and a retry is pending. none where nothing is being billed.
One ofpaidlatenone
Since when every charge of this subscription is held for a reason that is not the customer's. Null when none is. status and payment_status do not change for it, and Mesub keeps trying. access ends at access_until, and comes back with the first charge that goes through, with nothing for the customer to sign.
Why the charges are held. Null with blocked_since. Nine values name the plan's own setup, yours to fix or, for the last two, the token issuer's to lift: puller_not_allowed (Mesub's puller was taken off the plan on chain), receiver_not_allowed (the receiving wallet is not among the plan's destinations), receiver_account_missing (it has no account for the plan's token, and nobody else can be paid), receiver_account_frozen (its account for the plan's token is frozen), receiver_account_needs_memo (that account requires a memo on every transfer in, which Mesub's charges do not carry), receiver_account_confidential_only (that account takes confidential transfers only), mint_gone (the token no longer exists), mint_paused (the token's issuer paused it: no payment in it moves, and Mesub charges again once the pause is lifted) and mint_transfer_hook (the token's issuer made its transfers run a program of theirs, which Mesub does not support yet: it charges again if the issuer removes it). mesub is any cause on Mesub's side: nothing for you to fix. Mesub may add a value: keep a default branch.
One ofpuller_not_allowedreceiver_not_allowedreceiver_account_missingreceiver_account_frozenreceiver_account_needs_memoreceiver_account_confidential_onlymint_gonemint_pausedmint_transfer_hookmesub
The start of the current subscription.
The start of the very first one. Differs for a customer who left and came back.
The end of the period last paid for.
When they asked to stop, not when access ends.
When access ends unless a charge renews it. Never later than the plan's end date, where access stops for everybody. Null while access is false. On a subscription whose charges are blocked (blocked_since), the date access ends if nothing is collected by then: the end of the period after the one paid for, or sooner when the cause is the plan's setup, the end of the grace the plan gives a late payment.
Whether the subscriber can close the subscription on Solana now, which returns its deposit to their wallet: a cancellation whose end has passed, a subscription that ended with its plan, or one stopped with stop_reason authority_closed. As Mesub last knew the chain: the close reads the chain again, and may still be refused.
When the subscriber can close it, if not now: the end of the period a cancellation set. Null when closable is true, and when no date is known yet: a running subscription, or one stopped with out_of_retries, must be cancelled first. As Mesub last knew the chain, like closable.
The next charge. Null when a retry is pending instead, and when the plan's end date leaves no charge to make: a subscription in its last period has none.
The next retry of a missed charge. Null when the plan ends before it.
On Free only: when retries by hand close for the missed period, or the plan's end date when that comes first.
The last charges, newest first, five at most. Present only when asked with attempts=true.
skipped: nothing was sent because the chain said it could not work. rejected: refused for a reason that is the customer's, by the program or by the check made before sending (then signature is null). blocked: not tried, and never the customer's doing.
One ofpaidskippedrejectedblocked
Why it did not pay, null on a paid one. Short and stable, in snake case, and an open family rather than a closed list: Mesub adds reasons, so keep a default branch. Among them: insufficient_balance (the wallet held less than the period costs), approval_revoked, authority_closed (the wallet's subscription authority closed for good), token_account_frozen, plan_ended, plan_removed, plan_replaced, closed_elsewhere (the subscription account closed outside Mesub), cancelled (cancelled, and past the end of the period paid for), and, on a blocked one, the plan's setup (puller_not_allowed, receiver_not_allowed, receiver_account_missing, receiver_account_frozen, receiver_account_needs_memo, receiver_account_confidential_only, mint_gone, mint_paused, mint_transfer_hook). A refusal Mesub does not name is program_<N> (the program's or the token program's error code N) or solana_<N> (Solana's own). late_reason on the subscription is the reading of it a program should branch on.
In the token's smallest unit, as a string.
When it was tried.
The transaction. Null when nothing was sent.
Seconds this answer stays true. The SDK caches it for that long.
Limits:10 to 300
Bearer <API key>. The project's API key, which starts with SUB_. Keep it on your server. Where to get it.
curl "https://api.mesub.io/v1/access?external_id=user_42&plan=pro" \ -H "Authorization: Bearer $MESUB_API_KEY"
{ "wallet": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", "plan": "pro", "subscription_id": "cmg1x0abc0001", "access": true, "status": "active", "paused": false, "end_reason": null, "late_reason": null, "stop_reason": null, "payment_status": "paid", "blocked_since": null, "blocked_reason": null, "subscribed_since": "2026-01-01T00:00:05.000Z", "first_subscribed_at": "2026-01-01T00:00:05.000Z", "current_period_end": "2026-01-31T00:00:00.000Z", "cancelled_at": null, "access_until": "2026-01-31T00:00:00.000Z", "closable": false, "closable_from": null, "next_charge_at": "2026-01-31T00:00:00.000Z", "next_retry_at": null, "retry_deadline": null, "revalidate_after": 300 }