Webhook Lifecycle Events

Webhooks allow external systems to personalize calls at call start and receive call details when calls end.

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

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 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