Skip to main content
Use this when you need SIP-level control or already run LiveKit behind SIP infrastructure. Bluejay sends a SIP INVITE to your project’s SIP host; you provision an inbound trunk and dispatch rule that route the call to your agent.
This method is for inbound agents: Bluejay dials in and your agent answers. If your agent places calls, use Outbound agents. And if you don’t specifically need SIP, use Direct connection instead — it skips all of the trunk setup below.

How it connects

Bluejay dials sip:<number>@<your-project>.sip.livekit.cloud. Your LiveKit project matches the number to an inbound trunk, applies a dispatch rule that creates a room and dispatches your agent, and your agent answers. Audio bridges back to the Digital Human.

Setup

All of this is on your LiveKit project — the same project whose SIP host you give Bluejay.

1. Create an inbound trunk

The number is a routing key, not a real phone number — pick any E.164 value and use the same one everywhere.

2. Create a dispatch rule on that trunk

Routes the call into a fresh room and dispatches your agent. agentName must match the name your worker registers with.

3. (Optional) Read SIP headers

Add custom headers in Agent Settings → Connection. Bluejay sends each header on the SIP INVITE under the exact name you enter. It does not add an X- prefix. For example, X-CallType is sent as X-CallType: incoming_scheduling. The same headers are also available as a JSON object in the X-Custom-Headers header. The simplest way to read headers is the lk.sip.GetRemoteHeaders RPC. It needs no trunk configuration, returns all SIP headers in one call, and avoids waiting for participant attributes to update:
You can also expose headers as participant attributes:
  • Set headers_to_attributes on the trunk to map specific X-* headers. Configure each header in advance. LiveKit updates these attributes asynchronously, so they may not exist when the SIP participant first joins.
  • Set include_headers to SIP_X_HEADERS on the trunk to map every X-* header to a sip.h.* participant attribute without configuring each header.
To receive X-Simulation-Result-Id (for linking tool calls and traces back to the result), add explicit forwarding to the trunk:
It then appears in participant.attributes alongside the sip.* keys. Use it to call /v1/update-simulation-result.

4. Point Bluejay at your SIP host

In Agent Settings → Connection, set the connection type to SIP and the URI to: Form is sip:<number>@<host>. The number must exactly match the trunk’s numbers.

5. Create and run a simulation

  1. Go to the Simulations page, click Create in the top right, select your agent, and add or auto-generate Digital Human personas.
  2. In the Simulations tab, click Run on the simulation, then click Run calls (the button shows the call count, e.g. “Run 3 calls”).

Things to note

  • The number is a made-up routing key. It doesn’t need to be a purchased DID. Whatever you put in the trunk’s numbers, use the exact same string (E.164, leading +) in the URI.
  • The trunk must live on the same project as the SIP host. A project’s SIP host id (e.g. 65197ejfbqv) is not the same string as its project name — if you have more than one project it’s easy to create the trunk on the wrong one.
  • A trunk alone isn’t enough. Without a dispatch rule the call is accepted but never routed to a room.
  • Your agent must be running and producing audio. A worker registered under the dispatch rule’s agentName, with working LLM/TTS keys. A silent agent (e.g. bad provider key) connects but the call is scored as no answer.

Troubleshooting

A 404 proves the INVITE did reach your LiveKit project (it answered and rejected at trunk-matching). If it truly weren’t reaching LiveKit you’d see a timeout instead. So a 404 is always a trunk/number/project-match issue, never a network one.