Webhook integration

Three surfaces work together: inbound ingest (connectors → POST /v1/events/ingest), outbound delivery (platform → your HTTPS URL), and agent triggers (events → queued agent runs).

1. Create a subscription (SDK)

Use client.webhooks on a delegation with human_api:webhooks:write. Patterns use lowercase dot segments; a trailing .* matches a family.

typescript
import { HumanClient } from '@human/client-sdk';
const client = new HumanClient({ delegationToken: process.env.HUMAN_DELEGATION_TOKEN! });
const sub = await client.webhooks.createSubscription({
event_pattern: 'billing.invoice.paid',
target_url: 'https://api.example.com/hooks/human',
signing_secret: process.env.WEBHOOK_SIGNING_SECRET!, // optional; enables HMAC on delivery
});
console.log(sub.subscription_id);

2. Verify signatures

When a signing secret is stored, deliveries include X-Human-Signature-256, X-Webhook-Timestamp, and X-Webhook-Delivery-Id. Reject replays by enforcing a max age on the timestamp.

typescript
import { createHmac, timingSafeEqual } from 'node:crypto';
/**
* Verify X-Human-Signature-256: sha256=<hex>
* Signed payload: `${timestamp}.${rawBodyString}`
*/
export function verifyHumanWebhook(
rawBody: string,
signatureHeader: string | undefined,
timestampHeader: string | undefined,
secret: string,
maxAgeSeconds = 300,
): { ok: true } | { ok: false; reason: string } {
if (!signatureHeader?.startsWith('sha256=') || !timestampHeader) {
return { ok: false, reason: 'missing_headers' };
}
const ts = Number.parseInt(timestampHeader, 10);
if (Number.isNaN(ts)) return { ok: false, reason: 'bad_timestamp' };
const now = Math.floor(Date.now() / 1000);
if (now - ts > maxAgeSeconds) return { ok: false, reason: 'stale' };
const expected = createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex');
const received = signatureHeader.slice('sha256='.length);
const a = Buffer.from(received, 'utf8');
const b = Buffer.from(expected, 'utf8');
if (a.length !== b.length) return { ok: false, reason: 'sig_length' };
if (!timingSafeEqual(a, b)) return { ok: false, reason: 'sig_mismatch' };
return { ok: true };
}

3. Retries & dead letter

The platform retries with backoff on non-2xx responses and transport errors. After max attempts, the delivery moves to dead. Fix your endpoint, then use the Command Plane delivery inspector to Redeliver (or call client.webhooks.redeliver(deliveryId)).

4. Command Plane

Open Webhooks in the console to list subscriptions, create external endpoints, inspect per-delivery HTTP status and response bodies, and re-queue failed deliveries. Agent-trigger subscriptions appear in the same list; delivery logs apply to external HTTP subscriptions only.

5. Agent triggers

Declare on[] in your agent manifest and grant event_trigger capabilities. See Webhooks & event triggers.

See also