Notification Sinks
Notification sinks let you receive alerts when tasks complete, are cancelled, or fail. HPI supports three sink types: webhooks (HTTP POST), email (with PDF attachment), and NATS (message publish).
Setting Up Webhooks
Add a webhook sink when creating a task:
{
"title": "Review document",
"sinks": [{
"type": "webhook",
"url": "https://your-app.com/webhooks/task-complete",
"events": ["completed", "cancelled", "failed"]
}],
"steps": [...]
}
If you don't provide a secret, one is auto-generated and returned in the response. Store it to verify webhook signatures.
Webhook Payload
{
"source": "hpi",
"event": "task.completed",
"task_id": "a1b2c3d4-...",
"correlation_key": "your-corr-id",
"timestamp": "2026-02-24T12:05:00Z",
"data": {
"decision": "Approve",
"comments": "Looks good!"
}
}
Event Types
| Event | When |
|---|---|
task.completed | Operator submitted the task |
task.cancelled | Task was cancelled |
task.failed | Task failed |
For cancelled/failed events, a reason field is included instead of data.
Webhook Headers
Content-Type: application/json
X-Webhook-Event: task.completed
X-Webhook-Task-Id: a1b2c3d4-...
X-Webhook-Signature: sha256=abc123...
Signature Verification
Verify webhooks by computing an HMAC-SHA256 of the raw request body using the webhook secret:
import hmac
import hashlib
def verify_webhook(body: bytes, secret: str, signature_header: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(), body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature_header)
const crypto = require('crypto');
function verifyWebhook(body, secret, signatureHeader) {
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(body).digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader));
}
Retry Behavior
Failed webhook deliveries are retried automatically:
| Attempt | Delay |
|---|---|
| 1st | Immediate |
| 2nd | 5 seconds |
| 3rd | 30 seconds |
Each attempt has a 10-second timeout. After 3 failed attempts, the webhook is abandoned.
Email Sink
Send an email notification when a task completes, is cancelled, or fails. On completion, a PDF of the submitted form data is generated and attached to the email.
{
"type": "email",
"to": "user@example.com",
"events": ["completed"]
}
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Must be "email" |
to | string | Yes | Recipient email address |
events | array | No | Events to notify on (default: all) |
Behavior by event:
- completed — Email includes a PDF attachment with the full submitted form data
- cancelled / failed — Email is sent without attachment; includes the cancellation or failure reason
Note: Email sinks require SMTP to be configured on the server.
NATS Sink
Publish an event to a NATS subject when a task completes, is cancelled, or fails. The message is published as an ExternalSignal envelope.
{
"type": "nats",
"subject": "my.custom.subject",
"events": ["completed"]
}
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Must be "nats" |
subject | string | Yes | NATS subject to publish to |
events | array | No | Events to notify on (default: all) |