Skip to navigation

Create a webhook

View as Markdown

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: https only, 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 with 400. 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, and webhook.test, are rejected. See GET /api/webhooks/event-types.
  • filters: snake_case keys only (see WebhookFilters). Call filters (campaign_ids, agent_ids, outcomes, min_sentiment) cannot be combined with an explicit audit.log_recorded subscription, 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, trialing or past_due); without one the request is refused with 403 BILLING_ERROR (metadata.kind: subscription_required). See Billing and usage.

Authentication

AuthorizationBearer

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.

ScopeGET / HEADPOST / PUT / PATCH / DELETEAdmin-only routes
readYesNoNo
writeYesYesNo
fullYesYesYes

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

This endpoint expects an object.
urlstringRequiredformat: "uri"<=2000 characters

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.

eventslist of enumsRequired

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.

descriptionstring or nullOptional<=500 characters

Free-text label, up to 500 characters.

filtersobject or nullOptional

Optional delivery filters. See WebhookFilters.

headersmap from strings to strings or nullOptional

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.

dataobject

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.

Errors

400
Bad Request Error
401
Unauthorized Error
403
Forbidden Error
429
Too Many Requests Error