---
title: "Start a two-party telephony bridge"
method: POST
path: "/voice/bridge"
tags: ["voice"]
---

# Start a two-party telephony bridge

`POST /voice/bridge`

## Request

- Base URL: `https://corebee.ai/api/v1`
- URL: `https://corebee.ai/api/v1/voice/bridge`
- Auth: HTTP bearer

Business-first two-party bridge: dials the business number, navigates its IVR (optional single-step DTMF plan), confirms a live human answered via Premium AMD, speaks an AI prep line, then dials the consumer and bridges both legs. Requires the voice:bridge scope. Gated by a server feature flag: returns 503 when disabled.

## Request body

- BridgeCreate: Start a business-first two-party bridge. business_number and consumer_number are required E.164 numbers.
  - `business_number` string, required: E.164 number dialed FIRST (the business).
  - `consumer_number` string, required: E.164 number dialed only after a live human is confirmed on the business leg.
  - `from_number` string: Optional E.164 caller-ID. Must be a Telnyx DID owned by the credential org; a default connected DID is used when omitted.
  - `prep_line` string: Optional short line about why the consumer is calling. On the AI-conversation leg it becomes the agent's reasonForCall: spoken as soon as the business agrees to help, before the consumer is bridged in. ⚠️ ONLY THE FIRST ~180 CHARACTERS ARE SPOKEN ON THAT LEG. Longer text is cut at the last sentence boundary inside that budget (or, failing one, at a word boundary), so anything after it is never heard: measured on live traffic, prep lines average ~300 characters and ~40% of the text was discarded unannounced. Put the specifics the person answering needs, the vehicle, the request, the reference, in the FIRST sentence. The full text IS spoken on a briefing-only call (up to 500 characters, in the closing message) and on the legacy leg, verbatim with the required AI-disclosure prefixed.
  - `dtmf_plan` BridgeDtmfStep[]: Optional single IVR navigation step. Multi-step plans are rejected with 400 multi_step_ivr_unsupported: the bridge cannot pace steps 2..N today, so a multi-step plan would burn a channel and stall. When absent, IVR navigation is skipped. Digits use 0-9, A-D, *, # and the in-string pauses w (0.5s) / W (1s).
    - `digits` string, required: Digits 0-9, A-D, *, # plus in-string pauses w (0.5s) / W (1s).
    - `wait_ms` integer: Advisory wait after the step.
    - `note` string
  - `idempotency_key` string: Optional client key ([A-Za-z0-9._:-]). Reusing a key for a live session returns 409 with a reference to the existing session.
  - `request_recording_consent` boolean: Optional. The A/B toggle for consumer recording on THIS call. When true AND consumer recording is enabled server-side, the consumer hears a spoken recording-consent disclosure before being bridged; if they stay on the line (implied consent) the bridged consumer<->business conversation is recorded and transcribed, and if they hang up during the disclosure the call is simply not recorded (it is never dropped for declining). Necessary but NOT sufficient: recording is additionally gated by a server-side flag that is OFF by default pending legal sign-off, so in current production this field records nothing and the bridge is byte-identical whether it is true or false. Default false is the control arm. A non-boolean value is rejected with 400 validation_error.
  - `consent` BridgeConsent: Partner-captured evidence that the consumer asked to be connected. All three fields are required ONCE the object is supplied. Extra keys are preserved (ip, user_agent, form version, ...), bounded by the total serialized size.
    - `method` string, required: How consent was captured, e.g. web_form, recorded_call, sms_reply. Deliberately NOT an enum: the legal taxonomy of consent is yours to assert, and refusing a method string we had not enumerated would throw away real evidence over a vocabulary quibble. We bound its shape, not its meaning.
    - `captured_at` string, date-time, required: ISO-8601 instant at which consent was captured, normalized on validation. A timestamp in the future is rejected, consent captured after the call it justifies is not consent, with about five minutes of tolerance for a fast partner clock.
    - `reference` string, required: Pointer to the evidence on your side: a record id, a URL, a recording id.
  - `briefing_only` boolean: Optional test flag. When true the business is dialed and AMD-verified and the prep line is spoken, then the session COMPLETES without ever dialing the consumer and without bridging, so nothing is billed and no second person is called. Absent or false is the full production flow. A non-boolean value is a 400 validation_error, never coerced. Note that briefing-only sessions are excluded from GET /voice/bridge/usage, including from its `total`.
  - `metadata` object: Free-form bag echoed back on the status projection. `customer_ref` (string, <=255 chars) is the one key we treat specially: it is your correlation id, it is echoed on webhooks and on the usage feed, and it is what customer_ref= filters on. No other key in here is interpreted.

## Response `201`

Created

- object
  - `data` BridgeSession, required: Minimal reference returned when a bridge is created. A create can come back already state=failed (nothing was dialed), check failure_reason.
    - `id` integer
    - `state` 'created' | 'dialing_business' | 'ivr_nav' | 'amd_verdict' | 'human' | 'voicemail' | 'prep_line' | 'converse' | 'dialing_consumer' | 'bridging' | 'bridged' | 'completed' | 'failed'
    - `failure_reason` string, nullable: Null unless the bridge was refused at creation. concurrency_cap_exceeded means the org cap or the platform channel ceiling was full and NO leg was dialed: back off and retry later with a NEW idempotency_key rather than retrying this one.
    - `business_number` string
    - `consumer_number` string
    - `created_at` string, date-time, nullable
    - `status_url` string

## Other responses

- `400`: Validation error (code validation_error), or multi_step_ivr_unsupported when dtmf_plan carries more than one step
- `401`: Invalid or missing credential
- `403`: Forbidden (missing scope, or resource not owned by the credential org)
- `409`: Conflict (idempotency_key already used for a live session)
- `429`: Error
- `503`: Service unavailable (feature disabled or no capacity)

---

[API](https://skmtc.dev/corebee/apis/corebee-api.md) · [All operations](https://skmtc.dev/corebee/apis/corebee-api/llms.txt) · [OpenAPI document](https://skmtc.dev/corebee/apis/corebee-api/revisions/a48ea543b4dc?raw)
