Vendor Platforms (Vapi)
VocaLoop projects can live inside third-party agent platforms. Each vendor gets its own VocaLoop endpoint that speaks that vendor's request format — the agent calls it as a tool, VocaLoop generates the project from the caller's words and texts the fill link to their phone.
Supported today: Vapi (voice agents). Retell AI and ElevenLabs Agents are planned and will follow the same pattern.
Tip: the Getting Started wizard inside every project sets all of this up for you — it stores your Vapi key, creates the tool in your Vapi account with a fresh VocaLoop key embedded, and attaches it to an assistant. This page documents what it builds, for manual setups and debugging.
How it works
You add a custom tool to your Vapi assistant that points at:
POST <your app URL>/api/integrations/vapi/generate-sendWhen a caller asks for a project, the assistant calls the tool with the phone number and a description. VocaLoop regenerates the key's project UI from that description, texts the caller a fill link, and their submission lands on the project's Responses page (and its webhook, if set).
Auth: a project API key with the Generate & send action (granted by default), sent in the
X-API-Keyheader (Vapi'sX-Vapi-Secretrelay also works). The key decides which project the tool writes into.namespace: optional and, when sent, must be the key's project name — keys cannot reach or create other projects.The message goes out on WhatsApp through the account's whatsapp channel — the server's system Meta credentials (
WHATSAPP_*in the root.env); the channel must stay enabled on the Integrations page. Project generation uses the server's OpenAI key.Live-call feedback: VocaLoop talks back over the call's control URL — when the recipient submits, the answers are handed to the assistant as a system message so it can react mid-call.
1. Create the tool in Vapi
In the Vapi dashboard go to Tools → Create Tool → Custom Tool and paste the JSON below (or send it to POST https://api.vapi.ai/tool with your Vapi API key). Replace YOUR_API_KEY with the project's VocaLoop key — the key alone decides which project the tool writes into.
{
"type": "function",
"async": true,
"function": {
"name": "generate_and_send_project",
"description": "Generates a web project from a natural-language description and sends the fill link to a phone number via WhatsApp. Use when the caller wants to create and send a project.",
"parameters": {
"type": "object",
"properties": {
"phone": {
"type": "string",
"description": "Recipient phone number in E.164 format with country code, e.g. +14155550100"
},
"prompt": {
"type": "string",
"description": "Detailed description of the project to generate, including all fields the caller mentioned"
},
"expiry_minutes": {
"type": "number",
"description": "Optional: minutes until the fill link expires, counted from when the message is sent. Omit for a link that never expires."
}
},
"required": ["phone", "prompt"]
}
},
"messages": [
{
"type": "request-start",
"blocking": false
}
],
"server": {
"url": "<your app URL>/api/integrations/vapi/generate-send",
"timeoutSeconds": 20,
"headers": {
"X-API-Key": "YOUR_API_KEY"
}
}
}Notes on the shape:
There is no
namespaceargument — the project-scoped key already determines the project. Older tools that still send one keep working as long as it matches the key's project name."async": truemeans the assistant keeps talking while the project is generated. Set it tofalseif the assistant should wait and speak the result (e.g. confirm the message went out) before continuing.expiry_minutesis optional — when the assistant sets it, the fill link stops working that many minutes after the message; left out, links never expire. To pin a fixed window instead of letting the assistant choose, remove it fromfunction.parametersand add a static bottom-level"parameters": [{ "key": "expiry_minutes", "value": 30 }]list instead.Any extra tool argument beyond the modeled fields becomes a template
{placeholder}value (the Getting Started wizard calls these configurable keys) — e.g. acustomerargument fills{customer}in the message template. Explicitvariablesentries win; unusable keys are dropped silently.Arguments may also arrive as a JSON-encoded string — VocaLoop accepts both.
2. Add the tool to your assistant
Assistants → your assistant → Tools → select the tool you just created, then publish. Tell the assistant when to use it in its system prompt, for example:
When the caller wants to share details (contact info, lead details, feedback),
use the generate_and_send_project tool. Ask for their phone number first, then
describe every field they mentioned in the prompt argument.3. What VocaLoop answers
The endpoint always replies in Vapi's tool-result format — one result per tool call, which Vapi relays to the assistant:
{
"results": [
{
"toolCallId": "call_cZmJtguyfP0Expi7IlqZhx5y",
"result": "The \"Lead Project\" project was generated and its fill link was sent on WhatsApp to +918879283210. Request id: 1f0e6c3a-9b2d-4f7e-8a51-c3d2e1f0a9b8.",
"callId": "019f892f-9353-766d-ac6f-61e0837f5ae2",
"controlUrl": "https://phone-call-websocket.…vapi.ai/019f892f-…/control",
"listenUrl": "wss://phone-call-websocket.…vapi.ai/019f892f-…/listen",
"requestId": "1f0e6c3a-9b2d-4f7e-8a51-c3d2e1f0a9b8",
"projectId": "7a41d9c2-3e8f-4b6a-9d05-f1e2d3c4b5a6",
"namespace": "Lead Project",
"projectLink": "<your app URL>/fill/1f0e6c3a-…/text",
"phone": "+918879283210",
"status": "pending",
"error": null
}
]
}Vapi itself only reads toolCallId and result; the other keys are a structured mirror for your own systems — Vapi's call id and control/listen URLs echoed back, plus the VocaLoop request id, project id/namespace and the fill link.
Failures (invalid phone, wrong namespace, generation problems) come back the same way, as spoken-friendly Error: … text with status: "error", so the assistant can tell the caller what went wrong. Only a wrong API key is an HTTP error (401).
Every call is also recorded on the VocaLoop side (with Vapi's call, org and assistant ids) and surfaces in the project's Getting Started event log; the sent request appears on the project's Responses page, and its status can be polled via GET /api/v1/external/requests?ids=… with a key that has the Check status action (see the External API).