Issue a card
curl --request POST \
--url https://api.fyatu.com/api/v3.20/cards \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"cardholderId": "chl_01HXYZ1234ABCDEF5678",
"productId": "prd_01HXYZ1111ABCDEF0001",
"amount": 100,
"customName": "Travel Card"
}
'import requests
url = "https://api.fyatu.com/api/v3.20/cards"
payload = {
"cardholderId": "chl_01HXYZ1234ABCDEF5678",
"productId": "prd_01HXYZ1111ABCDEF0001",
"amount": 100,
"customName": "Travel Card"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
cardholderId: 'chl_01HXYZ1234ABCDEF5678',
productId: 'prd_01HXYZ1111ABCDEF0001',
amount: 100,
customName: 'Travel Card'
})
};
fetch('https://api.fyatu.com/api/v3.20/cards', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.fyatu.com/api/v3.20/cards",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'cardholderId' => 'chl_01HXYZ1234ABCDEF5678',
'productId' => 'prd_01HXYZ1111ABCDEF0001',
'amount' => 100,
'customName' => 'Travel Card'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.fyatu.com/api/v3.20/cards"
payload := strings.NewReader("{\n \"cardholderId\": \"chl_01HXYZ1234ABCDEF5678\",\n \"productId\": \"prd_01HXYZ1111ABCDEF0001\",\n \"amount\": 100,\n \"customName\": \"Travel Card\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.fyatu.com/api/v3.20/cards")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"cardholderId\": \"chl_01HXYZ1234ABCDEF5678\",\n \"productId\": \"prd_01HXYZ1111ABCDEF0001\",\n \"amount\": 100,\n \"customName\": \"Travel Card\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fyatu.com/api/v3.20/cards")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"cardholderId\": \"chl_01HXYZ1234ABCDEF5678\",\n \"productId\": \"prd_01HXYZ1111ABCDEF0001\",\n \"amount\": 100,\n \"customName\": \"Travel Card\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"status": 201,
"message": "Card issued",
"data": {
"id": "crd_01HXYZ5555ABCDEF1111",
"cardholderId": "chl_01HXYZ1234ABCDEF5678",
"productId": "prd_01HXYZ1111ABCDEF0001",
"status": "ACTIVE",
"cardType": "VIRTUAL",
"cardBrand": "VISA",
"maskedPan": "445123******4123",
"last4": "4123",
"createdAt": "2026-05-26T10:00:00Z",
"updatedAt": "2026-05-26T10:00:00Z",
"nameOnCard": "Travel Card",
"expirationDate": "06/2030",
"balance": 100,
"currency": "USD",
"features": {
"has3DS": true,
"hasApplePay": false,
"hasGooglePay": false,
"hasJIT": false,
"hasSpendControl": true,
"hasMccControl": false,
"isReloadable": true,
"isOneTimeUse": false
},
"spendingLimit": 1000,
"spendingPeriod": "TRANSAMOUNT",
"billingAddress": {
"address": "1234 Main St",
"city": "New York",
"state": "NY",
"zipCode": "10001",
"country": "US"
}
},
"meta": {
"requestId": "req_01HXY123456ABCDEF",
"platform": "Fyatu CaaS",
"timestamp": "2026-05-26T10:00:00Z"
}
}Cards
Issue Card
Issue a new virtual card to a cardholder. POST /cards. Requires cards:write scope.
POST
/
cards
Issue a card
curl --request POST \
--url https://api.fyatu.com/api/v3.20/cards \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"cardholderId": "chl_01HXYZ1234ABCDEF5678",
"productId": "prd_01HXYZ1111ABCDEF0001",
"amount": 100,
"customName": "Travel Card"
}
'import requests
url = "https://api.fyatu.com/api/v3.20/cards"
payload = {
"cardholderId": "chl_01HXYZ1234ABCDEF5678",
"productId": "prd_01HXYZ1111ABCDEF0001",
"amount": 100,
"customName": "Travel Card"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
cardholderId: 'chl_01HXYZ1234ABCDEF5678',
productId: 'prd_01HXYZ1111ABCDEF0001',
amount: 100,
customName: 'Travel Card'
})
};
fetch('https://api.fyatu.com/api/v3.20/cards', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.fyatu.com/api/v3.20/cards",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'cardholderId' => 'chl_01HXYZ1234ABCDEF5678',
'productId' => 'prd_01HXYZ1111ABCDEF0001',
'amount' => 100,
'customName' => 'Travel Card'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.fyatu.com/api/v3.20/cards"
payload := strings.NewReader("{\n \"cardholderId\": \"chl_01HXYZ1234ABCDEF5678\",\n \"productId\": \"prd_01HXYZ1111ABCDEF0001\",\n \"amount\": 100,\n \"customName\": \"Travel Card\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.fyatu.com/api/v3.20/cards")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"cardholderId\": \"chl_01HXYZ1234ABCDEF5678\",\n \"productId\": \"prd_01HXYZ1111ABCDEF0001\",\n \"amount\": 100,\n \"customName\": \"Travel Card\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fyatu.com/api/v3.20/cards")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"cardholderId\": \"chl_01HXYZ1234ABCDEF5678\",\n \"productId\": \"prd_01HXYZ1111ABCDEF0001\",\n \"amount\": 100,\n \"customName\": \"Travel Card\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"status": 201,
"message": "Card issued",
"data": {
"id": "crd_01HXYZ5555ABCDEF1111",
"cardholderId": "chl_01HXYZ1234ABCDEF5678",
"productId": "prd_01HXYZ1111ABCDEF0001",
"status": "ACTIVE",
"cardType": "VIRTUAL",
"cardBrand": "VISA",
"maskedPan": "445123******4123",
"last4": "4123",
"createdAt": "2026-05-26T10:00:00Z",
"updatedAt": "2026-05-26T10:00:00Z",
"nameOnCard": "Travel Card",
"expirationDate": "06/2030",
"balance": 100,
"currency": "USD",
"features": {
"has3DS": true,
"hasApplePay": false,
"hasGooglePay": false,
"hasJIT": false,
"hasSpendControl": true,
"hasMccControl": false,
"isReloadable": true,
"isOneTimeUse": false
},
"spendingLimit": 1000,
"spendingPeriod": "TRANSAMOUNT",
"billingAddress": {
"address": "1234 Main St",
"city": "New York",
"state": "NY",
"zipCode": "10001",
"country": "US"
}
},
"meta": {
"requestId": "req_01HXY123456ABCDEF",
"platform": "Fyatu CaaS",
"timestamp": "2026-05-26T10:00:00Z"
}
}Overview
Issue a virtual prepaid card to a cardholder under one of your programs. PassproductId — the program, card type, and spend limits are all derived from the product automatically.
Card issuance is asynchronous. A successful response means the request was accepted; the card may be returned with status
CREATING (no PAN yet) and becomes usable only once provisioning completes. If the response is delayed or times out, the card is still being created — poll Get Card until status is ACTIVE rather than treating the immediate response as final.- JIT-enabled products (
features.hasJIT: true): The card is funded on-demand at the point of each transaction.amountis optional. - Standard products (
features.hasJIT: false): The card requires an initial balance at issuance.amountis required.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
cardholderId | string | Yes | The cardholder to issue the card to |
productId | string | Yes | The card product — program, card type, and spend limits are derived from this |
amount | number | Conditional | Initial balance in USD. Required when the product is not JIT-enabled |
customName | string | No | Card label. Defaults to the cardholder’s full name |
Example
curl -X POST https://api.fyatu.com/api/v3.20/cards \
-H "Authorization: Bearer $FYATU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"cardholderId": "chl_01HXYZ1234ABCDEF5678",
"productId": "prd_01HXYZ1111ABCDEF0001",
"amount": 100.00,
"customName": "Travel Card"
}'
const resp = await fetch('https://api.fyatu.com/api/v3.20/cards', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.FYATU_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
cardholderId: 'chl_01HXYZ1234ABCDEF5678',
productId: 'prd_01HXYZ1111ABCDEF0001',
amount: 100.00,
customName: 'Travel Card'
})
});
const body = await resp.json();
const card = body.data;
console.log('Card ID:', card.id);
console.log('Expiry:', card.expirationDate);
console.log('Balance:', card.balance, card.currency);
import os, requests
resp = requests.post(
'https://api.fyatu.com/api/v3.20/cards',
headers={'Authorization': f'Bearer {os.environ["FYATU_API_KEY"]}'},
json={
'cardholderId': 'chl_01HXYZ1234ABCDEF5678',
'productId': 'prd_01HXYZ1111ABCDEF0001',
'amount': 100.00,
'customName': 'Travel Card'
}
)
card = resp.json()['data']
print('Card ID:', card['id'])
print('Expiry:', card['expirationDate'])
print('Balance:', card['balance'], card['currency'])
Success Response (201)
{
"success": true,
"status": 201,
"message": "Card issued",
"data": {
"id": "crd_01HXYZ5555ABCDEF1111",
"cardholderId": "chl_01HXYZ1234ABCDEF5678",
"productId": "prd_01HXYZ1111ABCDEF0001",
"status": "ACTIVE",
"cardType": "VIRTUAL",
"cardBrand": "VISA",
"maskedPan": "445123******4123",
"last4": "4123",
"createdAt": "2026-05-26T10:00:00Z",
"updatedAt": "2026-05-26T10:00:00Z",
"nameOnCard": "Travel Card",
"expirationDate": "06/2030",
"balance": 100.00,
"currency": "USD",
"features": {
"has3DS": true,
"hasApplePay": false,
"hasGooglePay": false,
"hasJIT": false,
"hasSpendControl": true,
"hasMccControl": false,
"isReloadable": true,
"isOneTimeUse": false
},
"spendingLimit": 1000.00,
"spendingPeriod": "TRANSAMOUNT",
"billingAddress": {
"address": "1234 Main St",
"city": "New York",
"state": "NY",
"zipCode": "10001",
"country": "US"
}
},
"meta": {
"requestId": "req_01HXY123456ABCDEF",
"platform": "Fyatu CaaS",
"timestamp": "2026-05-26T10:00:00Z"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
id | string | Card identifier (prefix crd_) |
cardholderId | string | The cardholder this card belongs to |
productId | string | The product the card was issued under |
status | string | Always ACTIVE at issuance |
cardType | string | VIRTUAL or PHYSICAL |
cardBrand | string | VISA or MASTERCARD |
maskedPan | string | BIN-masked PAN — first 6 digits + 6 stars + last 4 (e.g. 445123******4123) |
last4 | string | Last 4 digits of the PAN |
createdAt | string | ISO 8601 creation timestamp |
updatedAt | string | ISO 8601 last-update timestamp |
nameOnCard | string | Name displayed on the card — customName if provided, otherwise the cardholder’s full name |
expirationDate | string | Card expiry in MM/YYYY format (e.g. 06/2030) |
balance | number | Current card balance in USD |
currency | string | Card currency (always USD) |
features | object | Card capability flags inherited from the product |
features.has3DS | boolean | 3D Secure enabled |
features.hasApplePay | boolean | Apple Pay tokenisation supported |
features.hasGooglePay | boolean | Google Pay tokenisation supported |
features.hasJIT | boolean | Just-In-Time funding enabled (no pre-fund required) |
features.hasSpendControl | boolean | Spend limit control active |
features.hasMccControl | boolean | MCC (merchant category) control active |
features.isReloadable | boolean | Card can be topped up via POST /cards/{id}/fund |
features.isOneTimeUse | boolean | Card terminates automatically after its first settled transaction |
spendingLimit | number | Spend cap per spendingPeriod in USD, inherited from the product |
spendingPeriod | string | Period over which the spend cap applies — TRANSAMOUNT, DAILY, WEEKLY, MONTHLY, QUARTERLY, YEARLY, or LIFETIME |
billingAddress | object | Billing address registered with the card provider |
billingAddress.address | string | Street address |
billingAddress.city | string | City |
billingAddress.state | string | State or region |
billingAddress.zipCode | string | Postal code |
billingAddress.country | string | Two-letter ISO 3166-1 country code |
Provisioning is asynchronous
The card provider provisions cards asynchronously. When you callPOST /cards, the card may come back with status: "CREATING" and empty maskedPan, last4, and expirationDate — provisioning can take anywhere from a few seconds up to ~1 hour. The 201 response is an acknowledgement that the card was accepted, not a guarantee the card number is ready.
If you store only the
cardId from the 201, do not read maskedPan/last4/expirationDate from that response — they may be blank. Use the CARD_ISSUED webhook (below) as the authoritative “card is ready” signal: it fires once, when provisioning completes, and always carries the finalized maskedPan, last4, and expirationDate. You can also poll GET /cards/{id} — a CREATING card returns ACTIVE with full details once ready.Webhook
TheCARD_ISSUED event is fired when the card finishes provisioning (CREATING → ACTIVE) — immediately for instantly-provisioned cards, or later (up to ~1h) for cards that were CREATING. It always includes the complete card details:
{
"event": "CARD_ISSUED",
"eventId": "evt_01HXY123456ABCDEF",
"businessId": "BUS1A2B3C4D5E6F",
"environment": "LIVE",
"timestamp": "2026-05-26T10:00:00Z",
"data": {
"cardId": "crd_01HXYZ5555ABCDEF1111",
"status": "ACTIVE",
"cardType": "VIRTUAL",
"cardBrand": "VISA",
"cardholderId": "chl_01HXYZ1234ABCDEF5678",
"maskedPan": "445123******4123",
"last4": "4123",
"expirationDate": "06/2030",
"balance": 100.00,
"currency": "USD",
"is3ds": true,
"isTokenized": false,
"isJitfEnabled": false
}
}
Error Codes
| Code | HTTP | Cause |
|---|---|---|
CARD_AMOUNT_REQUIRED | 400 | amount was not provided for a non-JIT product |
INVALID_REQUEST | 400 | Missing required field or unsupported card type |
CARDHOLDER_NOT_FOUND | 404 | Cardholder does not exist or belongs to another business |
PRODUCT_NOT_FOUND | 404 | Product does not exist or belongs to another business |
PROGRAM_NOT_FOUND | 404 | Program linked to the product not found |
PRODUCT_INACTIVE | 422 | Product is not active |
PROGRAM_INACTIVE | 422 | Program is not active |
CARDHOLDER_INACTIVE | 422 | Cardholder is suspended or terminated |
CARDHOLDER_KYC_NOT_APPROVED | 422 | Cardholder KYC is not APPROVED or WAIVED |
CARDHOLDER_CARD_LIMIT_EXCEEDED | 409 | Cardholder has reached the maxCardsPerCardholder limit for this product |
PROVIDER_CREATE_FAILED | 422 | Card creation was rejected by the card provider |
CARD_CREATION_UNAVAILABLE | 503 | Card creation is temporarily unavailable — either paused by Fyatu, or a transient processing issue on our side. Retry later. |
INSUFFICIENT_SCOPE | 403 | Key lacks cards:write scope |
INTERNAL_ERROR | 500 | Server error |
Authorizations
API key from the FYATU CaaS portal. Pass as Authorization: Bearer <key>.
Body
application/json
The cardholder to issue the card to
Example:
"chl_01HXYZ1234ABCDEF5678"
The card product — card type and program are derived from this
Example:
"prd_01HXYZ1111ABCDEF0001"
Initial balance in USD. Required for non-JIT products; optional for JIT-enabled products.
Example:
100
Card label. Defaults to the cardholder's full name when omitted.
Example:
"Travel Card"
Response
Card issued
⌘I

