# Events

Everything that happened to your domains, newest first, with webhook deliveries and redelivery.

Base URL `https://api.apexly.dev`. Send your key as `Authorization: Bearer sk_live_…` or `sk_test_…`; the examples read it from `APEXLY_API_KEY`.

## List webhook events

`GET /v1/events`

Newest first (created_at desc), cursor-paginated. Filter by domain_id and type. Each event carries a delivery summary: delivered, pending (queued or retrying, with next_attempt_at), failed (retries exhausted) or none (no webhook URL was set).

### Query parameters

| Field | Type | Description |
| --- | --- | --- |
| `domain_id` | `string` |  |
| `type` | `string` | One of `domain.created`, `domain.verified`, `domain.active`, `domain.dns_broken`, `domain.cert_failed`, `domain.certificate_renewed`, `domain.deleted`, `domain.held`, `domain.released`. |
| `limit` | `integer` | Default `50`. 1 to 100. |
| `cursor` | `string` | next_cursor of the previous page. At most 200 characters. |

### Response

`200 OK`. Errors use the [error envelope](/docs/api/errors).

| Field | Type | Description |
| --- | --- | --- |
| `data` | `object[]` |  |
| `data[].id` | `string` | evt_… (the Apexly-Event-Id header). |
| `data[].type` | `string` | One of `domain.created`, `domain.verified`, `domain.active`, `domain.dns_broken`, `domain.cert_failed`, `domain.certificate_renewed`, `domain.deleted`, `domain.held`, `domain.released`. |
| `data[].domain_id` | `string` |  |
| `data[].hostname` | `string` |  |
| `data[].previous_status` | `string \| null` | One of `pending_dns`, `verifying`, `issuing`, `active`, `dns_broken`, `cert_failed`, `expired`, `held`, `deleted`. |
| `data[].status` | `string \| null` | The domain status the event moved to. One of `pending_dns`, `verifying`, `issuing`, `active`, `dns_broken`, `cert_failed`, `expired`, `held`, `deleted`. |
| `data[].created_at` | `string` |  |
| `data[].delivery` | `object` |  |
| `data[].delivery.status` | `string` | delivered: an attempt got a 2xx. pending: queued or retrying. failed: every attempt failed and retries are over. none: no webhook URL was set. One of `delivered`, `pending`, `failed`, `none`. |
| `data[].delivery.attempts` | `integer` | WebhookDelivery rows, redeliveries included. |
| `data[].delivery.last_status_code` | `integer \| null` |  |
| `data[].delivery.last_error` | `string \| null` | url_not_allowed \| dns_failed \| timeout \| tls_error \| connection_failed. |
| `data[].delivery.last_attempt_at` | `string \| null` |  |
| `data[].delivery.next_attempt_at` | `string \| null` | Next automatic attempt while pending. |
| `next_cursor` | `string \| null` |  |

### Example

```bash tab="curl"
curl https://api.apexly.dev/v1/events \
  -H "Authorization: Bearer $APEXLY_API_KEY"
```

```js tab="Node"
const res = await fetch("https://api.apexly.dev/v1/events", {
  headers: {
    Authorization: `Bearer ${process.env.APEXLY_API_KEY}`,
  },
});
const body = await res.json();
```

```python tab="Python"
import os
import requests

res = requests.get(
    "https://api.apexly.dev/v1/events",
    headers={"Authorization": f"Bearer {os.environ['APEXLY_API_KEY']}"},
)
body = res.json()
```

## Get an event

`GET /v1/events/{id}`

The event with every delivery attempt, newest first (at most 50).

### Path parameters

| Field | Type | Description |
| --- | --- | --- |
| `id` | `string` |  |

### Response

`200 OK`. Errors use the [error envelope](/docs/api/errors).

| Field | Type | Description |
| --- | --- | --- |
| `id` | `string` | evt_… (the Apexly-Event-Id header). |
| `type` | `string` | One of `domain.created`, `domain.verified`, `domain.active`, `domain.dns_broken`, `domain.cert_failed`, `domain.certificate_renewed`, `domain.deleted`, `domain.held`, `domain.released`. |
| `domain_id` | `string` |  |
| `hostname` | `string` |  |
| `previous_status` | `string \| null` | One of `pending_dns`, `verifying`, `issuing`, `active`, `dns_broken`, `cert_failed`, `expired`, `held`, `deleted`. |
| `status` | `string \| null` | The domain status the event moved to. One of `pending_dns`, `verifying`, `issuing`, `active`, `dns_broken`, `cert_failed`, `expired`, `held`, `deleted`. |
| `created_at` | `string` |  |
| `delivery` | `object` |  |
| `delivery.status` | `string` | delivered: an attempt got a 2xx. pending: queued or retrying. failed: every attempt failed and retries are over. none: no webhook URL was set. One of `delivered`, `pending`, `failed`, `none`. |
| `delivery.attempts` | `integer` | WebhookDelivery rows, redeliveries included. |
| `delivery.last_status_code` | `integer \| null` |  |
| `delivery.last_error` | `string \| null` | url_not_allowed \| dns_failed \| timeout \| tls_error \| connection_failed. |
| `delivery.last_attempt_at` | `string \| null` |  |
| `delivery.next_attempt_at` | `string \| null` | Next automatic attempt while pending. |
| `deliveries` | `object[]` | Newest first, at most 50. |
| `deliveries[].id` | `string` | dlv_… (the Apexly-Delivery-Id header). |
| `deliveries[].event_id` | `string` |  |
| `deliveries[].attempt` | `integer` | 1-based; counts every attempt of the event, redeliveries included. |
| `deliveries[].status_code` | `integer \| null` | The receiver's HTTP status, when it answered. |
| `deliveries[].response_ms` | `integer \| null` |  |
| `deliveries[].error` | `string \| null` | Why there was no HTTP answer. |
| `deliveries[].delivered_at` | `string \| null` |  |
| `deliveries[].next_attempt_at` | `string \| null` | When the automatic retry after this attempt was due. |
| `deliveries[].created_at` | `string` |  |

### Example

```bash tab="curl"
curl https://api.apexly.dev/v1/events/evt_01J9X8T4Q5M6N7P8R9S0V1W2X3 \
  -H "Authorization: Bearer $APEXLY_API_KEY"
```

```js tab="Node"
const res = await fetch("https://api.apexly.dev/v1/events/evt_01J9X8T4Q5M6N7P8R9S0V1W2X3", {
  headers: {
    Authorization: `Bearer ${process.env.APEXLY_API_KEY}`,
  },
});
const body = await res.json();
```

```python tab="Python"
import os
import requests

res = requests.get(
    "https://api.apexly.dev/v1/events/evt_01J9X8T4Q5M6N7P8R9S0V1W2X3",
    headers={"Authorization": f"Bearer {os.environ['APEXLY_API_KEY']}"},
)
body = res.json()
```

## Redeliver an event

`POST /v1/events/{id}/redeliver`

Sends the event's original body again now, freshly signed, to the app's current webhook URL, and returns the new attempt (a new delivery row; the receiver's answer is in status_code). A 2xx also takes the event off the automatic retry schedule. 10 per minute per app; 422 validation_failed when the app has no webhook URL.

### Path parameters

| Field | Type | Description |
| --- | --- | --- |
| `id` | `string` |  |

### Response

`201 Created`. Errors use the [error envelope](/docs/api/errors).

| Field | Type | Description |
| --- | --- | --- |
| `id` | `string` | dlv_… (the Apexly-Delivery-Id header). |
| `event_id` | `string` |  |
| `attempt` | `integer` | 1-based; counts every attempt of the event, redeliveries included. |
| `status_code` | `integer \| null` | The receiver's HTTP status, when it answered. |
| `response_ms` | `integer \| null` |  |
| `error` | `string \| null` | Why there was no HTTP answer. |
| `delivered_at` | `string \| null` |  |
| `next_attempt_at` | `string \| null` | When the automatic retry after this attempt was due. |
| `created_at` | `string` |  |

### Example

```bash tab="curl"
curl -X POST https://api.apexly.dev/v1/events/evt_01J9X8T4Q5M6N7P8R9S0V1W2X3/redeliver \
  -H "Authorization: Bearer $APEXLY_API_KEY"
```

```js tab="Node"
const res = await fetch("https://api.apexly.dev/v1/events/evt_01J9X8T4Q5M6N7P8R9S0V1W2X3/redeliver", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.APEXLY_API_KEY}`,
  },
});
const body = await res.json();
```

```python tab="Python"
import os
import requests

res = requests.post(
    "https://api.apexly.dev/v1/events/evt_01J9X8T4Q5M6N7P8R9S0V1W2X3/redeliver",
    headers={"Authorization": f"Bearer {os.environ['APEXLY_API_KEY']}"},
)
body = res.json()
```
