curl --request POST \
--url https://api.idunox.com/_reference/outbound-webhooks/result_ready \
--header 'Content-Type: application/json' \
--header 'X-IduScore-Delivery-Id: <x-iduscore-delivery-id>' \
--header 'X-IduScore-Event: <x-iduscore-event>' \
--header 'X-IduScore-Signature: <x-iduscore-signature>' \
--header 'X-IduScore-Timestamp: <x-iduscore-timestamp>' \
--data '
{
"completedAt": "2026-04-24T00:49:32.389Z",
"eventType": "result.ready",
"partnerSubmissionId": "SYN-SUB-20260331-000001",
"reportId": "8b37c3c5-a223-456b-9c96-ad2d0e2e2ce6",
"resultId": "db2550ba-4c7f-4e7f-95d8-0a064f368f14",
"status": "completed",
"statusLabel": "Completed",
"submissionId": "8d70fed5-8f01-410d-87bd-8755725d7c6f"
}
'import requests
url = "https://api.idunox.com/_reference/outbound-webhooks/result_ready"
payload = {
"completedAt": "2026-04-24T00:49:32.389Z",
"eventType": "result.ready",
"partnerSubmissionId": "SYN-SUB-20260331-000001",
"reportId": "8b37c3c5-a223-456b-9c96-ad2d0e2e2ce6",
"resultId": "db2550ba-4c7f-4e7f-95d8-0a064f368f14",
"status": "completed",
"statusLabel": "Completed",
"submissionId": "8d70fed5-8f01-410d-87bd-8755725d7c6f"
}
headers = {
"X-IduScore-Event": "<x-iduscore-event>",
"X-IduScore-Delivery-Id": "<x-iduscore-delivery-id>",
"X-IduScore-Timestamp": "<x-iduscore-timestamp>",
"X-IduScore-Signature": "<x-iduscore-signature>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-IduScore-Event': '<x-iduscore-event>',
'X-IduScore-Delivery-Id': '<x-iduscore-delivery-id>',
'X-IduScore-Timestamp': '<x-iduscore-timestamp>',
'X-IduScore-Signature': '<x-iduscore-signature>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
completedAt: '2026-04-24T00:49:32.389Z',
eventType: 'result.ready',
partnerSubmissionId: 'SYN-SUB-20260331-000001',
reportId: '8b37c3c5-a223-456b-9c96-ad2d0e2e2ce6',
resultId: 'db2550ba-4c7f-4e7f-95d8-0a064f368f14',
status: 'completed',
statusLabel: 'Completed',
submissionId: '8d70fed5-8f01-410d-87bd-8755725d7c6f'
})
};
fetch('https://api.idunox.com/_reference/outbound-webhooks/result_ready', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));Webhook: result.ready
Outbound callback the platform sends to your registered HTTPS URL when a result is ready.
curl --request POST \
--url https://api.idunox.com/_reference/outbound-webhooks/result_ready \
--header 'Content-Type: application/json' \
--header 'X-IduScore-Delivery-Id: <x-iduscore-delivery-id>' \
--header 'X-IduScore-Event: <x-iduscore-event>' \
--header 'X-IduScore-Signature: <x-iduscore-signature>' \
--header 'X-IduScore-Timestamp: <x-iduscore-timestamp>' \
--data '
{
"completedAt": "2026-04-24T00:49:32.389Z",
"eventType": "result.ready",
"partnerSubmissionId": "SYN-SUB-20260331-000001",
"reportId": "8b37c3c5-a223-456b-9c96-ad2d0e2e2ce6",
"resultId": "db2550ba-4c7f-4e7f-95d8-0a064f368f14",
"status": "completed",
"statusLabel": "Completed",
"submissionId": "8d70fed5-8f01-410d-87bd-8755725d7c6f"
}
'import requests
url = "https://api.idunox.com/_reference/outbound-webhooks/result_ready"
payload = {
"completedAt": "2026-04-24T00:49:32.389Z",
"eventType": "result.ready",
"partnerSubmissionId": "SYN-SUB-20260331-000001",
"reportId": "8b37c3c5-a223-456b-9c96-ad2d0e2e2ce6",
"resultId": "db2550ba-4c7f-4e7f-95d8-0a064f368f14",
"status": "completed",
"statusLabel": "Completed",
"submissionId": "8d70fed5-8f01-410d-87bd-8755725d7c6f"
}
headers = {
"X-IduScore-Event": "<x-iduscore-event>",
"X-IduScore-Delivery-Id": "<x-iduscore-delivery-id>",
"X-IduScore-Timestamp": "<x-iduscore-timestamp>",
"X-IduScore-Signature": "<x-iduscore-signature>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-IduScore-Event': '<x-iduscore-event>',
'X-IduScore-Delivery-Id': '<x-iduscore-delivery-id>',
'X-IduScore-Timestamp': '<x-iduscore-timestamp>',
'X-IduScore-Signature': '<x-iduscore-signature>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
completedAt: '2026-04-24T00:49:32.389Z',
eventType: 'result.ready',
partnerSubmissionId: 'SYN-SUB-20260331-000001',
reportId: '8b37c3c5-a223-456b-9c96-ad2d0e2e2ce6',
resultId: 'db2550ba-4c7f-4e7f-95d8-0a064f368f14',
status: 'completed',
statusLabel: 'Completed',
submissionId: '8d70fed5-8f01-410d-87bd-8755725d7c6f'
})
};
fetch('https://api.idunox.com/_reference/outbound-webhooks/result_ready', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));POST request the platform sends to your registered webhook URL when a result becomes ready.
Registering a webhook URL
Contactpartner@idunox.com to register your HTTPS callback URL.
Webhook headers
The platform sends the following headers on every delivery:| Header | Description |
|---|---|
X-Idunox-Event | Always result.ready for this event |
X-Idunox-Delivery-Id | UUID for this delivery attempt (use for idempotency on your side) |
X-Idunox-Timestamp | Unix time in seconds (integer as decimal string) |
X-Idunox-Signature | HMAC-SHA256 signature formatted as v1=<hex> |
Verifying the signature
Verify every delivery before processing:- Concatenate:
X-Idunox-Timestamp + "." + raw_request_body - Compute HMAC-SHA256 over that string using your webhook signing secret.
- Compare to the hex digest in
X-Idunox-Signature(after thev1=prefix). - Reject deliveries where the timestamp is more than 5 minutes old.
import hmac, hashlib, time
def verify(secret: str, timestamp: str, body: bytes, signature: str) -> bool:
if abs(time.time() - int(timestamp)) > 300:
return False
signed_payload = timestamp.encode() + b"." + body
mac = hmac.new(secret.encode(), signed_payload, hashlib.sha256)
expected = "v1=" + mac.hexdigest()
return hmac.compare_digest(expected, signature)
Responding to the webhook
Return any2xx status to acknowledge the delivery. Non-2xx responses and transport failures may be retried by the platform.
Webhook body
The body identifies the completed result so you can retrieve it:{
"eventType": "result.ready",
"resultId": "db2550ba-4c7f-4e7f-95d8-0a064f368f14",
"submissionId": "8d70fed5-8f01-410d-87bd-8755725d7c6f",
"partnerSubmissionId": "your-ref-001",
"reportId": "8b37c3c5-a223-456b-9c96-ad2d0e2e2ce6",
"status": "completed",
"statusLabel": "Completed",
"completedAt": "2026-04-27T00:49:32.389Z"
}
resultId to call GET /v1/results/{resultId} and retrieve the full result.Headers
Always result.ready for this flow (duplicates eventType in the body for routing layers).
result.ready Idempotency / support id for this delivery attempt.
Unix time in seconds (integer as decimal string) used in the HMAC input.
^[0-9]+$HMAC-SHA256 signature, formatted as v1=<hex>.
^v1=[0-9a-f]+$Body
Outbound result.ready webhook JSON body (HTTPS POST). Minimal partner notification: correlate by ids and
load full detail via GET result APIs. Does not include internal tenant UUIDs, job ids, model output, or
correlation metadata (those remain in delivery records server-side). Breaking change from the prior
envelope that included inference, tenantId, and processingJobId.
Not an HTTP path on this API; documented here as the partner contract for callbacks.
result.ready Stable public slug for submission pipeline state (partner JSON).
received, validating, validated, processing, completed, failed, rejected 1Present when a report bundle artifact id is available on the result (prefers PDF, then JSON, then HTML).
Response
Webhook received (any 2xx is treated as success)