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
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
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 (60 seconds by default). Request a new one each time the customer wants to view their card.
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.
Funding History
View all card funding transactions you have initiated for customers:Response
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.
Webhook Events
Subscribe to webhooks for real-time events. See Webhook Integration.| Event | Trigger |
|---|---|
customer.kyc.approved | KYC passed — wallet is being provisioned |
customer.kyc.rejected | KYC failed — redirect customer to retry |
customer.card.created | Card issued successfully |
card.transaction.approved | Purchase approved |
card.transaction.declined | Purchase declined |
card.transaction.completed | Settlement complete |
card.funded | Funding transfer completed |
card.funding.failed | Funding transfer failed |
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 |
| Funding history | GET | /v1/card-issuer/funding-history |
| 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 |
| 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 |

