Ingest API
The ingest API is the open, CDN-safe surface the JavaScript widget
talks to from your users’ browsers. It is authenticated with your public project
key (pr_…) in a header, uses no cookies, and has open CORS — the project key plus
optional origin allowlisting is the security boundary.
This is a different API from the REST API: that one lives
under /api/v1, is authenticated with a secret Bearer key (pr_sk_…), and is for
server-side reads and admin. The ingest API is for the widget only. Most people
never call it directly — the widget does. It is documented here for custom clients
and debugging.
Base URL and auth
Section titled “Base URL and auth”https://room.patchrooms.com/ingestEvery request carries the public project key in a header:
x-alphabug-project-key: pr_xxxIf a project sets allowedOrigins, a browser request whose Origin is not on that
list is rejected. Same-origin requests that omit Origin (e.g. first-party GETs)
pass. An identity token may be attached with x-alphabug-identity: <token> for
verified user identity; it is validated against the project’s identity secret and
ignored if unset.
Auth failure returns 401 { "error": "invalid_project_key_or_origin" } on every
route (except GET /flags/:key, which returns { "enabled": false }).
GET /config
Section titled “GET /config”Returns the widget configuration and any active channel hints. Used by the programmatic loader to theme itself.
{ "widgetConfig": { "mascot": "fox", "anchor": "middle-right" }, "hints": [{ "channelKey": "bug", "weight": "max", "userId": null }]}GET /channels
Section titled “GET /channels”Returns the project’s non-archived channels (sorted oldest first) and the default channel key.
{ "defaultChannelKey": "bug", "channels": [ { "id": "665d...", "projectId": "665e...", "key": "bug", "name": "Bug", "color": "#c0392b", "mascot": "fox", "baseWeight": 1, "matchers": [{ "conditions": [], "weight": 0, "note": "" }], "archived": false, "createdAt": "2026-05-01T12:00:00.000Z", "updatedAt": "2026-05-01T12:00:00.000Z" } ]}GET /flags/:key
Section titled “GET /flags/:key”Checks whether an alpha flag is enabled for the project. Returns { "enabled": false }
for unknown flags or auth failure.
{ "enabled": true }POST /blob
Section titled “POST /blob”Uploads a screenshot or audio blob before it is referenced from a report. The blob
is stored and returned as a blobId; it stays unbound until a report references it.
multipart/form-data:
| Field | Type | Description |
|---|---|---|
file | file | The binary. Required. |
kind | 'screenshot' | 'audio' | Required. Selects the size/mime limits. |
width, height | number | Screenshot pixel dimensions (optional). |
durationMs | number | Audio duration (optional, capped at the audio block limit). |
{ "blobId": "665f...", "mime": "image/png", "bytes": 20481 }Errors: 400 kind_invalid, 400 file_required, 400 duration_too_long,
413 block_too_large, 415 mime_not_allowed. Server-stored mime/bytes/
dimensions are authoritative — a report’s block metadata is overwritten with them.
POST /report
Section titled “POST /report”Submits a report. application/json:
| Field | Type | Description |
|---|---|---|
blocks | Block[] | Required. The report payload (text / screenshot / audio / selection). Binary blocks reference a blobId from POST /blob. |
channelKey | string | Optional. Which channel to file into — see resolution below. |
context | object | Optional. Page context, plus artifactId / artifact for Rooms. |
{ "reportId": "665f..." }Channel resolution
Section titled “Channel resolution”channelKey is resolved, never trusted verbatim. The server looks for a real,
non-archived channel with that key; if it doesn’t exist, it silently falls back to
the project’s defaultChannelKey; if that doesn’t resolve either, the request is
rejected with 400 channel_invalid. An unknown channel is never auto-created —
channels are created only through the REST API
or the dashboard. See Channels.
Errors
Section titled “Errors”| HTTP | error | Meaning |
|---|---|---|
400 | blocks_invalid | Blocks failed schema validation. |
400 | blob_id_invalid | A referenced blobId is not a valid id. |
400 | channel_invalid | No requested/default channel resolves. |
400 | context_invalid | context failed schema validation. |
400 | blob_mime_mismatch | A blob’s type doesn’t match the block referencing it. |
403 | blob_project_mismatch | A referenced blob belongs to another project. |
404 | blob_not_found | A referenced blob does not exist. |
409 | blob_already_used | A referenced blob is already bound to a report. |