customer_id/employee_id in the URL — both are passed as request
fields (query string on GET, request body on POST). Every customer_id
must belong to the authenticated business account, and every employee_id
must belong to that same customer_id — requests for data outside your own
business return 404.
Access requirements
Business Spend Cards must be enabled for your account before any of these endpoints can be used. Two checks apply to every Corporate Card request, and to the employee portal and/api/v1/spend/* and
/api/v1/business/spend-card/* endpoints:
- Your account is approved for Business Spend Cards. Approval is granted
by Yativo — contact support to request it. Until then every request
returns
403:Your account is not yet approved for Business Spend Cards. Please contact support. - The customer holds an approved
faster_paymentsendorsement. Checked for whichever customer the request targets — directly viacustomer_id, or through anemployee_idorcard_idthat belongs to it. Otherwise:This customer does not have an approved Faster Payments endorsement.(403)
403) while the employee is suspended or
terminated, the customer is banned, or your user account is suspended.
Concepts
- Customer — the business’s own registered customer record (already used elsewhere in the API for KYC, virtual accounts, etc). Corporate Card is layered on top of an existing, fully-KYC’d customer.
- Employee — the card holder. One employee can hold multiple cards. Created explicitly via the Employees endpoints below, or automatically the first time a card is requested for a customer that has none yet.
- Employee KYC — a lightweight KYC record captured per employee (identity, address, government ID, payslip/work contract, proof of address) required before a card can be fully activated for spend.
- Memo / Invoice — a note and/or invoice an employee attaches to their card activity, which the business then approves or rejects.
- USDC balance — the business’s own funding wallet. Funding an employee’s card balance debits this wallet; withdrawing credits it back. Every fee is also charged to this balance.
- Employee card balance — the money an employee can spend. It belongs to the employee, and every card they hold spends from it. You fund and withdraw it; the employee can only view it (see the Employee Portal). It exists once the employee’s first card is issued.
- Reserve — a minimum amount that must stay in your USDC balance at all times while your account is approved for Business Spend Cards. See Reserve.
- Corporate Card wallet — a dedicated USDC (Solana) deposit address a business can provision once to fund its USDC balance by depositing crypto directly, separate from any other wallets on the account.
Customers
Create a customer
customer_name, customer_email, customer_phone,
customer_type (individual or business), customer_country.
Before the customer can be used for Corporate Cards it also needs an approved
faster_payments endorsement — see Access requirements.
Employees
Create an employee
Selfie image (optional) — supply one of:
When both are present the uploaded file takes precedence. Omit both to skip.
Uploaded selfies are stored privately; see Private document links.
The upload happens before the employee is created: if it fails, the request
returns
502 (Unable to upload the selfie image. Please try again.) and no
employee is created, so it is safe to retry.
Update an employee
A failed selfie upload returns
502 and leaves the employee unchanged.
List employees
customer (customer_id, customer_name,
customer_email) and cards_count. Optional query filters:
Get an employee
metadata and current kyc sub-object.
Terminate an employee
status to terminated, suspends all cards held by that employee, and
soft-deletes the record. This action is not reversible via the API.
Employee KYC
Submit or update KYC
employee_id is a required field in the request body (multipart or JSON),
alongside the KYC data. Accepts either multipart/form-data with file
fields, or JSON with hosted URLs — both are supported for each document:
All three document fields are optional — supply at least the file or the URL
for any document you want to attach; omit both to skip it. A file field also
accepts a base64 string (
data:<type>;base64,... or raw base64) instead of a
multipart file. Accepted types: images (jpg, png, webp, gif, heic), PDF, Word,
Excel, CSV and plain text; max 10 MB. The type is detected from the file’s
content, not its name. If a file upload fails, the request returns 422 naming
the field (e.g. Unable to upload gov_id_image. Please try again.).
Private document links
Uploaded selfies and KYC documents are stored privately. The URL saved on the employee is a Yativo link (https://<api-host>/files/private/...) that only
opens for your account (bearer token) or Yativo staff. To display one in a
browser (<img>, new tab), exchange it for a 15-minute signed link:
{ "url": "<signed link>", "expires_in": 900 }. Only your own
files can be signed; anything else returns 404.
Required identity/address fields: employee_id, full_name, id_type,
id_number, dob, street, city, postal_code, gov_id_type,
gov_id_number.
Optional identity/address fields: state_id, country_id, nationality,
occupation.
country_id— the country’s ISO2 code (e.g.US), taken from theiso2field of the countries list below. Despite its name, this is not the numeric countryid.nationality— also an ISO2 code (e.g.NG).state_id— the numericidof a state from the states list below. An unknownstate_idis rejected with422 Invalid state_id.
employee_kyc fee to your USDC balance (Business Spend Card wallet only —
this wallet is not used for payouts, swaps, or other products). Resubmissions
and updates for the same employee are free. If the fee can’t be charged the
request returns 402, the KYC is not saved, and the error explains that you
need sufficient USDC to pay the employee KYC fee (for example:
Insufficient USDC balance to pay the employee KYC fee (0.50 USD). Fund your Business Spend Card wallet and try again.).
Looking up countries and states
Use these endpoints to populate country and state pickers and to resolve the values sent in the KYC request. They are public, need no authentication, and return cached reference data.{country_id} here is the numeric id from the countries list (e.g. 101),
not the ISO2 code. GET /api/v1/locations/states without a country returns
every state and is not recommended, as the response is large.
Example — list countries:
iso2 as country_id in the KYC request. Then fetch
/states/{id} with that country’s numeric id, and send the chosen state’s
id as state_id.
Get KYC status
status (pending, approved, rejected) and, when rejected, a
reject_reason. KYC approval/rejection itself is performed internally after
review — it is not a customer-facing action.
Memos / Invoices
Employees (or the business, on an employee’s behalf) can attach a memo and/or invoice to card activity, which the business then approves or rejects.POST .../memos requires employee_id in the body, plus note (text), and
either an invoice file upload or an invoice_url, plus an optional
card_id to tie the memo to a specific card. Rejecting a memo requires a
reject_reason. A failed invoice upload returns 502
(Unable to upload the invoice. Please try again.) and no memo is created.
Employee card balance
Each employee has one card balance that all of their cards spend from. You manage it; employees can view theirs in the employee portal but can’t move it.Get an employee’s card balance
available_balanceis what the employee can spend right now.ledger_balancealso includes authorizations that haven’t settled yet.has_cardholderisfalseuntil the employee’s first card is issued. Until then the balance is zero and can’t be funded.balance_unavailableistrueif the balance couldn’t be read in full right now. Retry later.accountsusually has a single entry. Employees whose cards were issued before employee card balances existed can have more than one; the totals above cover all of them.
Fund or withdraw
- Fund debits your USDC balance and credits the employee’s card balance. It can’t use the reserve.
- Withdraw moves money from the employee’s card balance back to your
USDC balance and charges the
card_withdrawalfee. It is refused with422if it exceeds the employee’s available balance. Withdrawing everything doesn’t close any cards. - An employee with no card yet returns
404. - Send an
Idempotency-Keyheader to make retries safe.
GET .../balance.
Cards
POST .../cards requires customer_id in the body. employee_id is
optional: pass it to issue the card to a specific employee (it must already
belong to that customer_id); omit it and the API resolves — or, the first
time, creates — that customer’s employee automatically. Either way, an
employee can hold any number of cards, with no per-employee limit.
Issuance fees are charged to your USDC balance before the card is
requested, and refunded automatically if the card can’t be issued:
Terminated or deleted virtual cards still count towards “first”, so
terminating and reissuing a card is not free. If a fee can’t be charged the
request returns
402 and no card is issued. Cards an employee creates for
themselves in the employee portal follow the same rules and are charged to
your balance.
GET .../cards returns every card you own: cards issued by your account,
and any card belonging to one of your customers or to an employee of one of
your customers. It accepts optional customer_id and employee_id query
filters, plus status.
Managing an employee’s cards
You can see and manage every card that belongs to your customers and their employees (you → customer → employee → card), including cards an employee created for themselves in the employee portal. Cards are referenced bycard_id (the opaque id returned in card responses).
.../{card_id}returns a single card.- To view full card details, call
GET /api/v1/spend/cards/{card_id}/widget-token. It returns{"iframe": "<url>"}, a short-lived link to a secure page showing the full card number, expiry and CVV. Embed it as an<iframe src>; request a new one each time. status,pinandlimitstakecustomer_idandcard_idin the body, plus:action(activate,suspend,terminate) for status;pinfor PIN; alimitsarray for limits.- To add or remove money, use the employee’s card balance, which all of their cards share.
/api/v1/spend/cards
(POST /spend/cards, GET /spend/cards, POST /spend/cards/status,
POST /spend/cards/pin, PUT /spend/cards/limits) with identical fields
and behaviour. POST /spend/cards/wallet (fund or withdraw by card_id)
remains for existing integrations. New integrations should use the
employee card balance instead.
Every endpoint only sees cards you own. A card_id that belongs to another
account returns 404.
Card transactions & disputes
Every card authorization is recorded in your transaction history, where you can add notes, attach receipts, and raise disputes.transaction_id in the
business_spend_card.transaction.* webhooks is the id used here.
On sandbox you can simulate a real spend-card authorization (it is written to
the card’s activity history) with
POST /api/v1/sandbox/spend-cards/{cardId}/simulate, or send a sample event
without creating a record with POST /api/v1/demo/webhook/spendcard. See
Testing on sandbox.
- The list accepts optional
statusandcard_idfilters. A single transaction includes itsnotesandinvoices. - Notes take
{ "note": "..." }. Invoices aremultipart/form-datawith aninvoicefile (jpg, jpeg, png or pdf, max 10 MB). Every file is virus-scanned before it is stored, and a file that fails the scan is rejected with422.
Raise a dispute
reason is required (max 500 characters). Raising a dispute charges the
dispute fee to your USDC balance, marks the transaction as disputed, and
sends a business_spend_card.transaction.disputed webhook. Our operations
team then files the dispute with the card network.
A transaction can also be disputed by customer with
POST /api/v1/spend/cards/transactions/{transaction_id}/dispute, which takes
customer_id and reason in the body and behaves the same way.
Corporate Card funding wallet (USDC deposits)
A business can provision a dedicated Solana/USDC deposit address to top up its USDC balance directly, separate from any other crypto wallets on the account.customer_id (body on POST, query string on GET) so the
request can be authorized against a customer you own. The wallet itself is
per business, not per customer — every customer on the same account
shares one Solana/USDC deposit address. POST is idempotent; calling it
again, even with a different customer_id, returns that same wallet. GET
returns the wallet address and status, plus your balance split into what is
reserved and what you can spend:
Deposits to this address are detected automatically and credited to the
business’s USDC balance — no manual reconciliation is required. They do
not load any employee card; assign balance with
POST /api/v1/corporate-card/employees/balance or from the dashboard.
Only send USDC on Solana to this address. Always read the current
wallet.wallet_address from GET /api/v1/corporate-card/wallet before
depositing rather than reusing a stored copy: Yativo may move a wallet to a
new address. When that happens, deposits that still arrive at the previous
address continue to be credited, but new deposits should go to the current
one. The wallet object contains wallet_address, wallet_currency
(USDC_SOL) and wallet_status.
Reserve
While your account is approved for Business Spend Cards, a minimum amount must stay in your USDC balance at all times. The default is 2,000 USD; Yativo may agree a different amount for your account.- The reserve can’t be spent — card balance funding and other spend-card debits stop at it (payouts and transfers cannot use the USDC wallet at all).
- Fees can use it. That is what it is held for, so a fee is still charged when your available balance is zero.
- A debit that would go below the reserve returns an error such as:
Insufficient available balance. A minimum balance of 2,000.00 USD must be kept in your USDC balance for Business Spend Cards; 150.00 USD is available to spend. - If access is revoked, the reserve is released.
usdc_available_balance from GET /api/v1/corporate-card/wallet to see
how much you can spend.
Fees
All Business Spend Card fees are charged to your USDC balance. Amounts come from your pricing agreement; contact your account manager for your rates. Each fee is charged at most once per event, so retries and repeated webhooks never double-charge.
A transaction is cross-border when the merchant is outside the card’s home
country or, if the merchant country isn’t known, when it is in a currency
other than the card’s home currency.
Fees you trigger through the API (card issuance, KYC, disputes, withdrawals)
are charged before the action runs: if the fee can’t be charged the request
returns
402 and nothing happens. Fees triggered by card activity or the
monthly cycle are retried automatically if your balance can’t cover them
when they fall due.
Errors
All endpoints return the standard API error envelope on failure.
When the card service rejects a request,
data.error gives the reason (for
example an invalid date of birth). When it can’t complete the request at all,
you get 502 with The card service could not complete this request right now. Please try again later. Responses never include the card service’s raw
response.
