---
title: "Create a capture hook"
method: POST
path: "/v1/hooks"
tags: ["hooks"]
---

# Create a capture hook

`POST /v1/hooks`

## Request

- Base URL: `https://api.mailfixture.com`
- URL: `https://api.mailfixture.com/v1/hooks`
- Auth: HTTP bearer

Mints a public ingest URL (on a dedicated utility host, never the brand or API origin). Any HTTP request sent there is recorded and answered with a fixed `200 {"ok":true}` — responses are not configurable. Creation shares the burst-10 creation bucket with inboxes. Captured requests are hard-capped per plan (free 100/mo, solo 2,500, team 15,000, scale 100,000; daily caps 100/2,000/10,000/50,000) — over-cap ingest answers 429 with Retry-After. Captures never fire outbound webhook events (loop prevention, by design).

## Request body

- CreateHookRequest: All fields optional; an empty or absent body creates an unlabeled hook with no expiry.
  - `label` string: Human label shown in lists and the dashboard.
  - `ttl_seconds` integer: Auto-delete the hook (and its captured requests) after this many seconds (max 30 days). Omit for no expiry.

## Response `201`

Hook created; `ingest_url` is the address to give the app under test.

- Hook
  - `created_at` string, date-time, required
  - `id` string, uuid, required
  - `ingest_url` string, required: The public URL to configure in the app under test. Any method; bodies up to 256KB. Successful captures always answer the fixed `200 {"ok":true}` — responses are not configurable; over-size bodies answer 413, exhausted quotas 429 with Retry-After, and an unknown token 404.
  - `label` string, nullable, required
  - `token` string, required: The write capability embedded in the ingest URL. Anyone who knows it can add requests to the bin — treat like a webhook secret. It never grants reads.
  - `ttl_expires_at` string, date-time, nullable, required

## Other responses

- `400`: `label` over 200 chars or `ttl_seconds` out of range.
- `401`: Missing bearer token, malformed key, or unknown/revoked/invalid API key.
- `403`: Account frozen, or the plan's hook cap is reached (free 1, solo 3, team 10, scale 25).
- `429`: Per-key rate limit exceeded. `Retry-After` says when the next request will be admitted; the RateLimit headers name the bucket that refused (`requests` or `creates`) with `r=0`.
- `500`: Unexpected server error. `detail` is null — internals are never leaked.

---

[API](https://skmtc.dev/mailfixture/apis/mailfixture-api.md) · [All operations](https://skmtc.dev/mailfixture/apis/mailfixture-api/llms.txt) · [OpenAPI document](https://skmtc.dev/mailfixture/apis/mailfixture-api/revisions/4ddefe29f6f6?raw)
