Skip to main content

Errors and Recovery

Every Agentic Payments error is an RFC 7807 Problem Details document whose type is a stable machine-readable code. The code, not the HTTP status, is what your integration should branch on.

Error Response Format

Validation Error
{
"type": "VALIDATION_ERROR",
"title": "Unrecognized key: \"recurring\"",
"status": 400,
"errors": {
"recurring": ["Unrecognized key: \"recurring\""]
}
}
AttributeTypeDescription
typestringStable error code. Branch on this
titlestringHuman-readable summary. For a validation failure, the first message
statusintegerHTTP status code
detailstringPresent where remediation guidance exists, mainly on provider failures
errorsobjectPresent on validation failures. Maps each offending field path to its messages, reporting every failing field rather than only the first

Every response carries a BT-TRACE-ID header. Include it when contacting support. Provider failures may also carry a debug.provider_correlation value for the same purpose. Internal diagnostics, provider response bodies, and credential values never appear in a response body.

These codes apply to every endpoint and are not listed again below. The framing codes are raised before the request body is validated, so no errors map accompanies them and nothing was read:

CodeHTTPMeaning
UNAUTHORIZED401The BT-API-KEY header is missing or invalid
FORBIDDEN403The key is valid but lacks the permission the endpoint requires
NOT_FOUND404No route matches the method and path. A resource that does not exist returns its own *_NOT_FOUND code instead
INVALID_BODY400The body is not parseable JSON, or is empty on a request that requires one
BODY_TOO_LARGE413The body exceeds the maximum accepted size
UNSUPPORTED_MEDIA_TYPE415Send the request as application/json

Classify Before You Retry

Four classes of failure, and the class determines what is safe to do next.

ClassTypical HTTPCredential mint dispatched?AllowanceSafe next action
Invalid request400 or 404NoUnchangedFix the request. If its body changes after an idempotency claim was made, use a new key
Conclusive failureUsually 422; listed pre-dispatch failures may be 500 or 502Either no, or the provider explicitly rejected the mintA mint's reserved amount is cleared, because no credential was issuedAddress the cause. A credential retry is a new operation: use a new key or omit it
Operation in progress409 …_IN_PROGRESSThe current call did not dispatch; the operation already running may haveA mint may be reservedRepeat the exact operation after a delay. Keep the same idempotency key if one was supplied
Unknown outcome409 CREATE_OUTCOME_UNKNOWN or 409 CREDENTIAL_OUTCOME_UNKNOWNPossiblyA credential amount is consumed as spentTreat this operation as terminal. Follow the resource-specific recovery below

Invalid Requests

No credential-provider call was made, so allowance capacity is unchanged. If correcting the request changes its body, use a new idempotency key; a claimed key cannot be reused with a different body.

CodeHTTPMeaning
VALIDATION_ERROR400Body, query, rail and provider pairing, credential format, or verification action failed validation. Read errors
INVALID_TOKEN400source.token_id is not a readable token in this tenant, or the token's type is not card
UNSUPPORTED_PROVIDER400The source has no supported provider for the requested rail (for a card, its network decides), or the rail is not configured for this deployment
RAIL_NOT_FOUND400That rail and provider pair is not present on the resource
RAIL_NOT_ACTIVE400The allowance rail is not active. Complete verification first
NO_ACTIVE_RAILS400The payment method has no enabled rail. Retry a failed payment method rail before creating an allowance
PAYMENT_METHOD_DELETED400The payment method was deleted. Create a new one
ALLOWANCE_CANCELLED400The allowance was cancelled. Create a new one
ALLOWANCE_EXPIRED400The allowance expiration has passed. Expiry is terminal, so create a new allowance
ALLOWANCE_AMOUNT_EXCEEDED400The requested mint exceeds amount_available
VERIFICATION_STATE_INVALID400The verification action is out of order. Restart from start
VERIFICATION_NOT_REQUIRED400That rail has no verification ceremony, so there is nothing to verify. spt allowance rails are active from creation
INVALID_OTP400The code is invalid or expired. Retry the step; the provider enforces the attempt limit
PAYMENT_METHOD_NOT_FOUND404No such payment method in this tenant
AGENT_NOT_FOUND404The supplied agent_id is not an agent in this tenant
ALLOWANCE_NOT_FOUND404No such allowance in this tenant
PAYMENT_CREDENTIAL_NOT_FOUND404No such credential under that allowance

Provider Rejections and Other Conclusive Failures

These errors are conclusive. Some are provider rejections; others prove that the credential request never left Basis Theory. For a credential mint, either no provider request was dispatched or the provider explicitly reported that it issued nothing, so the amount reserved for that mint is cleared and allowance capacity is unchanged. Other operations may persist an error rail that you can retry in place.

Clearing a reservation is not a release capability. It only applies while a mint is in flight and only when Basis Theory can prove no credential was issued. Once a credential mints, its amount is spent permanently: there is no void, release, or refund-to-allowance operation, and the amount is consumed even if the credential is never presented.

CodeHTTPMeaningWhat to do
CARD_REJECTED422The network refused the card during registrationUse a different card. The same card will be refused again
PROVIDER_ENROLLMENT_FAILED422Rail provisioning failed at the providerRetry the payment method rail
RAIL_ENROLLMENT_INVALID422The provider no longer recognizes the primitive this rail was provisioned withRetry the rail. If it fails again, register the source as a new payment method
RAIL_ALREADY_ENROLLED409The provider reports the source as already enrolledUse the existing payment method for this source, or retry the rail
PROVIDER_ALLOWANCE_FAILED422Allowance setup failed at the providerRetry the allowance rail
PROVIDER_ALLOWANCE_UPDATE_FAILED422The provider rejected the allowance update. The local allowance is unchangedCorrect the values and retry
PROVIDER_CREDENTIALS_FAILED422The provider refused to issue the credential, so the reserved amount was cleared and capacity is unchangedReplaying the same key returns this failure. Use a new key for a deliberate new mint attempt
PROVIDER_VERIFICATION_FAILED422The provider rejected or expired the verification session, or rejected the submitted assurance data, such as a passkey assertionRestart verification from start
VERIFICATION_NOT_SUPPORTED422The source cannot complete the ceremony, such as a Mastercard without managed authentication or a Visa card offering no supported code methodFall back to a rail with no verification ceremony, such as spt
PROVIDER_NOT_CONFIGURED422Tenant onboarding for that provider is incompleteContact us. No retry will succeed
MPP_KEY_UNAVAILABLE502The merchant's MPP Card encryption key could not be fetched from its jwksUri: a connection failure, timeout, non-2xx response, oversized body, or unparseable JSON. The credential provider was not called, so the reserved amount was cleared and capacity is unchanged. A jwksUri that breaks one of the safety constraints is a 400 VALIDATION_ERROR insteadVerify the challenge or key service, then make a deliberate new attempt with a new key
UNSUPPORTED_RAIL500Internal: a rail was selected that cannot perform this operationContact us
INTERNAL_ERROR500An unexpected server-side failureRepeat the exact request once, preserving its idempotency key when present; then contact us with the BT-TRACE-ID
PROVIDER_ALLOWANCE_CANCEL_FAILED500A provider-side allowance cancellation failed or could not be confirmed (e.g. at vic). The allowance remains active locallyRepeat the same DELETE; if it fails again, contact us with the BT-TRACE-ID

Rail Error Codes

rails[].error.code on a payment method or allowance is read from this same catalog. CARD_REJECTED, PROVIDER_ENROLLMENT_FAILED, PROVIDER_ALLOWANCE_FAILED, and UNSUPPORTED_PROVIDER are the common ones.

When a provider reports a failure without a code specific enough to classify, the rail records the generic fallback for that operation: PROVIDER_ENROLLMENT_FAILED for payment method provisioning and PROVIDER_ALLOWANCE_FAILED for allowance setup. A rail retry that fails the same way returns it as a 422. Treat either as "this rail failed at its provider for an unclassified reason," read the rail's full history at the resource's /errors endpoint, and retry the rail.

Operations in Progress

Operations that mutate provider state on the same resource are mutually exclusive, so verification, an allowance update, a cancellation, and a credential reservation cannot overlap. A 409 ending in _IN_PROGRESS names the operation holding the resource. All of them mean the same thing: wait briefly and repeat the request.

CodeHTTPOperation holding the resource
IDEMPOTENCY_IN_PROGRESS409Another request with the same idempotency key
ALLOWANCE_VERIFICATION_IN_PROGRESS409Provider verification
ALLOWANCE_UPDATE_IN_PROGRESS409A provider mandate update
ALLOWANCE_DELETE_IN_PROGRESS409Provider cancellation
ALLOWANCE_CREDENTIAL_IN_PROGRESS409A credential mint that has already reserved budget
PAYMENT_METHOD_DELETE_IN_PROGRESS409A payment method deletion cascade
PAYMENT_METHOD_OPERATION_IN_PROGRESS409Another child operation on the payment method
IDEMPOTENCY_CONFLICT409Not an in-progress condition: the key was reused with a different body
CREDENTIAL_PAYLOAD_UNAVAILABLE409Not an in-progress condition: the credential was already returned and cannot be replayed
RAIL_ALREADY_ENROLLED409Not an in-progress condition: the provider reports this source as already enrolled. Repeating unchanged will not help
PAYMENT_METHOD_DELETE_INCOMPLETE409Not an in-progress condition: a previous delete stopped during its cascade. Retry DELETE on that payment method; other operations do not revive it

Only one credential mint can reserve a given allowance at a time. A second operation with a different key or no key returns ALLOWANCE_CREDENTIAL_IN_PROGRESS; a replay of the running mint's supplied key returns IDEMPOTENCY_IN_PROGRESS. Reserving an amount, clearing it, and committing it to spend are atomic conditional writes, so neither path can overspend the mandate.

The Outcome Is Unknown

Basis Theory cannot reliably query any provider to recover a bearer credential or prove that one was not issued, so the API makes a conservative terminal decision.

CodeWhat may have happenedDurable local resultWhat to do
CREATE_OUTCOME_UNKNOWNA payment method or allowance may have committed even though its response was lostThe supplied idempotency key is terminal and cannot create againFor an allowance, list by payment_method_id. For a payment method, filter by consumer_id when you supplied one; otherwise paginate and match the returned consumer and source. If no matching resource exists and you intentionally try again, use a new key
CREDENTIAL_OUTCOME_UNKNOWNThe provider may have issued a spendable credential, but Basis Theory cannot return its bearer valueThe amount is moved to amount_spent; no credential record is created; a supplied key remains terminalDo not retry this operation. Continue with the allowance's remaining capacity, or create a new allowance if necessary
A new key or a keyless retry always means a new operation. After CREDENTIAL_OUTCOME_UNKNOWN, another mint can consume more allowance capacity; it cannot recover the missing credential. After CREATE_OUTCOME_UNKNOWN, list first so you do not create an accidental duplicate.

If a process disappears while a mint is in progress, the allowance can temporarily show the amount in amount_reserved. Once its five-minute operation lease is stale, the next mint, allowance update, cancellation, or verification attempt converts that exact reservation to amount_spent before proceeding. It is never cleared, because the stored state cannot prove that the provider issued nothing.

No reconciliation endpoint exists, and support cannot recover the credential value. A conclusive provider rejection is different: it returns 422, clears the reserved amount, and leaves capacity unchanged.

Idempotency

BT-IDEMPOTENCY-KEY is optional on payment method creates, allowance creates, and credential mints. Supplying it opts into durable retry handling. Unlike the platform-wide default, Agentic retains failed results and does not delete keys after 24 hours. Records are terminal; keys do not expire or become reusable. Without a key, every request is a new operation and an identical retry can create or mint again.

SituationPayment method or allowance createCredential mint
No keyEvery request is a new createEvery request is a new mint and can spend again
Same key and body after successReturns the original resource409 CREDENTIAL_PAYLOAD_UNAVAILABLE; no provider call and no second spend
Same key with a different body409 IDEMPOTENCY_CONFLICT409 IDEMPOTENCY_CONFLICT
Same key while running409 IDEMPOTENCY_IN_PROGRESS; retry the same request later409 IDEMPOTENCY_IN_PROGRESS; retry the same request later
Conclusive failureReplays the same stable code and statusReplays the same stable code and status; use a new key only for a deliberate new attempt
Outcome cannot be determined409 CREATE_OUTCOME_UNKNOWN on every replay409 CREDENTIAL_OUTCOME_UNKNOWN on every replay; capacity is spent

A successful credential replay cannot return the value because spendable credential payloads are never persisted. Calling the provider again would mint a second credential rather than replay the first.

Provider Error History

Both resources keep a paginated history of provider failures, retained for 90 days:

  • GET /agentic/payment-methods/{payment_method_id}/errors
  • GET /agentic/allowances/{allowance_id}/errors

The allowance history includes failed verification attempts and provider-reported credential failures. Both are safe to surface in your own customer-facing UI, because provider response bodies, provider messages, source metadata, and credential values are never included. An unknown mint outcome is reflected in the allowance counters and the mint response instead; it is not a provider-reported failure.

Provider Error Object

AttributeTypeDescription
idstringPrefixed with prv_
codestringStable Agentic Payments error code
titlestringBasis Theory-controlled summary, suitable for display
detailstringBasis Theory-controlled remediation guidance, suitable for display
providerstringvic, agentpay, or stripe
operationstringThe operation that failed, such as credentials or verification
railstringThe rail the operation was performed on
provider_codestringProvider-native machine-readable code, when available. Nullable
provider_correlation_idstringSafe provider correlation identifier for support. Nullable
payment_method_idstringNullable
allowance_idstringNullable
payment_credential_idstringNullable. The generated credential attempt ID. Present even when minting failed and no credential resource exists
occurred_atstringISO 8601 timestamp

A failed mint's payment_credential_id identifies the attempt in Basis Theory's logs; include it when contacting support.

Escalating to Basis Theory

For a declined checkout, start with the merchant, its acquirer, or your payment processor. They hold the authorization response and Basis Theory does not: minting the credential is the last event it observes. See transaction outcomes for why a credential's status never changes.

When you do escalate, send identifiers:

  • The payment method ID, allowance ID, and credential ID
  • The mint or attempt timestamp
  • The amount and currency
  • The merchant name and URL
  • The rail and provider
  • The BT-TRACE-ID from the response
  • Any provider_correlation_id and provider_code from the error history
  • For a decline, the merchant or processor decline code and reference
Never send card numbers, security codes, cryptograms, network tokens, Stripe token values, MPP credentials, or any other credential.value to support, through any channel. These are bearer credentials. Basis Theory does not need them to diagnose anything, and the identifiers above are sufficient.