Skip to main content

Overview

The custom integration feature allows you to send call transcripts from your own backend system or third-party service to Cekura via webhooks. This provides flexibility to integrate any voice platform while maintaining full control over your conversation data.

How It Works

  1. Configure your agent in Cekura and select “Custom” as the provider
  2. Cekura provides you with a webhook URL
  3. After each call ends, send the call data to the webhook URL
  4. Cekura listens for call data for 5 minutes after the call ends
  5. View evaluation results in the Cekura dashboard

Setup

In Cekura Dashboard

  1. Create or edit an agent in the Cekura dashboard
  2. Set the transcript provider to “Custom”
  3. Copy the webhook URL provided by Cekura
  4. Note your API key for authentication
One webhook URL per project: Cekura provides a single webhook URL per project. If you need separate webhook destinations for different environments (e.g., development vs. production), create separate projects in Cekura — each project gets its own webhook URL and API key. This is the recommended approach for environment isolation.

Webhook Implementation Requirements

Your system should send call transcripts to the Cekura webhook with the following specifications: HTTP Method: POST Headers:
Timing: Send the call data within 5 minutes after the call ends. Cekura will listen for webhooks for 5 minutes after the call ends.

Payload Format

Your webhook POST request should send a JSON payload with the following structure:

Top Level Structure

agent_id is required unless every call object in calls includes a run_id field. If you already have a Cekura Run ID for each call before sending the webhook — for example, when using SIP integrations where run IDs are available from SIP headers — you can omit agent_id entirely and include run_id on each call object instead. In this case, Cekura will trust the provided run IDs and match transcripts directly to the existing runs.

Call Object Structure

Each call in the calls array should include:
Passing a recording URL: The custom integration payload does not have a dedicated voice_recording_url field. To include a recording URL (or any other custom call context), add it to the metadata object:
You can then reference it in metrics:
  • LLM Judge metrics: use {{metadata.recording_url}} in your metric description
  • Python metrics: use data["metadata"]["recording_url"]
See Metric Variables for the full reference of variables available in metrics.

Message Object Structure

Each message in the messages array should include:
For function call messages, use the data field to include the tool call details. See the Transcript Format page for examples of how to structure function_call and function_call_result messages in Cekura format.

Complete Example

Here’s a complete example payload with two calls:

SIP / Pre-known Run ID Example

If you are using a SIP integration and already have Cekura Run IDs available from SIP headers before sending the webhook, you can omit agent_id at the top level and include run_id on each call instead. Cekura will trust the provided run IDs and attach the transcripts directly to the matching runs — no agent lookup needed.
When using run_id per call, every call in the calls array must include a run_id. Mixing calls with and without run_id in the same payload (when agent_id is absent) is not supported.

Important Considerations

For successful webhook integration, ensure:
  1. Timing: Send the call data within 5 minutes after the call ends
  2. Authentication: Include the X-CEKURA-API-KEY header with your API key
  3. Phone Numbers: Phone numbers must start with + followed by digits (max 15 chars, e.g., ‘+14155551234’). The to_phone_number should match the scenario’s inbound number for testing
  4. Timestamps: Use ISO 8601 format for startedAt and endedAt
  5. Message Timing: Use milliseconds from epoch for message start_time and end_time (optional fields)
  6. Agent ID: Use the correct agent ID from your Cekura dashboard. If you have a Cekura Run ID available ahead of time (e.g. from SIP headers), you can omit agent_id and include run_id on each call object instead — Cekura will match transcripts directly to the existing runs
  7. Unique Call IDs: Each call should have a unique identifier (max 255 chars)
  8. Metadata: Use the metadata field to pass additional key-value pairs for call information

Troubleshooting

If your webhook integration isn’t working as expected:

No calls appear in Cekura

  • Verify the webhook URL is correct
  • Check that the X-CEKURA-API-KEY header is included and correct
  • Ensure the payload format matches the specification
  • Confirm the agent_id is correct
  • Verify the call data was sent within 5 minutes after the call ended

Authentication issues

  • Double-check your API key is correct
  • Ensure the header name is exactly X-CEKURA-API-KEY (case-sensitive)
  • Verify the API key has proper permissions

Calls not matching scenarios

  • Confirm the to_phone_number in the payload matches the scenario’s inbound number
  • Ensure phone numbers start with + followed by digits (max 15 chars)
  • Check that the call ID is unique and under 255 characters
  • Verify timestamps are in ISO 8601 format

Invalid payload errors

  • Validate your JSON payload structure
  • Ensure all required fields are present (id, startedAt, endedAt)
  • Verify the agent_id is an integer, not a string (required unless each call includes a run_id)
  • Check that phone numbers follow the correct format (+ followed by digits, max 15 chars)
  • Ensure messages is an array with dictionaries containing role and content fields

Mock Tools (optional)

If your agent calls tools and you want to test it without hitting live third-party services, use Mock Tools. There are two ways to wire mocking into a custom / self-hosted integration:
  • MCP auto-discovery (recommended if your agent uses an MCP server). Cekura reads your tool list directly from your own MCP server, generates mock data, and then hosts a drop-in mock MCP endpoint you point your agent at during test runs. No per-tool wiring. Covered in Mock an MCP server.
  • Per-tool webhooks (works for any agent). Point each tool at its individual Cekura mock endpoint. Covered in Per-tool webhook mocking.
Whichever you use, you must also report each tool call in your transcript — otherwise tool-based metrics have nothing to score against.

Mock an MCP server

If your self-hosted agent talks to an MCP server (JSON-RPC 2.0) for its tools, Cekura can discover those tools automatically and stand in for the server during tests. You never rewrite individual tool URLs — you swap one MCP endpoint. Prerequisite: your agent’s MCP server must be reachable by Cekura and expose the standard tools/list method. Provide any auth as headers; they are stored encrypted.
1

Auto-fetch tools from your MCP server

Call auto-fetch with provider="custom" and your MCP server URL. Cekura queries tools/list, LLM-generates realistic mock input/output data for each tool from your agent’s context, and registers them all under a single Cekura-hosted mock MCP endpoint.
Returns a progress_id. Poll GET .../tools/auto-fetch-progress/?progress_id=<id> until status is completed. That’s the only setup call — there is no separate “enable” step for a self-hosted agent.
The mcp_server_url is validated before any request is made: only http/https schemes are allowed, private / loopback / link-local / cloud-metadata addresses are blocked (DNS is resolved and checked), and headers that could rewrite the request (Host, Cookie, X-Forwarded-*) are rejected. Headers are stored encrypted. An agent is pinned to a single MCP server — re-running auto-fetch with the same URL refreshes the tools; switching to a different URL requires deleting the existing mock tools first.
2

Review and edit the generated mock data

List the tools with GET .../tools/ and refine any input/output mappings (PATCH the mock tool). Add one entry per input variation your evaluators exercise — see Handling Dynamic Input Parameters. Re-running auto-fetch preserves tools that already have mock data.
3

Get your mock MCP endpoint URL

Read GET .../tools/mock-status/ — it returns the stable Cekura-hosted MCP endpoint for your agent under mcp_endpoints[]:
Always read the URL from the API — don’t hand-build it, so it stays correct across environments.
4

Point your agent at the mock endpoint during test runs

Configure your agent’s MCP client to use mcp_endpoints[0].url instead of your real MCP server for the duration of a test. It is a standard MCP JSON-RPC 2.0 server (initialize, tools/list, tools/call) and requires no authentication. A tools/call returns your configured mock output:
Enabling and disabling mocking is entirely on your side: point the MCP client at this URL to use the mocks, or back at your real server to stop. Cekura can’t reach into a self-hosted agent to flip it for you.
The mock MCP endpoint makes your tools respond correctly, but the Mock Tool Call Accuracy metric scores the transcript, not the endpoint. You must still emit a function_call message per tool call in the transcript you post — see Report the tool call in your transcript below.

Per-tool webhook mocking

If your agent does not use MCP, mock each tool individually. There are two pieces — both required for tool-based evaluation to work. 1. Call the Cekura mock endpoint during the call. Point the tool at its Cekura mock endpoint instead of the real service. During the call, your agent makes a normal HTTP request and gets back the mock output you configured.
  • Method: POST
  • Body: the tool’s arguments as a flat JSON object — the same shape as the input in your mock configuration. For example, a tool whose mock entry is {"input": {"user_id": 1}, ...} is called with body {"user_id": 1}.
  • Authentication: include your X-CEKURA-API-KEY header. A missing or wrong key is the most common cause of a mock call failing.
  • The endpoint matches your request against the configured input/output mappings and returns the matching output.
See the Mock Tool API reference for the exact endpoint and request/response schema.

Report the tool call in your transcript

Calling the mock endpoint makes the tool respond correctly during the call, but it does not by itself tell Cekura’s metrics that a tool was used. The Mock Tool Call Accuracy metric (and any tool-based metric) reads the transcript to determine what was called. So your webhook messages array must include a function_call message for each tool call, carrying the tool name and arguments in its data object:
Include the paired result as well (recommended):
If you omit these function_call messages, the Mock Tool Call Accuracy metric will report the tool as not called and the result will fail — even when the tool was actually called and used correctly during the call. The mock endpoint being hit is not visible to the metric; only the transcript is.
A tool that takes no input must still send "arguments": {}. See Transcript Format for a complete transcript example with function calls.

Next Steps