The Card Issuer Program lets your platform issue Visa virtual cards to your end customers. Yativo handles the card network, compliance, and settlement — your backend drives the entire flow via API.Documentation Index
Fetch the complete documentation index at: https://docs.yativo.com/llms.txt
Use this file to discover all available pages before exploring further.
Two API namespaces — keep them separate.
The
| Namespace | Base path | Purpose |
|---|---|---|
| Card Issuer | /v1/card-issuer/* | Your program: apply, check status, manage customers, fund cards |
| Card Customer | /v1/yativo-card/customers/* | Individual customer lifecycle: OTP, KYC, card creation, freeze, transactions |
/v1/customers/* path is WaaS (wallet sub-accounts for crypto deposits/withdrawals). It has nothing to do with card customers. Do not mix them up.Identity Model
- You are a Yativo user who has been approved into the Card Issuer Program.
- Your Customers are the end users of your platform who get a card. They are never authenticated directly against Yativo — all API calls come from your backend using your token.
yativo_card_idis the primary identifier for a card customer. Store it after onboarding.external_customer_idis your own reference ID — pass it at onboarding and use it to look up the customer later without storing Yativo IDs.
Flow Overview
Step 1 — Check Eligibility
Confirm your account has been granted access before applying.Response
eligible is false, contact your account manager. This gate is admin-only — there is no API call to change it yourself.
Step 2 — Apply
| Field | Type | Required | Description |
|---|---|---|---|
funding_structure | string | Yes | master_wallet or non_master (see below) |
preferred_chain | string | No | SOL (default) or XDC — the chain your master wallet will receive funds on |
iban_enabled | boolean | No | Enable IBAN for cardholders. Defaults to false. |
Funding Structures
| Value | How it works |
|---|---|
master_wallet | You maintain a shared balance and push funds to each customer card via the Fund Customer API. Best for platforms that control card top-ups. |
non_master | Each customer receives their own deposit address and funds their card directly. Best for self-serve wallets. |
Response
Step 3 — Check Program Status
Applications are reviewed within 1–2 business days. Poll untilstatus is approved.
Approved
On approval, Yativo provisions your master wallet set:
- SOL deposit address (
sol.address) — send USDC on Solana here to top up your USD balance. - USD balance — funded automatically when your SOL deposit confirms.
- EUR balance — funded by swapping from USD.
- GBP balance — funded by swapping from USD.
Step 4 — Fund Your Master Wallet (master_wallet programs only)
Get your current balances and deposit addresses:Response
sol.address. Once the deposit confirms, your usdc balance increases automatically. Swap to eur or gbp before funding customers who hold those card currencies.
Swap Currencies
If your customers are in the EU or UK, swap USDC into the correct card currency before funding:Response
Step 5 — Onboard a Customer
Start the onboarding flow for each end customer. Onlyemail is required.
Response 201
Step 6 — Verify OTP
Collect the OTP from your customer and submit it:Response 200
| Error code | Meaning | Recovery |
|---|---|---|
OTP_EXPIRED | 10-minute window passed | Call resend-otp |
OTP_INVALID_OR_EXPIRED | Wrong or expired code | Check code and retry, or call resend-otp |
OTP_VERIFICATION_FAILED | Verification service rejected with a specific reason | Inspect message, call resend-otp |
OTP_ATTEMPTS_EXCEEDED | 5 failed attempts | Call resend-otp — this resets the counter |
SESSION_EXPIRED | Session expired and couldn’t auto-refresh | Call resend-otp — a new OTP re-establishes the session |
data.next_step field and a data.action URL pointing to the exact endpoint to call next.
Resend OTP
Step 7 — Get KYC Link
Generate a verification URL for this customer:Response
kyc_url, or embed the KYC flow in your app using the Sumsub SDK with sumsub_sdk_token. Add ?refresh=true to generate a new link if the existing one has expired.
Step 8 — Poll KYC Status
Approved
Pending
Rejected
next_step is retry_kyc, fetch a fresh kyc-link?refresh=true and redirect the customer.
Step 9 — Source of Funds
Get questions
Response
Submit answers
Response
Step 10 — Phone Verification
Request SMS code
Response
Verify SMS code
Response
Step 11 — Create Virtual Card
All prerequisites are complete. Issue the card:Response 201
Multiple Cards per Customer
A single customer account supports up to 5 active cards (virtual + physical combined). You can issue additional virtual cards on top of the first one, subject to the limits set on your program.403 Limit reached
Card Limits
Limits work in a three-tier hierarchy:Set per-customer limits (issuer)
Override the limit for a specific customer, up to your program’s ceiling:Response 200
program_ceilings reflects the maximum values your program permits. You cannot set a customer limit above its corresponding ceiling.
| Error code | Meaning |
|---|---|
LIMIT_EXCEEDS_PROGRAM | The value you sent is above your program’s ceiling for that limit type |
NO_CHANGES | No valid limit fields were provided in the request body |
Step 12 — Fund the Card
Option A: Push from Master Wallet (master_wallet programs)
You can identify the customer by any of:customer_id, card_id, external_id, email, or yativo_card_id.
Response 200
transfer_id. Poll GET /v1/card-issuer/transfers/:transferId until status is completed (typically 2–5 minutes).
pricing_mode:
receive_x— the customer receives exactlyamount. Yativo deducts slightly more from your master wallet to cover fees.send_x(default) — exactlyamountis debited from your master wallet. The customer receives less after fees.
TOKEN_MISMATCH error: if you fund with the wrong currency for a customer’s card region, the API returns this error with the exact token their card requires. Swap your master wallet balance first.
Option B: Customer Self-Funds via Deposit Address (non_master programs)
Get the customer’s deposit address:Response
Card Management
List all customers
Response
flow_status: otp_requested, otp_verified, kyc_initiated, kyc_completed, card_created, active.
Look up a customer
Find a customer by any identifier:| Param | Description |
|---|---|
yativo_card_id | Yativo’s internal card customer ID |
customer_id | MongoDB customer ObjectId (or yativo_card_id as fallback) |
card_id | Card ID from card creation |
external_id | Your reference ID set at onboarding |
email | Customer email address |
id | MongoDB _id of the customer record |
Response
Freeze / Unfreeze a Card
Response
Response
Get Card Transactions
Response
Spending Limits
Get the current spending limit for a customer’s card:Response
Response
Limit changes go through a Gelato relay with a 3-minute processing delay. The
gelato_status: "ExecSuccess" confirms the transaction was enqueued. Poll GET /wallet/limits after 3 minutes to confirm the new limit is active.Secure Card View
To let a cardholder view their full card details (PAN, CVV, expiry, PIN), your backend requests a secure view URL from Yativo. You send that URL to your customer — via your app, an email link, or an in-app iframe. Yativo hosts the page and handles all cryptography internally. Your backend never sees or handles raw card data.How it works
Request a secure view URL
| Field | Type | Description |
|---|---|---|
enabled_views | array | Which panels to show: "data" (PAN/CVV/expiry), "pin". Defaults to both. |
require_access_code | boolean | Require the cardholder to enter a code before the card data unlocks. |
access_code | string | The code the cardholder must enter (set by you, shared via your app). |
theme.accent_color | string | Hex color for buttons and highlights. |
theme.background_color | string | Page background color. |
theme.panel_color | string | Card panel background color. |
theme.text_color | string | Primary text color. |
theme.logo_url | string | Your logo shown at the top of the page. |
theme.border_radius | number | Corner radius in px (8–36). |
theme.font_family | string | CSS font-family string. |
Response
secure_view_url in a browser tab, iframe, or mobile WebView. The URL is short-lived. Request a new one each time the customer wants to view their card.
The response includes pin_set — the last known state from the physical.card.pin.changed webhook. Use it in your UI to decide whether to prompt the customer to set their PIN before showing card details.
Customer PIN setup and change
Every card starts withpin_set: false. The customer must set a PIN before chip-and-PIN or ATM transactions will work. Use the same view-token endpoint with enabled_views: ["pin"] to show the PIN setup page — this also handles PIN changes.
secure_view_url for your customer in an iframe or WebView. The cardholder enters their 4-digit PIN directly in the hosted page — it never passes through your backend. Once saved, Gnosis Pay fires a physical.card.pin.changed webhook and Yativo updates pin_set: true on the card record.
pin_set is sourced from the webhook, not from the Gnosis API. Use it as a UI hint to prompt customers who haven’t yet set a PIN — not as a hard access gate.Deposits
View all funding deposits into your issuer program (SOL auto-funding and XDC manual deposits):status: pending, auto_funding, awaiting_manual, funding, funded, failed.
Filter by chain: SOL, XDC.
Transfers
All transfers
View all funding transfers you have sent to customer cards:Response
status, customer_id, and chain query filters. See List Transfers.
Single transfer status
Transfers for a specific customer
customerId accepts yativo_card_id, customer_id, or your own external_id. See List Customer Transfers.
Check Progress Anytime
Response
Delete an Incomplete Customer Record
If you created a customer by mistake (e.g. wrong email) and the card has not yet been issued:card_created or active status.
Reset Customer Onboarding
If a customer’s onboarding is stuck (KYC rejected multiple times, verification loop, wrong details submitted) and you need to start completely fresh, use the reset endpoint. This deletes the Yativo record and allows re-onboarding with a new verification flow.Response 200
card_created status, this endpoint returns:
400 Card already issued
Webhook Events
Subscribe to webhooks for real-time events. See Webhook Events for payload examples, signature verification, and the full event reference.| Event | Trigger |
|---|---|
customer.funded | Funding transfer completed into a customer’s card wallet |
customer.funding.failed | Funding transfer failed |
master_wallet.customer_funded | Master wallet debited for a customer funding (includes remaining_balance on direct transfers) |
master_wallet.deposit | Funds received into your master wallet |
master_wallet.swap | Token swap submitted from your master wallet |
card.created | New card issued to a customer |
card.activated | Physical card activated |
card.frozen | Card frozen |
card.unfrozen | Card unfrozen |
card.voided | Card permanently voided |
card.lost | Card reported lost |
card.stolen | Card reported stolen |
card.cancelled | Card cancelled |
transaction.authorized | Card transaction authorized at point of sale |
transaction.settled | Transaction cleared and settled |
transaction.declined | Transaction declined |
transaction.reversed | Transaction reversed |
transaction.refund.created | Refund created |
customer.balance.updated | Customer balance changed after a spend, top-up, or authorization |
KYC status changes are not delivered as webhooks — poll Get Customer or Look Up Customer to check
kyc_status after directing customers through the KYC link.Recovery & Continuation Reference
Every operation that can fail returns adata.next_step field and a data.action URL so you never have to guess what to do. This section documents every failure mode and the exact API call that recovers from it.
Onboarding State Machine
Handling All Error Codes
OTP Phase errors
| Error code | Cause | Recovery call |
|---|---|---|
OTP_EXPIRED | 10-min window elapsed | POST /customers/{id}/resend-otp |
OTP_INVALID_OR_EXPIRED | Wrong or expired code | Retry with correct code, or POST /customers/{id}/resend-otp |
OTP_VERIFICATION_FAILED | Verification service returned an unexpected error | Inspect message field; then resend-otp |
OTP_ATTEMPTS_EXCEEDED | 5 wrong attempts | POST /customers/{id}/resend-otp — this resets the counter |
SESSION_EXPIRED | JWT expired and SIWE auto-refresh failed | POST /customers/{id}/resend-otp — new OTP re-establishes the session |
JWT_REFRESH_FAILED | SIWE re-auth failed (rare) | POST /customers/{id}/resend-otp |
data.attempts_remaining, data.next_step: "resend_otp", and data.action in the response body.
KYC Phase errors
| Error code | Cause | Recovery call |
|---|---|---|
KYC_LINK_FAILED | Identity verification link could not be generated | Retry GET /customers/{id}/kyc-link?refresh=true after a short delay |
KYC_STATUS_ERROR | Live status check failed | Retry GET /customers/{id}/kyc-status — response falls back to cached status |
SESSION_EXPIRED | JWT expired and can’t refresh | GET /customers/{id}/kyc-link?refresh=true — this forces a SIWE re-auth internally |
Abandoned Onboardings — resume Endpoint
If a customer starts onboarding but never finishes (OTP not verified, KYC link never opened, KYC in progress for days), call the resume endpoint. It inspects the current state, takes the correct action automatically, and tells you exactly what to present to the customer next.
flow_status | Action taken | next_step returned |
|---|---|---|
otp_requested | Resends OTP to customer email, resets attempt counter | verify_otp |
reauth_otp_requested | Same as above (re-auth OTP pending) | verify_otp |
otp_verified | Generates a fresh KYC link | kyc_link |
kyc_initiated | Generates a fresh KYC link | kyc_link |
kyc_rejected | Generates a fresh KYC link for retry | retry_kyc |
kyc_completed / kyc_approved / safe_deployed | No action needed — ready for card creation | create_virtual_card |
card_created / active | Already complete | none |
Response — OTP phase
Response — KYC phase
Polling Strategy
For KYC status polling, use an exponential-backoff approach with a hard timeout:kyc_status === 'rejected', fetch a fresh KYC link and redirect the customer:
Full next_step Reference
Every API response in the customer lifecycle includes data.next_step. Use it to drive your state machine without hardcoding assumptions about flow order.
next_step value | What to do |
|---|---|
verify_otp | Show OTP input to customer |
resend_otp | OTP is unusable — call resend-otp then show OTP input |
kyc_link | Open kyc_url or embed SDK |
kyc_status | Start polling kyc-status |
retry_kyc | KYC rejected — show reason, get new link, redirect customer |
create_virtual_card | KYC done, Safe deployed — call POST /cards/virtual |
none | Customer is fully active, no further action |
null | Intermediate state — call GET /progress for full picture |
Common Integration Mistakes
| Mistake | Consequence | Fix |
|---|---|---|
| Using issuer email as customer email | ISSUER_EMAIL_NOT_ALLOWED — blocked at onboard | Use the customer’s own email address |
Not storing yativo_card_id | Can’t call any subsequent customer endpoint | Store it immediately after POST /customers/onboard |
Treating OTP_ATTEMPTS_EXCEEDED as fatal | Customer stuck | Call resend-otp — resets the counter |
Not handling kyc_rejected | Customer stuck in KYC loop | Detect rejection in kyc-status, fetch fresh link, re-direct |
| Re-creating customer after OTP failure | Duplicate records | Call resend-otp on the existing yativo_card_id |
Calling kyc-link for otp_requested customers | SESSION_EXPIRED or wrong step | Ensure OTP is verified before requesting KYC link |
| Assuming Safe deploy needs manual call | Extra API call, possible conflict | For customers: Safe deploys automatically after KYC approval |
Quick Reference
Issuer Program (/v1/card-issuer/*)
| Action | Method | Path |
|---|---|---|
| Check eligibility | GET | /v1/card-issuer/eligibility |
| Apply | POST | /v1/card-issuer/apply |
| Check program status | GET | /v1/card-issuer/status |
| Get master wallet balances | GET | /v1/card-issuer/master-wallets |
| Swap master wallet currencies | POST | /v1/card-issuer/master-wallets/swap |
| List customers | GET | /v1/card-issuer/customers |
| Look up customer | GET | /v1/card-issuer/lookup-customer |
| Fund a customer card | POST | /v1/card-issuer/fund-customer |
| List all transfers | GET | /v1/card-issuer/transfers |
| Get transfer status | GET | /v1/card-issuer/transfers/{transferId} |
| List customer transfers | GET | /v1/card-issuer/customers/{id}/transfers |
| Deposits list | GET | /v1/card-issuer/deposits |
| Delete incomplete customer | DELETE | /v1/card-issuer/customers/{id} |
Card Customer Lifecycle (/v1/yativo-card/customers/*)
| Action | Method | Path |
|---|---|---|
| Onboard customer | POST | /v1/yativo-card/customers/onboard |
| Verify OTP | POST | /v1/yativo-card/customers/{id}/verify-otp |
| Resend OTP | POST | /v1/yativo-card/customers/{id}/resend-otp |
| Resume stuck onboarding | POST | /v1/yativo-card/customers/{id}/resume |
| Get KYC link | GET | /v1/yativo-card/customers/{id}/kyc-link |
| Poll KYC status | GET | /v1/yativo-card/customers/{id}/kyc-status |
| Get SoF questions | GET | /v1/yativo-card/customers/{id}/source-of-funds |
| Submit SoF answers | POST | /v1/yativo-card/customers/{id}/source-of-funds |
| Request phone OTP | POST | /v1/yativo-card/customers/{id}/phone/request-verification |
| Verify phone OTP | POST | /v1/yativo-card/customers/{id}/phone/verify |
| Create virtual card | POST | /v1/yativo-card/customers/{id}/cards/virtual |
| Set per-customer card limits | PATCH | /v1/yativo-card/customers/{id}/card-limits |
| Reset customer onboarding | POST | /v1/yativo-card/customers/{id}/reset |
| Get deposit address | GET | /v1/yativo-card/customers/{id}/wallet/funding-address |
| Check onboarding progress | GET | /v1/yativo-card/customers/{id}/progress |
| Freeze card | POST | /v1/yativo-card/customers/{id}/cards/{cardId}/freeze |
| Unfreeze card | POST | /v1/yativo-card/customers/{id}/cards/{cardId}/unfreeze |
| Terminate card | POST | /v1/yativo-card/customers/{id}/cards/{cardId}/void |
| Get transactions | GET | /v1/yativo-card/customers/{id}/cards/{cardId}/transactions |
| Get spending limits | GET | /v1/yativo-card/customers/{id}/wallet/limits |
| Set spending limit | PUT | /v1/yativo-card/customers/{id}/wallet/limits |
| Get secure card view URL | POST | /v1/yativo-card/customers/{id}/cards/{cardId}/view-token |
| Get customer profile | GET | /v1/yativo-card/customers/{id}/profile |

