Skip to content

Handle errors and retries ​

Check three things on every call: the HTTP status, GraphQL errors, and the operation's success field. A 200 response can contain a GraphQL error or an unsuccessful operation.

Read the response ​

LayerWhere to lookExamples
HTTPStatus and response body401 authentication failure, 429 endpoint throttle, 503 API unavailable
GraphQLerrors[].message and errors[].extensions.codeSyntax, schema validation, authorization, or processor errors
Operationdata.<operation>.success and its error fieldsProvisioning validation, funding preflight, or webhook persistence failure

Operation envelopes vary. Provisioning and patch responses use errorCode and errorMessage. Application responses use errorCode and error. Many card operations use success and error; processor failures can also raise a top-level GraphQL error. Record queries return rows directly.

An HTTP authentication failure can look like:

json
{ "error": "Unauthorized", "description": "Invalid signature" }

A GraphQL error can look like:

json
{
  "data": null,
  "errors": [{ "message": "Not Authorized", "extensions": { "code": "AUTHENTICATION_ERROR" } }]
}

An operation validation failure can look like:

json
{
  "data": {
    "createPartnerCardUser": {
      "success": false,
      "cardUserId": null,
      "errorCode": "VALIDATION_ERROR",
      "errorMessage": "Invalid input: addressCity is required."
    }
  }
}

Ownership and scope failures return the GraphQL message Not Authorized with extensions.code AUTHENTICATION_ERROR, not HTTP 403. Some webhook and funding-status operations instead return success: false with errorCode: "FORBIDDEN" in the response payload. Depending on the operation, an inaccessible resource can also produce NOT_FOUND or an empty read result.

Fix authentication failures ​

A 401 is not a reason to repeat the same signed request. Check the API token's environment, expiry and revocation state, your clock, and the bytes being signed.

DescriptionCheck
Invalid API keyCorrect token and environment
Invalid signatureCorrect secret; sign the exact sent body
Timestamp outside allowed windowMilliseconds and clock within five minutes
Replay detectedGenerate a fresh timestamp and signature for a new attempt

If the API secret was rotated, replace it immediately; API rotation has no grace period.

Retry without duplicating work ​

Reads can be retried with backoff after transient failures. For mutations, a timeout or lost response can mean the side effect completed. Check the existing resource, job, or transaction before repeating the mutation.

OperationRecovery after an uncertain response
createPartnerCardUserRepeat the same customer organization and email; inspect reused
createPartnerCustomerOrganizationReconcile the customer organization with Agio; name is not an idempotency key
createCardApplicationForPartnerUserQuery the application by applicant_id
createCardQuery the application's cards before another issuance request
multiSendFromWalletReuse the saved idempotency key and immutable batch, then poll its job
cardFundSubClientFromTreasuryPoll a known funding job; if no ID was received, reconcile before another funding request
cardWithdrawForPartnerReconcile collateral history before repeating the operation
subscribePartnerWebhookQuery subscriptions by URL; a duplicate active URL returns a result code

Generate a fresh timestamp and HMAC signature for each retry. This request signature prevents replay; it does not make the business operation idempotent.

For funding and multisend, success: true at enqueue is not settlement. A job in submitted can have an uncertain on-chain outcome. Keep the same job and reconcile it; never replace it merely because confirmation is taking longer than expected.

Throttling and availability ​

Each operation has a per-minute limit per partner organization, and PIN and reveal calls also have one per card. A call over a limit returns the GraphQL error code RATE_LIMITED with extensions.retryAfterSeconds; wait that long before the next call. A refused call does not count against the limit. On HTTP 429 or CARD_RATE_LIMITED, retry with exponential backoff and jitter; do not retry all failed requests simultaneously. CARD_SIGNING_IN_FLIGHT returns retryAfterSec; wait that long before retrying.

Multisend also enforces a per-partner enqueue limit, defaulting to five requests per ten minutes. It returns RATE_LIMITED with retryAfterSec in its operation result.

HTTP 503 means the API is unavailable. Back off before a new request. For mutations, reconcile state first whenever execution may have begun.

Onboarding and card errors ​

These codes can appear in GraphQL errors or in the operation-specific result described above. Branch on the code at the layer that returned it; do not match free-form message text.

CodeAction
GRAPHQL_PARSE_FAILED, GRAPHQL_VALIDATION_FAILED, BAD_USER_INPUTCorrect the operation, fields, types, or enum values
AUTHENTICATION_ERROR (GraphQL error)Check partner ownership and scope
FORBIDDEN (in the operation result)Check partner ownership and supported operation
VALIDATION_ERROR, CARD_INVALID_REQUESTCorrect the named input fields
INCOMPLETE_ADDRESSPatch the cardholder's address before submitting
ATTESTATION_REQUIREDCollect and supply agreement acceptance
APPLICATION_ALREADY_SUBMITTEDStop using the pre-application profile patch
KYC_TOKEN_EXPIREDObtain a fresh share token through your configured KYC flow
KYC_WORKSPACE_NOT_AUTHORIZED, KYC_PROVIDER_NOT_SUPPORTEDContact Agio to verify KYC integration setup
CARD_USER_NOT_FOUND on createCardWait for issuer cardholder data to propagate after approval
MAX_CARDS_REACHEDThe cardholder reached the active-card limit set for your account
CARD_LIMIT_EXCEEDEDThe issuer-side limit was reached; contact Agio
CARD_NOT_FOUND, CARD_INVALID_TYPECheck the numeric Agio ID and card type
CARD_UNAUTHORIZED, CARD_FORBIDDENCheck the card state and program policy
CARD_CONFIG_ERRORContact Agio to verify card-service configuration
CARD_API_ERRORInspect the processor's returned detail and contact Agio if unresolved
CARD_RATE_LIMITEDBack off before the next processor call
RATE_LIMITEDWait extensions.retryAfterSeconds before calling the operation again
CARD_SERVICE_UNAVAILABLE, CARD_TIMEOUT, CARD_NETWORK_ERRORWait, reconcile any mutation outcome, then retry if appropriate

MAX_CARDS_REACHED ("You have reached the maximum number of active cards allowed for your account.") means the cardholder's count of cards that are not canceled or terminated reached the limit configured for your account. Agio sets the limit per account; ask your Agio contact for yours. The error carries extensions.limit and extensions.source.

Funding and withdrawal codes are documented with those operations, and multisend codes distinguish validation from background job failures.

Webhook management errors ​

CodeAction
DUPLICATE_ACTIVE_SUBSCRIPTIONInspect the existing canonical URL; unsubscribe before replacing its event set
INVALID_URLCorrect an unparseable receiver URL
INSERT_FAILEDCheck that the URL is HTTPS and inputs are valid; retry transient persistence failures
UPDATE_FAILEDRetry a transient subscription update failure
ROTATION_RACECoordinate the concurrent secret rotation before trying again
NOT_FOUNDCheck the subscription or delivery ID and your partner scope
SUBSCRIPTION_INACTIVEThe original subscription cannot receive a resend

Next: Review webhook health and delivery history.