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

# Webhook request body

> Callback envelope, event field, and per-product payloads

## What it is

When an **async** task finishes, VMEG sends an **HTTP POST** with a JSON body to your configured webhook URL. Verify `X-Timestamp` and `X-Signature` as described in [Webhook verification](/guides/webhook-verification).

The `create-async` HTTP response only confirms acceptance (`taskId`, etc.). **Deliverables arrive in this webhook body**, not in that response.

## Common envelope

All async completion callbacks share the same top-level shape. Product-specific fields live in `data`:

```json theme={null}
{
  "code": 200,
  "version": "v1",
  "event": "openapi-tts",
  "pipelineKey": "a1b2c3d4e5f6789012345678901234ab",
  "message": "",
  "extraData": { "your": "memo" },
  "data": { }
}
```

| Field         | Meaning                                                                              |
| ------------- | ------------------------------------------------------------------------------------ |
| `code`        | Outcome of this delivery (`200` = task succeeded)                                    |
| `version`     | API version of the task (e.g. `v1`, `v2`)                                            |
| `event`       | **Which product finished** — see table below                                         |
| `pipelineKey` | **Stable ID for this async completion** — use for receiver deduplication (see below) |
| `message`     | Detail when `code` is not success                                                    |
| `extraData`   | Echo of `extraData` from your async submit request (if you sent it)                  |
| `data`        | Task results; schema depends on `event`                                              |

## Deduplicate by `pipelineKey`

VMEG assigns one **`pipelineKey` per accepted async run**. It appears in every webhook POST for that completion.

| Situation                          | What to do                                                          |
| ---------------------------------- | ------------------------------------------------------------------- |
| First time you see a `pipelineKey` | Verify signature, process `data`, persist the key, return 2xx       |
| Same `pipelineKey` again (retry)   | Return 2xx quickly; **do not** repeat billable or irreversible work |

<Info>
  `pipelineKey` is for **webhook delivery** deduplication. It is not the same as [`X-Idempotency-Key`](/guides/idempotency) on `create-async` (which prevents duplicate task submission). One accepted async job has one `pipelineKey`; `data.taskId` identifies the task but retries are keyed by `pipelineKey`.
</Info>

## The `event` field

`event` is a **string in the JSON body** that tells your server which Open API product completed. Use it to route parsing logic (switch on `event`, then read `data`).

<Note>
  In [API reference](/api-reference/introduction), the **Callbacks** block on each `create-async` page is named for OpenAPI tooling. The value you must implement against is the **`event` field inside the POST JSON**, not that section title.
</Note>

### Event values by product

| Product                                                 | `event` value               | Async create endpoint                                                                               | What to read in `data`                                         |
| ------------------------------------------------------- | --------------------------- | --------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
| [Text to speech](/guides/products/text-to-speech)       | `openapi-tts`               | [Create TTS (async)](/api-reference/tts/create-tts-async)                                           | Synthesis `results`, `taskId` — see **Callbacks** on that page |
| [Text translation](/guides/products/text-translation)   | `openapi-translate`         | [Create text translation (async)](/api-reference/text-translation/create-text-translation-async)    | `items` (translated segments), `taskId`                        |
| [Voice clone](/guides/products/voice-clone)             | `openapi-clone-voice`       | [Create voice clone (async)](/api-reference/clone-voice/create-voice-clone-async)                   | `voiceId` and related clone fields when successful             |
| [Media translation](/guides/products/media-translation) | `openapi-media-translation` | [Create media translation (async)](/api-reference/media-translation/create-media-translation-async) | `result` with CDN URLs for deliverables                        |

Today, async task completion uses **only** these four `event` values. If we add more callback types later, they will be documented here and in the matching **Callbacks** schema.

### Example handler routing

```text theme={null}
POST /your-webhook
  → verify signature
  → parse JSON
  → if pipelineKey already processed → return 200
  → switch (event):
       openapi-tts              → parse TTS data
       openapi-translate        → parse translation data
       openapi-clone-voice      → parse clone data
       openapi-media-translation → parse media result
  → store pipelineKey → return 200
```

## Per-endpoint request schema

Field-level types and nested properties are defined under **Callbacks** on each `create-async` operation in API reference (linked in the table above).
