Skip to content
Browse documentation

Reliability

Limits

Every hard limit in one place: request body size, retention, rate limits, retries, timeouts, transform budgets, and endpoint quotas by plan.

This page lists the limits the current server enforces. Values come from packages/api/src/plans.ts, the ingest and delivery services, and the transform runtime; pricing copy reads the same plan constants.

These limits apply to every workspace. Most are configurable per destination within the stated range.

Area Limit When exceeded
Inbound request body 1 MiB platform ceiling; Free 64 KiB, Pro and Scale 1 MiB effective 413 payload_too_large; nothing is stored
Per-endpoint inbound rate Optional rateLimitPerMinute (1–100,000); action store or drop 429 RATE_LIMIT_EXCEEDED with Retry-After; store keeps a rate_limited event for triage
API request rate 600/min per API key prefix (or IP for sessions) 429 with Retry-After
Ingest request rate 1,000/min per IP + ASN 429 with Retry-After; event not stored
Manual retry rate 60/min per caller 429 with Retry-After
MCP request rate 600/min per API key prefix 429 with Retry-After
Inspector rate 120/min for /inspect/*, 240/min for /t/* 429 with Retry-After
Sign-up / auth rate 5/hour for sign-up (IP + ASN), 30/min for other auth routes 429 with Retry-After
Destination timeout 100 ms–30 s; default 10 s Attempt fails with a timeout error and retries if attempts remain
Retry attempts 1–10; default 5 (agent targets default 3) Last failure becomes dead (retryable failure) or failed (permanent failure)
Retry delay 1–60 s initial; default 2 s (agent targets 15 s); max 5–3,600 s Delay is capped at the max; jitter defaults to ±20%
Outbound rate per destination 600/min and 10 concurrent; agent targets 30/min and 3 Delivery is deferred to a later window, not dropped
JS transform script 20,000 characters TRANSFORM_INVALID_SCRIPT; delivery fails permanently
JS transform runtime 50 ms CPU, 16 MiB heap, 256 KiB output TRANSFORM_TIMEOUT, TRANSFORM_MEMORY_LIMIT or TRANSFORM_OUTPUT_TOO_LARGE
Captured request / response Request 16 KiB; response 64 KiB Longer bodies are truncated in the attempt log, never rejected
List pagination 100 rows max; REST default 20, MCP default 50 limit above 100 returns 400 VALIDATION_ERROR
Event search q 200 characters; filter 500 characters, 8 path levels 400 VALIDATION_ERROR; only inline payloads are searched
Uploads (task files) 5 MiB per file 413 PAYLOAD_TOO_LARGE
Temporary inspector 256 KiB per request, 50 requests, 24-hour session 413, INSPECT_DESTINATION_LIMIT, or INSPECT_SESSION_EXPIRED

Retry policy precedence: destination retryPolicy overrides the target adapter defaults, which override the platform defaults. Retries cover network errors, timeouts, 408, 425, 429 and 5xx; other 4xx responses fail permanently. When a retryable failure runs out of attempts the delivery is dead, so it can still be retried or replayed; a permanent failure is failed.

Limit Free Pro Scale
Accepted requests 1,000 lifetime per identity 10,000 per prepaid block Contract volume
Event retention 7 days 30 days 60 days
Endpoints 3 Unlimited Unlimited
Destinations per endpoint 2 Unlimited Unlimited
Bookmarks 20 Unlimited Unlimited
Members including owner 1 5 25
Max inbound body (effective) 64 KiB 1 MiB 1 MiB¹

¹ The plan definition allows 5 MiB on Scale, but the Worker currently enforces a 1 MiB ingress ceiling for every plan. Larger Scale bodies need the platform ceiling raised in a deployment.

The request quota is shared by all endpoints in a workspace and counts only accepted inbound events. Filtered, duplicate, rejected and retried requests are free. See billing and quota for the billable-unit table, including extra destinations, extra payload blocks and manual replays.

The body is rejected before it is stored:

{
"error": "payload_too_large",
"plan": "free",
"limit_bytes": 65536,
"message": "Free requests are limited to 65536 bytes. Upgrade to Pro for up to 1048576 bytes.",
"upgrade_url": "https://hooks.events/settings?tab=billing"
}

The status is 413; no event, delivery or billable request is created. Free responses include an upgrade link; paid workspaces receive Body exceeds <limit> bytes.

Inbound requests return 429 with error quota_exceeded and are not stored. There is no Retry-After, because neither the Free lifetime grant nor prepaid blocks reset; buy more blocks to restore service. The response carries X-Quota-Limit and X-Quota-Remaining.

Rate-limit responses use 429 RATE_LIMIT_EXCEEDED, carry Retry-After, and include X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset on every response. Events rejected this way are not stored. See rate limits for the caller key and window details.

Plan limits are checked when resources are created, not on read. Exceeding one returns 409 PLAN_LIMIT_EXCEEDED with the limit and resource in the message. A workspace that downgrades keeps its existing endpoints, destinations and members but cannot add more until it is back under the limit.

Events, deliveries, attempts and stored payloads are deleted after the plan’s retention window. Filtered and duplicate events are kept for 7 days regardless of plan, because they carry no delivery history. Cleanup runs on the one-minute cron; after a row ages out it cannot be recovered by replay.