Webhook Endpoint Integration
This documentation outlines the integration details for the webhook version of the policy execution endpoint, designed for immediate response and background processing.
Endpoint Configuration
Endpoint Target Address: As found in the decision management portal
HTTP Method: POST
Request Content-Type: application/json
Response Content-Type: application/json
Charset: UTF-8
Request Headers
| Header | Value | Description |
|---|---|---|
| X-API-KEY | YOUR_ENDPOINT_API_KEY | Your unique API key for authenticating with the Decisimo platform. This is mandatory. |
| Content-Type | application/json | Specifies that the request body is in JSON format. |
| Return-AnyHeaderName | AnyHeaderValue | Optional. You can include any custom headers prefixed with Return- in your request. These headers will be processed by the webhook and included in the immediate 202 Accepted response, as well as forwarded as headers in the subsequent callback request. For example, Return-ClientRef: ABC123 will result in ClientRef: ABC123 being present in the responses. |
| X-Result-Key | YOUR_RESULT_KEY | Optional. A secret of your choosing. When present, the result is also stored encrypted under it so you can retrieve it later by polling, which is the only way to recover a callback that could not be delivered. It is never stored on the Decisimo platform. |
Some names are reserved. A Return- header with one of these names is dropped, and the rest of the request is processed as normal. The check ignores case.
- Framing and connection:
Host,Content-Length,Content-Type,Content-Encoding,Transfer-Encoding,Connection,Keep-Alive,Upgrade,TE,Trailer,Expect - Credentials and cookies:
Authorization,Cookie,Set-Cookie,WWW-Authenticate, and any name startingProxy- - Redirects and browser policy:
Location,Strict-Transport-Security, and any name startingAccess-Control- - Set by the platform:
User-Agent, and any name startingX-Decisimo-orX-Webhook-
HTTP Response Codes
| Response Code | Description |
|---|---|
| 202 Accepted | Webhook request successfully received and background processing initiated. The response body will contain a request_id for tracking the asynchronous execution and an optional callback_url. |
| 400 Bad Request | The body was missing or did not parse. message says which: No content or Malformed JSON. |
| 401 Unauthorized | No API key on the request. message is Missing API Key. |
| 404 Not Found | The specified endpoint (name) was not found on the platform, or the api_key did not match an existing endpoint. The two are indistinguishable on purpose, so check both. |
| 429 Too Many Requests | Rate limit reached. Nothing is executed. The body carries "error": "rate_limited". See Rate Limits below. |
| 501 Not Implemented | The request was not a POST. The body is empty. |
Anything other than 202 means the submission did not start: nothing will be executed, delivered or stored for it. Branch on the status code rather than on the body.
Rate Limits
On shared endpoints, each endpoint accepts up to 50 requests per second and runs up to 10 requests at the same time, unless your contract sets different limits. A request over either limit gets 429 Too Many Requests with a Retry-After: 1 header and the error code rate_limited. A refused request does not run the decision flow and is not billed. Wait the number of seconds in Retry-After, then send it again.
A webhook request counts as running from the moment it is accepted until its background run finishes.
Execution Time Limit
The webhook endpoint responds immediately with a 202 Accepted status to acknowledge receipt of the request. The actual policy execution then proceeds in the background with no time limit enforced on the background process. This makes it suitable for long-running operations like LLM service calls or complex data enrichments without blocking your client application.
Integration Workflow
The webhook integration follows an asynchronous pattern:
1. Generate Payload
Prepare your data as a valid JSON object.
2. Call Webhook Endpoint
Send a POST request to the webhook endpoint, including your API key and the JSON payload. Optionally, include a callback_url in your JSON payload or as a GET parameter if you wish to receive the execution result.
3. Receive Immediate Acceptance
Your client application will receive an immediate 202 Accepted response. This response confirms the request has been received and provides a request_id for tracking. Your application should not wait for the full execution at this point.
4. Process Immediate Response
Handle the 202 Accepted response and its request_id.
5. Await Callback (if configured)
If a callback_url was provided in the initial request, Decisimo will send a POST request to that URL once the background policy execution is complete (or fails). This callback will contain the execution results, status, and the original request_id.
Callback Mechanism
The system will attempt to send the callback up to 3 times if the previous attempt does not return a 2xx or 3xx HTTP status code. Three attempts leave two gaps: a 2 second pause after the first attempt and a 4 second pause after the second.
Callback Payload
The callback payload is a JSON object that includes:
| Field | Type | Description |
|---|---|---|
status | string | completed or failed |
request_id | string | The ID generated for the original webhook request |
endpoint_name | string | The name of the executed policy |
execution_time_ms | number | The duration of the policy execution in milliseconds |
timestamp | string | When the callback was sent |
result | object/string | The output of the policy execution, parsed as a JSON object if the policy's output is valid JSON, otherwise it will be the raw output |
error | string | A code, never free text: step_failed when a step failed and the flow stopped, execution_failed when the engine itself failed. Absent when execution succeeded |
success | boolean | Indicates execution success |
Inside result are two fields the platform always adds: __request_code, which identifies the execution, and __release_name, which says which release of the decision flow ran. __request_code is not request_id. request_id is the handle the poll endpoint accepts; __request_code is what to quote when you contact support about a run. Polling with __request_code answers 404.
Callback Headers
In addition to Content-Type: application/json and Content-Length, the callback request will include X-Webhook-Attempt and X-Webhook-Max-Attempts headers, along with any custom headers you specified with Return- in the initial request.
HTTP header names are case-insensitive, and proxies and HTTP/2 routinely rewrite their casing in transit. Match the callback headers case-insensitively on your side. A header you sent as Return-Webhook-Token may arrive as webhook-token, and a lookup that expects an exact casing will miss it even though the header is present. Normalise the header names to lower case before you look one up.
When your tenant has a callback credential configured, the callback is also signed. Three more headers ride along: X-Decisimo-Timestamp, X-Decisimo-Nonce and X-Decisimo-Signature. The signature is a hex HMAC-SHA256 over {timestamp}.{nonce}.{raw request body}, computed with the credential. Check that the timestamp is inside your replay window, then check the signature, and only then parse the body. Every attempt is signed afresh, so a retry carries a new timestamp and nonce. To turn signing on, create a credential named webhook_callback_secret in the decision management portal. Every callback for that tenant then arrives signed, and nothing else needs configuring.
When a Callback Cannot Be Delivered
How long the three attempts take depends on how your receiver fails. Each attempt allows 10 seconds to open the connection and 30 seconds in total, so a receiver that refuses outright ends the whole window in about six seconds, while one that accepts the connection and then hangs stretches it to about ninety. An outage lasting longer than that outlives the retries, so a result nobody could receive is kept for you to collect by polling instead.
This works only if you supplied a result_key. The result is encrypted with your key and we never keep the key, so without one there is nothing we can store and nothing you could read back. If you depend on callbacks, send a result_key on every call and poll for the ones that did not arrive.
A result collected this way carries the same Return-* headers the callback would have carried, returned as headers on the poll response.
Polling for Results
As an alternative (or addition) to the callback mechanism, you can retrieve the execution result by polling instead of receiving a POST callback. This is useful when your application cannot expose a publicly reachable callback_url.
Requesting Polling
Include a result_key in your JSON payload or as a GET parameter when you call the webhook endpoint. This is a secret of your choosing — it is never stored on the Decisimo platform; it is only used to encrypt the result so that only the holder of the key can read it back. When a result_key is supplied, the immediate 202 Accepted response will include "result_polling": true.
The key must be at least 16 characters long. A shorter key is set aside: the 202 Accepted response then carries "result_polling": false and "result_key_error": "result_key_too_short", and nothing is stored for polling.
Prefer the X-Result-Key request header over the payload field, so the key stays out of the URL and out of any stored copy of the request body. The payload field and the GET parameter are accepted as a fallback for callers that cannot send custom headers.
{
"...": "your normal payload fields",
"result_key": "a-secret-you-generate-and-keep"
}
Polling Endpoint
Endpoint Target Address: Same base path as your webhook endpoint, with /webhook/ replaced by /poll/ (as found in the decision management portal)
HTTP Method: GET or POST
Response Content-Type: application/json
| Parameter | Description |
|---|---|
name | The endpoint name, same as used for the webhook call. |
api_key | Your endpoint API key. Accepted via X-API-Key header, Basic auth, or as a parameter. |
request_id | The request_id returned in the original 202 Accepted response. |
result_key | The same secret key you supplied to the webhook call. Accepted via the X-Result-Key header or as a parameter. |
Polling Response Codes
| Response Code | Status | Description |
|---|---|---|
| 200 OK | completed/failed | Execution has finished. The response body contains status, request_id, and result. |
| 202 Accepted | pending | Execution has not finished yet. Poll again after a short delay. |
| 400 Bad Request | error | One or more required parameters (name, api_key, request_id, result_key) are missing. |
| 401 Unauthorized | error | The endpoint name or api_key is invalid. |
| 403 Forbidden | error | The result_key does not match the one used at execution time. |
| 404 Not Found | error | The request_id is unknown, the result has expired, or it belongs to another tenant or endpoint. |
Security and Expiry
- Results are encrypted at rest (AES-256-GCM) using a key derived from your
result_key. The key itself is never persisted — only a one-way hash used to reject wrong-key poll attempts. - A delivered result is retained for 24 hours after execution completes.
- A result that no callback could deliver is retained for 30 days, because it is the only copy that exists.
- A collected result is deleted 24 hours after your first successful poll. Polling again inside that window returns the same result; only the first poll starts the clock.
- Polling and the callback mechanism are independent and can be used together: supply both
callback_urlandresult_keyif you want the result pushed to you and available for polling as a fallback.
Payload Limitations
Decisimo has two limitations on the payload:
- Must be a valid JSON object
- Cannot be larger than 1MB
Best Practices
- Set appropriate timeouts in your client application for the initial webhook call
- Implement robust callback handling if using the callback mechanism
- Use unique request identifiers to correlate requests with callbacks
- Handle retry scenarios for callback failures
- Monitor execution times using the provided metrics in callbacks
Related Topics:
- API Endpoint Integration - Synchronous API endpoint documentation
- Testing Endpoint - How to test your endpoints