Calls

Every voice interaction handled by Phone.inc — inbound or outbound, ringing or ended — shows up as a call. The Calls API lets you list recent activity, filter by phone number, direction, or state, pull a single call by its public ID, and run an attended (warm) transfer between employees.

The call model

A call links a business number, a remote party, and (when applicable) the employees who handled it. The full lifecycle is captured in the state field, with timestamps for when the call started and when it was answered.

Properties

  • Name
    id
    Type
    string
    Description

    Unique public identifier for the call. Use this when calling the retrieve endpoint.

  • Name
    from
    Type
    string
    Description

    The originating phone number in E.164 format.

  • Name
    to
    Type
    string
    Description

    The destination phone number in E.164 format.

  • Name
    direction
    Type
    string
    Description

    Either inbound (someone called you) or outbound (an employee called out).

  • Name
    outside_business_hours
    Type
    boolean | null
    Description

    Whether an inbound call arrived outside the business number's hours, recorded when routing began. false means it arrived during business hours. null means the decision is unknown, including older calls and outbound calls. Later schedule changes do not change this value. An after-hours call may still be answered or leave a voicemail.

  • Name
    state
    Type
    string
    Description

    The current lifecycle state. See the state values section below for the full list.

  • Name
    started_at
    Type
    timestamp
    Description

    ISO 8601 timestamp of when the call was initiated. May be null for calls that haven't started yet.

  • Name
    answered_at
    Type
    timestamp
    Description

    ISO 8601 timestamp of when the call was answered. null for missed or rejected calls.

  • Name
    duration
    Type
    integer
    Description

    Total length of the call in seconds, measured from answered_at. null while the call is in progress.

  • Name
    queue_position
    Type
    integer
    Description

    While the caller waits for an employee (state is queued): their place in the business number's queue, where 1 is next. null otherwise.

  • Name
    enqueued_at
    Type
    timestamp
    Description

    While the caller waits for an employee: ISO 8601 timestamp of when they entered the queue, after any greeting or menu. null otherwise.

  • Name
    summary
    Type
    string
    Description

    Auto-generated summary of the call once it ends. null while the call is in progress or if a summary hasn't been produced.

  • Name
    transcription
    Type
    string
    Description

    Full text transcription of the call recording. null until the recording has been transcribed.

  • Name
    transcription_segments
    Type
    array
    Description

    Speaker-diarized transcription segments. Each entry has speaker, text, and an optional employee_id (the employee's public ID). null until transcribed.

  • Name
    business_number_id
    Type
    string
    Description

    The ID of the business number the call was placed to or from.

  • Name
    business_number_name
    Type
    string
    Description

    The label of the business number (e.g. Sales).

  • Name
    business_number
    Type
    string
    Description

    The business number in E.164 format.

  • Name
    business_number_formatted
    Type
    string
    Description

    The business number formatted for display.

  • Name
    recording_url
    Type
    string
    Description

    URL where the call recording can be played or downloaded. New isolated stereo recordings switch to mono MP3s after playback processing; other recordings retain their original channel layout. null if recording is disabled or the call hasn't ended yet. The URL is generated per request — don't cache it long-term.

  • Name
    employees
    Type
    array
    Description

    Employees who participated in the call. Each entry has id, full name, first_name, and last_name.

  • Name
    transfers
    Type
    array
    Description

    Every warm transfer attempted on the call, oldest first, including finished ones. Each entry has id, state (see the transfer model), from_employee, and to_employee (each with id, full name, first_name, and last_name). Read this after a call ends to see how a transfer actually resolved — completed means the target took over, cancelled means the caller went back to the controller, failed means the caller hung up mid-transfer.

  • Name
    initiated_by
    Type
    object
    Description

    For outbound calls only — the employee who placed the call. Has id, full name, first_name, and last_name. Omitted on inbound calls.

Call states

The state field walks through the call's lifecycle. The values are:

  • Name
    initiated
    Description

    The call has been created but not yet answered. Welcome and menu prompts run in this state.

  • Name
    queued
    Description

    The caller is waiting for an available employee. The inbound carrier leg may already be answered so wait audio can play, but answered_at stays null until an employee picks up. Callers wait in order on that business number; only available employees are rung.

  • Name
    answered
    Description

    The call was answered. answered_at is now set.

  • Name
    playing_audio
    Description

    A pre-recorded greeting or message is being played to the caller.

  • Name
    transferring
    Description

    The call is being transferred to an employee or another destination.

  • Name
    recording
    Description

    The call is being recorded (e.g. taking a voicemail).

  • Name
    bridged
    Description

    Two parties are connected and talking. This is the typical state for an active conversation.

  • Name
    ended
    Description

    The call has hung up. duration is now set, and a summary may follow shortly.


GET/v1/calls

List recent calls

Returns calls for the authenticated employee's company. Without a query, calls are ordered newest first. With a query, calls are ordered using hybrid keyword and semantic search across their transcription, summary, and saved caller context, so results can match exact words, customer details, or related topics. By default you get 10 calls; raise that with limit (capped at 50). All filters can be combined.

Without query, follow next_cursor using the cursor parameter and the same filters until it is null to retrieve all matching calls. Ordering uses creation time, then an internal ID to break ties. Newer calls added after the first page do not move existing pages. A deleted or foreign-company cursor returns 404; a non-string cursor returns 422. Search results remain capped at 50, return next_cursor: null, and do not support cursor pagination; combining query with cursor returns 422.

For reports, filter the call-start period with start_at and end_at. These use started_at, falling back to creation time if absent. When combined with query, the date range is applied before search ranking and the result limit, so out-of-range calls do not consume the available results. Boundaries must be ISO 8601 timestamps with a time zone; invalid timestamps or an end not after the start return 422. Convert local calendar boundaries to UTC or send explicit offsets, including daylight-saving changes. Do not mistake a single page or capped search for complete statistics.

Optional query parameters

  • Name
    query
    Type
    string
    Description

    Search transcribed calls by exact language and semantic similarity. Summaries and saved caller context are included when available. Calls without a transcription do not match.

  • Name
    business_number_id
    Type
    string
    Description

    Filter to one business number by its public id.

  • Name
    phone_number
    Type
    string
    Description

    Filter to calls involving this phone number on the remote side. Accepts E.164 and best-effort matches local formats too. Combine with direction to disambiguate inbound vs outbound.

  • Name
    direction
    Type
    string
    Description

    Limit results to inbound or outbound. Defaults to both.

  • Name
    state
    Type
    string
    Description

    Filter by call state, e.g. ended for completed calls only. Unknown values are silently ignored.

  • Name
    start_at
    Type
    timestamp
    Description

    Inclusive call-start boundary, such as 2026-03-29T00:00:00+01:00.

  • Name
    end_at
    Type
    timestamp
    Description

    Exclusive call-start boundary. Use the next local midnight to include an entire day, such as 2026-03-30T00:00:00+02:00.

  • Name
    cursor
    Type
    string
    Description

    The previous response's next_cursor. Keep all filters unchanged. Not available with query.

  • Name
    limit
    Type
    integer
    Description

    Maximum number of calls to return. Defaults to 10, capped at 50.

Request

GET
/v1/calls
curl -G https://app.phone.inc/api/v1/calls \
  -H "X-Api-Key: $PHONE_INC_API_KEY" \
  -d query="order status" \
  -d business_number_id=0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01 \
  -d direction=inbound \
  -d state=ended \
  -d limit=25

Response

{
  "calls": [
    {
      "id": "0193f4ba-1234-7c00-9e3d-2b2b8a7f1c11",
      "from": "+14085550199",
      "to": "+14155551234",
      "direction": "inbound",
      "state": "ended",
      "started_at": "2026-05-11T14:02:11Z",
      "answered_at": "2026-05-11T14:02:14Z",
      "duration": 187,
      "summary": "Customer asked about the status of order #1042.",
      "transcription": "Hello, I'm calling about order 1042...",
      "transcription_segments": [
        { "speaker": "Caller", "text": "Hello, I'm calling about order 1042.", "employee_id": null },
        { "speaker": "Alex Wong", "text": "Sure, let me look that up for you.", "employee_id": "0193f4b0-aaaa-7c00-9e3d-2b2b8a7f1c20" }
      ],
      "recording_url": "https://app.phone.inc/rails/active_storage/blobs/redirect/.../recording.mp3",
      "business_number_id": "0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01",
      "business_number_name": "Sales",
      "business_number": "+14155551234",
      "business_number_formatted": "+1 415-555-1234",
      "employees": [
        {
          "id": "0193f4b0-aaaa-7c00-9e3d-2b2b8a7f1c20",
          "name": "Alex Wong",
          "first_name": "Alex",
          "last_name": "Wong"
        }
      ]
    }
  ],
  "next_cursor": null
}

GET/v1/calls/:id

Retrieve a call

Returns a single call by its public id. Useful when you receive a webhook or push notification with a call ID and want the latest state. Returns a 404 if the call doesn't exist on this company's account.

Request

GET
/v1/calls/0193f4ba-1234-7c00-9e3d-2b2b8a7f1c11
curl https://app.phone.inc/api/v1/calls/0193f4ba-1234-7c00-9e3d-2b2b8a7f1c11 \
  -H "X-Api-Key: $PHONE_INC_API_KEY"

Response

{
  "id": "0193f4ba-1234-7c00-9e3d-2b2b8a7f1c11",
  "from": "+14085550199",
  "to": "+14155551234",
  "direction": "inbound",
  "state": "bridged",
  "started_at": "2026-05-11T14:02:11Z",
  "answered_at": "2026-05-11T14:02:14Z",
  "duration": null,
  "summary": null,
  "transcription": null,
  "transcription_segments": null,
  "recording_url": null,
  "business_number_id": "0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01",
  "business_number_name": "Sales",
  "business_number": "+14155551234",
  "business_number_formatted": "+1 415-555-1234",
  "transfers": [
    {
      "id": "0193f4c2-bbbb-7c00-9e3d-2b2b8a7f1c33",
      "state": "completed",
      "from_employee": { "id": "0193f4b0-aaaa-7c00-9e3d-2b2b8a7f1c20", "name": "Alex Wong", "first_name": "Alex", "last_name": "Wong" },
      "to_employee": { "id": "0193f4b0-cccc-7c00-9e3d-2b2b8a7f1c21", "name": "Bella Núñez", "first_name": "Bella", "last_name": "Núñez" }
    }
  ],
  "employees": [
    {
      "id": "0193f4b0-aaaa-7c00-9e3d-2b2b8a7f1c20",
      "name": "Alex Wong",
      "first_name": "Alex",
      "last_name": "Wong"
    }
  ]
}

The transfer model

An attended (warm) transfer moves a live call from one employee (the controller) to another without hanging up the customer. The customer is held in the same conference with music while the target rings; after they answer, the controller can complete the handoff or pull the call back, and the target can accept the call to finish the handoff. Call state stays answered — transfer lifecycle lives on the transfer object.

Transfer properties

  • Name
    id
    Type
    string
    Description

    Unique public identifier for the transfer.

  • Name
    state
    Type
    string
    Description

    One of ringing, consulting, completed, cancelled, or failed.

  • Name
    from_employee
    Type
    object
    Description

    The controller who started the transfer. Has id, full name, first_name, and last_name.

  • Name
    to_employee
    Type
    object
    Description

    The employee being transferred to. Has id, full name, first_name, and last_name.

Transfer states

  • Name
    ringing
    Description

    The customer is on hold and the target employee is being rung (up to 30 seconds).

  • Name
    consulting
    Description

    The target answered. Controller and target can talk while the customer stays on hold.

  • Name
    completed
    Description

    The handoff finished. The original controller left; customer and target stay connected.

  • Name
    cancelled
    Description

    The transfer was pulled back or the target never answered. The controller and customer resume.

  • Name
    failed
    Description

    The transfer ended because the customer hung up (or the call otherwise failed).


GET/v1/calls/active

Get the active call

Returns the authenticated employee's currently active call (if any), any open transfer on that call, and coworkers you can transfer to. Also returns a call when the employee is the target of an open transfer (ringing or consulting), even before they have joined. Returns 204 No Content when the employee is idle.

Response fields

  • Name
    call
    Type
    object
    Description

    Short call summary: id, state, direction, from, to.

  • Name
    transfer
    Type
    object
    Description

    Open transfer, or null. Same shape as the transfer model.

  • Name
    employees
    Type
    array
    Description

    Coworkers at the company, excluding the authenticated employee. Each entry has id, full name, first_name, last_name, status (available, on_call, do_not_disturb, ringing, logged_out, or unknown), and do_not_disturb_expires_at — an ISO 8601 timestamp when a timed do-not-disturb ends, or null. Coworkers with status available or do_not_disturb can be transferred to; do-not-disturb silences queue calls, not a deliberate transfer. A do_not_disturb coworker must still have at least one ringable device (a live browser session or a registered mobile device) and must not already be ringing for another call — otherwise the transfer returns 409 with error: "employee_unavailable".

  • Name
    available_employees
    Type
    array
    Description

    Coworkers with status available. Each entry has id, full name, first_name, and last_name. Same people as the available rows in employees.

Request

GET
/v1/calls/active
curl https://app.phone.inc/api/v1/calls/active \
  -H "X-Api-Key: $PHONE_INC_API_KEY"

Response

{
  "call": {
    "id": "0193f4ba-1234-7c00-9e3d-2b2b8a7f1c11",
    "state": "answered",
    "direction": "inbound",
    "from": "+14085550199",
    "to": "+14155551234"
  },
  "transfer": null,
  "employees": [
    {
      "id": "0193f4b0-bbbb-7c00-9e3d-2b2b8a7f1c21",
      "name": "Jordan Lee",
      "first_name": "Jordan",
      "last_name": "Lee",
      "status": "available",
      "do_not_disturb_expires_at": null
    },
    {
      "id": "0193f4b0-cccc-7c00-9e3d-2b2b8a7f1c22",
      "name": "Sam Ortiz",
      "first_name": "Sam",
      "last_name": "Ortiz",
      "status": "do_not_disturb",
      "do_not_disturb_expires_at": "2026-01-15T14:30:00Z"
    }
  ],
  "available_employees": [
    {
      "id": "0193f4b0-bbbb-7c00-9e3d-2b2b8a7f1c21",
      "name": "Jordan Lee",
      "first_name": "Jordan",
      "last_name": "Lee"
    }
  ]
}

POST/v1/calls/:id/transfers

Start a warm transfer

Starts an attended transfer to another employee. The customer is held in-conference; the target rings for up to 30 seconds.

Missing employee_id returns 400 with error: "invalid_request". Concurrent starts return 409 with error: "transfer_in_progress". An ESL communication failure returns 502 with error: "esl_unreachable"; if cleanup cannot be confirmed, the transfer remains open until its outcome is confirmed. Fetch the active call before retrying.

Required attributes

  • Name
    employee_id
    Type
    string
    Description

    Public ID of the coworker to transfer to. Must have status available, or do_not_disturb with at least one ringable device and no ring in progress on another call, and not be the current controller. Anything else returns 409 with error: "employee_unavailable".

Request

POST
/v1/calls/:id/transfers
curl https://app.phone.inc/api/v1/calls/$CALL_ID/transfers \
  -H "X-Api-Key: $PHONE_INC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"employee_id":"0193f4b0-bbbb-7c00-9e3d-2b2b8a7f1c21"}'

Response

{
  "transfer": {
    "id": "0193f4c0-dddd-7c00-9e3d-2b2b8a7f1c40",
    "state": "ringing",
    "from_employee": {
      "id": "0193f4b0-aaaa-7c00-9e3d-2b2b8a7f1c20",
      "name": "Alex Wong",
      "first_name": "Alex",
      "last_name": "Wong"
    },
    "to_employee": {
      "id": "0193f4b0-bbbb-7c00-9e3d-2b2b8a7f1c21",
      "name": "Jordan Lee",
      "first_name": "Jordan",
      "last_name": "Lee"
    }
  }
}

POST/v1/calls/:id/transfers/:transfer_id/completion

Complete a warm transfer

Finishes a transfer that is in consulting (or already completed — idempotent). The original controller leaves; the customer and target stay connected. The controller or the employee being transferred to can call this.

Attempting to complete while the target is still ringing returns 409 with error: "transfer_not_consulting" and does not change the transfer.

Request

POST
/v1/calls/:id/transfers/:transfer_id/completion
curl https://app.phone.inc/api/v1/calls/$CALL_ID/transfers/$TRANSFER_ID/completion \
  -X POST \
  -H "X-Api-Key: $PHONE_INC_API_KEY"

Response

{
  "transfer": {
    "id": "0193f4c0-dddd-7c00-9e3d-2b2b8a7f1c40",
    "state": "completed",
    "from_employee": {
      "id": "0193f4b0-aaaa-7c00-9e3d-2b2b8a7f1c20",
      "name": "Alex Wong",
      "first_name": "Alex",
      "last_name": "Wong"
    },
    "to_employee": {
      "id": "0193f4b0-bbbb-7c00-9e3d-2b2b8a7f1c21",
      "name": "Jordan Lee",
      "first_name": "Jordan",
      "last_name": "Lee"
    }
  }
}

DELETE/v1/calls/:id/transfers/:transfer_id

Cancel a warm transfer

Pulls the transfer back while it is ringing or consulting. Target legs are dropped and the customer is released from hold to the original controller.

Request

DELETE
/v1/calls/:id/transfers/:transfer_id
curl https://app.phone.inc/api/v1/calls/$CALL_ID/transfers/$TRANSFER_ID \
  -X DELETE \
  -H "X-Api-Key: $PHONE_INC_API_KEY"

Response

{
  "transfer": {
    "id": "0193f4c0-dddd-7c00-9e3d-2b2b8a7f1c40",
    "state": "cancelled",
    "from_employee": {
      "id": "0193f4b0-aaaa-7c00-9e3d-2b2b8a7f1c20",
      "name": "Alex Wong",
      "first_name": "Alex",
      "last_name": "Wong"
    },
    "to_employee": {
      "id": "0193f4b0-bbbb-7c00-9e3d-2b2b8a7f1c21",
      "name": "Jordan Lee",
      "first_name": "Jordan",
      "last_name": "Lee"
    }
  }
}

GET/v1/activity/unseen

Unseen activity

Get the number of distinct people with unseen incoming calls or voicemails for each business number, including incoming SMS when the company's messaging feature flag is enabled. Numbers with no unseen activity are omitted. A person with several unseen items counts once within that business number. The messaging flag defaults to off and is managed by Phone.inc.

Request

GET
/v1/activity/unseen
curl https://app.phone.inc/api/v1/activity/unseen \
  -H "X-Api-Key: $PHONE_INC_API_KEY"

Response

{
  "numbers": [
    { "business_number_id": "0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01", "people": 2 }
  ]
}

POST/v1/calls/seen

Mark a conversation seen

Set the seen state of calls and voicemails from one person on a business number. Send business_number_id (the number's public ID), phone_number (the remote person's E.164 number), and seen (a boolean). Returns 204 No Content.

Setting seen to true marks unseen calls and voicemails as seen without changing whether voicemails have been listened to. Setting it to false marks unanswered inbound calls and voicemails as unseen and clears voicemail listened state. Answered and outbound calls stay seen. A missing or invalid seen returns 422; an unknown business number or missing phone number returns 404.

Request

POST
/v1/calls/seen
curl https://app.phone.inc/api/v1/calls/seen \
  -H "X-Api-Key: $PHONE_INC_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"business_number_id":"0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01","phone_number":"+14155551234","seen":true}'