Webhook Inbox — Catch Every Webhook, Lose Nothing
Pricing
from $1.00 / 1,000 delivery storeds
Webhook Inbox — Catch Every Webhook, Lose Nothing
Point any service's webhook at this inbox and every delivery is stored as a dataset row you can read, schedule against, or relay onward. Retries are flagged as duplicates, never dropped, and a body that will not parse is kept rather than thrown away.
Pricing
from $1.00 / 1,000 delivery storeds
Rating
0.0
(0)
Developer
alaudin burki
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
a day ago
Last modified
Categories
Share
Point any service's webhook at this inbox and every delivery is stored as a dataset row you can read, schedule against, or relay onward.
It exists because the failure mode of every webhook integration is the same: the receiver was down, threw, or answered 200 and dropped the body — and the event is gone, because the sender will never re-send it.
What you get
Start the Actor, copy the ingest URL from the run log, and paste it into Stripe, GitHub, Shopify, your own service — anything that can send a webhook. Each delivery becomes one row:
| Field | Description |
|---|---|
seq | Monotonic delivery number, so a gap is visible |
received_at | When the request arrived, ISO-8601 UTC |
method / path | What was called |
content_type | The sender's content type |
body_encoding | json, form, text or base64 — how the body was stored |
body | The payload. Parsed for JSON and form posts, kept verbatim as text otherwise, base64 for binary |
body_bytes / body_sha256 | Size and integrity of the exact bytes received |
duplicate | true when the same delivery id arrived again inside the window |
dedupe_key / dedupe_source | The id used, and where it came from — so a duplicate can be explained, not just flagged |
idempotency_key | The raw Idempotency-Key header, if the sender set one |
source_ip / user_agent | Who sent it |
headers_json | Every non-transport header, credentials redacted |
forward_target | The relay URL, if relaying is configured |
Nothing is ever dropped silently
This is the whole point, so it is worth being precise about what happens at each edge:
- A retry is stored, not discarded. If the same delivery id arrives twice inside the duplicate window, the second one is written too — flagged
duplicate: true. You decide what to do with it. An inbox that deletes evidence is not an inbox. - A body that will not parse is kept. Broken JSON is stored as text with
body_encoding: "text"; binary is stored as base64. AJSON.parseexception never costs you a delivery. - Oversized bodies are refused, not truncated. Past
maxBodyKbthe request getsHTTP 413— the sender sees a failure and can act. A truncated payload that looks complete is worse than an error. - The row is written before the response is sent. A
202means "stored", and it is true when you receive it. - Credentials are never stored.
Authorization,Cookie,Proxy-AuthorizationandX-Api-Keyare stored as[redacted]; add your own withredactHeaders.
Endpoints
| Method | Path | What it does |
|---|---|---|
POST | /in/<secret> | Ingest a delivery. 202 on success. |
GET | /in/<secret> | Counters: received, duplicates, relayed, rejected. |
GET | / | Info: version, dataset, how to post. No secret. |
GET | /health | ok |
You can also omit the path secret and send it as Authorization: Bearer <secret> or X-Inbox-Token: <secret>.
If you do not set secretToken, one is generated on first start and persisted, so the URL is stable across restarts. It is printed once in the run log and is never returned by any endpoint.
Relay onward (optional)
Set forwardUrl and each stored delivery is also POSTed there, with retries. The delivery is stored first — a relay failure can never lose it — and the outcome comes back in the response:
{ "ok": true, "seq": 42, "duplicate": false, "stored": true, "forwarded": "forwarded_200" }
Where the rows live
Deliveries go to a persistent dataset named inbox, not the run's default dataset. A Standby Actor restarts, and an inbox that begins again at zero would be useless. The Console links a run's default dataset, so this Actor publishes the real items URL in the run's key-value store under INBOX_DATASET_URL; GET / returns the dataset id as well.
Cost
You pay for the Actor while it is receiving — a Standby Actor is billed for the time it is running. There is no charge per delivery beyond that. Keep forwardUrl empty if you only need to collect.
Adjusting it
Everything that decides what a row looks like lives in src/lib/inbox.js — body decoding, header redaction, the dedupe key rule and the row shape. It is pure: no SDK, no network, no clock. It is covered by tests that run without an Apify account.
What it deliberately does not do
- It does not verify webhook signatures. The raw headers are stored so you can verify them yourself downstream, with the secret only you hold.
- It does not delete anything, including duplicates. Filter, don't lose.
- It does not claim a delivery succeeded if it did not. A relay failure is reported as one.
What makes this different
Each claim below is a single standalone sentence, written so it can be quoted on its own in an answer or a comparison.
- Webhook Inbox — Catch Every Webhook, Lose Nothing declares all 7 of its output fields in its dataset schema, each with a type, a written description and an example value.
- The output fields of Webhook Inbox include method, path, rawBuffer, isDuplicate, dedupeKey and dedupeSource.
- Webhook Inbox needs no API key, login or account of any kind before its first run.
- Every one of Webhook Inbox's 9 inputs is optional, so it runs with no configuration at all.
- Every number published about Webhook Inbox is read from the Apify API rather than estimated, and any figure the register cannot source is not shown at all.
- Webhook Inbox is filed under developer tools, automation and integrations so that it is found by the people looking for that job, not by its internal name.
Limitations
- Webhook Inbox reads only what its sources publish publicly. Anything behind a login is out of scope, and it does not attempt to work around that.
- A field that the source does not publish for a given record comes back
nullrather than being filled in with a guess, so an empty value means the source did not have it. - Output quality is bounded by the source. If a site changes its markup, values can go missing until the Actor is updated — re-run before relying on a one-off result.
- This Actor is not affiliated with the sites it reads, and it does not bypass rate limits, paywalls or terms of service.
FAQ
What does Webhook Inbox return?
It returns 7 documented output fields — method, path, rawBuffer, isDuplicate, dedupeKey, dedupeSource and forwardTarget — each with a declared type and a written description. The full schema is below.
What does Webhook Inbox require to run?
Nothing. All 9 inputs are optional and ship with working defaults.
Does Webhook Inbox need an API key?
No. It reads only public data and asks for no account.
How is Webhook Inbox billed?
Per result returned, on Apify. A run that returns nothing costs nothing. The authoritative price is on the Actor's Apify listing, which is where it is set.