Subscription error reference

Every code every subscription route can return, grouped by route. All bodies are {"message": "...", "error_code": "..."} unless a different shape is shown. Where a body carries status too, branch on status first. Match on error_code, never on message.

Authentication and gates (every route)

HTTPCode or bodyMeaningRemedy
401{"message": "X-Game-Secret-Key header is required"}No key.Send the header.
401{"message": "Invalid game secret key"}Unknown or rotated-out key.Use the current key for this environment.
403{"message": "Game '...' is not active"}Game suspended.Contact Invo.
403GAME_NOT_LIVECreate refused; game is testing.Make the game live in the console.
503{"status": "error", "error": "flow_paused", "message": "..."}Maintenance pause (create, amount, payment-method, Steam init, card setup).Retry later with the same idempotency key.
503FLOW_PAUSEDMaintenance pause (refund, sandbox clock).Retry later.
429{"error": "rate_limit_exceeded", "message": "...", "retry_after": n}Rate limited.Honour Retry-After.
429RATE_LIMITEDRate limited (refund, sandbox clock).Slow down.
429{"error": "spending_limit_exceeded", "message": "..."}Member spending limit (Steam init).Retry later.
404SUBSCRIPTION_NOT_FOUNDNot your subscription, or no such id.Check the id and the key.
400INVALID_BODYBody is not a JSON object.Send an object.
400INVALID_FIELD_VALUEA value the database refused (length, characters).Fix the value.
500INTERNAL_ERRORUnexpected.Retry with the same idempotency key.

Create (/subscribe, /steam/init)

HTTPCodeMeaningRemedy
400CLIENT_REQUEST_ID_REQUIRED, CLIENT_REQUEST_ID_INVALID, CLIENT_REQUEST_ID_TOO_LONGMissing, not a string, or over 255 chars.Send a string of at most 255 chars.
400CLIENT_REQUEST_ID_RESERVEDKey begins with sub_.Do not begin keys with sub_.
400PLAYER_EMAIL_INVALID, PLAYER_EMAIL_TOO_LONG, PLAYER_NAME_REQUIRED, PLAYER_NAME_TOO_LONG, PLAYER_PHONE_TOO_LONGIdentity field invalid.Fix the field.
400ITEM_ID_REQUIRED, ITEM_ID_TOO_LONG, ITEM_NAME_TOO_LONGItem field invalid.Fix the field.
400AMOUNT_REQUIRED, AMOUNT_INVALID, AMOUNT_TOO_SMALL, AMOUNT_TOO_LARGEPrice invalid.0.01 to 999999.99; keep at or below 500.00 to be chargeable.
400INTERVAL_INVALID, INTERVAL_COUNT_INVALID, INTERVAL_COUNT_OUT_OF_RANGEInterval invalid.month or year; count 1 to 36 (1 on Steam).
400TRIAL_DAYS_INVALID, TRIAL_DAYS_OUT_OF_RANGE, TRIAL_END_INVALID, TRIAL_END_IN_PAST, TRIAL_END_TOO_FARTrial invalid.1 to 365 days; ISO 8601 in the future.
400METADATA_INVALID, METADATA_TOO_LARGEMetadata invalid.JSON object, at most 8192 bytes, no NUL.
400CONSENT_AT_INVALID, CONSENT_INVALID, CONSENT_DISCLOSED_AMOUNT_INVALID, CONSENT_DISCLOSED_INTERVAL_INVALIDConsent field invalid.Fix the consent field.
400REVENUE_SHARE_INVALID, REVENUE_SHARE_PERCENT_OUT_OF_RANGE, REVENUE_SHARE_RECIPIENT_REQUIRED, REVENUE_SHARE_RECIPIENT_IS_SUBSCRIBER, REVENUE_SHARE_RECIPIENT_NOT_FOUNDRevenue share invalid.Name an existing player in this game who is not the subscriber; percent 0 to 100.
400CURRENCY_NOT_CONFIGUREDThe game has no currency.Configure the game currency.
400PAYMENT_METHOD_INVALID, PAYMENT_METHOD_EXPIREDCard id invalid or card expired.Pass an integer card id of an unexpired card.
404PAYMENT_METHOD_NOT_FOUNDThe card is not this player’s in this game, or the player does not exist yet.Save a card for the player first.
409WALLET_ONLY_SUBSCRIPTIONwallet_only: true combined with a card, or sent on Steam.Do not combine wallet_only: true with a card; on Steam do not send wallet_only.
409ACTIVE_SUBSCRIPTION_EXISTS (+ subscription_id)The player already has a live subscription to this item, on either rail.Use the live subscription. Same item id across rails is intended.
409CONCURRENT_REQUESTTwo creates for a new player collided.Retry with the same key.
409CLIENT_REQUEST_ID_CONFLICTKey already used for a different player or item.Use a key unique per subscription and player.
409IDEMPOTENT_REPLAY_MISMATCH (+ mismatched_fields)Same key, same player and item, different material terms.Use /amount or /payment-method to change terms, or a new key.
409REVENUE_SHARE_EXISTSShare already set.Nothing; the share is set once at create.
409PHONE_SHARE_APPROVAL_REQUIRED (+ approval_id, expires_at, next_endpoint)The phone belongs to another identity.Complete the approval flow in the body, then retry.
400DATA_CONFLICTA value the database refused.Retry with a new key after fixing the data.
400STEAMID_REQUIRED, INVALID_USERSESSION, MISSING_PLAYER_IP, STEAM_INTERVAL_COUNT_UNSUPPORTED, CARD_FIELDS_NOT_ALLOWED, TRIAL_NOT_SUPPORTED_ON_STEAM, AMOUNT_TOO_SMALL_FOR_STEAM, STEAM_REQUEST_INVALIDSteam field rules.See the Steam road.
403STEAM_RAIL_NOT_ENTITLED, RAIL_NOT_AVAILABLE_TO_PLATFORMTitle not enabled for Steam / rail not available to your tenant type.Enable Steam for the title in the console; contact Invo.
409STEAM_CHANNEL_REQUIRED, STEAM_ACCOUNT_LOCKED, STEAM_CHARGE_UNPLANNABLE, PARTNER_BILLING_NOT_SET_UP, PARTNER_RAIL_SUSPENDED, PARTNER_CREDIT_UNAVAILABLESteam gates.See the Steam road.
409STEAM_AUTHORIZATION_PENDING (+ subscription_id)A Steam subscription for this player and item is waiting for authorisation and this request carries different terms.Finalize, cancel or wait out the pending row, or send the same terms to get it back.
503STEAM_NOT_CONFIGURED, STEAM_UNAVAILABLE, {"message": "Steam subscriptions are not enabled."}Steam configuration missing / Steam down / rail off.Configure Steam; retry with a new key; contact Invo.
502STEAM_ERRORSteam could not start the subscription; row abandoned.Retry with a new key.
500CLAIM_FAILED, ORDER_FAILEDInvo could not open the first period.Retry with a new key.

Finalize (/steam/finalize)

HTTPCode or bodyMeaningRemedy
400SUBSCRIPTION_ID_REQUIREDMissing body field.Send the id.
409{"status": "not_authorized", "steam_status": "..."}The member has not completed authorisation yet.Retry after they have.
409NOT_A_STEAM_SUBSCRIPTIONNot a Steam subscription.Nothing to finalize.
409SUBSCRIPTION_TERMINALCanceled or expired.Start a new one.
409NO_STEAM_AUTHORIZATIONNo open Steam authorisation.Start a new subscription.
409STEAM_APP_CHANGEDStarted against a different Steam application.Contact Invo.
503{"status": "service_unavailable"}Steam unavailable.Retry.
502{"status": "steam_error"}Could not verify the authorisation.Retry.

Read, list, cancel, amount, payment-method

HTTPCode or bodyMeaningRemedy
400PLAYER_EMAIL_REQUIRED, PLAYER_EMAIL_TOO_LONGList without a valid email.Send the email.
400STATUS_INVALIDUnknown status in the list filter.Use the statuses on the overview or live.
400PAGINATION_INVALIDlimit outside 1 to 100 or offset outside 0 to 100000.Fix the parameter.
409SUBSCRIPTION_TERMINALAmount or payment-method on a canceled or expired row.Start a new subscription.
409STEAM_REAUTHORIZATION_REQUIRED (+ current_amount_usd, requested_amount_usd)Price increase on Steam.Start a new Steam subscription at the new price; cancel this one.
400PAYMENT_METHOD_REQUIREDNo card id in the body.Send the id.
400WALLET_ONLY_CONFLICTwallet_only: true together with a card.Send one or the other.
409WALLET_ONLY_SUBSCRIPTIONCard attached to a wallet-only subscription without wallet_only: false.Pass wallet_only: false.
409NOT_A_CARD_SUBSCRIPTIONPayment-method on Steam.Not available on Steam.
409PAYMENT_METHOD_UNAVAILABLEThe card was removed concurrently.Pick another card.
404PAYMENT_METHOD_NOT_FOUNDNot this player’s card in this game.Use a card from /player-cards.
400PAYMENT_METHOD_EXPIRED, PAYMENT_METHOD_INVALIDExpired or malformed id.Use an unexpired card id.

Refund (/refund)

HTTPCode or bodyMeaningRemedy
400CLIENT_REQUEST_ID_REQUIRED, CLIENT_REQUEST_ID_INVALID, CLIENT_REQUEST_ID_TOO_LONG, CLIENT_REQUEST_ID_RESERVEDKey invalid.One key per refund, at most 255 chars, not sub_-prefixed.
400INVALID_PERIOD_SEQNot an integer at or above 1.Fix.
404PERIOD_NOT_FOUNDNo such period on this subscription.Check the sequence.
400INVALID_AMOUNTNot a decimal string above zero.Fix.
400AMOUNT_EXCEEDS_REMAINING (+ remaining_refundable_usd, already_refunded_usd)More than is left to refund.Refund at most the remaining amount.
409NO_PAID_PERIODNothing collected yet.Nothing to refund.
409PERIOD_NOT_REFUNDABLE (+ period_status)That period was never collected.Pick a paid period.
409ALREADY_REFUNDED (+ refunded_amount_usd, amount_usd)Fully refunded already.Nothing to do.
409STEAM_REFUND_NOT_SUPPORTEDThe period was charged through Steam. Refused before anything moves.Not supported yet. Wallet-covered periods of a Steam subscription are refundable.
409MINT_ORDER_MISSING, NO_PAYMENT_REFERENCEThe card charge’s record cannot be found.Contact Invo.
409TENANT_ROWS_MISSINGThe period’s settlement rows cannot be found for your game.Contact Invo.
502REFUND_LOOKUP_FAILED, REFUND_MISMATCHNeeds manual attention.Contact Invo.
502PROCESSOR_ERRORThe card processor refused or failed.Retry with the same key; contact Invo if it persists.
503{"error": "service_unavailable"}Temporary.Retry shortly.
503error_code_public: PROCESSOR_NOT_CONFIGUREDCard processor not configured for this environment.Contact Invo.

Card capture (/setup-intent, /setup-intent/confirm, purchase save_card)

HTTPCode or bodyMeaningRemedy
400MISSING_SETUP_REFERENCE, INVALID_SETUP_REFERENCEReference missing or outside the character rules.Send 1 to 200 chars of A-Z a-z 0-9 . _ : -
404PLAYER_NOT_FOUNDThe player does not exist in this game.Create the player first.
409SETUP_REFERENCE_REUSEDSame reference, different parameters.Use a new reference.
400INVALID_PAYMENT_METHOD, CARD_DECLINED, SETUP_FAILEDThe card could not be saved.Ask for another card.
400RAW_CARD_NOT_SUPPORTEDRaw card numbers were sent.Send a tokenised card.
400{"status": "still_requires_action"}The client has not finished confirming.Confirm with the card element, then call confirm again.
500CARD_PERSIST_FAILEDAuthorised but not recorded.Retry /setup-intent/confirm with the same setup_intent_id.
500SETUP_CONFIRMATION_FAILEDConfirm failed unexpectedly.Retry confirm with the same id.
400INVALID_SAVE_CARDsave_card was not a JSON boolean (purchase path).Send true, not "true".

Sandbox clock tools

HTTPCode or bodyMeaningRemedy
401SANDBOX_CLOCK_UNAUTHORIZEDMissing, wrong or never-issued clock key.Reveal the key in the sandbox console (Game Settings) and send X-Sandbox-Clock-Key.
400INVALID_INTERVALS, INVALID_OUTCOMEBody value out of range.intervals 0 to 60; outcome card_declined, insufficient_funds or error.
409SUBSCRIPTION_NOT_LIVETerminal or pending row.Use a live subscription (finalize a pending Steam row first).
409ATTEMPT_IN_FLIGHTAn unresolved attempt.Wait about 30 minutes.
409AUTH_CHALLENGE_OPENA challenge is open.Complete it or let it expire.
409AMOUNT_OVER_CEILINGPrice above 500.00 USD.Lower the price.
409PERIOD_TOO_FAR_AHEADForced twice without advancing.Call advance-clock.
409NO_CHARGEABLE_PERIODNothing due.Call advance-clock.
409WINDOW_ALREADY_PAIDThe window is behind the paid boundary.Create a fresh subscription.
500CLAIM_FAILEDCould not claim the row.Retry.
503FLOW_PAUSEDBilling paused.Retry shortly.
404{"message": "Not found"}You are outside sandbox, or the path has /api in it.Use https://sandbox.invo.network/sandbox/subscriptions/<id>/...

Reporting (/api/subscriptions/reporting/...)

HTTPCode or bodyMeaningRemedy
400WINDOW_INVALIDstart or end missing, unparseable, or end not after start.Send ISO 8601 dates, end after start.
400WINDOW_TOO_LONGRange over 400 days.Narrow the range.
400WINDOW_TOO_LARGE (+ counts)More than 20,000 settled or refunded renewals in the range.Run the report in parts.
400RECIPIENT_INVALIDrecipient_player_id not an integer.Fix.
400SUBSCRIPTION_ID_INVALIDsubscription_id over 50 chars.Fix.
400PAGINATION_INVALIDlimit or offset out of range.Fix.
400STATUS_INVALIDUnknown period status in the history filter.Use pending, paid, failed, forgiven, refunded.
404SUBSCRIPTION_NOT_FOUND, PERIOD_NOT_FOUNDNot on your game.Check the id.

Webhook verification (SDK)

Thrown by verifyWebhook / verify_webhook rather than returned by the API:

CodeMeaningRemedy
WEBHOOK_SIGNATURE_MISSINGNo X-Invo-Signature header.Check the request reached you unmodified.
WEBHOOK_SECRET_MISSINGYou passed no secret.Pass the signing secret from registration.
WEBHOOK_TIMESTAMP_EXPIREDThe signed timestamp is more than 300 seconds from now.Check your clock; do not queue deliveries before verifying.
WEBHOOK_SIGNATURE_INVALIDNo v1 value matched.Verify the raw body bytes, not a re-serialised object; during a rotation pass both secrets.
WEBHOOK_MALFORMEDThe body is not a valid envelope.Check for truncation or a proxy rewriting the body.