{"info":{"title":"Webhook Dispatcher API","version":"1.0.0","description":"Read-only access to the webhook logs of a single workspace.\n\nAuthenticate every call with a workspace API key sent as `Authorization: Bearer whd_sk_...`. Keys are created from *Workspace settings → Agent access*, are scoped to the workspace that created them, and are limited to 120 calls per minute. The same key also opens the MCP endpoint at `/api/mcp`."},"servers":[{"url":"https://webhook.impulselab.ai/api/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Workspace API key, e.g. `whd_sk_...`."}},"schemas":{"UnauthorizedError":{"type":"object","description":"Missing, invalid, revoked or expired API key. The response also carries a `WWW-Authenticate` header.","properties":{"error":{"type":"string","enum":["unauthorized"]},"message":{"type":"string"}},"required":["error","message"]},"RateLimitExceededError":{"type":"object","description":"More than 120 calls in 60 seconds for this key. The response also carries a `Retry-After` header.","properties":{"error":{"type":"string","enum":["rate_limit_exceeded"]},"message":{"type":"string"},"retryAfterSeconds":{"type":"number"}},"required":["error","message","retryAfterSeconds"]},"InputValidationFailedError":{"type":"object","description":"A query or path parameter was rejected.","properties":{"defined":{"type":"boolean"},"code":{"type":"string","enum":["INPUT_VALIDATION_FAILED"]},"status":{"type":"number","enum":[422]},"message":{"type":"string"},"data":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["defined","code","status","message","data"]}}},"openapi":"3.1.1","paths":{"/webhooks":{"get":{"operationId":"listWebhooks","summary":"List webhooks","description":"List the webhooks of the workspace with their recent activity: total requests, requests in the last 24h, last request date and number of enabled destinations.","tags":["Webhooks"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"webhooks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string","description":"Slug used in the public ingest url."},"dispatchMode":{"type":"string","description":"How incoming requests are forwarded, e.g. manual or auto."},"localUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Local url targeted through the reroute CLI, if any."},"createdAt":{"type":"string","format":"date-time","x-native-type":"date"},"totalRequests":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Requests received since day 1."},"requestsLast24h":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Requests received in the last 24 hours."},"lastRequestAt":{"anyOf":[{"type":"string","format":"date-time","x-native-type":"date"},{"type":"null"}],"description":"When the last request was received."},"enabledDestinations":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of enabled forwarding destinations."}},"required":["id","name","slug","dispatchMode","localUrl","createdAt","totalRequests","requestsLast24h","lastRequestAt","enabledDestinations"]}}},"required":["webhooks"]}}}},"401":{"description":"Missing, invalid, revoked or expired API key. The response also carries a `WWW-Authenticate` header.","headers":{"WWW-Authenticate":{"description":"Bearer challenge describing why the key was rejected.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedError"}}}},"429":{"description":"More than 120 calls in 60 seconds for this key. The response also carries a `Retry-After` header.","headers":{"Retry-After":{"description":"Seconds to wait before the next call is accepted.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitExceededError"}}}}}}},"/requests":{"get":{"operationId":"listRequests","summary":"List webhook requests","description":"List the webhook requests received by the workspace, newest first. Bodies are truncated to a preview: use the detail endpoint for the full payload.","tags":["Requests"],"parameters":[{"name":"webhookId","in":"query","schema":{"type":"string","description":"Restrict to a single webhook id."},"allowEmptyValue":true,"allowReserved":true},{"name":"method","in":"query","schema":{"type":"string","description":"Filter by HTTP method, e.g. POST."},"allowEmptyValue":true,"allowReserved":true},{"name":"search","in":"query","schema":{"type":"string","description":"Full text search in body, headers, query params and url."},"allowEmptyValue":true,"allowReserved":true},{"name":"since","in":"query","schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"string","format":"date"}],"description":"ISO date, only requests received after this instant."},"allowEmptyValue":true,"allowReserved":true},{"name":"until","in":"query","schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"string","format":"date"}],"description":"ISO date, only requests received before this instant."},"allowEmptyValue":true,"allowReserved":true},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"description":"Number of items to return (1-100, default 20)."},"allowEmptyValue":true,"allowReserved":true},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Pagination offset."},"allowEmptyValue":true,"allowReserved":true}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"requests":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"webhookId":{"type":"string"},"webhookName":{"type":"string"},"webhookSlug":{"type":"string"},"method":{"type":"string","description":"HTTP method of the incoming request."},"url":{"type":"string"},"receivedAt":{"type":"string","format":"date-time","x-native-type":"date"},"pinned":{"type":"boolean"},"bodyPreview":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"First characters of the body, truncated with an ellipsis."},"bodySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Full body length in characters."}},"required":["id","webhookId","webhookName","webhookSlug","method","url","receivedAt","pinned","bodyPreview","bodySize"]}},"pagination":{"type":"object","properties":{"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items returned."},"offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Offset applied to the result set."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Total number of matching items."}},"required":["limit","offset","total"],"description":"Pagination applied to the result set."}},"required":["requests","pagination"]}}}},"401":{"description":"Missing, invalid, revoked or expired API key. The response also carries a `WWW-Authenticate` header.","headers":{"WWW-Authenticate":{"description":"Bearer challenge describing why the key was rejected.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedError"}}}},"422":{"description":"A query or path parameter was rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InputValidationFailedError"}}}},"429":{"description":"More than 120 calls in 60 seconds for this key. The response also carries a `Retry-After` header.","headers":{"Retry-After":{"description":"Seconds to wait before the next call is accepted.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitExceededError"}}}}}}},"/requests/{requestId}":{"get":{"operationId":"getRequest","summary":"Get a webhook request","description":"Full detail of one request: headers, body, query params, delivery attempts and CLI tunnel state. Credential headers are masked unless includeSecrets is true.","tags":["Requests"],"parameters":[{"name":"requestId","in":"path","required":true,"schema":{"type":"string","description":"Id returned by list_requests."}},{"name":"includeSecrets","in":"query","schema":{"type":"boolean","description":"Set to true to reveal credential headers (authorization, signatures, cookies). Off by default."},"allowEmptyValue":true,"allowReserved":true}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"request":{"type":"object","properties":{"id":{"type":"string"},"webhookId":{"type":"string"},"webhookName":{"type":"string"},"webhookSlug":{"type":"string"},"method":{"type":"string"},"url":{"type":"string"},"headers":{"description":"Headers of the incoming request. Credential headers are masked unless includeSecrets is true."},"queryParams":{"description":"Query string parsed as an object."},"body":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Raw body, untruncated."},"receivedAt":{"type":"string","format":"date-time","x-native-type":"date"},"pinned":{"type":"boolean"}},"required":["id","webhookId","webhookName","webhookSlug","method","url","body","receivedAt","pinned"]},"dispatches":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","description":"Delivery status: pending, success or error."},"responseStatus":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"HTTP status returned by the destination."},"responseBody":{"anyOf":[{"type":"string"},{"type":"null"}]},"errorMessage":{"anyOf":[{"type":"string"},{"type":"null"}]},"dispatchedAt":{"type":"string","format":"date-time","x-native-type":"date"},"destinationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"destinationUrl":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","status","responseStatus","responseBody","errorMessage","dispatchedAt","destinationName","destinationUrl"]},"description":"Delivery attempts towards the webhook destinations."},"cli":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","description":"Tunnel delivery status: pending, processing, completed or failed."},"createdAt":{"type":"string","format":"date-time","x-native-type":"date"},"machineName":{"anyOf":[{"type":"string"},{"type":"null"}]},"localUrl":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","status","createdAt","machineName","localUrl"]},"description":"Deliveries towards the reroute CLI tunnels."},"redactedHeaders":{"type":"array","items":{"type":"string"},"description":"Names of the headers that were masked in this response."},"secretsIncluded":{"type":"boolean","description":"Whether credential headers were returned in clear."}},"required":["request","dispatches","cli","redactedHeaders","secretsIncluded"]}}}},"401":{"description":"Missing, invalid, revoked or expired API key. The response also carries a `WWW-Authenticate` header.","headers":{"WWW-Authenticate":{"description":"Bearer challenge describing why the key was rejected.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedError"}}}},"404":{"description":"404","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"defined":{"const":true},"code":{"const":"REQUEST_NOT_FOUND"},"status":{"const":404},"message":{"type":"string","default":"Request not found in this workspace."},"data":{}},"required":["defined","code","status","message"]},{"type":"object","properties":{"defined":{"const":false},"code":{"type":"string"},"status":{"type":"number"},"message":{"type":"string"},"data":{}},"required":["defined","code","status","message"]}]}}}},"422":{"description":"A query or path parameter was rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InputValidationFailedError"}}}},"429":{"description":"More than 120 calls in 60 seconds for this key. The response also carries a `Retry-After` header.","headers":{"Retry-After":{"description":"Seconds to wait before the next call is accepted.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitExceededError"}}}}}}},"/stats":{"get":{"operationId":"getStats","summary":"Get workspace stats","description":"Aggregated activity over a time window: request volume per webhook and delivery success/error rate.","tags":["Stats"],"parameters":[{"name":"hours","in":"query","schema":{"type":"integer","minimum":1,"maximum":2160,"description":"Size of the time window in hours (default 24)."},"allowEmptyValue":true,"allowReserved":true},{"name":"webhookId","in":"query","schema":{"type":"string","description":"Restrict the stats to a single webhook."},"allowEmptyValue":true,"allowReserved":true}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"since":{"type":"string","format":"date-time","x-native-type":"date","description":"Start of the time window."},"totalRequests":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Requests received during the window."},"byWebhook":{"type":"array","items":{"type":"object","properties":{"webhookId":{"type":"string"},"webhookName":{"type":"string"},"requests":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["webhookId","webhookName","requests"]}},"dispatches":{"type":"object","properties":{"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Delivery attempts during the window."},"byStatus":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"Delivery attempts grouped by status."},"errorRate":{"type":"number","description":"Share of failed deliveries, between 0 and 1."}},"required":["total","byStatus","errorRate"]}},"required":["since","totalRequests","byWebhook","dispatches"]}}}},"401":{"description":"Missing, invalid, revoked or expired API key. The response also carries a `WWW-Authenticate` header.","headers":{"WWW-Authenticate":{"description":"Bearer challenge describing why the key was rejected.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedError"}}}},"422":{"description":"A query or path parameter was rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InputValidationFailedError"}}}},"429":{"description":"More than 120 calls in 60 seconds for this key. The response also carries a `Retry-After` header.","headers":{"Retry-After":{"description":"Seconds to wait before the next call is accepted.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitExceededError"}}}}}}},"/cli-connections":{"get":{"operationId":"listCliConnections","summary":"List CLI tunnels","description":"List the reroute CLI tunnels attached to the workspace webhooks: machine, local url, status, latency and last heartbeat. Most recent heartbeat first.","tags":["CLI tunnels"],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"description":"Number of items to return (1-100, default 20)."},"allowEmptyValue":true,"allowReserved":true},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Pagination offset."},"allowEmptyValue":true,"allowReserved":true}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"connections":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string"},"webhookId":{"type":"string"},"webhookName":{"type":"string"},"machineName":{"type":"string","description":"Machine running the reroute CLI."},"localUrl":{"type":"string","description":"Local url the tunnel forwards to."},"status":{"type":"string","description":"connected or disconnected."},"latencyMs":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Latency measured on the last heartbeat."},"lastHeartbeat":{"type":"string","format":"date-time","x-native-type":"date"},"createdAt":{"type":"string","format":"date-time","x-native-type":"date"}},"required":["connectionId","webhookId","webhookName","machineName","localUrl","status","latencyMs","lastHeartbeat","createdAt"]}},"pagination":{"type":"object","properties":{"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items returned."},"offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Offset applied to the result set."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Total number of matching items."}},"required":["limit","offset","total"],"description":"Pagination applied to the result set."}},"required":["connections","pagination"]}}}},"401":{"description":"Missing, invalid, revoked or expired API key. The response also carries a `WWW-Authenticate` header.","headers":{"WWW-Authenticate":{"description":"Bearer challenge describing why the key was rejected.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedError"}}}},"422":{"description":"A query or path parameter was rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InputValidationFailedError"}}}},"429":{"description":"More than 120 calls in 60 seconds for this key. The response also carries a `Retry-After` header.","headers":{"Retry-After":{"description":"Seconds to wait before the next call is accepted.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitExceededError"}}}}}}}}}