Call
One conversation as the caller lives it, from the first ring to the last hang-up, with every Leg that it takes.
A call through an IVR and a Hunt Group, then a transfer, is still one Call. Each step is a Leg.
This is the Call Log of app.onsim, with one Call open. The top row is the Call: who called, who answered, when, and for how long. The rows under it are its Legs, in the order that the call took. A Leg sits one step to the right of the Leg that caused it.
Fields
Section titled “Fields”| Field | Type | What it is | On app.onsim |
|---|---|---|---|
id | string | The ID of the Call. It can hold @ and :, so encode it in a path. | Not shown. |
direction | "inbound" | "outbound" | "internal" | inbound: from outside to you. outbound: from you to outside. internal: between two of your extensions. | The icon at the start of the Call column. |
outcome | "answered" | "missed" | "abandoned" | "unanswered" | answered: a person speaks to the caller. missed: an inbound Call rings a User or a Hunt Group, and nobody answers. abandoned: the caller of an inbound Call hangs up in an IVR, before anything rings. unanswered: nobody answers an outbound or an internal Call. | The badge of the Call column. |
from | Party | Who makes the Call. | The From column. |
answered_byoptional | Party | The first person who speaks to the caller. Only an answered Call has it. | The name of the To column, and the avatar at the front of its stack. |
started_at | string | When the Call starts. | The Date & Time column. |
ended_at | string | When the Call ends. | The Duration column: ended_at less started_at. |
chargeoptional | CallCharge | What we charge for the Call. A Call has none when none of its Legs has a charge. | The Charge column, in pounds to 2 decimal places. A Call with no charge shows a dash. |
legs | list of Leg | The Legs of the Call, as a tree. The first is the start of the Call. | The rows under the Call when it is open. The To column also stacks the party that the caller dials and each party that answers. |
A Leg is one step of a Call that tries to reach one party. Legs nest: the Leg that causes another is its parent.
| Field | Type | What it is | On app.onsim |
|---|---|---|---|
id | string | The ID of the Leg. It holds spaces, so encode it in a path. | Not shown. |
call_idoptional | string | The ID of the call that this Leg comes from, only when it is not the id of the Call. An attended transfer joins a second call into the Call. Use this ID to get the Recording of the Leg. | Not shown. |
party | Party | Who the Leg tries to reach. | The To column of the row of the Leg. |
outcome | "answered" | "voicemail" | "busy" | "answered_elsewhere" | "unreachable" | "unanswered" | How the Leg ends. answered means that the Leg connects, also to an IVR or a mailbox. It does not mean that a person speaks: the outcome of the Call says that. voicemail: voicemail takes the Leg. busy: the phone is busy. answered_elsewhere: another phone of the same ring takes the call. unreachable: the phone is offline. unanswered: every other end. | The badge of the row. A Leg that nobody answers is faint. |
started_at | string | When the Leg starts. For a ring that nobody answers, this is when the phone starts to ring. | The start of the grey part of the bar, which is the ring. |
answered_atoptional | string | When the Leg connects. A Leg that nobody answers has none. | The start of the purple part of the bar. |
passed_on_atoptional | string | When a Leg under this one takes the call over. The part of this Leg ends here. A Leg that keeps the call has none. | The end of the purple part of the bar. |
ended_at | string | When the Leg closes. A Leg that passes the call on stays open to the end of the Call, so do not use ended_at less started_at as its length. The part of the Leg is from answered_at to passed_on_at, or to ended_at when it has no passed_on_at. | The end of the purple part, for a Leg that keeps the call. |
recorded | boolean | True when the Leg has a Recording. | Not shown. |
chargeoptional | Charge | What we charge for the Leg. A Leg has none when the call record has no amount. A duplicate and an artefact have their own charge. To get the charge of one step, add the charges of the duplicates and artefacts next to its Leg. | Not shown. |
unlinkedoptional | boolean | Only on a Leg whose place in the Call is not known. It is next to the first Leg, not under the Leg that caused it. | The Unlinked badge. |
duplicate_ofoptional | string | Only on a duplicate: the ID of the Leg that it duplicates. A call between two of your accounts has two legs. One is on the account that dials, and one is on the account that the call reaches. The Leg is the one that the call reaches. The duplicate is next to it, with no Legs under it. It has the charge of the account that dials. Its outcome is the outcome of the account that dials, so it can read answered in a missed Call. Leave out the duplicates to show each step one time. A duplicate can have a Recording of the same conversation. | No row. The call log leaves out a duplicate, so each step shows one time. |
artefact_ofoptional | string | Only on an artefact: the ID of the IVR Leg that it is next to. An IVR makes an extra leg on its own account, with a withheld caller. It shows no step of its own, but it can have a charge. The artefact is next to the IVR Leg, with no Legs under it. Leave out the artefacts to show each step one time. | No row. The call log leaves out an artefact, because it shows no step. |
legs | list of Leg | The Legs that this Leg causes, in the order that they start. | The rows under the row, one step to the right, each with an arrow. |
How long a Leg lasts
Section titled “How long a Leg lasts”A Leg that passes the call on stays open until the Call ends. So ended_at less started_at is not the length of the Leg. The part of a Leg is from answered_at to passed_on_at, or to ended_at when it has no passed_on_at.
answered on a Leg
Section titled “answered on a Leg”On a Leg, answered means that the Leg connects. An IVR and a mailbox connect too. The outcome of the Call says if a person speaks to the caller, and answered_by says who.
Duplicates and artefacts
Section titled “Duplicates and artefacts”Some steps have more than one leg. The API keeps each leg, so that the charges add up. It marks the extra legs.
- A duplicate has
duplicate_of. A call between two of your accounts has two legs: one on the account that dials, one on the account that the call reaches. The Leg is the one that the call reaches. The duplicate is next to it, with no Legs under it. - An artefact has
artefact_of. An IVR makes an extra leg on its own account. It is next to the IVR Leg, with no Legs under it.
To show each step one time, leave out the Legs with duplicate_of or artefact_of. The call log of app.onsim does this.
Charge
Section titled “Charge”We charge each Leg by its tariff. The tariff rates most calls in the UK at zero, so a charge is often 0. When the call record has no amount, the Leg has no charge. A Call has no charge when none of its Legs has one.
The charge of a Call
Section titled “The charge of a Call”The charge of a Call is the sum of the charges of all its Legs, with the duplicates and the artefacts.
| Field | Type | What it is |
|---|---|---|
amount | number | The sum of the charges of all Legs of the Call, with the duplicates and the artefacts. |
currency | string | The currency of amount, as an ISO 4217 code, such as GBP. |
The charge of a Leg
Section titled “The charge of a Leg”A duplicate and an artefact have a charge of their own. When you leave them out, add their charges to the Leg next to them. A Data Session has the same Charge, with kib as its unit.
| Field | Type | What it is |
|---|---|---|
amount | number | The money that we charge. 0 when the tariff rates the use at no cost. |
currency | string | The currency of amount, as an ISO 4217 code, such as GBP. |
quantityoptional | integer | The units that we bill, after the tariff rounds them. For data, the tariff rounds up to the next 20 KiB. |
used_quantityoptional | integer | The units that we measure, before the tariff rounds them. Only a Leg has it: a Data Session gives the same value as bytes. A Leg that passes the call on stays bridged to the end of the Call, and we measure that time too. |
unit | "seconds" | "kib" | The unit of quantity and used_quantity: seconds for a Leg, kib for a Data Session. |
destinationoptional | Destination | What the tariff rates the use as. A Leg to one of your extensions has none. |
Destination
Section titled “Destination”| Field | Type | What it is |
|---|---|---|
prefix | string | The entry that the tariff matches: a prefix of the dialled number, such as 447968, or a data zone, such as MXGDATAZ1GBR. |
description | string | The name of that entry in the tariff, such as UK - Mobile - T-Mobile or Mobile Data (UK). It says why the price is what it is. |
countryoptional | string | The country of that entry, as an ISO 3166-1 alpha-3 code, such as GBR. For a Leg, it is the country of the dialled number, not of the caller. |
A party is who takes part: who makes a Call, or who a Leg tries to reach. Every part of the API that points at someone uses this same object. A Number uses it for what takes its calls and for who shows it.
| Field | Type | What it is | On app.onsim |
|---|---|---|---|
extensionoptional | string | The extension, for a party of your own: a User, a Hunt Group or an IVR. Look it up in their lists to learn which, and its name. | The line under the name. app.onsim finds the name and the mark with it. |
numberoptional | string | The digits of a phone number, for an outside party. withheld when the party hides it. A feature code such as *40 is here too. | The number. A number that is withheld shows as Withheld. |
accountoptional | string | The name of one of your own lines that has no extension, such as a SIM in a router. app.onsim shows it in the Account column of its logs. | The Account column of the Data Log and of the SMS Log. |
| The party | What it has |
|---|---|
| One of your extensions | extension |
| An outside number | number |
| An outside caller who hides their number | number, as withheld |
| One of your Users who hides their number | extension, and number as withheld |
| One of your lines with no extension, such as a SIM in a router | account |
| A party that the record does not name, such as an IVR with no extension | Nothing |
A party does not say if an extension is a User, a Hunt Group or an IVR, and it has no name. Read the three lists one time, keep them, and look the extension up there.
Example
Section titled “Example”The Call of the picture. A caller reaches the menu (500) and goes on to Support (300). Support rings 201 and 202 at the same time, and 202 answers.
{ "id": "494c70e7-40e9-1240-e7ae-0242ac110004", "direction": "inbound", "outcome": "answered", "from": { "number": "447700900123" }, "answered_by": { "extension": "202" }, "started_at": "2026-10-01T09:14:02.000Z", "ended_at": "2026-10-01T09:17:44.000Z", "charge": { "amount": 0, "currency": "GBP" }, "legs": [ { "id": "2AD2070D B0A44C2D 289C04DC 289C04DC", "party": { "extension": "500" }, "outcome": "answered", "started_at": "2026-10-01T09:14:02.000Z", "answered_at": "2026-10-01T09:14:02.000Z", "passed_on_at": "2026-10-01T09:14:33.000Z", "ended_at": "2026-10-01T09:17:44.000Z", "recorded": false, "charge": { "amount": 0, "currency": "GBP", "quantity": 222, "used_quantity": 222, "unit": "seconds" }, "legs": [ { "id": "7F3E91A2 5C0D44B8 91E6A3F0 91E6A3F0", "party": { "extension": "300" }, "outcome": "answered", "started_at": "2026-10-01T09:14:20.000Z", "answered_at": "2026-10-01T09:14:33.000Z", "passed_on_at": "2026-10-01T09:14:33.000Z", "ended_at": "2026-10-01T09:17:44.000Z", "recorded": false, "charge": { "amount": 0, "currency": "GBP", "quantity": 191, "used_quantity": 191, "unit": "seconds" }, "legs": [ { "id": "C41B7D09 E2F85A16 3B9C2E74 3B9C2E74", "party": { "extension": "201" }, "outcome": "answered_elsewhere", "started_at": "2026-10-01T09:14:21.000Z", "ended_at": "2026-10-01T09:14:33.000Z", "recorded": false, "charge": { "amount": 0, "currency": "GBP", "quantity": 0, "used_quantity": 0, "unit": "seconds" }, "legs": [] }, { "id": "8A6F20D3 174BC9E5 D05A8F61 D05A8F61", "party": { "extension": "202" }, "outcome": "answered", "started_at": "2026-10-01T09:14:21.000Z", "answered_at": "2026-10-01T09:14:33.000Z", "ended_at": "2026-10-01T09:17:44.000Z", "recorded": true, "charge": { "amount": 0, "currency": "GBP", "quantity": 191, "used_quantity": 191, "unit": "seconds" }, "legs": [] } ] } ] } ]}Methods
Section titled “Methods”The list needs a time window. Its filters are direction, outcome, extension and number. A Call must pass each filter that you give.
extension and number find a Call that involves the party, as the caller or as the party of a Leg. The outcome filter is the outcome of the Call, not of that party. So extension=201&outcome=answered gives the answered Calls that involve 201, also when another party answers. Check answered_by for the Calls that 201 answers.
Give number in any usual form: +442079460123, 020 7946 0123 or 442079460123. A number with no country code is a UK number. In a query, encode a + as %2B.
The list gives each Call whole, with its Legs. The get is for one Call that you know by its ID. It looks at the last 90 days.
A Call with an attended transfer
Section titled “A Call with an attended transfer”In an attended transfer, a User puts the caller on hold, calls another party from their own phone, and joins the two calls. The second call has an ID of its own.
- The list gives one Call. The Legs of the second call are in its tree, and each has a
call_idwith the ID of the second call. - The get reads one ID. With the ID of the Call it gives the Call without those Legs. With the
call_idof such a Leg it gives the second call as a Call of its own.
So take a Call with an attended transfer from the list.
Related
Section titled “Related”A Leg with recorded as true has a Recording.
Encode an ID before you put it in a path. A Call ID can hold @ and :, and a Leg ID holds spaces.