> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lyceum.technology/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook Callbacks

> Get notified when a run finishes by having Lyceum POST to your URL

When you submit a run, you can supply a list of URLs that Lyceum Cloud will call with completion info once the execution finishes. This is the right tool when you don't want to poll the API yourself.

Common patterns:

* A backend that submits a long training job and wants to be notified when it's done
* A queue worker that fans out runs and needs to mark them complete in its own database
* A CI pipeline waiting on a remote build

For interactive workflows where a human is watching, the dashboard or `lyceum workloads list` is simpler.

## How it works

The execution request body for all three execution types accepts a `user_callback_urls` field, a list of HTTPS URLs. When the run reaches a terminal state (`completed`, `failed`, `system_failure`, `aborted`, `cancelled`), Lyceum POSTs job completion info to each URL.

The same field exists on:

* Python runs (`POST /execution/streaming/start`)
* Docker image runs (`POST /execution/image/start`)
* Docker Compose runs (`POST /execution/compose/start`)

## Submitting a callback

```bash theme={null}
curl -X POST https://api.lyceum.technology/api/v2/external/execution/streaming/start \
  -H "Authorization: Bearer $LYCEUM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "print(1+1)",
    "machine_type": "cpu",
    "user_callback_urls": [
      "https://your-service.example.com/lyceum-webhook"
    ]
  }'
```

You can supply more than one URL, useful for fanning out to multiple downstream systems.

## Receiving the callback

The endpoint at the URL you registered will receive an HTTPS POST when the run finishes. Build your handler to:

* **Return 2xx quickly**, Lyceum doesn't need a body, just an acknowledgement
* **Verify the source**, gate the endpoint behind a shared secret in the URL path or a header you control, since Lyceum doesn't sign callbacks
* **Be idempotent**, handle the case where a callback is delivered more than once

## Combining with secrets

If your callback handler requires a token (e.g. an HMAC secret you check), put it in an environment variable on Lyceum [Secrets](/docs/serverless/secrets) and reference it in the URL or as a query parameter when you submit the run. That keeps the secret out of your codebase.
