Webhooks API
REST endpoints for webhooks in SKUFlow: 13 operations with parameters, request and response fields, permissions and curl examples.
Base URL: https://app.skuflow.ai/api. Every call needs Authorization: Bearer skf_… (Authentication); {organizationId} ($ORGANIZATION_ID in the examples) is your business's id.
| Operation | Endpoint | Risk |
|---|---|---|
| List event types | GET /organizations/{organizationId}/webhooks/event-types | read |
| List webhook endpoints | GET /organizations/{organizationId}/webhooks | read |
| Create a webhook endpoint | POST /organizations/{organizationId}/webhooks | sensitive |
| Get a webhook endpoint | GET /organizations/{organizationId}/webhooks/{webhookId} | read |
| Update a webhook endpoint | PATCH /organizations/{organizationId}/webhooks/{webhookId} | sensitive |
| Delete a webhook endpoint | DELETE /organizations/{organizationId}/webhooks/{webhookId} | sensitive |
| Turn a webhook endpoint on or off | POST /organizations/{organizationId}/webhooks/{webhookId}/active | write |
| Regenerate the signing secret | POST /organizations/{organizationId}/webhooks/{webhookId}/secret | sensitive |
| List an endpoint's deliveries | GET /organizations/{organizationId}/webhooks/{webhookId}/deliveries | read |
| Get a delivery | GET /organizations/{organizationId}/webhooks/{webhookId}/deliveries/{deliveryId} | read |
| Resend a delivery | POST /organizations/{organizationId}/webhooks/{webhookId}/deliveries/{deliveryId}/resend | sensitive |
| Send a test event | POST /organizations/{organizationId}/webhooks/{webhookId}/test | write |
| List domain events | GET /organizations/{organizationId}/events | read |
List event types
GET /organizations/{organizationId}/webhooks/event-types
The event catalogue: every domain event type with its area (for subscribing by area), what it means, its payload version and the fields of its data (ids and safe fields only). Read-only.
| Permission | integrations.manage (Owner, Admin) |
| Risk | read, OAuth scope skuflow.read. Read: reads only. |
| MCP tool | webhooks_eventTypes (toolset settings) |
Example
curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/webhooks/event-types" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
areas | array of enum | |
events | array of object | |
events[].type | string | |
events[].area | enum | One of customers, sales, invoices, payments, team, inventory, engagement, marketing, website, stores, orders, reviews, phone, system. |
events[].description | string | |
events[].version | integer | |
events[].fields | array of string |
List webhook endpoints
GET /organizations/{organizationId}/webhooks
The organization's webhook endpoints with their subscribed events, whether they are on, the secret's last four characters, the last delivery and how many deliveries are failing. Read-only.
| Permission | integrations.manage (Owner, Admin) |
| Risk | read, OAuth scope skuflow.read. Read: reads only. |
| MCP tool | webhooks_list (toolset settings) |
Example
curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/webhooks" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
An array of objects:
| Field | Type | Description |
|---|---|---|
id | string | |
url | string | |
description | string or null | |
eventTypes | array of string | Empty = every event. |
active | boolean | |
secretHint | string | The signing secret's last four characters. |
consecutiveDeadCount | integer | |
disabledAt | string or null | |
disabledReason | string or null | Why it was turned off automatically (repeated failures); null when turned off by hand. |
createdById | string or null | |
createdAt | string | |
updatedAt | string | |
lastDeliveryAt | string or null | |
failingDeliveries | integer |
Create a webhook endpoint
POST /organizations/{organizationId}/webhooks
Sends data out: from now on, the organization's events (all, or eventTypes) are POSTed to url as JSON {id, type, occurredAt, organizationId, data}, signed with SKUFlow-Signature: t=<unix>,v1=<hex HMAC-SHA256 of "t.body">. Returns the signing secret ONCE. Retries 1 m, 5 m, 30 m, 2 h, 12 h, then DEAD; an endpoint whose deliveries die 5 times in a row is turned off. Send a test with POST /webhooks/{webhookId}/test.
| Permission | integrations.manage (Owner, Admin) |
| Risk | sensitive, OAuth scope skuflow.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access. |
| MCP tool | webhooks_create (toolset settings) |
| Approval | Waits for your approval in SKUFlow when called with an API key or a connected app: the first call answers 428 APPROVAL_REQUIRED; once you approve it, repeat the call with the X-SKUFlow-Approval header. See Approvals. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Where events are POSTed. https only (http://localhost only where the server allows private targets, i.e. development). Private, loopback and link-local addresses are refused. Up to 2048 characters. |
description | string or null | No | Up to 500 characters. |
eventTypes | array of string | No | The events to send; empty or omitted = every event. Up to 100 items. |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/webhooks" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com"}'Response
201: the answer's fields
| Field | Type | Description |
|---|---|---|
endpoint | object | |
endpoint.id | string | |
endpoint.url | string | |
endpoint.description | string or null | |
endpoint.eventTypes | array of string | Empty = every event. |
endpoint.active | boolean | |
endpoint.secretHint | string | The signing secret's last four characters. |
endpoint.consecutiveDeadCount | integer | |
endpoint.disabledAt | string or null | |
endpoint.disabledReason | string or null | Why it was turned off automatically (repeated failures); null when turned off by hand. |
endpoint.createdById | string or null | |
endpoint.createdAt | string | |
endpoint.updatedAt | string | |
endpoint.lastDeliveryAt | string or null | |
endpoint.failingDeliveries | integer | |
secret | string | The signing secret (whsec_…). Shown this once: store it now; reads only show its last four characters. |
Get a webhook endpoint
GET /organizations/{organizationId}/webhooks/{webhookId}
One endpoint with its delivery counts by status. The secret is never returned here (only its last four characters). Read-only.
| Permission | integrations.manage (Owner, Admin) |
| Risk | read, OAuth scope skuflow.read. Read: reads only. |
| MCP tool | webhooks_get (toolset settings) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
webhookId | path | string | Yes | From GET /webhooks. |
Example
curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/webhooks/{webhookId}" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
id | string | |
url | string | |
description | string or null | |
eventTypes | array of string | Empty = every event. |
active | boolean | |
secretHint | string | The signing secret's last four characters. |
consecutiveDeadCount | integer | |
disabledAt | string or null | |
disabledReason | string or null | Why it was turned off automatically (repeated failures); null when turned off by hand. |
createdById | string or null | |
createdAt | string | |
updatedAt | string | |
lastDeliveryAt | string or null | |
failingDeliveries | integer | |
deliveryCounts | object | |
deliveryCounts.PENDING | integer | |
deliveryCounts.SUCCEEDED | integer | |
deliveryCounts.FAILED | integer | |
deliveryCounts.DEAD | integer |
Update a webhook endpoint
PATCH /organizations/{organizationId}/webhooks/{webhookId}
Sends data out: change an endpoint's URL, description or subscribed events (empty = all). A new URL receives every later event. The secret is unchanged.
| Permission | integrations.manage (Owner, Admin) |
| Risk | sensitive, OAuth scope skuflow.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access. |
| MCP tool | webhooks_update (toolset settings) |
| Approval | Waits for your approval in SKUFlow when called with an API key or a connected app: the first call answers 428 APPROVAL_REQUIRED; once you approve it, repeat the call with the X-SKUFlow-Approval header. See Approvals. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
webhookId | path | string | Yes | From GET /webhooks. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
url | string | No | Where events are POSTed. https only (http://localhost only where the server allows private targets, i.e. development). Private, loopback and link-local addresses are refused. Up to 2048 characters. |
description | string or null | No | Up to 500 characters. |
eventTypes | array of string | No | The events to send; empty or omitted = every event. Up to 100 items. |
Example
curl -X PATCH "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/webhooks/{webhookId}" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com","description":"string","eventTypes":["string"]}'Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
id | string | |
url | string | |
description | string or null | |
eventTypes | array of string | Empty = every event. |
active | boolean | |
secretHint | string | The signing secret's last four characters. |
consecutiveDeadCount | integer | |
disabledAt | string or null | |
disabledReason | string or null | Why it was turned off automatically (repeated failures); null when turned off by hand. |
createdById | string or null | |
createdAt | string | |
updatedAt | string | |
lastDeliveryAt | string or null | |
failingDeliveries | integer |
Delete a webhook endpoint
DELETE /organizations/{organizationId}/webhooks/{webhookId}
Destructive: deletes the endpoint and its delivery log. Events stay in the event log. Turn it off instead to keep the log.
| Permission | integrations.manage (Owner, Admin) |
| Risk | sensitive, OAuth scope skuflow.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access. |
| MCP tool | webhooks_delete (toolset settings) |
| Approval | Over MCP, this tool always waits for your approval in SKUFlow. See Approvals. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
webhookId | path | string | Yes | From GET /webhooks. |
Example
curl -X DELETE "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/webhooks/{webhookId}" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
ok | true |
Turn a webhook endpoint on or off
POST /organizations/{organizationId}/webhooks/{webhookId}/active
active: false pauses deliveries (they wait); active: true resumes them and clears an automatic turn-off and its failure count. Resend dead deliveries afterwards if needed.
| Permission | integrations.manage (Owner, Admin) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | webhooks_setActive (toolset settings) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
webhookId | path | string | Yes | From GET /webhooks. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
active | boolean | Yes |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/webhooks/{webhookId}/active" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"active":true}'Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
id | string | |
url | string | |
description | string or null | |
eventTypes | array of string | Empty = every event. |
active | boolean | |
secretHint | string | The signing secret's last four characters. |
consecutiveDeadCount | integer | |
disabledAt | string or null | |
disabledReason | string or null | Why it was turned off automatically (repeated failures); null when turned off by hand. |
createdById | string or null | |
createdAt | string | |
updatedAt | string | |
lastDeliveryAt | string or null | |
failingDeliveries | integer |
Regenerate the signing secret
POST /organizations/{organizationId}/webhooks/{webhookId}/secret
Replaces the endpoint's signing secret and returns the new one ONCE. The old secret stops working at once: update the receiver first or accept failed verifications until then.
| Permission | integrations.manage (Owner, Admin) |
| Risk | sensitive, OAuth scope skuflow.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access. |
| MCP tool | webhooks_regenerateSecret (toolset settings) |
| Approval | Waits for your approval in SKUFlow when called with an API key or a connected app: the first call answers 428 APPROVAL_REQUIRED; once you approve it, repeat the call with the X-SKUFlow-Approval header. See Approvals. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
webhookId | path | string | Yes | From GET /webhooks. |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/webhooks/{webhookId}/secret" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
endpoint | object | |
endpoint.id | string | |
endpoint.url | string | |
endpoint.description | string or null | |
endpoint.eventTypes | array of string | Empty = every event. |
endpoint.active | boolean | |
endpoint.secretHint | string | The signing secret's last four characters. |
endpoint.consecutiveDeadCount | integer | |
endpoint.disabledAt | string or null | |
endpoint.disabledReason | string or null | Why it was turned off automatically (repeated failures); null when turned off by hand. |
endpoint.createdById | string or null | |
endpoint.createdAt | string | |
endpoint.updatedAt | string | |
endpoint.lastDeliveryAt | string or null | |
endpoint.failingDeliveries | integer | |
secret | string | The signing secret (whsec_…). Shown this once: store it now; reads only show its last four characters. |
List an endpoint's deliveries
GET /organizations/{organizationId}/webhooks/{webhookId}/deliveries
The delivery log, newest first: event type, status (PENDING, SUCCEEDED, FAILED = will retry, DEAD = out of attempts), attempts, the last HTTP status, time taken and error, the next attempt. Filter with status. Read-only.
| Permission | integrations.manage (Owner, Admin) |
| Risk | read, OAuth scope skuflow.read. Read: reads only. |
| MCP tool | webhooks_deliveries (toolset settings) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
webhookId | path | string | Yes | From GET /webhooks. |
status | query | enum | No | One of PENDING, SUCCEEDED, FAILED, DEAD. |
limit | query | integer | No | Page size, 1–200. Default 50. |
offset | query | integer | No | Rows to skip; the answer's total counts every match. Default 0. |
Example
curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/webhooks/{webhookId}/deliveries" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
items | array of object | |
items[].id | string | |
items[].endpointId | string | |
items[].eventId | string | |
items[].eventType | string | |
items[].eventOccurredAt | string | |
items[].subjectType | string | |
items[].subjectId | string | |
items[].status | enum | One of PENDING, SUCCEEDED, FAILED, DEAD. |
items[].attemptCount | integer | |
items[].nextAttemptAt | string or null | |
items[].lastAttemptAt | string or null | |
items[].completedAt | string or null | |
items[].responseStatus | integer or null | |
items[].latencyMs | integer or null | |
items[].error | string or null | |
items[].createdAt | string | |
total | integer |
Get a delivery
GET /organizations/{organizationId}/webhooks/{webhookId}/deliveries/{deliveryId}
One delivery with the request body sent, the receiver's response (first 2 KB) and the last 10 attempts. Read-only.
| Permission | integrations.manage (Owner, Admin) |
| Risk | read, OAuth scope skuflow.read. Read: reads only. |
| MCP tool | webhooks_getDelivery (toolset settings) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
webhookId | path | string | Yes | From GET /webhooks. |
deliveryId | path | string | Yes |
Example
curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/webhooks/{webhookId}/deliveries/{deliveryId}" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
id | string | |
endpointId | string | |
eventId | string | |
eventType | string | |
eventOccurredAt | string | |
subjectType | string | |
subjectId | string | |
status | enum | One of PENDING, SUCCEEDED, FAILED, DEAD. |
attemptCount | integer | |
nextAttemptAt | string or null | |
lastAttemptAt | string or null | |
completedAt | string or null | |
responseStatus | integer or null | |
latencyMs | integer or null | |
error | string or null | |
createdAt | string | |
requestBody | string or null | The JSON envelope last sent. |
responseBody | string or null | The receiver's answer, first 2 KB. |
attempts | array of object | |
attempts[].at | string | |
attempts[].status | integer or null | |
attempts[].latencyMs | integer or null | |
attempts[].error | string or null |
Resend a delivery
POST /organizations/{organizationId}/webhooks/{webhookId}/deliveries/{deliveryId}/resend
Sends data out: delivers the event to the endpoint again now, whatever its status, with a fresh signature; a failure starts a new retry schedule. 409 while a worker is sending it.
| Permission | integrations.manage (Owner, Admin) |
| Risk | sensitive, OAuth scope skuflow.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access. |
| MCP tool | webhooks_resend (toolset settings) |
| Approval | Over MCP, this tool always waits for your approval in SKUFlow. See Approvals. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
webhookId | path | string | Yes | From GET /webhooks. |
deliveryId | path | string | Yes |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/webhooks/{webhookId}/deliveries/{deliveryId}/resend" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
id | string | |
endpointId | string | |
eventId | string | |
eventType | string | |
eventOccurredAt | string | |
subjectType | string | |
subjectId | string | |
status | enum | One of PENDING, SUCCEEDED, FAILED, DEAD. |
attemptCount | integer | |
nextAttemptAt | string or null | |
lastAttemptAt | string or null | |
completedAt | string or null | |
responseStatus | integer or null | |
latencyMs | integer or null | |
error | string or null | |
createdAt | string | |
requestBody | string or null | The JSON envelope last sent. |
responseBody | string or null | The receiver's answer, first 2 KB. |
attempts | array of object | |
attempts[].at | string | |
attempts[].status | integer or null | |
attempts[].latencyMs | integer or null | |
attempts[].error | string or null |
Send a test event
POST /organizations/{organizationId}/webhooks/{webhookId}/test
Records a webhook.test event for this endpoint only and delivers it now (signed like any event; no customer data). Answers the delivery with the receiver's response, so a setup can be checked in one call.
| Permission | integrations.manage (Owner, Admin) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | webhooks_sendTest (toolset settings) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
webhookId | path | string | Yes | From GET /webhooks. |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/webhooks/{webhookId}/test" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
id | string | |
endpointId | string | |
eventId | string | |
eventType | string | |
eventOccurredAt | string | |
subjectType | string | |
subjectId | string | |
status | enum | One of PENDING, SUCCEEDED, FAILED, DEAD. |
attemptCount | integer | |
nextAttemptAt | string or null | |
lastAttemptAt | string or null | |
completedAt | string or null | |
responseStatus | integer or null | |
latencyMs | integer or null | |
error | string or null | |
createdAt | string | |
requestBody | string or null | The JSON envelope last sent. |
responseBody | string or null | The receiver's answer, first 2 KB. |
attempts | array of object | |
attempts[].at | string | |
attempts[].status | integer or null | |
attempts[].latencyMs | integer or null | |
attempts[].error | string or null |
List domain events
GET /organizations/{organizationId}/events
The outbox: every domain event the organization produced, newest first, with its payload (ids and safe fields), who caused it (USER, AGENT, SYSTEM, PUBLIC) and its webhook deliveries. Filter by type (exact, or a prefix ending in . such as invoice.), subjectType + subjectId (one record's history), actorUserId and from / to (UTC days). Useful to see what happened to a record. Read-only.
| Permission | integrations.manage (Owner, Admin) |
| Risk | read, OAuth scope skuflow.read. Read: reads only. |
| MCP tool | events_list (toolset reports) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
type | query | string | No | Up to 100 characters. |
subjectType | query | string | No | invoice, quote, customer, payment… Up to 50 characters. |
subjectId | query | string | No | |
actorUserId | query | string | No | |
from | query | string | No | A calendar date in the business's own calendar, YYYY-MM-DD. |
to | query | string | No | A calendar date in the business's own calendar, YYYY-MM-DD. |
limit | query | integer | No | Page size, 1–200. Default 50. |
offset | query | integer | No | Rows to skip; the answer's total counts every match. Default 0. |
Example
curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/events" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
items | array of object | |
items[].id | string | |
items[].type | string | |
items[].version | integer | |
items[].occurredAt | string | |
items[].subjectType | string | |
items[].subjectId | string | |
items[].actorType | enum | One of USER, AGENT, SYSTEM, PUBLIC. |
items[].actorUserId | string or null | |
items[].dispatchedAt | string or null | When it was fanned out to webhooks and integrations. |
items[].data | object | |
items[].deliveries | object | |
items[].deliveries.total | integer | |
items[].deliveries.succeeded | integer | |
items[].deliveries.failing | integer | |
total | integer |