Create a webhook
Registers an endpoint that receives signed POST requests for the subscribed event types. The
signing secret (whsec_ followed by the base64 encoding of 32 random bytes) is returned only in
this response. Store it immediately: it cannot be retrieved later, only replaced with
POST /api/webhooks/{webhookId}/rotate-secret.
Deliveries implement Standard Webhooks: every request carries
webhook-id, webhook-timestamp and webhook-signature, and the body is the event envelope
(WebhookEventEnvelope). The Webhooks guide covers signature verification, the retry
schedule and the full event catalog.
Validation. Unknown fields are rejected with 400.
url:httpsonly, up to 2000 characters, without embedded credentials, and not a private, loopback, link-local or internal host. The hostname is resolved, and a non-public address is rejected with400. The same check runs again before every delivery attempt.events: 1 to 100 names."*"covers every type that is not opt-in only; opt-in-only types (audit.log_recorded,security.event_recorded,agent_action.recorded,contact.created,message.*,contact.updated) must be listed explicitly and can be combined with"*". Names outside the catalog, andwebhook.test, are rejected. SeeGET /api/webhooks/event-types.filters: snake_case keys only (seeWebhookFilters). Call filters (campaign_ids,agent_ids,outcomes,min_sentiment) cannot be combined with an explicitaudit.log_recordedsubscription, because an audit event carries none of those fields.headers: up to 20. Names reserved by Jelliu are rejected (webhook-*,x-jelliu-*,host,content-length,content-type,connection,transfer-encoding,te,upgrade,keep-alive,proxy-*); values up to 2000 characters, without line breaks.- At most 20 webhooks per workspace.
Every validation failure returns 400 VALIDATION_FAILED with a single, specific Spanish message in
message (no details list).
Side effects. Stores the endpoint as active. It receives events that occur from that point on;
earlier stored events can be sent with POST /api/webhooks/{webhookId}/replay. Written to the audit
log with url and headers redacted.
Idempotency. Not idempotent. Retrying after a timeout can create a second endpoint with a
different secret, and the receiver would then receive every event twice (with the same
webhook-id, so deduplication still applies). Before retrying, call GET /api/webhooks and check
for the URL.
Webhook events. Emits audit.log_recorded to endpoints subscribed to it. See Webhooks.
Access
- Required scope:
full. Human users need the owner or admin role. A key minted through the ChatGPT or Claude connection is refused. - Rate limit: General API (120–600 requests/min per workspace, by plan) plus the configuration-mutations limit — 10 requests/min per workspace, shared with other configuration changes such as agents, integrations and exports. See Rate limits.
- Plan: Available on every plan. Requires an active subscription (
active,trialingorpast_due); without one the request is refused with403 BILLING_ERROR(metadata.kind: subscription_required). See Billing and usage.
Authentication
Workspace API key: jl_ followed by 64 lowercase hex characters, created by the workspace owner in the
dashboard (Settings → API Keys) and sent as Authorization: Bearer jl_.... The plaintext is shown once,
at creation; Jelliu stores only a SHA-256 hash. A workspace can hold up to 25 active keys.
Operations restricted to admins or owners reject keys without the full scope with 403, and say so in
their description. No key, whatever its scope, can mint or revoke API keys or rotate a webhook secret —
that requires a signed-in owner session. A revoked key stops authenticating within about 10 seconds.
See Authentication.
Request
https URL (plain http is rejected in production), up to 2000 characters, without embedded
credentials. Private, loopback, link-local and internal hosts are rejected, as is a hostname that
does not resolve to a public address. The check runs again before every delivery attempt.
Event types to receive (duplicates are ignored). "*" covers every type that is not opt-in only;
opt-in-only types must be listed explicitly and can be combined with "*". Every name must be
available for subscription (GET /api/webhooks/event-types); webhook.test cannot be
subscribed to.
Free-text label, up to 500 characters.
Optional delivery filters. See WebhookFilters.
Custom request headers sent with every delivery, up to 20. Names must be valid HTTP tokens (up to
200 characters) and cannot be names reserved by Jelliu: webhook-*, x-jelliu-*, host,
content-length, content-type, connection, transfer-encoding, te, upgrade,
keep-alive, proxy-*. A user-agent header is dropped (Jelliu always sends its own). Values up
to 2000 characters, with no line breaks. Values are encrypted at rest and never returned.
Response
Created. data.secret holds the signing secret, returned only in this response.
An outbound webhook endpoint as returned by the API. The signing secret is never included; it is
returned once by POST /api/webhooks (as an additional secret field) and by rotate-secret.
Custom headers keep their names, but every value is "[configured]". Members below admin (and
API keys without the full scope) see only the origin of url.

