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.
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.
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
- ctx.events
- Connectors — inbound ingest secrets for vendor webhooks.