Most developers never call this directly — the SDK does it for you. But the whole contract is small, so here it is, hand-authored and complete.
All requests are POST to your project's ingest endpoint. Authenticate every request with a single project-key header.
POST https://<your-endpoint>/api/projects/{project_slug}/notices
x-errorgap-project-key: <key>
content-type: application/json
user-agent: errorgap-{lang}/{version}The only header the API reads is x-errorgap-project-key. Note that X-Errorgap-Api-Key is not accepted. Set a descriptive User-Agent so requests are attributable in logs.
| Purpose | Method | Path |
|---|---|---|
| Errors | POST | /api/projects/{project_slug}/notices |
| APM transactions | POST | /api/projects/{project_slug}/transactions |
| Session replay | POST | /api/projects/{project_slug}/sessions |
| Release tracking optional | POST | /api/projects/{project_slug}/releases |
The body sent to /notices. One envelope can carry multiple errors (e.g. an error chain).
{
"received_at": "2026-06-23T10:14:05Z",
"errors": [
{
"type": "TypeError",
"message": "Cannot read properties of undefined (reading 'id')",
"backtrace": [
{ "file": "app/checkout.js", "line": 42, "function": "applyCoupon", "in_app": true }
]
}
],
"context": {
"notifier": "errorgap-node",
"notifier_version": "0.1.0",
"release": "a1b2c3d",
"environment": "production"
},
"params": { "coupon": "[FILTERED]" }
}received_at — ISO-8601 timestamperrors[] — each with type + messagecontext.notifiercontext.notifier_versionproject_idbacktrace[].in_appcontext.release · context.root_directoryenvironment · session · paramsSDKs mask sensitive values before they leave the host. The default key list is matched as a case-insensitive substring; any match has its value replaced with "[FILTERED]". Filtering applies to params only.
password token secret api_key authorization cookie
# substring match, case-insensitive — "x_api_key" also matches "api_key"| Code | Meaning | Body |
|---|---|---|
| 201 | Accepted | JSON with group_id |
| 202 | Accepted, sampled | Accepted but rate-limited or sampled |
| 401 | Unauthorized | Bad or missing project key |
Release tracking additionally returns 200 (release already recorded) and 403 (key lacks release scope).
Send a test error with nothing but curl. A 201 with a group_id means ingestion works.
curl -X POST https://<your-endpoint>/api/projects/$SLUG/notices \
-H "x-errorgap-project-key: $KEY" \
-H "content-type: application/json" \
-d '{"received_at":"2026-06-23T10:14:05Z",
"errors":[{"type":"TestError","message":"hello from curl"}],
"context":{"notifier":"curl","notifier_version":"0"}}'Post a release so errors can be attributed to the deploy that introduced them.
{
"version": "a1b2c3d",
"environment": "production",
"deployed_at": "2026-06-23T10:00:00Z"
}| Code | Meaning |
|---|---|
| 201 | Release recorded |
| 200 | Release already existed |
| 403 | Key lacks release scope |