Dialora AI Logo
Developers

Build on Dialora

One script tag for the chat widget, a REST API behind scoped keys, an MCP server for AI clients, signed webhooks with retries, n8n templates and numbers routed to agents. The same endpoints the dashboard uses.

Illustration
Embed

The chat widget

One script tag. The widget renders inside a Shadow DOM so your page styles and its styles never meet, and it talks to the agent you chose for your website.

Source: backend/public/widget.js · backend/routes/widget.js · components/settings/chat-widget-settings.tsx

<script src="https://aicall.vitrano.in/widget.js" data-key="wgt_…" async></script>

<!-- optional: name a routing label for this page (Settings → Chat widget → Routing) -->
<script src="https://aicall.vitrano.in/widget.js" data-key="wgt_…" data-agent="pricing" async></script>
  • Answers from the agent's knowledge base: retrieved passages when the base is indexed, the whole base when it is not.
  • Voice input: the visitor taps the mic, the clip is transcribed on our speech recognition and sent as a message; replies to spoken questions are read aloud by the browser.
  • Callback request and lead capture: a name and number become a lead in Leads and, where connected, your CRM.
  • Handoff: when the visitor asks for a person the thread lands in the Conversations inbox, where your team takes over live.
  • A rating prompt at the end of the chat, and surveys when a survey is attached to the agent.
  • Allowed origins, title, greeting, colour, starter buttons and auto-open are set in the dashboard.

Where the key comes from. Settings → Integrations → Chat Widget. The key starts with wgt_ and can be regenerated there at any time.

Routing pages to agents. Rules in Settings → Chat widget → Routing match the page URL to an agent, so a pricing page and a support page can be answered by different agents from one embed code. A page can also name a label with data-agent="<label>", which the rules can match on. Without a rule the widget uses the agent chosen in the widget settings.

REST

The API, behind scoped keys

Create a key in Settings → API keys, choose its scopes, and send it in the X-API-Key header. Every endpoint the dashboard uses answers to it, under the same ownership checks, plan limits and compliance gate.

Source: backend/routes/api-keys.js · backend/utils/api-scopes.js · backend/middleware/auth.js

curl -X POST https://aicall.vitrano.in/api/leads \
  -H "X-API-Key: ic_…" \
  -H "Content-Type: application/json" \
  -d '{"name":"Asha Patel","phone":"+919876543210","tags":["website"]}'

curl -X POST https://aicall.vitrano.in/api/calls/dial \
  -H "X-API-Key: ic_…" \
  -H "Content-Type: application/json" \
  -d '{"to":"+919876543210","agentId":"<agent id>","name":"Asha Patel"}'
  • GET/api/agentsYour agents, with ids for the other calls
  • POST/api/leadsAdd a lead: name, phone, tags, custom fields
  • GET/api/leadsSearch leads by name, phone or tag
  • POST/api/calls/dialCall a number now with an agent
  • GET/api/call-logsCall history, transcripts and analysis
  • POST/api/appointmentsBook an appointment
  • GET/api/eventsThe event log, with replay

Scopes. A scope is <resource>:read or <resource>:write (write includes read), or * for everything a key may reach. The resource is the router the request hits: /api/leads needs leads:read for GET and leads:write for anything else.

What a key never reaches. Users, team, settings, billing and the keys themselves. Those need a signed-in session.

Housekeeping. Keys start with ic_, are shown once, can be given an expiry, record when they were last used, and can be revoked. Creating or revoking one is itself an event.

AI clients

An MCP server

Point Claude Desktop, Cursor or your own agent framework at /api/mcp and it lists these tools and calls them. Each tool is a thin adapter onto the REST API, so the key's scopes decide what the client may do.

Source: backend/routes/mcp.js · backend/services/mcp-server.js

POST https://aicall.vitrano.in/api/mcp
X-API-Key: ic_…
Content-Type: application/json

{"jsonrpc":"2.0","id":1,"method":"tools/list"}

{"jsonrpc":"2.0","id":2,"method":"tools/call",
 "params":{"name":"create_lead","arguments":{"name":"Asha Patel","phone":"+919876543210"}}}
{
  "mcpServers": {
    "dialora": {
      "url": "https://aicall.vitrano.in/api/mcp",
      "headers": { "X-API-Key": "ic_…" }
    }
  }
}

Transport. Streamable HTTP, stateless: POST one JSON-RPC 2.0 message or a batch and the answer comes back as JSON. There is no server-to-client event stream (GET answers 405) and no session; every request stands on its own, authenticated with X-API-Key or a dashboard session.

Tools.

  • list_agents
  • create_lead
  • search_leads
  • dial_call
  • list_calls
  • get_call
  • book_appointment
  • list_appointments
  • campaign_status
  • start_campaign
  • list_events
  • agent_versions
Events out

Signed webhooks, with retries

Your workspace webhook is set in Settings → Webhooks, and up to ten extra endpoints can each have their own HTTPS URL, secret, event list and envelope. Every delivery is recorded and can be inspected and replayed from the dashboard.

Source: backend/services/webhook-delivery.js · backend/models/WebhookEndpoint.js · backend/models/WebhookDelivery.js · backend/utils/event-catalog.js

// Node: verify X-Dialora-Signature-V2 on the raw body
const crypto = require("crypto");
const [t, v1] = req.get("X-Dialora-Signature-V2").split(",").map((p) => p.split("=")[1]);
const expected = crypto.createHmac("sha256", SECRET).update(`${t}.${rawBody}`).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));

Headers on every delivery. X-Dialora-Event, X-Dialora-Event-Id, X-Dialora-Attempt, X-Dialora-Timestamp, X-Dialora-Signature (HMAC-SHA256 of the body) and X-Dialora-Signature-V2 (t=<unix time>,v1=<HMAC of "t.body">), which also covers the send time so a captured delivery cannot be replayed later.

Retries. A failed delivery is tried again after 1 min, 5 min, 30 min, 2 h, 6 h and 12 h, seven attempts in all, with jitter. A 410 from your server stops retries. An extra endpoint that fails ten deliveries in a row is switched off with the reason kept, and can be switched back on.

Envelopes. dialora (the default) or cloudevents, whose type is in.dialora.<dotted type>.

EventWhen
inboundCallAn inbound call reached an agent
outboundCallAn outbound call was placed
callCompletedA call ended, with its outcome
voicemailLeftAn answering machine picked up and a message was left
callBlockedThe compliance gate refused a dial
callbackRequestedA caller asked to be called back
leadCreatedA lead was added
leadQualifiedCall analysis rated a lead as qualified
leadDispositionedAn agent set a disposition on a lead
optOutA number asked not to be called again
consentRecordedConsent to be contacted was recorded
consentRevokedConsent was withdrawn
campaignCompletedA campaign finished dialling
appointmentBookedAn appointment was booked
appointmentCanceledAn appointment was cancelled
chatHandoffA chat asked for a human
agentTransferOne agent handed the conversation to another
usageThresholdUsage crossed a plan threshold
modelFallbackThe local model was unreachable and the hosted fallback answered
agentVersionCreatedAn agent was changed or restored
Automation

n8n templates

Three ready-made workflows. Import one into n8n and connect the rest to your own tools. The event-driven ones receive their events from Settings → Integrations → n8n, where you paste the workflow's webhook URL; the instant-call one sends your API key in X-API-Key.

Source: frontend/public/n8n-templates/ · backend/services/n8n-service.js · components/settings/n8n-integration.tsx

  • Instant AI call on form submit
    A form submission becomes a POST /api/calls/dial with your API key in X-API-Key.
    /n8n-templates/intellicall-instant-call.json
    Download JSON
  • Qualified lead to CRM + notify
    Receives Dialora events, keeps the lead-qualified ones, and posts the lead to your CRM and a notification webhook.
    /n8n-templates/intellicall-lead-qualified-crm.json
    Download JSON
  • Call log to Google Sheets
    Receives Dialora events, keeps the call-completed ones, and appends each to a Google Sheet.
    /n8n-templates/intellicall-call-log-to-sheets.json
    Download JSON
Numbers

Numbers, routing and SIP

A phone number belongs to a workspace and points at an agent. What happens when it rings is decided by its routing rules, and the carrier behind it is Twilio or your own SIP trunk.

Source: backend/routes/numbers.js · backend/services/inbound-router.js · components/numbers/inbound-routing-sheet.tsx · backend/routes/sip-trunks.js

  • GET/api/numbersNumbers in the workspace, with trunk and agent
  • POST/api/numbersAdd a number: provider twilio or sip, agent, hours
  • PATCH/api/numbers/:idChange the agent, hours, menu or fallback
  • GET/api/sip-trunksYour SIP trunks and their registration status
  • POST/api/sip-trunks/:id/testCheck that a trunk's host answers

Inbound routing. Opening hours are checked first, then an optional keypad menu, then the step: connect the agent, forward to a person, take a voicemail, play a message or hang up. Each decision is written into the call log with its reason.

Carriers. Twilio numbers work out of the box; Twilio webhooks are signature-verified. A SIP trunk (Vobiz, Plivo, or any provider) is configured into our Asterisk and can be checked for reachability and with a test call from the dashboard.

Outbound. POST /api/calls/dial places a call with an agent and, optionally, a specific outbound number. The compliance gate (do-not-call list, calling hours, consent) runs before every dial.

Start with a key

Sign up, create a scoped API key in Settings, and the first call is a curl away. Everything on this page is also described for machines in /llms.txt.

Developers · Dialora AI