Ingest API
POST /api/v1/bugs — the public endpoint the widget uses. Body schema, optional fields, attachment flow.
The ingest endpoint is the only API route in the public surface that doesn't need a JWT. It accepts a project's X-API-Key and writes one bichito to that honeycomb's inbox.
This is what the widget calls. You can also call it directly from a server-side tool, a CLI, or a CI hook — anywhere you'd want to post a structured report.
Endpoint
POST /api/v1/bugs
x-api-key: sk_…
content-type: application/json
Body schema
{
"title": "Login button broken on Safari 17",
"description": "Steps: visit /login, click Sign in. Nothing happens. No console errors.",
"severity": "high",
"environment": "production",
"app_version": "1.4.2",
"stack_trace": null,
"url": "https://example.com/login",
"user_agent": "Mozilla/5.0 ...",
"reporter_email": "user@example.com",
"reporter_identifier": "user_42",
"extra": { "viewport": "1440x900", "billing_plan": "pro" }
}
| Field | Type | Required | Notes |
|---|---|---|---|
title | string | yes | 1–500 chars. |
description | string | yes | 1–10,000 chars. |
severity | enum | no | low, medium (default), high, critical. |
environment | string | no | Free-form (production, staging, anything you want). |
app_version | string | no | Free-form. |
stack_trace | string | no | Up to ~50KB. We don't parse it; it's stored as-is. |
url | string | no | The page the report came from. |
user_agent | string | no | Browser UA. The widget fills this; if you call the API directly, send what you have. |
reporter_email | string | no | Optional reporter contact. Validated as email. |
reporter_identifier | string | no | Anything that helps you find this user (user id, session id, …). |
extra | object | no | Free-form JSON. Stored verbatim. Useful for app-specific metadata. |
Response
201 Created:
{
"id": 12345,
"project_id": 42,
"title": "...",
"status": "open",
"severity": "high",
"created_at": "2026-05-07T11:42:00Z",
...
}
This is the canonical bichito payload — same shape GET /api/v1/bugs/{id} returns.
Attachments
Each bichito can carry one image attachment, max 2 MB. The flow is two-step (presigned URL):
- Submit the bichito as above. Note the returned
id. POST /api/v1/bugs/{id}/attachmentswith{ filename, content_type, content_length }. Returns a presigned URL.- PUT the bytes to the presigned URL directly (Cloudflare R2 or S3-compatible storage).
- The presigned URL stamps the attachment record once the PUT succeeds.
The widget does this dance for you. If you're hand-rolling, see the dashboard's /api/v1/bugs/{id}/attachments route for the exact shape.
Allowed types: image/png, image/jpeg, image/webp. Anything else returns 400.
Idempotency
The endpoint isn't idempotent today — submitting the same body twice creates two bichitos. If your client retries on network errors, the spam blocklist won't catch the duplicate (different created_at, identical otherwise). Either:
- Implement a client-side dedup window.
- Use the duplicate-of marker in the dashboard to link them after the fact.
Rate limit
60 reports / minute / X-API-Key. See Rate limits for what 429 looks like and the recommended retry behaviour.
What gets dropped silently
Reports matching a blocklist rule for the honeycomb still return 201 — the spammer never knows. Honeycombs over their monthly free cap also return 201 but the bichito is not persisted; we make the difference invisible to the reporter on purpose.
Companion endpoint
GET /api/v1/widget/info (authenticated with the same X-API-Key) returns plan-related metadata the widget needs at boot:
{
"plan": "free",
"powered_by_visible": true
}
That's how the "Powered by" badge in the widget knows whether to render. Not a public API to write your own UI on, but available if you want it.