# Webhooks and events API

> Where events go, how each delivery went, and the record of every event.

Send `Authorization: Bearer vk_test_...` on every call.

## `POST /v1/webhooks`

Its own page: [POST /v1/webhooks](https://vestra.ai/developers/reference/api/webhooks-and-events/post-v1-webhooks.md)

Register a URL and the events it wants. The signing secret is shown once.

Your API key, scope `setup` or `all`. On the card: [`events`](https://vestra.ai/developers/events.md). Every call here is a checked sample.

### Request

Body:

- `url` (`string (URL)`, required): Where to send the events: a public https URL, at most 2,048 characters. Private, local and internal addresses are refused. Limits: at most 2048 characters. Example: `https://api.example.com/vestra`.
- `events` (`(string | "*")[]`, required): The events it wants: 1 to 40 types, or * for all. Limits: 1 to 40 items.
- `description` (`string`): A note for you, in at most 500 characters. Limits: at most 500 characters.
- `active` (`boolean`): Whether to send to it. Default: true. Default: `true`.

### Answers 201

- `id` (`string`): The endpoint (whk_...). Example: `whk_2bq`.
- `object` (`"webhook_endpoint"`): Always webhook_endpoint.
- `url` (`string`): Where the events go.
- `events` (`(string | "*")[]`): The events it wants.
- `description` (`string | null`): Your note; null when you gave none.
- `active` (`boolean`): Whether events are sent to it.
- `mode` (`"live" | "test"`): The mode it hears: test or live, the mode of the key that made it. A test endpoint never hears a live event.
- `deployment_id` (`string | null`): Only this deployment's events reach it (dep_...), plus your account's, such as keys, users and usage alerts. Set when a deployment's vestra.yaml declared the endpoint. Null: every event its types allow.
- `managed_by` (`"file" | null`): file: declared in that deployment's vestra.yaml, so deploying the file changes it; null: you made it.
- `created_at` (`string`): When it was made, as an ISO 8601 time.
- `updated_at` (`string`): When it last changed, as an ISO 8601 time.
- `secret` (`string`): The signing secret, shown this once: check every delivery against it (the Vestra-Signature header). Keep it on your server. Example: `whsec_...`.

### Code

**TypeScript**

```ts
const endpoint = await vestra.events.to('https://hooks.example.com/vestra');
```

**Python**

```python
endpoint = vestra.events.to("https://hooks.example.com/vestra")
```

**CLI**

```bash
vestra events --to https://hooks.example.com/vestra
```

**HTTP**

```bash
# Stream a conversation live. If the connection drops, reconnect with the last seq you saw.
curl -N "$VESTRA_BASE_URL/v1/conversations/conv_8f2k/events" \
  -H "Authorization: Bearer $VESTRA_API_KEY" \
  -H "Last-Event-ID: 41"

# Read the same events as JSON. You get them in pages, after the seq you give.
curl "$VESTRA_BASE_URL/v1/conversations/conv_8f2k/events?format=json&after=41" \
  -H "Authorization: Bearer $VESTRA_API_KEY"

# Read a task afterwards. You get every step of one task, with tokens and cost per turn.
curl "$VESTRA_BASE_URL/v1/tasks/task_91d/trace" \
  -H "Authorization: Bearer $VESTRA_API_KEY"

# Send events to your server. Register a URL and the events it wants. The signing secret is shown only once.
curl "$VESTRA_BASE_URL/v1/webhooks" \
  -H "Authorization: Bearer $VESTRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://hooks.example.com/vestra", "events": ["task.completed", "interaction.created", "usage.cap_reached"] }'

# Catch up on what you missed. List the events your webhooks were sent, newest first.
curl "$VESTRA_BASE_URL/v1/events?type=task.failed" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**MCP**

```json
{
  "method": "tools/call",
  "params": {
    "name": "events",
    "arguments": { "user": "traveller-42", "conversation": "conv_8f2k", "after": 0 }
  }
}
```

## `GET /v1/webhooks`

Its own page: [GET /v1/webhooks](https://vestra.ai/developers/reference/api/webhooks-and-events/get-v1-webhooks.md)

Your endpoints.

Your API key, scope `setup` or `all`. On the card: [`events`](https://vestra.ai/developers/events.md). Over HTTP it is made from the contract: fill in every value.

### Request

Query:

- `limit` (`integer`): How many items per page, 1 to 100. Default 20.
- `cursor` (`string`): Where to go on from: the `next_cursor` of the page before, unchanged. Absent: the first page.

### Answers 200

- `data` (`object[]`): The items on this page.
  - `id` (`string`): The endpoint (whk_...). Example: `whk_2bq`.
  - `object` (`"webhook_endpoint"`): Always webhook_endpoint.
  - `url` (`string`): Where the events go.
  - `events` (`(string | "*")[]`): The events it wants.
  - `description` (`string | null`): Your note; null when you gave none.
  - `active` (`boolean`): Whether events are sent to it.
  - `mode` (`"live" | "test"`): The mode it hears: test or live, the mode of the key that made it. A test endpoint never hears a live event.
  - `deployment_id` (`string | null`): Only this deployment's events reach it (dep_...), plus your account's, such as keys, users and usage alerts. Set when a deployment's vestra.yaml declared the endpoint. Null: every event its types allow.
  - `managed_by` (`"file" | null`): file: declared in that deployment's vestra.yaml, so deploying the file changes it; null: you made it.
  - `created_at` (`string`): When it was made, as an ISO 8601 time.
  - `updated_at` (`string`): When it last changed, as an ISO 8601 time.
- `next_cursor` (`string | null`): Send it as `cursor` for the next page; null on the last page.

### Code

**HTTP**

```bash
curl "$VESTRA_BASE_URL/v1/webhooks" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**TypeScript, Python, CLI, MCP**: No sample in your language for this route, so here it is over HTTP.

## `GET /v1/webhooks/{endpoint_id}`

Its own page: [GET /v1/webhooks/{endpoint_id}](https://vestra.ai/developers/reference/api/webhooks-and-events/get-v1-webhooks-endpoint-id.md)

One endpoint.

Your API key, scope `setup` or `all`. On the card: [`events`](https://vestra.ai/developers/events.md). Over HTTP it is made from the contract: fill in each {…} and every value.

### Request

Path:

- `endpoint_id` (`string`, required): The webhook endpoint's id (`whk_...`).

### Answers 200

- `id` (`string`): The endpoint (whk_...). Example: `whk_2bq`.
- `object` (`"webhook_endpoint"`): Always webhook_endpoint.
- `url` (`string`): Where the events go.
- `events` (`(string | "*")[]`): The events it wants.
- `description` (`string | null`): Your note; null when you gave none.
- `active` (`boolean`): Whether events are sent to it.
- `mode` (`"live" | "test"`): The mode it hears: test or live, the mode of the key that made it. A test endpoint never hears a live event.
- `deployment_id` (`string | null`): Only this deployment's events reach it (dep_...), plus your account's, such as keys, users and usage alerts. Set when a deployment's vestra.yaml declared the endpoint. Null: every event its types allow.
- `managed_by` (`"file" | null`): file: declared in that deployment's vestra.yaml, so deploying the file changes it; null: you made it.
- `created_at` (`string`): When it was made, as an ISO 8601 time.
- `updated_at` (`string`): When it last changed, as an ISO 8601 time.

### Code

**HTTP**

```bash
curl "$VESTRA_BASE_URL/v1/webhooks/{endpoint_id}" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**TypeScript, Python, CLI, MCP**: No sample in your language for this route, so here it is over HTTP.

## `PATCH /v1/webhooks/{endpoint_id}`

Its own page: [PATCH /v1/webhooks/{endpoint_id}](https://vestra.ai/developers/reference/api/webhooks-and-events/patch-v1-webhooks-endpoint-id.md)

Change URL or events, switch it on or off.

Your API key, scope `setup` or `all`. On the card: [`events`](https://vestra.ai/developers/events.md). Over HTTP it is made from the contract: fill in each {…} and every value.

### Request

Path:

- `endpoint_id` (`string`, required): The webhook endpoint's id (`whk_...`).

Body:

- `url` (`string (URL)`): A new public https URL. Limits: at most 2048 characters.
- `events` (`(string | "*")[]`): The events it wants now: 1 to 40 types, or * for all. Limits: 1 to 40 items.
- `description` (`string | null`): A new note; null clears it. Limits: at most 500 characters.
- `active` (`boolean`): false stops sending to it, until you set true again.

### Answers 200

- `id` (`string`): The endpoint (whk_...). Example: `whk_2bq`.
- `object` (`"webhook_endpoint"`): Always webhook_endpoint.
- `url` (`string`): Where the events go.
- `events` (`(string | "*")[]`): The events it wants.
- `description` (`string | null`): Your note; null when you gave none.
- `active` (`boolean`): Whether events are sent to it.
- `mode` (`"live" | "test"`): The mode it hears: test or live, the mode of the key that made it. A test endpoint never hears a live event.
- `deployment_id` (`string | null`): Only this deployment's events reach it (dep_...), plus your account's, such as keys, users and usage alerts. Set when a deployment's vestra.yaml declared the endpoint. Null: every event its types allow.
- `managed_by` (`"file" | null`): file: declared in that deployment's vestra.yaml, so deploying the file changes it; null: you made it.
- `created_at` (`string`): When it was made, as an ISO 8601 time.
- `updated_at` (`string`): When it last changed, as an ISO 8601 time.

### Code

**HTTP**

```bash
curl -X PATCH "$VESTRA_BASE_URL/v1/webhooks/{endpoint_id}" \
  -H "Authorization: Bearer $VESTRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```

**TypeScript, Python, CLI, MCP**: No sample in your language for this route, so here it is over HTTP.

## `DELETE /v1/webhooks/{endpoint_id}`

Its own page: [DELETE /v1/webhooks/{endpoint_id}](https://vestra.ai/developers/reference/api/webhooks-and-events/delete-v1-webhooks-endpoint-id.md)

Remove it.

Your API key, scope `setup` or `all`. On the card: [`events`](https://vestra.ai/developers/events.md). Over HTTP it is made from the contract: fill in each {…} and every value.

### Request

Path:

- `endpoint_id` (`string`, required): The webhook endpoint's id (`whk_...`).

### Answers 200

- `id` (`string`): The endpoint (whk_...).
- `object` (`"webhook_endpoint"`): Always webhook_endpoint.
- `deleted` (`true`): Always true: nothing more is sent to it.

### Code

**HTTP**

```bash
curl -X DELETE "$VESTRA_BASE_URL/v1/webhooks/{endpoint_id}" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**TypeScript, Python, CLI, MCP**: No sample in your language for this route, so here it is over HTTP.

## `POST /v1/webhooks/{endpoint_id}/roll-secret`

Its own page: [POST /v1/webhooks/{endpoint_id}/roll-secret](https://vestra.ai/developers/reference/api/webhooks-and-events/post-v1-webhooks-endpoint-id-roll-secret.md)

New signing secret; the old one is accepted for 24 hours.

Your API key, scope `setup` or `all`. On the card: [`events`](https://vestra.ai/developers/events.md). Over HTTP it is made from the contract: fill in each {…} and every value.

### Request

Path:

- `endpoint_id` (`string`, required): The webhook endpoint's id (`whk_...`).

### Answers 200

- `id` (`string`): The endpoint (whk_...). Example: `whk_2bq`.
- `object` (`"webhook_endpoint"`): Always webhook_endpoint.
- `url` (`string`): Where the events go.
- `events` (`(string | "*")[]`): The events it wants.
- `description` (`string | null`): Your note; null when you gave none.
- `active` (`boolean`): Whether events are sent to it.
- `mode` (`"live" | "test"`): The mode it hears: test or live, the mode of the key that made it. A test endpoint never hears a live event.
- `deployment_id` (`string | null`): Only this deployment's events reach it (dep_...), plus your account's, such as keys, users and usage alerts. Set when a deployment's vestra.yaml declared the endpoint. Null: every event its types allow.
- `managed_by` (`"file" | null`): file: declared in that deployment's vestra.yaml, so deploying the file changes it; null: you made it.
- `created_at` (`string`): When it was made, as an ISO 8601 time.
- `updated_at` (`string`): When it last changed, as an ISO 8601 time.
- `secret` (`string`): The signing secret, shown this once: check every delivery against it (the Vestra-Signature header). Keep it on your server. Example: `whsec_...`.

### Code

**HTTP**

```bash
curl -X POST "$VESTRA_BASE_URL/v1/webhooks/{endpoint_id}/roll-secret" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**TypeScript, Python, CLI, MCP**: No sample in your language for this route, so here it is over HTTP.

## `POST /v1/webhooks/{endpoint_id}/test`

Its own page: [POST /v1/webhooks/{endpoint_id}/test](https://vestra.ai/developers/reference/api/webhooks-and-events/post-v1-webhooks-endpoint-id-test.md)

Send a sample event now.

Your API key, scope `setup` or `all`. On the card: [`events`](https://vestra.ai/developers/events.md). Every call here is a checked sample.

### Request

Path:

- `endpoint_id` (`string`, required): The webhook endpoint's id (`whk_...`).

Headers:

- `Idempotency-Key` (`string`): Send the same key to retry this call safely for 24 hours.

### Answers 200

- `ok` (`boolean`): Whether your endpoint answered 2xx to a signed webhook.test event.
- `status_code` (`integer | null`): What it answered; null when it did not answer.
- `duration_ms` (`integer`): How long it took, in milliseconds: 10 seconds at most.
- `error` (`string | null`): What went wrong, such as a timeout; null when it answered.

### Code

**HTTP**

```bash
# Register your endpoint and the events it wants. The signing secret is in the answer, shown once.
curl "$VESTRA_BASE_URL/v1/webhooks" \
  -H "Authorization: Bearer $VESTRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://hooks.example.com/vestra", "events": ["task.completed", "interaction.created"] }'

# Send a sample event now, to see your endpoint answer.
curl -X POST "$VESTRA_BASE_URL/v1/webhooks/whk_9sd/test" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**TypeScript, Python, CLI, MCP**: No sample in your language for this route, so here it is over HTTP.

## `GET /v1/webhooks/{endpoint_id}/deliveries`

Its own page: [GET /v1/webhooks/{endpoint_id}/deliveries](https://vestra.ai/developers/reference/api/webhooks-and-events/get-v1-webhooks-endpoint-id-deliveries.md)

Every attempt with status code and timing.

Your API key, scope `setup` or `all`. On the card: [`events`](https://vestra.ai/developers/events.md). Over HTTP it is made from the contract: fill in each {…} and every value.

### Request

Path:

- `endpoint_id` (`string`, required): The webhook endpoint's id (`whk_...`).

Query:

- `limit` (`integer`): How many items per page, 1 to 100. Default 20.
- `cursor` (`string`): Where to go on from: the `next_cursor` of the page before, unchanged. Absent: the first page.
- `state` (`"pending" | "sending" | "sent" | "failed"`): Only deliveries in this state.

### Answers 200

- `data` (`object[]`): The items on this page.
  - `id` (`string`): The delivery: one event, to one endpoint (dlv_...).
  - `object` (`"webhook_delivery"`): Always webhook_delivery.
  - `endpoint_id` (`string`): The endpoint (whk_...).
  - `event_id` (`string`): The event (evt_...): read it again with GET /v1/events.
  - `event_type` (`string | null`): The event's type; null when the event is gone. Limits: one of 28 values.
  - `state` (`"pending" | "sending" | "sent" | "failed"`): pending: waiting for its next try. sending: being sent now. sent: your endpoint answered 2xx. failed: it gave up: after 5 tries, or when the endpoint was turned off or the event is gone.
  - `attempts` (`integer`): How many times it has been tried: 5 at most, waiting 1, 5, 15 and then 60 minutes between them.
  - `next_attempt_at` (`string | null`): When it is tried next, as an ISO 8601 time; null when it will not be.
  - `last_status_code` (`integer | null`): What your endpoint last answered; null when it never answered.
  - `last_error` (`string | null`): What last went wrong; null when nothing did.
  - `attempt_log` (`object[]`): Every try, oldest first.
    - `at` (`string`): When it was tried, as an ISO 8601 time.
    - `status_code` (`integer | null`): What your endpoint answered; null when it did not answer.
    - `duration_ms` (`integer`): How long the try took, in milliseconds: a try waits 10 seconds at most.
    - `error` (`string | null`): What went wrong, such as a timeout; null when it was sent.
  - `created_at` (`string`): When the event was queued for this endpoint, as an ISO 8601 time.
  - `sent_at` (`string | null`): When your endpoint took it, as an ISO 8601 time; null until then.
- `next_cursor` (`string | null`): Send it as `cursor` for the next page; null on the last page.

### Code

**HTTP**

```bash
curl "$VESTRA_BASE_URL/v1/webhooks/{endpoint_id}/deliveries" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**TypeScript, Python, CLI, MCP**: No sample in your language for this route, so here it is over HTTP.

## `POST /v1/webhooks/{endpoint_id}/deliveries/{delivery_id}/retry`

Its own page: [POST /v1/webhooks/{endpoint_id}/deliveries/{delivery_id}/retry](https://vestra.ai/developers/reference/api/webhooks-and-events/post-v1-webhooks-endpoint-id-deliveries-delivery-id-retry.md)

Send one again.

Your API key, scope `setup` or `all`. On the card: [`events`](https://vestra.ai/developers/events.md). Over HTTP it is made from the contract: fill in each {…} and every value.

### Request

Path:

- `endpoint_id` (`string`, required): The webhook endpoint's id (`whk_...`).
- `delivery_id` (`string`, required): The delivery's id (`dlv_...`).

Headers:

- `Idempotency-Key` (`string`): Send the same key to retry this call safely for 24 hours.

### Answers 200

- `id` (`string`): The delivery: one event, to one endpoint (dlv_...).
- `object` (`"webhook_delivery"`): Always webhook_delivery.
- `endpoint_id` (`string`): The endpoint (whk_...).
- `event_id` (`string`): The event (evt_...): read it again with GET /v1/events.
- `event_type` (`string | null`): The event's type; null when the event is gone. Limits: one of 28 values.
- `state` (`"pending" | "sending" | "sent" | "failed"`): pending: waiting for its next try. sending: being sent now. sent: your endpoint answered 2xx. failed: it gave up: after 5 tries, or when the endpoint was turned off or the event is gone.
- `attempts` (`integer`): How many times it has been tried: 5 at most, waiting 1, 5, 15 and then 60 minutes between them.
- `next_attempt_at` (`string | null`): When it is tried next, as an ISO 8601 time; null when it will not be.
- `last_status_code` (`integer | null`): What your endpoint last answered; null when it never answered.
- `last_error` (`string | null`): What last went wrong; null when nothing did.
- `attempt_log` (`object[]`): Every try, oldest first.
  - `at` (`string`): When it was tried, as an ISO 8601 time.
  - `status_code` (`integer | null`): What your endpoint answered; null when it did not answer.
  - `duration_ms` (`integer`): How long the try took, in milliseconds: a try waits 10 seconds at most.
  - `error` (`string | null`): What went wrong, such as a timeout; null when it was sent.
- `created_at` (`string`): When the event was queued for this endpoint, as an ISO 8601 time.
- `sent_at` (`string | null`): When your endpoint took it, as an ISO 8601 time; null until then.

### Code

**HTTP**

```bash
curl -X POST "$VESTRA_BASE_URL/v1/webhooks/{endpoint_id}/deliveries/{delivery_id}/retry" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**TypeScript, Python, CLI, MCP**: No sample in your language for this route, so here it is over HTTP.

## `GET /v1/events`

Its own page: [GET /v1/events](https://vestra.ai/developers/reference/api/webhooks-and-events/get-v1-events.md)

The same events as a list you can pull, for anything you missed.

Your API key, scope `runtime` or `all`. On the card: [`events`](https://vestra.ai/developers/events.md). Every call here is a checked sample.

### Request

Query:

- `limit` (`integer`): How many items per page, 1 to 100. Default 20.
- `cursor` (`string`): Where to go on from: the `next_cursor` of the page before, unchanged. Absent: the first page.
- `type` (`string`): Only events of this type.
- `user_id` (`string`): Only this user's, by your id for them.
- `task_id` (`string`): Only this task's (task_...).
- `created_after` (`string (date and time)`): Only events after this ISO 8601 time.
- `created_before` (`string (date and time)`): Only events before this ISO 8601 time.
- `after` (`string`): Only events after this one (evt_...), oldest first: poll with the last one you saw and you miss nothing. Without it, newest first.

### Answers 200

- `data` (`object[]`): The items on this page.
  - `id` (`string`): The event (evt_...): the same on every retry, so use it to skip one you already took. Example: `evt_4hq`.
  - `object` (`"event"`): Always event.
  - `type` (`string`): An event a webhook carries: every event of the catalog but the six that ride only the stream (message.delta, task.progress, usage.updated, screen.control, error and ping). Limits: one of 28 values. Example: `task.completed`.
  - `mode` (`"live" | "test"`): The mode it happened in: test or live.
  - `created_at` (`string`): When it happened, as an ISO 8601 time.
  - `user_id` (`string | null`): Your id for the user it concerns; null for your company's own Bash, or when it concerns no user.
  - `task_id` (`string | null`): The task it concerns (task_...); null when none.
  - `conversation_id` (`string | null`): The conversation it concerns (conv_...); null when none.
  - `data` (`map of any`): What it says: its fields depend on its type, as the events reference lists them.
- `next_cursor` (`string | null`): Send it as `cursor` for the next page; null on the last page.

### Code

**TypeScript**

```ts
const events = await vestra.events.list();
```

**Python**

```python
events = vestra.events.list()
```

**CLI**

```bash
vestra events
```

**HTTP**

```bash
# Stream a conversation live. If the connection drops, reconnect with the last seq you saw.
curl -N "$VESTRA_BASE_URL/v1/conversations/conv_8f2k/events" \
  -H "Authorization: Bearer $VESTRA_API_KEY" \
  -H "Last-Event-ID: 41"

# Read the same events as JSON. You get them in pages, after the seq you give.
curl "$VESTRA_BASE_URL/v1/conversations/conv_8f2k/events?format=json&after=41" \
  -H "Authorization: Bearer $VESTRA_API_KEY"

# Read a task afterwards. You get every step of one task, with tokens and cost per turn.
curl "$VESTRA_BASE_URL/v1/tasks/task_91d/trace" \
  -H "Authorization: Bearer $VESTRA_API_KEY"

# Send events to your server. Register a URL and the events it wants. The signing secret is shown only once.
curl "$VESTRA_BASE_URL/v1/webhooks" \
  -H "Authorization: Bearer $VESTRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://hooks.example.com/vestra", "events": ["task.completed", "interaction.created", "usage.cap_reached"] }'

# Catch up on what you missed. List the events your webhooks were sent, newest first.
curl "$VESTRA_BASE_URL/v1/events?type=task.failed" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**MCP**

```json
{
  "method": "tools/call",
  "params": {
    "name": "events",
    "arguments": { "user": "traveller-42", "conversation": "conv_8f2k", "after": 0 }
  }
}
```

## `GET /v1/events/{event_id}`

Its own page: [GET /v1/events/{event_id}](https://vestra.ai/developers/reference/api/webhooks-and-events/get-v1-events-event-id.md)

One event.

Your API key, scope `runtime` or `all`. On the card: [`events`](https://vestra.ai/developers/events.md). Over HTTP it is made from the contract: fill in each {…} and every value.

### Request

Path:

- `event_id` (`string`, required): The event's id (`evt_...`).

### Answers 200

- `id` (`string`): The event (evt_...): the same on every retry, so use it to skip one you already took. Example: `evt_4hq`.
- `object` (`"event"`): Always event.
- `type` (`string`): An event a webhook carries: every event of the catalog but the six that ride only the stream (message.delta, task.progress, usage.updated, screen.control, error and ping). Limits: one of 28 values. Example: `task.completed`.
- `mode` (`"live" | "test"`): The mode it happened in: test or live.
- `created_at` (`string`): When it happened, as an ISO 8601 time.
- `user_id` (`string | null`): Your id for the user it concerns; null for your company's own Bash, or when it concerns no user.
- `task_id` (`string | null`): The task it concerns (task_...); null when none.
- `conversation_id` (`string | null`): The conversation it concerns (conv_...); null when none.
- `data` (`map of any`): What it says: its fields depend on its type, as the events reference lists them.

### Code

**HTTP**

```bash
curl "$VESTRA_BASE_URL/v1/events/{event_id}" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**TypeScript, Python, CLI, MCP**: No sample in your language for this route, so here it is over HTTP.
