# Create Webhook

`POST https://api.inboxjot.com/v1/webhooks`

Creates a webhook. Inboxjot sends the events you pick to its URL. Needs a Full key. A key limited to one domain answers 403. Send an optional `Idempotency-Key` header to retry safely. See Idempotency.

The response holds the signing secret. It is returned only here, so store it now. To see it again, copy it from the webhook page in the dashboard.

## Body Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | Yes | The webhook name, 1 to 100 characters. |
| `url` | string | Yes | An `https://` URL on a public address, up to 2,000 characters. It cannot hold a user name or password. |
| `events` | string[] | Yes | At least one of `email.sent`, `email.delivered`, `email.opened`, `email.clicked`, `email.bounced`, `email.complained`, `email.delivery_delayed`, `email.rejected`, `email.failed`, `email.unsubscribed`, `contact.created`, `contact.updated` or `contact.deleted`. |

## Response

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | No | The webhook id. |
| `name` | string | No | The webhook name. |
| `url` | string | No | Where events are sent. |
| `events` | string[] | No | The event types it gets. |
| `status` | string | No | `enabled` or `disabled`. Inboxjot turns a webhook off when deliveries keep failing. |
| `disabled_reason` | string \| null | No | Why the webhook was turned off. |
| `created_at` | string | No | When it was created. |
| `updated_at` | string | No | When it last changed. |
| `secret` | string | No | The signing secret, starting with `whsec_`. Returned only here; store it now. |

## Request

cURL:

```bash
curl -X POST https://api.inboxjot.com/v1/webhooks \
  -H "Authorization: Bearer $INBOXJOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Production",
    "url": "https://api.acme.dev/webhooks/inboxjot",
    "events": [
      "email.delivered",
      "email.bounced",
      "email.complained"
    ]
  }'
```

## Responses

| Status | Description |
| --- | --- |
| 201 | Created the webhook. |
| 400 | A field is missing or invalid, or the Idempotency-Key header is not valid. |
| 401 | The API key is missing, revoked or expired. |
| 403 | The key is a Sending key or is limited to one domain, or the request comes from outside its IP allowlist. |
| 409 | A request with the same Idempotency-Key is still running. Retry after one second. |
| 413 | The body is larger than 2 MB. |
| 415 | The Content-Type header is not application/json. |
| 422 | The Idempotency-Key was already used with a different request. |
| 429 | Too many requests for this key. Wait for the seconds in the Retry-After header. |
| 500 | Something failed on our side. Retry later. |

201:

```json
{
  "id": "whk_06d2mfk8r8ja5fv2xn7qe",
  "name": "Production",
  "url": "https://api.acme.dev/webhooks/inboxjot",
  "events": [
    "email.delivered",
    "email.bounced",
    "email.complained"
  ],
  "status": "enabled",
  "disabled_reason": null,
  "created_at": "2026-10-21T09:00:00.000Z",
  "updated_at": "2026-10-21T09:00:00.000Z",
  "secret": "whsec_MfKQ9r1GKG3tZ8vQ2pX7aN4bE6cD1fH0"
}
```

400:

```json
{
  "name": "validation_error",
  "status": 400,
  "message": "The URL must use HTTPS",
  "errors": [
    {
      "message": "The URL must use HTTPS",
      "location": "url"
    }
  ],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```

401:

```json
{
  "name": "unauthorized",
  "status": 401,
  "message": "Unauthorized",
  "errors": [],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```

403:

```json
{
  "name": "forbidden",
  "status": 403,
  "message": "This key cannot be used from 203.0.113.7",
  "errors": [],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```

409:

```json
{
  "name": "concurrent_idempotent_requests",
  "status": 409,
  "message": "A request with this idempotency key is still in progress. Try again later.",
  "errors": [],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```

413:

```json
{
  "name": "payload_too_large",
  "status": 413,
  "message": "The request body is too large",
  "errors": [],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```

415:

```json
{
  "name": "unsupported_media_type",
  "status": 415,
  "message": "The Content-Type must be application/json",
  "errors": [],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```

422:

```json
{
  "name": "invalid_idempotent_request",
  "status": 422,
  "message": "This idempotency key was already used with a different request",
  "errors": [],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```

429:

```json
{
  "name": "rate_limit_exceeded",
  "status": 429,
  "message": "Too many attempts. Try again later.",
  "errors": [],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```

500:

```json
{
  "name": "unknown_error",
  "status": 500,
  "message": "Something went wrong. Please try again later.",
  "errors": [],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```
