API Reference
Complete reference for the HostWebhook REST API — ingress, webhook management, payload filters, and event operations.
Base URL
https://api.hostwebhook.comhostwh login — the dashboard and CLI handle authentication automatically.Every node lives in a workspace
POST to a node collection such as /api/webhooks, /api/http-actions or /api/triggers) requires workspaceId in the body. Without it the API answers 400 with "code": "workspace_required". The API no longer picks your Default workspace for you: send the id of the workspace the node belongs to. You can list yours with GET /api/workspaces.Ingress (webhook receiver)
/api/in/:tokenpublicAccept an incoming webhook. Responds immediately with 202 Accepted. The payload is stored and queued for delivery.
Path / query params
tokenstringrequiredIngress token from the webhookHTTP 202 Accepted
{ "eventId": "64f1a2b3c4d5e6f7a8b9c0d1" }Webhooks
List webhooks
/webhooksList all webhooks for the authenticated user/organization.
[{ "id": "...", "name": "Stripe prod", "targetUrl": "https://...", "isActive": true, ... }]Create webhook
/webhooksCreate a new webhook. Returns the webhook with its ingress URL and signing secret.
Request body
namestringrequiredFriendly labeltargetUrlstringYour server's webhook handler URL (optional — leave empty for notification-only webhooks)descriptionstringOptional descriptionisActivebooleanWhether it accepts deliveries (default: false — a new webhook starts paused; send true to create it live, or activate it later with PATCH /webhooks/:id or /toggle-active)maxRetriesnumber0–20 (default: 3)retryDelaySecondsnumberBase delay for exponential backoff (default: 60, min: 10)rateLimitPerMinutenumberMax deliveries per minute — 0 = unlimited (default: 0)incomingSignatureTypestringVerify inbound signatures: none | stripe | github | custom (default: none)incomingSignatureSecretstringSecret used to verify inbound signatures (required if type ≠ none)payloadFiltersPayloadFilter[]Rules to discard events before deliverypayloadTransformstringJSON template with {{path}} interpolation — reshapes the payload before it is delivered to targetUrldegradedAfternumberConsecutive failures before health → degraded (default: 2)downAfternumberConsecutive failures before health → down (default: 4){
"id": "...",
"name": "Stripe prod",
"targetUrl": "https://yourapp.com/webhooks",
"ingressToken": "tok_...",
"signingSecret": "whsec_...",
"isActive": false,
"maxRetries": 3,
"retryDelaySeconds": 60,
"rateLimitPerMinute": 0,
"incomingSignatureType": "stripe",
"payloadFilters": [],
"healthStatus": "healthy",
"createdAt": "2024-05-01T12:00:00.000Z"
}Get webhook
/webhooks/:idGet a single webhook by ID.
Path / query params
idstringrequiredWebhook IDUpdate webhook
/webhooks/:idUpdate any webhook field. All fields are optional — only provided fields are updated.
Path / query params
idstringrequiredWebhook IDRequest body
namestringtargetUrlstringdescriptionstringmaxRetriesnumberretryDelaySecondsnumberrateLimitPerMinutenumberisActivebooleanincomingSignatureTypestringincomingSignatureSecretstringpayloadFiltersPayloadFilter[]Replaces the full filter listpayloadTransformstring | nullSet to null to remove the transformDelete webhook
/webhooks/:idPermanently delete a webhook and all its events.
Path / query params
idstringrequiredWebhook ID204 No Content
Toggle active
/webhooks/:id/toggle-activeToggle the webhook's isActive status (pause/activate).
Path / query params
idstringrequiredWebhook ID{ "isActive": false }Rotate ingress token
/webhooks/:id/rotate-tokenGenerate a new ingress token. The old ingress URL stops working immediately.
Path / query params
idstringrequiredWebhook ID{ "ingressToken": "tok_newtoken..." }Rotate signing secret
/webhooks/:id/rotate-signing-secretGenerate a new signing secret. The old secret stops working immediately.
Path / query params
idstringrequiredWebhook ID{ "signingSecret": "whsec_newsecret..." }Payload Filters
Payload filters discard events before delivery. Only events matching all rules are delivered — non-matching events are marked filtered.
PayloadFilter object
| Field | Type | Description |
|---|---|---|
| field | string | Dot-notation path (e.g. data.object.status) |
| operator | string | eq | neq | contains | gt | lt | exists | not_exists | in | not_in |
| value | string? | Comparison value — not required for exists / not_exists |
Example
{
"payloadFilters": [
{ "field": "type", "operator": "eq", "value": "invoice.paid" },
{ "field": "data.object.amount_paid", "operator": "gt", "value": "1000" }
]
}Events
List events
/eventsList events with optional filters. Returns paginated results.
Path / query params
webhookIdstringFilter by webhookstatusstringpending | delivered | retrying | failed | filteredeventTypestringMatch the top-level type or event field in the payloaddateFromstringISO 8601 date (inclusive)dateTostringISO 8601 date (inclusive)pagenumberPage number (default: 1)limitnumberResults per page (default: 15, max: 100){
"data": [{ "id": "...", "status": "delivered", "createdAt": "...", ... }],
"total": 142,
"page": 1,
"limit": 15
}Get distinct event types
/events/typesGet all distinct event types (top-level type field) seen on a webhook. Used to populate filter dropdowns.
Path / query params
webhookIdstringFilter to one webhook["payment_intent.succeeded", "payment_intent.created", "customer.subscription.updated"]
Get event
/events/:idGet a single event with its full payload.
Path / query params
idstringrequiredEvent IDDelivery attempts
/events/:eventId/deliveriesList all delivery attempts for an event, including response body, latency, and target info.
Path / query params
eventIdstringrequired[{
"id": "...",
"targetUrl": "https://yourapp.com/webhooks",
"attempt": 1,
"statusCode": 200,
"responseBody": "ok",
"latencyMs": 143,
"success": true,
"attemptedAt": "2024-05-01T12:00:00.000Z"
}]Replay event
/events/:eventId/replayManually replay an event. Creates a new delivery attempt with the original payload.
Path / query params
eventIdstringrequired{ "ok": true }Replay all failed
/events/replay-allReplay all failed events for a webhook.
Path / query params
webhookIdstringrequiredQuery param{ "queued": 12 }Cancel event
/events/:eventId/cancelCancel a pending or retrying event. Cannot be undone, but can be replayed.
Path / query params
eventIdstringrequired204 No Content
Delivery stats
/events/statsAggregate delivery stats for the current user.
Path / query params
webhookIdstringFilter to one webhook{ "total": 1200, "delivered": 1180, "failed": 20, "successRate": 98.3 }Latency stats
/events/latencyLatency percentiles (ms) for successful deliveries.
Path / query params
webhookIdstringFilter to one webhook{ "avg": 210, "p95": 580, "p99": 1240 }Routers
/routersList all routers.
/routersCreate a router with conditional routing rules.
Request body
namestringrequiredRouter nameroutesRoute[]Array of {field, operator, value, outputWebhookId}/routers/:idUpdate a router.
Path / query params
idstringrequired/routers/:idDelete a router.
Path / query params
idstringrequired204 No Content
Filter Nodes
/filter-nodesList all filter nodes.
/filter-nodesCreate a filter node.
Request body
namestringrequiredFilter namefilterModestring'and' | 'or' (default: 'and')filtersFilter[]Array of {field, operator, value}/filter-nodes/:idUpdate a filter node.
Path / query params
idstringrequired/filter-nodes/:idDelete a filter node.
Path / query params
idstringrequired204 No Content
Transform Nodes
/transform-nodesList all transform nodes.
/transform-nodesCreate a transform node.
Request body
namestringrequiredTransform nametransformModestring'handlebars' | 'jq' | 'javascript'templatestringTransform template string/transform-nodes/:idUpdate a transform node.
Path / query params
idstringrequired/transform-nodes/:idDelete a transform node.
Path / query params
idstringrequired204 No Content
Schema Validators
/schema-validatorsList all schema validators.
/schema-validatorsCreate a schema validator.
Request body
namestringrequiredValidator namestrictModebooleanReject payloads with extra fields (default: false)fieldsField[]Array of {path, type, required, constraints}/schema-validators/:idUpdate a schema validator.
Path / query params
idstringrequired/schema-validators/:idDelete a schema validator.
Path / query params
idstringrequired204 No Content
Delay Nodes
/delay-nodesList all delay nodes.
/delay-nodesCreate a delay node.
Request body
namestringrequiredDelay namedelaySecondsnumberrequiredSeconds to delay before forwarding/delay-nodes/:idUpdate a delay node.
Path / query params
idstringrequired/delay-nodes/:idDelete a delay node.
Path / query params
idstringrequired204 No Content
Merge Nodes
/merge-nodesList all merge nodes.
/merge-nodesCreate a merge node.
Request body
namestringrequiredMerge namemodestring'wait_all' | 'first' (default: 'wait_all')expectedBranchCountnumberNumber of branches to wait for/merge-nodes/:idUpdate a merge node.
Path / query params
idstringrequired/merge-nodes/:idDelete a merge node.
Path / query params
idstringrequired204 No Content
Approval Nodes
/approval-nodesList all approval nodes.
/approval-nodesCreate an approval node.
Request body
namestringrequiredApproval gate nametimeoutMinutesnumberAuto-action after timeout (default: 60)autoActionOnTimeoutstring'approve' | 'reject' (default: 'reject')notifyEmailsstring[]Emails to notify for approval/approval-nodes/:id/approveApprove a pending event at this gate.
Path / query params
idstringrequired/approval-nodes/:id/rejectReject a pending event at this gate.
Path / query params
idstringrequired/approval-nodes/:idUpdate an approval node.
Path / query params
idstringrequired/approval-nodes/:idDelete an approval node.
Path / query params
idstringrequired204 No Content
Email Actions
/email-actionsList all email actions.
/email-actionsCreate an email action.
Request body
namestringrequiredEmail action nametostringrequiredRecipient emailsubjectstringEmail subject (supports templates)bodystringEmail body (supports templates)triggerOnstring'success' | 'failure' | 'always'/email-actions/:idUpdate an email action.
Path / query params
idstringrequired/email-actions/:idDelete an email action.
Path / query params
idstringrequired204 No Content
Gmail
/gmail-actionsList all Gmail nodes.
/gmail-actionsCreate a Gmail node.
Request body
namestringrequiredGmail node namecredentialIdstringConnected Google accountoperationstringOne of the 17 operations (default: 'send')operationConfigobjectParameters for the chosen operation (supports templates)aiEnabledbooleanExpose the 16-tool toolkit to an AI NodetriggerOnstring'success' | 'always'/gmail-actions/:idUpdate a Gmail node.
Path / query params
idstringrequiredGmail node ID/gmail-actions/:idDelete a Gmail node.
Path / query params
idstringrequiredGmail node ID/gmail-actions/labels/:credentialIdList the account's Gmail labels.
Path / query params
credentialIdstringrequiredConnected Google accountHTTP Actions
/http-actionsList all HTTP actions.
/http-actionsCreate an HTTP action.
Request body
namestringrequiredHTTP action nameurlstringrequiredTarget URLmethodstringGET | POST | PUT | PATCH | DELETE (default: POST)headersobjectCustom headersbodystringRequest body templatetriggerOnstring'success' | 'failure' | 'always'/http-actions/:idUpdate an HTTP action.
Path / query params
idstringrequired/http-actions/:idDelete an HTTP action.
Path / query params
idstringrequired204 No Content
MongoDB Actions
/mongo-actionsList all MongoDB actions.
/mongo-actionsCreate a MongoDB action.
Request body
namestringrequiredAction nameconnectionUristringrequiredMongoDB connection string (encrypted)databasestringrequiredDatabase namecollectionstringrequiredCollection nameoperationstring'insertOne' | 'updateOne' | 'replaceOne'documentstringDocument template/mongo-actions/:idUpdate a MongoDB action.
Path / query params
idstringrequired/mongo-actions/:idDelete a MongoDB action.
Path / query params
idstringrequired204 No Content
Notification Actions
/notification-actionsList all notification actions (Slack/Discord).
/notification-actionsCreate a notification action.
Request body
namestringrequiredAction nameplatformstringrequired'slack' | 'discord'webhookUrlstringrequiredPlatform webhook URLtemplatePresetstring'default' | 'detailed' | 'minimal' | 'custom'triggerOnstring'success' | 'failure' | 'always'/notification-actions/:idUpdate a notification action.
Path / query params
idstringrequired/notification-actions/:idDelete a notification action.
Path / query params
idstringrequired204 No Content
Google Sheets Actions
/sheets-actionsList all Google Sheets actions.
/sheets-actionsCreate a Sheets action.
Request body
namestringrequiredAction namespreadsheetIdstringrequiredGoogle Sheets spreadsheet IDsheetNamestringSheet tab name (default: Sheet1)operationstring'append_row' | 'update_cell'columnsstring[]Template array mapping payload fields to columns/sheets-actions/:idUpdate a Sheets action.
Path / query params
idstringrequired/sheets-actions/:idDelete a Sheets action.
Path / query params
idstringrequired204 No Content
Scheduled Workflows
/scheduled-workflowsList all scheduled webhooks.
/scheduled-workflowsCreate a scheduled webhook (cron-based HTTP calls).
Request body
namestringrequiredNamecronExpressionstringrequiredCron expression (e.g. '0 */5 * * *')urlstringTarget URL (or connect to a webhook)methodstringHTTP method (default: POST)headersobjectCustom headersbodystringRequest bodyisActivebooleanEnable/disable (default: true)/scheduled-workflows/:idUpdate a scheduled webhook.
Path / query params
idstringrequired/scheduled-workflows/:idDelete a scheduled webhook.
Path / query params
idstringrequired204 No Content
Vector Stores
Everything the dashboard does under Settings → Vector Stores and in the Vector Store node, over REST. The plain-language guide is Vector Stores Quick Start; this section is the exact contract.
Catalog
/vector-stores/providers/embeddingsEmbedding providers and their models: id, dimensions, max input tokens, price per million tokens, and whether the model is available on the managed backend.
/vector-stores/providers/backendsStorage backends: hostwebhook (managed), mongo_atlas, mongo_external, pgvector — with the config fields each one needs.
/vector-stores/test-backendTest a bring-your-own backend before creating the store. Reports server version, vector support, and whether the index or table exists; for Mongo it returns the index JSON to create, for Postgres the SQL.
Request body
backendobjectrequired{ provider, config } — same shape as on createdimensionsnumberVector size of the model you intend to use (needed to validate the index)/vector-stores/setup-backendpgvector only: idempotently create the extension, table and index the test reported missing, then re-test.
Request body
backendobjectrequired{ provider: 'pgvector', config }dimensionsnumberrequiredVector size for the columnStores
/vector-storesList the organization's stores with their stats.
/vector-storesCreate a store. Provider, model and backend are immutable afterwards — every chunk is vectorised under them.
Request body
namestringrequiredDisplay name; also the basis of the AI-tool name (query_<name>)descriptionstringShown in lists and used as the AI-tool descriptionembeddingobjectrequired{ provider: 'openai' | 'cohere', model, credentialId }backendobjectrequired{ provider: 'mongo_atlas' | 'mongo_external' | 'pgvector', config? } — omit config for the managed backendchunkingobject{ strategy: 'recursive' | 'fixed', chunkSize (50–8000 chars), chunkOverlap (0–4000, < chunkSize) }. Default recursive / 500 / 50requireCleanScanbooleanWait for a clean malware verdict before storing an uploaded file (default true)dedupOnIngestbooleanSkip chunks whose content hash already exists (default true)workspaceIdstringWorkspace the store belongs to/vector-stores/:idOne store, with its embedding config, backend, chunking and stats.
Path / query params
idstringrequired/vector-stores/:idUpdate what is mutable: name, description, credentialId (same provider only), chunking (applies to future ingests), isActive (pause / resume), requireCleanScan, dedupOnIngest.
Path / query params
idstringrequired/vector-stores/:idDrop the store and every chunk in it. Nodes and AI tools that reference it keep the id and fail until re-pointed — the dashboard shows them as disconnected.
Path / query params
idstringrequired204 No Content
/vector-stores/:id/statsCurrent chunk count, stored bytes, tokens embedded, and last usage.
Path / query params
idstringrequired/vector-stores/:id/access-logPaginated audit log: create, update, insert_chunks, query, delete, delete_chunks — with timestamp, user and source IP.
Path / query params
idstringrequiredlimitnumberDefault 100offsetnumberContent
/vector-stores/:id/ingestChunk, embed and store text and/or an uploaded file. Content type (JSON, CSV, Markdown, code, prose) is detected and split structure-aware; a chunk identical to one already stored is skipped when dedup is on.
Path / query params
idstringrequiredRequest body
textstringText to ingest. Either text or fileId is requiredfileIdstringId of a file uploaded to the organization's file store (PDF, CSV, JSON, text/*)sourceDocIdstringLogical document id — what delete-by-document and upsert key onsourceDocNamestringHuman label shown next to every matchsourceDocTypestringOptional type hintmetadataobjectFlat object of scalar values stored on every chunk; queryable via filterchunkingOverrideobject{ strategy, chunkSize, chunkOverlap } for this ingest only{
"chunksInserted": 42,
"skipped": 3,
"bytes": 21014,
"sourceCount": 2,
"upsertedOver": 18,
"warnings": ["json: value at chapters[4] exceeded the per-chunk limit and was split as text"],
"skippedFiles": [{ "name": "logo.png", "reason": "binary" }]
}upsertedOver, warnings and skippedFiles are present only when they apply. When nothing extractable arrived the call succeeds with chunksInserted: 0 and a skippedReason such as empty text and no file. From the Vector Store node the same object is the node's output, wrapped as { "_meta": { "iterable": false, "count": 1, "success": true, "mode": "insert" }, ... }.
/vector-stores/:id/querySemantic search: the query is embedded with the store's model (billed to the store's key) and compared against every chunk. Returns the top-K matches with scores.
Path / query params
idstringrequiredRequest body
querystringrequiredThe questiontopKnumberMax matches, 1–50 (default 5)minScorenumberCosine similarity floor, 0–1; matches below it are droppedfilterobjectFlat object of scalar values matched against chunk metadata (see below){
"matches": [
{
"chunkId": "665f...",
"content": "Refunds are issued to the original payment method within 14 days…",
"score": 0.871,
"sourceDocId": "https://example.com/policies/returns",
"sourceDocName": "Returns policy",
"metadata": { "tenant": "acme", "lang": "en" }
}
],
"tookMs": 212
}From the Vector Store node the output is the same object marked iterable over matches: "_meta": { "iterable": true, "iterateField": "matches", "count": 3, "success": true, "mode": "query" }.
/vector-stores/:id/delete-chunksDelete chunks by id, by document, or by metadata filter. At least one selector is required; an empty selector deletes nothing and returns deletedCount: 0 with a skippedReason.
Path / query params
idstringrequiredRequest body
chunkIdsstring[]Specific chunkssourceDocIdstringEvery chunk of that documentmetadataobjectEvery chunk whose metadata matches this flat object{ "deletedCount": 18 }/vector-stores/:id/flushDelete every chunk and keep the store, its config and its credential.
Path / query params
idstringrequired{ "deletedCount": 1204 }/vector-stores/:id/chunksPaginated browse of chunks, without embeddings — what the Content tab shows.
Path / query params
idstringrequiredlimitnumberDefault 50offsetnumbersourceDocIdstringOnly this documentsourceDocNamestringOnly documents with this labelsearchstringSubstring of the chunk textfilter or metadata selector must be a flat object of scalar values. Objects, arrays and keys starting with $ are rejected with 400, and the operation aborts rather than running with a wider filter. The reason is what a template does with a public payload:template { "customerId": "{{payload.customerId}}" }
payload { "customerId": { "$ne": "__none__" } }
filter { "customerId": { "$ne": "__none__" } } ← would match everyoneCanvas Snapshots
/canvas-snapshotsList all canvas snapshots.
/canvas-snapshotsSave a canvas snapshot (nodes + edges layout).
Request body
namestringrequiredSnapshot namenodesobject[]requiredReactFlow nodes arrayedgesobject[]requiredReactFlow edges array/canvas-snapshots/:idGet a single snapshot.
Path / query params
idstringrequired/canvas-snapshots/:idDelete a snapshot.
Path / query params
idstringrequired204 No Content
Time Travel
/events/:id/time-travelDry-run replay an event through a historical canvas snapshot.
Request body
snapshotIdstringrequiredCanvas snapshot ID to simulate against{
"steps": [{ "node": "schema-validator", "name": "...", "result": "pass" }, ...],
"finalStatus": "delivered",
"matchedNodes": 4
}Contract Testing
/events/:webhookId/contract-healthValidate recent events against connected schema validators.
Path / query params
webhookIdstringrequiredWebhook IDlimitnumberNumber of recent events to check (default: 100){
"score": 94,
"totalChecked": 100,
"passed": 94,
"failed": 6,
"validators": [{ "id": "...", "name": "...", "passRate": 94 }]
}Errors
All error responses follow a consistent shape:
{
"statusCode": 400,
"message": "targetUrl must be a URL address",
"error": "Bad Request"
}| Status | Meaning |
|---|---|
| 400 | Bad Request — invalid or missing parameters |
| 401 | Unauthorized — missing or expired session |
| 403 | Forbidden — resource belongs to another user, or plan limit exceeded |
| 404 | Not Found — resource doesn't exist |
| 429 | Too Many Requests — rate limit exceeded |
| 500 | Internal Server Error — something went wrong on our end |
| 503 | Service Unavailable — something the request needed failed or didn't answer in time. It may carry a code: upstream_unavailable or upstream_timeout for what used to be a 502 or 504 (see below), and the voice and tunnel pages list their own |
An error the API used to raise as 502 or 504 now comes back as 503, with the same message and a code — upstream_unavailable for a 502, upstream_timeout for a 504 — unless it already carried one of its own. Cloudflare, in front of the API, replaces a 502 with its own HTML page, so the message telling you what to fix never reached you.