Bu sayfanın Türkçesi de var. Türkçe oku →
Ingest formats
Errorbird offers four write endpoints. All of them use the same X-API-KEY
authentication, the same quota and the same PII scrubbing; they differ only in the
body format.
| Endpoint | Body | Use |
|---|---|---|
POST /api/v1/ingest |
A single CLEF event (JSON) | Manual testing, low volume |
POST /api/v1/ingest/batch |
NDJSON (one event per line), gzip supported | Production; Serilog/Seq sinks |
POST /api/v1/ingest/otlp |
OTLP/HTTP JSON logs | OpenTelemetry Collector |
POST /api/v1/ingest/browser |
Browser error (JSON) | @errorbird/browser; see Browser errors |
All of them return HTTP 202 on success, meaning "queued". Waiting for the write inside the request would tie your application's response time to Errorbird's database speed; that is why the acceptance criterion is "202 within 50 ms".
CLEF fields
CLEF (Compact Log Event Format) is the format Seq uses. Errorbird recognizes these fields:
| Field | Meaning |
|---|---|
@t |
Timestamp (ISO 8601). If missing, the time the server received the event is used. |
@l |
Level: Verbose, Debug, Information, Warning, Error, Fatal |
@mt |
Message template (User {UserId} not found) |
@m |
Rendered message |
@x |
Exception text / stack trace |
@r |
Rendered values of the template |
@i |
Event type id |
Template properties (such as UserId) are stored as jsonb in Metadata and are
searchable. Errorbird also reads release, environment, serverName and
stackTrace as top-level fields — they answer "which release introduced this error?".
Migrating from Serilog
In your existing Serilog.Sinks.Seq configuration, only the address and the key
change, with no code changes:
Log.Logger = new LoggerConfiguration()
.WriteTo.Seq(
serverUrl: "https://api.errorbird.com/api/v1/ingest",
apiKey: "ebrd_secret_…")
.CreateLogger();
The sink sends events in batches as NDJSON, and Errorbird's batch endpoint accepts exactly that. Client-side buffering and retries are the sink's own behavior and keep working as they are.
Batch sending
gzip -c events.ndjson | curl -X POST https://api.errorbird.com/api/v1/ingest/batch \
-H "X-API-KEY: ebrd_secret_…" \
-H "content-type: application/x-ndjson" \
-H "content-encoding: gzip" \
--data-binary @-
A single request can carry at most 5,000 events; a larger body returns 400.
The limit protects memory: if one request could open an unbounded buffer on the
server, the ingest pipeline would be at the mercy of a single client.
OTLP
curl -X POST https://api.errorbird.com/api/v1/ingest/otlp \
-H "X-API-KEY: ebrd_secret_…" \
-H "content-type: application/json" \
-d @otlp-logs.json
The resourceLogs[].scopeLogs[].logRecords[] structure is read; severityText
becomes the level, body.stringValue the message, and attributes go to Metadata.
Error codes
| Code | Meaning | What to do |
|---|---|---|
401 |
The key is invalid or revoked | Check the key |
400 |
The body could not be parsed or the batch limit was exceeded | Fix the body |
429 |
The monthly quota is used up or the rate limit was exceeded | Wait for the Retry-After header |
503 |
Circuit breaker open (the queue cannot be written) | Keep the events in a client buffer and retry |
The write rate limit is 2,000 events per second (token bucket, per key) and is separate from the read pool: read traffic does not slow down writes, and write traffic does not slow down reads.
Do not drop events on 429 or 503. Both are temporary; buffer on the client
and resend with exponential backoff.
How is the fingerprint calculated?
Grouping the same root error under a single Issue relies on a SHA-256 digest of the normalized message and stack trace:
- Variables in the message are replaced with placeholders. GUIDs, emails,
URLs, file paths, timestamps, IPs, hex values, quoted text and numbers are
replaced in that order.
Cart 9f3c… not found for user 4821andCart a1b2… not found for user 77produce the same signature. - The exception type is extracted. A prefix such as
System.NullReferenceException: messageis split off and enters the signature as a separate component. - The first 5 stack frames are used. Deeper frames vary with the calling code and would scatter the same error across different groups.
- Line numbers are dropped and paths are made machine-independent. Otherwise a one-line edit or a different build machine would create a new Issue.
.NET, Node.js, Java and browser (Chrome/Edge and Firefox/Safari) stack trace formats
are recognized separately. In browser frames the host and the query string are
dropped as well: the same bundle served from a CDN or with ?v=3 produces the same
signature. For minified JavaScript, the signature is calculated from the stack
mapped back to the original code with a source map. When the
same root error is sent 500 times with different line numbers and different variable
values, 500 raw rows are written to LogEvents, but only one row is created in
Issues, with a totalCount of 500.
Quota and retention
The quota is monthly and depends on the plan (Hobby 5,000, Pro 100,000, Business
1,000,000 events). When it runs out, ingest returns 429; the counter resets at the
start of the month.
Retention also depends on the plan (3 / 15 / 30 / 90+ days). Expired data is
dropped at the chunk level in TimescaleDB with drop_chunks; there is no
row-by-row deletion.