Skip to main content
All validation failures on the Cards API are returned synchronously. Business logic errors are returned as 422 responses with an invalid_parameters array that identifies which fields failed and why, so you can correct the request before retrying.
{
  "code": "validation_error",
  "title": "Validation Error",
  "detail": "One or more request parameters failed validation",
  "invalid_parameters": [ 
     { 
      "parameter": "<param>", 
      "reason": "<reason>" 
     } 
  ]
}
Every mutating request (POST, PATCH, and the action endpoints) requires an Idempotency-Key header. Omitting it returns 400 operation_not_allowed (reason: parameter "Idempotency-Key" in header has an error: value is required but missing). A request body that is not valid JSON returns 400 bad_request with The request body contains malformed JSON.

POST /v0/cards

Creates a card. The card is always created in active status.

Required Fields

ParameterValidation RuleError Reason
account_idRequired objectproperty account_id is missing
entity_idRequired objectproperty entity_id is missing
detailsRequired objectproperty details is missing
details.card_product_nameRequiredproperty card_product_name is missing
details.is_virtualRequiredproperty is_virtual is missing
details.card_typeRequiredproperty card_type is missing
details.expiry_dateRequiredproperty expiry_date is missing
details.last_fourRequiredproperty last_four is missing
Idempotency-Key headerRequired (all mutations)400 operation_not_allowed — parameter Idempotency-Key in header has an error: value is required but missing

Field Validations

ParameterValidation RuleError Reason
entity_idMust match the pattern ^entity_[^\s]{1,33}$String doesn’t match the regular expression ^entity_[^\s]{1,33}$
account_idMust match the pattern ^account_\w+$String doesn’t match the regular expression ^account_\w+$
details.last_fourMust match the pattern ^[0-9]{4}$String doesn’t match the regular expression ^[0-9]{4}$
details.expiry_dateMust be a valid ISO 8601 date (YYYY-MM-DD), expressed as the last day of the expiration monthString doesn’t match the format “date”
details.expiry_dateMust not be earlier than the time of object creation (e.g., if created any time on 2026-06-01 UTC, an expiry_date before 2026-06-01 is rejected)invalid_date
details.card_typeMust be one of hsa, fsa, consumer, commercialvalue is not one of the allowed values ["hsa","fsa","consumer","commercial"]
details.is_virtualMust be a boolean valueValue must be a boolean
details.replacement_forIf provided, must reference a card that exists, is in closed status, is not already referenced by another card, and matches the pattern ^card_\w+$Referenced card must be in closed status to be replaced

Referenced card not found

Replacement for card has already been referenced

String doesn’t match the regular expression ^card_\w+$

Reference Validations

ParameterValidation RuleError Reason
account_idMust reference a valid account whose status is active or inactiveThe account_id referenced by this card does not exist
entity_idMust be linked to the provided account_id as an account_holder or authorized_userThe entity_id is not associated with the referenced account
Creating a card against a closed account is rejected with 400 operation_not_allowed (title “This operation cannot be done on this object.”) rather than a 422, because it is an operation that cannot be performed on the object.

GET /v0/cards/{id}

Retrieves a card by its server-generated ID.
ValidationError
id must match the pattern ^card_\w+$404 not_found: the card ID passed in cannot be found
Card must exist and belong to the caller’s program404 not_found: the requested card was not found

GET /v0/cards?client_card_id={client_card_id}

Retrieves a card by the client-provided client_card_id (for cards created via file ingestion).
ValidationError
client_card_id query parameter is required422 validation_error: parameter client_card_id in query has an error: value is required but missing
client_card_id must not be empty400 bad_request
Card must exist for the caller’s program404 not_found: the requested card was not found

PATCH /v0/cards/{id}

Partial update. Only details.card_product_name and metadata are mutable.
Parameter / RuleBehaviorError Reason
details.card_product_name, metadataMutable — updated when present
Any other field (status, details.expiry_date, details.is_virtual, details.card_type, details.last_four, account_id, entity_id)Silently ignored — the value is not applied, and updated_at is only bumped if a mutable field actually changed— (returns 200)
details.card_product_nameIf provided, must be a non-empty string422 validation_error: details.card_product_nameCard is missing required client_card_product_name field
Card statusA card in closed status cannot be updated422 validation_error: statusCard cannot be updated when status is closed
metadataMust not exceed the DynamoDB item size limit422 validation_error (oversized metadata)
Unlike a create, non-mutable fields sent on a PATCH are ignored rather than rejected (consistent with the Accounts API). A PATCH that changes nothing (empty body, or only non-mutable fields) returns 200 without bumping updated_at.
The status of a card is system-managed and changes only through the three action endpoints below (each takes an Idempotency-Key header):
EndpointAllowed source statesRequired bodyEnforced status_reason enum
POST /v0/cards/{id}/activateinactive, closed— (no body)
POST /v0/cards/{id}/deactivateactive, closedstatus_reasondormant, frozen, other
POST /v0/cards/{id}/closeactive, inactivestatus_reasonentity_closed, client_closed, paid_off, charged_off, canceled

POST /v0/cards/{id}/activate

Validation RuleError Reason
Card must not already be activestatuscard is already active
A card whose expiry_date is in the past cannot be activatedstatuscard is expired and cannot be activated
A card that has been replaced (i.e., its ID has been referenced in the replacement_for field on a separate card) cannot be reactivatedstatuscard has been replaced and cannot be reactivated
Reactivating a closed card clears its closed_at and status_reason.

POST /v0/cards/{id}/deactivate

Validation RuleError Reason
status_reason is requiredproperty status_reason is missing
status_reason must be a valid enum valuevalue is not one of the allowed values ["dormant","frozen","other"]
Card must not already be inactivestatuscard is already inactive
A card that has been replaced (i.e., its ID has been referenced in the replacement_for field on a separate card) cannot be deactivatedstatuscard has been replaced and cannot be deactivated
Deactivating a closed card clears its closed_at and sets the new status_reason.

POST /v0/cards/{id}/close

Validation RuleError Reason
status_reason is requiredproperty status_reason is missing
status_reason must be a valid enum valuevalue is not one of the allowed values ["entity_closed","client_closed","paid_off","charged_off","canceled"]
Card must not already be closedstatuscard is already closed

Authentication

Authentication and scope are enforced at the gateway.
ScenarioError
Using a card/read token to call POST, PATCH, or an action endpoint403 insufficient_scope: you cannot call /v0/cards with the scope card/read
Using an unrelated scope token403 insufficient_scope
Using a missing, malformed, or expired token403