Adding a Voice Agent to Your SaaS in 3 API Calls
You build software for dental practices. Your customers have asked about AI phone answering. You could evaluate five vendors, negotiate contracts, and build a custom integration — or you could ship the feature in a week.
This post walks through the complete integration path: from a new WFW service account to a per-customer provisioned agent with webhook notifications. Three core API calls. No voice infrastructure to manage.
The Setup (One Time)
Before you can provision agents for your customers, you need a service account for your SaaS product. This is a one-time setup in the WFW admin dashboard under Settings → API → Service Accounts.
Choose a descriptive name ("Ridgeline Dental Software Integration") and select the scopes your integration needs:
agents:write — create and configure agents
agents:read — read agent status and configuration
calls:read — access call logs and transcripts
webhooks:write — subscribe to event webhooks
Save your clientid and clientsecret. You'll use these to obtain access tokens.
Call 1: Create an Agent on Customer Signup
When a new customer signs up for your "AI receptionist" feature, call POST /v2/agents with their business URL. WFW's Workforce Wave provisioning handles everything else.
curl -X POST https://api.workforcewave.com/v2/agents \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: provision-customer-$CUSTOMER_ID" \
-d '{
"payload": {
"name": "Ridgeline Dental AI",
"platform": "elevenlabs",
"business_url": "https://ridgelinedental.com",
"template_id": "dental_receptionist",
"white_label": {
"product_name": "YourSaaS AI Receptionist",
"partner_slug": "your-saas-slug"
}
}
}'
Response:
{
"data": {
"operation_id": "op_abc123",
"status": "pending",
"estimated_seconds": 90
}
}
This returns a 202 Accepted immediately. Workforce Wave is now crawling the practice website, building the knowledge base, and provisioning the voice agent in the background. Store the operation_id — you'll need it.
The Idempotency-Key header is required. If your process crashes during provisioning and you retry, the same key returns the same operation_id without creating a duplicate agent. Use a key that encodes your customer ID so you can reconstruct it after a crash.
Handling the Async Provisioning
Workforce Wave takes 75–120 seconds. You have two options for knowing when it's done.
Option A: Poll. Call GET /v2/operations/{operation_id} every 5–10 seconds until status is active or failed.
async function waitForAgent(operationId, token) {
while (true) {
const res = await fetch(`https://api.workforcewave.com/v2/operations/${operationId}`, {
headers: { Authorization: `Bearer ${token}` }
}).then(r => r.json());
if (res.data.status === 'active') return res.data.agent_id;
if (res.data.status === 'failed') throw new Error(res.data.error?.message);
await new Promise(r => setTimeout(r, 8000)); // poll every 8s
}
}
Option B: Webhook. Subscribe to agent.activated before provisioning (see Call 2 below) and let WFW push you the notification. This is the better choice for production — no polling loop, and your UI can update reactively.
When the operation completes:
{
"data": {
"operation_id": "op_abc123",
"status": "active",
"agent_id": "agt_xyz789",
"phone_number": "+18435552847",
"provisioning_time_seconds": 88
}
}
Store agentid and phonenumber against your customer record. The phone number is live immediately — the practice can start receiving calls.
Call 2: Subscribe to Webhooks
Subscribe once per customer to receive notifications on agent and call events:
curl -X POST https://api.workforcewave.com/v2/webhooks \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "agt_xyz789",
"url": "https://your-saas.com/webhooks/wfw",
"events": ["agent.activated", "call.started", "call.ended", "call.transcript_ready"],
"secret": "your_webhook_signing_secret"
}'
WFW will POST to your endpoint with a signed payload for each event. Verify the signature with HMAC-SHA256(secret, raw_body) against the X-WFW-Signature header.
For call.transcript_ready, the payload includes the structured extractions — intent, outcome, whether an appointment was booked. Your dashboard can display these without calling back to fetch the full transcript.
The Full Lifecycle
Customer signup
│
▼
POST /v2/agents (with customer's businessUrl)
│
▼
Store operation_id in your DB
│
▼
agent.activated webhook fires (~90s later)
│
▼
Store agent_id + phone_number
Show customer "Your AI receptionist is live at +1 (843) 555-2847"
│
▼
call.transcript_ready fires after each call
│
▼
Update your call log UI
White Label: Your Product Name, Not WFW
If you'd rather your customers see your brand, not WFW's, use the whitelabel field in the agent creation payload. With a partnerslug configured, the agent uses your product name in the provisioning confirmation, your support contact in any escalation messages, and your branding in any customer-facing communications.
The voice agent itself doesn't mention WFW. From your customer's perspective, it's entirely your product. WFW is the infrastructure underneath.
Subaccounts vs. One Shared Account
For most SaaS integrations, a single service account that manages agents for all of your customers is the right choice. It's simpler to implement and your single service account gives you visibility across all agents.
Subaccounts make sense when your customers need direct API access — if you want each practice to be able to call the WFW API directly with their own credentials, each gets a subaccount. This adds isolation at the cost of more account management. Most SaaS builders using WFW as infrastructure (not exposing the API to end users) stay on the single service account model.
Next in this series: Using the WFW MCP Server with Claude Code — configure Claude Code to manage WFW agents via natural language.
Ready to put AI voice agents to work in your business?
Get a Live Demo — It's FreeContinue Reading
Related Articles
Rate Limiting and Idempotency: What Your Bot Needs to Know
The two most important API patterns for AI consumers of the WFW API — with concrete examples and a production-ready TypeScript client.
Workforce Wave AI: The Engine Behind Auto-Provisioning
What happens inside the 5-step Workforce Wave pipeline when a partner enters a business URL, why partners get an operationId instead of a 30-second wait, and how ww_operations powers the fleet dashboard progress bar.
The Bot Creation Matrix: Four Ways to Deploy AI, Now All Live on WFW
Dual-mode agent support just shipped, completing the Bot Creation Matrix. WFW is now the only platform where a bot can be the creator and the consumer — entirely human-free.