Skip to content

Response Format

Every endpoint returns application/json encoded as UTF-8, regardless of the Accept header. Send Content-Type: application/json on requests that carry a body.

Collection endpoints wrap their payload in data; single-object endpoints return their fields at the top level. This is not an accident, and it is worth knowing before you write a parser:

{ "data": [ { "id": 47, "slug": "wavalid-realtime" } ] }
{ "balance": "5.230000" }

GET /v1/products is the collection case; GET /v1/balance and GET /v1/api-key are the single-object case. The realtime endpoints return the call’s own object — request_id, status, results — at the top level.

Errors use a fixed two-field object:

{
"code": "invalid_realtime_request",
"message": "A realtime request cannot mix phone and email products."
}
FieldMeaning
codeA stable machine-readable identifier. Branch on this.
messageHuman-readable detail. Wording may change; do not parse it.

The code values are documented per endpoint, together with the HTTP status they arrive with — see Error codes for the full list.

Money appears in two forms, and the difference matters when you parse:

WhereTypeExample
balance in GET /v1/balancestring"5.230000"
total_charged, charged_amount, refunded_amount in realtime responsesnumber0.004000

The balance is emitted as a fixed-precision decimal string so that no client ever sees a rounding artefact on a value it is about to compare against a threshold. Realtime amounts are numbers rounded to six decimal places — treat them as approximate at beyond six decimals.

Amounts are in USD, and the currency symbol is never included in the payload. Format the number yourself for display; do not infer the currency from a separator or a prefix.

Timestamps are ISO 8601 in UTC, with a Z suffix:

2026-09-13T10:00:00Z

checked_at on a realtime result, and the task timestamps on bulk responses, follow this.

Two patterns exist and both are deliberate:

  • Realtime: HTTP 200 means the call was executed, not that every product answered. Read status and each entry’s billing_status.
  • Bulk: a submission returns 202-style task acceptance; the work continues asynchronously and the outcome only exists once the task reaches a terminal status.

The rule in both cases: the status code tells you whether to retry, the body tells you what happened.