# Webhook Bin — for AI agents (text mode)

A free, no-signup webhook bin: a public URL that captures any HTTP request sent
to it so you can inspect webhooks, callbacks and HTTP requests. This page is the
text/plain-text variant of https://webhookrelay.com/webhook-bin written for AI
agents and command-line use — every step is a copy-pasteable `curl` command.

- API base URL: `https://bin.webhookrelay.com`
- All endpoints accept and return JSON (except the webhook receiver, which
  accepts anything).
- CORS is enabled. No API key or authentication is required.
- Bins are public and expire automatically after ~48 hours. Do not send secrets.

---

## TL;DR (the whole flow)

```bash
# 1. Create a bin and capture its ID
BIN=$(curl -s -X POST https://bin.webhookrelay.com/v1/bins | jq -r .id)

# 2. This is the public URL to give to any webhook sender (accepts ANY method):
echo "https://bin.webhookrelay.com/v1/webhooks/$BIN"

# 3. Send a test webhook to it
curl -s -X POST "https://bin.webhookrelay.com/v1/webhooks/$BIN" \
  -H 'Content-Type: application/json' \
  -d '{"hello":"world"}'

# 4. Read back every captured request (raw, as JSON):
curl -s "https://bin.webhookrelay.com/v1/bins/$BIN" | jq '.requests'
```

Open the same bin in a browser UI: `https://webhookrelay.com/webhook-bin?bin=<BIN_ID>`

---

## 1. Create a new bin

`POST /v1/bins` — no body required.

```bash
curl -s -X POST https://bin.webhookrelay.com/v1/bins
```

Response (`201 Created`):

```json
{
  "id": "0e2c9b1a-7f3d-4c0a-9b2e-1f6a8c4d5e7b",
  "createdAt": 1735776000,
  "updatedAt": 1735776000,
  "response": { "status": 200 }
}
```

The `id` is what you use everywhere below. Extract it with:

```bash
BIN=$(curl -s -X POST https://bin.webhookrelay.com/v1/bins | jq -r .id)
```

---

## 2. The webhook receiver URL (the "raw" URL to call)

Give this URL to any service, script, or webhook sender. It accepts **any HTTP
method** (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`, ...), any headers, and any
body. Every request is recorded.

```
https://bin.webhookrelay.com/v1/webhooks/<BIN_ID>
```

Example — send something to it:

```bash
curl -s -X POST "https://bin.webhookrelay.com/v1/webhooks/$BIN" \
  -H 'Content-Type: application/json' \
  -d '{"event":"order.created","id":42}'
```

The receiver replies with the bin's configured response (default: `200 OK`,
empty body). See section 5 to customise it.

---

## 3. Read captured webhooks (raw)

`GET /v1/bins/{id}` returns the bin plus every captured request in the
`requests` array. This is the endpoint to poll to retrieve webhooks.

```bash
curl -s "https://bin.webhookrelay.com/v1/bins/$BIN"
```

```json
{
  "id": "0e2c9b1a-...",
  "createdAt": 1735776000,
  "updatedAt": 1735776000,
  "response": { "status": 200 },
  "requests": [
    {
      "id": "01HQ...",
      "receivedAt": 1735776123,
      "bin": "0e2c9b1a-...",
      "method": "POST",
      "query": "source=test",
      "ip": "203.0.113.7",
      "header": {
        "Content-Type": { "key": "Content-Type", "values": ["application/json"] }
      },
      "body": "{\"event\":\"order.created\",\"id\":42}",
      "responseStatus": 200
    }
  ]
}
```

Field notes:

- `receivedAt` — Unix timestamp in **seconds**.
- `body` — the raw request body as a string (parse it yourself if it is JSON).
- `header` — map of header name → `{ key, values[] }` (values is an array
  because a header can repeat).
- `query` — the raw query string (without the leading `?`).
- `responseStatus` — the HTTP status the bin returned to the sender.

Handy extractions:

```bash
# Just the most recent request's body
curl -s "https://bin.webhookrelay.com/v1/bins/$BIN" \
  | jq -r '.requests | sort_by(.receivedAt) | last | .body'

# Number of captured requests
curl -s "https://bin.webhookrelay.com/v1/bins/$BIN" | jq '.requests | length'
```

### Poll until a webhook arrives

```bash
until [ "$(curl -s "https://bin.webhookrelay.com/v1/bins/$BIN" | jq '.requests | length')" -gt 0 ]; do
  sleep 2
done
echo "Webhook received:"
curl -s "https://bin.webhookrelay.com/v1/bins/$BIN" | jq '.requests | last'
```

---

## 4. Stream webhooks in real time (Server-Sent Events)

Instead of polling, subscribe to a live SSE stream of new requests for a bin:

```bash
curl -N "https://bin.webhookrelay.com/v1/events?stream=$BIN"
```

Each new captured request is pushed as an SSE `data:` line containing the
request JSON (same shape as the entries in `requests` above). Keep the
connection open; the server holds it for you.

---

## 5. Configure the response the bin returns (optional)

`PUT /v1/bins/{id}` updates what the receiver replies with. Useful to simulate a
real endpoint: custom status, body, headers, latency, and probabilistic
failures.

```bash
curl -s -X PUT "https://bin.webhookrelay.com/v1/bins/$BIN" \
  -H 'Content-Type: application/json' \
  -d '{
    "id": "'"$BIN"'",
    "response": {
      "status": 201,
      "body": "{\"ok\":true}",
      "delay": 250,
      "header": {
        "Content-Type": { "key": "Content-Type", "values": ["application/json"] }
      },
      "failures": [
        { "percentage": 10, "status": 500, "body": "simulated failure" }
      ]
    }
  }'
```

`response` fields:

- `status` — HTTP status code to return (default `200`).
- `body` — response body string (max 500 KB).
- `delay` — artificial delay in **milliseconds** before responding.
- `header` — response headers, same `{ key, values[] }` shape.
- `failures[]` — each entry has a `percentage` (0–100) chance to override the
  normal response with its own `status`/`body`. Use it to test how a sender
  handles intermittent errors.

---

## 6. Delete a bin

```bash
curl -s -X DELETE "https://bin.webhookrelay.com/v1/bins/$BIN"
```

---

## Endpoint reference

| Method        | Path                          | Purpose                                  |
|---------------|-------------------------------|------------------------------------------|
| `POST`        | `/v1/bins`                    | Create a new bin                         |
| `GET`         | `/v1/bins/{id}`               | Get bin + all captured requests          |
| `PUT`         | `/v1/bins/{id}`               | Update the bin's response configuration  |
| `DELETE`      | `/v1/bins/{id}`               | Delete the bin                           |
| *(any)*       | `/v1/webhooks/{id}`           | Public receiver — send webhooks here     |
| `GET`         | `/v1/events?stream={id}`      | SSE stream of new requests (real time)   |
| `GET`         | `/v1/health`                  | Health check                             |

---

## Limits & behaviour

- **Expiry:** bins and their requests are garbage-collected after ~48 hours.
- **Public:** anyone with the bin ID can read its requests. Never send secrets,
  credentials, or personal data to a free bin.
- **Body size:** request and response bodies are capped at 500 KB.
- **Rate limiting:** the service is rate limited; a bin that is flooded with
  requests is temporarily shielded and returns `429 Too Many Requests`.
- **Persistence:** for permanent webhook URLs, larger limits, forwarding to
  localhost or internal services, and transformations, use Webhook Relay:
  https://webhookrelay.com

---

## Minimal agent recipe

```bash
# Create, capture URL, wait for one webhook, print it, clean up.
BIN=$(curl -s -X POST https://bin.webhookrelay.com/v1/bins | jq -r .id)
URL="https://bin.webhookrelay.com/v1/webhooks/$BIN"
echo "Send your webhook to: $URL"

until [ "$(curl -s https://bin.webhookrelay.com/v1/bins/$BIN | jq '.requests|length')" -gt 0 ]; do sleep 2; done

curl -s "https://bin.webhookrelay.com/v1/bins/$BIN" | jq '.requests | last'
curl -s -X DELETE "https://bin.webhookrelay.com/v1/bins/$BIN" >/dev/null
```
