Callback Contract¶
The Dispatcher POSTs a JSON payload to the Controller when a task reaches a terminal state.
Endpoint¶
Authentication¶
Two layers, both checked before the payload is processed:
Bearer Token¶
The token is generated at dispatch time and stored as a SHA-256 hash on the task record. The callback view hashes the incoming token and compares using constant-time comparison.
HMAC Signature (optional)¶
When CALLBACK_SIGNING_KEY is set, the Dispatcher must send:
The signature is HMAC-SHA256(key, "<task-guid>:<raw-body>").
Timing attack prevention
Both checks use constant-time comparison to prevent timing attacks.
Payload Schema¶
| Field | Type | Required | Description |
|---|---|---|---|
status |
string | yes | Terminal status: completed, failed, timed_out, or cancelled |
exit_code |
integer or null | no | Process exit code. 0 = success. null if killed before exit |
result_key |
string | no | Object storage key for the result artifact. Max 500 chars |
result_metadata |
object | no | Arbitrary metadata (tokens used, duration, etc.) |
error_message |
string | no | Human-readable error. Max 5000 chars |
error |
string | no | Alias for error_message (backward compat). Max 5000 chars |
completed_at |
string (ISO 8601) | no | When the task finished on the Dispatcher side |
task_id |
string | no | Task UUID echoed back. Informational only |
log_stream |
string | no | Log stream reference or URL. Max 1000 chars |
Strict schema
Additional properties are not allowed. Unknown fields will be rejected.
Successful Completion¶
{
"status": "completed",
"exit_code": 0,
"result_key": "results/550e8400-e29b-41d4-a716-446655440000/output.json",
"result_metadata": {
"tokens_used": 12450,
"duration_seconds": 87
}
}
Failure¶
{
"status": "failed",
"exit_code": 137,
"error_message": "Container killed: OOM (memory limit 2Gi exceeded)"
}
Responses¶
200 OK¶
Callback accepted, task record updated.
400 Bad Request¶
Payload failed schema validation.
{
"error": "Invalid callback payload.",
"validation_errors": [
"(root): 'status' is a required property"
]
}
403 Forbidden¶
Invalid token or HMAC signature.
404 Not Found¶
Task GUID does not exist.
429 Too Many Requests¶
Rate limit exceeded (100 requests/minute per IP).
Rate Limiting¶
Callbacks are rate-limited to 100 requests per minute per IP. The CallbackThrottle class in tasks/api.py enforces this.
Schema Definition¶
The canonical JSON Schema lives in controller/tasks/callback_schema.py as CALLBACK_SCHEMA. It is validated server-side using jsonschema before any task state is mutated.