Webhooks#

Opt-in push notifications. Submit with a webhook_url and webhook_secret, and the platform will POST the result to your endpoint when it is ready. No polling needed.

How it works#

  1. You submit code with webhook_url and webhook_secret
  2. Your code executes in the sandbox
  3. The platform POSTs the result to your URL with HMAC-SHA256 signature headers
  4. You verify the signature and process the result

Example#

curl -X POST "https://api.rustbox.orkait.com/api/submit" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: rb_live_your_key_here" \
  -d '{
    "language": "python",
    "code": "print(42)",
    "webhook_url": "https://your-app.com/hooks/result",
    "webhook_secret": "your-hmac-secret"
  }'

Webhook payload#

When execution completes, the platform POSTs the full result to your URL:

{
  "id": "a0928c83-0a1d-4f5e-b724-7ecad619538f",
  "language": "python",
  "job_status": "completed",
  "schema_version": "1.0",
  "verdict": "AC",
  "exit_code": 0,
  "signal": null,
  "stdout": "42\n",
  "stderr": "",
  "output_integrity": "complete",
  "error_message": null,
  "cpu_time_secs": 0.009,
  "wall_time_secs": 0.025,
  "memory_peak_bytes": 3858432,
  "evidence": {
    "verdict_cause": "normal_exit",
    "verdict_actor": "runtime",
    "isolation_mode": "strict",
    "controls_applied": ["pid_namespace", "mount_namespace", "network_namespace", "memory_limit", "process_limit", "no_new_privileges"],
    "controls_missing": [],
    "cgroup": {
      "memory_limit_bytes": 268435456,
      "memory_peak_bytes": 3858432,
      "oom_events": 0,
      "oom_kill_events": 0,
      "cpu_usage_usec": 9000,
      "process_count": 0,
      "process_limit": 10
    },
    "timing": {
      "cpu_ms": 9,
      "wall_ms": 25,
      "cpu_wall_ratio": 0.36,
      "divergence": "cpu_bound"
    },
    "process_lifecycle": {
      "reap_status": "clean",
      "descendant_containment": "ok",
      "zombie_count": 0
    },
    "judge_actions": [],
    "collection_errors": []
  },
  "created_at": "2026-04-02T12:00:00.000Z",
  "started_at": "2026-04-02T12:00:00.001Z",
  "completed_at": "2026-04-02T12:00:00.026Z"
}

Signature verification#

We follow the Standard Webhooks specification - the same pattern used by OpenAI, Stripe, and Svix.

Headers#

HeaderValue
webhook-idUnique message ID (the submission UUID)
webhook-timestampUnix timestamp (seconds)
webhook-signaturev1,<base64-encoded-hmac>

Signed content#

The HMAC-SHA256 is computed over:

{webhook-id}.{webhook-timestamp}.{body}

Verification example (Python)#

import hmac, hashlib, base64
 
def verify_webhook(body: bytes, headers: dict, secret: str) -> bool:
    msg_id = headers["webhook-id"]
    timestamp = headers["webhook-timestamp"]
    signature = headers["webhook-signature"]
 
    signed_content = f"{msg_id}.{timestamp}.".encode() + body
    expected = hmac.new(
        secret.encode(), signed_content, hashlib.sha256
    ).digest()
    expected_b64 = "v1," + base64.b64encode(expected).decode()
 
    return hmac.compare_digest(signature, expected_b64)

Delivery behaviour#

  • Webhooks are opt-in. No URL, no webhook.
  • Secret is mandatory when URL is provided. The platform does not deliver unsigned webhooks.
  • HTTPS required. Webhook URLs must use HTTPS.
  • Non-blocking delivery. Webhook failures do not affect the submission result.
  • 3 attempts. Immediate, then 1s delay, then 5s delay. Server errors (5xx) trigger retry; client errors (4xx) do not. Poll /api/result/{id} as fallback if all attempts fail.

SSRF protection#

Webhook URLs are validated:

  • Must use HTTPS
  • Private IPs blocked: 10.x, 172.16-31.x, 192.168.x, 169.254.x
  • Loopback blocked: 127.0.0.1, ::1, localhost