REST is the contract. The Python and Node SDKs are thin clients over the same endpoint: they validate the event before it leaves your process, add the headers for you, and turn a refusal into a typed error.
Choose your path
| Path | Install | Guide |
|---|---|---|
| Python | pip install traffic-lights-events | Python SDK |
| Node | npm install @traffic-lights/events | Node SDK |
| REST | Nothing — one HTTPS POST | This page, below |
| AI agents | Add a connector — no code | Connect over MCP |
Configuration
Both SDKs read two environment variables. With either missing they refuse to send, and say which one.
export TL_API_BASE_URL="https://api.traffic-lights.io" export TL_API_KEY="<your API key>"
TL_API_BASE_URL is the bare origin — the SDK adds the path. Keep TL_API_KEY on the server: it travels in a header on every request, so it must never ship to a browser.
The REST API
One request. No SDK required.
curl -X POST https://api.traffic-lights.io/api/v1/events \
-H "X-Api-Key: $TL_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"source": "sai.tl.billing",
"detail-type": "FLOW_CALLBACK",
"detail": {
"runID": "run-2026-09-28-001",
"taskID": "20006510",
"status": "SUCCESS"
}
}'Headers
| Header | Required | What it does |
|---|---|---|
X-Api-Key | Yes | Your API key. The account is taken from the key, never from the body. |
Idempotency-Key | Yes | A unique value per event. Resending the same key returns the original eventId instead of creating a second event — so a retried timeout is safe. |
Content-Type | Yes | application/json |
Body
| Field | What it is |
|---|---|
source | The system reporting the event. Use the prefix shown in the examples. |
detail-type | What happened — for example FLOW_CALLBACK, the result of a task in a run. |
detail | The event itself. It must carry runID — the run you are reporting on. Traffic Lights never invents one for you. |
Responses
- 202 with
{"eventId": "…"}— the event was accepted. This is the only success. - 4xx — refused, with the server's reason. Fix the request; retrying the same one will not help.
- 5xx or timeout — delivery failed. Retry with the same
Idempotency-Key.
Treat anything other than a 202 as not delivered — including a 200. A 200 means something other than the events endpoint answered.