12345678{ "statusCode": 409, "message": "You are already subscribed to this plan.", "error": "Conflict", "code": "already_subscribed", "retryable": false, "request_id": "req_4f8KzQ2nVb7XcR1mT9wLp3sD" }
| Field | What it says |
statusCode | The HTTP status, repeated |
message | A sentence for a person. A validation error answers a list of them. It may be reworded |
error | The status's name |
code | What your code reads |
retryable | Whether the same request, sent again unchanged, may succeed later |
request_id | The request's id, as the Mesub-Request-Id header says it. Quote it to Mesub support |
code, never on message. A code is never moved to another status
or reused, and is renamed only in a new Mesub-Version, but new ones are
added: keep a default branch.2026-10-02:
plan_deleted became plan_removed, and plan_rebuilt became
plan_replaced. The old names are no longer answered. Code written against
them must branch on the new ones.retryable is true, the same request sent again unchanged may succeed
later; a Retry-After header says when, in seconds. It never means "retry at
once". Every route is safe to call twice.code | Status | When |
invalid_request | 400 | A parameter is missing or malformed |
unsupported_version | 400 | Mesub-Version names a version not served |
missing_api_key | 401 | No API key was sent |
invalid_api_key | 401 | The key is not one Mesub issued |
forbidden | 403 | The request is understood and refused |
not_found | 404 | Nothing at that address |
conflict | 409 | The request does not fit the current state |
payload_too_large | 413 | The body is too large |
rate_limited | 429 | Too many calls. Retryable |
internal_error | 500 | A failure on Mesub's side. Retryable |
unavailable | 503 | Mesub cannot answer right now. Retryable |
network_unavailable | 503 | The Solana network does not answer. Retryable |
code | Status | When |
plan_not_found | 404 | No plan of yours under that slug |
plan_not_on_chain | 409 | The plan was never published |
plan_removed | 409 | The plan is gone from the chain |
plan_sunset | 409 | The plan takes no new subscribers |
plan_ended | 409 | The plan is past its end date: see below |
plan_replaced | 409 | Another plan now stands at its address |
plan_mismatch | 409 | The plan on chain is not the one Mesub recorded |
receiver_account_missing | 409 | The wallet that receives has no account for the token |
receiver_account_frozen | 409 | The account the plan pays into is frozen |
receiver_account_needs_memo | 409 | That account requires a memo on every transfer in |
receiver_account_confidential_only | 409 | That account takes confidential transfers only |
mint_paused | 409 | The token's issuer paused it |
mint_transfer_hook | 409 | The token's issuer made its transfers run a program |
mint_not_on_chain | 400 | The token does not exist on chain |
plan_ended is what Create a subscription
answers once a plan's end date has passed. In the dashboard, the same code
refuses closing that plan to new subscribers, changing its names, and retrying
one of its payments by hand: nothing can be charged on it any more.code | Status | When |
end_date_too_soon | 400 | The end date is less than one billing period, plus five minutes, away |
end_date_too_far | 400 | The end date is more than 100 years away |
end_date_stale | 409 | The plan's end date no longer holds as you sign its creation |
end_date_too_far is what a date sent in milliseconds gets.mint_not_a_token (400, no token program owns that address),
mint_paused and mint_transfer_hook (409), and mint_frozen_by_default,
mint_non_transferable, mint_confidential_only, mint_extension_unknown
and mint_display_scaled (400).
How it works says what each means.code | Status | When |
already_subscribed | 409 | This wallet already holds this plan |
insufficient_balance | 409 | The wallet cannot pay the first period |
insufficient_sol | 409 | The wallet holds too little SOL for the rent, the fee and its reserve |
seat_cap_reached | 409 | The project is at its subscriber limit |
pending_cap_reached | 429 | Too many subscriptions wait for a signature. Retryable |
wallet_mismatch | 409 | The wallet is not the one the subscription was created for |
payment_pending | 409 | A payment on it failed and is being retried |
subscription_cancelled | 409 | It was cancelled already |
subscription_stopped | 409 | It stopped after missed payments |
subscription_terms_changed | 409 | The plan's terms changed since it was created |
comeback_in_flight | 409 | A return to this plan is being confirmed. Retryable |
comeback_landed | 409 | A return to this plan already landed |
comeback_period_rolling | 409 | A return while its billing period turns. Retryable |
code | Status | When |
terms_missing | 403 | No signed terms came with the transaction |
terms_expired | 403 | The terms were signed too late. Create again |
invalid_terms_signature | 403 | The signature is not the wallet's, over those terms |
terms_used | 403 | Those terms were already used |
terms_changed | 409 | The terms no longer match the plan |
not_our_transaction | 400 | The transaction is not the one Mesub built |
transaction_not_built | 409 | Nothing was built for this subscription yet |
transaction_expired | 409 | The transaction expired before it was sent |
transaction_refused | 409 | The chain refused the transaction |
not_awaiting_signature | 409 | The subscription is past the signing step |
subscription_changed | 409 | It changed while the request ran. Retryable |
transaction_expired, nothing was sent and the same submit cannot land.
Ask for a fresh transaction, have the wallet
sign it, and sign the terms again if terms.message changed.code | Status | When |
subscription_not_found | 404 | No subscription of your project under that id |
subscription_not_active | 409 | Cancel: it is not active, unpaid or stopped |
subscription_not_cancelled | 409 | Resume or close: nothing cancelled it. Cancel a stopped one first |
subscription_ended | 409 | Resume: the paid period is over |
close_too_early | 409 | Close: its end has not passed yet |
subscription_not_on_chain | 409 | It is closed already |
nothing_to_confirm | 400 | A confirm before any transaction was built |
code | Status | When |
subscription_not_late | 409 | It is not unpaid: only a late payment is retried |
subscription_paused | 409 | A parked seat: nothing charges it until a seat frees up |
retry_too_soon | 409 | The wait since the last retry is not over. Retryable |
pull_running | 409 | A charge of it is running now. Retryable |
retry_cannot_succeed | 409 | It would fail whatever the wallet holds: late_reason |
retries_spent | 409 | On Free, the missed period's three retries are spent |
retry_deadline_passed | 409 | On Free, the missed period ends too soon, or has ended |
code | Status | When |
event_not_found | 404 | No event of your project under that id, in the window |