How to send analytics results from CallAIder via webhook

Webhook delivery in CallAIder lets you automatically send dialog analytics results to an external system: CRM, BI dashboard, helpdesk, internal workspace, quality control tool, or any other service that can receive HTTP requests.

This is useful when analytics results should not remain only inside the CallAIder interface. For example, you can automatically create a task for a team lead when a call needs attention, update a customer card in CRM, send quality scores to BI, or store a full history of reviews in your own database.

In this guide, we will cover:

  • where result delivery is enabled;
  • how to configure conditions so only relevant dialogs are sent;
  • which webhook settings need to be filled in;
  • what JSON your system will receive;
  • how to verify the request signature;
  • how to avoid duplicates during retries;
  • how to test the integration before launch.

When to use webhook delivery

Use webhook delivery when an action should happen in another system after a dialog is analyzed.

Common scenarios:

ScenarioWhat webhook delivery can do
Quality controlSend problematic calls to a supervisor or operator quality system.
CRMUpdate a customer card, deal, or request after the conversation is analyzed.
HelpdeskCreate a ticket when a customer is dissatisfied or the issue was not resolved.
BI and reportingCollect scores, analytics fields, duration, and statuses in your own storage.
Internal workflowsTrigger automations: notifications, checks, routing, escalations.

The main benefit is that data is sent automatically after analysis is completed. Your team does not need to export spreadsheets manually or check for new results on a schedule.

How delivery works

From the customer’s point of view, the flow is simple:

  1. A dialog enters CallAIder and is analyzed using an analytics rule.
  2. CallAIder checks whether result delivery is enabled for the team.
  3. If delivery conditions are configured, the result is checked against those conditions.
  4. If the conditions match, or if no conditions are configured, CallAIder sends an HTTP request to the URL specified in the webhook settings.
  5. Your system receives the JSON payload, processes it, and returns an HTTP 2xx status.

Webhook delivery does not block analytics. The analysis result is saved in CallAIder, and the request to your system is sent separately. Because of this, there may be a short delay between analysis completion and webhook arrival.

What to prepare before setup

Before enabling webhook delivery in CallAIder, prepare an endpoint in your system.

Minimum requirements:

  • a public HTTPS URL available from the outside;
  • support for JSON request bodies;
  • a fast 2xx response when the payload is accepted;
  • duplicate-safe handling of repeated requests;
  • request logging during the testing stage.

Also decide in advance which results should be sent:

  • all analytics results for the team;
  • only dialogs with a low score;
  • only results that require attention;
  • only dialogs where a specific analytics field has a specific value;
  • only calls with a certain direction, duration, operator, or other dialog property.

If your system uses authorization, prepare the token or secret that should be sent in an additional HTTP header.

Where delivery is configured

Delivery settings are located in the team creation or editing wizard, on the Delivery step.

This step contains three main sections:

SectionPurpose
Delivery conditionsDefine which analytics results should be sent to the external system.
WebhookConfigure the HTTP request: URL, method, signature, retry count, headers, and payload options.
Email and TelegramFuture delivery channels. They are visible in the interface but do not send results yet.

For webhook delivery to work, enable general result delivery at the top of the Delivery step and then enable the Webhook channel separately.

Delivery step in the CallAIder team wizard

Step 1. Enable result delivery

At the top of the Delivery step, turn on result delivery.

This switch controls delivery for the whole team. If it is disabled, webhook requests will not be sent even if the Webhook section has a URL configured.

After that, move to delivery conditions.

Step 2. Configure delivery conditions

Conditions let you send only the analytics results that matter for your process instead of sending everything.

If no conditions are configured, CallAIder will send all successful analytics results for this team.

This is a good option if you want to keep a full copy of results in your own system or build complete BI reporting.

If the webhook is meant to trigger actions only in specific situations, add conditions. For example:

  • Needs attention = Yes;
  • Total score < 7;
  • Task completed = No;
  • Duration > 180;
  • Direction = incoming.

Condition matching mode

In the conditions section, you can select the matching mode:

ModeHow it works
All conditionsWebhook is sent only when all added conditions match.
Any conditionWebhook is sent when at least one added condition matches.

Example for All conditions:

  • Needs attention = Yes;
  • Total score < 7.

In this case, webhook will be sent only for results that both need attention and have a total score below 7.

Example for Any condition:

  • Needs attention = Yes;
  • Total score < 7.

In this case, webhook will be sent if the result either needs attention or has a low score. This is a broader selection.

Data sources for conditions

A condition consists of a data source, field, operator, and value.

SourceWhat can be checkedExample
Analytics resultTotal score, score, penalty score, attention flag, quality limit flag.Needs attention = Yes, Total score < 7
Analytics fieldDynamic fields configured in the analytics rule.Task completed = No, Target = Yes
Dialog dataCall or dialog data: duration, client, operator, direction, and similar fields.Duration > 180, Direction = incoming

The Analytics field source is especially useful when your analytics rule contains business fields: task status, contact reason, customer intent, consultation result, sale presence, churn risk, and similar values.

Condition operators

Available operators depend on the field type, but the most common ones are:

OperatorExample
EqualsNeeds attention = Yes
Does not equalTask completed != Yes
Greater thanTotal score > 8
Greater than or equal toDuration >= 60
Less thanTotal score < 7
Less than or equal toPenalty score <= 1
ExistsClient email exists
Does not existClient email does not exist
ContainsClient name contains "LLC"

Step 3. Enable webhook

In the Webhook section, turn on Enable webhook.

Then fill in the HTTP request settings.

FieldWhat to enter
URLThe endpoint in your system where CallAIder should send JSON.
MethodHTTP method: POST, PUT, or PATCH. In most cases, use POST.
Signature secretOptional secret used to verify that the request really came from CallAIder.
Retry countHow many times CallAIder should retry delivery if the endpoint returns an error or does not respond.
Include analytics fieldsAdds data.result.fields with dynamic analytics rule fields to the payload.
Include dialogAdds data.result.transcript with a structured dialog transcript to the payload.
Additional headersLets you send custom HTTP headers, for example Authorization.

Recommended starting setup:

  • method: POST;
  • retry count: 3;
  • signature secret: enable it for production endpoints;
  • Include analytics fields: enable it if you need custom analytics field values;
  • Include dialog: enable it only if the external system really needs the transcript.

The transcript can significantly increase payload size. If you only need scores, statuses, and short analytics fields, keep Include dialog disabled.

Step 4. Add authorization headers

If your endpoint is protected by a token, add it in Additional headers.

For example:

Authorization: Bearer <token>

Or, if your system uses a custom header:

X-Api-Key: <api-key>

Do not use additional headers to override CallAIder system headers. Headers such as Content-Type, X-Callaider-Event, X-Callaider-Signature, X-Callaider-Delivery-Id, and Idempotency-Key are generated by the platform.

Step 5. Save the team and run a test analysis

After filling in the settings, save the team.

To test delivery, run a test analysis or wait for a new dialog that matches the analytics rule and delivery conditions.

During testing, it is convenient to use a temporary endpoint such as webhook.site. This lets you see:

  • whether the request arrives;
  • which HTTP method was used;
  • which headers were sent;
  • what JSON was generated;
  • whether the signature is present;
  • whether additional headers were included.

Example received webhook request with analytics result

After verification, replace the test URL with your production endpoint.

What counts as successful delivery

Webhook delivery is considered successful when your endpoint returns an HTTP 2xx status, for example:

  • 200 OK;
  • 201 Created;
  • 202 Accepted;
  • 204 No Content.

If the endpoint returns 4xx, 5xx, does not respond, or takes too long to respond, CallAIder may retry delivery according to the configured retry count.

Because of this, your endpoint should be ready for repeated requests. This is a normal part of reliable delivery.

How your endpoint should behave

Recommendations for a stable integration:

  1. Accept the request body as JSON.
  2. Verify authorization or signature if you use them.
  3. Store Idempotency-Key to avoid duplicates.
  4. Return 2xx when the payload is accepted.
  5. Run heavy processing asynchronously on your side.
  6. Log eventId, resultId, data.analyzableItemId, and X-Callaider-Delivery-Id for diagnostics.
  7. Do not write secrets, tokens, or full personal data to open logs.

A simple rule: the endpoint should quickly accept the event, confirm receipt, and then run longer business logic inside your own system.

Webhook system headers

CallAIder sends webhook requests with a JSON body and system headers.

HeaderDescription
Content-TypeAlways application/json.
X-Callaider-EventEvent type. For analytics results: analytics.result.completed.
X-Callaider-Delivery-IdID of the concrete delivery attempt. Useful for technical logs.
Idempotency-KeyStable key used to prevent duplicates during retries.
X-Callaider-SignatureHMAC signature of the request body. Sent only when a signature secret is configured.

Additional headers configured in webhook settings will also be sent with the request.

Payload format

The request body is always sent as JSON.

General structure:

{
  "event": "analytics.result.completed",
  "timestamp": "2026-07-03T06:27:55.693Z",
  "eventId": "analytics-result-1678",
  "companyId": 1,
  "commandId": 1,
  "ruleItemId": 1,
  "resultId": 1678,
  "data": {
    "eventId": "analytics-result-1678",
    "occurredAt": "2026-07-03T03:27:54.832Z",
    "companyId": 1,
    "commandId": 1,
    "ruleItemId": 1,
    "taskId": 427,
    "analyzableItemId": 19668,
    "result": {},
    "item": {}
  }
}

Top-level payload fields

FieldTypeMeaning
eventstringEvent type. For this webhook: analytics.result.completed.
timestampstringTime when the webhook request was created.
eventIdstringAnalytics result event ID. Useful for logging.
companyIdnumberCompany ID in CallAIder.
commandIdnumber | nullID of the team this result belongs to.
ruleItemIdnumber | nullID of the analytics rule used for analysis.
resultIdnumberID of the concrete analytics result.
dataobjectMain event data: analytics result and dialog data.

Dialog ID vs result ID

For integrations, it is important not to confuse the dialog with the analytics result.

IdentifierMeaningHow to use it
data.analyzableItemIdMain ID of the dialog or other object that was analyzed.Use it as the dialog ID in your system.
data.item.idObject ID in the dialog details block.Usually equals data.analyzableItemId.
resultId / data.result.idID of the concrete analytics result.Use it as the ID of a separate review or analysis version.
eventIdID of the result delivery event.Useful for logging and technical event deduplication.

The same dialog can be analyzed more than once. In that case, data.analyzableItemId stays the same, while resultId and data.result.id will be different.

Recommended storage model in your system:

  • store or update the dialog by data.analyzableItemId;
  • store analytics results as separate records by data.result.id;
  • determine the current result by data.result.analyzedAt or your own business logic.

Do not use resultId as the only dialog ID. It is the analytics result ID, not the dialog ID.

data.result block

data.result contains the analytics result.

FieldTypeMeaning
idnumberID of the concrete analytics result.
scorenumber | string | nullMain score.
penaltyScorenumber | string | nullPenalty score.
totalScorenumber | string | nullFinal score.
lessThanAcceptableLimitbooleanWhether the result is below the acceptable quality limit.
attentionbooleanWhether the result needs attention.
scoringJustificationstring | nullExplanation of score calculation.
penaltyJustificationstring | nullExplanation of penalties.
analyzedAtstring | nullTime when analysis was completed.
fieldsarrayDynamic analytics rule fields. Present only if Include analytics fields is enabled.
transcriptarrayStructured dialog transcript. Present only if Include dialog is enabled.

data.result.fields[] block

The fields array contains fields configured in the analytics rule.

Example:

{
  "name": "Task completed",
  "value": "true",
  "fieldKey": "field_105",
  "fieldType": "boolean",
  "aiJustification": "The operator successfully rescheduled the client's appointment to another date and time."
}
FieldTypeMeaning
namestringField name visible to the CallAIder user.
valuestringValue detected by analytics. For boolean fields, "true" or "false" is sent.
fieldKeystring | nullStable technical field key. Prefer it for mapping.
fieldTypestringField type, for example string, number, boolean.
aiJustificationstring | nullExplanation of why analytics detected this value.

For integrations, it is better to map by fieldKey rather than by field name. The visible name can be changed in the interface, while the technical key is intended for stable mapping.

data.result.transcript[] block

If Include dialog is enabled, the payload will include a structured transcript.

Example:

{
  "text": "Good afternoon, my name is Artem...",
  "speaker": "operator",
  "timestamp": "00:00",
  "speakerName": "Operator"
}
FieldTypeMeaning
textstringPhrase from the dialog.
speakerstringParticipant role, for example operator or client.
timestampstringPhrase timestamp within the dialog.
speakerNamestring | nullParticipant name, if detected.

Enable transcript delivery only when it is required for your scenario. For many integrations, scores, analytics fields, and dialog metadata are enough.

data.item block

data.item contains information about the call or other object that was analyzed.

FieldTypeMeaning
idnumberObject ID in CallAIder. Usually equals data.analyzableItemId.
itemTypestringObject type, for example CALL.
sourceTypestringObject source, for example integration_call.
contentTypestring | nullContent type, for example audio.
commandIdnumber | nullTeam ID.
externalIdstring | nullID in an external system or provider.
clientNumberstring | nullClient phone number.
clientNamestring | nullClient name.
clientEmailstring | nullClient email.
operatorNumberstring | nullOperator number.
operatorIdstring | nullOperator ID in the external system.
operatorNamestring | nullOperator name.
operatorEmailstring | nullOperator email.
directionstring | nullCall direction, for example incoming or outgoing.
startTimestring | nullStart time.
endTimestring | nullEnd time.
durationnumber | nullDuration in seconds.
providerPropertiesobject | nullAdditional provider or integration data.

Short payload example

Below is an example webhook payload. Personal data in the example is anonymized.

{
  "event": "analytics.result.completed",
  "eventId": "analytics-result-1678",
  "resultId": 1678,
  "commandId": 1,
  "companyId": 1,
  "timestamp": "2026-07-03T06:27:55.693Z",
  "data": {
    "eventId": "analytics-result-1678",
    "occurredAt": "2026-07-03T03:27:54.832Z",
    "companyId": 1,
    "commandId": 1,
    "ruleItemId": 1,
    "taskId": 427,
    "analyzableItemId": 19668,
    "result": {
      "id": 1678,
      "score": 2.1,
      "totalScore": 2.1,
      "penaltyScore": 0,
      "attention": true,
      "lessThanAcceptableLimit": false,
      "analyzedAt": "2026-07-03T03:27:54.832Z",
      "scoringJustification": "The operator completed the main conversation stages...",
      "penaltyJustification": "",
      "fields": [
        {
          "name": "Client name",
          "value": "Artem",
          "fieldKey": "field_488",
          "fieldType": "string",
          "aiJustification": "The client introduced himself at the beginning of the conversation."
        },
        {
          "name": "Task completed",
          "value": "true",
          "fieldKey": "field_105",
          "fieldType": "boolean",
          "aiJustification": "The operator successfully rescheduled the client's appointment."
        }
      ],
      "transcript": [
        {
          "text": "Good afternoon, my name is Artem...",
          "speaker": "operator",
          "timestamp": "00:00",
          "speakerName": "Operator"
        }
      ]
    },
    "item": {
      "id": 19668,
      "itemType": "CALL",
      "sourceType": "integration_call",
      "contentType": "audio",
      "commandId": 1,
      "externalId": "6693228761",
      "clientNumber": "050***8290",
      "clientName": "",
      "clientEmail": null,
      "operatorNumber": "722",
      "operatorId": "",
      "operatorName": "Operator",
      "operatorEmail": null,
      "direction": "incoming",
      "startTime": "2026-07-03T06:22:52.000Z",
      "endTime": null,
      "duration": 83,
      "providerProperties": null
    }
  }
}

Signature verification

If Signature secret is configured in webhook settings, CallAIder will add this header:

X-Callaider-Signature: sha256=<hex-hmac>

The signature is generated as HMAC-SHA256 from the raw HTTP request body.

This allows your system to verify that the payload was not changed and that the request was generated using a secret known only to you and CallAIder.

Node.js verification example:

import crypto from 'crypto';

function verifyCallaiderSignature(
  rawBody: string,
  receivedSignature: string | undefined,
  secret: string,
): boolean {
  if (!receivedSignature) {
    return false;
  }

  const expectedSignature =
    'sha256=' +
    crypto.createHmac('sha256', secret).update(rawBody).digest('hex');

  const received = Buffer.from(receivedSignature);
  const expected = Buffer.from(expectedSignature);

  return (
    received.length === expected.length &&
    crypto.timingSafeEqual(received, expected)
  );
}

Important: verify the signature against the raw HTTP request body. Do not verify it against a parsed and re-serialized JSON object, because even a small formatting change will change the HMAC.

Idempotency and retries

A webhook can arrive more than once if a previous attempt was not confirmed with a successful response. For example, the endpoint temporarily returned 500, the request timed out, or the connection was interrupted.

To avoid duplicates:

  1. Store the Idempotency-Key header value.
  2. If a request with the same key has already been processed successfully, do not create a duplicate record.
  3. For a repeated request that does not need new processing, return 2xx.

You can also log eventId, resultId, and X-Callaider-Delivery-Id, but Idempotency-Key is the best key for preventing duplicates of the same delivery.

Also account for repeated analysis of the same dialog:

  • if you need to update a dialog card, find it by data.analyzableItemId;
  • if you need to keep analysis history, create a separate record for each data.result.id;
  • do not use resultId as the only dialog identifier.

Practical setup scenarios

Send all analytics results for a team

Use this scenario when your system needs a full copy of analytics results.

Settings:

  • general result delivery is enabled;
  • webhook is enabled;
  • URL is filled in;
  • no conditions are configured;
  • Include analytics fields is enabled if needed.

Result: CallAIder will send all successful analytics results for this team.

Send only problematic calls

Use this scenario for quality control, escalations, and supervisor tasks.

Settings:

  • condition mode: Any condition;
  • condition 1: Needs attention = Yes;
  • condition 2: Total score < 7.

Result: webhook will arrive for calls that need attention or have a low score.

Send only calls where the task was not completed

Use this scenario when your analytics rule has a field that defines conversation outcome.

Settings:

  • source: Analytics field;
  • field: Task completed;
  • operator: Equals;
  • value: No.

Result: webhook will arrive only when analytics determines that the task was not completed.

Send only long inbound calls with a low score

Use this scenario when you need to review complex or potentially problematic requests.

Settings:

  • condition mode: All conditions;
  • condition 1: Direction = incoming;
  • condition 2: Duration > 180;
  • condition 3: Total score < 7.

Result: webhook will arrive only for inbound calls longer than three minutes with a result below the required level.

Common issues and checks

Webhook does not arrive

Check:

  • whether general result delivery is enabled on the Delivery step;
  • whether the Webhook switch is enabled;
  • whether the URL is correct;
  • whether the endpoint is publicly reachable;
  • whether the analytics result actually matches delivery conditions;
  • whether the endpoint returns an error or times out.

For diagnostics, temporarily remove conditions or use a test endpoint to confirm that requests are being generated.

Payload does not contain analytics fields

Check whether Include analytics fields is enabled.

Also make sure the analytics rule has dynamic fields configured that should appear in data.result.fields.

Payload does not contain transcript

Check whether Include dialog is enabled.

If transcript is not required for your process, keep this option disabled so the payload remains smaller.

Endpoint returns 401 or 403

Check:

  • whether the required Authorization or X-Api-Key header is configured;
  • whether the token contains extra spaces;
  • whether your system expects a different header name;
  • whether firewall or reverse proxy rules block the request.

Signature does not match

Most common causes:

  • wrong secret is used;
  • signature is checked against something other than the raw request body;
  • middleware parses JSON before signature verification and changes the body format;
  • code uses a different encoding or algorithm.

HMAC verification requires the raw body received before any transformation.

Duplicates appear in the external system

Check whether you store Idempotency-Key and whether you avoid creating a new record for a key that has already been processed.

If dialogs and analytics results are stored separately, make sure that:

  • the dialog is identified by data.analyzableItemId;
  • the analytics result is identified by data.result.id;
  • repeated delivery does not create a duplicate of the same event.
  1. Prepare an HTTPS endpoint in your system.
  2. Make sure the endpoint accepts JSON and returns 2xx.
  3. Add authorization or signature verification.
  4. Open the team creation or editing wizard.
  5. Go to the Delivery step.
  6. Enable result delivery.
  7. Add conditions or leave the list empty to send all results.
  8. Enable Webhook.
  9. Enter the endpoint URL.
  10. Select the method, usually POST.
  11. Add Authorization or other headers if needed.
  12. Set a signature secret if needed.
  13. Choose whether to include analytics fields and dialog transcript.
  14. Save the team.
  15. Run a test analysis and verify that the request is received.
  16. Confirm that repeated requests do not create duplicates.
  17. Replace the test endpoint with the production URL if you tested through an external service.

Current limitations

  • Result delivery is currently implemented through webhook.
  • Email and Telegram are visible in the form as future delivery channels, but they do not send results yet.
  • Delivery is asynchronous, so the webhook may arrive with a short delay after analysis completion.
  • Delivery is considered successful only when your endpoint returns a 2xx status.

A correctly configured webhook turns dialog analytics from a separate report into part of your operational workflow. CallAIder identifies important results, and your system immediately receives structured data for CRM, reporting, quality control, or automation of next steps.