{"openapi":"3.1.0","info":{"title":"Webhook Studio API","version":"1.0.0","description":"Capture, verify, route and replay webhooks. Every operation here is usable without the dashboard. The same surface is available as an MCP (Model Context Protocol) server at /mcp (Streamable HTTP, same Bearer auth) — recommended for agents. Agent-oriented usage notes, including the recovery-after-context-loss recipe, live at /llms.txt."},"servers":[{"url":"https://webhook-studio.com"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An API key from the dashboard: \"Authorization: Bearer ws_live_...\"."}},"schemas":{"Event":{"type":"object","properties":{"id":{"type":"string"},"method":{"type":"string"},"headers":{"type":"object","additionalProperties":{"type":"string"}},"body":{"type":"string","nullable":true},"content_type":{"type":"string","nullable":true},"source_ip":{"type":"string","nullable":true},"provider":{"type":"string","nullable":true,"description":"null means unattributed, not an error."},"event_type":{"type":"string","nullable":true},"signature_valid":{"type":"boolean","nullable":true},"signature_failure_reason":{"type":"string","nullable":true,"enum":["missing_header","malformed_header","malformed_timestamp","timestamp_out_of_tolerance","signature_mismatch"],"description":"Why verification failed. timestamp_out_of_tolerance means a delayed or replayed delivery, NOT a wrong secret."},"ip_allowed":{"type":"boolean","nullable":true},"received_at":{"type":"string","format":"date-time"},"labels":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"},"color":{"type":"string"}}}}}},"Delivery":{"type":"object","properties":{"id":{"type":"string"},"event_id":{"type":"string"},"destination_id":{"type":"string"},"destination_name":{"type":"string","nullable":true},"destination_url":{"type":"string","nullable":true},"rule_id":{"type":"string","nullable":true},"source":{"type":"string","enum":["rule","replay","manual_test"]},"attempt_number":{"type":"integer"},"request_headers":{"type":"object","nullable":true},"request_body":{"type":"string","nullable":true},"response_status":{"type":"integer","nullable":true},"response_body":{"type":"string","nullable":true},"latency_ms":{"type":"integer","nullable":true},"success":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}}},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}},"paths":{"/v1/endpoints":{"get":{"summary":"List endpoints","description":"Filter by external_ref to re-find an endpoint whose id you no longer have.","parameters":[{"name":"external_ref","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"429":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}},"post":{"summary":"Create an endpoint","description":"Returns the ingest url and the signing secret. The secret is returned here and on rotation only.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"environment":{"type":"string","enum":["production","staging","sandbox","development"]},"external_ref":{"type":"string","description":"Stable caller-chosen name, unique per account. Set it — it is how you find this endpoint again later."}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"403":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"409":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"429":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/endpoints/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"summary":"Get an endpoint","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}},"patch":{"summary":"Update an endpoint","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"environment":{"type":"string","enum":["production","staging","sandbox","development"]},"external_ref":{"type":"string","nullable":true,"description":"null clears it."}}}}}},"responses":{"200":{"description":"OK"},"400":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"409":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}},"delete":{"summary":"Delete an endpoint and all of its events","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/endpoints/{id}/events":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"since","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only events at or after this time. ISO 8601, or a bare YYYY-MM-DD."},{"name":"until","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only events at or before this time."},{"name":"provider","in":"query","schema":{"type":"string","enum":["stripe","github"]},"description":"Provider attributed from request headers at ingest."},{"name":"type","in":"query","schema":{"type":"string"},"description":"The provider's own event name, matched exactly (e.g. payment_intent.succeeded)."},{"name":"method","in":"query","schema":{"type":"string"}},{"name":"signature_valid","in":"query","schema":{"type":"boolean"}},{"name":"q","in":"query","schema":{"type":"string"},"description":"Case-insensitive substring over body, content type, method, event type and label values."},{"name":"limit","in":"query","schema":{"type":"integer","maximum":100,"default":20}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"get":{"summary":"List captured events, newest first","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"method":{"type":"string"},"headers":{"type":"object","additionalProperties":{"type":"string"}},"body":{"type":"string","nullable":true},"content_type":{"type":"string","nullable":true},"source_ip":{"type":"string","nullable":true},"provider":{"type":"string","nullable":true,"description":"null means unattributed, not an error."},"event_type":{"type":"string","nullable":true},"signature_valid":{"type":"boolean","nullable":true},"signature_failure_reason":{"type":"string","nullable":true,"enum":["missing_header","malformed_header","malformed_timestamp","timestamp_out_of_tolerance","signature_mismatch"],"description":"Why verification failed. timestamp_out_of_tolerance means a delayed or replayed delivery, NOT a wrong secret."},"ip_allowed":{"type":"boolean","nullable":true},"received_at":{"type":"string","format":"date-time"},"labels":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"},"color":{"type":"string"}}}}}}},"next_cursor":{"type":"string","nullable":true}}}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/endpoints/{id}/events/latest":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"since","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only events at or after this time. ISO 8601, or a bare YYYY-MM-DD."},{"name":"until","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only events at or before this time."},{"name":"provider","in":"query","schema":{"type":"string","enum":["stripe","github"]},"description":"Provider attributed from request headers at ingest."},{"name":"type","in":"query","schema":{"type":"string"},"description":"The provider's own event name, matched exactly (e.g. payment_intent.succeeded)."},{"name":"method","in":"query","schema":{"type":"string"}},{"name":"signature_valid","in":"query","schema":{"type":"boolean"}},{"name":"q","in":"query","schema":{"type":"string"},"description":"Case-insensitive substring over body, content type, method, event type and label values."}],"get":{"summary":"The most recent matching event, with its deliveries","description":"One call for \"what was the last Stripe event?\". 404 when nothing matches.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"method":{"type":"string"},"headers":{"type":"object","additionalProperties":{"type":"string"}},"body":{"type":"string","nullable":true},"content_type":{"type":"string","nullable":true},"source_ip":{"type":"string","nullable":true},"provider":{"type":"string","nullable":true,"description":"null means unattributed, not an error."},"event_type":{"type":"string","nullable":true},"signature_valid":{"type":"boolean","nullable":true},"signature_failure_reason":{"type":"string","nullable":true,"enum":["missing_header","malformed_header","malformed_timestamp","timestamp_out_of_tolerance","signature_mismatch"],"description":"Why verification failed. timestamp_out_of_tolerance means a delayed or replayed delivery, NOT a wrong secret."},"ip_allowed":{"type":"boolean","nullable":true},"received_at":{"type":"string","format":"date-time"},"labels":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"},"color":{"type":"string"}}}}}}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/endpoints/{id}/events/wait":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"since","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only events at or after this time. ISO 8601, or a bare YYYY-MM-DD."},{"name":"until","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only events at or before this time."},{"name":"provider","in":"query","schema":{"type":"string","enum":["stripe","github"]},"description":"Provider attributed from request headers at ingest."},{"name":"type","in":"query","schema":{"type":"string"},"description":"The provider's own event name, matched exactly (e.g. payment_intent.succeeded)."},{"name":"method","in":"query","schema":{"type":"string"}},{"name":"signature_valid","in":"query","schema":{"type":"boolean"}},{"name":"q","in":"query","schema":{"type":"string"},"description":"Case-insensitive substring over body, content type, method, event type and label values."},{"name":"timeout","in":"query","schema":{"type":"integer","minimum":1,"maximum":55,"default":30}}],"get":{"summary":"Long-poll for the next matching event","description":"Blocks until a matching event arrives or the timeout elapses. Non-matching events do not consume the wait. Use this instead of sleeping while a human triggers a test webhook.","responses":{"200":{"description":"An event arrived","content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"object","properties":{"id":{"type":"string"},"method":{"type":"string"},"headers":{"type":"object","additionalProperties":{"type":"string"}},"body":{"type":"string","nullable":true},"content_type":{"type":"string","nullable":true},"source_ip":{"type":"string","nullable":true},"provider":{"type":"string","nullable":true,"description":"null means unattributed, not an error."},"event_type":{"type":"string","nullable":true},"signature_valid":{"type":"boolean","nullable":true},"signature_failure_reason":{"type":"string","nullable":true,"enum":["missing_header","malformed_header","malformed_timestamp","timestamp_out_of_tolerance","signature_mismatch"],"description":"Why verification failed. timestamp_out_of_tolerance means a delayed or replayed delivery, NOT a wrong secret."},"ip_allowed":{"type":"boolean","nullable":true},"received_at":{"type":"string","format":"date-time"},"labels":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"},"color":{"type":"string"}}}}}}}}}}},"204":{"description":"Timed out; call again"},"400":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/endpoints/{id}/deliveries":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"success","in":"query","schema":{"type":"boolean"},"description":"false lists failed deliveries."},{"name":"source","in":"query","schema":{"type":"string","enum":["rule","replay","manual_test"]}},{"name":"limit","in":"query","schema":{"type":"integer","maximum":100,"default":20}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"get":{"summary":"Outbound delivery attempts for this endpoint","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"deliveries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"event_id":{"type":"string"},"destination_id":{"type":"string"},"destination_name":{"type":"string","nullable":true},"destination_url":{"type":"string","nullable":true},"rule_id":{"type":"string","nullable":true},"source":{"type":"string","enum":["rule","replay","manual_test"]},"attempt_number":{"type":"integer"},"request_headers":{"type":"object","nullable":true},"request_body":{"type":"string","nullable":true},"response_status":{"type":"integer","nullable":true},"response_body":{"type":"string","nullable":true},"latency_ms":{"type":"integer","nullable":true},"success":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}}}},"next_cursor":{"type":"string","nullable":true}}}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/events/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"summary":"One event, with every delivery attempt made for it","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/events/{id}/replay":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"summary":"Re-send a captured event to any URL","description":"Captured headers — including the provider signature — are replayed verbatim by default. If the receiver verifies with a different secret, or you change the body, pass resign_with so the signature is recomputed over what is actually sent and the receiver's own verification passes.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string"},"preserve_headers":{"type":"boolean","default":true},"headers":{"type":"object","additionalProperties":{"type":"string"}},"body":{"type":"string"},"resign_with":{"type":"string","minLength":16},"signature_header":{"type":"string","default":"x-signature"}}}}}},"responses":{"200":{"description":"Sent","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"integer","nullable":true},"latency_ms":{"type":"integer"},"success":{"type":"boolean"},"sent_headers":{"type":"object"},"response_body":{"type":"string","nullable":true},"error":{"type":"string","nullable":true}}}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/endpoints/{id}/destinations":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"summary":"List destinations","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}},"post":{"summary":"Add a forwarding destination, optionally with its rule","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string"},"name":{"type":"string"},"forward_all":{"type":"boolean","description":"Forward every future event."},"condition_tree":{"description":"A condition group { op: \"AND\"|\"OR\", children: [...] } or a leaf { field, operator, value? }, nested arbitrarily. field is \"body.<dot.path>\", \"header.<name>\" or \"meta.<key>\". operator is equals|not_equals|contains|exists|regex; all but exists require value. An empty AND group matches every event.","type":"object"},"rule_name":{"type":"string"}}}}}},"responses":{"201":{"description":"Created"},"400":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/destinations/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"summary":"Get a destination","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}},"patch":{"summary":"Update a destination","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"name":{"type":"string"},"headers":{"type":"object","nullable":true}}}}}},"responses":{"200":{"description":"OK"},"400":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}},"delete":{"summary":"Delete a destination","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/endpoints/{id}/rules":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"summary":"List routing rules","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}},"post":{"summary":"Create a routing rule","description":"The condition tree is validated on write; a malformed one is rejected rather than stored as a rule that silently never matches.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["name","condition_tree","destination_ids"],"properties":{"name":{"type":"string"},"condition_tree":{"description":"A condition group { op: \"AND\"|\"OR\", children: [...] } or a leaf { field, operator, value? }, nested arbitrarily. field is \"body.<dot.path>\", \"header.<name>\" or \"meta.<key>\". operator is equals|not_equals|contains|exists|regex; all but exists require value. An empty AND group matches every event.","type":"object"},"destination_ids":{"type":"array","items":{"type":"string"},"minItems":1},"active":{"type":"boolean","default":true}}}}}},"responses":{"201":{"description":"Created"},"400":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/rules/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"summary":"Get a rule","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}},"patch":{"summary":"Update a rule","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"active":{"type":"boolean"},"condition_tree":{"description":"A condition group { op: \"AND\"|\"OR\", children: [...] } or a leaf { field, operator, value? }, nested arbitrarily. field is \"body.<dot.path>\", \"header.<name>\" or \"meta.<key>\". operator is equals|not_equals|contains|exists|regex; all but exists require value. An empty AND group matches every event.","type":"object"},"destination_ids":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"OK"},"400":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}},"delete":{"summary":"Delete a rule","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/endpoints/{id}/auth-config":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"summary":"Signature verification config (never includes the secret)","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}},"patch":{"summary":"Enable verification and set the signing secret","description":"Set the PROVIDER's own secret (Stripe's whsec_..., GitHub's configured secret). A platform-generated secret can only verify traffic we signed ourselves. The scheme is detected from the header's shape, so there is no algorithm to configure.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"hmac_enabled":{"type":"boolean"},"secret":{"type":"string","minLength":16},"header_name":{"type":"string"},"tolerance_seconds":{"type":"integer","minimum":1},"on_failure":{"type":"string","enum":["reject","accept_log"]},"log_blocked_ips":{"type":"boolean"}}}}}},"responses":{"200":{"description":"OK"},"400":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/endpoints/{id}/auth-config/rotate-secret":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"summary":"Generate and return a new platform signing secret","description":"Do not call this on an endpoint verifying a real provider — providers issue their own secrets and will not accept a rotated one, so every delivery would begin failing verification.","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/endpoints/{id}/allowlist":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"summary":"List IP allowlist entries","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}},"post":{"summary":"Add an IP or CIDR range","description":"The allowlist is deny-by-default once non-empty: adding the first entry starts rejecting every source not covered by it.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cidr"],"properties":{"cidr":{"type":"string"}}}}}},"responses":{"201":{"description":"Created"},"400":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/allowlist/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"delete":{"summary":"Remove an allowlist entry","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/endpoints/{id}/labels":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"summary":"List label rules","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}},"post":{"summary":"Extract a value from every future event as a searchable tag","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["path","output_key"],"properties":{"source":{"type":"string","enum":["body","header"],"default":"body"},"path":{"type":"string"},"output_key":{"type":"string"},"color":{"type":"string"}}}}}},"responses":{"201":{"description":"Created"},"400":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/labels/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"patch":{"summary":"Update a label rule","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}},"delete":{"summary":"Delete a label rule","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/endpoints/{id}/stats":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"summary":"24-hour rollup: volume, success rate, latency, destination health","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/schemas":{"parameters":[{"name":"provider","in":"query","schema":{"type":"string"}},{"name":"event_type","in":"query","schema":{"type":"string"}}],"get":{"summary":"Learned event shapes for this account","description":"What the account's traffic has taught us, retained permanently — a schema listed here may have no payloads left behind it. Derived from real traffic, so it is ground truth about the provider that cannot be reconstructed from training data.","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/schemas/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","schema":{"type":"string"},"description":"A version number or \"current\" (default)."}],"get":{"summary":"One schema: fields, types, optionality, presence","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/schemas/{id}/versions":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"summary":"The evolution timeline, newest first","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/schemas/{id}/diff":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"from","in":"query","schema":{"type":"string"},"description":"Version number; defaults to the one before \"to\"."},{"name":"to","in":"query","schema":{"type":"string"},"description":"Version number or \"current\"."}],"get":{"summary":"What changed between two versions, and what breaks","description":"The \"why did production break?\" endpoint. Each change is classified added|removed|type_changed|became_nullable|became_required and flagged breaking (from the consumer's side) or not.","responses":{"200":{"description":"OK"},"400":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/schemas/{id}/types":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"lang","in":"query","schema":{"type":"string","enum":["typescript","json-schema","zod"],"default":"typescript"}},{"name":"framework","in":"query","schema":{"type":"string","enum":["next","express"]},"description":"Return a ready-to-paste handler (type + zod validation + verify step) instead of a bare type. Overrides lang."},{"name":"version","in":"query","schema":{"type":"string"}}],"get":{"summary":"Types, a validator, or a handler generated from the real shape","description":"Optional fields are emitted optional, nullable ones nullable, because that is what was actually observed. lang gives a bare type (typescript/json-schema/zod); framework gives a Next/Express handler. Generated fresh each request, never cached, so it never drifts from the schema.","responses":{"200":{"description":"OK"},"400":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/schemas/{id}/correlations":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","schema":{"type":"string"}}],"get":{"summary":"Correlation-key candidates for a learned schema","description":"The id-like fields to group events by when reconstructing a lifecycle, ranked by how consistently they appear. A read over data already collected at learn time.","responses":{"200":{"description":"OK"},"400":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/v1/endpoints/{id}/schemas":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"summary":"Learned shapes seen on one endpoint","responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}},"/api/start":{"post":{"summary":"Provision a temporary endpoint with no account and no API key","description":"The only unauthenticated write. Returns a 3-day endpoint: ingest_url for the provider, inbox_url for the human. No /v1 access — registering (free) claims it permanently. Without cookie persistence every call mints a NEW endpoint, so call it once and reuse ingest_url.","security":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ref":{"type":"string"},"provider_hint":{"type":"string"}}}}}},"responses":{"200":{"description":"Provisioned","content":{"application/json":{"schema":{"type":"object","properties":{"endpoint_id":{"type":"string"},"inbox_url":{"type":"string"},"ingest_url":{"type":"string"},"expires_at":{"type":"string"},"expires_in_days":{"type":"integer"},"reused":{"type":"boolean"}}}}}},"409":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}},"429":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}}}}}}}}}