> For the complete documentation index, see [llms.txt](https://docs.ur.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ur.app/developer-resources/api-reference-card-mode-crypto-backed.md).

# API reference: Crypto Backed Card

> This document is the Partner-facing API reference for **Card Mode: Crypto Backed**. It covers the three integration surfaces a Partner must implement on top of their chosen Account Mode: **Prefund Account operations**, the **Card Authorization callback** (UR → Partner, synchronous), and the **Card Mode webhooks** (post-swipe and Prefund balance alerts).
>
> For the conceptual definition of Card Mode and how it relates to Account Mode, see [Integration Guide](/getting-started/integration-guide.md#card-mode-where-card-spend-draws-funds-from). For the Account Mode API surfaces this mode plugs into, see [API Reference: Managed Custody Mode](/developer-resources/api-reference-managed-custody-mode.md) or [API Reference: External Wallet Access Mode](/developer-resources/api-reference-external-wallet-access-mode.md).

***

## 1. Mode Context

### 1.1 What Card Mode: Crypto Backed Is

**Card Mode** answers a single question: when the user taps the card, **which balance is debited**?

* **Card Mode: Fiat Only** — the card draws exclusively from the user's UR fiat balance. UR runs the authorization on-chain; the Partner is **not** in the authorization path.
* **Card Mode: Crypto Backed** *(this document)* — the card can settle directly against the user's crypto holdings via a Partner-funded **Prefund Account**, with no per-swipe off-ramp required. UR synchronously consults the Partner at authorization time; the Partner asynchronously debits the user's crypto after a successful swipe.

Card Mode is **orthogonal to Account Mode** — a Partner can pair Crypto Backed with either External Wallet Access Mode or Managed Custody Mode.

### 1.2 The Two Phases

Crypto Backed runs in two phases that operate on different timescales:

| Phase             | Initiator  | Cadence                               | What happens                                                                                                                                                                                                                                                                                     |
| ----------------- | ---------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **1. Prefund**    | Partner    | Scheduled (daily / weekly / on-alert) | Partner tops up crypto into UR's prefund address. UR Ops converts to fiat and credits the Partner's Prefund Account.                                                                                                                                                                             |
| **2. Card spend** | User (tap) | Real-time                             | Mastercard routes the auth to UR → UR calls Partner webhook → Partner returns approve + source → UR settles against Prefund Account (CRYPTO path) or user's UR fiat balance (FIAT path) → after Mastercard finalizes, UR sends a post-swipe webhook to the Partner → Partner debits user crypto. |

The Prefund Account exists to absorb real-time card authorizations: Partners cannot bridge user crypto fast enough to meet Mastercard's 1.5 s authorization window, so UR is pre-funded and the Partner reconciles asynchronously.

### 1.3 What This Document Covers vs. Doesn't

**This document covers** — Partner-facing surfaces that exist only in Card Mode: Crypto Backed:

* [§3 Prefund Account](#id-3-prefund-account) funding flow + balance API
* [§4 Card Authorization callback (UR → Partner, synchronous)](#id-4-card-authorization-callback-ur-greater-than-partner)
* [§5 Card Mode webhooks](#id-5-card-mode-webhooks) (post-swipe transaction + Prefund balance alert)
* [§6 Implementation checklist](#id-6-implementation-checklist)

**This document does NOT cover** — endpoints that are common to both Card Modes (Create Card, Get Card Info, Set Default Currency, Card history). Those live in the Account Mode API reference under the Card section:

* Managed Custody Partners → [API Reference: Managed Custody Mode §11](/developer-resources/api-reference-managed-custody-mode.md#id-11-card)
* External Wallet Access Partners → [API Reference: External Wallet Access Mode](/developer-resources/api-reference-external-wallet-access-mode.md#id-3-card)

### 1.4 Partner Prerequisites

Before integrating Card Mode: Crypto Backed, the Partner must have:

* An Account Mode chosen and operational (External Wallet Access or Managed Custody).
* The ability to make an **initial crypto prefund** to seed card spending capacity.
* The ability to **schedule periodic crypto top-ups** to UR's prefund address on a supported chain.
* The ability to respond to the Card Authorization callback within **500 ms** with valid Partner Auth signatures.
* The ability to **reliably debit user crypto after the swipe is approved** — typically via a smart contract wallet under the Partner's programmatic control, or centralized custody, so the user cannot move the crypto between approval and debit. UR does not enforce this on the Partner's behalf.
* Operational tolerance for **working-float management** — if the Prefund Account drains below the minimum balance, authorizations begin to decline.

***

## 2. API Foundation

This document inherits the API foundation defined in the Account Mode reference — base URLs, Partner Auth (EIP-191) headers, response envelope, idempotency rules. See:

* Managed Custody Partners → [API Reference: Managed Custody Mode §2](/developer-resources/api-reference-managed-custody-mode.md#id-2-api-foundation)
* External Wallet Access Partners → [API Reference: External Wallet Access Mode](/developer-resources/api-reference-external-wallet-access-mode.md#id-1-overview)

Two header-block shorthands are used below:

* **Partner-Scoped Partner Auth Headers** — `X-Api-Signature` + `X-Api-Deadline` + `X-Api-PublicKey`, **no** user identity. Used for Prefund Account endpoints ([§3](#id-3-prefund-account)).
* **UR-Signed Inbound** — for requests where UR calls the Partner ([§4](#id-4-card-authorization-callback-ur-greater-than-partner) callback and [§5](#id-5-card-mode-webhooks) webhooks), UR signs the body with EIP-191 using UR's signer key. The Partner must verify the signature against UR's public key before acting on the payload.

***

## 3. Prefund Account

> **Scope:** Partner-scoped (not user-scoped). One Prefund Account per Partner, regardless of how many users the Partner has onboarded.

### 3.1 What the Prefund Account Is

The Prefund Account is a Partner-level operational funding account used to settle card swipes that the Partner has marked as `sourceUsed: CRYPTO`. The Partner funds it; UR debits it during card settlement; the Partner asynchronously debits the user's crypto to replenish its own books.

It is **not**:

* A user balance — users cannot see it, cannot deposit to it, and cannot withdraw from it.
* A real-time authorization gate the Partner queries per swipe. Use it for **operational monitoring only**; UR performs Prefund availability checks inside the Card Authorization flow ([§4](#id-4-card-authorization-callback-ur-greater-than-partner)).

### 3.2 Funding the Prefund Account

```mermaid
sequenceDiagram
    participant Partner as Partner Treasury
    participant DepAddr as UR Prefund Deposit Address
    participant Ops as UR Ops
    participant Pre as Prefund Account<br/>(Partner-scoped)

    Note over Partner, Pre: Scheduled top-up (daily / weekly / balance-monitor trigger)
    Partner->>DepAddr: 1. Send crypto top-up
    Ops->>Ops: 2. Off-ramp crypto → settlement fiat
    Ops->>Pre: 3. Credit Prefund Account balance
```

**Currently supported:**

* **Prefund USDC on supported chains:** You can deposit USDC on any UR [Supported Chains](https://docs.ur.app/developer-resources/pages/yEG7tyYvgaB42helZKpJ#id-3.1.9-get-supported-chain-config)
* **Settlement currency:** `USD` — the Prefund Account is held on Mantle as a `USD`-denominated tokenized fiat balance.
* **Minimum balance:** agreed with UR during onboarding. UR emits `prefund.balance.alert` ([§5.5](#id-5.5-prefund-balance-alert-event-prefund.balance.alert)) when `balance ≤ minBalance`.

Operational constraints:

* **Confirm the deposit address with UR before every production funding setup.** UR may rotate addresses; sending to a stale address can result in funds being held in operations.
* **Do not assume deposits are instantly reflected.** Crypto-to-fiat off-ramping is asynchronous; monitor the Prefund Balance API ([§3.3](#id-3.3-get-prefund-balance)) and the `prefund.balance.alert` webhook ([§5.5](#id-5.5-prefund-balance-alert-event-prefund.balance.alert)).
* **Maintain a buffer above the minimum balance.** Each `prefund.balance.alert` indicates the Partner is now exposed to authorization decline risk on the next swipe. Plan top-up SLA accordingly.

### 3.3 Get Prefund Balance

| Item    | Value                               |
| ------- | ----------------------------------- |
| Method  | `GET`                               |
| Path    | `/api/fma/v1/prefund-balance`       |
| Headers | Partner-Scoped Partner Auth Headers |

This endpoint is **partner-scoped**, not user-scoped. It returns the current state of the Partner's Prefund Account.

Request body: none. Query parameters: none.

Response example:

```json
{
  "code": 0,
  "message": "",
  "data": {
    "partnerId": "partner_id",
    "account": "0xPrefundAccAddress",
    "currency": "USD",
    "balance": "125000.00",
    "minBalance": "50000.00",
    "level": "normal",
    "updatedAt": 1713700000
  }
}
```

Response fields:

| Field        | Description                                                                               |
| ------------ | ----------------------------------------------------------------------------------------- |
| `partnerId`  | Partner identifier registered with UR.                                                    |
| `account`    | On-chain address of the Prefund Account (Mantle).                                         |
| `currency`   | Prefund settlement currency: `USD` (see [§3.2](#id-3.2-funding-the-prefund-account)).     |
| `balance`    | Current balance in settlement currency, decimal string.                                   |
| `minBalance` | Minimum balance threshold; `prefund.balance.alert` fires at or below this value.          |
| `level`      | `"normal"` \| `"warning"` (≤ `minBalance`) \| `"critical"` (severely below `minBalance`). |
| `updatedAt`  | Unix seconds, last balance update.                                                        |

Usage recommendations:

* **Polling cadence** — operational dashboard cadence, e.g. no more frequently than once per minute unless UR advises otherwise.
* **Authoritative source** — treat this endpoint as the source of truth for `balance` and `minBalance`. Webhook payloads are eventually consistent.
* **Reactive pattern** — use `prefund.balance.alert` ([§5.5](#id-5.5-prefund-balance-alert-event-prefund.balance.alert)) as a passive trigger; call this endpoint to confirm current state before initiating a top-up.
* **Not for authorization decisions** — do not call this endpoint from inside the Card Authorization callback ([§4](#id-4-card-authorization-callback-ur-greater-than-partner)). UR already performs Prefund availability checks before approving. Adding a Partner-side check increases your 500 ms callback latency for no benefit.

***

## 4. Card Authorization Callback (UR → Partner)

> **Scope:** Required only for Card Mode: Crypto Backed. Card Mode: Fiat Only Partners are not in the authorization path at all.

When the user taps the card, UR **synchronously** calls a Partner-hosted authorization endpoint. The Partner returns an approval decision and a settlement-source recommendation; UR then performs final balance, limit, compliance, and Prefund checks before responding to Mastercard.

### 4.1 Endpoint Contract

The Partner hosts an endpoint at a URL registered with UR during onboarding (e.g. `https://api.partner.example/ur/card-authorizations`). UR calls it on every card authorization for users whose accounts are configured with Card Mode: Crypto Backed.

| Item           | Value                                                                                                                                      |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| Method         | `POST`                                                                                                                                     |
| Path           | Partner-hosted (registered with UR during onboarding)                                                                                      |
| Direction      | **UR → Partner**                                                                                                                           |
| Auth           | UR-Signed Inbound (EIP-191; verify against UR's public key)                                                                                |
| Latency budget | **≤ 500 ms** Partner response time. UR allocates the remaining \~1 s for internal checks within Mastercard's \~1.5 s authorization window. |
| Failure mode   | Timeout / 5xx / signature-verification failure / invalid response → UR treats as **DECLINE** for this swipe.                               |

The Partner's authorization endpoint should be **low-latency, idempotent, auditable, and fail-safe**. Treat the 500 ms budget as a hard ceiling — design for p99 well under it.

### 4.2 Flow

```mermaid
sequenceDiagram
    participant MC as Mastercard Network
    participant UR as UR
    participant Partner as Partner Backend
    participant Pool as Prefund Account
    participant UserBal as User UR Fiat Balance

    MC->>UR: 1. Authorization request (user taps card)
    UR->>Partner: 2. Authorization callback
    Partner-->>UR: 3. { approve, settleCurrency }
    UR->>UR: 4. Final checks: balance, limit, compliance, Prefund availability
    alt approve = true AND UR checks pass
      alt settleCurrency = USD
        UR->>Pool: 5a. Book against Prefund Account
      else other supported currency
        UR->>UserBal: 5b. Book against user UR fiat balance
      end
      UR-->>MC: 6. APPROVED (within 1.5s)
    else any decline
      UR-->>MC: 6. DECLINED
    end
    Note over UR, Partner: Result follow-up (§5.4)
    UR->>Partner: 7. transaction_v2 webhook<br/>(MARQETA_AUTHORIZE)
    opt Prefund Account was used and approved
      Partner->>Partner: 8. Debit equivalent crypto from user
    end
```

### 4.3 Request Body (UR → Partner)

UR sends the following JSON body when calling the Partner's authorization endpoint:

```json
{
  "eventId": "auth_0123456789",
  "urId": 7123456789,
  "externalUserId": "partner-user-0001",
  "amount": "25.00",
  "currency": "EUR",
  "merchant": {
    "name": "Merchant ABC",
    "mcc": 5812,
    "country": "CH"
  },
  "cardTokenId": "106654866313",
  "timestamp": 1713700000
}
```

Field reference:

| Field              | Type                        | Description                                                                                                                           |
| ------------------ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `eventId`          | string                      | UR-generated idempotency key for this authorization attempt. The Partner must respond identically to retries with the same `eventId`. |
| `urId`             | number                      | User's URID.                                                                                                                          |
| `externalUserId`   | string                      | Partner's user ID mapped during onboarding.                                                                                           |
| `amount`           | string (decimal)            | Authorization amount, denominated in `currency`.                                                                                      |
| `currency`         | string (ISO 4217)           | Transaction currency requested by the merchant.                                                                                       |
| `merchant.name`    | string                      | Merchant name from the Mastercard message.                                                                                            |
| `merchant.mcc`     | number                      | Merchant category code.                                                                                                               |
| `merchant.country` | string (ISO 3166-1 alpha-2) | Merchant country.                                                                                                                     |
| `cardTokenId`      | string                      | UR token ID identifying the card.                                                                                                     |
| `timestamp`        | number                      | Unix seconds when UR received the authorization from Mastercard.                                                                      |

### 4.4 Response Body (Partner → UR)

The Partner returns one of two response shapes.

**Approval:**

```json
{
  "approve": true,
  "settleCurrency": "USD",
  "reason": "ok"
}
```

**Decline:**

```json
{
  "approve": false,
  "settleCurrency": null,
  "reason": "insufficient_user_crypto"
}
```

Response field reference:

| Field            | Required   | Description                                                                                                                                                                                                                                                       |
| ---------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `approve`        | Yes        | `true` to approve, `false` to decline.                                                                                                                                                                                                                            |
| `sourceUsed`     | On approve | `"CRYPTO"` → settle via the Prefund Account (Partner will debit user crypto post-swipe). `"FIAT"` → settle from the user's UR fiat balance directly.                                                                                                              |
| `settleCurrency` | On approve | Fiat ISO code for the settlement currency. For `sourceUsed: CRYPTO`, this must be `USD` (the Prefund Account currency; see [§3.2](#id-3.2-funding-the-prefund-account)). For `sourceUsed: FIAT`, this must be a currency the user holds in their UR fiat balance. |
| `reason`         | Yes        | A short code; see [§4.6](#id-4.6-recommended-reason-codes). UR logs this for reconciliation.                                                                                                                                                                      |

Important behavior:

* The Partner decides only `approve` + `sourceUsed` + `settleCurrency` + `reason`. **UR retains final authority** — UR still performs balance / limit / compliance / Prefund availability checks after the Partner response and can decline an approved swipe if any of those fail.
* The Partner **cannot use `sourceUsed: CRYPTO` to overdraft the Prefund Account** — UR's Prefund availability check will decline if the swipe would take the Prefund Account below operational minimums.
* If the Partner responds with `sourceUsed: FIAT`, the swipe behaves exactly like a Card Mode: Fiat Only swipe — UR debits the user's tokenized fiat balance directly, and no post-swipe Partner crypto debit is required.
* The Partner should **not** call `GET /prefund-balance` ([§3.3](#id-3.3-get-prefund-balance)) from inside this handler — see [§3.3](#id-3.3-get-prefund-balance) "Not for authorization decisions".

### 4.5 Fail-Safe Semantics

UR treats the following as **DECLINE** (the Partner's authorization endpoint is considered unavailable):

| Failure                                                                | UR action                                                                              |
| ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| HTTP timeout (no response within 500 ms)                               | Decline with internal reason `partner_timeout`                                         |
| HTTP 5xx                                                               | Decline with internal reason `partner_5xx`                                             |
| HTTP 4xx                                                               | Decline with internal reason `partner_4xx` (likely Partner config error — investigate) |
| Invalid signature on response                                          | Decline with internal reason `partner_sig_invalid`                                     |
| Response body fails schema validation                                  | Decline with internal reason `partner_invalid_response`                                |
| Partner returns `approve: true` but `sourceUsed` is missing or unknown | Decline with internal reason `partner_invalid_source`                                  |

UR exposes the internal decline reason on the post-swipe transaction webhook ([§5.4](#id-5.4-transaction-event-post-swipe-event-transaction-data.type-crd)) for reconciliation.

**Operational note on the authorization URL.** The Partner-hosted authorization URL is registered with UR during onboarding. To update it (e.g. environment migration), coordinate the change with UR — there is no self-serve endpoint for this. UR will reject calls that fail signature verification, so URL changes must be paired with key/cert validation on the Partner side.

### 4.6 Recommended `reason` Codes

The `reason` field is a free-form short code used for reconciliation and analytics. UR recommends the following standard set; Partners may add custom codes for internal categorization but should not overload the standard codes' meanings.

| `reason`                       | When to use                                                                                                                                           |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ok`                           | Approve (`approve: true`).                                                                                                                            |
| `insufficient_user_crypto`     | User does not have enough crypto on the Partner side to cover a CRYPTO settlement.                                                                    |
| `insufficient_partner_prefund` | Partner's Prefund Account is too low to safely cover this swipe. (UR will also decline on its own check; this code is for Partner-side optimization.) |
| `insufficient_user_fiat`       | User has insufficient tokenized fiat for a FIAT settlement.                                                                                           |
| `user_blocked`                 | Partner-side compliance block on this user.                                                                                                           |
| `merchant_blocked`             | Partner-side MCC / merchant block.                                                                                                                    |
| `card_disabled`                | Card is locked or frozen on the Partner side.                                                                                                         |
| `internal_error`               | Catch-all decline; treat as transient.                                                                                                                |

***

## 5. Card Mode Webhooks

UR delivers Card Mode events via the standard webhook envelope. The Partner must verify every webhook signature before acting on it.

### 5.1 Webhook Envelope

```json
{
  "event": "<event-type>",
  "data": {},
  "timestamp": 1704234567
}
```

### 5.2 Signature Verification

UR signs webhook bodies with EIP-191. Verification steps:

1. Read the **exact raw request body string** (do not re-serialize).
2. Recover the signer address using the body and `X-Api-Signature`.
3. Accept the event only if the signer address matches the **UR public key** provided out of band.

See [Signature and Verification](/developer-resources/signature-and-verify.md) for the canonical recovery algorithm.

### 5.3 Retry and Idempotency

* The Partner should return `HTTP 200` within **10 seconds**.
* UR retries non-200 / timed-out webhook deliveries **up to 3 times**, with a **5-minute interval**.
* Use `data.id` as the idempotency key for card payment `transaction_v2` events.

### 5.4 Card payment transaction (`event: "transaction_v2"`)

UR sends `transaction_v2` when a card payment transaction reaches a terminal state. Card payment records use `data.type = "MARQETA_AUTHORIZE"`. The same event covers successful and failed card payments.

Confirmed payment example:

```json
{
  "event": "transaction_v2",
  "data": {
    "id": 353244,
    "txHash": "0x30e3...",
    "blockNumber": 39376686,
    "createTimeE9": 1780298041358000000,
    "broadcastTimeE9": 1780298041358000000,
    "finalTimeE9": 1780298045000000000,
    "type": "MARQETA_AUTHORIZE",
    "chainId": "eip155:5003",
    "chainName": "MNT",
    "urId": "6570621322",
    "direction": "OUT",
    "amount": "0.06",
    "currency": "usd",
    "status": "CONFIRMED",
    "detailsJson": "{\"authorizationId\":\"card-auth-0001\",\"balance\":\"12360572.18\",\"cardCurrency\":\"USD\",\"cardId\":\"card-id-0001\",\"city\":\"Singapore\",\"country\":\"SGP\",\"mcc\":\"7299\",\"merchant\":\"Merchant ABC\",\"merchantId\":\"merchant-0001\",\"settlementAmount\":\"0.06\",\"settlementCurrency\":\"EUR\",\"transactionAmount\":\"0.06\",\"transactionCurrency\":\"USD\"}"
  },
  "timestamp": 1780298051
}
```

Failed payment example:

```json
{
  "event": "transaction_v2",
  "data": {
    "id": 353245,
    "txHash": "0x9eec...",
    "blockNumber": 96571332,
    "createTimeE9": 1781272976000000000,
    "broadcastTimeE9": 1781272976000000000,
    "finalTimeE9": 1781272976000000000,
    "type": "MARQETA_AUTHORIZE",
    "chainId": "eip155:5000",
    "chainName": "MNT",
    "urId": "4596332147",
    "direction": "OUT",
    "amount": "15.39",
    "currency": "cnh",
    "status": "FAILED",
    "detailsJson": "{\"authorizationId\":\"card-auth-0002\",\"merchantId\":\"merchant-0002\",\"merchant\":\"Merchant ABC\",\"mcc\":\"5999\",\"city\":\"Shanghai\",\"country\":\"CHN\",\"cardId\":\"card-id-0002\",\"cardCurrency\":\"USD\",\"transactionCurrency\":\"CNH\",\"settlementCurrency\":\"EUR\",\"transactionAmount\":\"15.39\",\"settlementAmount\":\"1.97\",\"reason\":\"Insufficient USD24 allowance\"}"
  },
  "timestamp": 1781272979
}
```

Key fields for Crypto Backed reconciliation:

| Field                 | Description                                                                                    |
| --------------------- | ---------------------------------------------------------------------------------------------- |
| `id`                  | UR transaction record ID. Use this field as the idempotency key for `transaction_v2` delivery. |
| `type`                | Card payment transactions use `MARQETA_AUTHORIZE`.                                             |
| `status`              | Terminal transaction status, such as `CONFIRMED` or `FAILED`.                                  |
| `direction`           | `OUT` for card spend.                                                                          |
| `amount` / `currency` | Amount and currency recorded on the transaction row.                                           |
| `txHash`              | On-chain transaction hash when available.                                                      |
| `detailsJson`         | Stringified JSON with card payment details. Parse this value before reading nested fields.     |

`detailsJson` may include the following card payment fields:

| Field                 | Description                                                                             |
| --------------------- | --------------------------------------------------------------------------------------- |
| `authorizationId`     | Card authorization identifier.                                                          |
| `balance`             | Balance value recorded with the card payment.                                           |
| `cardCurrency`        | Card currency.                                                                          |
| `cardId`              | Card identifier.                                                                        |
| `city`                | Merchant city.                                                                          |
| `country`             | Merchant country.                                                                       |
| `mcc`                 | Merchant category code.                                                                 |
| `merchant`            | Merchant display name.                                                                  |
| `merchantId`          | Merchant identifier.                                                                    |
| `settlementAmount`    | Settlement amount recorded for the card payment.                                        |
| `settlementCurrency`  | Settlement currency recorded for the card payment.                                      |
| `transactionAmount`   | Merchant transaction amount.                                                            |
| `transactionCurrency` | Merchant transaction currency.                                                          |
| `reason`              | Failure reason. This field appears only when the card payment record includes a reason. |

**Partner crypto-debit responsibility.** When a Crypto Backed card payment succeeds, the partner is responsible for computing and debiting the corresponding user crypto amount in its own system. UR reports the card payment transaction data; UR does not move user crypto on the partner's behalf.

Use `transaction_v2` records with `data.type = "MARQETA_AUTHORIZE"` and `data.status = "FAILED"` for failed card payments. The failure reason is in `detailsJson.reason` when UR has one.

***

## 6. Implementation Checklist

Before going live with Card Mode: Crypto Backed:

**Prefund operations**

* Confirm the deposit chain, deposit currency and the minimum balance (agreed during onboarding) for your integration.
* Confirm the current production deposit address with UR.
* Implement scheduled top-up automation with SLA aligned to your minimum-balance buffer.
* Build an operational dashboard that polls `GET /prefund-balance` and surfaces `level` transitions.
* Subscribe to `prefund.balance.alert` ([§5.5](#id-5.5-prefund-balance-alert-event-prefund.balance.alert)) and route to your ops channel.

**Card Authorization callback**

* Host the authorization endpoint at the URL registered with UR (see operational note in [§4.5](#id-4.5-fail-safe-semantics)).
* Verify every inbound request's EIP-191 signature against UR's public key before doing any business logic.
* Implement the handler with a **p99 < 500 ms** budget. Pre-compute everything you can; avoid cross-region database calls in the hot path.
* Decide `sourceUsed` deterministically — typically check user crypto balance first, fall back to user fiat balance, otherwise decline.
* Make the handler **idempotent on `eventId`** — UR may retry on transient network errors.
* Build a fail-safe path: if any internal dependency fails, return `approve: false` with `reason: "internal_error"` rather than 5xx — UR treats 5xx as decline anyway, but explicit declines preserve `reason` for reconciliation.

**Post-swipe + reconciliation**

* Subscribe to `transaction` webhooks ([§5.4](#id-5.4-transaction-event-post-swipe-event-transaction-data.type-crd)); verify signatures.
* For `sourceUsed: CRYPTO, status: completed`, perform the user-side crypto debit and record it against the same `eventId`.
* Handle the override case: Partner returned `approve: true` but UR returned `status: declined` — clean up any speculative Partner-side state.
* Decide your refund policy ([§6](#id-6-refund-handling)) and document it for end users.

**Operational**

* Treat webhook delivery as **at-least-once** and implement idempotency on `eventId` (transactions) and `account + updatedAt` (Prefund alerts).
* Maintain monitoring on Partner-side authorization handler latency, success rate, and decline reason distribution.

***

## 8. Reference Docs

* [Integration Guide](/getting-started/integration-guide.md) — Account Mode × Card Mode framing.
* [API Reference: Managed Custody Mode](/developer-resources/api-reference-managed-custody-mode.md) — common card endpoints (Create Card, Get Card Info, Set Default Currency, history) and the Account Mode this plugs into.
* [API Reference: External Wallet Access Mode](/developer-resources/api-reference-external-wallet-access-mode.md) — the alternative Account Mode this can pair with.
* [Signature and Verification](/developer-resources/signature-and-verify.md) — EIP-191 signing and verification for Partner Auth and webhook signatures.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.ur.app/developer-resources/api-reference-card-mode-crypto-backed.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
