Skip to main content
POST
Set Webhook
Auth: TokenAccount or TokenInstanceRate limit: Global (100/min) • Idempotent: yes (upsert by label)

Description

Creates or updates the (instance, label) row in webhook_configs. Each instance accepts up to 3 simultaneously enabled webhooks, identified by a free-form label. Webhooks with enabled=false are kept in the database but do not count toward the limit and do not receive deliveries. Use cases:
  • Create a new webhook: send a label not used yet.
  • Update existing: send the same label, all new fields overwrite the old ones.
  • Soft-disable: send the same label with {"enabled": false} (clears url, authorization, events, mediaBase64, but preserves the row).
  • Parallel migration: run the old webhook while validating the new one under a different label; once confirmed, disable the old one.

Examples

Minimum

Enables the default webhook pointing to https://meuapp.com/webhook. Without events, it receives the 6 types; without authorization, it sends no auth header.

With label, filter and Authorization

Creates a webhook named analytics-pipeline that only receives message.exchange and message.status, sends the header Authorization: Bearer svc-token-xyz on each delivery, and turns off the base64 backup.

byEvents = true (URL-based routing)

Turns on byEvents: true so each delivery is sent with the event name as a URL suffix (e.g., https://meuapp.com/wh/message.exchange), allowing server-side routing per endpoint without inspecting the payload.

Soft-disable preserving the label

Disables the analytics-pipeline webhook by sending only enabled: false. The row stays in the database but url, authorization, events and mediaBase64 are cleared, and the entry no longer counts toward the limit of 3 active webhooks.

Base64 media (raw backup)

Configures a webhook dedicated to backup that only receives message.exchange with mediaBase64: true, so each message with media includes the binary content base64-encoded inside the payload.

Success response

The response returns the webhook object with the configuration actually persisted (label, enabled, url, authorization, byEvents, events, mediaBase64), mirrors the request body after the upsert. When enabled=false, the url, authorization, events and mediaBase64 fields come back cleared. The dispatcher starts using the new config immediately (the internal 30s cache is invalidated on save).
200 OK

Path parameters

string
required
Instance name (e.g., $Instance_Name).

Headers

string
required
TokenAccount or TokenInstance.
string
required
application/json

Request body

string
default:"default"
Local identifier. Max 50 chars; accepts [a-zA-Z0-9_-]. Empty or omitted becomes "default". Allows multiple webhooks per instance.
boolean
required
Turns the webhook on/off. When false, the url, authorization, byEvents, events and mediaBase64 fields are cleared before saving.
string
Destination URL. Required when enabled=true. Goes through the SSRF guard (see below), blocks localhost, private IPs, link-local, multicast.
string | null
default:"null"
Literal content of the Authorization header sent on each delivery (e.g., Bearer secret-key-123). Encrypted at rest with AES-256-GCM when ENCRYPTION_KEY is configured.
boolean
default:"false"
If true, the URL receives the /<event-name> suffix on each delivery, useful for endpoint-based routing without inspecting the payload (https://app/wh/message.exchange).
string[]
default:"[]"
Filter. Empty array = receive all 6 types. Each entry must be in {message.exchange, message.status, call.update, group.flow, instance.state, label.update}.
boolean
default:"false"
When true, message.exchange events with media include media.base64 (increases payload, may exceed 100KB).

SSRF guard

The url is validated at configuration time and before each delivery. It blocks destinations that point to internal infrastructure:
If you need to test against a local server in development, expose it through a public tunnel (ngrok, cloudflared, localhost.run), the SSRF guard is active in every environment.

Notes

  • Empty authorization vs. null: send null or omit it to skip the header. An empty string "" would result in an empty Authorization: header, which some proxies reject.
  • enabled=false clears the fields: re-enabling the same label later requires re-sending the url (and any other fields you want to preserve).
  • There is no DELETE: to “remove” a webhook, POST with {"enabled": false} keeping the label. Operators can inspect/clean the row directly in the database when needed.
  • Optional encryption: if ENCRYPTION_KEY is not configured, authorization is stored in plain text. In production, always configure the key.
  • Cache invalidated: the new config becomes visible to the dispatcher immediately (the internal 30s TTL is invalidated on save).

Errors

Envelope:
The 3-webhook limit check is only enforced when creating a new row with enabled=true. Editing an existing row (same label) never triggers the limit.

Next

List webhooks

GET /api/events/getWebhook/:instance, all or by ?label=.

Event catalog

What each event carries in data.