> ## Documentation Index
> Fetch the complete documentation index at: https://developer.suki.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook Payload & Response

> Learn about the structure of the webhook payload and response

Suki sends each notification as a <Badge color="blue" size="sm">POST</Badge> with **`Content-Type: application/json`**. Every delivery includes headers you use to verify the request before you trust the body:

| Header             | What it is                                                                                                                            |
| :----------------- | :------------------------------------------------------------------------------------------------------------------------------------ |
| **`X-API-Key`**    | Hex-encoded **HMAC-SHA-256** signature of this request (see [Signature verification](/documentation/webhook/signature-verification)). |
| **`generated-at`** | Unix time in **milliseconds** for when Suki built the request. Use it to spot stale or replayed traffic.                              |

Your handler should verify those headers first, then read the top-level **`status`** field in the JSON and branch on **`"success"`** or **`"failure"`**.

For the full request specification and sample handler code in Python and TypeScript, refer to the [Asynchronous notifications (webhook)](/api-reference/asynchronous/webhook) API reference.

## Payload structure

Every webhook body includes a top-level `status` field. All other fields depend on that value.

**When `status` is `"success"`:** The payload identifies the session and encounter and provides links to retrieve results. It includes:

* `session_id`, `encounter_id` (always present)
* Optionally: `sessions`, `additional_info`, `_links`

**Inside `_links`**, each key is an array of link objects (`href`, `method`, `name`, `type`).

Following are the keys you will see in the `_links` object:

* **`contents`:** Session-level note content.
* **`encounter_content`:** Encounter-level content.
* **`structured_data`:** Session-level structured clinical data.
* **`encounter_structured_data`:** Encounter-level structured clinical data.
* **`status`:** Status checks.
* **`transcripts`:** Transcripts.

<Note>
  Use the **`_links`** object to get URLs for fetching session content, encounter content, structured clinical data, status, and transcripts from the Ambient APIs. For each link, combine its **`href`** with your API base URL and use the correct authentication when you call those follow-up APIs.

  The **`sessions`** array lists the session IDs tied to the encounter so far.
</Note>

**When `status` is `"failure"`:** The payload identifies the session and encounter and describes the error. It includes:

* `session_id`, `encounter_id`, `error_code`, `error_detail`

Use these fields to log the failure, trigger alerts, or show an error in your application.

For a summary of completion, failure, timeout, and cancellation events, refer to [Event types](/documentation/webhook/event-types).

## Example payloads

The following examples show the JSON bodies your endpoint receives. Use them to validate your parser and to see how the structure maps to the description above.

**Success:**

When a session completes and note generation succeeds, your endpoint receives a payload like this:

```json JSON theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
{
  "_links": {
    "contents": [
      {
        "href": "/path/to/resource", // the URL to fetch the session content
        "method": "GET",
        "name": "name",
        "type": "application/json"
      }
    ],
    "encounter_content": [
      {
        "href": "/path/to/resource", // the URL to fetch the encounter content
        "method": "GET",
        "name": "name",
        "type": "application/json"
      }
    ],
    "structured_data": [
      {
        "href": "/path/to/resource",
        "method": "GET",
        "name": "name",
        "type": "application/json"
      }
    ],
    "encounter_structured_data": [
      {
        "href": "/path/to/resource",
        "method": "GET",
        "name": "name",
        "type": "application/json"
      }
    ],
    "status": [
      {
        "href": "/path/to/resource", // the URL to fetch the status
        "method": "GET",
        "name": "name",
        "type": "application/json"
      }
    ],
    "transcripts": [
      {
        "href": "/path/to/resource", // the URL to fetch the transcripts
        "method": "GET",
        "name": "name",
        "type": "application/json"
      }
    ]
  },
  "additional_info": {
    "priority": "high"
  },
  "encounter_id": "4d753ce1-bbff-43e1-950a-82dea2d86873",
  "session_id": "a953839a-ddcd-407d-b9b0-3ed4b6be4be2",
  "sessions": [
    "20965414-929a-4f71-a3e5-b92bec07d086",
    "29de56bc-960a-4cd5-b18f-79a798d62874"
  ],
  "status": "success"
}
```

Combine each `href` in `_links` with your API base URL and send a <Badge color="green" size="sm">GET</Badge> request with the appropriate authentication to retrieve content, structured data, encounter resources, status, or transcripts. The `sessions` array lists all session IDs for this encounter.

**Failure:**

When a session or note generation fails, your endpoint receives a payload like this:

```json JSON theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
{
  "encounter_id": "29de56bc-960a-4cd5-b18f-79a798d62874", // the ID of the encounter that failed
  "error_code": "ERROR_CODE_TRANSCRIPTION", // the error code that occurred
  "error_detail": "Error in transcription", // the error detail
  "session_id": "20965414-929a-4f71-a3e5-b92bec07d086", // the ID of the session that failed
  "status": "failure"
}
```

Use `error_code` and `error_detail` to log the failure, send an alert, or display an error to the user.

## Implementation tips

<Tip>
  * Return **200 OK** quickly and do heavy work (follow-up API calls, database updates) in a background job or queue.
  * Treat the handler as idempotent; use `session_id` to detect duplicate deliveries and process each notification only once.
  * Check **`generated-at`** and reject requests that are too old for your risk window, so replayed calls are less useful to an attacker.
  * Store the **secret key** in a secrets manager (for example AWS Secrets Manager or Azure Key Vault), not in source control.
  * Add **rate limiting** on the public URL so abuse is harder.
  * Keep the endpoint highly available (for example a load balancer or redundant instances).
  * Log that a webhook was received plus `session_id`, `encounter_id`, and `status`; avoid logging full bodies if they contain sensitive data.
</Tip>

## Responses from Suki webhook endpoint

When you call the Suki Webhook Endpoint (for example, using the `href` values in `_links` to fetch content, status, or transcripts), Suki returns an HTTP status and, for errors, a JSON body with `code` and `message`.

| Code    | Description                                                                                                          |
| ------- | -------------------------------------------------------------------------------------------------------------------- |
| **200** | OK. The request succeeded.                                                                                           |
| **400** | Bad Request. The request was invalid. Example: `{"code": 400, "message": "invalid request"}`                         |
| **401** | Unauthorized. The token is invalid or authentication failed. Example: `{"code": 401, "message": "invalid token"}`    |
| **500** | Internal Server Error. The server encountered an error. Example: `{"code": 500, "message": "internal server error"}` |

In your application, handle `401` by re-authenticating or refreshing the token. Handle `400` by fixing the request or showing an error. Consider retrying on `5xx` when appropriate.
