Appearance
Receiving Webhooks
When a Case completes, APLYiD sends an HTTP POST request to the Webhook URL configured on your integration. This is how you find out the outcome of a verification without polling the API.
When a webhook is sent
A case.completed webhook is sent when a Case finishes, provided the Case was created with an activity.external_id (see Creating Cases). In other words, you receive webhooks for the Cases you created through the API and identified with your own reference.
The request we send
We send a POST request to your Webhook URL with the following headers:
| Header | Example value | Description |
|---|---|---|
| Content-Type | application/json | The body is always JSON. |
| X-Workflow-Event-Type | case.completed | The type of event. |
| X-Workflow-Webhook-Id | a1b2c3d4-e5f6-47a1-b2c3-d4e5f6a1b2c3 | A unique identifier for this delivery. Use it to deduplicate. |
The request body contains the data for the event:
http
POST /your/webhook/path HTTP/1.1
Content-Type: application/json
X-Workflow-Event-Type: case.completed
X-Workflow-Webhook-Id: a1b2c3d4-e5f6-47a1-b2c3-d4e5f6a1b2c3
{
"case_id": 1024,
"external_id": "order-9281",
"guided_flow_id": 5567,
"status": "completed",
"case_url": "https://workflow.aplyid.com/guided_flows/standard/5567/overview",
"client": {
"id": 8843,
"name": "John Doe",
"external_id": "cust-4471",
"approval_status": "approved"
}
}Body fields:
| Property | Type | Notes |
|---|---|---|
| case_id | Integer | APLYiD's identifier for the Case. |
| external_id | String | The reference you supplied when creating the Case. Use it to match the event to your records. |
| guided_flow_id | Integer | Identifier for the guided flow that was completed. |
| status | String | The Case status — completed for this event. |
| case_url | String | A link to the completed Case's guided flow in the APLYiD app. |
| client | Object | The Client on the Case. |
| client.id | Integer | APLYiD's identifier for the Client. |
| client.name | String | The Client's display name. |
| client.external_id | String / null | The reference you supplied for the Client. |
| client.approval_status | String | The verification outcome: approved or denied. |
Event types
X-Workflow-Event-Type | Description |
|---|---|
case.completed | A Case has been completed. Currently the only event type. |
NOTE
Always check the X-Workflow-Event-Type header (or the event you expect) before processing, so your receiver keeps working if new event types are added in future.
Responding to webhooks
- Respond with a
2xxstatus code (for example200 OK) to acknowledge receipt. - Respond quickly. Acknowledge first, then do any heavy processing asynchronously.
- Expect retries. If your endpoint returns a non-
2xxstatus (or is unreachable), the delivery is retried. As a result, your endpoint may occasionally receive the same event more than once — treatX-Workflow-Webhook-Idas an idempotency key and ignore IDs you've already processed.
Example receiver (Node / Express):
js
import express from "express";
const app = express();
app.use(express.json());
app.post("/webhooks/aplyid", (req, res) => {
const eventType = req.header("X-Workflow-Event-Type");
const webhookId = req.header("X-Workflow-Webhook-Id");
// Acknowledge immediately so the delivery isn't retried.
res.sendStatus(200);
// Ignore deliveries you've already handled.
if (alreadyProcessed(webhookId)) return;
if (eventType === "case.completed") {
const { external_id, client } = req.body;
// Match external_id back to your own records, then process asynchronously.
console.log(`Case ${external_id} completed — outcome: ${client?.approval_status}`);
}
});
app.listen(3000);Securing your endpoint
- Your Webhook URL must be HTTPS.
- Use a URL that is hard to guess, and validate each event against your own records (for example, confirm the
external_idmatches a Case you created) before acting on it.
NOTE
You can update your Webhook URL at any time from the portal — see Managing your integration.
