Skip to main content
POST
Agency Webhooks
Webhooks stay workspace-scoped: each client gets its own row, its own scope and its own secret. What changes is who can create it — your agency key can, for any workspace you own, so registration happens in the same script that creates the client.

Endpoint

  • Method: POST to create, GET to read, DELETE /api/agency/webhooks/{id} to remove
  • Path: /api/agency/webhooks
  • Auth: Authorization: Bearer tucoagency_xxxxxxxxxxxxx (agency key)

Body

One client

Every client, one call

This is the call that removes “ten clients means ten registrations”. Supply your own secret and a single receiver can verify all of them.
Each client still gets its own webhook row, so every delivery carries exactly one tenant’s data. Read workspaceId off the payload to route it.

Which clients are not wired up yet

workspacesWithoutWebhook is the useful read: the clients that would silently receive nothing. Secrets are never returned here — they are shown once, at creation. Add ?workspaceId=org_… to scope the read to one client.

Removing one

Unlike deleting a line, this is available to an API key — a webhook is re-created with one call, so it is not an irreversible action.

Line-health events

Ten events are open to anyone. Two more — line.down and line.recovered — are not, and they are the ones an agency usually wants most. A line going quiet is operational detail. Sent to the end client it is noise they cannot act on, so Tuco never emails or webhooks it to them. An agency is a different reader: for its clients it is the support desk, so these two events are available to agencies Tuco has switched on.
Switched on automatically when your agency is invoiced — Tuco bills you, not your clients, so you are already the operator for every line in the group. On Stripe billing, ask us and we will enable it by hand without changing how you pay.

Payload

Same envelope as every other event — the line-specific fields sit under data.
The top-level nulls are the shared CRM fields every event carries; they are not meaningful here. Read data. The payload carries what an operator can act on and nothing else — no failure strings, no hostnames, no ports. Those stay internal. Signed and retried exactly like every other event — see Message Webhooks for verifying X-Tuco-Signature.

Two ways this is gated

Both have to hold:
  1. Agency key only. A workspace key (tuco_…) cannot subscribe to these however the body is crafted — the workspace route never offers them.
  2. Your agency has to be enabled. If it is not, the create returns 400 with a reason rather than a flat “invalid event”, so you can tell a typo from a feature that is simply not on yet:
Switching an agency off stops delivery immediately, even though its subscriptions still exist — the check runs at send time, not at subscribe time.

Relationship to the workspace route

POST /api/webhooks still does the same job with that one client’s workspace key, and both routes share one validator — a URL or event list rejected by one is rejected by the other, identically. Use the workspace route when your code already holds that client’s key; use this one when you are operating across the group.

Error responses