Verticals
Call tracking
Tracking numbers, dynamic number insertion pools, buyer routing, qualification rules and call conversions.
Call tracking attributes phone calls to the click or campaign that caused them and turns qualified calls into conversions with payouts, just like web conversions.
Provider
Telephony runs through a provider. Twilio is supported (and a deterministic fake for testing). Configure it with PUT /calls/provider: provider, credentials (sealed with DT_SECRETS_KEY), and the public origin the provider will call back. The provider calls Metrixed at POST /calls/voice/{provider}/{tenant} for call control and POST /calls/webhook/{provider}/{tenant} for status and recordings; those endpoints are authenticated by the provider's signature, not an API key. DT_TWILIO_BASE_URL overrides the Twilio API base for tests.
Numbers, pools and routing
| Object | Purpose |
|---|---|
| Numbers | Tracking numbers you search for (GET /calls/numbers/available), buy and assign, in E.164 format. |
| Pools | A set of numbers shared by visitors for dynamic number insertion (DNI). |
| Destinations | Buyer phone numbers with time zone, business hours, weight and position. |
| Routes | How a number's calls reach destinations. |
Routing strategies: round_robin, weighted and priority, with a fallback number dialled when no destination is open or available, and an optional press-1 menu (IVR) that maps digits to destinations. Business hours are weekday windows in the destination's time zone; a window that ends before it starts runs past midnight.
Dynamic number insertion
DNI shows each web visitor a different number from a pool so a call can be tied back to a visit.
- Include the snippet from the pool page. It loads
/dni.jsfrom ingest (under 3 kB). - The script asks
POST /dni/v1/assignfor a number, keyed by the click id (or a session id). The assignment is a lease held in Redis for the pool's TTL, so the same visitor keeps the same number and a number is shared by only one visitor at a time. - When a call arrives on a leased number, the webhook looks up the lease and finds the click, hence the offer and partner. If every number in the pool is busy the visitor gets the pool's fallback number and the call is unattributed.
Pools are published to Redis with POST /calls/pools/{id}/publish. Set DT_API_REDIS_ADDR on the API, DT_INGEST_DNI_REDIS_ADDR (or DT_INGEST_REDIS_ADDR) on ingest, and DT_CALLS_INGEST_URL so the snippet points at your ingest origin.
Qualification and conversions
A finished call becomes a conversion only if it qualifies. Per offer or route the rules are:
| Rule | Reason code when it fails |
|---|---|
| The call was answered and completed | not_answered |
| Minimum duration in seconds | too_short |
| Inside the destination's business hours (optional) | outside_business_hours |
| No qualified call from the same caller for the same offer within a repeat window (optional) | repeat_caller |
Qualified calls are converted by the calls worker (calls-sync, with retries) through an internal ingest path, so they pass the normal payout engine, caps and fraud hooks and arrive as ordinary conversions (conversion method call). Calls are mirrored to ClickHouse for reporting. Caller numbers are stored only as a salted hash, never in the clear.
Reports and portals
Traffic, Call log, Numbers & pools and Call routing in the admin portal; GET /calls/stats and the call log API for analysis; partners get their own statistics through GET /partner/calls/stats. Calls on partner-less pools keep the partner empty until ingest resolves it from the click, so those calls are missing from partner statistics.
Switches
DT_CALLS_DISABLE=1 stops the calls worker; DT_CALLS_INTERVAL sets its poll period.