VocoAgentsVocoAgents

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

RequestWhen it is sentJSON shape
Lifecycle webhookCall or conversation starts, and when a call endswebhook/lifecycle JSON-RPC envelope
Custom tool callThe agent calls a configured REST API or MCP toolTool arguments + metadata

Both request types include the same authentication headers. See Request Signing & Security.

Webhook Events

EventTrigger
new_outbound_callOutbound call starts
new_inbound_callInbound call starts
call_endedCall 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

FieldTypeDescription
params.eventstringnew_outbound_call or new_inbound_call
params.agent.idstringAgent UUID
params.call.idstringCall UUID
params.call.directionstringinbound or outbound
params.call.channelstringweb, phone, or whatsapp
params.call.userPhoneNumberstringUser'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

FieldTypeDescription
personalization.first_namestringVisitor's first name, used to greet them
personalization.sexstringmale, female, or unknown
personalization.languagestringISO 639-1 language code (e.g., en, es, he)
additional_contextstringAdditional context injected into agent prompt
metadataobjectPass-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

FieldTypeDescription
call.ended_atstringISO 8601 timestamp when call ended
call.ended_bystringuser, agent, or system
call.durationnumberCall duration in seconds
call.transcriptarrayArray of { role, text } objects
call.summarystringAI-generated call summary
call.recording_urlstringURL to call recording (if enabled)
call.objective_metbooleanWhether the call objective was achieved
call.extraction_dataobjectCustom 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