mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-22 08:38:13 +02:00
feat: refactor telephony to support multiple telephony configurations (#251)
Co-authored-by: Sabiha Khan <sabihak89@gmail.com>
This commit is contained in:
parent
2f860e7f6d
commit
e16f6438bd
101 changed files with 10906 additions and 5420 deletions
|
|
@ -98,6 +98,8 @@
|
|||
"integrations/telephony/inbound",
|
||||
"integrations/telephony/twilio",
|
||||
"integrations/telephony/vonage",
|
||||
"integrations/telephony/plivo",
|
||||
"integrations/telephony/telnyx",
|
||||
"integrations/telephony/cloudonix",
|
||||
"integrations/telephony/vobiz",
|
||||
"integrations/telephony/asterisk-ari",
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 374 KiB After Width: | Height: | Size: 88 KiB |
|
|
@ -90,8 +90,8 @@ Refer to the [Asterisk WebSocket documentation](https://docs.asterisk.org/) for
|
|||
|
||||
### Step 1: Navigate to Telephony Settings
|
||||
|
||||
1. Go to **Workflow** → **Phone Call** → **Configure Telephony**
|
||||
2. Select **Asterisk (ARI)** as your provider
|
||||
1. Navigate to **/telephony-configurations** and click **Add configuration**
|
||||
2. Select **Asterisk ARI** as your provider
|
||||
|
||||
### Step 2: Enter Your ARI Credentials
|
||||
|
||||
|
|
@ -103,47 +103,69 @@ Configure the following fields:
|
|||
| **Stasis App Name** | The ARI username configured in `ari.conf` | `dograh` |
|
||||
| **App Password** | The ARI password configured in `ari.conf` | `your_secure_password` |
|
||||
| **WebSocket Client Name** | The connection name from `websocket_client.conf` | `dograh_staging` |
|
||||
| **Inbound Workflow ID** | The workflow to activate for inbound calls (optional) | `42` |
|
||||
| **SIP Extensions / Numbers** | Optional SIP extensions or trunk numbers for outbound calls | `PJSIP/6001` or `6001` |
|
||||
| **From Extensions** | Optional SIP extensions or trunk numbers for outbound calls | `PJSIP/6001` or `6001` |
|
||||
|
||||
### Step 3: Save and Test
|
||||
### Step 3: Save and Add Extensions
|
||||
|
||||
1. Click **Save Configuration**
|
||||
2. Create a test workflow
|
||||
3. Initiate a test call to verify the connection
|
||||
2. Open the configuration you just created and add each SIP extension that should be reachable as a **phone number** (e.g. `8000`). For inbound, you'll assign a workflow to each extension separately — see [Inbound Calling](#inbound-calling) below.
|
||||
3. Create a test workflow and initiate a test call to verify the connection.
|
||||
|
||||
## Inbound Calling
|
||||
|
||||
Unlike other telephony providers that use HTTP webhooks for inbound calls, ARI delivers inbound calls as **StasisStart events on the ARI WebSocket**. Dograh automatically detects these events and activates the configured workflow.
|
||||
Unlike other telephony providers that use HTTP webhooks for inbound calls, ARI delivers inbound calls as **StasisStart events on the ARI WebSocket**. Dograh automatically detects these events and activates the workflow assigned to the called extension.
|
||||
|
||||
### How It Works
|
||||
|
||||
1. An external call arrives at Asterisk and the dialplan routes it to `Stasis(dograh)`
|
||||
2. Asterisk fires a StasisStart event over the ARI WebSocket with the channel in `Ring` state
|
||||
3. Dograh identifies this as an inbound call, validates your quota, and creates a workflow run
|
||||
2. Asterisk fires a StasisStart event over the ARI WebSocket with the channel in `Ring` state and the dialed extension in the dialplan context
|
||||
3. Dograh looks up the called extension in your telephony configuration's phone numbers, finds the assigned workflow, validates quota, and creates a workflow run
|
||||
4. The call is answered, bridged to an external media channel, and your voice agent workflow begins
|
||||
|
||||
Workflow assignment is **per extension**, so different extensions on the same Asterisk can route to different agents.
|
||||
|
||||
### Setting Up Inbound Calls
|
||||
|
||||
**Step 1: Configure the Asterisk dialplan**
|
||||
|
||||
Ensure your dialplan routes inbound calls to the Stasis application as shown in the [dialplan configuration above](#configure-the-stasis-dialplan-extensionsconf).
|
||||
Ensure your dialplan routes the extensions you care about into the Stasis application. Either route a specific extension:
|
||||
|
||||
**Step 2: Set the Inbound Workflow ID in Dograh**
|
||||
```ini
|
||||
[from-external]
|
||||
exten => 8000,1,NoOp(Incoming call to 8000)
|
||||
same => n,Stasis(dograh)
|
||||
same => n,Hangup()
|
||||
```
|
||||
|
||||
1. Go to **Workflow** → **Phone Call** → **Configure Telephony**
|
||||
2. In the ARI configuration, enter the **Inbound Workflow ID** — this is the ID of the workflow you want to activate when an inbound call arrives
|
||||
3. Click **Save Configuration**
|
||||
…or use a pattern that catches every extension you'll register in Dograh:
|
||||
|
||||
You can find a workflow's ID in the URL when viewing it (e.g., `/workflows/42` means the ID is `42`).
|
||||
```ini
|
||||
[from-external]
|
||||
exten => _X.,1,NoOp(Incoming call to ${EXTEN})
|
||||
same => n,Stasis(dograh)
|
||||
same => n,Hangup()
|
||||
```
|
||||
|
||||
<Note>
|
||||
If no Inbound Workflow ID is configured, inbound calls will be hung up immediately. You must set this field for inbound calling to work.
|
||||
</Note>
|
||||
Replace `dograh` with the app name you configured in `ari.conf` and in Dograh.
|
||||
|
||||
**Step 2: Add the extension as a phone number in Dograh**
|
||||
|
||||
1. Go to **/telephony-configurations** and open your Asterisk ARI configuration
|
||||
2. In the **Phone numbers** section, add a phone number whose address is the SIP extension (e.g. `8000`)
|
||||
3. Set its **Inbound workflow** to the agent that should answer
|
||||
4. Save
|
||||
|
||||
<Note>
|
||||
Adding the extension in Dograh doesn't change Asterisk's dialplan — that's
|
||||
what Step 1 is for. The Dograh entry tells the StasisStart handler which
|
||||
workflow to run when a call to that extension reaches the Stasis app.
|
||||
</Note>
|
||||
|
||||
Repeat Step 2 for each extension that should reach a voice agent.
|
||||
|
||||
**Step 3: Test an inbound call**
|
||||
|
||||
Place a call to a number or extension routed to your Stasis application. You should see the workflow activate and the voice agent respond.
|
||||
Place a call to one of the extensions you configured. You should see the assigned workflow activate and the voice agent respond.
|
||||
|
||||
### Inbound Call Context
|
||||
|
||||
|
|
@ -188,10 +210,14 @@ When an inbound call activates a workflow, the following context is available to
|
|||
</Accordion>
|
||||
|
||||
<Accordion title="Inbound calls are immediately hung up">
|
||||
- Verify the **Inbound Workflow ID** is set in your ARI telephony configuration
|
||||
- Confirm the workflow ID exists and belongs to the same organization as the ARI config
|
||||
- Verify the called extension is added as a phone number under your ARI
|
||||
configuration in /telephony-configurations and has an **Inbound workflow**
|
||||
assigned
|
||||
- Confirm the workflow exists and belongs to the same organization as the
|
||||
ARI config
|
||||
- Check that your organization has available quota
|
||||
- Review Dograh logs for warnings mentioning "no inbound_workflow_id configured"
|
||||
- Review Dograh logs for warnings like "no matching phone number registered
|
||||
for config" or "has no inbound_workflow_id assigned"
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="WebSocket client connection issues">
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ Before setting up Cloudonix integration, you'll need:
|
|||
|
||||
- A [Cloudonix account](https://cockpit.cloudonix.io/onboarding?affiliate=DOGRAH)
|
||||
- A Cloudonix domain UUID (or the domain name)
|
||||
- A Cloudonix domain API Key
|
||||
- A Cloudonix domain API Key (Bearer Token)
|
||||
- A Cloudonix **Voice Application** on that domain — Dograh will manage its `url`
|
||||
- A Cloudonix outbound voice trunk service provider connection
|
||||
- Dograh AI instance running and accessible
|
||||
|
||||
|
|
@ -36,38 +37,36 @@ Watch this step-by-step guide to set up Cloudonix with Dograh AI:
|
|||
### Step 1: Get Cloudonix Credentials
|
||||
|
||||
1. Log in to your [Cloudonix Console](https://cockpit.cloudonix.io/onboarding?affiliate=DOGRAH)
|
||||
2. Find your **Domain UUID** and **Domain API Key** on the dashboard
|
||||
2. Find your **Domain ID** (UUID or domain name) and **Bearer Token** (Domain API Key) on the dashboard
|
||||
3. Navigate to your domain's **Applications** and create (or open) the application you'll use with Dograh
|
||||
4. Copy the **Application Name** — Dograh will manage this application's `url`
|
||||
|
||||
### Step 2: Configure in Dograh AI
|
||||
|
||||
1. Navigate to **Workflow** → **Phone Call** → **Configure Telephony**
|
||||
1. Navigate to **/telephony-configurations** and click **Add configuration**
|
||||
2. Watch the Cloudonix setup video tutorial above for detailed guidance
|
||||
3. Select **Cloudonix** as your provider
|
||||
4. Enter your credentials:
|
||||
- Domain UUID
|
||||
- Domain API Key
|
||||
- Bearer Token
|
||||
- Domain ID
|
||||
- Application Name
|
||||
5. Click **Save Configuration**
|
||||
6. Open the configuration you just created and add at least one **phone number** (with country code in E.164 format, e.g. `+1234567890`). The default caller ID is used for outbound calls.
|
||||
|
||||
### Step 3: Test Your Configuration
|
||||
|
||||
1. Create a test workflow
|
||||
2. Click "Test Call" to verify connection
|
||||
2. Click "Call" to verify connection
|
||||
3. Check call logs for successful connection
|
||||
|
||||
## Inbound Calling Setup
|
||||
|
||||
The Dograh AI configuration for inbound calling is **identical** to outbound calling - use the same credentials configured above. However, you need additional setup in your Cloudonix Console to route incoming calls to Dograh AI.
|
||||
Cloudonix routes inbound calls per **Voice Application** — the webhook URL is set once on the application, and applies to every DNID bound to it. **When you save an inbound workflow on a phone number, Dograh automatically pushes the webhook URL to your Voice Application's `url`** (provided the credentials are correct), so you don't need to set the webhook by hand.
|
||||
|
||||
### Configure Inbound Trunk and Application
|
||||
### Step 1: Set Up the Inbound Trunk
|
||||
|
||||
1. **Set Up Inbound Trunk**:
|
||||
- Log in to your [Cloudonix Console](https://cockpit.cloudonix.io)
|
||||
- Navigate to **Trunks** → **Create Inbound Trunk**
|
||||
- Configure your inbound trunk with your voice service provider
|
||||
- Ensure the trunk can receive calls to your desired phone numbers
|
||||
|
||||
2. **Create Application for Your Domain**:
|
||||
- Select your domain in the Cloudonix Console
|
||||
1. Log in to your [Cloudonix Console](https://cockpit.cloudonix.io)
|
||||
2. Navigate to **Trunks** → **Create Inbound Trunk** and configure your inbound trunk with your voice service provider
|
||||
|
||||
<img
|
||||
className="block dark:hidden"
|
||||
|
|
@ -80,32 +79,79 @@ The Dograh AI configuration for inbound calling is **identical** to outbound cal
|
|||
alt="Cloudonix console showing domain selection"
|
||||
/>
|
||||
|
||||
- Create a new application for your domain
|
||||
- Set the webhook URL in the application:
|
||||
```
|
||||
https://api.dograh.com/api/v1/telephony/inbound/{workflow_id}
|
||||
```
|
||||
### Step 2: Create the Voice Application and Link DNIDs
|
||||
|
||||
1. In the Cloudonix cockpit, select your domain and navigate to **Applications**
|
||||
2. Create a new application (or open the existing one whose name you configured in Dograh) with these settings:
|
||||
- **Application Resource Type**: `Remote Application Resource`
|
||||
- **Application Runtime**: `Cloudonix (CXML)`
|
||||
- **Application URL**: `https://api.dograh.com/api/v1/telephony/inbound/run`
|
||||
- **HTTP Method**: `POST`
|
||||
3. Under **DNID Numbers**, add each phone number (DNID) you want to route through this application
|
||||
4. Save
|
||||
|
||||
<Note>
|
||||
Replace `{workflow_id}` with your actual workflow ID. If using self-hosted Dograh, replace `api.dograh.com` with your domain.
|
||||
The Application URL is what Dograh's auto-push updates in Step 3 — you
|
||||
can leave it blank during creation and let the auto-push fill it in,
|
||||
or paste the URL above so the application is usable immediately.
|
||||
Either works. Self-hosted Dograh deployments use their backend domain
|
||||
in place of `api.dograh.com`.
|
||||
</Note>
|
||||
|
||||
<img
|
||||
className="block dark:hidden"
|
||||
src="/images/cloudonix-inbound-config-application.png"
|
||||
alt="Cloudonix application form showing Remote Application Resource type, Cloudonix CXML runtime, the Dograh inbound URL, POST method, and a DNID number entry"
|
||||
/>
|
||||
<img
|
||||
className="hidden dark:block"
|
||||
src="/images/cloudonix-inbound-config-application.png"
|
||||
alt="Cloudonix application form showing Remote Application Resource type, Cloudonix CXML runtime, the Dograh inbound URL, POST method, and a DNID number entry"
|
||||
/>
|
||||
|
||||
### Step 3: Assign an Inbound Workflow to the Phone Number in Dograh
|
||||
|
||||
1. Go to **/telephony-configurations** and open your Cloudonix configuration
|
||||
2. In the **Phone numbers** section, edit the number that should receive inbound calls
|
||||
3. Set its **Inbound workflow** to the agent that should answer
|
||||
4. Save
|
||||
|
||||
### Step 4: Verify the URL on the Voice Application
|
||||
|
||||
1. Open your Cloudonix cockpit and navigate to your domain's **Applications**
|
||||
2. Open the application whose name you configured in Dograh
|
||||
3. Confirm:
|
||||
- **URL** is set to: `https://api.dograh.com/api/v1/telephony/inbound/run`
|
||||
- **Method** is `POST`
|
||||
|
||||
<Note>
|
||||
Dograh pushed this URL automatically when you saved the inbound workflow
|
||||
in Step 3. The same URL is shared across every DNID bound to that
|
||||
application — Dograh routes each inbound call to the right agent based
|
||||
on the called number's inbound workflow assignment. If the field is
|
||||
empty, shows a different URL, or Dograh surfaced a sync warning on
|
||||
save, the auto-push failed — most often because the Bearer Token,
|
||||
Domain ID, or Application Name in Dograh is incorrect. Paste the URL
|
||||
into the field yourself, set the method to `POST`, and save. On
|
||||
self-hosted Dograh, replace `api.dograh.com` with your backend domain.
|
||||
</Note>
|
||||
|
||||
<img
|
||||
className="block dark:hidden"
|
||||
src="/images/cloudonix-inbound-config-2.png"
|
||||
alt="Cloudonix application creation with webhook URL configuration"
|
||||
alt="Cloudonix application showing webhook URL configuration"
|
||||
/>
|
||||
<img
|
||||
className="hidden dark:block"
|
||||
src="/images/cloudonix-inbound-config-2.png"
|
||||
alt="Cloudonix application creation with webhook URL configuration"
|
||||
alt="Cloudonix application showing webhook URL configuration"
|
||||
/>
|
||||
|
||||
3. **Verify Configuration**:
|
||||
- Ensure your Dograh AI instance is publicly accessible
|
||||
- Test that webhook URL responds correctly
|
||||
- Verify any firewalls allow Cloudonix's IP ranges
|
||||
- Confirm your inbound trunk is active and receiving calls
|
||||
### Step 5: Verify Setup
|
||||
|
||||
- Ensure your Dograh AI instance is publicly accessible
|
||||
- Verify any firewalls allow Cloudonix's IP ranges
|
||||
- Confirm your inbound trunk is active and receiving calls
|
||||
|
||||
### Test Inbound Calling
|
||||
|
||||
|
|
@ -122,34 +168,36 @@ The Dograh AI configuration for inbound calling is **identical** to outbound cal
|
|||
</Accordion>
|
||||
|
||||
<Accordion title="Authentication failed">
|
||||
- Verify Domain UUID and Domain API Key are correct
|
||||
- Verify Domain ID, Bearer Token, and Application Name are correct
|
||||
- Check for extra spaces in credentials
|
||||
- Ensure credentials haven't been disabled or deleted in Cloudonix Console
|
||||
</Accordion>
|
||||
|
||||
|
||||
<Accordion title="No audio on calls">
|
||||
- Verify WebSocket connection is established
|
||||
- Check firewall rules for WebSocket traffic
|
||||
- Ensure audio pipeline is configured correctly
|
||||
</Accordion>
|
||||
|
||||
|
||||
<Accordion title="Inbound calls not reaching voice agent">
|
||||
- Verify inbound trunk is properly configured and active
|
||||
- Check routing rules point to correct Dograh AI webhook endpoint
|
||||
- Ensure webhook URLs are publicly accessible
|
||||
- Confirm phone numbers are correctly routed to your trunk
|
||||
- Verify the DNID is bound to the same Voice Application whose name you
|
||||
configured in Dograh - Confirm the called number exists in your Dograh
|
||||
telephony configuration and has an **Inbound workflow** assigned -
|
||||
After assigning the inbound workflow, confirm Dograh successfully updated
|
||||
the application's `url` (no warning shown on save) - Verify your inbound
|
||||
trunk is active and receiving calls
|
||||
</Accordion>
|
||||
|
||||
|
||||
<Accordion title="Voice agent doesn't respond to inbound calls">
|
||||
- Verify organization_id in webhook URLs matches your setup
|
||||
- Check that voice agent workflow is properly configured
|
||||
- Ensure SIP connection instructions are correctly returned
|
||||
- Review webhook logs for error responses
|
||||
- Confirm the phone number has an **Inbound workflow** assigned in
|
||||
/telephony-configurations - Verify the Bearer Token in Dograh matches the
|
||||
one in your Cloudonix Console - Verify WebSocket connection establishes
|
||||
successfully - Review call logs for error messages
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Store credentials securely in the database
|
||||
- Test your configuration with a single call before running campaigns
|
||||
- Monitor Cloudonix Sessions for usage
|
||||
- Use a dedicated Voice Application for Dograh so the shared `url` doesn't conflict with other systems
|
||||
|
|
|
|||
|
|
@ -5,286 +5,394 @@ description: "Build your own telephony provider integration for Dograh AI"
|
|||
|
||||
## Overview
|
||||
|
||||
Dograh AI's telephony abstraction layer allows you to integrate any telephony service by implementing the `TelephonyProvider` interface.
|
||||
A telephony provider is implemented as a **self-registering package** under `api/services/telephony/providers/<name>/`. The package contributes everything Dograh needs to wire the provider in — the provider class, transport factory, audio config, request/response schemas, optional HTTP routes, and the form metadata used to render its configuration UI — through a single `ProviderSpec` registered at import time.
|
||||
|
||||
## Provider Interface
|
||||
Adding a new provider should not require touching the factory, the audio config, the API routes module, the run-pipeline module, or the frontend. The only edits outside the provider folder are:
|
||||
|
||||
All telephony providers must implement this abstract base class:
|
||||
1. One import line in `api/services/telephony/providers/__init__.py`
|
||||
2. One import line in `api/schemas/telephony_config.py` to add the request/response classes to the `TelephonyConfigRequest` discriminated union
|
||||
|
||||
## Provider Package Layout
|
||||
|
||||
```
|
||||
api/services/telephony/providers/your_provider/
|
||||
├── __init__.py # Builds and registers ProviderSpec
|
||||
├── config.py # Pydantic Request/Response schemas
|
||||
├── provider.py # TelephonyProvider subclass
|
||||
├── transport.py # Pipecat WebSocket transport factory
|
||||
├── serializers.py # Frame serializer (usually re-exports from pipecat)
|
||||
├── routes.py # (optional) HTTP webhook/callback handlers
|
||||
└── strategies.py # (optional) Transfer/hangup strategies
|
||||
```
|
||||
|
||||
Three files are required (`__init__.py`, `config.py`, `provider.py`, `transport.py`). The rest are optional and are discovered automatically when present:
|
||||
|
||||
- **`routes.py`** — if the module exists and exports `router: APIRouter`, the routes module is imported lazily and mounted under `/api/v1/telephony` by `api.routes.telephony` via `importlib`. Providers that only stream over WebSocket (e.g. ARI) can omit it.
|
||||
- **`strategies.py`** — used by transports that need provider-specific call transfer/hangup logic in the frame serializer (e.g. Twilio Conference transfers).
|
||||
- **`serializers.py`** — typically a re-export from pipecat. Keep the file even when it's a one-line re-export so transport code imports from `.serializers`, giving you an obvious place to drop a custom subclass later.
|
||||
|
||||
## The `TelephonyProvider` Interface
|
||||
|
||||
Subclass `TelephonyProvider` in `provider.py`:
|
||||
|
||||
```python
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, Dict, List, Optional
|
||||
from api.services.telephony.base import (
|
||||
CallInitiationResult,
|
||||
NormalizedInboundData,
|
||||
ProviderSyncResult,
|
||||
TelephonyProvider,
|
||||
)
|
||||
|
||||
class TelephonyProvider(ABC):
|
||||
"""Abstract base class for telephony providers."""
|
||||
|
||||
@abstractmethod
|
||||
async def initiate_call(
|
||||
self,
|
||||
to_number: str,
|
||||
webhook_url: str,
|
||||
workflow_run_id: Optional[int] = None,
|
||||
**kwargs: Any
|
||||
) -> Dict[str, Any]:
|
||||
"""Initiate an outbound call."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_call_status(self, call_id: str) -> Dict[str, Any]:
|
||||
"""Get current status of a call."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_available_phone_numbers(self) -> List[str]:
|
||||
"""Get list of available phone numbers."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def validate_config(self) -> bool:
|
||||
"""Validate provider configuration."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def verify_webhook_signature(
|
||||
self, url: str, params: Dict[str, Any], signature: str
|
||||
) -> bool:
|
||||
"""Verify webhook signature for security."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_webhook_response(
|
||||
self, workflow_id: int, user_id: int, workflow_run_id: int
|
||||
) -> str:
|
||||
"""Generate initial webhook response."""
|
||||
pass
|
||||
|
||||
async def get_call_cost(self, call_id: str) -> Dict[str, Any]:
|
||||
"""Get cost information for a completed call."""
|
||||
pass
|
||||
|
||||
class YourProvider(TelephonyProvider):
|
||||
PROVIDER_NAME = "your_provider"
|
||||
WEBHOOK_ENDPOINT = "your-provider-xml" # path under /api/v1/telephony
|
||||
|
||||
def __init__(self, config: dict):
|
||||
self.api_key = config.get("api_key")
|
||||
self.from_numbers = config.get("from_numbers", [])
|
||||
|
||||
# ---------- outbound ----------
|
||||
async def initiate_call(self, to_number, webhook_url, workflow_run_id=None,
|
||||
from_number=None, **kwargs) -> CallInitiationResult: ...
|
||||
async def get_call_status(self, call_id) -> dict: ...
|
||||
async def get_call_cost(self, call_id) -> dict: ...
|
||||
async def get_available_phone_numbers(self) -> list[str]: ...
|
||||
def validate_config(self) -> bool: ...
|
||||
|
||||
# ---------- webhooks ----------
|
||||
async def verify_webhook_signature(self, url, params, signature) -> bool: ...
|
||||
async def get_webhook_response(self, workflow_id, user_id, workflow_run_id) -> str: ...
|
||||
def parse_status_callback(self, data: dict) -> dict: ...
|
||||
|
||||
# ---------- websocket ----------
|
||||
async def handle_websocket(self, websocket, workflow_id, user_id, workflow_run_id): ...
|
||||
|
||||
# ---------- inbound ----------
|
||||
@classmethod
|
||||
def can_handle_webhook(cls, webhook_data, headers) -> bool: ...
|
||||
|
||||
@staticmethod
|
||||
def parse_inbound_webhook(webhook_data) -> NormalizedInboundData: ...
|
||||
|
||||
@staticmethod
|
||||
def validate_account_id(config_data, webhook_account_id) -> bool: ...
|
||||
|
||||
def normalize_phone_number(self, phone_number: str) -> str: ...
|
||||
|
||||
async def verify_inbound_signature(self, url, webhook_data, headers, body="") -> bool: ...
|
||||
|
||||
async def start_inbound_stream(self, *, websocket_url, workflow_run_id,
|
||||
normalized_data, backend_endpoint): ...
|
||||
|
||||
@staticmethod
|
||||
def generate_error_response(error_type, message) -> tuple: ...
|
||||
|
||||
# ---------- transfers ----------
|
||||
async def transfer_call(self, destination, transfer_id, conference_name,
|
||||
timeout=30, **kwargs) -> dict: ...
|
||||
def supports_transfers(self) -> bool: ...
|
||||
|
||||
# ---------- optional ----------
|
||||
async def configure_inbound(self, address, webhook_url) -> ProviderSyncResult:
|
||||
# Default returns ok=True — implement only if your provider supports
|
||||
# programmatic webhook configuration (e.g. binding a number to a URL
|
||||
# via API). Used to point inbound numbers at /api/v1/telephony/inbound/run.
|
||||
return ProviderSyncResult(ok=True)
|
||||
```
|
||||
|
||||
See `api/services/telephony/base.py` for the full docstrings on each method.
|
||||
|
||||
## Implementation Guide
|
||||
|
||||
### 1. Create Your Provider
|
||||
### 1. Configuration schemas
|
||||
|
||||
Create a new file in `api/services/telephony/providers/`:
|
||||
Define Pydantic models for the credential payload. The `provider` `Literal` discriminator is what makes the schemas dispatch correctly through the registry's discriminated union.
|
||||
|
||||
```python
|
||||
# api/services/telephony/providers/your_provider.py
|
||||
# providers/your_provider/config.py
|
||||
from typing import List, Literal
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from typing import Any, Dict, List, Optional
|
||||
from api.services.telephony.base import TelephonyProvider
|
||||
|
||||
class YourProvider(TelephonyProvider):
|
||||
"""Your custom telephony provider implementation."""
|
||||
|
||||
def __init__(self, config: Dict[str, Any]):
|
||||
"""Initialize with configuration dictionary."""
|
||||
# Extract your provider-specific configuration
|
||||
self.api_key = config.get("api_key")
|
||||
self.api_secret = config.get("api_secret")
|
||||
self.from_number = config.get("from_numbers", [""])[0]
|
||||
|
||||
def validate_config(self) -> bool:
|
||||
"""Check if all required configuration is present."""
|
||||
return bool(self.api_key and self.api_secret and self.from_number)
|
||||
|
||||
async def initiate_call(
|
||||
self,
|
||||
to_number: str,
|
||||
webhook_url: str,
|
||||
workflow_run_id: Optional[int] = None,
|
||||
**kwargs: Any
|
||||
) -> Dict[str, Any]:
|
||||
"""Start an outbound call using your provider's API."""
|
||||
# Implement your provider's call initiation logic
|
||||
pass
|
||||
|
||||
# Implement other required methods...
|
||||
class YourProviderConfigurationRequest(BaseModel):
|
||||
provider: Literal["your_provider"] = Field(default="your_provider")
|
||||
api_key: str = Field(..., description="Your Provider API key")
|
||||
api_secret: str = Field(..., description="Your Provider API secret")
|
||||
from_numbers: List[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class YourProviderConfigurationResponse(BaseModel):
|
||||
provider: Literal["your_provider"] = Field(default="your_provider")
|
||||
api_key: str # masked when returned
|
||||
api_secret: str # masked when returned
|
||||
from_numbers: List[str]
|
||||
```
|
||||
|
||||
### 2. Register in Factory
|
||||
### 2. Transport factory
|
||||
|
||||
Update `api/services/telephony/factory.py` to include your provider:
|
||||
Build the Pipecat `FastAPIWebsocketTransport` for accepted WebSockets. Always load credentials through `load_credentials_for_transport` so the right config row is picked when the workflow run carries a `telephony_configuration_id` (multi-config orgs).
|
||||
|
||||
```python
|
||||
from api.services.telephony.providers.your_provider import YourProvider
|
||||
# providers/your_provider/transport.py
|
||||
from fastapi import WebSocket
|
||||
from api.services.pipecat.audio_config import AudioConfig
|
||||
from api.services.pipecat.audio_mixer import build_audio_out_mixer
|
||||
from api.services.telephony.factory import load_credentials_for_transport
|
||||
from pipecat.transports.websocket.fastapi import (
|
||||
FastAPIWebsocketParams,
|
||||
FastAPIWebsocketTransport,
|
||||
)
|
||||
from .serializers import YourProviderFrameSerializer
|
||||
|
||||
async def get_telephony_provider(
|
||||
organization_id: int
|
||||
) -> TelephonyProvider:
|
||||
"""Factory function to get appropriate telephony provider."""
|
||||
|
||||
config = await load_telephony_config(organization_id)
|
||||
provider_type = config.get("provider", "twilio")
|
||||
|
||||
if provider_type == "twilio":
|
||||
return TwilioProvider(config)
|
||||
elif provider_type == "vonage":
|
||||
return VonageProvider(config)
|
||||
elif provider_type == "your_provider":
|
||||
return YourProvider(config)
|
||||
else:
|
||||
raise ValueError(f"Unknown telephony provider: {provider_type}")
|
||||
|
||||
async def create_transport(
|
||||
websocket: WebSocket,
|
||||
workflow_run_id: int,
|
||||
audio_config: AudioConfig,
|
||||
organization_id: int,
|
||||
*,
|
||||
vad_config: dict | None = None,
|
||||
ambient_noise_config: dict | None = None,
|
||||
telephony_configuration_id: int | None = None,
|
||||
# provider-specific kwargs (forwarded by run_pipeline_telephony as **transport_kwargs)
|
||||
stream_id: str,
|
||||
call_id: str,
|
||||
):
|
||||
config = await load_credentials_for_transport(
|
||||
organization_id, telephony_configuration_id,
|
||||
expected_provider="your_provider",
|
||||
)
|
||||
|
||||
serializer = YourProviderFrameSerializer(
|
||||
stream_id=stream_id,
|
||||
call_id=call_id,
|
||||
api_key=config["api_key"],
|
||||
)
|
||||
mixer = await build_audio_out_mixer(
|
||||
audio_config.transport_out_sample_rate, ambient_noise_config
|
||||
)
|
||||
|
||||
return FastAPIWebsocketTransport(
|
||||
websocket=websocket,
|
||||
params=FastAPIWebsocketParams(
|
||||
audio_in_enabled=True,
|
||||
audio_out_enabled=True,
|
||||
audio_in_sample_rate=audio_config.transport_in_sample_rate,
|
||||
audio_out_sample_rate=audio_config.transport_out_sample_rate,
|
||||
audio_out_mixer=mixer,
|
||||
serializer=serializer,
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
### 3. Add Configuration Support
|
||||
### 3. Routes (optional)
|
||||
|
||||
Update the configuration loader in `factory.py` to handle your provider's database configuration:
|
||||
If your provider POSTs webhooks to Dograh (answer URL, status callbacks, hangup callbacks), expose them through a module-level `router`. The routes are auto-mounted under `/api/v1/telephony`.
|
||||
|
||||
```python
|
||||
# In load_telephony_config function
|
||||
if provider == "your_provider":
|
||||
# providers/your_provider/routes.py
|
||||
from fastapi import APIRouter, Request
|
||||
from api.services.telephony.factory import get_telephony_provider
|
||||
from api.services.telephony.status_processor import (
|
||||
StatusCallbackRequest,
|
||||
_process_status_update,
|
||||
)
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("/your-provider/status-callback/{workflow_run_id}")
|
||||
async def status_callback(workflow_run_id: int, request: Request):
|
||||
...
|
||||
```
|
||||
|
||||
Routes are loaded lazily via `importlib` from `api.routes.telephony._mount_provider_routers`, so your route module can freely import other backend services without creating import cycles at provider-class load time.
|
||||
|
||||
### 4. Register the `ProviderSpec`
|
||||
|
||||
The package's `__init__.py` is where everything comes together:
|
||||
|
||||
```python
|
||||
# providers/your_provider/__init__.py
|
||||
from typing import Any, Dict
|
||||
|
||||
from api.services.pipecat.audio_config import AudioConfig
|
||||
from api.services.telephony.registry import (
|
||||
ProviderSpec,
|
||||
ProviderUIField,
|
||||
ProviderUIMetadata,
|
||||
register,
|
||||
)
|
||||
|
||||
from .config import YourProviderConfigurationRequest, YourProviderConfigurationResponse
|
||||
from .provider import YourProvider
|
||||
from .transport import create_transport
|
||||
|
||||
|
||||
def _config_loader(value: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Normalize the stored credentials dict into the constructor shape."""
|
||||
return {
|
||||
"provider": "your_provider",
|
||||
"api_key": config.value.get("api_key"),
|
||||
"api_secret": config.value.get("api_secret"),
|
||||
"from_numbers": config.value.get("from_numbers", [])
|
||||
"api_key": value.get("api_key"),
|
||||
"api_secret": value.get("api_secret"),
|
||||
"from_numbers": value.get("from_numbers", []),
|
||||
}
|
||||
|
||||
|
||||
_AUDIO_CONFIG = AudioConfig(
|
||||
transport_in_sample_rate=8000,
|
||||
transport_out_sample_rate=8000,
|
||||
vad_sample_rate=8000,
|
||||
pipeline_sample_rate=8000,
|
||||
buffer_size_seconds=5.0,
|
||||
)
|
||||
|
||||
|
||||
_UI_METADATA = ProviderUIMetadata(
|
||||
display_name="Your Provider",
|
||||
docs_url="https://docs.your-provider.com",
|
||||
fields=[
|
||||
ProviderUIField(name="api_key", label="API Key", type="text", sensitive=True),
|
||||
ProviderUIField(name="api_secret", label="API Secret", type="password", sensitive=True),
|
||||
ProviderUIField(
|
||||
name="from_numbers", label="Phone Numbers", type="string-array",
|
||||
description="E.164-formatted phone numbers used for outbound calls",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
SPEC = ProviderSpec(
|
||||
name="your_provider",
|
||||
provider_cls=YourProvider,
|
||||
config_loader=_config_loader,
|
||||
transport_factory=create_transport,
|
||||
audio_config=_AUDIO_CONFIG,
|
||||
config_request_cls=YourProviderConfigurationRequest,
|
||||
config_response_cls=YourProviderConfigurationResponse,
|
||||
ui_metadata=_UI_METADATA,
|
||||
# Credential field that uniquely identifies the provider account.
|
||||
# Used to disambiguate inbound webhooks across multiple configs of the
|
||||
# same provider. Empty string for providers without an account-id concept.
|
||||
account_id_credential_field="api_key",
|
||||
)
|
||||
|
||||
register(SPEC)
|
||||
```
|
||||
|
||||
The configuration will be stored in the database under the `TELEPHONY_CONFIGURATION` key in the `organization_configuration` table and managed through the web interface.
|
||||
`ProviderSpec` covers everything downstream code needs:
|
||||
|
||||
| Field | Used by |
|
||||
| --- | --- |
|
||||
| `name` | Stored as the discriminator on every `TelephonyConfiguration` row and as the `WorkflowRunMode` value |
|
||||
| `provider_cls` | `factory.get_telephony_provider*` |
|
||||
| `config_loader` | `factory._normalize_with_phone_numbers` (replaces the old if/elif chain) |
|
||||
| `transport_factory` | `run_pipeline_telephony` |
|
||||
| `audio_config` | `create_audio_config()` and `run_pipeline_telephony` |
|
||||
| `config_request_cls` / `config_response_cls` | `TelephonyConfigRequest` discriminated union |
|
||||
| `ui_metadata` | `GET /api/v1/organizations/telephony-providers/metadata` (drives the form UI) and the `_sensitive_fields` masking helper |
|
||||
| `account_id_credential_field` | Inbound webhook routing across multiple configs of the same provider |
|
||||
|
||||
### 5. Wire the package into the registry import chain
|
||||
|
||||
Add one import line to `api/services/telephony/providers/__init__.py`:
|
||||
|
||||
```python
|
||||
from api.services.telephony.providers import ( # noqa: F401 -- side effects
|
||||
ari,
|
||||
cloudonix,
|
||||
plivo,
|
||||
telnyx,
|
||||
twilio,
|
||||
vobiz,
|
||||
vonage,
|
||||
your_provider, # ← add this
|
||||
)
|
||||
```
|
||||
|
||||
### 6. Add to the discriminated union
|
||||
|
||||
Add one import block to `api/schemas/telephony_config.py` so the request/response classes participate in the `TelephonyConfigRequest` union and the `TelephonyConfigurationResponse` shape:
|
||||
|
||||
```python
|
||||
from api.services.telephony.providers.your_provider.config import (
|
||||
YourProviderConfigurationRequest,
|
||||
YourProviderConfigurationResponse,
|
||||
)
|
||||
|
||||
TelephonyConfigRequest = Annotated[
|
||||
Union[
|
||||
# ...existing entries...
|
||||
YourProviderConfigurationRequest,
|
||||
],
|
||||
Field(discriminator="provider"),
|
||||
]
|
||||
|
||||
|
||||
class TelephonyConfigurationResponse(BaseModel):
|
||||
# ...existing entries...
|
||||
your_provider: Optional[YourProviderConfigurationResponse] = None
|
||||
```
|
||||
|
||||
That's it for backend wiring.
|
||||
|
||||
## Frontend
|
||||
|
||||
The configuration form is **metadata-driven**. The UI calls `GET /api/v1/organizations/telephony-providers/metadata`, gets back the list of providers and their `ProviderUIField` definitions, and renders each form generically. **No per-provider frontend code is needed** — your `ProviderUIMetadata` declaration is what drives the form.
|
||||
|
||||
If you add a new field type that the existing renderer doesn't support (e.g. a file upload), extend the renderer in `ui/src/app/(authenticated)/telephony-configurations/`. The supported `ProviderUIField.type` values today are `text`, `password`, `textarea`, `string-array`, and `number`.
|
||||
|
||||
## Audio Format Considerations
|
||||
|
||||
Different providers use different audio formats:
|
||||
- **Twilio**: 8kHz μ-law (MULAW) encoded in Base64
|
||||
- **Vonage**: 16kHz Linear PCM as binary frames
|
||||
Each provider declares its wire format through its `AudioConfig`. Common shapes:
|
||||
|
||||
Your provider may differ, so ensure proper audio format conversion in your WebSocket handler and configure the audio pipeline accordingly.
|
||||
- **Twilio / Plivo**: 8 kHz μ-law, base64-encoded JSON frames
|
||||
- **Vonage**: 16 kHz Linear PCM as binary frames
|
||||
- **Asterisk ARI**: 8 kHz Linear PCM via externalMedia
|
||||
|
||||
The pipeline sample rate is capped at 16 kHz to satisfy VAD; transports handle resampling between the wire format and the pipeline's internal rate.
|
||||
|
||||
## Testing
|
||||
|
||||
Create unit tests for your provider:
|
||||
|
||||
```python
|
||||
# tests/test_your_provider.py
|
||||
|
||||
# api/tests/telephony/test_your_provider.py
|
||||
import pytest
|
||||
from api.services.telephony.providers.your_provider import YourProvider
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_validate_config():
|
||||
config = {
|
||||
provider = YourProvider({
|
||||
"api_key": "test_key",
|
||||
"api_secret": "test_secret",
|
||||
"from_numbers": ["+1234567890"]
|
||||
}
|
||||
provider = YourProvider(config)
|
||||
"from_numbers": ["+1234567890"],
|
||||
})
|
||||
assert provider.validate_config() is True
|
||||
```
|
||||
|
||||
For end-to-end testing, save your provider through the telephony-configurations UI and trigger a test call from a workflow.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Error Handling**: Implement robust error handling with meaningful messages
|
||||
2. **Logging**: Use `loguru.logger` for consistent logging
|
||||
3. **Async Operations**: All I/O operations should be async
|
||||
4. **Configuration Validation**: Validate config on initialization
|
||||
5. **Security**: Always verify webhook signatures
|
||||
1. **Trust the registry** — never import another provider's class directly; resolve through `factory.get_telephony_provider*`.
|
||||
2. **Sensitive fields** — mark every credential field `sensitive=True` in `ProviderUIMetadata`. The save endpoint masks these on read and preserves the original when the client re-submits a masked value.
|
||||
3. **Inbound signature verification** — always validate inbound webhook signatures in `verify_inbound_signature`. Returning `True` when no signature header is present is acceptable; return `False` when a signature *is* present but invalid.
|
||||
4. **Transports load credentials lazily** — call `load_credentials_for_transport` with the `telephony_configuration_id` from the workflow run. Don't read the org's default config from `transport.py`.
|
||||
5. **Logging** — use `loguru.logger`.
|
||||
|
||||
## Reference Implementations
|
||||
|
||||
See these provider implementations for complete examples:
|
||||
- **Twilio**: `api/services/telephony/providers/twilio_provider.py` - Basic authentication, XML (TwiML) responses
|
||||
- **Vonage**: `api/services/telephony/providers/vonage_provider.py` - JWT authentication, JSON (NCCO) responses
|
||||
| Provider | Notable for |
|
||||
| --- | --- |
|
||||
| `providers/twilio/` | Full-featured: outbound, inbound, conference transfers, status callbacks, custom strategies |
|
||||
| `providers/plivo/` | Recently-added reference; mirrors Twilio's shape with multi-callback signatures |
|
||||
| `providers/vonage/` | JWT auth, 16 kHz Linear PCM, NCCO responses |
|
||||
| `providers/cloudonix/` | SIP-based, custom call strategies |
|
||||
| `providers/telnyx/` | Call-control style: REST-driven inbound answer flow rather than markup response |
|
||||
| `providers/ari/` | Minimal example — no `routes.py`, no inbound webhook verification, WebSocket-only |
|
||||
|
||||
<Note>
|
||||
Other providers like Plivo, Telnyx, or custom SIP providers can be implemented following the same pattern.
|
||||
These are not included out-of-the-box but can be easily added by implementing the TelephonyProvider interface.
|
||||
Use ARI as the smallest viable example when your provider doesn't expose HTTP
|
||||
webhooks, and Twilio as the reference when it does.
|
||||
</Note>
|
||||
|
||||
## UI Implementation Guide
|
||||
|
||||
To integrate your new provider into the frontend, you'll need to update the configuration form and the workflow header.
|
||||
|
||||
### 1. Update Configuration Page
|
||||
|
||||
Modify `src/app/configure-telephony/page.tsx` to include your provider's form fields.
|
||||
|
||||
**A. Update Interface**
|
||||
|
||||
Add your provider's specific configuration fields to the `TelephonyConfigForm` interface:
|
||||
|
||||
```typescript
|
||||
interface TelephonyConfigForm {
|
||||
provider: string;
|
||||
// ... existing fields
|
||||
|
||||
// Your Provider Fields
|
||||
your_provider_api_key?: string;
|
||||
your_provider_secret?: string;
|
||||
}
|
||||
```
|
||||
|
||||
**B. Add to Dropdown**
|
||||
|
||||
Add your provider to the `Select` component options:
|
||||
|
||||
```tsx
|
||||
<SelectContent>
|
||||
<SelectItem value="twilio">Twilio</SelectItem>
|
||||
<SelectItem value="vonage">Vonage</SelectItem>
|
||||
<SelectItem value="your_provider">Your Provider</SelectItem>
|
||||
</SelectContent>
|
||||
```
|
||||
|
||||
**C. Add Form Fields**
|
||||
|
||||
Render your provider's fields conditionally:
|
||||
|
||||
```tsx
|
||||
{selectedProvider === "your_provider" && (
|
||||
<>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="your_provider_api_key">API Key</Label>
|
||||
<Input
|
||||
id="your_provider_api_key"
|
||||
{...register("your_provider_api_key", {
|
||||
required: selectedProvider === "your_provider"
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
{/* Add other fields similarly */}
|
||||
</>
|
||||
)}
|
||||
```
|
||||
|
||||
**D. Handle Submission**
|
||||
|
||||
Update the `onSubmit` function to format the request correctly:
|
||||
|
||||
```typescript
|
||||
// Inside onSubmit function
|
||||
if (data.provider === "your_provider") {
|
||||
requestBody = {
|
||||
provider: "your_provider",
|
||||
api_key: data.your_provider_api_key,
|
||||
// ... other fields
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Enable Call Button
|
||||
|
||||
Update `src/app/workflow/[workflowId]/components/WorkflowHeader.tsx` to enable the "Phone Call" button when your provider is configured.
|
||||
|
||||
```typescript
|
||||
// In handlePhoneCallClick function
|
||||
if (
|
||||
configResponse.error ||
|
||||
(!configResponse.data?.twilio &&
|
||||
!configResponse.data?.vonage &&
|
||||
!configResponse.data?.your_provider) // Add this check
|
||||
) {
|
||||
setConfigureDialogOpen(true);
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Update API Client
|
||||
|
||||
After updating the backend and frontend, regenerate the API client to ensure types are synced:
|
||||
|
||||
```bash
|
||||
npm run generate-client
|
||||
```
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
title: "Inbound Calling"
|
||||
description: "Configure inbound calling for Twilio, Vonage, and Cloudonix providers in Dograh AI"
|
||||
description: "Configure inbound calling for Twilio, Vonage, Plivo, Telnyx, Cloudonix, Vobiz, and Asterisk ARI providers in Dograh AI"
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Dograh AI supports inbound calling across all supported telephony providers. When someone calls your configured phone number, your voice agent automatically answers and handles the interaction. The inbound calling configuration in Dograh AI uses the same telephony settings as outbound calling.
|
||||
Dograh AI supports inbound calling across all supported telephony providers. When someone calls your configured phone number, your voice agent automatically answers and handles the interaction. Inbound and outbound calls share the same telephony configuration.
|
||||
|
||||
## Supported Providers for Inbound Calls
|
||||
|
||||
|
|
@ -13,6 +13,15 @@ Dograh AI supports inbound calling across all supported telephony providers. Whe
|
|||
<Card title="Twilio" href="/integrations/telephony/twilio">
|
||||
Industry-leading platform with robust inbound call handling
|
||||
</Card>
|
||||
<Card title="Vonage" href="/integrations/telephony/vonage">
|
||||
Application-level inbound routing with high-quality 16kHz audio
|
||||
</Card>
|
||||
<Card title="Plivo" href="/integrations/telephony/plivo">
|
||||
Application-level inbound routing on Plivo's global voice cloud
|
||||
</Card>
|
||||
<Card title="Telnyx" href="/integrations/telephony/telnyx">
|
||||
Application-level inbound via Telnyx Call Control API
|
||||
</Card>
|
||||
<Card title="Cloudonix" href="/integrations/telephony/cloudonix">
|
||||
SIP-based inbound calling with flexible trunk configuration
|
||||
</Card>
|
||||
|
|
@ -24,59 +33,67 @@ Dograh AI supports inbound calling across all supported telephony providers. Whe
|
|||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Note>
|
||||
**Vonage**: Inbound calling support is coming soon. Currently supports outbound calling only.
|
||||
</Note>
|
||||
|
||||
## How Inbound Calling Works
|
||||
|
||||
When someone calls your configured phone number:
|
||||
Dograh exposes a **single inbound webhook URL** for the whole org:
|
||||
|
||||
1. **Call Received**: The telephony provider receives the incoming call
|
||||
2. **Webhook Triggered**: The provider sends a webhook to Dograh AI
|
||||
3. **Agent Activated**: Dograh AI activates your configured voice agent workflow
|
||||
```
|
||||
https://api.dograh.com/api/v1/telephony/inbound/run
|
||||
```
|
||||
|
||||
When a call arrives:
|
||||
|
||||
1. **Call Received**: Your telephony provider receives the incoming call
|
||||
2. **Webhook Triggered**: The provider sends a webhook to `/inbound/run`
|
||||
3. **Org & Agent Resolved**: Dograh identifies the org from the webhook's account credentials, then looks up which agent should answer based on the called number's **Inbound workflow** assignment in your telephony configuration
|
||||
4. **Audio Streaming**: Real-time audio streams between caller and agent via WebSocket
|
||||
5. **Conversation Handled**: Your voice agent manages the entire conversation
|
||||
|
||||
You don't construct per-workflow URLs anymore — the routing is done by the called number's inbound workflow assignment in Dograh.
|
||||
|
||||
## Configuration in Dograh AI
|
||||
|
||||
Setting up inbound calling requires three simple steps:
|
||||
Setting up inbound calling takes three steps:
|
||||
|
||||
### Step 1: Configure Telephony Provider
|
||||
|
||||
The telephony configuration for inbound calling is **identical** to outbound calling. Follow the **Configuration** section in your provider's documentation page:
|
||||
The telephony configuration for inbound calling is **identical** to outbound calling. Add (or open) a configuration at **/telephony-configurations** following your provider's documentation:
|
||||
|
||||
- [Twilio Configuration](/integrations/telephony/twilio#configuration)
|
||||
- [Vonage Configuration](/integrations/telephony/vonage#configuration)
|
||||
- [Plivo Configuration](/integrations/telephony/plivo#configuration)
|
||||
- [Telnyx Configuration](/integrations/telephony/telnyx#configuration)
|
||||
- [Cloudonix Configuration](/integrations/telephony/cloudonix#configuration)
|
||||
- [Vobiz Configuration](/integrations/telephony/vobiz#configuration)
|
||||
- [Asterisk ARI Configuration](/integrations/telephony/asterisk-ari#configuration-in-dograh)
|
||||
|
||||
### Step 2: Get Your Workflow Webhook URL
|
||||
### Step 2: Assign an Inbound Workflow to the Phone Number
|
||||
|
||||
1. **Find Your Workflow ID**:
|
||||
- Navigate to your workflow page (e.g., `https://app.dograh.com/workflow/3`)
|
||||
- Note the workflow ID from the URL (in this example: `3`)
|
||||
1. Go to **/telephony-configurations** and open your configuration
|
||||
2. In the **Phone numbers** section, edit the number that should receive inbound calls
|
||||
3. Set its **Inbound workflow** to the agent that should answer
|
||||
4. Save
|
||||
|
||||
2. **Construct Webhook URL**:
|
||||
```
|
||||
https://api.dograh.com/api/v1/telephony/inbound/{workflow_id}
|
||||
```
|
||||
|
||||
For example, if your workflow ID is `3`:
|
||||
```
|
||||
https://api.dograh.com/api/v1/telephony/inbound/3
|
||||
```
|
||||
This is what tells Dograh which agent to run when a call comes in for that number.
|
||||
|
||||
<Note>
|
||||
If you're using a self-hosted Dograh instance, replace `api.dograh.com` with your own domain.
|
||||
</Note>
|
||||
### Step 3: Point Your Provider at `/inbound/run`
|
||||
|
||||
### Step 3: Configure Provider-Specific Inbound Settings
|
||||
Each provider needs its inbound webhook (Twilio Voice URL / Vonage Answer URL / etc.) set to the global Dograh endpoint:
|
||||
|
||||
Each telephony provider requires additional configuration to route incoming calls to your Dograh AI webhook. Follow the provider-specific inbound setup instructions:
|
||||
```
|
||||
https://api.dograh.com/api/v1/telephony/inbound/run
|
||||
```
|
||||
|
||||
<Note>
|
||||
If you're self-hosting Dograh, replace `api.dograh.com` with your own domain.
|
||||
</Note>
|
||||
|
||||
The exact place to set this varies by provider — follow the provider-specific instructions:
|
||||
|
||||
- [Twilio Inbound Setup](/integrations/telephony/twilio#inbound-calling-setup)
|
||||
- [Vonage Inbound Setup](/integrations/telephony/vonage#inbound-calling-setup)
|
||||
- [Plivo Inbound Setup](/integrations/telephony/plivo#inbound-calling-setup)
|
||||
- [Telnyx Inbound Setup](/integrations/telephony/telnyx#inbound-calling-setup)
|
||||
- [Cloudonix Inbound Setup](/integrations/telephony/cloudonix#inbound-calling-setup)
|
||||
- [Vobiz Inbound Setup](/integrations/telephony/vobiz#inbound-calling-setup)
|
||||
- [Asterisk ARI Inbound Setup](/integrations/telephony/asterisk-ari#inbound-calling)
|
||||
|
|
@ -114,8 +131,8 @@ After completing both the Dograh AI configuration and provider-specific setup:
|
|||
|
||||
<Accordion title="Workflow not found error">
|
||||
- **Error**: "Workflow not found"
|
||||
- **Solution**: Verify the workflow ID in your webhook URL is correct and the workflow exists in your dashboard
|
||||
- Double-check the webhook URL format: `https://api.dograh.com/api/v1/telephony/inbound/{workflow_id}`
|
||||
- **Solution**: Open the called number in **/telephony-configurations** and confirm an **Inbound workflow** is assigned. Without an assignment, Dograh has no agent to route the call to.
|
||||
- Verify the assigned workflow still exists in your dashboard
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Account validation failed">
|
||||
|
|
@ -126,8 +143,8 @@ After completing both the Dograh AI configuration and provider-specific setup:
|
|||
|
||||
<Accordion title="Phone number not configured">
|
||||
- **Error**: "Phone number not configured: This number is not set up for inbound calls"
|
||||
- **Solution**: Add this phone number to your telephony configuration in Dograh AI
|
||||
- Ensure the phone number is properly linked to your provider account
|
||||
- **Solution**: Add this phone number under **Phone numbers** in your telephony configuration at **/telephony-configurations**
|
||||
- Ensure the phone number is also linked to your provider account
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Signature validation failed">
|
||||
|
|
@ -162,12 +179,11 @@ After completing both the Dograh AI configuration and provider-specific setup:
|
|||
- **Single Configuration**: Use the same telephony configuration for both inbound and outbound calls
|
||||
- **Testing**: Always test inbound calling after configuration changes
|
||||
- **Monitoring**: Monitor both Dograh AI logs and provider dashboards for call analytics
|
||||
- **Backup Numbers**: Configure multiple phone numbers for redundancy
|
||||
- **Security**: Ensure webhook signature verification is enabled for security
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Choose your telephony provider and complete the basic configuration
|
||||
2. Follow the provider-specific setup instructions (to be detailed)
|
||||
3. Test your inbound calling setup
|
||||
4. Configure your voice agent workflow for optimal caller experience
|
||||
2. Follow the provider-specific setup instructions
|
||||
3. Assign an inbound workflow to each phone number that should accept calls
|
||||
4. Test your inbound calling setup
|
||||
|
|
@ -5,7 +5,7 @@ description: "Connect voice agents with telephony providers for inbound and outb
|
|||
|
||||
## Overview
|
||||
|
||||
Dograh AI's telephony integration system provides a unified interface for connecting with various telephony providers. This abstraction layer allows you to easily switch between providers without changing your application logic.
|
||||
Dograh AI's telephony integration system provides a unified interface for connecting with various telephony providers. The same configuration powers both outbound calls (initiated from Dograh) and inbound calls (received on a phone number you own).
|
||||
|
||||
## Supported Providers
|
||||
|
||||
|
|
@ -16,98 +16,70 @@ Dograh AI's telephony integration system provides a unified interface for connec
|
|||
<Card title="Vonage" href="/integrations/telephony/vonage">
|
||||
High-quality voice with 16kHz audio and excellent international coverage
|
||||
</Card>
|
||||
<Card title="Plivo" href="/integrations/telephony/plivo">
|
||||
Cloud communications platform with programmable voice and global PSTN reach
|
||||
</Card>
|
||||
<Card title="Cloudonix" href="/integrations/telephony/cloudonix">
|
||||
SIP-based telephony with flexible trunk configuration
|
||||
</Card>
|
||||
<Card title="Vobiz" href="/integrations/telephony/vobiz">
|
||||
Cloud-based telephony with global reach and competitive pricing
|
||||
</Card>
|
||||
<Card title="Asterisk ARI" href="/integrations/telephony/asterisk-ari">
|
||||
Connect to your own Asterisk PBX via the Asterisk REST Interface
|
||||
</Card>
|
||||
<Card title="Custom Provider" href="/integrations/telephony/custom">
|
||||
Build your own telephony provider integration
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Architecture
|
||||
|
||||
The telephony integration system uses a provider abstraction pattern that ensures consistency across different services:
|
||||
|
||||
```python
|
||||
# All providers implement this interface
|
||||
class TelephonyProvider(ABC):
|
||||
async def initiate_call(to_number: str, webhook_url: str, workflow_run_id: Optional[int] = None, **kwargs) -> CallInitiationResult
|
||||
async def get_call_status(call_id: str) -> Dict[str, Any]
|
||||
async def get_available_phone_numbers() -> List[str]
|
||||
def validate_config() -> bool
|
||||
async def verify_webhook_signature(url: str, params: Dict, signature: str) -> bool
|
||||
async def get_webhook_response(workflow_id: int, user_id: int, workflow_run_id: int) -> str
|
||||
async def get_call_cost(call_id: str) -> Dict[str, Any]
|
||||
def parse_status_callback(data: Dict[str, Any]) -> Dict[str, Any]
|
||||
async def handle_websocket(websocket: WebSocket, workflow_id: int, user_id: int, workflow_run_id: int) -> None
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Dograh AI uses database configuration for all telephony providers. Configure providers through the web interface:
|
||||
All telephony providers are configured from a single page in Dograh:
|
||||
|
||||
1. Navigate to **Workflow** → **Phone Call** → **Configure Telephony**
|
||||
2. Select your provider (Twilio or Vonage)
|
||||
3. Watch the provider-specific video tutorial for setup guidance
|
||||
4. Enter your credentials
|
||||
5. Save configuration
|
||||
6. Test with a phone call
|
||||
1. Navigate to **/telephony-configurations** and click **Add configuration**
|
||||
2. Select your provider
|
||||
3. Enter your credentials and save
|
||||
4. Open the new configuration and add at least one **phone number**
|
||||
5. (Optional) Assign an **Inbound workflow** to a phone number to enable inbound calling
|
||||
|
||||
<iframe
|
||||
className="w-full aspect-video rounded-xl"
|
||||
src="https://www.tella.tv/video/setting-up-telephony-configurations-in-dobra-f6zj/embed"
|
||||
title="Setting up telephony configurations in Dograh"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
|
||||
A single org can hold multiple configurations (for example, separate Twilio sub-accounts) and multiple phone numbers per configuration. Mark one configuration as the **default outbound** to use it for test calls and campaigns by default.
|
||||
|
||||
## Common Features
|
||||
|
||||
The telephony integration in Dograh AI supports:
|
||||
|
||||
- **Outbound Calls**: Initiate calls to any phone number
|
||||
- **Outbound Calls**: Initiate calls to any phone number from a workflow or campaign
|
||||
- **Inbound Calls**: Route incoming calls to the right voice agent — see the [Inbound Calling guide](/integrations/telephony/inbound)
|
||||
- **Call Transfer**: Transfer an in-progress call to a human or another number (provider-dependent)
|
||||
- **Call Status Tracking**: Monitor call lifecycle events (initiated, ringing, answered, completed, failed)
|
||||
- **WebSocket Streaming**: Real-time audio streaming for voice agents
|
||||
- **Webhook Authentication**: Secure webhook signature verification
|
||||
- **WebSocket Audio Streaming**: Real-time, bidirectional audio between caller and agent
|
||||
- **Webhook Signature Verification**: Inbound webhooks are verified against the matched configuration's credentials
|
||||
|
||||
## Code Usage
|
||||
## Inbound Calling
|
||||
|
||||
Here's how to use the telephony provider in your code:
|
||||
Inbound calls use a **single org-wide webhook URL**:
|
||||
|
||||
```python
|
||||
from api.services.telephony.factory import get_telephony_provider
|
||||
|
||||
# Get provider based on organization configuration
|
||||
provider = await get_telephony_provider(organization_id)
|
||||
|
||||
# Initiate a call
|
||||
result = await provider.initiate_call(
|
||||
to_number="+1234567890",
|
||||
webhook_url="https://your-domain.com/webhook",
|
||||
workflow_run_id=123
|
||||
)
|
||||
|
||||
# Check call status
|
||||
status = await provider.get_call_status(result.call_id)
|
||||
|
||||
# Get call cost after completion
|
||||
cost_info = await provider.get_call_cost(result.call_id)
|
||||
```
|
||||
https://api.dograh.com/api/v1/telephony/inbound/run
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
The telephony system exposes these unified endpoints:
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|---------|-------------|
|
||||
| `/api/v1/telephony/initiate-call` | POST | Start an outbound call |
|
||||
| `/api/v1/telephony/twilio/status-callback/{id}` | POST | Receive Twilio status updates |
|
||||
| `/api/v1/telephony/vonage/events/{id}` | POST | Receive Vonage event updates |
|
||||
| `/api/v1/telephony/twiml` | POST | Handle Twilio webhook (TwiML) |
|
||||
| `/api/v1/telephony/ncco` | GET | Handle Vonage webhook (NCCO) |
|
||||
| `/api/v1/telephony/ws/{workflow_id}/{user_id}/{workflow_run_id}` | WebSocket | Real-time audio streaming |
|
||||
|
||||
## Implementation Status
|
||||
|
||||
- **Twilio**: ✅ Fully implemented and tested
|
||||
- **Vonage**: ✅ Fully implemented with 16kHz audio support
|
||||
- **Custom Providers**: The abstraction layer supports adding new providers by implementing the `TelephonyProvider` interface
|
||||
Dograh resolves the org from the webhook's account credentials and the agent from the called number's **Inbound workflow** assignment. See [Inbound Calling](/integrations/telephony/inbound) for the full setup.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Calls not connecting">
|
||||
- Verify credentials are correctly configured
|
||||
- Check phone number format (must include country code)
|
||||
- Check phone number format (E.164 with country code, e.g. `+1234567890`)
|
||||
- Ensure webhook URLs are publicly accessible
|
||||
- Review provider-specific error logs
|
||||
</Accordion>
|
||||
|
|
@ -116,14 +88,11 @@ The telephony system exposes these unified endpoints:
|
|||
- Check network bandwidth and latency
|
||||
- Verify audio codec compatibility
|
||||
- Review WebSocket connection stability
|
||||
- Ensure proper audio format:
|
||||
- Twilio: 8kHz μ-law (MULAW)
|
||||
- Vonage: 16kHz Linear PCM
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Webhook signature validation failing">
|
||||
- Confirm auth tokens match between provider and configuration
|
||||
- Verify webhook URL matches exactly (including parameters)
|
||||
- Confirm auth tokens / API secrets match between provider and Dograh configuration
|
||||
- Verify webhook URL matches exactly (including the `/inbound/run` path)
|
||||
- Check for proxy or load balancer modifications
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
|
@ -131,5 +100,5 @@ The telephony system exposes these unified endpoints:
|
|||
## Next Steps
|
||||
|
||||
- [Set up your first telephony provider](/integrations/telephony/twilio)
|
||||
- [Configure inbound calling](/integrations/telephony/inbound)
|
||||
- [Build a custom provider integration](/integrations/telephony/custom)
|
||||
- [Configure webhooks and callbacks](/integrations/telephony/webhooks)
|
||||
138
docs/integrations/telephony/plivo.mdx
Normal file
138
docs/integrations/telephony/plivo.mdx
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
---
|
||||
title: "Plivo Integration"
|
||||
description: "Configure Plivo for voice communication in Dograh AI"
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Plivo is a cloud communications platform that provides global voice and messaging APIs. Dograh AI's Plivo integration uses Plivo's XML and WebSocket streaming to power your voice agents.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before setting up Plivo integration, you'll need:
|
||||
|
||||
- A [Plivo account](https://www.plivo.com/)
|
||||
- Auth ID and Auth Token from your Plivo Console
|
||||
- A Plivo **Application** with Voice capability (used for inbound webhook routing)
|
||||
- At least one Plivo phone number
|
||||
- Dograh AI instance running and accessible
|
||||
|
||||
## Configuration
|
||||
|
||||
### Step 1: Get Plivo Credentials
|
||||
|
||||
1. Log in to your [Plivo Console](https://console.plivo.com/)
|
||||
2. Find your **Auth ID** and **Auth Token** on the dashboard
|
||||
3. Navigate to **Voice** → **Applications** and create (or open) the application you'll use with Dograh
|
||||
4. Copy the **Application ID** (a UUID) — you'll attach numbers to this app and Dograh will manage its `answer_url`
|
||||
5. Navigate to **Phone Numbers** → **Your Numbers** and copy the numbers you plan to use
|
||||
|
||||
### Step 2: Configure in Dograh AI
|
||||
|
||||
1. Navigate to **/telephony-configurations** and click **Add configuration**
|
||||
2. Select **Plivo** as your provider
|
||||
3. Enter your credentials:
|
||||
- Auth ID
|
||||
- Auth Token
|
||||
- Application ID
|
||||
4. Click **Save Configuration**
|
||||
5. Open the configuration you just created and add at least one **phone number** (with country code in E.164 format, e.g. `+1234567890`). The default caller ID is used for outbound calls.
|
||||
|
||||
### Step 3: Test Your Configuration
|
||||
|
||||
1. Create a test workflow
|
||||
2. Click "Call" to verify connection
|
||||
3. Check call logs for successful connection
|
||||
|
||||
## Inbound Calling Setup
|
||||
|
||||
Plivo numbers don't carry an `answer_url` directly — the URL lives on a Plivo **Application**, and each number is linked to one application. **When you save an inbound workflow on a phone number, Dograh automatically pushes the webhook URL to your Plivo Application's `answer_url`** (provided the credentials are correct). You don't need to set the webhook by hand.
|
||||
|
||||
### Step 1: Link the Phone Number to Your Plivo Application
|
||||
|
||||
1. Go to **Phone Numbers** → **Your Numbers** in the [Plivo Console](https://console.plivo.com/)
|
||||
2. Open the number you want to use for inbound calls
|
||||
3. Set its **Application** to the same application whose ID you configured in Dograh
|
||||
4. Save
|
||||
|
||||
### Step 2: Assign an Inbound Workflow to the Phone Number in Dograh
|
||||
|
||||
1. Go to **/telephony-configurations** and open your Plivo configuration
|
||||
2. In the **Phone numbers** section, edit the number that should receive inbound calls
|
||||
3. Set its **Inbound workflow** to the agent that should answer
|
||||
4. Save
|
||||
|
||||
### Step 3: Verify the Answer URL on the Plivo Application
|
||||
|
||||
1. Open your Plivo Application in the [Plivo Console](https://console.plivo.com/) under **Voice** → **Applications**
|
||||
2. Confirm:
|
||||
- **Answer URL** is set to: `https://api.dograh.com/api/v1/telephony/inbound/run`
|
||||
- **Answer Method** is `POST`
|
||||
|
||||
<Note>
|
||||
Dograh pushed this URL automatically when you saved the inbound workflow
|
||||
in Step 2. The same URL is shared across every number linked to that
|
||||
application — Dograh routes each inbound call to the right agent based
|
||||
on the called number's inbound workflow assignment. If the field is
|
||||
empty, shows a different URL, or Dograh surfaced a sync warning on
|
||||
save, the auto-push failed — most often because the Auth ID/Token or
|
||||
Application ID in Dograh is incorrect. Paste the URL into the field
|
||||
yourself, set the method to `POST`, and save the application. On
|
||||
self-hosted Dograh, replace `api.dograh.com` with your backend domain.
|
||||
</Note>
|
||||
|
||||
### Step 4: Verify Setup
|
||||
|
||||
- Ensure your Dograh AI instance is publicly accessible
|
||||
- Verify any firewalls allow Plivo's IP ranges
|
||||
|
||||
### Test Inbound Calling
|
||||
|
||||
1. Call your configured Plivo phone number from another phone
|
||||
2. Verify your Dograh AI voice agent answers and responds
|
||||
3. Check call logs in both Dograh AI dashboard and Plivo Console
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Invalid phone number error">
|
||||
Ensure phone numbers include country code in E.164 format: `+1234567890`
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Authentication failed">
|
||||
- Verify Auth ID and Auth Token are correct - Check for extra spaces in
|
||||
credentials - Ensure credentials haven't been regenerated in Plivo Console
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Webhook signature validation failing">
|
||||
- Confirm your Auth Token matches exactly - Verify the webhook URL matches
|
||||
what Plivo sends - Check if you're behind a proxy that modifies requests
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="No audio on calls">
|
||||
- Verify WebSocket connection is established - Check firewall rules for
|
||||
WebSocket traffic - Ensure audio pipeline is configured correctly
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Inbound calls go to voicemail or aren't answered">
|
||||
- Verify the phone number is linked to the same Plivo Application whose
|
||||
ID you configured in Dograh - Confirm the called number exists in your
|
||||
Dograh telephony configuration and has an **Inbound workflow** assigned
|
||||
- After assigning the inbound workflow, confirm Dograh successfully
|
||||
updated the application's `answer_url` (no warning shown on save) -
|
||||
Verify Dograh AI instance is running and responding
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Voice agent doesn't respond to inbound calls">
|
||||
- Confirm the phone number has an **Inbound workflow** assigned in
|
||||
/telephony-configurations - Check webhook signature validation is working
|
||||
(Auth Token in Dograh matches Plivo Console) - Verify WebSocket connection
|
||||
establishes successfully - Review call logs for error messages
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Test your configuration with a single call before running campaigns
|
||||
- Monitor Plivo Console for usage and billing
|
||||
- Use a dedicated Plivo Application for Dograh so the shared `answer_url` doesn't conflict with other systems
|
||||
134
docs/integrations/telephony/telnyx.mdx
Normal file
134
docs/integrations/telephony/telnyx.mdx
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
---
|
||||
title: "Telnyx Integration"
|
||||
description: "Configure Telnyx for voice communication in Dograh AI"
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Telnyx is a cloud communications platform that provides programmable voice via its Call Control API. Dograh AI's Telnyx integration uses Call Control plus WebSocket media streaming to power your voice agents.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before setting up Telnyx integration, you'll need:
|
||||
|
||||
- A [Telnyx account](https://telnyx.com/)
|
||||
- An **API Key** from the Telnyx Mission Control Portal
|
||||
- A **Call Control Application** (its `connection_id` is what Dograh stores)
|
||||
- At least one Telnyx phone number assigned to that Call Control Application
|
||||
- Dograh AI instance running and accessible
|
||||
|
||||
## Configuration
|
||||
|
||||
### Step 1: Get Telnyx Credentials
|
||||
|
||||
1. Log in to the [Telnyx Mission Control Portal](https://portal.telnyx.com/)
|
||||
2. Navigate to **API Keys** and create (or copy) an API Key
|
||||
3. Navigate to **Call Control** → **Applications** and create (or open) the application you'll use with Dograh
|
||||
4. Copy the application's **Connection ID** (Call Control App ID)
|
||||
5. Navigate to **Numbers** → **My Numbers** and assign your phone numbers to that Call Control Application
|
||||
|
||||
### Step 2: Configure in Dograh AI
|
||||
|
||||
1. Navigate to **/telephony-configurations** and click **Add configuration**
|
||||
2. Select **Telnyx** as your provider
|
||||
3. Enter your credentials:
|
||||
- API Key
|
||||
- Call Control App ID (Connection ID)
|
||||
4. Click **Save Configuration**
|
||||
5. Open the configuration you just created and add at least one **phone number** (with country code in E.164 format, e.g. `+1234567890`). The default caller ID is used for outbound calls.
|
||||
|
||||
### Step 3: Test Your Configuration
|
||||
|
||||
1. Create a test workflow
|
||||
2. Click "Call" to verify connection
|
||||
3. Check call logs for successful connection
|
||||
|
||||
## Inbound Calling Setup
|
||||
|
||||
Telnyx delivers inbound webhooks at the **Call Control Application** level — the webhook URL is configured once on the application, and applies to every number assigned to it. **When you save an inbound workflow on a phone number, Dograh automatically pushes the webhook URL to your Call Control Application's `webhook_event_url`** (provided the credentials are correct).
|
||||
|
||||
### Step 1: Assign an Inbound Workflow to the Phone Number
|
||||
|
||||
1. Go to **/telephony-configurations** and open your Telnyx configuration
|
||||
2. In the **Phone numbers** section, edit the number that should receive inbound calls
|
||||
3. Set its **Inbound workflow** to the agent that should answer
|
||||
4. Save
|
||||
|
||||
### Step 2: Verify the Webhook URL on the Call Control Application
|
||||
|
||||
1. Go to **Call Control** → **Applications** in the Telnyx Portal
|
||||
2. Open the application whose Connection ID you configured in Dograh
|
||||
3. In **Webhook Settings**, confirm:
|
||||
- **Webhook URL** is set to: `https://api.dograh.com/api/v1/telephony/inbound/run`
|
||||
- **HTTP Method** is `POST`
|
||||
4. Make sure the phone numbers you want to use for inbound are assigned to this application
|
||||
|
||||
<Note>
|
||||
Dograh pushed this URL automatically when you saved the inbound workflow
|
||||
in Step 1. The same URL is shared across every number on the Call
|
||||
Control Application — Dograh matches the inbound call to the right
|
||||
agent using the called number's inbound workflow assignment. If the
|
||||
field is empty, shows a different URL, or Dograh surfaced a sync
|
||||
warning on save, the auto-push failed — most often because the API
|
||||
Key or Connection ID in Dograh is incorrect. Paste the URL into the
|
||||
field yourself, set the method to `POST`, and save. On self-hosted
|
||||
Dograh, replace `api.dograh.com` with your backend domain.
|
||||
</Note>
|
||||
|
||||
### Step 3: Verify Setup
|
||||
|
||||
- Ensure your Dograh AI instance is publicly accessible
|
||||
- Verify any firewalls allow Telnyx's IP ranges
|
||||
|
||||
### Test Inbound Calling
|
||||
|
||||
1. Call your configured Telnyx phone number from another phone
|
||||
2. Verify your Dograh AI voice agent answers and responds
|
||||
3. Check call logs in both Dograh AI dashboard and Telnyx Portal
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Invalid phone number error">
|
||||
Ensure phone numbers include country code in E.164 format: `+1234567890`
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Authentication failed">
|
||||
- Verify the API Key is correct and active - Check for extra spaces in the
|
||||
key - Ensure the key hasn't been revoked in the Telnyx Portal
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Webhook signature validation failing">
|
||||
- Telnyx signs webhooks with Ed25519 - confirm the public key on the
|
||||
application hasn't changed - Verify the webhook URL matches what Telnyx
|
||||
sends - Check if you're behind a proxy that modifies request bodies
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="No audio on calls">
|
||||
- Verify WebSocket connection is established - Check firewall rules for
|
||||
WebSocket traffic - Ensure audio pipeline is configured correctly
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Inbound calls aren't answered">
|
||||
- Verify the Call Control Application's webhook URL is set to
|
||||
`https://api.dograh.com/api/v1/telephony/inbound/run` - Ensure the webhook
|
||||
URL is publicly accessible from the internet - Confirm the called number
|
||||
is assigned to the same Call Control Application whose Connection ID is
|
||||
configured in Dograh - Confirm the called number exists in your Dograh
|
||||
telephony configuration and has an **Inbound workflow** assigned - Verify
|
||||
Dograh AI instance is running and responding
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Voice agent doesn't respond to inbound calls">
|
||||
- Confirm the phone number has an **Inbound workflow** assigned in
|
||||
/telephony-configurations - Verify the API Key matches the one stored in
|
||||
your Dograh telephony configuration - Verify WebSocket connection
|
||||
establishes successfully - Review call logs for error messages
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Test your configuration with a single call before running campaigns
|
||||
- Monitor the Telnyx Portal for usage and billing
|
||||
- Use a dedicated Call Control Application for Dograh so the shared webhook URL doesn't conflict with other systems
|
||||
|
|
@ -16,18 +16,6 @@ Before setting up Twilio integration, you'll need:
|
|||
- At least one Twilio phone number
|
||||
- Dograh AI instance running and accessible
|
||||
|
||||
## Video Tutorial
|
||||
|
||||
Watch this step-by-step guide to set up Twilio with Dograh AI:
|
||||
|
||||
<iframe
|
||||
className="w-full aspect-video rounded-xl"
|
||||
src="https://www.youtube.com/embed/jlPD4CSJHHI"
|
||||
title="Dograh Twilio Setup"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
|
||||
## Configuration
|
||||
|
||||
### Step 1: Get Twilio Credentials
|
||||
|
|
@ -39,40 +27,47 @@ Watch this step-by-step guide to set up Twilio with Dograh AI:
|
|||
|
||||
### Step 2: Configure in Dograh AI
|
||||
|
||||
1. Navigate to **Workflow** → **Phone Call** → **Configure Telephony**
|
||||
2. Watch the Twilio setup video tutorial above for detailed guidance
|
||||
3. Select **Twilio** as your provider
|
||||
4. Enter your credentials:
|
||||
1. Navigate to **/telephony-configurations** and click **Add configuration**
|
||||
2. Select **Twilio** as your provider
|
||||
3. Enter your credentials:
|
||||
- Account SID
|
||||
- Auth Token
|
||||
- From Phone Number (with country code, e.g., +1234567890)
|
||||
5. Click **Save Configuration**
|
||||
4. Click **Save Configuration**
|
||||
5. Open the configuration you just created and add at least one **phone number** (with country code in E.164 format, e.g. `+1234567890`). The default caller ID is used for outbound calls.
|
||||
|
||||
### Step 3: Test Your Configuration
|
||||
|
||||
1. Create a test workflow
|
||||
2. Click "Test Call" to verify connection
|
||||
2. Click "Call" to verify connection
|
||||
3. Check call logs for successful connection
|
||||
|
||||
## Inbound Calling Setup
|
||||
|
||||
To enable inbound calling with Twilio:
|
||||
Inbound routing is driven by the phone number itself — there is a **single webhook URL** for the entire org, and Dograh resolves which agent to run from the called number's assigned inbound workflow. **When you save an inbound workflow on a phone number, Dograh automatically pushes the webhook URL to that number's `VoiceUrl` in your Twilio account** (provided the credentials are correct and the number belongs to that account).
|
||||
|
||||
1. **Complete Telephony Configuration**: Use the same [Configuration](#configuration) steps above
|
||||
2. **Get Your Workflow Webhook URL**: Find your workflow ID and construct the webhook URL as: `https://api.dograh.com/api/v1/telephony/inbound/{workflow_id}`
|
||||
### Step 1: Assign an Inbound Workflow to the Phone Number
|
||||
|
||||
### Configure Webhook in Twilio Console
|
||||
1. Go to **/telephony-configurations** and open your Twilio configuration
|
||||
2. In the **Phone numbers** section, edit the number that should receive inbound calls
|
||||
3. Set its **Inbound workflow** to the agent that should answer
|
||||
4. Save
|
||||
|
||||
1. **Configure Phone Number Webhook**:
|
||||
- Go to **Phone Numbers** → **Manage** → **Active Numbers** in Twilio Console
|
||||
- Click on the phone number you want to use for inbound calls
|
||||
- In the "Voice Configuration" section:
|
||||
- Set **Webhook** to: `https://api.dograh.com/api/v1/telephony/inbound/{workflow_id}`
|
||||
- Set **HTTP Method** to: `POST`
|
||||
- Click **Save Configuration**
|
||||
### Step 2: Verify the Webhook URL in Twilio Console
|
||||
|
||||
1. Go to **Phone Numbers** → **Manage** → **Active Numbers** in Twilio Console
|
||||
2. Click the phone number you assigned an inbound workflow to in Step 1
|
||||
3. In the **Voice Configuration** section, confirm:
|
||||
- **Webhook** is set to: `https://api.dograh.com/api/v1/telephony/inbound/run`
|
||||
- **HTTP Method** is `POST`
|
||||
|
||||
<Note>
|
||||
Replace `{workflow_id}` with your actual workflow ID. If using self-hosted Dograh, replace `api.dograh.com` with your domain.
|
||||
Dograh pushed this URL automatically when you saved the inbound workflow
|
||||
in Step 1. If the field is empty, shows a different URL, or Dograh
|
||||
surfaced a sync warning, the auto-push failed — most often because the
|
||||
credentials are incorrect or the number isn't owned by this Twilio
|
||||
account. Paste the URL into the field yourself, set the method to
|
||||
`POST`, and click **Save Configuration**. On self-hosted Dograh,
|
||||
replace `api.dograh.com` with your backend domain.
|
||||
</Note>
|
||||
|
||||
<img
|
||||
|
|
@ -86,9 +81,10 @@ To enable inbound calling with Twilio:
|
|||
alt="Twilio phone number voice configuration showing webhook URL setup for inbound calls"
|
||||
/>
|
||||
|
||||
2. **Verify Setup**:
|
||||
- Ensure your Dograh AI instance is publicly accessible
|
||||
- Verify any firewalls allow Twilio's IP ranges
|
||||
### Step 3: Verify Setup
|
||||
|
||||
- Ensure your Dograh AI instance is publicly accessible
|
||||
- Verify any firewalls allow Twilio's IP ranges
|
||||
|
||||
### Test Inbound Calling
|
||||
|
||||
|
|
@ -102,42 +98,39 @@ To enable inbound calling with Twilio:
|
|||
<Accordion title="Invalid phone number error">
|
||||
Ensure phone numbers include country code in E.164 format: `+1234567890`
|
||||
</Accordion>
|
||||
|
||||
|
||||
<Accordion title="Authentication failed">
|
||||
- Verify Account SID and Auth Token are correct
|
||||
- Check for extra spaces in credentials
|
||||
- Ensure credentials haven't been regenerated in Twilio Console
|
||||
- Verify Account SID and Auth Token are correct - Check for extra spaces in
|
||||
credentials - Ensure credentials haven't been regenerated in Twilio Console
|
||||
</Accordion>
|
||||
|
||||
|
||||
<Accordion title="Webhook signature validation failing">
|
||||
- Confirm your Auth Token matches exactly
|
||||
- Verify the webhook URL matches what Twilio sends
|
||||
- Check if you're behind a proxy that modifies requests
|
||||
- Confirm your Auth Token matches exactly - Verify the webhook URL matches
|
||||
what Twilio sends - Check if you're behind a proxy that modifies requests
|
||||
</Accordion>
|
||||
|
||||
|
||||
<Accordion title="No audio on calls">
|
||||
- Verify WebSocket connection is established
|
||||
- Check firewall rules for WebSocket traffic
|
||||
- Ensure audio pipeline is configured correctly
|
||||
- Verify WebSocket connection is established - Check firewall rules for
|
||||
WebSocket traffic - Ensure audio pipeline is configured correctly
|
||||
</Accordion>
|
||||
|
||||
|
||||
<Accordion title="Inbound calls go to voicemail">
|
||||
- Verify webhook URL is correctly configured in Twilio Console
|
||||
- Ensure webhook URL is publicly accessible from internet
|
||||
- Check that phone number is properly linked to webhook
|
||||
- Verify Dograh AI instance is running and responding
|
||||
- Verify the Twilio number's webhook is set to
|
||||
`https://api.dograh.com/api/v1/telephony/inbound/run` - Ensure the webhook
|
||||
URL is publicly accessible from the internet - Confirm the called number
|
||||
exists in your Dograh telephony configuration and has an **Inbound
|
||||
workflow** assigned - Verify Dograh AI instance is running and responding
|
||||
</Accordion>
|
||||
|
||||
|
||||
<Accordion title="Voice agent doesn't respond to inbound calls">
|
||||
- Confirm voice agent workflow is properly configured
|
||||
- Check webhook signature validation is working
|
||||
- Verify WebSocket connection establishes successfully
|
||||
- Review call logs for error messages
|
||||
- Confirm the phone number has an **Inbound workflow** assigned in
|
||||
/telephony-configurations - Check webhook signature validation is working
|
||||
(Auth Token in Dograh matches Twilio Console) - Verify WebSocket connection
|
||||
establishes successfully - Review call logs for error messages
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Store credentials securely in the database
|
||||
- Test your configuration with a single call before running campaigns
|
||||
- Monitor Twilio Console for usage and billing
|
||||
- Monitor Twilio Console for usage and billing
|
||||
|
|
|
|||
|
|
@ -12,109 +12,91 @@ Vobiz is a cloud-based telephony service provider that offers global reach with
|
|||
Before setting up Vobiz integration, you'll need:
|
||||
|
||||
- A [Vobiz account](https://vobiz.com)
|
||||
- Auth ID from your Vobiz dashboard
|
||||
- Auth Token generated for your account
|
||||
- At least one configured phone number in your Vobiz account
|
||||
- Auth ID and Auth Token from your Vobiz dashboard
|
||||
- A Vobiz **Application** (used for inbound webhook routing)
|
||||
- At least one Vobiz phone number
|
||||
- Dograh AI instance running and accessible
|
||||
|
||||
## Configuration
|
||||
|
||||
### Step 1: Get Vobiz Credentials
|
||||
|
||||
1. Sign up for a Vobiz account
|
||||
2. Log in to your Vobiz dashboard
|
||||
3. Navigate to your account settings to find your **Auth ID**
|
||||
4. Generate an **Auth Token** for API access
|
||||
5. Configure phone numbers in your Vobiz account for outbound calling
|
||||
1. Log in to your Vobiz dashboard
|
||||
2. Find your **Auth ID** and generate an **Auth Token** for API access
|
||||
3. Navigate to the **Applications** section and create (or open) the application you'll use with Dograh
|
||||
4. Copy the **Application ID** — Dograh will manage its `answer_url`
|
||||
5. Navigate to **Phone Numbers** and copy the numbers you plan to use
|
||||
|
||||
### Step 2: Configure in Dograh AI
|
||||
|
||||
1. Navigate to **Workflow** → **Phone Call** → **Configure Telephony**
|
||||
1. Navigate to **/telephony-configurations** and click **Add configuration**
|
||||
2. Select **Vobiz** as your provider
|
||||
3. Enter your credentials:
|
||||
- Auth ID
|
||||
- Auth Token
|
||||
- From Phone Number (with country code, e.g., +1234567890)
|
||||
- Application ID
|
||||
4. Click **Save Configuration**
|
||||
|
||||
<Note>
|
||||
Vobiz provides cloud-based telephony services with global reach and competitive pricing.
|
||||
</Note>
|
||||
5. Open the configuration you just created and add at least one **phone number** (with country code in E.164 format, e.g. `+1234567890`). The default caller ID is used for outbound calls.
|
||||
|
||||
### Step 3: Test Your Configuration
|
||||
|
||||
1. Create a test workflow
|
||||
2. Click "Test Call" to verify connection
|
||||
2. Click "Call" to verify connection
|
||||
3. Check call logs for successful connection
|
||||
|
||||
## Inbound Calling Setup
|
||||
|
||||
To enable inbound calling with Vobiz:
|
||||
Vobiz numbers don't carry an `answer_url` directly — the URL lives on a Vobiz **Application**, and each number is linked to one application. **When you save an inbound workflow on a phone number, Dograh automatically pushes the webhook URL to your Vobiz Application's `answer_url`** (provided the credentials are correct).
|
||||
|
||||
1. **Complete Telephony Configuration**: Use the same [Configuration](#configuration) steps above
|
||||
2. **Get Your Workflow Webhook URL**: Find your workflow ID and construct the webhook URL as: `https://api.dograh.com/api/v1/telephony/inbound/{workflow_id}`
|
||||
### Step 1: Link the Phone Number to Your Vobiz Application
|
||||
|
||||
### Configure Application in Vobiz Console
|
||||
|
||||
Vobiz requires creating an XML application to handle inbound calls. Follow these steps:
|
||||
|
||||
1. **Navigate to Applications**:
|
||||
- Log in to your Vobiz Console
|
||||
- Navigate to the **Applications** section
|
||||
1. Log in to your Vobiz Console and open the **Applications** section
|
||||
2. Edit the application whose ID you configured in Dograh
|
||||
3. Attach the phone number you want to use for inbound calls
|
||||
4. Save
|
||||
|
||||
<img
|
||||
className="block dark:hidden"
|
||||
src="/images/vobiz-inbound-config-1.png"
|
||||
alt="Vobiz console showing Applications section navigation"
|
||||
src="/images/vobiz-inbound-config-3.png"
|
||||
alt="Vobiz application showing phone number attachment interface"
|
||||
/>
|
||||
<img
|
||||
className="hidden dark:block"
|
||||
src="/images/vobiz-inbound-config-1.png"
|
||||
alt="Vobiz console showing Applications section navigation"
|
||||
src="/images/vobiz-inbound-config-3.png"
|
||||
alt="Vobiz application showing phone number attachment interface"
|
||||
/>
|
||||
|
||||
2. **Create New Application**:
|
||||
- Click **Create New Application**
|
||||
- Configure the XML application with the following URLs:
|
||||
- **Answer URL**: `https://api.dograh.com/api/v1/telephony/inbound/{workflow_id}`
|
||||
- **Hangup URL**: `https://api.dograh.com/api/v1/telephony/vobiz/hangup-callback/workflow/{workflow_id}`
|
||||
- **Fallback Answer URL**: `https://api.dograh.com/api/v1/telephony/inbound/fallback`
|
||||
- Save the application
|
||||
### Step 2: Assign an Inbound Workflow to the Phone Number in Dograh
|
||||
|
||||
1. Go to **/telephony-configurations** and open your Vobiz configuration
|
||||
2. In the **Phone numbers** section, edit the number that should receive inbound calls
|
||||
3. Set its **Inbound workflow** to the agent that should answer
|
||||
4. Save
|
||||
|
||||
### Step 3: Verify the Answer URL on the Vobiz Application
|
||||
|
||||
1. Open your Vobiz Console and navigate to **Applications**
|
||||
2. Open the application whose ID you configured in Dograh
|
||||
3. Confirm:
|
||||
- **Answer URL** is set to: `https://api.dograh.com/api/v1/telephony/inbound/run`
|
||||
- **Answer Method** is `POST`
|
||||
|
||||
<Note>
|
||||
Replace `{workflow_id}` with your actual workflow ID. If using self-hosted Dograh, replace `api.dograh.com` with your domain.
|
||||
Dograh pushed this URL automatically when you saved the inbound workflow
|
||||
in Step 2. The same URL is shared across every number linked to that
|
||||
application — Dograh routes each inbound call to the right agent based
|
||||
on the called number's inbound workflow assignment. If the field is
|
||||
empty, shows a different URL, or Dograh surfaced a sync warning on
|
||||
save, the auto-push failed — most often because the Auth ID/Token or
|
||||
Application ID in Dograh is incorrect. Paste the URL into the field
|
||||
yourself, set the method to `POST`, and save. On self-hosted Dograh,
|
||||
replace `api.dograh.com` with your backend domain.
|
||||
</Note>
|
||||
|
||||
<img
|
||||
className="block dark:hidden"
|
||||
src="/images/vobiz-inbound-config-2.png"
|
||||
alt="Vobiz XML application configuration showing Answer URL, Hangup URL, and Fallback Answer URL"
|
||||
/>
|
||||
<img
|
||||
className="hidden dark:block"
|
||||
src="/images/vobiz-inbound-config-2.png"
|
||||
alt="Vobiz XML application configuration showing Answer URL, Hangup URL, and Fallback Answer URL"
|
||||
/>
|
||||
### Step 4: Verify Setup
|
||||
|
||||
3. **Attach Phone Number**:
|
||||
- After saving the application, edit it to attach a phone number
|
||||
- Select the phone number you want to use for inbound calls
|
||||
- Link it to your created application
|
||||
|
||||
<img
|
||||
className="block dark:hidden"
|
||||
src="/images/vobiz-inbound-config-3.png"
|
||||
alt="Vobiz application showing phone number attachment interface"
|
||||
/>
|
||||
<img
|
||||
className="hidden dark:block"
|
||||
src="/images/vobiz-inbound-config-3.png"
|
||||
alt="Vobiz application showing phone number attachment interface"
|
||||
/>
|
||||
|
||||
2. **Verify Setup**:
|
||||
- Ensure your Dograh AI instance is publicly accessible
|
||||
- Verify any firewalls allow Vobiz's webhook requests
|
||||
- Ensure your Dograh AI instance is publicly accessible
|
||||
- Verify any firewalls allow Vobiz's webhook requests
|
||||
|
||||
### Test Inbound Calling
|
||||
|
||||
|
|
@ -147,24 +129,26 @@ Vobiz requires creating an XML application to handle inbound calls. Follow these
|
|||
- Ensure audio pipeline is configured correctly
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Inbound calls not connecting">
|
||||
- Verify webhook URL is correctly configured in Vobiz dashboard
|
||||
- Ensure webhook URL is publicly accessible from internet
|
||||
- Check that phone number is properly linked to webhook
|
||||
- Verify Dograh AI instance is running and responding
|
||||
<Accordion title="Inbound calls go to voicemail or aren't answered">
|
||||
- Verify the phone number is linked to the same Vobiz Application whose
|
||||
ID you configured in Dograh - Confirm the called number exists in your
|
||||
Dograh telephony configuration and has an **Inbound workflow** assigned
|
||||
- After assigning the inbound workflow, confirm Dograh successfully
|
||||
updated the application's `answer_url` (no warning shown on save) -
|
||||
Verify Dograh AI instance is running and responding
|
||||
</Accordion>
|
||||
|
||||
|
||||
<Accordion title="Voice agent doesn't respond to inbound calls">
|
||||
- Confirm voice agent workflow is properly configured
|
||||
- Check webhook processing is working correctly
|
||||
- Verify WebSocket connection establishes successfully
|
||||
- Review call logs for error messages
|
||||
- Confirm the phone number has an **Inbound workflow** assigned in
|
||||
/telephony-configurations - Check webhook signature validation is working
|
||||
(Auth Token in Dograh matches Vobiz dashboard) - Verify WebSocket connection
|
||||
establishes successfully - Review call logs for error messages
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Store credentials securely in the database
|
||||
- Test your configuration with a single call before running campaigns
|
||||
- Monitor Vobiz dashboard for usage and billing
|
||||
- Keep your Auth Token secure and rotate it periodically
|
||||
- Keep your Auth Token secure and rotate it periodically
|
||||
- Use a dedicated Vobiz Application for Dograh so the shared `answer_url` doesn't conflict with other systems
|
||||
|
|
@ -14,21 +14,10 @@ Before setting up Vonage integration, you'll need:
|
|||
- A [Vonage account](https://www.vonage.com/communications-apis/)
|
||||
- Vonage Application with Voice capability enabled
|
||||
- Application ID and Private Key from your Vonage Dashboard
|
||||
- At least one Vonage phone number
|
||||
- API Key and API Secret from your Vonage Dashboard
|
||||
- At least one Vonage phone number linked to the application
|
||||
- Dograh AI instance running and accessible
|
||||
|
||||
## Video Tutorial
|
||||
|
||||
Watch this step-by-step guide to set up Vonage with Dograh AI:
|
||||
|
||||
<iframe
|
||||
className="w-full aspect-video rounded-xl"
|
||||
src="https://www.tella.tv/video/configuring-telephony-on-dograh-with-vonage-3wvo/embed?b=1&title=1&a=1&loop=0&t=0&muted=0&wt=1"
|
||||
title="Dograh Vonage Setup"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
|
||||
## Configuration
|
||||
|
||||
### Step 1: Create Vonage Application
|
||||
|
|
@ -48,37 +37,65 @@ Watch this step-by-step guide to set up Vonage with Dograh AI:
|
|||
|
||||
### Step 3: Configure in Dograh AI
|
||||
|
||||
1. Navigate to **Workflow** → **Phone Call** → **Configure Telephony**
|
||||
2. Watch the Vonage setup video tutorial above for detailed guidance
|
||||
3. Select **Vonage** as your provider
|
||||
4. Enter your credentials:
|
||||
1. Navigate to **/telephony-configurations** and click **Add configuration**
|
||||
2. Select **Vonage** as your provider
|
||||
3. Enter your credentials:
|
||||
- Application ID
|
||||
- Private Key (entire key including BEGIN/END lines)
|
||||
- API Key (Optional - for some operations)
|
||||
- API Secret (Optional - for webhook verification)
|
||||
- From Phone Number (without '+' prefix, e.g., 14155551234)
|
||||
5. Click **Save Configuration**
|
||||
- API Key
|
||||
- API Secret
|
||||
4. Click **Save Configuration**
|
||||
5. Open the configuration you just created and add at least one **phone number** (without `+` prefix, e.g. `14155551234`). The default caller ID is used for outbound calls.
|
||||
|
||||
### Step 4: Test Your Configuration
|
||||
|
||||
1. Create a test workflow
|
||||
2. Click "Test Call" to verify connection
|
||||
2. Click "Call" to verify connection
|
||||
3. Check call logs for successful connection
|
||||
|
||||
## Inbound Calling
|
||||
## Inbound Calling Setup
|
||||
|
||||
<Note>
|
||||
**Coming Soon**: Inbound calling support for Vonage is currently under development and will be available in a future release. For now, Vonage integration supports outbound calling only.
|
||||
</Note>
|
||||
Vonage configures inbound webhooks at the **application level**, not per phone number. A single **Answer URL** on the Vonage application applies to every number linked to it. Dograh routes the call to the right agent based on the called number's inbound workflow assignment inside Dograh. **When you save an inbound workflow on a phone number, Dograh automatically pushes the webhook URL to your Vonage Application's Answer URL** (provided the credentials are correct).
|
||||
|
||||
Vonage integration currently supports outbound calling. Inbound calling functionality is being developed and will include:
|
||||
### Step 1: Link Phone Numbers to Your Vonage Application
|
||||
|
||||
- Webhook configuration for incoming calls
|
||||
- NCCO response handling
|
||||
- Event tracking for call lifecycle management
|
||||
- WebSocket audio streaming for inbound calls
|
||||
1. Open the [Vonage Dashboard](https://dashboard.nexmo.com/)
|
||||
2. Under **Numbers** → **Your Numbers**, link each number you want to use for inbound to the same Vonage Application whose ID you configured in Dograh
|
||||
|
||||
For inbound calling needs, consider using [Twilio](/integrations/telephony/twilio), [Cloudonix](/integrations/telephony/cloudonix), or [Vobiz](/integrations/telephony/vobiz) which have full inbound support.
|
||||
### Step 2: Assign an Inbound Workflow to the Phone Number in Dograh
|
||||
|
||||
1. Go to **/telephony-configurations** and open your Vonage configuration
|
||||
2. In the **Phone numbers** section, edit the number that should receive inbound calls
|
||||
3. Set its **Inbound workflow** to the agent that should answer
|
||||
4. Save
|
||||
|
||||
### Step 3: Verify the Answer URL on the Vonage Application
|
||||
|
||||
1. Open your Vonage Application in the [Vonage Dashboard](https://dashboard.nexmo.com/)
|
||||
2. Under **Capabilities** → **Voice**, confirm:
|
||||
- **Answer URL** is set to: `https://api.dograh.com/api/v1/telephony/inbound/run`
|
||||
- **HTTP Method** is `POST`
|
||||
|
||||
<Note>
|
||||
Dograh pushed this URL automatically when you saved the inbound workflow
|
||||
in Step 2. If the field is empty, shows a different URL, or Dograh
|
||||
surfaced a sync warning on save, the auto-push failed — most often
|
||||
because the API Key/Secret or Application ID in Dograh is incorrect.
|
||||
Paste the URL into the field yourself, set the method to `POST`, and
|
||||
save the application. On self-hosted Dograh, replace `api.dograh.com`
|
||||
with your backend domain.
|
||||
</Note>
|
||||
|
||||
### Step 4: Verify Setup
|
||||
|
||||
- Ensure your Dograh AI instance is publicly accessible
|
||||
- Verify any firewalls allow Vonage's IP ranges
|
||||
|
||||
### Test Inbound Calling
|
||||
|
||||
1. Call your configured Vonage phone number from another phone
|
||||
2. Verify your Dograh AI voice agent answers and responds
|
||||
3. Check call logs in both Dograh AI dashboard and Vonage Dashboard
|
||||
|
||||
## Audio Quality Optimization
|
||||
|
||||
|
|
@ -124,17 +141,17 @@ Vonage uses higher quality audio (16kHz) which provides:
|
|||
</Accordion>
|
||||
|
||||
<Accordion title="Inbound calls not reaching voice agent">
|
||||
- Verify Answer URL is correctly configured in Vonage application
|
||||
- Ensure Answer URL is publicly accessible and returns valid NCCO
|
||||
- Check that phone numbers are linked to the correct application
|
||||
- Verify Event URL is configured for call tracking
|
||||
- Verify the Vonage application's Answer URL is set to `https://api.dograh.com/api/v1/telephony/inbound/run`
|
||||
- Ensure the Answer URL is publicly accessible
|
||||
- Confirm the called number is linked to the correct Vonage application
|
||||
- Confirm the called number exists in your Dograh telephony configuration and has an **Inbound workflow** assigned
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Voice agent doesn't respond to inbound calls">
|
||||
- Confirm NCCO response includes correct WebSocket endpoint
|
||||
- Check that organization_id in Event URL matches your setup
|
||||
- Verify voice agent workflow is properly configured
|
||||
- Review webhook logs for error responses
|
||||
- Confirm the phone number has an **Inbound workflow** assigned in /telephony-configurations
|
||||
- Verify API Key matches the one stored in your Dograh telephony configuration (used to identify the org from the inbound webhook)
|
||||
- Verify WebSocket connection establishes successfully
|
||||
- Review call logs for error messages
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
|
|
@ -155,42 +172,6 @@ Vonage pricing includes:
|
|||
|
||||
Check [Vonage pricing](https://www.vonage.com/communications-apis/voice/pricing/) for current rates.
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Custom Headers
|
||||
|
||||
Add custom headers to WebSocket connections:
|
||||
|
||||
```python
|
||||
# In your webhook response
|
||||
"headers": {
|
||||
"X-Custom-Header": "value",
|
||||
"Authorization": "Bearer token"
|
||||
}
|
||||
```
|
||||
|
||||
### Call Recording
|
||||
|
||||
Enable call recording via NCCO:
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "record",
|
||||
"eventUrl": ["https://your-domain/recording-webhook"],
|
||||
"format": "mp3"
|
||||
}
|
||||
```
|
||||
|
||||
## API Differences from Twilio
|
||||
|
||||
| Feature | Twilio | Vonage |
|
||||
|---------|---------|---------|
|
||||
| Audio Format | 8kHz μ-law | 16kHz Linear PCM |
|
||||
| Control Format | TwiML (XML) | NCCO (JSON) |
|
||||
| Authentication | Basic Auth | JWT |
|
||||
| WebSocket Data | Base64 text | Binary frames |
|
||||
| Phone Format | With '+' | Without '+' |
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Test your Vonage integration with a simple workflow
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
---
|
||||
title: "Twilio"
|
||||
description: "Setting up Twilio on Dograh AI"
|
||||
---
|
||||
|
||||
### Introduction
|
||||
You can setup Twilio on Dograh AI to make and receive calls when executing your Voice Agent Workflow. You can watch below video to get started with the setup once you have your Dograh AI stack running.
|
||||
|
||||
<iframe
|
||||
className="w-full aspect-video rounded-xl"
|
||||
src="https://www.youtube.com/embed/jlPD4CSJHHI"
|
||||
title="Dogrh Twilio Setup"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
Loading…
Add table
Add a link
Reference in a new issue