# Ingestion API > https://docs.errora.org/en/api/ingest These endpoints live **outside `/api/v1`** and are authenticated by the **DSN public key**, not by a user token. They are what SDKs, crontabs and browsers talk to. ## Authentication Any of these carries the key: ```http X-Sentry-Auth: Sentry sentry_version=7, sentry_key= ``` ```text ?sentry_key= # browser SDKs and non-SDK clients {"dsn": "https://@/"} # the dsn field of an envelope header (tunnelled) ``` The key is resolved **together with the project id in the path**, so a valid key aimed at the wrong project is rejected the same way a bad key is: `401 Invalid DSN key`. Too many requests in a minute → `429`. ## Events ```text POST /api//store/ # a single error event (legacy, still supported) POST /api//envelope/ # everything (modern default) ``` Both accept gzip-compressed bodies (`Content-Encoding: gzip`) and answer **`202 Accepted`** as soon as the payload is accepted; grouping and storage follow right after. Oversized payloads are rejected with `413`. ### Envelope format Newline-delimited JSON — a header, then per item an item-header line and a payload line: ```text {"event_id":"9a1f…","sent_at":"2026-01-01T00:00:00Z","dsn":"https://@/"} {"type":"event","content_type":"application/json"} {"level":"error","exception":{"values":[{"type":"ValueError","value":"boom"}]}} ``` Item types Errora consumes: | Item type | Product | | --- | --- | | `event` | [Errors](/en/products/issues) | | `transaction` | [Performance](/en/products/performance) (and [AI monitoring](/en/products/insights) for `gen_ai.*`/`mcp.*` spans) | | `log` | [Structured logs](/en/products/logs) | | `replay_event`, `replay_recording` | [Session replay](/en/products/session-replay) | | `check_in` | [Cron monitoring](/en/products/crons) | | `feedback`, `user_report` | [User feedback](/en/products/user-feedback) | | `profile`, `profile_chunk` | [Profiling](/en/products/profiling) | | `trace_metric`, `statsd` | [Metrics](/en/products/metrics) | ## Cron check-ins For jobs with no SDK. The key sits in the path, so a crontab line can use it directly. ```text POST /api//cron///?status=in_progress|ok|error PUT /api//cron////?status=ok|error ``` Optional query parameters: `environment`, `duration` (milliseconds). A `POST` with `status=in_progress` returns the check-in id you close later with the `PUT`. ## Security policy reports ```text POST /api//security/?sentry_key= ``` Accepts CSP, Expect-CT, Expect-Staple, HPKP and batched Reporting API bodies. Use it as your `report-uri` / `report-to` endpoint — see [Security policy reports](/en/products/security-reports). ## Crash-report modal ```text GET /api/embed/error-page/?dsn=&eventId= → the dialog's JavaScript POST /api/embed/error-page/?dsn=&eventId= → stores name/email/comments ``` A public, unauthenticated-by-session write by design — it runs on your users' pages — so it carries its own per-IP rate limit (10 submissions per minute). Every label is overridable with a query parameter of the same name. See [User feedback](/en/products/user-feedback#option-2--the-crash-report-modal). ## Status codes | Code | Meaning | | --- | --- | | `202` | Queued. This is success. | | `400` | Malformed payload or envelope | | `401` | Bad, missing or deactivated DSN key — or a key that doesn't belong to that project id | | `413` | Payload over the size limit | | `429` | Rate limited, **or** ingestion paused because the wallet is past its credit line — the `detail` field says which | ## Debugging a client ```bash # Does the key work at all? curl -i -X POST "$ERRORA/api/$PROJECT_ID/store/" \ -H "Content-Type: application/json" \ -H "X-Sentry-Auth: Sentry sentry_version=7, sentry_key=$KEY" \ -d '{"event_id":"9a1f4c2e7b8d4a1fa0c3e5d6b7a8c9d0","platform":"other","level":"error", "exception":{"values":[{"type":"SmokeTest","value":"hello"}]}}' ``` `202` means Errora took the event. If it still doesn't appear in **Issues**, check the project's sample rate and the organization's wallet balance.