API reference: Crypto Backed Card

Prefund operations, card authorization callback, and card webhooks for Crypto Backed mode.

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. For the Account Mode API surfaces this mode plugs into, see API Reference: Managed Custody Mode or API Reference: External Wallet Access Mode.


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:

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:

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:

Two header-block shorthands are used below:

  • Partner-Scoped Partner Auth HeadersX-Api-Signature + X-Api-Deadline + X-Api-PublicKey, no user identity. Used for Prefund Account endpoints (§3).

  • UR-Signed Inbound — for requests where UR calls the Partner (§4 callback and §5 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).

3.2 Funding the Prefund Account

Currently supported:

  • Prefund USDC on supported chains: You can deposit USDC on any UR Supported Chains

  • 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) 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) and the prefund.balance.alert webhook (§5.5).

  • 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:

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).

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) 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). 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

4.3 Request Body (UR → Partner)

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

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:

Decline:

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). For sourceUsed: FIAT, this must be a currency the user holds in their UR fiat balance.

reason

Yes

A short code; see §4.6. 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) from inside this handler — see §3.3 "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) 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.

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

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 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.txHash or data.id (for transaction events) and data.account + data.updatedAt (for Prefund alerts) as idempotency keys.

5.4 Transaction Event — Post-Swipe (event: "transaction", data.type: "CRD")

This is the follow-up that closes the loop after the Card Authorization callback (§4). It carries the final settlement state of the swipe — including any UR-side decline that overrode the Partner's approve: true response.

Payload example:

Key fields for Crypto Backed reconciliation:

Field
Description

eventId

The same eventId UR sent in the Card Authorization callback (§4.3) — primary idempotency key.

status

"completed" | "declined" | "reversed".

sourceUsed

The actual source UR used. For declines, may be null.

settleCurrency / settleAmount

The settlement currency UR booked the swipe in, and the amount in that currency (after FX from amount / currency). For sourceUsed: CRYPTO, this is the Prefund Account debit amount; the Partner should use it to compute how much crypto to debit from the user.

declineReason

Populated when status: "declined". Values include UR-internal decline codes (partner_timeout, insufficient_prefund, etc.) and Partner-supplied reason from §4.6.

Partner crypto-debit responsibility. When status: completed and sourceUsed: CRYPTO, the Partner is responsible for:

  1. Computing the crypto amount to debit from the user based on its own pricing / conversion logic. UR reports the fiat settleAmount; UR does not prescribe the crypto-to-fiat conversion rate the Partner uses.

  2. Performing the on-chain (or custody-side) crypto debit. UR does not move crypto on the Partner's behalf.

  3. Recording the debit against the same eventId for reconciliation.

How the Partner enforces the debit (smart-contract-wallet pre-authorization, centralized custody freeze + debit, etc.) is part of the Partner's own business logic and is out of scope for this document.

5.5 Prefund Balance Alert (event: "prefund.balance.alert")

UR emits this event when the Prefund Account reaches warning conditions.

Trigger behavior:

  • UR sends level = "warning" when balance ≤ minBalance.

  • While the balance remains at or below minBalance, UR may resend the alert after every Prefund debit (i.e. after every CRYPTO-path card swipe).

  • Alerts stop after the balance returns above minBalance.

Payload example:

Recommended handling:

  • Store the alert idempotently (key on account + updatedAt).

  • Confirm with the authoritative API — call GET /api/fma/v1/prefund-balance (§3.3) before acting; webhook payloads are eventually consistent.

  • Notify the Partner operations channel if level = "warning" or "critical".

  • Trigger top-up workflows — at warning, schedule a top-up; at critical, escalate.


6. Refund Handling

Any card refund is credited to the user's UR fiat balance, regardless of whether the original swipe was settled from the Prefund Account (sourceUsed: CRYPTO) or from the user's fiat balance (sourceUsed: FIAT).

Implications for Crypto Backed Partners:

  • A refund for a CRYPTO-path swipe does not automatically reverse the Partner's user-side crypto debit. The Partner must decide its own policy — credit equivalent crypto back to the user, leave the fiat refund as a UR fiat balance, or surface the choice to the user.

  • The refund is delivered as a transaction event with data.type = "CRD", direction = "IN", and a originalEventId field linking to the original swipe.

Payload sketch:


7. 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) 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).

  • 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); 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) 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

Last updated