Skip to content

API Reference

REST API for sending events and errors to LogNorth

Send events to LogNorth over HTTP. This is what the SDKs use under the hood.

Create an app key in Settings. 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 — same handler.

FieldTypeRequiredDescription
messagestringYesWhat happened
timestampstringNoISO 8601 (defaults to now)
duration_msintegerNoHow long it took in milliseconds
trace_idstringNoCorrelation ID for grouping related events
contextobjectNoArbitrary 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:

FieldExampleUsed for
method"POST"HTTP method
path"/api/checkout"Request path
status500HTTP 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
{
"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)

A batch of 10 events where 2 fail validation returns {"created": 8, "errors": [...]}.

Error responses:

StatusBodyReason
400{"error": "Invalid request body"}Malformed JSON
401{"error": "API key required"}Missing Authorization header
401{"error": "Invalid API key"}Key doesn’t exist or inactive

Events are written immediately to a fast buffer, then processed asynchronously in the background. This means:

  • The API responds fast (no processing overhead on write)
  • Events appear in the dashboard within a few seconds
  • Errors are grouped into issues automatically
  • Notifications fire after processing

Ingestion endpoints allow 1,000 requests per minute per instance. Each request can contain multiple events in a batch, so the effective event throughput is much higher.

Already using OpenTelemetry? Point your OTLP exporter at LogNorth instead. See OpenTelemetry.