errorcoredocsbeta

API reference

Ingest: POST /v1/ingest

Content-Type: application/errorcore+json. This is the only production ingest contract; there is no plaintext JSON alternative.

Headers

HeaderMeaning
Authorization: Bearer ec_live_…Ingestion API key. The sole source of organization, project, and environment scope.
X-Errorcore-Event-IdRouting hint. Must equal the envelope eventId.
X-Errorcore-Key-IdRouting hint. Must equal the envelope keyId.
X-Errorcore-Payload-KindRouting hint. Must equal the envelope kind.

Body

{
  "v": 2,
  "eventId": "<uuid>",
  "kind": "error",
  "sdk": { "name": "errorcore", "version": "<semver>" },
  "keyId": "<16 hex chars>",
  "iv": "<base64>",
  "ciphertext": "<base64>",
  "authTag": "<base64>",
  "hmac": "<base64>",
  "compressed": false,
  "producedAt": "<ISO 8601>"
}

kind is error or payload_blob. blobId is required when kind is payload_blob and absent otherwise; for a blob, eventId is the parent error's id.

The ciphertext decrypts to an SDK ErrorPackage. Accepted inner schemaVersion values are 1.1.0, 1.2.0, and 1.3.0; the current SDK emits 1.3.0. The inner eventId must equal the envelope eventId: a mismatch is quarantined, never silently accepted.

Cryptography

  • Encryption key = HKDF-SHA256 of your DEK; MAC key derived the same way unless self-managed.
  • keyId = first 8 bytes of sha256(derived encryption key), hex.
  • AES-256-GCM with AAD "2|" + keyId + "|" + sdkVersion + "|" + eventId + "|" + kind + "|" + (blobId ?? "").
  • Outer hmac = HMAC-SHA256 over iv ‖ ciphertext ‖ authTag ‖ AAD, verified timing-safe before any decryption.
  • Plaintext larger than 8 KiB is raw-deflate compressed before encryption; inflation is bounded on both sides.

Order of checks

  1. Authenticate the API key → tenant scope. Otherwise 401.
  2. Enforce content type (415), streaming body cap (413), bounded JSON parse.
  3. Validate envelope shape and header/envelope agreement (422).
  4. Resolve the project encryption key by scope and keyId. Unknown or retired → 403, zero quota.
  5. Verify the outer HMAC. Failure → 403, zero quota.
  6. Rate limit → 429 with Retry-After, zero quota, nothing persisted.
  7. Admission: reserve exactly one usage unit atomically, or reject 403 plan_limit.
  8. Store the envelope bytes as received, enqueue the job, return 202.

Responses

StatusMeaningConsumes allowanceSDK retries
202Accepted. Envelope, admission, and job are committed.one unit for a new kind=errorn/a
202 with duplicate: trueReplay of an existing receipt for the same identity and digest.non/a
401API key missing, unknown, or revoked.nono
403 plan_limitThe organization's allowance is used up.nono
403 envelope authUnknown or retired keyId, or HMAC verification failed.nono
409Same event identity, different content digest.nono
413Body exceeds the configured cap.nono
415Wrong content type.nono
422Envelope failed shape validation.nono
429Rate limited.noyes
500, 502, 503, 504Transient server or dependency failure.noyes

403 plan_limit and 429 are deliberately distinct. A plan limit means the allowance is exhausted and retrying cannot help; upgrade or wait for the period reset. Rate limiting means slow down; the SDK retries with jitter and honors Retry-After. See billing and usage.

A 202 means the event was durably admitted, not that reconstruction finished. Idempotency identity is (scope, eventId, kind, blobId?); retry an unknown outcome with the same eventId.

Console endpoints

The browser calls authenticated same-origin endpoints. Server handlers derive the user and active organization from the session, validate the selected project and environment against that organization, then call the errorcore backend. A caller-supplied organization id is never accepted.

  • GET /api/console/workspaces: projects authorized for the active organization.
  • GET /api/console/bootstrap?projectId=…&environment=…: org account snapshot and overview state.
  • GET /api/console/search?projectId=…&environment=…&q=…: at most 20 case and event results.
  • GET /api/console/setup/first-event?projectId=…&environment=…: latest setup stage.
  • PATCH /api/console/cases/{caseId}/status?projectId=…&environment=…: persists a case state.
  • POST /api/console/dlq/{failureId}/retry?projectId=…&environment=…: queues an admin-authorized retry.

Mutations require an Idempotency-Key. Responses use private, no-store caching. Errors are returned as safe categories (authentication, authorization, invalid request, conflict, rate limited, timeout, unavailable, upstream contract) without backend detail.

Backend boundary

Every console request is scoped beneath:

/v1/console/organizations/{authenticatedOrgId}/projects/{projectId}/environments/{environment}

Organization-level operations (account, provisioning, project creation, billing sessions) sit directly under the organization root. Every response DTO is validated before it is rendered.

Credential plaintext is derived from a secret-manager CSPRNG secret and a tenant-scoped operation nonce, then shown once. Retrying the same idempotency key derives the same value and cannot create a second credential; different tenants, workspaces, targets, and operation keys derive unrelated values. The backend marks replayed mutations, and replayed responses never reveal plaintext; a lost first reveal requires rotation or reissue. Only a keyed digest, prefix, and last four characters cross the persistence boundary, and the returned mask must match before plaintext is revealed.

Decrypted event payloads are never returned by console endpoints.

On this page