API reference: Managed Custody Mode

Core banking API reference for partners integrating via Managed Custody Mode.

This document is the Core Banking OpenAPI reference for Partners integrating with UR in Managed Custody Mode. Section 3 covers onboarding for Partners whose users complete KYC in the Partner's Sumsub flow and share that verification with UR through Sumsub reuse. Fund-moving APIs still require the user's UR account to be Live and the mapped Partner user to exist.

For the conceptual definition of Managed Custody Mode and how it compares to External Wallet Access Mode, see Integration Guide.


1. Mode Context

1.1 Where This API Sits

Managed Custody Mode is one of UR's two Account Modes. In this mode:

  • The user's UR account (URID + tokenized fiat balances) lives inside a UR-managed embedded wallet.

  • The Partner backend accesses that account entirely through REST APIs, signed with the Partner's signer key.

  • Routine banking actions (FX, Pay-in, Payout, On-ramp, Off-ramp, Card) are submitted by the Partner's backend; UR validates, runs compliance / risk / limit checks, and executes the on-chain settlement using UR's wallet infrastructure.

  • The user is not prompted to sign on-chain transactions for routine banking actions.

The Partner owns the entire UX surface; UR is the regulated banking infrastructure underneath.

1.2 Operation Layer Map

Every Core Banking endpoint maps to one of UR's six core operations. This table is the canonical anchor for the rest of this document.

Operation
Direction
Endpoint family
Settlement

On-ramp

User fiat → crypto (out to a target chain)

Async via webhook

Off-ramp

Crypto (from external chain) → user fiat

Async via webhook

FX

One fiat token → another fiat token

On-chain, near-instant; webhook confirms

Pay-in

External bank → user IBAN

Covered in Deposits

Async (SEPA/SWIFT)

Payout

User fiat → external bank

Async (SEPA/SWIFT)

Card

User → merchant via Mastercard

Real-time authorization, async settlement

Read-only endpoints (Profile §5, Balance §6, Transactions §12) sit beside these operations.


2. API Foundation

2.1 Base URLs

Environment
Base URL

Production

https://openapi.ur.app

Preview

https://openapi-preview.ur.app

Testnet

https://uropenapi-qa.ur-inc.xyz

Confirm the exact base URL set with UR before production rollout.

2.2 Authentication — Partner Auth (EIP-191)

All authenticated Partner → UR requests use Partner Auth with EIP-191 signatures.

Every authenticated request must include:

Header
Required
Description

X-Api-Signature

Yes

0x-prefixed 65-byte hex signature over the canonical request payload, produced with the Partner signer's private key.

X-Api-Deadline

Yes

Unix seconds. UR rejects the request if now > deadline. Recommended validity window ≤ 5 min.

X-Api-PublicKey

Yes

The Partner signer address (0x-prefixed). Must be registered with UR.

Canonical payload:

  • GET requests sign the raw query string exactly as sent, without the leading ?.

  • Non-GET requests sign the raw request body exactly as sent.

  • Append the user identity suffix to that payload before signing: urId:{X-Ur-Id}externalUserId:{X-External-User-Id}. If a header is not sent, use an empty value in its slot.

For example, a POST body of {"amount":"100"} with X-Ur-Id: 7123456789 and no X-External-User-Id signs:

For the EIP-191 recovery algorithm, see Signature and Verification.

2.3 User Identity Headers

Every user-scoped Partner → UR endpoint must identify the user with at least one of the following headers.

Header
Description

X-Ur-Id

The user's URID (numeric token ID of the URID NFT).

X-External-User-Id

The Partner's own user ID, mapped to a URID during onboarding.

Rules:

  • Send at least one of X-Ur-Id or X-External-User-Id. Sending neither is invalid.

  • Sending both is allowed. When both are present, UR resolves the user by X-Ur-Id first.

  • User identity must not be duplicated in query parameters or request bodies for user-scoped APIs.

Example:

or:

2.4 Header Block References

To avoid repeating long header tables, endpoint sections refer to these named blocks.

  • User-Scoped Partner Auth Headers — Partner Auth headers (§2.2) + at least one user identity header (§2.3). Used for every user-scoped Partner → UR endpoint.

  • Partner-Scoped Partner Auth Headers — Partner Auth headers (§2.2) only, no user identity. Used for partner-level endpoints not tied to a single user.

  • Public Metadata Headers — No auth required. Used for fully public reference endpoints (banks, payment purposes, etc.). UR reserves the right to change this access policy.

2.5 Standard Response Envelope

Core Banking APIs use the standard UR OpenAPI response envelope:

  • code = 0 → success; non-zero → business error (see endpoint-specific tables and the global error code reference).

  • message → human-readable explanation, may be empty on success.

  • data → endpoint-specific payload.

2.6 Idempotency

Endpoints that move funds (Off-ramp submission, FX, Payout, On-ramp, Onramp retry) accept a Partner-supplied idempotency key:

  • The field name is reqId.

  • Keep reqId stable across retries of the same logical operation. Replays with the same reqId return the original outcome instead of re-executing.

  • Webhook delivery is at-least-once — use data.txHash or the transaction id as the idempotency key on the Partner side.

2.7 Preconditions for Fund-Moving APIs

Before calling Off-ramp, On-ramp, FX, Payout, or Card APIs, the Partner must ensure:

  1. The UR account status is Live.

  2. The mapped Partner user and UR account exist and are not frozen.

  3. Any integration-specific approval required by UR has been enabled for your production setup.


3. Onboarding

Use this section when your platform verifies the user through your own Sumsub tenant. During onboarding, your platform shares the completed Sumsub applicant with UR through Sumsub's share-token reuse mechanism. UR reruns the required checks against UR's Sumsub level, creates a URID, provisions the UR-managed wallet, renders and signs Form A, and activates the user's UR Account.

Two onboarding paths are supported:

  • Sumsub reuse (this page). Your platform completes KYC in your own Sumsub tenant and shares the approved applicant with UR through Sumsub reuse. Use this when you already operate a Sumsub tenant.

  • Sumsub SDK on user device. Your backend requests a UR-issued Sumsub access token and the Sumsub SDK on the user device runs KYC against UR's Sumsub tenant. See API reference: Managed Custody SDK KYC. Use this when you do not run a Sumsub tenant.

Both paths produce the same end state and use the same post-onboarding banking APIs documented in this page.

3.1 Prerequisites

Before you start onboarding users, make sure the following setup is complete:

  • Your Partner Auth signing key is registered with UR.

  • Your platform and UR are configured as Donor / Recipient Partners in Sumsub.

  • Your backend can generate a Sumsub share token scoped to UR's Sumsub clientId after the applicant is approved.

  • Your backend can submit the share token through your dedicated integration channel.

  • Your backend can persist externalUserId, sessionId, urId, and evmAddress for each user.

  • Your backend can receive onboarding webhooks from UR, especially fma.kyc.retry_required.

Store the returned identifiers before you show the user that onboarding has started. Your externalUserId is your stable user ID. UR maps that value to the returned urId.

3.2 Identity headers during onboarding

Onboarding uses the same Partner Auth rules as the rest of this page. The identity header changes after UR creates the user's UR Account.

Phase
Endpoint
Required identity header
Notes

Pre-account

POST /api/fma/v1/create-account

X-External-User-Id

Do not send X-Ur-Id before UR returns the user's urId.

Post-account

/api/fma/v1/kyc/* and /api/fma/v1/account-status

X-Ur-Id

Use the urId returned by /create-account. Sending X-External-User-Id as well is allowed.

For GET /api/fma/v1/kyc/form-a-info and GET /api/fma/v1/account-status, sign the raw query string exactly as sent. For POST endpoints, sign the raw request body exactly as sent. Append the same identity suffix described in §2.2.

3.3 Onboarding flow

The onboarding flow starts after the user has completed KYC in your Sumsub workflow and your backend has shared the approved applicant with UR through Sumsub reuse. UR validates the reused KYC snapshot, records the required attestation on UR's Sumsub level, and activates the UR Account asynchronously.

1

Create the UR Account

Call POST /api/fma/v1/create-account with your X-External-User-Id, the user's email, and the completed Sumsub applicantId. UR creates or reuses the user's URID, provisions the UR-managed wallet, and returns sessionId, urId, and evmAddress.

2

Poll KYC completeness

Call POST /api/fma/v1/kyc/check with the returned sessionId. UR validates the reused Sumsub applicant against UR's Sumsub level and returns complete=true when the session can proceed.

3

Show Form A

Call GET /api/fma/v1/kyc/form-a-info?sessionId=.... Display data.text to the user exactly as returned. Store data.textHash for the signing call.

4

Sign Form A

After the user consents, call POST /api/fma/v1/kyc/sign-form with sessionId and textHash. UR signs Form A with the user's UR-managed custodial wallet.

5

Submit activation

Call POST /api/fma/v1/kyc/submit. UR starts the asynchronous bank account activation process. Treat fma.account.result or GET /api/fma/v1/account-status as the source of truth for the final Live state.

3.4 Create account

Create or reuse the user's UR Account and onboarding session.

Item
Value

Method

POST

Path

/api/fma/v1/create-account

Headers

Partner Auth headers + X-External-User-Id

Request body:

Request fields:

Field
Required
Description

applicantId

Yes

The completed Sumsub applicant ID in your tenant. UR uses this value to match the applicant shared through Sumsub reuse.

email

Yes

The user's email address.

Response example:

Rules:

  • Repeated calls with the same X-External-User-Id return the existing onboarding session with idempotentReplay=true.

  • Persist sessionId, urId, and evmAddress before continuing.

  • Use X-Ur-Id on subsequent onboarding calls.

3.5 Check KYC completeness

Validate the user's reused Sumsub applicant and check whether the session can proceed to Form A.

Item
Value

Method

POST

Path

/api/fma/v1/kyc/check

Headers

User-Scoped Partner Auth Headers

Request body:

Complete response:

Incomplete response:

Poll this endpoint every 30 seconds to 2 minutes while the user is completing KYC or while UR is waiting for the Sumsub reuse result. Stop polling after /kyc/submit succeeds, or when the session reaches a terminal state.

Error handling:

Code
Meaning
Partner action

20004

The KYC snapshot is incomplete.

Ask the user to finish the missing Sumsub steps, then poll again.

40001

Sumsub is temporarily unavailable.

Back off and retry.

40002

UR cannot match the applicantId to a reusable Sumsub applicant.

Check the applicantId and share-token setup for the user.

3.6 Get Form A

Fetch the exact Form A text that the user must review.

Item
Value

Method

GET

Path

/api/fma/v1/kyc/form-a-info?sessionId={sessionId}

Headers

User-Scoped Partner Auth Headers

Request body: none.

Response example:

Rules:

  • Display data.text to the user exactly as returned.

  • Pass data.textHash unchanged to /kyc/sign-form.

  • textHash is the 0x-prefixed keccak256 hash of the UTF-8 bytes of data.text.

  • If this endpoint returns 20007, the KYC snapshot is not ready. Return to /kyc/check.

3.7 Sign Form A

Ask UR to sign the rendered Form A text with the user's UR-managed custodial wallet.

Item
Value

Method

POST

Path

/api/fma/v1/kyc/sign-form

Headers

User-Scoped Partner Auth Headers

Request body:

Response example:

Rules:

  • The request does not include a user signature. UR produces the Form A signature using the user's UR-managed wallet.

  • textHash must match the latest Form A text rendered by UR.

  • If user data changes before /kyc/submit, call /kyc/form-a-info again and re-sign the latest textHash.

3.8 Submit onboarding

Submit the completed onboarding session for asynchronous account activation.

Item
Value

Method

POST

Path

/api/fma/v1/kyc/submit

Headers

User-Scoped Partner Auth Headers

Request body:

Response example:

The registrationId can be empty in the synchronous response. UR fills downstream activation details asynchronously. Use fma.account.result or /api/fma/v1/account-status to confirm the final state.

Preconditions:

  • /kyc/check has returned complete=true.

  • Form A has been signed through /kyc/sign-form.

  • The session is in Register state.

3.9 Get account status

Use account status as a polling fallback after /kyc/submit, or as an explicit confirmation before enabling fund-moving features.

Item
Value

Method

GET

Path

/api/fma/v1/account-status

Headers

User-Scoped Partner Auth Headers

Response example:

Poll this endpoint at a 1-minute cadence after /kyc/submit if you do not receive fma.account.result. Stop polling when data.statusStr is Live, Blocked, or Closed.

3.10 Onboarding states

Use the following state values for your local onboarding cache:

State
Meaning
Partner action

PartnerDataIngestion

UR created the onboarding session and is waiting for a complete KYC snapshot.

Call /kyc/check after the Sumsub applicant is complete.

IdentityVerification

UR is still validating identity evidence.

Continue polling /kyc/check, or ask the user to complete missing KYC steps.

SignFormA

The KYC snapshot is ready for Form A.

Call /kyc/form-a-info, display the text, then call /kyc/sign-form.

Register

Form A is signed and the session is ready to submit.

Call /kyc/submit.

Submitting

UR is activating the account with the downstream banking partner.

Wait for fma.account.result or poll /api/fma/v1/account-status.

Completed

The UR Account is activated.

Enable fund-moving features only after account-status returns Live.

Failed

UR rejected or expired the onboarding session.

Show the failure state and wait for UR guidance or a retry webhook.

3.11 Onboarding webhooks

UR sends onboarding webhooks to the webhook URL registered for your integration. Verify every webhook with the same EIP-191 recovery rules in §13.2.

Activation or rejection:

When data.status is activated, confirm Live with /api/fma/v1/account-status before enabling fund-moving features. When data.status is rejected, the payload includes rejectCode and rejectReason.

Retry required:

When you receive fma.kyc.retry_required, store retrySessionId and run the onboarding flow again from /kyc/check against the retry session. Do not call /create-account for a retry session.


4. Core banking integration principles

The following rules apply across all fund-moving endpoints in this reference.

  1. User balances are queried with GET /api/fma/v1/balance (§6.1).

  2. Off-ramp converts crypto (held on a supported source chain) into the user's tokenized fiat balance. For the current set of supported source chains, source tokens, and target fiat currencies, see Supported Chains & Tokens.

  3. On-ramp converts the user's tokenized fiat balance into crypto on a supported destination chain. New On-ramp submissions must be blocked while a pending retry exists. For the current set of supported destination chains and tokens, see cryptos with aggregatorSupported value in the response of Supported Chains & Tokens.

  4. Card authorization behavior depends on the Partner's Card Mode. See API Reference: Card Mode — Crypto Backed for the Crypto Backed integration surface; Card Mode: Fiat Only has no Partner-side authorization surface.

  5. All async settlement results are delivered via the transaction webhook (§13). The webhook is the authoritative source of truth — API responses to fund-moving calls return only a txHash (the operation has been submitted on-chain, not yet settled).


5. Profile

5.1 Get BR Profile

Fetch the user's banking profile, including IBAN, fiat limits, contacts, deposit bank details, and card eligibility.

Item
Value

Method

GET

Path

/api/fma/v1/br

Headers

User-Scoped Partner Auth Headers

Request body: none. Query parameters: none.

Response example:

Notes:

  • limits are denominated in CHF and use a rolling 30-day window.

  • FX, card spending, on-ramp, and payout share the same fiat limit bucket.

  • A single transaction must not exceed limits.available.


6. Balance

6.1 Get User Balance

Fetch the user's fiat and crypto balances held inside the user's UR account.

Item
Value

Method

GET

Path

/api/fma/v1/balance

Headers

User-Scoped Partner Auth Headers

Response example:

  • fiatItems enumerates the user's tokenized fiat balances on Mantle (EUR24, CHF24, USD24, etc.).

  • cryptoItems enumerates any crypto held inside the user's UR-managed wallet, if Partner has enabled crypto-holding for that user.


7. Off-ramp

Off-ramp converts crypto into fiat in the user's UR account.

Currently supported:

Flow

The UR API step is quote retrieval. After the Partner receives the quote, the user (via the Partner Frontend) signs and submits the Off-ramp contract call from whichever wallet holds the source crypto. See §7.2.

7.1 Get Off-ramp Quote

Item
Value

Method

POST

Path

/api/fma/v1/quote/deposit

Headers

User-Scoped Partner Auth Headers

Request body:

  • chainId & fromToken — see Supported Chains & Tokens

  • toCurrency — target fiat currency symbol.

  • amount — human-readable decimal string; UR converts it to token smallest units using the source token decimals.

Response example:

Contract execution notes:

  • Pass best.to, best.swapCalldata, and best.minUsdcAmount to the UR Off-ramp contract exactly as returned.

  • The signing Crypto Wallet (UR-managed or external; see §7.2) must have approved the Off-ramp contract to spend fromToken for at least amount.

  • The transaction must be submitted before best.deadline; otherwise it can revert.

  • networkFee and crossChainFee are denominated in the source chain's native token and paid by the user from the source chain wallet (in addition to amount).

  • Final settlement is reported asynchronously through the transaction webhook with data.type = "CRYPTO_DEPOSIT".

7.2 Initiate Off-ramp

In Managed Custody Mode, the Fiat Wallet is always UR-managed, but the Crypto Wallet could be the same as the UR-managed account or an external wallet, depending on the Partner's choice. The Off-ramp contract is agnostic to the source — it uses the _targetAccount parameter to know which UR Account receives the resulting fiat.

Contract: depositTokenViaAggregatorToAccount on the Off-ramp contract. Contract addresses per chain: see Deposit (Off-ramp).

Contract Parameters:

Parameter
Type
Required
Description
Example

_inputToken

address

Yes

Source token address (Use 0x00...00 for native tokens).

"0xA0b8...B48" (USDC)

_outputToken

address

Yes

Target fiat token address (Fiat type after deposit).

"0x1234...5678"

_amount

uint256

Yes

Deposit amount (in smallest unit, e.g., Wei).

For USDC: "10000000" = 10.000000

_aggregator

address

Yes

Exchange contract address — use best.to from §7.1.

_swapCalldata

bytes

Yes

Use best.swapCalldata from §7.1.

"0x" for USDC direct deposit.

_minUsdcAmount

uint256

Yes

Use best.minUsdcAmount from §7.1.

_feeAmountViaUsdc

uint256

Yes

Put "0" when user calls the contract directly.

_targetAccount

address

Yes

Use data.targetAccount from §7.1. This is the user's UR Account address that receives the resulting fiat.

If you require Partner-side API submission for Off-ramp instead of on-chain user signing, please contact the UR team.


8. FX

FX converts one tokenized fiat balance into another tokenized fiat balance, both held inside the user's UR account.

8.1 FX Quote

Item
Value

Method

POST

Path

/api/fma/v1/quote/fx

Headers

User-Scoped Partner Auth Headers

Request body:

Response example:

8.2 Execute FX

Item
Value

Method

POST

Path

/api/fma/v1/fx-exchange

Headers

User-Scoped Partner Auth Headers

Request body:

amountOutMinimum is optional. If omitted, UR applies a default 0.5% slippage buffer based on the submitted amount.

Response example:

Final result is reported through the transaction webhook with data.type = "FRX". See §12.1 for the full set of status values.


9. Bank Payout

Bank Payout sends tokenized fiat from the user's UR account to an external bank account via SEPA / SWIFT.

Flow

9.1 Get Payout Fees

Item
Value

Method

GET

Path

/api/v1/banks/payout/fees

Headers

Public Metadata Headers

Public metadata, not scoped to a single user. Returns the standard envelope:

9.2 Choose Recipient

The Partner can use either a recent contact returned by GET /api/fma/v1/br, or create / verify a new contact.

Recent contact path:

  • Read data.contacts[currency] from the BR Profile response (§5.1).

  • Use contact.id as contactId.

  • If the user provides a new reference, call POST /api/fma/v1/verify-reference (§9.3) to get a fresh refId + purposeId.

New contact path:

  • Identify the recipient bank by IBAN (GET /api/v1/banks/iban/{iban}) or by selecting from the non-IBAN bank list (GET /api/v1/banks).

  • Collect required creditor name, address, country, city, payment purpose, and reference.

  • Call POST /api/fma/v1/verify-contact (§9.4).

Public metadata APIs (/api/v1/banks, /api/v1/banks/iban/{iban}, /api/v1/country-cities, /api/v1/payment-purposes) do not require user identity headers unless UR changes their access policy.

9.3 Verify Reference

Item
Value

Method

POST

Path

/api/fma/v1/verify-reference

Headers

User-Scoped Partner Auth Headers

Request body:

Response example:

9.4 Verify Contact

Item
Value

Method

POST

Path

/api/fma/v1/verify-contact

Headers

User-Scoped Partner Auth Headers

Request body:

Response example:

creditorInfo.name, creditorInfo.street, creditorInfo.city, and creditorInfo.country must use Latin characters.

9.5 Submit Payout

Item
Value

Method

POST

Path

/api/fma/v1/submit-payout

Headers

User-Scoped Partner Auth Headers

Request body:

Response example:

Constraints:

  • metadata name, address, and reference values must use Latin characters.

  • purposeId and refId must be provided together, or both omitted.

  • Minimum amount is currency-specific and comes from minimalPayoutAmount (§9.1).

  • Network fees and payout fees are deducted from amount; they are not charged separately.

  • Payout is subject to the user's rolling 30-day CHF-denominated fiat limits.

  • Final result is reported through the transaction webhook with data.type = "FIAT_WITHDRAW".


10. On-ramp

On-ramp converts the user's tokenized fiat balance into crypto on a target chain.

Currently supported:

  • Destination chains and tokens: see cryptos with aggregatorSupported value in the response of Supported Chains & Tokens.

  • Source fiat currencies: USD, EUR, CHF, SGD, JPY, HKD

Flow

10.1 On-ramp Login Initialization

When the user enters the On-ramp flow, the Partner should run these checks in order:

  1. GET /api/fma/v1/onramp-limit

  2. GET /api/fma/v1/onramp/pending-retry — only if the limit response allows the flow.

If a pending retry exists, the Partner must force the user to Retry or Cancel before starting a new On-ramp.

10.2 Get On-ramp Limit

Item
Value

Method

GET

Path

/api/fma/v1/onramp-limit

Headers

User-Scoped Partner Auth Headers

Response example:

Block the flow if regionLocked, usdcDepegged, or livenessLocked is true, or if the requested amount exceeds maxAmounts[currency].

10.3 Check Pending Retry

Item
Value

Method

GET

Path

/api/fma/v1/onramp/pending-retry

Headers

User-Scoped Partner Auth Headers

Pending retry represents an On-ramp whose bridge succeeded but whose swap leg failed; the user must resolve it before starting a new On-ramp.

No pending item:

When there is no pending retry, data.originalTxHash is empty.

Pending item:

10.4 Get On-ramp Quote

Item
Value

Method

POST

Path

/api/fma/v1/quote/onramp

Headers

User-Scoped Partner Auth Headers

Request body for the main On-ramp flow:

Notes:

  • scene is onramp for the main flow and swap_retry for retry (§10.8).

  • srcChainId is the chain where the user's tokenized fiat is held (UR's home chain).

  • fromCurrency is required for scene = "onramp". fromToken is used only for scene = "swap_retry".

  • dstChainId and toToken must match a crypto type with aggregatorSupported value in the response of Supported Chains & Tokens.

  • networkFee returned in the quote response is the destination-chain gas + cross-chain fee, deducted from the user's input fiat.

  • If the response has needLiveness = true, the Partner must complete liveness before submitting On-ramp.

10.5 Liveness Token

Item
Value

Method

GET

Path

/api/fma/v1/onramp-liveness-token

Headers

User-Scoped Partner Auth Headers

Only call this endpoint when a quote returns needLiveness = true.

Response example:

10.6 Liveness Result

Item
Value

Method

GET

Path

/api/fma/v1/onramp-liveness-result

Headers

User-Scoped Partner Auth Headers

Response example:

After liveness_result = "pass", the Partner should request a new quote and submit using the new quoteId.

10.7 Submit On-ramp

Item
Value

Method

POST

Path

/api/fma/v1/onramp

Headers

User-Scoped Partner Auth Headers

Request body:

Response example:

Submit constraints:

  • amountIn is a human-readable decimal string and must match the amount used for the cached quote.

  • quoteId must match UR's cached quote (and not be expired).

  • A quote requiring liveness cannot be submitted until liveness passes.

  • New On-ramp must be blocked while a pending retry exists (§10.3).

  • withdrawAddress is optional and is only supported for cross-chain On-ramp (chainId != dstChainId).

  • If withdrawAddress is omitted, UR sends the destination-chain crypto to the user's UR EVM address.

  • Do not send withdrawAddress for same-chain On-ramp (chainId == dstChainId); the request will be rejected.

  • Final result is reported through the transaction webhook.

10.8 Retry On-ramp Swap

On-ramp is a two-leg flow (bridge + swap). When the bridge succeeds but the swap fails, the user's funds are stuck as the bridge intermediate token on the destination chain. Retry redoes the swap leg only — so the payload drops fiat/source-chain inputs and instead carries originalTxHash, the post-bridge intermediate-token amount, and a fresh swap quote.

Item
Value

Method

POST

Path

/api/fma/v1/onramp-swap

Headers

User-Scoped Partner Auth Headers

Only call this endpoint when GET /api/fma/v1/onramp/pending-retry returns a pending item.

Retry flow:

  1. Read pending retry from GET /api/fma/v1/onramp/pending-retry.

  2. Request a fresh retry quote:

    • scene = "swap_retry"

    • srcChainId = pendingRetry.chainId

    • dstChainId = pendingRetry.chainId

    • fromToken = pendingRetry.fromToken

    • toToken = pendingRetry.toToken

    • amount = pendingRetry.amount (human-readable)

  3. Submit /api/fma/v1/onramp-swap:

    • usdcAmount = pendingRetry.amountRaw (USDC minimal unit)

    • tokenOut = pendingRetry.toToken

    • minAmountOut = quote.best.minAmountOut

    • aggregator = quote.best.to (not quote.best.aggregator)

    • swapCalldata = quote.best.swapCalldata

Request body:

10.9 Cancel On-ramp Retry

Item
Value

Method

POST

Path

/api/fma/v1/onramp/retry/cancel

Headers

User-Scoped Partner Auth Headers

Request body:

A successful response clears the pending retry record and allows the Partner to re-enable the normal On-ramp entry point.


11. Card

The user's debit card is issued and processed by UR through Mastercard. This section covers only the card-management endpoints common to all Card Modes: card creation, card info retrieval, default-currency selection, and post-settlement history.

Card authorization, prefund, and card-related webhooks are Card-Mode-specific. Card Mode: Fiat Only has no Partner-side authorization surface — UR handles authorization on-chain against the user's tokenized fiat balance. Card Mode: Crypto Backed has its own integration surface (synchronous authorization callback, Prefund Account, Prefund Balance Alert webhook) documented in API Reference: Card Mode — Crypto Backed.

11.1 Create Card

Create a virtual card for an eligible Live user.

Item
Value

Method

POST

Path

/api/fma/v1/open-card

Headers

User-Scoped Partner Auth Headers

Request body: {}

Preconditions:

  • GET /api/fma/v1/br returns isCardEligible = true.

  • The user has no existing card if UR only allows one card per user.

  • The user balance satisfies cardActivation.amount and cardActivation.currency.

Response example:

11.2 Get Card Info

Fetch card metadata and a short-lived cardToken for secure card display.

Item
Value

Method

GET

Path

/api/fma/v1/card

Headers

User-Scoped Partner Auth Headers

Response example:

Security constraints:

  • UR does not return real PAN, CVV, or expiry through this API.

  • masked values are display placeholders only.

  • The Partner backend must not store cardToken.

  • The Partner backend should only pass cardToken to the frontend.

  • The Partner frontend must pass cardToken into the secure card display webview provided by UR. Real PAN, CVV, and expiry are rendered only inside that webview.

11.3 Set Default Card Currency

Set the user's default card transaction currency.

Item
Value

Method

POST

Path

/api/fma/v1/card-currency

Headers

User-Scoped Partner Auth Headers

Request body:

Response example:

Notes:

  • The target card is resolved server-side from the urId in the User-Scoped Partner Auth Headers; the Partner does not pass a cardTokenId.

  • The next GET /api/fma/v1/card response should show the updated currency.

  • This setting affects UR's default refund currency display and debit preference.

  • Per-transaction overrides at swipe time are governed by the Card Mode — see API Reference: Card Mode — Crypto Backed.

11.4 Card Authorization

Card authorization behavior is Card-Mode-specific and is not covered in this document. See API Reference: Card Mode — Crypto Backed for the Crypto Backed integration surface. Card Mode: Fiat Only has no Partner-side authorization surface.

11.5 Card Settlement Notes

Card settlement result records are exposed through transaction history (§12) with data.type = "CRD". Additional card adjustment event contracts (chargebacks, fee adjustments) must be agreed separately with UR.


12. Transactions

Use transaction history for reconciliation. The same endpoint also supports exact lookup by transaction hash or transaction ID.

12.1 Fetch Transaction History

Item
Value

Method

POST

Path

/api/fma/v1/transactions

Headers

User-Scoped Partner Auth Headers

Simple first-page request:

Filtered request:

Response example:

Pagination is driven by the response flags and cursors. Only send cursor fields returned by the API, and only when the corresponding flag is true.

To fetch the next page, use nextCursor when hasNextPage is true:

To fetch the previous page, use prevCursor when hasPrevPage is true:

If hasPrevPage is false, do not use prevCursor; a zero cursor means there is no previous page.

Request fields:

Field
Type
Description

pageSize

integer

Page size. Defaults to 50; maximum is 100.

type

string

Single transaction type filter. Do not send together with txTypes.

txTypes

string[]

Multiple transaction type filter. Do not send together with type.

currencies

string[]

Currency filter. Values are normalized to lowercase by UR.

direction

string

Direction filter: IN, OUT, or ALL.

status

string

Transaction status filter.

chainId

string

Chain ID filter, for example eip155:5000.

tokenSymbol

string

Token symbol filter, for example USDC.

minAmount

string

Minimum amount filter.

maxAmount

string

Maximum amount filter.

fromTimestamp

integer

Start timestamp filter.

toTimestamp

integer

End timestamp filter.

cursorTimestamp

integer

Next-page cursor timestamp from data.nextCursor.timestamp.

cursorId

integer

Next-page cursor ID from data.nextCursor.id.

prevCursorTimestamp

integer

Previous-page cursor timestamp from data.prevCursor.timestamp.

prevCursorId

integer

Previous-page cursor ID from data.prevCursor.id.

id

integer

Exact lookup by UR internal transaction ID. Do not send together with txHash.

txHash

string

Exact lookup by transaction hash. Do not send together with id.

Partner-relevant transaction types:

type

Meaning

CRYPTO_DEPOSIT

Crypto deposit / tokenized fiat top-up.

INTERNAL_TOKEN_TRANSFER

Internal token transfer between UR accounts.

UNKNOWN

Unknown or uncategorized transaction type.

FX_EXCHANGE

FX exchange.

MARQETA_AUTHORIZE

Card authorization / card payment.

FIAT_WITHDRAW

Fiat withdrawal / bank payout.

FIAT_DEPOSIT

Fiat deposit / bank pay-in.

ONRAMP

On-ramp.

Transaction status values:

status

Description

UNKNOWN

Unknown; default value. Should not appear in normal flows.

INIT

Transaction created internally but not yet broadcast to the blockchain node.

PENDING

Transaction is in the mempool (transaction pool), awaiting confirmation.

CONFIRMED

Transaction has been confirmed and settled on-chain.

FAILED

Transaction execution failed on-chain.

PENDING_DROP

Transaction is scheduled to be dropped, for example replaced or cancelled.

DROPPED

Transaction was removed from the mempool without being confirmed.

REJECTED

Transaction was rejected by UR's validation or compliance checks before or during execution.

12.2 Fetch Transaction Details

Use this endpoint to fetch a single transaction. Send exactly one lookup key: txHash for an on-chain transaction hash, or id for UR's internal transaction ID.

Item
Value

Method

POST

Path

/api/fma/v1/transactions

Headers

User-Scoped Partner Auth Headers

Lookup by transaction hash:

Lookup by UR internal transaction ID:

Response:

  • The response uses the same data.items[] transaction structure as §12.1.

  • Send either id or txHash, never both.

  • If no transaction matches the lookup key, data.items[] is empty.


13. Webhooks

Webhooks are the asynchronous delivery channel for transaction settlement updates. The Partner should subscribe to the transaction event for Off-ramp, FX, On-ramp, Fiat Deposit, and Payout settlement.

Card-Mode-specific webhooks (post-swipe card transaction, prefund.balance.alert) are documented in API Reference: Card Mode — Crypto Backed.

13.1 Webhook Envelope

13.2 Webhook Signature Verification

UR signs webhook requests with EIP-191.

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

13.3 Retry and Idempotency

  • The Partner should return HTTP 200 within 10 seconds.

  • UR retries non-200 or timed-out webhook deliveries up to 3 times, with a 5-minute interval.

  • Use data.txHash or the transaction data.id as the idempotency key on the Partner side.

13.4 Transaction Event

The transaction event uses the same transaction data structure as /api/fma/v1/transactions (§12.1). Route by data.type — see the type table in §12.1 for the canonical set.


14. Implementation Checklist

Before going live:

  • Store both externalUserId (Partner side) and urId (UR side) after onboarding.

  • For user-scoped APIs, send at least one of X-External-User-Id or X-Ur-Id (sending both is allowed; UR resolves by X-Ur-Id first).

  • Sign GET requests with the raw query string, and sign non-GET requests with the raw body, then append urId:{X-Ur-Id}externalUserId:{X-External-User-Id}.

  • Keep reqId stable across retries for POST /api/fma/v1/fx-exchange, POST /api/fma/v1/submit-payout, POST /api/fma/v1/onramp, and POST /api/fma/v1/onramp-swap.

  • Treat webhook delivery as at-least-once and implement idempotency keyed on data.txHash or data.id.

  • Reconcile transaction history through POST /api/fma/v1/transactions; use txHash or id on that same endpoint for exact lookup.

  • Verify every webhook with EIP-191 recovery against UR's public key (§13.2).

  • If the Partner is enabling Card Mode: Crypto Backed, complete the additional checklist in API Reference: Card Mode — Crypto Backed.


15. Reference Docs

Last updated