Agent Integrations
VocoAgents sends two kinds of requests to your integration: lifecycle webhooks for engagement events and custom tool calls when the agent needs your API or MCP server to perform an action.
Integration Request Types
| Request | When it is sent | JSON shape |
|---|---|---|
Lifecycle webhook | Call or conversation starts, and when a call ends | webhook/lifecycle JSON-RPC envelope |
Custom tool call | The agent calls a configured REST API or MCP tool | Tool arguments + metadata |
Both request types include the same authentication headers. See Request Signing & Security.
Webhook Events
| Event | Trigger |
|---|---|
new_outbound_call | Outbound call starts |
new_inbound_call | Inbound call starts |
call_ended | Call ends |
Call Start Webhook
When a call starts, a POST request is sent to the configured webhook URL.
Request Format (JSON-RPC 2.0)
{
"id": "uuid",
"jsonrpc": "2.0",
"method": "webhook/lifecycle",
"metadata": {},
"params": {
"event": "new_outbound_call",
"timestamp": "2024-01-15T10:30:00.000Z",
"metadata": {},
"agent": {
"id": "agent-uuid",
"timezone": "America/New_York"
},
"call": {
"id": "call-uuid",
"status": "initializing",
"direction": "outbound",
"channel": "phone",
"caller": "+1234567890",
"callee": "+0987654321",
"userPhoneNumber": "+0987654321",
"personalization": {}
}
}
}Request Fields
| Field | Type | Description |
|---|---|---|
params.event | string | new_outbound_call or new_inbound_call |
params.agent.id | string | Agent UUID |
params.call.id | string | Call UUID |
params.call.direction | string | inbound or outbound |
params.call.channel | string | web, phone, or whatsapp |
params.call.userPhoneNumber | string | User's phone number |
Custom Tool Calls
Configure a custom REST API tool or MCP tool in the agent settings. When the agent invokes it, VocoAgents sends the tool arguments together with the current integration context under metadata. REST tool arguments remain at the top level; metadata is a reserved top-level integration field.
REST API tool (POST, PUT, or DELETE)
{
"customer_id": "CRM-12345",
"action": "get_status",
"metadata": {
"source": "widget",
"userAgent": "Mozilla/5.0 ...",
"location": "https://example.com/pricing",
"crm_contact_id": "CRM-12345"
}
}MCP tool (JSON-RPC 2.0 runtime shape)
{
"id": "uuid",
"jsonrpc": "2.0",
"method": "lookup_customer",
"metadata": {
"source": "widget",
"userAgent": "Mozilla/5.0 ...",
"location": "https://example.com/pricing",
"crm_contact_id": "CRM-12345"
},
"params": {
"customer_id": "CRM-12345"
}
}Metadata
metadata is an object containing the effective session metadata. REST arguments remain at the top level, while MCP arguments remain under params. Metadata starts with metadata supplied with the engagement and is overlaid with metadata returned by the enrichment webhook. If both contain the same key, the webhook value wins. Metadata is pass-through context and may contain custom keys from your widget, campaign, or webhook. Do not define metadata as a REST tool parameter because the name is reserved for this integration context.
For a REST GET tool, the tool parameters remain URL query parameters because GET requests do not have a JSON request body. The same metadata is still available in the x-voco-session-metadata header.
Expected Response
The webhook should return a JSON response with a result object.
Response Format
{
"result": {
"personalization": {
"first_name": "Joe",
"sex": "unknown",
"language": "en"
},
"additional_context": "## Customer\n- Plan: Pro\n- Open ticket #1234",
"metadata": {
"crm_id": "CRM-12345",
"segment": "enterprise"
}
}
}Response Fields
| Field | Type | Description |
|---|---|---|
personalization.first_name | string | Visitor's first name, used to greet them |
personalization.sex | string | male, female, or unknown |
personalization.language | string | ISO 639-1 language code (e.g., en, es, he) |
additional_context | string | Additional context injected into agent prompt |
metadata | object | Pass-through metadata available to later tool calls and sent back at call end |
Implementation Examples
Ready-to-use starting points you can hand to a developer or automation partner. Each one receives the call-start request, reads the visitor id from params.call.id, and returns the personalization response shown above. Replace the example data with a lookup against your own CRM or database.
n8n
In n8n: top-right menu → "Import from clipboard" → paste. Then set the Webhook node's Production URL as your agent's webhook, and edit the "Build personalization" node to read from your system.
{
"name": "VocoAgents Personalization Webhook",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "vocoagents-personalization",
"responseMode": "responseNode",
"options": {}
},
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
260,
300
],
"webhookId": "vocoagents-personalization"
},
{
"parameters": {
"jsCode": "const id = $input.first().json.body?.params?.call?.id;\n// TODO: look up the visitor by id in your CRM / database\nreturn [{ json: { result: {\n personalization: { first_name: 'Joe', sex: 'unknown', language: 'en' },\n additional_context: '## Customer\\n- Plan: Pro\\n- Open ticket #1234'\n} } }];"
},
"name": "Build personalization",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
480,
300
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ $json }}",
"options": {}
},
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
700,
300
]
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Build personalization",
"type": "main",
"index": 0
}
]
]
},
"Build personalization": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
}
}
}Make.com
In Make: create a scenario → ⋯ menu → "Import Blueprint" → paste. Copy the Custom webhook URL into your agent settings, then edit the Webhook response body.
{
"name": "VocoAgents Personalization Webhook",
"flow": [
{
"id": 1,
"module": "gateway:CustomWebHook",
"version": 1,
"parameters": {
"hook": null,
"maxResults": 1
},
"mapper": {},
"metadata": {
"designer": {
"x": 0,
"y": 0
}
}
},
{
"id": 2,
"module": "gateway:WebhookRespond",
"version": 1,
"parameters": {},
"mapper": {
"status": "200",
"headers": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": "{\n \"result\": {\n \"personalization\": {\n \"first_name\": \"Joe\",\n \"sex\": \"unknown\",\n \"language\": \"en\"\n },\n \"additional_context\": \"## Customer\\n- Plan: Pro\\n- Open ticket #1234\"\n }\n}"
},
"metadata": {
"designer": {
"x": 300,
"y": 0
}
}
}
],
"metadata": {
"version": 1,
"scenario": {
"roundtrips": 1,
"maxErrors": 3,
"autoCommit": true
},
"designer": {
"orphans": []
}
}
}JavaScript (Node / Express)
A standalone webhook server. Point your agent's webhook URL at /vocoagents/personalization.
// VocoAgents personalization webhook — minimal Express server
// Install: npm i express
// Run: node server.js
import express from 'express';
const app = express();
app.use(express.json());
app.post('/vocoagents/personalization', async (req, res) => {
const id = req.body?.params?.call?.id;
// TODO: look up the visitor by `id` in your CRM / database
// const user = await db.findVisitor(id);
res.json({
result: {
personalization: {
first_name: 'Joe',
sex: 'unknown',
language: 'en'
},
additional_context: '## Customer\n- Plan: Pro\n- Open ticket #1234'
}
});
});
app.listen(3000, () => console.log('Webhook listening on :3000'));
Call End Webhook
When a call ends, the same webhook receives a call_ended event with full call details.
Request Format
{
"id": "uuid",
"jsonrpc": "2.0",
"method": "webhook/lifecycle",
"metadata": {},
"params": {
"event": "call_ended",
"timestamp": "2024-01-15T10:35:00.000Z",
"metadata": {
"crm_id": "CRM-12345",
"segment": "enterprise"
},
"agent": {
"id": "agent-uuid",
"timezone": "America/New_York"
},
"call": {
"id": "call-uuid",
"status": "ended",
"direction": "outbound",
"channel": "phone",
"caller": "+1234567890",
"callee": "+0987654321",
"userPhoneNumber": "+0987654321",
"personalization": { "language": "en" },
"ended_at": "2024-01-15T10:35:00.000Z",
"ended_by": "user",
"duration": 300,
"transcript": [
{ "role": "assistant", "text": "Hello, how can I help you today?" },
{ "role": "user", "text": "I have a question about my account." }
],
"summary": "Customer inquired about account balance.",
"recording_url": "https://storage.example.com/recordings/call.wav",
"objective_met": true,
"extraction_data": {
"customer_sentiment": "positive",
"issue_category": "billing"
}
}
}
}Additional Call End Fields
| Field | Type | Description |
|---|---|---|
call.ended_at | string | ISO 8601 timestamp when call ended |
call.ended_by | string | user, agent, or system |
call.duration | number | Call duration in seconds |
call.transcript | array | Array of { role, text } objects |
call.summary | string | AI-generated call summary |
call.recording_url | string | URL to call recording (if enabled) |
call.objective_met | boolean | Whether the call objective was achieved |
call.extraction_data | object | Custom extracted fields (configured per agent) |
Error Handling
- Webhook failures do not stop the call
- If webhook times out or returns invalid JSON, the call continues without enrichment
- Errors are logged but not exposed to end users
- Default timeout: 5000ms (5 seconds), configurable per agent
