curl -X POST 'https://crypto-api.yativo.com/api/v1/yativo-card/customers/onboard' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"email": "customer@example.com",
"external_customer_id": "usr_8821"
}'
const response = await fetch(
'https://crypto-api.yativo.com/api/v1/yativo-card/customers/onboard',
{
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'customer@example.com',
external_customer_id: 'usr_8821',
}),
}
);
const data = await response.json();
// data.data.yativo_card_id — save this for all subsequent calls
{
"success": true,
"message": "Customer card onboarding initiated. Verification code sent to customer email.",
"data": {
"yativo_card_id": "yativo_card_customer_8f9a2b3c4d5e6f7a8b9c0d1e_1769031332068",
"customer_id": "6627f3a2c5d4e100123abcde",
"external_customer_id": "usr_8821",
"email_masked": "cu***@example.com",
"next_step": "verify_otp",
"otp_expires_in_seconds": 600
}
}
{
"success": false,
"error_code": "INVALID_EMAIL",
"message": "Valid customer email is required"
}
{
"success": false,
"error_code": "ISSUER_EMAIL_NOT_ALLOWED",
"message": "You cannot use your own account email as a customer email. Use a different email for this customer."
}
{
"success": false,
"error_code": "EMAIL_ALREADY_IN_USE",
"message": "This email is already associated with your personal card. Each card must use a unique email address.",
"data": {
"account_type": "user",
"flow_status": "card_created"
}
}
{
"success": false,
"error_code": "CUSTOMER_CARD_ALREADY_ACTIVE",
"message": "A customer card with this email already exists. Use the returned card ID to continue onboarding.",
"data": {
"yativo_card_id": "yativo_card_customer_8f9a2b3c4d5e6f7a8b9c0d1e_1769031332068",
"flow_status": "otp_verified",
"next_step": "kyc_link",
"external_customer_id": "usr_8821"
}
}
{
"success": false,
"error_code": "CUSTOMER_CARD_ALREADY_ACTIVE",
"message": "Customer card onboarding already in progress",
"data": {
"yativo_card_id": "yativo_card_customer_8f9a2b3c4d5e6f7a8b9c0d1e_1769031332068",
"flow_status": "otp_requested",
"next_step": "verify_otp"
}
}
{
"success": false,
"error_code": "CUSTOMER_ALREADY_ONBOARDED",
"message": "This customer has already completed card onboarding. No further action is needed.",
"data": {
"yativo_card_id": "yativo_card_customer_8f9a2b3c4d5e6f7a8b9c0d1e_1769031332068",
"flow_status": "active",
"external_customer_id": "usr_8821",
"next_step": "none"
}
}
Card Customer — Onboarding
Create Card Customer
Register a new card customer under your issuer program and trigger email OTP verification
POST
/
v1
/
yativo-card
/
customers
/
onboard
curl -X POST 'https://crypto-api.yativo.com/api/v1/yativo-card/customers/onboard' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"email": "customer@example.com",
"external_customer_id": "usr_8821"
}'
const response = await fetch(
'https://crypto-api.yativo.com/api/v1/yativo-card/customers/onboard',
{
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'customer@example.com',
external_customer_id: 'usr_8821',
}),
}
);
const data = await response.json();
// data.data.yativo_card_id — save this for all subsequent calls
{
"success": true,
"message": "Customer card onboarding initiated. Verification code sent to customer email.",
"data": {
"yativo_card_id": "yativo_card_customer_8f9a2b3c4d5e6f7a8b9c0d1e_1769031332068",
"customer_id": "6627f3a2c5d4e100123abcde",
"external_customer_id": "usr_8821",
"email_masked": "cu***@example.com",
"next_step": "verify_otp",
"otp_expires_in_seconds": 600
}
}
{
"success": false,
"error_code": "INVALID_EMAIL",
"message": "Valid customer email is required"
}
{
"success": false,
"error_code": "ISSUER_EMAIL_NOT_ALLOWED",
"message": "You cannot use your own account email as a customer email. Use a different email for this customer."
}
{
"success": false,
"error_code": "EMAIL_ALREADY_IN_USE",
"message": "This email is already associated with your personal card. Each card must use a unique email address.",
"data": {
"account_type": "user",
"flow_status": "card_created"
}
}
{
"success": false,
"error_code": "CUSTOMER_CARD_ALREADY_ACTIVE",
"message": "A customer card with this email already exists. Use the returned card ID to continue onboarding.",
"data": {
"yativo_card_id": "yativo_card_customer_8f9a2b3c4d5e6f7a8b9c0d1e_1769031332068",
"flow_status": "otp_verified",
"next_step": "kyc_link",
"external_customer_id": "usr_8821"
}
}
{
"success": false,
"error_code": "CUSTOMER_CARD_ALREADY_ACTIVE",
"message": "Customer card onboarding already in progress",
"data": {
"yativo_card_id": "yativo_card_customer_8f9a2b3c4d5e6f7a8b9c0d1e_1769031332068",
"flow_status": "otp_requested",
"next_step": "verify_otp"
}
}
{
"success": false,
"error_code": "CUSTOMER_ALREADY_ONBOARDED",
"message": "This customer has already completed card onboarding. No further action is needed.",
"data": {
"yativo_card_id": "yativo_card_customer_8f9a2b3c4d5e6f7a8b9c0d1e_1769031332068",
"flow_status": "active",
"external_customer_id": "usr_8821",
"next_step": "none"
}
}
Issuer program required. This endpoint is only available to users with an approved Card Issuer Program. Each customer gets a dedicated
yativo_card_id used for all subsequent onboarding steps.string
required
Bearer token:
Bearer YOUR_ACCESS_TOKENstring
required
The customer’s email address. Yativo sends a one-time verification code to this address. Must be unique per active customer card under your account — you cannot reuse your own issuer account email.
string
Your own reference ID for this customer (e.g., a user ID from your platform). Stored as-is and returned on all customer records so you can correlate them on your side. No two active customer sessions may share the same
external_customer_id under your account.curl -X POST 'https://crypto-api.yativo.com/api/v1/yativo-card/customers/onboard' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"email": "customer@example.com",
"external_customer_id": "usr_8821"
}'
const response = await fetch(
'https://crypto-api.yativo.com/api/v1/yativo-card/customers/onboard',
{
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'customer@example.com',
external_customer_id: 'usr_8821',
}),
}
);
const data = await response.json();
// data.data.yativo_card_id — save this for all subsequent calls
{
"success": true,
"message": "Customer card onboarding initiated. Verification code sent to customer email.",
"data": {
"yativo_card_id": "yativo_card_customer_8f9a2b3c4d5e6f7a8b9c0d1e_1769031332068",
"customer_id": "6627f3a2c5d4e100123abcde",
"external_customer_id": "usr_8821",
"email_masked": "cu***@example.com",
"next_step": "verify_otp",
"otp_expires_in_seconds": 600
}
}
{
"success": false,
"error_code": "INVALID_EMAIL",
"message": "Valid customer email is required"
}
{
"success": false,
"error_code": "ISSUER_EMAIL_NOT_ALLOWED",
"message": "You cannot use your own account email as a customer email. Use a different email for this customer."
}
{
"success": false,
"error_code": "EMAIL_ALREADY_IN_USE",
"message": "This email is already associated with your personal card. Each card must use a unique email address.",
"data": {
"account_type": "user",
"flow_status": "card_created"
}
}
{
"success": false,
"error_code": "CUSTOMER_CARD_ALREADY_ACTIVE",
"message": "A customer card with this email already exists. Use the returned card ID to continue onboarding.",
"data": {
"yativo_card_id": "yativo_card_customer_8f9a2b3c4d5e6f7a8b9c0d1e_1769031332068",
"flow_status": "otp_verified",
"next_step": "kyc_link",
"external_customer_id": "usr_8821"
}
}
{
"success": false,
"error_code": "CUSTOMER_CARD_ALREADY_ACTIVE",
"message": "Customer card onboarding already in progress",
"data": {
"yativo_card_id": "yativo_card_customer_8f9a2b3c4d5e6f7a8b9c0d1e_1769031332068",
"flow_status": "otp_requested",
"next_step": "verify_otp"
}
}
{
"success": false,
"error_code": "CUSTOMER_ALREADY_ONBOARDED",
"message": "This customer has already completed card onboarding. No further action is needed.",
"data": {
"yativo_card_id": "yativo_card_customer_8f9a2b3c4d5e6f7a8b9c0d1e_1769031332068",
"flow_status": "active",
"external_customer_id": "usr_8821",
"next_step": "none"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
yativo_card_id | string | Unique customer card identifier. Save this — required for every subsequent onboarding call. |
customer_id | string | Internal Yativo database ID for this customer record. |
external_customer_id | string | null | Your reference ID, echoed back unchanged. |
email_masked | string | Partially masked version of the customer’s email for display purposes. |
next_step | string | Always "verify_otp" on creation. |
otp_expires_in_seconds | number | How long the emailed code is valid (600 = 10 minutes). |
Idempotency
This endpoint is safe to retry. If you call it again with the sameemail or external_customer_id while a session is already active, the API returns the existing card rather than creating a duplicate.
Handling CUSTOMER_CARD_ALREADY_ACTIVE
When you receive this error code, treat it as a resume signal — not a failure. The customer’s card was already created and their OTP was already sent. Read next_step from data and continue the onboarding flow from there:
next_step | What to do next |
|---|---|
verify_otp | OTP has been sent — call POST /customers/{yativoCardId}/verify-otp |
kyc_link | OTP verified — call GET /customers/{yativoCardId}/kyc-link |
continue | Resume from the current flow_status |
none | Customer is fully onboarded — no action needed |
flow_status is active, safe_deployed, or kyc_approved), the API returns 409 CUSTOMER_ALREADY_ONBOARDED with next_step: "none" — no further action is needed for this customer.
Next Steps
After a201 response, direct your customer to check their email and proceed:
- Verify OTP —
POST /v1/yativo-card/customers/{yativoCardId}/verify-otp - Get KYC link —
GET /v1/yativo-card/customers/{yativoCardId}/kyc-link - Poll KYC status —
GET /v1/yativo-card/customers/{yativoCardId}/kyc-status - Submit source of funds —
POST /v1/yativo-card/customers/{yativoCardId}/source-of-funds - Create virtual card —
POST /v1/yativo-card/customers/{yativoCardId}/cards/virtual

