Change eventsPOST /change-events

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.