Formats
Timestamps
Always RFC 3339, always UTC, on the way out:
"startTime": "2026-08-11T13:20:01Z"
There is no local-time variant and no epoch variant. If you need to show a user
their own wall-clock time, GET /users returns each user's IANA timeZone
(America/New_York) — convert client-side.
Phone numbers
| On input | Formatting is stripped. "(212) 555-0188", "212-555-0188" and "12125550188" are the same number. |
| On output | Digits, 11-digit form for US numbers: "12125550188". No +, no punctuation. |
Two consequences worth knowing:
Copy output straight into input. number from GET /sms/lines is exactly
what POST /sms/messages wants as from. No reformatting step.
Normalized values come back in the response. A send to "(347) 555-0123"
returns "13475550123" in messages[].to — what was actually dialled and what
the charge is against. The one exception is skipped[].to, which echoes your
input, because a skipped recipient may not have normalized at all and you need to
match it back to what you sent.
Extensions vs numbers
Both appear as strings and they are not interchangeable:
"204"— an internal extension."12125550188"— an external number.
On a recording's from/to, an internal leg carries extensions, not phone
numbers. Do not assume every value is dialable from outside.
Ids
| Id | Type | Example |
|---|---|---|
| User id | integer | 481920 |
| Webhook id | integer | 2074 |
| SMS message id | integer | 88214417 |
| Call id | string | "1754489201.884213" |
Recording leg id (uniqueId) | string | "1754489201.884213" |
A call id is a unix timestamp, a dot, and a sequence number. Keep it a
string — parsing it as a float loses precision and silently corrupts the id.
Malformed call ids get a 400 naming the expected shape, not a 404.
Money
{"currency": "USD", "unitPrice": 0.0025, "price": 0.0025, "totalPrice": 0.0025}
Prices are JSON numbers in whole dollars — 0.0025 is a quarter of a cent,
not 25 of anything. currency is always USD today and is stated on every
response so you never have to assume.
:::caution Do not sum these as floats A per-segment SMS price has four decimal places, and accumulating thousands of them in a float drifts. Convert to a decimal type on arrival, or work in ten-thousandths of a dollar as integers. :::
price = unitPrice × units, always. See
SMS billing for what a unit is.
Booleans mean what they say
No 0/1, no "true" strings. true and false.
The one to watch is billing.billed, which is always true — it describes
the endpoint (this costs money), not the individual call. It stays true even
when a particular request cost nothing because everything was skipped.