> ## Documentation Index
> Fetch the complete documentation index at: https://www.caretta.so/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Receive Caretta webhooks

> Deliver transcripts, AI notes, and evaluated metrics to your HTTPS endpoint after a call.

Caretta can send signed HTTPS webhooks when call data becomes available. Use webhooks to move transcripts, AI-generated meeting notes, and evaluated metrics into your own systems.

## Quickstart

<Steps>
  <Step title="Add an endpoint">
    As an organisation administrator, open **Settings → Webhooks → Add endpoint** in Caretta and enter a public HTTPS URL.
  </Step>

  <Step title="Choose a delivery mode">
    Select individual events for the lowest latency, or choose a bundled `call.ready` event for one combined payload.
  </Step>

  <Step title="Save the signing secret">
    Copy the signing secret when Caretta shows it. It is displayed once. Store it in a secrets manager or encrypted environment variable.
  </Step>

  <Step title="Send a test">
    Select **Send test** for the endpoint. Caretta sends a `webhook.test` request.
  </Step>

  <Step title="Verify and acknowledge">
    Verify `X-Caretta-Signature` against the raw request body and return a `2xx` response within 10 seconds.
  </Step>
</Steps>

## Events

| Event                | Sent when                                    | Key data                                                |
| -------------------- | -------------------------------------------- | ------------------------------------------------------- |
| `call.completed`     | A captured call finishes processing.         | Call envelope and transcript.                           |
| `call.notes_ready`   | AI-generated notes become available.         | Markdown notes, summary, and next steps.                |
| `call.metrics_ready` | Metric evaluation finishes.                  | Evaluated metrics, or an empty list with a skip reason. |
| `call.ready`         | Every selected bundled component is ready.   | Transcript plus the selected notes and/or metrics.      |
| `webhook.test`       | An administrator sends a test from Settings. | A test message.                                         |

Eligible calls are real calls longer than 60 seconds that have not been deleted. Calls lasting 60 seconds or less, and deleted calls, do not produce delivery events.

## Choose a delivery strategy

### Per-event delivery

Select any combination of `call.completed`, `call.notes_ready`, and `call.metrics_ready`. This is the default and sends each component as soon as it is ready.

Use `call.completed` when you need one reliable event for every eligible call. Use `call.metrics_ready` when you need the evaluation result for every eligible call, including calls that were skipped with a recorded reason.

### Bundled delivery

Bundled mode sends one `call.ready` event after all selected components are ready. The transcript is always included; notes and metrics are optional.

<Warning>
  Notes are best-effort. Roughly 3–4% of calls never generate notes, usually because the desktop app is closed before generation completes and is not reopened. In that case, `call.notes_ready` is not sent and a bundle that requires notes is never delivered. Notes may also arrive seconds or minutes after the transcript, and occasionally hours later.
</Warning>

If you must receive every eligible call:

* Subscribe to `call.completed` using per-event delivery.
* For a reliable single bundle, include metrics but do not require notes.
* If you need a notes-and-metrics bundle, add a second per-event endpoint for `call.completed` as a safety net.

You can configure multiple endpoints and mix delivery modes.

## Verify signatures

Every request includes these headers:

| Header                  | Description                                                            |
| ----------------------- | ---------------------------------------------------------------------- |
| `X-Caretta-Signature`   | `v1=` followed by the hexadecimal HMAC-SHA256 signature.               |
| `X-Caretta-Timestamp`   | Unix timestamp in seconds. Reject requests more than five minutes old. |
| `X-Caretta-Delivery-Id` | Identifier for one delivery attempt. Network retries reuse it.         |
| `X-Caretta-Event-Id`    | Stable idempotency key for the event. Retries reuse it.                |

Caretta signs this exact byte sequence:

```text theme={"system"}
{timestamp}.{raw request body}
```

with your endpoint secret as the HMAC-SHA256 key.

<Warning>
  Verify the original raw request body. Parsing JSON and serialising it again can change whitespace or key order and will break signature verification.
</Warning>

```javascript verify-caretta-signature.js theme={"system"}
const crypto = require("crypto");

function verifyCarettaSignature(req, secret) {
  const timestamp = req.headers["x-caretta-timestamp"];
  const signature = req.headers["x-caretta-signature"];

  if (!timestamp || !signature) return false;
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;

  const expected =
    "v1=" +
    crypto
      .createHmac("sha256", secret)
      .update(`${timestamp}.${req.rawBody}`)
      .digest("hex");

  return (
    expected.length === signature.length &&
    crypto.timingSafeEqual(
      Buffer.from(expected),
      Buffer.from(signature)
    )
  );
}
```

Verify the signature before parsing or acting on the payload. Keep the endpoint secret server-side and rotate it if it may have been exposed.

## Delivery behaviour

* Return any `2xx` response within 10 seconds.
* Delivery is at least once. Deduplicate using `X-Caretta-Event-Id`.
* Event ordering is not guaranteed. Correlate related events with `data.call.id`.
* Failed requests are retried with backoff for approximately two hours.
* Network retries reuse the event and delivery IDs.

A good handler verifies the signature, stores or queues the event, returns `2xx`, and performs slower processing asynchronously.

## Payloads

All events include `event`, `schema_version`, `event_id`, `delivery_id`, and `occurred_at`.

<AccordionGroup>
  <Accordion title="call.completed">
    ```json theme={"system"}
    {
      "event": "call.completed",
      "schema_version": 1,
      "event_id": "evt_01J...",
      "delivery_id": "dlv_01J...",
      "occurred_at": "2026-07-14T18:42:11.000Z",
      "data": {
        "call": {
          "id": "call_01J...",
          "title": "Acme discovery",
          "duration_seconds": 1842,
          "owner": {
            "name": "Alex Morgan",
            "email": "alex@example.com"
          },
          "participants": [
            {
              "name": "Sam Lee",
              "email": "sam@acme.example"
            }
          ]
        },
        "transcript": [
          {
            "speaker": "seller",
            "text": "Thanks for making the time today."
          },
          {
            "speaker": "client",
            "text": "Happy to be here."
          }
        ]
      }
    }
    ```
  </Accordion>

  <Accordion title="call.notes_ready">
    ```json theme={"system"}
    {
      "event": "call.notes_ready",
      "schema_version": 1,
      "event_id": "evt_01J...",
      "delivery_id": "dlv_01J...",
      "occurred_at": "2026-07-14T18:44:32.000Z",
      "data": {
        "call": {
          "id": "call_01J..."
        },
        "notes_markdown": "## Summary\n...",
        "summary": "The team agreed to run a pilot.",
        "next_steps": [
          "Send the security questionnaire",
          "Schedule a technical review"
        ]
      }
    }
    ```
  </Accordion>

  <Accordion title="call.metrics_ready">
    ```json theme={"system"}
    {
      "event": "call.metrics_ready",
      "schema_version": 1,
      "event_id": "evt_01J...",
      "delivery_id": "dlv_01J...",
      "occurred_at": "2026-07-14T18:45:08.000Z",
      "data": {
        "call": {
          "id": "call_01J..."
        },
        "metrics": [
          {
            "slug": "discovery-quality",
            "name": "Discovery quality",
            "value": 0.87,
            "confidence": 0.91,
            "evidence": "The seller confirmed the buyer's current process and impact.",
            "evaluated_at": "2026-07-14T18:45:08.000Z"
          }
        ]
      }
    }
    ```

    A completed evaluation can return an empty `metrics` array with a skip reason. Metrics can be re-evaluated; use `evaluated_at` to identify the latest result.
  </Accordion>

  <Accordion title="webhook.test">
    ```json theme={"system"}
    {
      "event": "webhook.test",
      "schema_version": 1,
      "event_id": "evt_01J...",
      "delivery_id": "dlv_01J...",
      "occurred_at": "2026-07-14T18:40:00.000Z",
      "data": {
        "message": "Caretta webhook test"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

<Note>
  These examples show the payload structure and use illustrative values. Build consumers to tolerate additional fields so they remain compatible as Caretta adds data.
</Note>

## Manage an endpoint

Open **Settings → Webhooks** to:

* enable or disable delivery;
* change the URL, subscribed events, or delivery mode;
* send a test event;
* inspect the delivery log;
* rotate the signing secret; or
* delete the endpoint.

Rotating the secret invalidates the previous secret immediately. Update your receiver before sending another test.

<Note>
  Endpoint management through a public REST API is planned but is not currently available.
</Note>
