API Reference
The LogNorth HTTP API: send events and errors in batches, with the key, the limits, and what each answer means.
Send events to LogNorth over HTTP. This is what the SDKs use under the hood.
This page is the write path. To read your logs from an agent, use MCP: there is no REST read API.
Authentication
Section titled “Authentication”Each app has its own key. Create the app on the Apps page and copy its key. Keys start with lgn-.
Authorization: Bearer lgn-your-key-hereSend Events
Section titled “Send Events”POST /api/v1/eventsSend a single event or a batch. Both formats go to the same endpoint.
Single event:
curl -X POST https://logs.yoursite.com/api/v1/events \ -H "Authorization: Bearer lgn-your-key" \ -H "Content-Type: application/json" \ -d '{ "message": "POST /api/users → 201", "duration_ms": 150, "trace_id": "req-abc-123", "context": { "method": "POST", "path": "/api/users", "status": 201 } }'Batch:
curl -X POST https://logs.yoursite.com/api/v1/events \ -H "Authorization: Bearer lgn-your-key" \ -H "Content-Type: application/json" \ -d '{ "events": [ {"message": "GET /home → 200", "context": {"status": 200}}, {"message": "POST /login → 401", "context": {"status": 401}} ] }'There’s also an explicit batch alias at POST /api/v1/events/batch. It uses the same handler.
Event Schema
Section titled “Event Schema”| Field | Type | Required | Description |
|---|---|---|---|
message |
string | Yes | What happened |
timestamp |
string | No | RFC 3339, for example 2026-10-01T12:00:05.123Z. Missing or unreadable: the time LogNorth receives it |
duration_ms |
integer | No | How long it took in milliseconds |
trace_id |
string | No | Correlation ID for grouping related events |
context |
object | No | Arbitrary metadata (key-value pairs) |
message is the only required field. Everything else is optional.
Context
Section titled “Context”The context object is freeform. Put whatever you want in it. Common fields:
| Field | Example | Used for |
|---|---|---|
method |
"POST" |
HTTP method |
path |
"/api/checkout" |
Request path |
status |
500 |
HTTP status code |
error |
"connection timeout" |
Error message |
error_class |
"ConnectionError" |
Error type (for issue grouping) |
user |
"user@example.com" |
Who triggered it |
stack_trace |
"at checkout.go:42..." |
Full stack trace |
You can add any fields beyond these. They’re all searchable.
Error Detection
Section titled “Error Detection”You don’t set is_error. LogNorth derives it automatically. An event becomes an error when any of these are true:
context.errorexists and is non-emptycontext.error_classexists and is non-emptycontext.status >= 500(a number: the string"500"does not count)
{ "message": "POST /checkout → 500", "context": { "status": 500, "error": "Database connection timeout", "error_class": "ConnectionError" }}No levels (info/warn/error). Binary: error or not.
Response
Section titled “Response”201 Created:
{ "created": 2, "errors": ["event[1]: message is required"]}created: Number of events storederrors: Validation errors for individual events (partial success is allowed). The key is absent when every event is valid.
A batch of 10 events where 2 fail validation returns {"created": 8, "errors": [...]}. An event whose context.path starts with /. (/.env, /.git/config) is a scanner probe: LogNorth drops it without an error, and created does not count it. From v0.30.0, LogNorth keeps paths under /.well-known/, where OAuth and OpenID discovery live (RFC 8615).
Error responses:
| Status | Body | Reason |
|---|---|---|
| 400 | {"error": "Invalid request body"} |
Malformed JSON |
| 400 | {"error": "Invalid gzip body"} |
Content-Encoding: gzip with a body that is not gzip |
| 401 | {"error": "API key required"} |
Missing Authorization header |
| 401 | {"error": "Invalid API key"} |
Key doesn’t exist or inactive |
| 413 | {"error": "at most 1000 events per request"} |
More than 1,000 events in one request |
| 413 | {"error": "Request body too large"} |
A gzip body over 16 MB once inflated |
| 429 | {"error": "Too Many Requests", ...} |
Over the rate limit |
| 503 | {"error": "Could not store events. Retry."} |
The database was busy. Send the same batch again after the Retry-After header (5 seconds) |
The body may be gzip-compressed: send Content-Encoding: gzip. A request body is at most 4 MB as sent.
Events appear in LogNorth within a few seconds.
Rate Limits
Section titled “Rate Limits”Ingestion endpoints allow 1,000 requests per minute from each IP address. Each request can hold up to 1,000 events, so the event throughput is much higher. The SDKs send batches of 10.
OpenTelemetry
Section titled “OpenTelemetry”Already using OpenTelemetry? Two env vars and you’re done. See OpenTelemetry.