Skip to content
Install · free

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.

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-here
POST /api/v1/events

Send a single event or a batch. Both formats go to the same endpoint.

Single event:

Terminal window
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:

Terminal window
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.

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.

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.

You don’t set is_error. LogNorth derives it automatically. An event becomes an error when any of these are true:

  • context.error exists and is non-empty
  • context.error_class exists and is non-empty
  • context.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.

201 Created:

{
"created": 2,
"errors": ["event[1]: message is required"]
}
  • created: Number of events stored
  • errors: 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.

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.

Already using OpenTelemetry? Two env vars and you’re done. See OpenTelemetry.