202 → signed-retry pattern — the same one used by Embedded Wallet
credential revocation and wallet export. This page covers the flow,
what each transition does, and how to handle the signing step.
PATCH /cards/{id} covers freeze / unfreeze (state), funding source
updates (fundingSources), and per-transaction spending limits
(maxSpendPerTransaction). See
Funding sources for the
funding-source-only flow. The signed-retry mechanics below apply to all
fields.
Valid state transitions
Any other transition returns
409 INVALID_STATE_TRANSITION. In
particular, you cannot un-freeze a CLOSED card — close is terminal.
You can also combine a state change with a funding source replacement
in one PATCH — just include both fields in the body.
The signed-retry flow
Each request follows the same two-call shape:Step 1 — initial call
202 Accepted:
Step 2 — signed retry
SignpayloadToSign with the session private key of a verified
authentication credential on the card’s owning internal account, then
retry the same request with the signature and the request id echoed
back:
200 OK with the updated Card and a
CARD.STATE_CHANGE webhook.
The signing flow is identical to the one used by Embedded Wallet
credential revocation. If you’ve already wired that up, you can reuse
the same key-handling code for cards.
What freeze does
Setting a card toFROZEN:
- Causes Authorization Decisioning to decline new auths with
CARD_PAUSED. - Does not pause the lifecycle of authorizations that already passed. Pulls, clearings, and refunds against existing transactions continue to reconcile normally.
- Emits
CARD.STATE_CHANGEwithstate: "FROZEN".
state: "ACTIVE") reverses this — new auths flow normally
again.
What close does
Closing a card is done with the samePATCH /cards/{id} endpoint by
setting state: "CLOSED". The operation is permanent:
- Card state transitions to
CLOSED,stateReason: "CLOSED_BY_PLATFORM". - All pending authorizations reconcile to a terminal state via the existing reconcile primitive.
- Funding-source bindings are detached. Refunds already in flight continue to complete because Lightspark holds the card-reserve keys.
- Inbound clearings received after close follow the standard force-post / late-presentment path — Lightspark absorbs the loss if a post-hoc pull on the now-unbound source fails.
CARD.STATE_CHANGEfires withstate: "CLOSED".
fundingSources cannot be supplied alongside state: CLOSED.
409 CARD_ALREADY_CLOSED is returned if the card is already in the
terminal CLOSED state.
Updating the per-transaction limit
To set or change the per-transaction spending limit:null to clear it. Omitting the field leaves the
current limit unchanged. If the platform config sets
cardConfigs.maxSpendPerTransaction, Grid enforces the lower of the card
and platform values without replacing the card-specific value.
maxSpendPerTransaction cannot be supplied alongside state: CLOSED.