Skip to content

GET /integrations/webhooks

The workspace's webhook subscriptions

Every subscription in the workspace, newest first, with its state and how many consecutive failures it has seen. The secret is not among the fields: it is answered once, at creation and at each rotation, and stored sealed - there is no read that can produce it again.

Responses

  • 200 The subscriptions
  • 4XX An error per RFC 9457 Problem
Example bash
curl -X GET "$HUBTASK_URL/integrations/webhooks" \  -H "Authorization: Bearer $HUBTASK_TOKEN"

POST /integrations/webhooks

Subscribe an external system to the event stream

The subscribe half of the REST hooks pattern: an integration platform creates its own subscription through this route and deletes it again when the user turns the automation off. What arrives at the target is the CloudEvent, identical to the one this system uses internally - there is no feature available only internally or only externally - signed with a secret generated here, answered once in this response, and never readable afterwards. The target is an egress channel and is treated as one: it goes through the guarded client, so a private range or the cloud metadata address is refused unless the installation has deliberately released private networks.

Headers

NameTypeRequiredDescription
Idempotency-Keystring (uuid) optionalA UUID; identical requests return the same result for 24 h.

Request body application/json — WebhookSubscriptionCreate

NameTypeRequiredDescription
target_urlstring (uri)
  • maxLength: 2000
required
event_typesarray of string required
filterstring, or null optionalRefused until the expression engine lands.

Responses

Example bash
curl -X POST "$HUBTASK_URL/integrations/webhooks" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H "Idempotency-Key: $(uuidgen)" \  -H "Content-Type: application/json" \  -d '{  "target_url": "https://example.org",  "event_types": [    "string"  ],  "filter": "string"}'

GET /integrations/webhooks/{webhookId}

One webhook subscription

Path parameters

NameTypeRequiredDescription
webhookIdstring (uuid) required

Responses

Example bash
curl -X GET "$HUBTASK_URL/integrations/webhooks/{webhookId}" \  -H "Authorization: Bearer $HUBTASK_TOKEN"

PATCH /integrations/webhooks/{webhookId}

Change a subscription

The target, the event types, the filter and the state. Re-enabling a subscription that was disabled for sustained unreachability is a write like any other and is audited as one - somebody decided the target is reachable again, and the trail says who. An omitted field is left alone. The secret is not changeable here; rotation has its own route, because handing a new secret to a subscriber is a different act from editing one.

Path parameters

NameTypeRequiredDescription
webhookIdstring (uuid) required

Headers

NameTypeRequiredDescription
If-Matchstring optionalThe ETag of the state last read (optimistic locking).

Request body application/merge-patch+json — WebhookSubscriptionUpdate

NameTypeRequiredDescription
target_urlstring (uri), or null
  • maxLength: 2000
optional
event_typesarray of string optional
filterstring, or null optional
statestring, or null
  • ACTIVE
  • PAUSED
  • null
optionalDISABLED is not settable by hand: it is what the system concludes from a run of failures.

Responses

Example bash
curl -X PATCH "$HUBTASK_URL/integrations/webhooks/{webhookId}" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H 'If-Match: "<the ETag you read>"' \  -H "Content-Type: application/merge-patch+json" \  -d '{  "target_url": "https://example.org",  "event_types": [    "string"  ],  "filter": "string",  "state": "ACTIVE"}'

DELETE /integrations/webhooks/{webhookId}

Unsubscribe

The unsubscribe half of the REST hooks pattern. The deliveries go with the subscription: a delivery log for a subscription nobody can reach any more is a record of attempts against an address the workspace no longer knows.

Path parameters

NameTypeRequiredDescription
webhookIdstring (uuid) required

Responses

  • 204 Unsubscribed
  • 4XX An error per RFC 9457 Problem
Example bash
curl -X DELETE "$HUBTASK_URL/integrations/webhooks/{webhookId}" \  -H "Authorization: Bearer $HUBTASK_TOKEN"

GET /integrations/webhooks/{webhookId}/deliveries

What was delivered, and what happened to it

Every attempt with its status, the response the target gave and when the next attempt is due. A run of eight failures ends in DEAD_LETTER, which is where an operator looks and what a replay acts on.

Path parameters

NameTypeRequiredDescription
webhookIdstring (uuid) required

Query parameters

NameTypeRequiredDescription
cursorstring optional
sizeinteger
  • default: 50
  • minimum: 1
  • maximum: 200
optional
statusstring
  • PENDING
  • SUCCEEDED
  • FAILED
  • DEAD_LETTER
optionalNarrow to one outcome - DEAD_LETTER is the one an operator usually wants.

Responses

Example bash
curl -X GET "$HUBTASK_URL/integrations/webhooks/{webhookId}/deliveries" \  -H "Authorization: Bearer $HUBTASK_TOKEN"

POST /integrations/webhooks/{webhookId}/deliveries/{deliveryId}:replay

Send a dead-lettered delivery again

The same event, sent again by hand after whatever made it fail has been fixed. The event identifier is the one it always had, so a subscriber that deduplicates on X-Hubtask-Event-Id sees the repeat for what it is; the attempt counter carries on rather than resetting, so the delivery log stays a true account of how many times this event was sent.

Path parameters

NameTypeRequiredDescription
webhookIdstring (uuid) required
deliveryIdstring (uuid) required

Responses

Example bash
curl -X POST "$HUBTASK_URL/integrations/webhooks/{webhookId}/deliveries/{deliveryId}:replay" \  -H "Authorization: Bearer $HUBTASK_TOKEN"

POST /integrations/webhooks/{webhookId}:send

Deliver one event to this subscription

One event, delivered to one named subscription through the same pipeline every delivery takes: the same delivery table, the same signature, the same retry ladder and the same dead letter. The subscription's own event-type filter is deliberately not consulted - naming the subscription is the point of the call - but a paused or disabled subscription is refused, and an event a restore replayed is never delivered. This is also what a rule's SEND_WEBHOOK action performs: the rule names the subscription, and the run supplies the event it is about.

Path parameters

NameTypeRequiredDescription
webhookIdstring (uuid) required

Request body application/json — WebhookSend

NameTypeRequiredDescription
event_idstring (uuid) requiredThe event to deliver, as X-Hubtask-Event-Id will carry it.

Responses

Example bash
curl -X POST "$HUBTASK_URL/integrations/webhooks/{webhookId}:send" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H "Content-Type: application/json" \  -d '{  "event_id": "018f6e2a-2b7c-7c1e-9b1a-3d5e6f7a8b9c"}'

POST /integrations/webhooks/{webhookId}:rotate-secret

Issue a new signing secret

Answers the new secret once, and keeps the old one verifying for a grace period. That overlap is the whole point of the route: a subscriber cannot deploy atomically, and a rotation that took effect instantly would drop every event arriving between the call and the deployment. Signatures are computed with the current secret from this moment on. What the grace period buys is the subscriber's side of the check, not ours.

Path parameters

NameTypeRequiredDescription
webhookIdstring (uuid) required

Headers

NameTypeRequiredDescription
Idempotency-Keystring (uuid) optionalA UUID; identical requests return the same result for 24 h.

Request body application/json — WebhookSecretRotation

NameTypeRequiredDescription
grace_secondsinteger, or null
  • minimum: 0
  • maximum: 604800
optionalHow long the previous secret keeps verifying, so a subscriber can deploy the new one without dropping what arrives in between.

Responses

Example bash
curl -X POST "$HUBTASK_URL/integrations/webhooks/{webhookId}:rotate-secret" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H "Idempotency-Key: $(uuidgen)" \  -H "Content-Type: application/json" \  -d '{  "grace_seconds": 0}'

GET /integrations/triggers/{eventType}

The pull half of the event stream

Events of one type, oldest first, for a platform that has no address a webhook could reach - an n8n instance behind NAT, a Zapier polling trigger. The body of each entry is the same CloudEvent a webhook subscription would have been POSTed: one schema, two transports, and id is the same value X-Hubtask-Event-Id carries, so a consumer that already deduplicates on it needs to learn nothing new. The cursor is opaque, signed and derived from the outbox's own ordering, so it survives a restart and a failover. Two polls with it neither repeat an event nor step over one. The window is the outbox's retention period, and a cursor older than it is refused with 410 gone rather than silently answered from the beginning. A poller that missed more than the window has to be told that it missed - one that was quietly restarted would go on reporting a consistency it does not have. A replayed event - one a restore wrote rather than one somebody did - is not answered here, exactly as it is not delivered to a webhook.

Path parameters

NameTypeRequiredDescription
eventTypestring requiredThe type to poll, in full - de.hubtask.work.item.created.v1.

Query parameters

NameTypeRequiredDescription
sincestring optionalWhere the last poll stopped.
limitinteger
  • default: 100
  • minimum: 1
  • maximum: 200
optional

Responses

Example bash
curl -X GET "$HUBTASK_URL/integrations/triggers/{eventType}" \  -H "Authorization: Bearer $HUBTASK_TOKEN"