201 lines
5.6 KiB
Markdown
201 lines
5.6 KiB
Markdown
# Handling PSTN/SIP Dial-in on Pipecat Cloud
|
|
|
|
This repository contains two server implementations for handling
|
|
the pinless dial-in workflow in Pipecat Cloud. This is the companion to the
|
|
Pipecat Cloud [pstn_sip starter image](https://github.com/daily-co/pipecat-cloud-images/tree/main/pipecat-starters/pstn_sip).
|
|
In addition you can use `/api/dial` to trigger dial-out, and
|
|
eventually, call-transfers.
|
|
|
|
1. [FastAPI Server](fastapi-webhook-server/README.md) -
|
|
A FastAPI implementation that handles PSTN (Public Switched Telephone
|
|
Network) and SIP (Session Initiation Protocol) calls using the Daily API.
|
|
|
|
2. [Next.js Serverless](nextjs-webhook-server/README.md) -
|
|
A Next.js API implementation designed for deployment on Vercel's
|
|
serverless platform.
|
|
|
|
Both implementations provide:
|
|
|
|
- HMAC signature validation for pinless webhook
|
|
- Structured logging
|
|
- Support for dial-in and dial-out settings
|
|
- Voicemail detection and call transfer functionality (coming soon)
|
|
- Test request handling
|
|
|
|
## Choosing an Implementation
|
|
|
|
- Use the **FastAPI Server** if you:
|
|
|
|
- Need a standalone server
|
|
- Prefer Python and FastAPI
|
|
- Want to deploy to traditional hosting platforms
|
|
|
|
- Use the **Next.js Serverless** implementation if you:
|
|
- Want serverless deployment
|
|
- Prefer JavaScript/TypeScript
|
|
- Already use Next.js and Vercel for other projects
|
|
- Need quick scaling and zero maintenance
|
|
|
|
## Prerequisites
|
|
|
|
### Environment Variables
|
|
|
|
Both implementations require similar environment variables:
|
|
|
|
- `PIPECAT_CLOUD_API_KEY`: Pipecat Cloud API Key, begins with pk\_\*
|
|
- `AGENT_NAME`: Your Daily agent name
|
|
- `PINLESS_HMAC_SECRET`: Your HMAC secret for request verification
|
|
- `LOG_LEVEL`: (Optional) Logging level (defaults to 'info')
|
|
|
|
See the individual README files in each implementation directory for
|
|
specific setup instructions.
|
|
|
|
### Phone number setup
|
|
|
|
You can buy a phone number through the Pipecat Cloud Dashboard:
|
|
|
|
1. Go to `Settings` > `Telephony`
|
|
2. Follow the UI to purchase a phone number
|
|
3. Configure the webhook URL to receive incoming calls (e.g. `https://my-webhook-url.com/api/dial`)
|
|
|
|
Or purchase the number using Daily's
|
|
[PhoneNumbers API](https://docs.daily.co/reference/rest-api/phone-numbers).
|
|
|
|
```bash
|
|
curl --request POST \
|
|
--url https://api.daily.co/v1/domain-dialin-config \
|
|
--header 'Authorization: Bearer $TOKEN' \
|
|
--header 'Content-Type: application/json' \
|
|
--data-raw '{
|
|
"type": "pinless_dialin",
|
|
"name_prefix": "Customer1",
|
|
"phone_number": "+1PURCHASED_NUM",
|
|
"room_creation_api": "https://example.com/api/dial",
|
|
"hold_music_url": "https://example.com/static/ringtone.mp3",
|
|
"timeout_config": {
|
|
"message": "No agent is available right now"
|
|
}
|
|
}'
|
|
```
|
|
|
|
The API will return a static SIP URI (`sip_uri`) that can be called
|
|
from other SIP services.
|
|
|
|
### `room_creation_api`
|
|
|
|
To make and receive calls currently you have to host a server that
|
|
handles incoming calls. In the coming weeks, incoming calls will be
|
|
directly handled within Daily and we will expose an endpoint similar
|
|
to `{service}/start` that will manage this for you.
|
|
|
|
In the meantime, the server described below serves as the webhook
|
|
handler for the `room_creation_api`. Configure your pinless phone
|
|
number or SIP interconnect to the `ngrok` tunnel or
|
|
the actual server URL, append `/api/dial` to the webhook URL.
|
|
|
|
## Example curl commands
|
|
|
|
Note: Replace `http://localhost:3000` with your actual server URL and
|
|
phone numbers with valid values for your use case.
|
|
|
|
### Dialin Request
|
|
|
|
The server will receive a request when a call is received from Daily.
|
|
The payload that the webhook received is as follows:
|
|
```json
|
|
{
|
|
// for dial-in from webhook
|
|
"To": "+14152251493",
|
|
"From": "+14158483432",
|
|
"callId": "string-contains-uuid",
|
|
"callDomain": "string-contains-uuid",
|
|
"sipHeaders": {
|
|
"X-My-Custom-Header": "value",
|
|
"x-caller": "+1234567890",
|
|
"x-called": "+1987654321",
|
|
},
|
|
}
|
|
```
|
|
The `To`, `From`, `callId`, `callDomain` fields are converted to
|
|
`snake_case` and mapped to `dialin_settings`. In addition, `sipHeader`
|
|
contains any custom SIP headers received by Daily on the SIP
|
|
interconnect address (`sip_uri`). These are headers sent from
|
|
Twilio or other external SIP platforms, for example, to send the
|
|
caller's phone number.
|
|
|
|
### Dialout Request
|
|
|
|
Dial a number, will use any purchased number
|
|
|
|
```bash
|
|
curl -X POST http://localhost:3000/api/dial \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"dialout_settings": [
|
|
{
|
|
"phoneNumber": "+1234567890",
|
|
}
|
|
]
|
|
}'
|
|
```
|
|
|
|
Dial a number with callerId, which is the UUID of a purchased number.
|
|
|
|
```bash
|
|
curl -X POST http://localhost:3000/api/dial \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"dialout_settings": [
|
|
{
|
|
"phoneNumber": "+1234567890",
|
|
"callerId": "purchased_phone_uuid"
|
|
}
|
|
]
|
|
}'
|
|
```
|
|
|
|
Dial a number
|
|
|
|
```bash
|
|
curl -X POST http://localhost:3000/api/dial \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"dialout_settings": [
|
|
{
|
|
"phoneNumber": "+1234567890",
|
|
"callerId": "purchased_phone_uuid"
|
|
}
|
|
]
|
|
}'
|
|
```
|
|
|
|
### Advanced Request with Voicemail Detection
|
|
|
|
```bash
|
|
curl -X POST http://localhost:3000/api/dial \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"To": "+1234567890",
|
|
"From": "+1987654321",
|
|
"callId": "call-uuid-123",
|
|
"callDomain": "domain-uuid-456",
|
|
"sipHeader": {},
|
|
"dialout_settings": [
|
|
{
|
|
"phoneNumber": "+1234567890",
|
|
"callerId": "purchased_phone_uuid"
|
|
}
|
|
],
|
|
"voicemail_detection": {
|
|
"testInPrebuilt": true
|
|
},
|
|
"call_transfer": {
|
|
"mode": "dialout",
|
|
"speakSummary": true,
|
|
"storeSummary": true,
|
|
"operatorNumber": "+1234567890",
|
|
"testInPrebuilt": true
|
|
}
|
|
}'
|
|
```
|