Agent Platform
Webhooks
Register workspace event endpoints and verify Fullness signatures against the unmodified request body.
GET
/v1/external/webhooksList endpoints for the selected authenticated Fullness workspace.
POST
/v1/external/webhooksRegister an HTTPS URL and one or more event types; the signing secret is returned once.
POST
/v1/external/webhooks/{endpointId}/revokeStop future delivery to an endpoint.
Delivery headers
fullness-event-id— unique delivery/event identifierfullness-timestamp— Unix timestamp in secondsfullness-signature—v1=<hex HMAC>
Signature construction
Algorithm
signedPayload = timestamp + "." + eventId + "." + rawRequestBody
expected = "v1=" + hex(HMAC_SHA256(signingSecret, signedPayload))Compare signatures in constant time. Reject timestamps more than five minutes from the receiver’s clock and persist accepted event IDs so replays are rejected.
Node.js verification
Node.js
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifyFullnessWebhook({ rawBody, secret, timestamp, eventId, signature }) {
const age = Math.abs(Date.now() / 1000 - Number(timestamp));
if (!Number.isFinite(age) || age > 300) return false;
const expected = 'v1=' + createHmac('sha256', secret)
.update(`${timestamp}.${eventId}.${rawBody}`)
.digest('hex');
const left = Buffer.from(expected);
const right = Buffer.from(signature);
return left.length === right.length && timingSafeEqual(left, right);
}Delivery behavior
Fullness sends JSON with a 10-second timeout and does not follow redirects. HTTP 408, 429 and 5xx responses are retryable; other non-success responses fail the delivery. Receivers must still be idempotent because retries can repeat an event.