AI agent, auto-reply & calling

Bind one of your voice AI agents to a WhatsApp number and it can reply to messages automatically and answer WhatsApp voice calls. Both are configured per channel. Auto-reply works on every number in your inbox; calling needs a native WhatsApp number or a Plivo WhatsApp number. This page covers turning them on, the requirements, and the APIs.

The API routes here are on the org surface: use your org API key (X-API-Key: vai_live_…) or a dashboard login. App keys have no agent or calling routes. Changes need an owner, admin or developer key.


AI auto-reply

When a customer messages your number, the bound agent generates and sends a reply — no human needed. You can pause the AI on any single conversation for a human to take over, then resume.

Turn it on

In the dashboard: open Communicate → WhatsApp, pick the channel, and in the agent bar choose an answering agent, then toggle AI on. Owners and admins only.

Over the API (the key's creator must be an owner or admin):

curl -X PUT https://api.telenow.ai/api/orgs/{orgId}/whatsapp-hub/channels/{channelId}/agent \
  -H "X-API-Key: vai_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "agent_id": "a1b2c3d4-…", "ai_enabled": true, "agent_opener": "Hi! I'\''m the Acme assistant — how can I help?" }'
{ "success": true }
FieldTypeRequiredNotes
agent_iduuidto enable AIthe agent that answers; must belong to your org (404 agent not found in this workspace otherwise). A realtime-only (speech-to-speech) agent can't answer text and returns 400
ai_enabledbool—default false; forced false when no agent is bound
agent_openerstring—optional greeting sent first on a new conversation; blank clears it

The PUT replaces the whole binding: leaving out agent_id unbinds the agent, and leaving out agent_opener clears the greeting — send all three each time.

Requirement: auto-reply runs only when the platform flag FEATURE_WHATSAPP_AGENT is on and the channel has an agent bound with ai_enabled: true. Text, image and video captions, and button or list taps trigger a reply; voice-note transcription isn't built yet, so a customer's voice note doesn't. A reply is also skipped when your workspace's balance can't cover it.

Pause AI on one conversation

Hand a single thread to a human (and resume later) without unbinding the agent:

curl -X PUT https://api.telenow.ai/api/orgs/{orgId}/whatsapp-hub/threads/{threadId}/pause \
  -H "X-API-Key: vai_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "paused": true }'

paused is required; the response is { "success": true }. Any org member can pause/resume (with a key, it must be a writing key — not viewer). In the dashboard this is the Agent reply switch in the conversation header: off pauses the AI on that conversation, on resumes it. To hand a conversation to a specific person, see assigning threads.

How it works

An inbound message (fresh, within 24 hours) that is real user text runs the bound agent on that conversation and sends its reply back — the reply shows in the shared inbox tagged AI, and it fires the normal whatsapp.message.status events. While the agent composes, a typing indicator is shown to the customer.


WhatsApp Calling

WhatsApp lets customers place a voice call to your business number. With calling enabled, your voice AI agent answers the call — the same agent stack you use for phone calls, bridged to WhatsApp over WebRTC. Calls are logged, and a call that can't be answered is cleanly rejected rather than left ringing into dead air.

Requirements (mandatory)

Calling needs more than the messaging setup. All of these must be in place:

RequirementWhat / who
A native WhatsApp channeltelenow_whatsapp_cloud (the recommended connection). A Plivo WhatsApp number also works — see the note below. Bring-your-own Meta, GupShup, AiSensy and WhatsApp Web numbers return 400 with the reason
An answering agent bound to the channelthe voice agent that picks up
A messaging limit of 2,000/24 h or higheryours — it's your business portfolio's limit, shared by every number in it. Raised by business verification + sending history, not by adding numbers. Below it, Meta refuses with 138015
No payment-method block on the WABAyours — a payment error (141006) blocks business-initiated conversations and shows in the health banner
An app subscribed to the WABA's calls webhook fieldplatform — without it Meta refuses with 138018
Platform build with the wa_calling_media featurethe media plane is a compile-time cargo feature (operator/self-host step)
Runtime flag FEATURE_WHATSAPP_CALLING_MEDIA=trueenables the media plane at runtime
WHATSAPP_CALL_ICE_URLS — a STUN/TURN serverWebRTC needs a reachable ICE path; a public IP or a TURN server is required for media to connect

The last four are platform/operator settings (see the go-live runbook). On a hosted Telenow plan they're already provisioned — you only bind an agent and toggle calling on. If calling isn't available in your workspace, contact your administrator.

The two marked yours are the ones you can act on, and they're both visible before you try: the account-health endpoint or banner shows your messaging limit and any payment-method warning.

Turn it on

In the dashboard: on the channel, open the Calling bar, pick an answering agent, and toggle calling on. This also flips the calling setting at Meta for your number. Owners and admins only.

Over the API (the key's creator must be an owner or admin):

curl -X PUT https://api.telenow.ai/api/orgs/{orgId}/whatsapp-hub/channels/{channelId}/calling-agent \
  -H "X-API-Key: vai_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "agent_id": "a1b2c3d4-…", "calling_enabled": true }'
{ "success": true,
  "data": { "callingEnabled": true, "agentId": "a1b2c3d4-…", "metaSynced": true, "warnings": [] } }
FieldTypeRequiredNotes
agent_iduuidto enable callingthe agent that answers calls; must belong to your org, and its Telephony channel must be on (400 otherwise)
calling_enabledbool—default false; forced false when no agent is bound. Setting this calls Meta to enable/disable calling on the number

metaSynced says whether Meta's own switch is known to match what was stored: true applied, false we tried and Meta refused (your channel setting still governs whether an agent answers), null Meta never reported its state. warnings carries anything real but non-blocking — a payment-method problem, a display name still in review — and the response can also include notes.

Plivo WhatsApp numbers: calling is switched on in Telenow only — nothing is sent to Meta. The response is { callingEnabled, agentId, metaSynced: null, answerUrl, notes }; point the number's call handling in Plivo at answerUrl.

To turn calling off, send { "calling_enabled": false }. Disabling always succeeds — it is recorded on your channel first and Meta is told afterwards, so an account problem can never trap you with calling stuck on.

Enabling is the direction Meta can refuse. When it does you get an actionable 400 naming the blocker, with the full list under blockers so fixing the first one doesn't just reveal the second:

{ "success": false,
  "error": "Your messaging limit is too low for WhatsApp calling. WhatsApp only allows calling once your business can start at least 2000 conversations a day; yours is at 1000. …",
  "code": "wa_calling_messaging_limit",
  "blockers": [ { "code": "wa_calling_messaging_limit", "level": "error", "title": "…", "detail": "…", "action": "Open Meta Business Manager" } ] }

The 400 also carries advisories and notes next to blockers. When Meta itself rejects the switch, the 400 carries meta: { code, subcode, fbtraceId } instead of blockers. A revoked access token is a 400 with code: "wa_token_revoked". The codes are listed under Calling errors. A 502 from this endpoint means something on Meta's side failed rather than your account being ineligible — retry it.

Re-saving a channel whose calling state is unchanged writes only the agent binding; Telenow then checks Meta's switch and re-applies it if Meta disagrees, and a failure there comes back as a warning rather than an error — so merely re-saving a page can't fail on an account problem you didn't introduce.

How a call flows

  1. A customer places a WhatsApp call to your number → Meta sends Telenow a connect event.
  2. If calling is enabled and an agent is bound and the media plane is on, Telenow answers: it negotiates WebRTC, stands up the agent's session, and accepts the call at Meta. The agent talks to the caller.
  3. Otherwise the call is rejected at Meta immediately — the caller isn't left ringing.
  4. When either side hangs up, the call is logged with its duration.

Call log

List a channel's calls (most recent first):

curl "https://api.telenow.ai/api/orgs/{orgId}/whatsapp-hub/channels/{channelId}/calls" \
  -H "X-API-Key: vai_live_…"
{ "success": true, "data": { "calls": [
  { "call_id": "wacid.…", "direction": "inbound", "from_number": "+919876543210",
    "status": "completed", "duration_secs": 92, "agent_id": "a1b2c3d4-…",
    "start_time": "2026-01-01T12:00:00Z", "end_time": "2026-01-01T12:01:32Z" }
] } }

status is one of ringing, accepted, rejected, completed, failed, or missed (missed comes from Plivo numbers only). Each row also carries id, org_id, channel_id, phone_number_id, to_number, session_id, last_error, created_at and updated_at. The endpoint returns up to the 100 most recent calls (newest first) with no pagination, filtering, or offset, and there's no WhatsApp-call webhook event — poll this endpoint to keep your own history. duration_secs is in seconds, and direction reflects the value WhatsApp reports for the call (e.g. inbound).


Customer satisfaction (CSAT)

Ask customers to rate a conversation when it's resolved. Set it up per channel (Meta Cloud numbers only; the key's creator must be an owner or admin):

curl -X PUT https://api.telenow.ai/api/orgs/{orgId}/whatsapp-hub/channels/{channelId}/csat \
  -H "X-API-Key: vai_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true, "template_name": "csat_rating", "template_language": "en_US" }'
{ "success": true, "data": { "enabled": true } }
  • When a thread moves to resolved inside the 24-hour window, the customer gets three buttons — Great (5), OK (3), Not good (1).
  • Outside the window, the approved template named in template_name is sent instead. Build it with one body variable (Telenow fills it with "your recent conversation") and three quick-reply buttons — the first counts as 5, the second as 3, the third as 1. Without a template, nobody is asked once the window has closed.
  • Opted-out numbers are never asked, and each number is asked at most once every 7 days. A blank template_name clears the template.

GET …/channels/{channelId}/csat (any member) returns { enabled, templateName, templateLanguage, averageScore, responseCount } for the last 30 days; averageScore is null until someone rates.