Recipe — Fire a webhook when a case closes
Use a case-close automation to notify a downstream system as soon as a case reaches its closed state. This is useful for refund queues, escalation reporting, fulfillment systems, data warehouses, or any external workflow that should start when a case in a particular workflow is resolved.
What this rule does
This recipe creates a rule that:
- Trigger: Runs when a case is closed.
- Condition: Continues only when the case belongs to the workflow you choose — for this recipe, Refunds. Case conditions can also match on stage, status, priority, assigned agent or team, title, or description. There is no case-tag condition.
- Action: POSTs a JSON payload you write to your downstream system.
The webhook body is sent as you wrote it. There are no case merge tags, and the contact merge tags resolve to empty on a case trigger because a case-close run carries no contact — so the payload can’t identify which case closed. If your receiver needs the case itself, subscribe it to the case.status_changed webhook event, which delivers the full case, or have it query the API (GET /api/v1/cases?status=closed). Use this rule when a fixed “a case closed in this workflow” ping is enough, or as the filtered nudge that tells the receiver to go and look.
Before you start
Prepare:
- The destination webhook URL from your downstream system.
- Any required authentication header, such as
Authorization: Bearer your-tokenorX-Shared-Secret: your-token. - The payload your receiver expects.
- A test case in the workflow that can be closed safely.
Store credentials for outbound or inbound integrations securely, and rotate them if they are shared with an external system.
Build it
- Go to Settings → Automation Rules → New Rule → Manual Builder.
- Choose the Case Closed trigger.
- Add a condition: Workflow equals your refunds workflow. The case fields are listed under Cases in the condition picker.
- Add the Send Webhook to External Service action.
- Set the method to
POST. - Paste the destination URL.
- Add any required headers, for example:
Content-Type: application/jsonAuthorization: Bearer your-tokenX-Shared-Secret: your-token - Paste the body (see below).
- Save the rule.
- Test it with a safe case before enabling it for production traffic.
Body template
Use the payload shape your downstream system expects. The body is fixed text: it can’t carry the case’s ID or fields (see above), so keep it to what the receiver needs to know which rule fired.
Example:
{ “event”: “case.closed”, “workflow”: “Refunds”, “source”: “atender-automation” }
Idempotency
Any webhook receiver should be idempotent. Webhook actions can fire more than once for the same logical event under unusual conditions such as network retries, manual re-runs, or re-triggers from edits.
Because the payload doesn’t identify the case, key duplicates on an idempotency key generated by your receiver, or on the case ID once the receiver has looked it up through a webhook subscription or the API.
Throttling
Add a rule throttle if your downstream system has rate limits. Common pattern: Global, 60 per minute to protect a small downstream service from a burst of automation events.
Verify it worked
Close a test case that matches the rule condition. Check Run History for the rule. A run shows Success or Failed, with a badge per action:
- A 2xx response from the receiver leaves the webhook action successful. The response body isn’t stored, so confirm receipt on the receiver’s side.
- A non-2xx response or a network error marks the action failed and the run Failed; the row shows the error message, which carries the status code and the first part of the receiver’s response body — read it to debug.
Variants
- Multiple downstream systems. Use multiple webhook actions in the same branch — they fire in sequence.
- Different payloads by workflow or priority. Use branches keyed on the case conditions (Workflow, Stage, Priority, and so on) to send a different fixed payload per branch.
- Include the case itself. Not possible from this action. Use the case.status_changed webhook subscription instead: it delivers the full case with a
previoussnapshot, and every delivery is signed with HMAC-SHA256. - Authenticate the request. Add a custom header carrying a shared secret (e.g.
X-Shared-Secret: your-token) so the receiver can reject requests that don’t come from your rule. Header values are fixed text plus merge tags — the action can’t compute per-request signatures. If you need cryptographically signed deliveries, use webhook subscriptions instead.
Troubleshooting
-
Symptom: You cannot find the
Case Closedtrigger. Fix: It sits under Cases in the Manual Builder’s trigger list. -
Symptom: You cannot find a case-tag condition. Fix: There isn’t one. Filter on Workflow, Stage or Priority instead, or do the tag filtering in your receiver after it has looked the case up.
-
Symptom: Receiver doesn’t see the POST. Fix: Open Run History and read the run’s error message. If the run shows success but the receiver disagrees, the URL is wrong or being intercepted by a proxy. If the run failed with a network error, the URL is unreachable from Atender’s egress IPs — confirm DNS and any IP allowlists.
-
Symptom: Receiver returns 401. Fix: Bearer token is stale or the wrong header name. Some systems expect
X-Auth-Tokenrather thanAuthorization. -
Symptom: Receiver returns 422 with a “missing field” error. Fix: Your receiver expected a field the fixed body doesn’t carry — usually a case or contact identifier. This action can’t supply those; get them from a webhook subscription or the API instead.
-
Symptom: Webhook fires multiple times for one event. Fix: Add an appropriate throttle. Make sure the receiver is idempotent regardless.
See also
- Actions catalogue — Webhook
- Debug a rule using execution history
- Webhook events reference — the
case.*events that carry the full case - API Keys — if the downstream system needs to call back into Atender