Skip to content
Bugtail Docs
Menu

HTTP without an SDK

No SDK needed: anything that can make an HTTP request can send events and log lines to Bugtail. A shell script, a cron job, a log shipper or a language without a Sentry SDK.

Use a collector with the Bugtail native protocol, created under Settings > Projects and collectors. Its key goes in the URL.

Endpoints

POST https://ingest.bugtail.eu/ingest/<key>/events
POST https://ingest.bugtail.eu/ingest/<key>/logs
POST https://ingest.bugtail.eu/ingest/<key>/batch

/events and /logs take any of these:

  • a single JSON object
  • a JSON array of objects
  • an object wrapping the list: {"events": [...]} or {"logs": [...]}
  • NDJSON, one object per line, with Content-Type: application/x-ndjson

Bodies may be compressed with gzip or deflate.

Events

An event becomes an issue, grouped with earlier events of the same error.

curl -X POST https://ingest.bugtail.eu/ingest/<key>/events \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Sync failed",
    "level": "error",
    "environment": "production",
    "release": "1.4.0",
    "user": {"id": 4821},
    "exception": {
      "type": "SyncException",
      "value": "Remote refused",
      "frames": [
        {"file": "/app/Jobs/Sync.php", "line": 20, "function": "handle"}
      ]
    }
  }'
Field Meaning
message What happened. Used as the title when there is no exception.
level debug, info, warning, error or fatal. Defaults to error.
exception type, value and a list of frames with file, line and function, innermost last.
environment, release For filtering, and for releases.
user An object with an id, email or username. Counted as users affected.
fingerprint A list of strings that overrides grouping. See Grouping.
timestamp Unix seconds or an ISO 8601 date. Defaults to the time it arrives.
event_id Optional. An id that was recorded before is ignored, so retries never count twice.

Log lines

Log lines are shown under Logs. The shape is the one a Monolog handler writes, so a log shipper usually needs no mapping:

curl -X POST https://ingest.bugtail.eu/ingest/<key>/logs \
  -H "Content-Type: application/x-ndjson" \
  --data-binary $'{"level":"info","message":"Backup started"}\n{"level":"error","message":"Backup failed","context":{"disk":"/var"}}'
Field Meaning
message The line itself.
level A level name, or a Monolog level number.
channel Where it came from, such as database or billing.
context An object with anything else worth keeping.
environment, release For filtering.
trace_id, span_id Links the line to a traced operation.
timestamp Unix seconds or an ISO 8601 date. Defaults to the time it arrives.

Several kinds at once

/batch takes one object with a list per kind. Every list is optional:

{
  "events": [],
  "logs": [],
  "metrics": []
}

Events and log lines have the shapes above. A browser can send a batch with navigator.sendBeacon(), which is why the key is in the URL: a beacon cannot set headers. Browsers refuse beacons over about 64 KB, so split larger batches.

Metrics

Each metric in the batch is one reading:

{
  "name": "checkout.duration",
  "kind": "histogram",
  "timestamp": 1756296000.5,
  "value": 1234.5,
  "count": 12,
  "min": 40,
  "max": 300,
  "unit": "ms",
  "attributes": {"route": "/checkout"}
}

kind is gauge, sum or histogram. A histogram carries the sum of its observations in value and their number in count. Readings are deltas: what happened since the previous send, not a running total. Send "temporality": "cumulative" for a running total. Attributes are what a series is split on, so keep them to a small set of values.

Responses

Status Meaning
202 Accepted. It shows up in the dashboard within seconds.
401 The key is unknown.
403 The collector is disabled, the key was rotated, or the site is not in the allowed origins.
413 The body is larger than the collector allows.
429 Too many requests. Wait for the number of seconds in Retry-After.