Pinless dial-in and SIP Interconnect allow incoming calls to trigger a webhook on your infrastructure, which then routes the call to a Daily room — no PIN required from the caller.
This pattern is common in contact centers, voice bots, and IVR flows where the destination room isn’t known at call time.
How it works
- A caller dials your purchased phone number or a static SIP URI.
- Daily places the caller on hold (hold music plays).
- Daily sends a webhook to your configured
room_creation_api URL.
- Your server creates or selects a Daily room and waits for
dialin-ready to fire.
- Your server calls
pinlessCallUpdate with the room’s sip_uri to connect the held caller.
Configure your domain with a pinless_dialin array. Each object represents one incoming number or SIP interconnect:
curl --request POST \
--url https://api.daily.co/v1/ \
--header 'Authorization: Bearer $DAILY_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"properties": {
"pinless_dialin": [
{
"phone_number": "$PURCHASED_NUMBER",
"room_creation_api": "$WEBHOOK_URL",
"name_prefix": "my-pinless-phone",
"hmac": "base64-encoded-secret",
"hold_music_url": "https://example.com/hold.mp3",
"timeout_config": {
"message": "Agent not available. Please call later."
}
},
{
"room_creation_api": "$WEBHOOK_URL",
"name_prefix": "sip-interconnect"
}
]
}
}'
You can omit phone_number for SIP Interconnect (no phone number needed). Otherwise, phone_number is required and must be a number purchased from Daily.
The response is the room’s config object, including an array of pinless_dialin entries, each with a static sip_uri and the corresponding room_creation_api URL — the sip_uri is the address your SIP system dials for interconnect flows:
{
"config": {
"pinless_dialin": [
{
"sip_uri": "static-address--0@example.sip.daily.co",
"phone_number": "+12095038039",
"room_creation_api": "https://webhook.example.com/create_room",
"hmac": "base64-encoded-secret"
},
{
"sip_uri": "static-address--1@example.sip.daily.co",
"room_creation_api": "https://webhook.example.com/handle_twilio",
"hmac": "base64-encoded-secret"
}
]
}
}
When you configure pinless_dialin, Daily sends a test request to your room_creation_api endpoint with body {"To": "$PURCHASED_PHONE"}. It can be used to verify the endpoint. Even if we do not receive 200 response, endpoint is configured to maintain backward compatibility for existing domains which may not recognize the test body.
Incoming webhook payload
When a call arrives, Daily POSTs to your room_creation_api:
{
"From": "+CALLERS_PHONE",
"To": "$PURCHASED_PHONE",
"callId": "a7bf8461-7d33-4083-9677-5cfdb4f337a5",
"callDomain": "9c975848-a067-4de0-bf47-1b4179ceba4e",
"sipHeaders": {
"x-custom-header": "value"
}
}
From — caller’s phone or SIP address
To — your Daily phone number or static SIP URI
callId + callDomain — use these to connect the held call to a Daily room
sipHeaders — custom SIP headers sent to the sip_uri (e.g., for external SIP systems forwarding caller context). For example, when you receive a call on your Avaya on-premise SIP server and need to send the caller phone and called phone, the to and from fields will already be the Avaya sip addresses. In that case, you can add custom sip headers prepended with an x-. This would be something like static-address--1@example.sip.daily.co?x-caller=7861230000&x-called=6501230000.
Verifying the webhook signature (HMAC)
Each pinless_dialin entry has an hmac — a Base64-encoded HMAC-SHA256 secret shared between Daily and your server. Use it to verify that the webhook came from Daily.
Daily includes two headers with each webhook request:
X-Pinless-Timestamp
X-Pinless-Signature
To verify:
// You'll need to save the hmac value the API returned when you created your webhook and insert it here
const hmacSecret = 'NQrSA5z0FkJ44QPrFerW7uCc5kdNLv3l2FDEKDanL1U=';
const signature = headers['X-Pinless-Timestamp'] + '.' + JSON.stringify(body);
const base64DecodedSecret = Buffer.from(hmacSecret, 'base64');
const hmac = crypto.createHmac('sha256', base64DecodedSecret);
const computedSignature = hmac.update(signature).digest('base64');
// computedSignature should match headers['X-Pinless-Signature']
You can provide your own Base64-encoded secret in the hmac field when configuring. If omitted, Daily generates a new one each time you update pinless_dialin.
Keep your hmac secret private. Anyone with it can forge webhook requests.
Connecting the held call to a Daily room
Once your webhook handler has created or selected a room:
- Join the room with a Daily participant (e.g., a Pipecat bot or agent) so the room is active.
- Wait for
dialin-ready to fire.
- Call
pinlessCallUpdate with the room’s sip_uri and the callId/callDomain from the webhook:
curl --request POST \
--url https://api.daily.co/v1/dialin/pinlessCallUpdate \
--header 'Authorization: Bearer $DAILY_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"callId": "a7bf8461-7d33-4083-9677-5cfdb4f337a5",
"callDomain": "9c975848-a067-4de0-bf47-1b4179ceba4e",
"sipUri": "sip:room-specific-id@example.sip.daily.co?x-daily_display_name=caller"
}'
Calling pinlessCallUpdate before dialin-ready fires may cause the call to drop.
Make sure the sip_uri you provide is not already in use by another SIP client. See multiple SIP endpoints for provisioning multiple endpoints per room.
For building voice bots with this pattern, see the Pipecat dial-in docs.