Skip to main content
Get one call

Authorizations

Authorization
string
header
required

Every request sends Authorization: Bearer <token>. The token is either a panel session (a JWT from /auth/login, 12 hours) or an API key ft_<id>_<secret>. An API key is accepted only from an address on its IP allowlist (403 ip_not_allowed otherwise; 403 ip_allowlist_required for an old key that has none), is limited to its rate per minute (429 rate_limited with Retry-After; X-RateLimit-Limit/Remaining/Reset on every response), and at most 60 call placements a minute.

Path Parameters

uuid
string<uuid>
required

Response

The call. Margin fields are withheld unless the caller holds margin:read.

billing_mode
enum<string>
required
Available options:
rated,
free
billsec
integer
required
call_uuid
string<uuid>
required
direction
enum<string>
required
Available options:
inbound,
outbound,
internal
started_at
string<date-time>
required
transcoded
boolean
required

codec_a differs from codec_b. A rising transcode ratio is the leading indicator of a capacity problem: it presents as 'the switch feels slow' long before anything errors.

transport
enum<string>
required
Available options:
sip,
whatsapp
agent_id
string<uuid> | null
ai_tokens
integer<int64>

Input plus output tokens for the AI that handled this call; absent when no AI did. Read from the conversation rather than the charge, because a charge row exists only where settlement found something to price -- sourcing it from the charge would report "no AI" for a call an AI demonstrably answered. Audio is not added: it is the audio portion of the input, and adding it double-counts.

answered_at
string<date-time> | null
bridge_cause
string

The far end's hangup cause for the last bridge attempt, e.g. a carrier's CALL_REJECTED. hangup_cause is this leg's own. Absent when there was no bridge or no answer.

caller_number
string
campaign_id
string<uuid>

The campaign that placed this call, when one did.

client_trunk_id
string<uuid>

The client trunk the call came in on, when a client's own PBX sent it (the Client trunks module). Absent on every other call. Filter on it with GET /cdrs?client_trunk_id=. Since 2026-09-30.

codec_a
string | null
codec_b
string | null
contact_id
string<uuid>

The customer this call was with.

cost_amount
string

Exact decimal amount as a string. Never a JSON number: rates are fractions of a cent and binary floating point cannot represent them exactly.

Example:

"0.062000"

cost_amount_original
string

What the carrier charged, in cost_currency, before conversion. cost_amount is this multiplied by fx_rate. Omitted without margin:read.

Example:

"0.024000"

cost_currency
string

The currency the CARRIER charged in. Omitted without margin:read.

cost_unconverted
boolean

True when no exchange rate existed for the pair: cost_amount is then the carrier's RAW figure and margin is a subtraction across two currencies, which means nothing. Present only when true, and only with margin:read.

currency
string

ISO 4217 code that sell_amount, cost_amount and margin are all in: the call's own currency, which is its sell rate's. Absent on calls recorded before it was written.

destination_number
string
dialled_number
string

What the caller keyed in, when routing read it as a different number (919216217231 routed as +919216217231). Absent when it was dialled as routed.

ended_at
string<date-time> | null
fs_node_id
string<uuid> | null

The switch node that carried this call. Absent on calls recorded before nodes were written to the record, and on a call the control plane could not attribute to one.

fx_rate
string

The exchange rate in force when the call was settled: one unit of cost_currency in currency. Stored on the call, so a margin does not move when a later rate is entered. Omitted without margin:read.

Example:

"83.20000000"

hangup_cause
string | null
jitter_ms
number | null

Peak inbound jitter in milliseconds. If every leg of every call shows it at once, the cause is the node being scheduled late rather than any one network.

loss_pct
number | null

Percent of inbound packets that never arrived. ABSENT, not zero, when too little audio arrived to judge: FreeSWITCH scores a leg that received nothing as quality 100 and MOS 4.50, and zero is a measurement this leg does not have.

margin
string

Exact decimal amount as a string. Never a JSON number: rates are fractions of a cent and binary floating point cannot represent them exactly.

Example:

"0.062000"

mean_interval_ms
number | null

Mean gap between arriving packets. About 20 on a healthy 20 ms stream; double the negotiated ptime is a ptime mismatch.

media_verdict
enum<string> | null

What the RTP layer said about the audio that ARRIVED on the caller's leg. The codec and the duration both look healthy on a call nobody could understand; this does not. lossy_inbound and jittery_inbound are statistics of what reached the switch, so the damage was done before it got here. Absent for a leg with no RTP session.

Available options:
ok,
unanswered,
no_inbound_media,
no_outbound_media,
wrong_advertised_address,
lossy_inbound,
jittery_inbound,
unpaced_sender,
ptime_mismatch,
degraded_audio
mos
number | null

Derived from quality_pct alone, so it is the same measurement on a different scale and not an independent opinion.

quality_pct
number | null

FreeSWITCH's own (received - flaws) / received.

sell_amount
string

Exact decimal amount as a string. Never a JSON number: rates are fractions of a cent and binary floating point cannot represent them exactly.

Example:

"0.062000"

sip_status
integer

The far end's final SIP response for the last bridge attempt: 403, 503, 486. Absent when none was received.

team_id
string<uuid> | null