Formats and limits
How the Gravv API writes amounts, dates, ids, country codes and statuses, and how large an uploaded file can be.
The Gravv API mixes a few formats. Most amounts are decimal strings, a few are in minor units, and card routes take numbers. This page lists the rules every route follows and the exceptions. Each endpoint's page has its own details.
Example. You pay out 2,500.00 USD. You send "amount": "2500.00", a string. The transfer response shows "fee": "1.5", with the trailing zero trimmed. The account's ledger_balance.posted reads 120000 with scale 2, which is 1,200.00. The created_at of the transaction reads 2026-10-13T09:15:02.481263Z. Parse all three as written, never as floats.
Amounts
| Where | Format | Example |
|---|---|---|
| Transfers, collections, FX quotes and card funding (requests) | A decimal string in major units, at most 2 decimal places. Transfers also accept a JSON number, but it can lose precision | "2500.00" |
Card withdrawals (amount) and card limits (card_limit, limit) |
A JSON number in US dollars. A string can fail with an internal error | 435.8 |
Most response amounts: amount, fee, account and wallet balance |
A decimal string in major units. The API may trim trailing zeros | "1.5", "250" |
ledger_balance.posted and ledger_balance.projected on accounts |
Minor units, with scale |
120000 with scale 2 is 1,200.00 |
Collections: fee_cents, total_amount_cents |
Minor units (cents) | 150 is 1.50 |
| Webhook amounts | Decimal strings. Transfers trim zeros. Collections always show 2 decimals | "100.5", "1500.00" |
- Never parse an amount as a floating-point number. Use a decimal type, or integers of minor units.
- Currencies are ISO 4217 codes in upper case (
USD,EUR,NGN). Stablecoins areUSDCandUSDT. - The API matches a settlement instruction's
currencyexactly, so always send it in upper case.
Dates and times
- Timestamps are RFC 3339, usually in UTC (
Z), with or without fractional seconds. Gravv sends both2026-10-13T09:15:02Zand2026-10-13T09:15:02.481263Z. Some fields carry an offset instead, such as a customer'sdate_added(+01:00). Parse with an RFC 3339 parser that accepts optional fractions and offsets, and compare times, not text. - A webhook's
timestampis when Gravv sent the event, not always when the change happened. Its precision depends on the event. - Dates without a time are
YYYY-MM-DD:date_of_birth,remitter_date_of_birth, and the dates on KYC documents. Gravv does not check document dates on upload, but a review can reject a document with a wrong date. - Date filters differ by route, and some lists have none. Webhook history takes RFC 3339,
YYYY-MM-DDor a date and time without a zone, and reads all of them as UTC. The transactions list has no date filter, and the FX orders list ignores dates. Filter on your side.
Ids and references
- Gravv ids are UUIDs:
customer_id,account_id,external_account_id,card_id,wallet_id. A transfer'ssource.idandcustomer_idmust be UUID version 4. - Ids belong to one environment. A sandbox id is "not found" with a live key, and the other way round.
- A transfer has two ids: the
transaction_idyou read in transactions, and thereferenceyou resume with. client_referenceis your own reference. Use one per payment and keep it unique.- An on-chain deposit's
transaction_idis<network>:<hash>. - A webhook's
event_id, in the body, is unique per event, so deduplicate on it. TheX-Event-IDheader is shared by every event of one change. See Webhooks.
Codes and casing
| What | Format | Example |
|---|---|---|
| Countries on customers, payees and institutions | ISO 3166-1 alpha-2, upper case | NG, US |
| Countries in card KYC | ISO 3166-1 alpha-3, including on the selfie | NGA |
| Countries in customer KYC documents | Alpha-2 or alpha-3, upper case | NG or NGA |
| States and regions on v2 account forms | ISO 3166-2 | US-CA, GB-LND |
| Statuses, types and most other values | Lower case with underscores. Filters are case-sensitive, so status=PENDING matches nothing |
manual_review, setup_failed, paused |
On-chain deposit events (inflow.onchain.*) |
status in upper case |
COMPLETED, FAILED |
| Customer KYC document types and sides | Upper case | PASSPORT, FRONT_SIDE |
| Card KYC document types | Lower case | passport, id_card |
| Blockchain networks | Lower case | polygon, stellar |
| Phone numbers | E.164, with the country code | +2348012345678 |
Upload sizes
Files go in the JSON body as base64. The decoded file must be a JPEG, PNG or PDF, and Gravv checks the type from the file's content.
| Upload | Largest file in live |
|---|---|
Customer KYC documents, POST /v1/customers/kyc/upload-document |
10 MB |
Card KYC documents, POST /v1/risk/upload-document |
5 MB |
Transfer supporting documents, POST /v1/transfer/documents |
700 KB |
| v2 account documents, on create and on an application update | 2 MB each |
- In sandbox, keep every file under 500 KB, and the files of one request under 500 KB together. Sandbox refuses requests of about 600 KB or more with
413the uploaded file is too large — the maximum is 10MB, whatever the route's own limit. - Gravv does not deduplicate a request body over 1 MiB under its
Idempotency-Key. Base64 encoding makes a file over about 770 KB that large. A retry of such an upload runs again instead of returning the first response. After a timeout, look for what the first call stored before you send it again. See Idempotent requests. - Send standard base64 with no
data:prefix. The v2 account routes also take URL-safe base64.