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 are USDC and USDT.
  • The API matches a settlement instruction's currency exactly, 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 both 2026-10-13T09:15:02Z and 2026-10-13T09:15:02.481263Z. Some fields carry an offset instead, such as a customer's date_added (+01:00). Parse with an RFC 3339 parser that accepts optional fractions and offsets, and compare times, not text.
  • A webhook's timestamp is 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-DD or 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's source.id and customer_id must 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_id you read in transactions, and the reference you resume with.
  • client_reference is your own reference. Use one per payment and keep it unique.
  • An on-chain deposit's transaction_id is <network>:<hash>.
  • A webhook's event_id, in the body, is unique per event, so deduplicate on it. The X-Event-ID header 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 413 the 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.
Was this page helpful?