Skip to main content

Cards

A SafeBank card is a debit card funded directly by a wallet (a Safe multisig). There is no float and no prefunded balance to top up: at authorization time the card draws USDC from the Safe on-chain. On top of that funding rail you attach software spend limits — per-transaction, daily, weekly, monthly, and MCC allow/block rules — that SafeBank evaluates on every authorization, most-restrictive-wins.

The limit windows are real, rolling accumulators (UTC day, ISO week, calendar month). An approved authorization advances them; a reversal credits them back. When a card has no limits configured, the Safe's on-chain allowance remains the only control — setting limits layers software policy on top.

Key endpoints

MethodPathScopePurpose
POST/v1/wallets/{walletId}/cardscards:issueIssue a Safe-funded card from a wallet (sandbox).
GET/v1/cards/{id}/limitscards:readRead a card's configured limits.
PUT/v1/cards/{id}/limitscards:manageSet limits (per-txn / daily / weekly / monthly / MCC).
POST/v1/cards/{id}/freezecards:manageFreeze — authorizations decline immediately.
POST/v1/cards/{id}/unfreezecards:manageReactivate a frozen card.

See the REST reference for full request/response schemas.

Issue a card

Issue a Safe-funded card straight from a wallet — the card draws USDC from that wallet's Safe. Seed its spend limits in the same call. Sandbox only for now (a Stripe cardholder is minted for your tenant automatically); live issuance requires KYB onboarding.

curl -X POST https://api.sandbox.safebank.ai/v1/wallets/w_1a2b3c/cards \
-H "X-SafeBank-Api-Key: $SAFEBANK_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "dailyUsd": "500.00", "monthlyUsd": "5000.00" }'

Setting limits

Every field on PUT /v1/cards/{id}/limits is optional — only the fields you send are changed. Send an explicit null on a USD cap or on allowedMcc to clear it (unlimited / no allowlist). USD values are decimal strings; MCC entries are 2–4 digit code strings.

curl -X PUT https://api.sandbox.safebank.ai/v1/cards/card_1a2b3c/limits \
-H "X-SafeBank-Api-Key: $SAFEBANK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"perTransactionUsd": "250.00",
"dailyUsd": "500.00",
"weeklyUsd": "2000.00",
"monthlyUsd": "5000.00",
"blockedMcc": ["7995"],
"allowedMcc": ["5411", "5812"]
}'

What a limit breach looks like

When an authorization would exceed a cap or hit a blocked MCC, SafeBank declines it in real time and records the reason. The decline reasons are:

ReasonMeaning
PER_TXN_LIMITAmount exceeds the per-transaction cap.
DAILY_CAP / WEEKLY_CAP / MONTHLY_CAPThe amount would push the rolling window over its cap.
MCC_BLOCKEDThe merchant category is on the block list.
MCC_NOT_ALLOWEDAn allowlist is set and the merchant category isn't on it.
CARD_INACTIVEThe card is frozen.
INSUFFICIENT_SAFE_BALANCEThe funding Safe can't cover the amount.

Freeze and unfreeze

Freezing sets the card inactive at the issuer and in SafeBank, so authorizations decline immediately (CARD_INACTIVE). Unfreeze reverses it — freeze uses a reversible inactive state, never a terminal cancellation.

curl -X POST https://api.sandbox.safebank.ai/v1/cards/card_1a2b3c/freeze \
-H "X-SafeBank-Api-Key: $SAFEBANK_API_KEY"

curl -X POST https://api.sandbox.safebank.ai/v1/cards/card_1a2b3c/unfreeze \
-H "X-SafeBank-Api-Key: $SAFEBANK_API_KEY"