POST /change-events
Ingest a deploy / commit / release event for status-transition correlation
Request body
{
"source": "ci",
"kind": "deploy",
"ref": "abc123",
"title": "string",
"url": "string",
"service": "string",
"occurred_at": "2026-01-01T00:00:00.000Z",
"dedupe_key": "string"
}
Example request
curl -X POST "/api/v1/change-events" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d "{"source":"ci","kind":"deploy","ref":"abc123","title":"string","url":"string","service":"string","occurred_at":"2026-01-01T00:00:00.000Z","dedupe_key":"string"}"
Responses
200: recorded
400: invalid request
title: invalid_body. The body is not valid JSON.
401: missing or invalid bearer token
title: unauthenticated. No bearer token was sent, or the key is
invalid or revoked. detail distinguishes the two.
403: missing required scope
title: forbidden. The key is valid but does not carry
write:change_events.
422: invalid event
title: invalid_change_event. The event parsed and was
structurally valid JSON, but its contents failed validation.
429: rate limit exceeded
title: rate_limited. A burst or daily limit was exceeded;
detail names which. The body carries retry_after in seconds.
500: internal error
title: internal_error. An unhandled server error. Safe to retry.
Every error is an RFC 7807 problem detail served as
application/problem+json:
{
"type": "https://observer.example/problems/forbidden",
"title": "forbidden",
"status": 403,
"detail": "missing scope: write:change_events"
}
Branch on title, not on detail. See
Errors and status codes for the full
catalogue and the rate-limit headers.