Ingest

Envelope, legacy store, release artifacts, and user feedback, all DSN-authenticated.

Core ingest path. Authenticate with DSN credentials. Dashboard sessions are not valid here.

What is ingest?

A DSN-authenticated POST to /api/{project_id}/envelope/ or /store/. Success is 202 { "id": "<uuid>" } with a 2 MB body cap.

Base: POST /api/{project_id}/… where {project_id} is the project UUID from the DSN. Persist runs after the response.

Try ingest

Build a store POST for a host you already run. Seed defaults match ./scripts/seed-dev.sh. Change host if EPURE_PORT is not 8080. Fields persist in this tab.

store curl

curl -sS -D - -o /tmp/epure-ingest.json -X POST
  "http://localhost:8080/api/550e8400-e29b-41d4-a716-446655440000/store/"
  -H "X-Sentry-Auth: Sentry sentry_version=7, sentry_key=a1b2c3d4e5f6g7h8i9j0, sentry_secret=supersecretdevkey"
  -H "Content-Type: application/json"
  -d '{
  "platform": "javascript",
  "exception": {
    "values": [{ "type": "Error", "value": "Epure try-it" }]
  }
}'

Expected

HTTP/1.1 202 Accepted

{ "id": "<event-uuid>" }

Then open Issues. This panel does not POST from the browser. CORS and your DSN stay on your machine.

POST /api/{project_id}/envelope/

Accepts application/x-sentry-envelope (newline-delimited Sentry envelope).

Request

AuthX-Sentry-Auth or sentry_key / sentry_secret query
BodyEnvelope bytes ≤ 2 MB
CORSOPTIONS supported

Envelope layout:

  1. Envelope header JSON line (may include event_id, sdk, …)
  2. Repeated: item header JSON (type, optional length) + newline + payload

Item handling

Item typeBehavior
eventParsed, queued, persisted
transactionDiscarded (exception-only product)
attachment, session, replay_*, profile*, check_in, otherSkipped

If no event item is present → 400 invalid_envelope.

Response

202 Accepted

{ "id": "660e8400-e29b-41d4-a716-446655440001" }

id is the assigned event UUID. Persistence runs on a Tokio mpsc worker after the response.

From the repo root after seed-dev:

curl -sS -D - -o /tmp/epure-envelope.json -X POST \
  "http://localhost:8080/api/550e8400-e29b-41d4-a716-446655440000/envelope/" \
  -H "X-Sentry-Auth: Sentry sentry_version=7, sentry_key=a1b2c3d4e5f6g7h8i9j0, sentry_secret=supersecretdevkey" \
  -H "Content-Type: application/x-sentry-envelope" \
  --data-binary @fixtures/sentry/browser/envelope.txt
HTTP/1.1 202 Accepted

POST /api/{project_id}/store/

Legacy single-event JSON ingest (older SDKs, curl, microcontrollers).

Request

AuthDSN (header or query)
BodyJSON event, or gzip/zlib-compressed JSON (Content-Encoding)
Limit≤ 2 MB

Response

202 Accepted with { "id": "<uuid>" } (same shape as envelope).

Malformed / empty / bad compression → 400 invalid_store.

curl -sS -D - -o /tmp/epure-store.json -X POST \
  "http://localhost:8080/api/${PROJECT_ID}/store/" \
  -H "X-Sentry-Auth: Sentry sentry_version=7, sentry_key=${PUBLIC}, sentry_secret=${SECRET}" \
  -H "Content-Type: application/json" \
  -d '{"platform":"javascript","exception":{"values":[{"type":"Error","value":"boom"}]}}'

POST /api/{project_id}/releases/{version}/files/

Upload release artifacts for JS/TS demangle. Walkthrough: Source maps.

Request

AuthDSN
Content-Typemultipart/form-data
Fieldsfile (required), name (optional path)
{version}Release label; no .., /, or \

Response

201 Created

{ "id": "<artifact-uuid>", "name": "~/dist/app.min.js.map" }
StatuserrorWhat to do
400invalid_release_versionDrop .. / \ from {version}
400invalid_release_fileSend multipart field file
401invalid_dsnFix key
403dsn_revoked / project_mismatchRotate key or match project id
500storage_errorCheck EPURE_ARTIFACTS_DIR volume

Files land under EPURE_ARTIFACTS_DIR (canonical-path sandbox).


POST /api/{project_id}/user-feedback/

Crash-dialog feedback linked to an ingested event.

Request body

{
  "event_id": "660e8400-e29b-41d4-a716-446655440001",
  "name": "Ada",
  "email": "ada@example.com",
  "comments": "Clicked Save and it crashed"
}
FieldRequired
event_idyes; must exist for this project
name, email, commentsno

Email values are scrubbed with the same secret rules as event ingest.

Response

201 Created{ "id": "<feedback-uuid>" }

Unknown event_id404 event_not_found. Read it back: Events.


Async path and spike valve

After DSN + ingest-cap checks:

  1. Fingerprint preview from the event payload.
  2. Spike valve (default 100 events/min/fingerprint): enqueue full body or counter-only (body discarded; issue count still increments). Both still return 202.
  3. Worker demangles JS/TS when maps exist, scrubs PII, groups, writes Postgres.

Per-project hard cap (default 5000 events/hour) → 403 ingest_cap_exceeded before enqueue.

Queue unavailable → 503 queue_unavailable.

Details: Errors.

Can I GET an event with the DSN?

No. The DSN is inbound only. Use a session and Events. A cookie on envelope or store does nothing. Ingest success stays 202 { "id": "<uuid>" }.

What does HTTP 202 mean?

Accept is non-blocking. Persist and JS/TS demangle run on a Tokio mpsc worker after the response. Spike-valve saturation still returns 202 while dropping duplicate bodies. Empty Issues after a 202 is usually the environment filter: Errors.

What is the 2 MB cap?

Envelope and store bodies over 2 MB return 413 payload_too_large, and release file uploads share that cap. {version} cannot contain .., /, or \. This is separate from the hourly ingest cap, which returns 403.

What does the spike valve do?

About 100 raw events per minute per fingerprint. Saturated fingerprints still get 202 and a counter bump, while extra bodies may drop. The hourly project cap (default 5000) is the 403 ingest_cap_exceeded path, checked before enqueue. A closed queue is 503.