Skip to main content

Build automations on Qvasa: dashboard alerts, ticket payloads and outbound webhooks

Build automations on Qvasa: dashboard alerts, ticket payloads and outbound webhooks

A Qvasa alert doesn't have to end in a Slack message. Three features combine into something closer to an automation platform: a dashboard widget alert is the trigger, a ticket payload definition is the data, and an outbound webhook is the delivery. Put them together and a threshold breach becomes a signed JSON request to your own service, carrying a structured record of every ticket behind the number — enough for the receiving system to re-route those tickets, page a team, open an incident, or write them into a warehouse, without anyone reading the alert first.

This guide wires the three together end to end. For the alert half on its own — thresholds, grouped widgets, moving averages, schedules — see Dashboard alerts and scheduled exports; this article picks up where the payload starts to matter.

How the three pieces fit

  • The trigger. A widget on an alert dashboard breaches its threshold. If that widget inspects tickets, the alert knows exactly which Zendesk tickets are behind the number.

  • The data. A ticket payload definition turns each of those tickets into a JSON object of your own design — your field names, your nesting, built from any column in the tickets table.

  • The delivery. An outbound webhook POSTs one JSON envelope to your HTTPS endpoint: the alert's own details, anything static you want to add, and the per-ticket payloads nested wherever your receiver expects them.

Each piece is reusable and configured separately, which is what makes this worth setting up once: one payload definition can feed several alerts, and one webhook can serve every alert on the account.

Before you start

  • Ticket Payload Definitions and Outbound Webhooks are enabled per account. If you don't see them in Settings, ask the Qvasa team to switch them on.

  • You need to be an admin, or have permission to manage configurable workflows.

  • An existing alert dashboard with at least one widget condition. If you don't have one yet, build it first — see Dashboard alerts and scheduled exports.

  • An HTTPS endpoint you control that accepts a POST. Plain HTTP is rejected, and so are internal or private addresses.

Step 1: Design the ticket payload

Go to Settings → Ticket Payload Definitions and click Create New Payload Definition. A definition is the JSON document for one ticket, written out in full. Nest objects and arrays however your receiver wants them; inside any string value, reference a ticket attribute with {{ attribute }}.

Every column in the tickets table is available — subject, status, tags, assignee, queue, durations, AI fields, your own custom fields: well over a hundred on a typical account. Insert an attribute searches them by name and drops the token at your cursor, and All attribute keys lists every key at once. Format & Validate pretty-prints the JSON and tells you if it's broken or references an attribute that doesn't exist.

One rule: a definition must reference {{ zendesk_identifier }} at least once, so every resolved payload can be tied back to a ticket.

Display values and raw values. By default a token injects the attribute's display value — formatted the way the Qvasa UI shows it. Append | raw for the underlying value instead. That matters more than it sounds for an automation: {{ ticket_created_at }} gives 2026-10-02 01:40 PM, while {{ ticket_created_at | raw }} gives 2026-10-02 20:40:12 UTC — the one a receiving system can parse. Same for durations: a display value of 55m 0s against a raw value of 3300 seconds. The attribute picker tags the attributes where the two differ with (raw/display); for the rest both produce the same thing.

Link attributes work the other way round from what you might expect: for {{ zendesk_ticket_url }} the plain token is the full URL, and | raw is the bare ticket id. Use the plain token when you want something clickable.

There's no harm in including both forms of the same field — a machine-readable value and a human-readable one side by side is a reasonable payload design.

Check it against a real ticket. The Preview panel at the bottom of the editor takes a Zendesk ticket id and renders the payload that definition produces, using the exact same service the alerts and webhooks use at fire time. This is the fastest way to find a field that's empty on your data, or a raw/display choice that reads wrong.

Step 2: Create the outbound webhook

Go to Settings → Outbound Webhooks and click Create New Webhook. Give it a destination URL and choose how it authenticates:

  • HMAC-SHA256 signature — Qvasa signs every request with a shared secret. The best choice when your endpoint is public.

  • Bearer token, Basic auth, or a custom API key header — when your receiver already expects one of those.

  • None — only sensible behind some other gate.

Credentials and any custom headers are stored encrypted, and are never shown again after saving (leave a credential field blank to keep the current value). Put secrets in the authentication strategy rather than in custom headers.

The trigger source is fixed at creation — it decides which values the envelope can reference — and today's source is the Workflow Condition Alert.

Failure handling is on the same page and worth setting deliberately. Each delivery is attempted once, with no retries. Qvasa tracks successes, failures and the last error, warns you by email after a number of consecutive failures you choose, and auto-disables the webhook after a higher number (or once the recent error rate crosses a percentage you set). A 410 Gone response disables it immediately — that's the deliberate way to turn off a webhook from your side.

Step 3: Shape the envelope

The envelope is the JSON body Qvasa POSTs. Start from the default and restructure it however your receiver expects — rename keys, nest them, add static values of your own. Insert a value searches everything the alert produces: the workflow and condition names, the breach description, the direction, the threshold and observed value, the dashboard URL, the inspected ticket ids and count, any capacity changes the alert made, and the per-ticket payloads.

Two things to know about tokens:

  • A token that is the entire string value is replaced with the real typed value — numbers stay numbers, lists stay lists, and the ticket payloads block stays a nested object. A token embedded in a longer sentence interpolates as text.

  • Four top-level keys are always included so receivers can rely on a stable envelope: event_type, event_id, occurred_at and account_identifier. Remove one and Format & Validate (and saving) puts it back. Everything else is yours.

Adding your own constants is the thing that makes this an automation rather than a notification. A routing block carrying a severity, a team name and a runbook URL costs nothing and lets the receiving system switch on it without knowing anything about Qvasa.

Choosing which payload shapes the ticket block. The {{ ticket_payloads }} value is one JSON payload per inspected ticket, keyed by Zendesk ticket id. Every workflow that fires this webhook has its own attached payload definition, so you decide how the two interact:

  • Leave "Always use this payload" unchecked — the firing workflow's own definition wins, and the one selected here is used only when a workflow hasn't attached one. Pick this when one webhook serves several alerts that each want a different shape.

  • Check it — every delivery uses the definition selected here, whatever the firing workflow has. Pick this when the receiver needs one fixed contract.

Step 4: Preview the exact body, then send a test

The Preview panel renders the exact body this webhook will POST. Leave the ticket id box blank and the per-ticket block fills with placeholder values, which is enough to check the shape; enter one or more comma-separated Zendesk ticket ids and it fills with real ticket data, so you can hand a receiving developer a genuine sample before anything is wired up.

[SCREENSHOT: webhook_preview]

Send Test Payload then POSTs a sample to your real destination with the real authentication, and reports the HTTP status and round-trip time. Do this before attaching the webhook to anything — it separates "my endpoint is wrong" from "my alert never fired".

What your endpoint receives. Every request is a POST with Content-Type: application/json and these headers:

  • X-Qvasa-Webhook-Id — which webhook sent it.

  • X-Qvasa-Delivery-Id — a unique id for this delivery, the same value as event_id in the body. Dedupe on it and a replay can never double-process.

  • X-Qvasa-Timestamp and X-Qvasa-Signature — on HMAC webhooks only. The signature is v1= followed by an HMAC-SHA256 of the string <timestamp>.<raw request body>, keyed with your signing secret. Recompute it over the raw bytes you received, compare, and reject timestamps that are too old.

A few limits worth designing around: Qvasa waits 5 seconds to connect and 10 seconds for a response, doesn't follow redirects (a 3xx counts as a failure), and caps the body at 256 KB. Anything outside the 2xx range is a failure. So have your endpoint acknowledge quickly and do the real work asynchronously, and keep payload definitions to the fields you actually use — an alert that inspects a hundred tickets multiplies every field you added by a hundred.

Step 5: Wire it to the alert

Now connect the two to the trigger. Open your alert dashboard and use the command center bar at the top:

  • Channels → add your webhook as a notification destination. An alert can have several destinations at once, so the webhook can run the automation while a Slack channel keeps humans informed of the same breach.

  • Alert Message → under Inspected Ticket Details, turn on Custom ticket payloads and choose your definition in Ticket Payload Definition.

[SCREENSHOT: alert_custom_payloads]

That toggle is what makes a breach resolve the definition against the inspected tickets and hand the result to the webhook. Without it the alert still fires and the webhook still delivers — the ticket_payloads block is simply absent, as it is whenever a condition breaches without inspecting any tickets. Write your receiver to tolerate that.

What done looks like

The webhook's row in Outbound Webhooks reads Active. Your alert dashboard lists the webhook among its notification channels and shows a next run time. When a condition breaches, your endpoint receives a signed POST within moments, carrying the alert, your static routing block, and one payload per breaching ticket.

The Delivery health panel at the bottom of the webhook's page is where you confirm it: delivered and failed counts, the current consecutive-failure streak, the last error, and a table of recent deliveries with their HTTP statuses.

[SCREENSHOT: delivery_health]

What this is good for

  • Escalate automatically. First reply time breaches on the VIP queue; the payload carries each ticket's id, assignee and how long it has been waiting; your service re-tags, re-routes or re-prioritises them in Zendesk.

  • Page with context. Send straight into your incident tool, so the page arrives with the breaching tickets and a runbook link rather than "a dashboard went red".

  • Drive a no-code platform. Any tool that accepts an inbound webhook can be the receiver, so the automation itself can be built without engineering time.

  • Record what happened. Point it at a collector and keep a durable log of every breach and the tickets behind it, for later analysis of what your thresholds actually catch.

  • Adjust capacity. For the specific case of agent capacity, an alert can already apply a capacity rule on breach and restore it on resolve — and the changes it made arrive in the webhook too, so your systems can follow along.

Troubleshooting

  • The payload block is missing from the body. Either the breaching condition inspected no tickets, or Custom ticket payloads is off on the alert. Check the alert's Alert Message settings first.

  • Fields come through empty. The attribute is genuinely blank on those tickets. Preview the definition against a real ticket id to see exactly which ones fill.

  • A timestamp or duration is unusable. You're getting the display value. Append | raw to that token.

  • Signature checks fail. Sign the raw request body bytes, not a re-serialized copy — any reformatting changes the signature. The signed string is <timestamp>.<body>, and the header value includes the v1= prefix.

  • The webhook auto-disabled. Its row says so and the edit page names the reason and last error. Fix the endpoint, then click Re-enable webhook — the failure streak resets.

  • Deliveries fail but the endpoint looks healthy. Check for a redirect (not followed), a slow response (10-second read timeout), a body over 256 KB, or a non-public address — internal hosts are blocked deliberately.

  • A definition won't delete. It's attached to a workflow. The editor's Where this is used panel lists them; detach it there first.

Did this answer your question?