bichito
API

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" }
}
FieldTypeRequiredNotes
titlestringyes1–500 chars.
descriptionstringyes1–10,000 chars.
severityenumnolow, medium (default), high, critical.
environmentstringnoFree-form (production, staging, anything you want).
app_versionstringnoFree-form.
stack_tracestringnoUp to ~50KB. We don't parse it; it's stored as-is.
urlstringnoThe page the report came from.
user_agentstringnoBrowser UA. The widget fills this; if you call the API directly, send what you have.
reporter_emailstringnoOptional reporter contact. Validated as email.
reporter_identifierstringnoAnything that helps you find this user (user id, session id, …).
extraobjectnoFree-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):

  1. Submit the bichito as above. Note the returned id.
  2. POST /api/v1/bugs/{id}/attachments with { filename, content_type, content_length }. Returns a presigned URL.
  3. PUT the bytes to the presigned URL directly (Cloudflare R2 or S3-compatible storage).
  4. 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.

On this page