API Documentation

Complete reference for all LogRack APIs: ingest logs, query historical data, stream real-time events, and manage log streams.

Ingest API

The Ingest API allows you to send log events to LogRack. You can send individual log entries or batch multiple events in a single request for better performance.

POST/api/ingest
Required Scope: ingest:write

Request Format

Send a JSON body with an events array containing one or more log entries:

Request Body
{
  "events": [
    {
      "message": "Your log message here",
      "level": "info",
      "ts": "2024-01-15T14:30:00.000Z",
      "metadata": { "key": "value" },
      "streamName": "api-logs"
    }
  ]
}

Field Reference

FieldTypeRequiredDescription
messagestringYesThe log message content. Maximum length: 64KB (65,536 characters).
levelstringYesLog severity level. Must be one of: trace, debug, info, warn, error, fatal.
tsstringNoISO-8601 timestamp in UTC (e.g., "2024-01-15T14:30:00.000Z"). Defaults to current server time if omitted.
metadataobjectNoArbitrary JSON object for structured data. Can contain any valid JSON values.
streamNamestringNoStream name to associate logs with. Auto-creates stream if it does not exist. Cannot be used with streamId.
streamIdstringNoStream ID to associate logs with. Cannot be used with streamName.

Log Levels

The following log levels are supported, in order of severity:

tracedebuginfowarnerrorfatal

Limits

1,000
Max events per batch
64 KB
Max message size
1,000
Requests per minute
per API key

Response

200 OK
{
  "success": true,
  "data": {
    "acceptedCount": 3,
    "rejectedCount": 0
  }
}

Partial Success

If some events fail validation, valid ones are still ingested:

200 OK (Partial Success)
{
  "success": true,
  "data": {
    "acceptedCount": 2,
    "rejectedCount": 1,
    "errors": [
      {
        "index": 1,
        "reason": "Invalid log level: critical. Must be one of: trace, debug, info, warn, error, fatal"
      }
    ]
  }
}

Examples

cURL — Single Log
curl -X POST https://your-domain/api/ingest \
  -H "Authorization: Bearer lrk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [{
      "message": "User logged in",
      "level": "info",
      "metadata": { "userId": "123" }
    }]
  }'
cURL — Batch
curl -X POST https://your-domain/api/ingest \
  -H "Authorization: Bearer lrk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      { "message": "Request started", "level": "debug" },
      { "message": "Processing data", "level": "info", "metadata": { "items": 42 } },
      { "message": "Request completed", "level": "info" }
    ]
  }'
JavaScript / Fetch
async function sendLog(apiKey, message, level, metadata = {}) {
  const response = await fetch('/api/ingest', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      events: [{
        message,
        level,
        metadata,
        ts: new Date().toISOString(), // Optional: defaults to server time
      }],
    }),
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error?.message || 'Failed to send log');
  }

  return response.json();
}

// Usage
await sendLog('lrk_your_api_key', 'User signed up', 'info', {
  userId: 'user_123',
  plan: 'premium',
});
Python / Requests
import requests
from datetime import datetime, timezone

def send_logs(api_key: str, events: list[dict]) -> dict:
    """Send log events to LogRack."""
    response = requests.post(
        "https://your-domain/api/ingest",
        headers={
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
        },
        json={"events": events},
    )
    response.raise_for_status()
    return response.json()

# Single log
send_logs("lrk_your_api_key", [{
    "message": "Payment processed",
    "level": "info",
    "metadata": {"amount": 99.99, "currency": "USD"},
}])

# Batch of logs
send_logs("lrk_your_api_key", [
    {"message": "Order created", "level": "info"},
    {"message": "Inventory checked", "level": "debug"},
    {"message": "Payment processed", "level": "info"},
    {"message": "Order confirmed", "level": "info"},
])

Query API

Query log events with filtering, pagination, and time range selection. Results are returned in pages with cursor-based pagination for efficient navigation through large result sets.

GET/api/logs
Required Scope: query:read

Query Parameters

ParameterTypeRequiredDefaultDescription
startstringNo1 hour agoStart of time range (inclusive). ISO-8601 format in UTC.
endstringNonowEnd of time range (exclusive). ISO-8601 format in UTC.
limitnumberNo100Maximum number of results. Max: 500.
cursorstringNoOpaque cursor for pagination. Use nextCursor from previous response.
orderstringNodescSort order by timestamp. Values: "asc" or "desc".
levelstringNoFilter by log level. Can be repeated: level=error&level=warn.
qstringNoSearch query for message field. Case-insensitive substring match. Max: 200 chars.
metaKeystringNoFilter logs where metadata contains this key.
metaValuestringNoFilter logs where metadata[metaKey] equals this value. Requires metaKey.
streamIdstringNoFilter logs by stream ID.

Response Format

200 OK
{
  "success": true,
  "data": {
    "items": [
      {
        "id": "cm5abc123def456",
        "timestamp": "2024-01-15T14:30:00.000Z",
        "ingestedAt": "2024-01-15T14:30:01.234Z",
        "level": "error",
        "message": "Connection timeout after 30s",
        "metadata": {
          "service": "api-gateway",
          "requestId": "req_789xyz"
        }
      },
      {
        "id": "cm5abc123def457",
        "timestamp": "2024-01-15T14:29:55.000Z",
        "ingestedAt": "2024-01-15T14:29:56.123Z",
        "level": "warn",
        "message": "High latency detected",
        "metadata": {
          "latencyMs": 2500
        }
      }
    ],
    "nextCursor": "eyJ0cyI6IjIwMjQtMDEtMTVUMTQ6Mjk6NTUuMDAwWiIsImlkIjoiY201YWJjMTIzZGVmNDU3In0",
    "pageInfo": {
      "limit": 50,
      "returned": 2
    }
  }
}

Pagination

The API uses cursor-based pagination for efficient navigation. When more results are available, the response includes a nextCursor value. Pass this value as the cursor parameter in your next request to fetch the next page.

Tip:

When nextCursor is null, you've reached the end of the results. Cursors are opaque strings — don't parse or modify them.

Examples

cURL — Basic Query
curl -X GET "https://your-domain/api/logs?limit=50&order=desc" \
  -H "Authorization: Bearer lrk_your_api_key"
cURL — With Filters
curl -X GET "https://your-domain/api/logs?level=error&level=warn&q=timeout&limit=100" \
  -H "Authorization: Bearer lrk_your_api_key"
cURL — Custom Time Range
curl -X GET "https://your-domain/api/logs?start=2024-01-15T00:00:00Z&end=2024-01-16T00:00:00Z" \
  -H "Authorization: Bearer lrk_your_api_key"
cURL — Pagination
curl -X GET "https://your-domain/api/logs?cursor=eyJ0cyI6IjIwMjQtMDEtMTVUMTQ6MzA6MDAuMDAwWiIsImlkIjoiYWJjMTIzIn0" \
  -H "Authorization: Bearer lrk_your_api_key"

Single Log API

Retrieve a single log entry by its unique ID. Returns a flat response (not wrapped in success/data envelope).

GET/api/logs/:id
Required Scope: query:read

Response Format

200 OK
{
  "id": "cm5abc123def456",
  "timestamp": "2024-01-15T14:30:00.000Z",
  "ingestedAt": "2024-01-15T14:30:01.234Z",
  "level": "error",
  "message": "Connection timeout after 30s",
  "metadata": {
    "service": "api-gateway",
    "requestId": "req_789xyz"
  }
}

Error Response

404 Not Found
{
  "error": "NOT_FOUND",
  "message": "Log entry not found"
}

Example

cURL
curl -X GET "https://your-domain/api/logs/cm5abc123def456" \
  -H "Authorization: Bearer lrk_your_api_key"

Stats API

Get aggregate statistics about your logs, including total count and breakdown by log level.

GET/api/logs/stats
Required Scope: query:read

Query Parameters

ParameterTypeRequiredDefaultDescription
startstringNo1 hour agoStart of time range. ISO-8601 UTC.
endstringNonowEnd of time range. ISO-8601 UTC.

Response Format

200 OK
{
  "success": true,
  "data": {
    "total": 15234,
    "byLevel": {
      "debug": 2100,
      "info": 10500,
      "warn": 1800,
      "error": 780,
      "fatal": 54
    },
    "timeRange": {
      "start": "2024-01-15T00:00:00.000Z",
      "end": "2024-01-16T00:00:00.000Z"
    }
  }
}

Example

cURL
curl -X GET "https://your-domain/api/logs/stats?start=2024-01-15T00:00:00Z&end=2024-01-16T00:00:00Z" \
  -H "Authorization: Bearer lrk_your_api_key"

Tail API

The Tail API enables real-time log streaming via polling. It returns logs newer than a specified timestamp, ordered oldest to newest, making it ideal for live log viewers.

GET/api/tail
Required Scope: query:read

Query Parameters

ParameterTypeRequiredDefaultDescription
sincestringYesFetch logs newer than this timestamp. ISO-8601 format in UTC. Required.
limitnumberNo200Maximum number of results. Max: 500.
levelstringNoFilter by log level. Can be repeated.
qstringNoSearch query for message field. Case-insensitive.
metaKeystringNoFilter logs where metadata contains this key.
metaValuestringNoFilter logs where metadata[metaKey] equals this value.
streamIdstringNoFilter logs by stream ID.

Response Format

200 OK
{
  "success": true,
  "data": {
    "items": [
      {
        "id": "cm5abc123def458",
        "timestamp": "2024-01-15T14:31:15.000Z",
        "ingestedAt": "2024-01-15T14:31:16.123Z",
        "level": "error",
        "message": "Database connection failed",
        "metadata": {
          "database": "postgres",
          "retryCount": 3
        }
      }
    ],
    "nextSince": "2024-01-15T14:31:16.123Z",
    "count": 1
  }
}

Polling Pattern

The Tail API is designed for polling. After each request, use the nextSince value from the response as the since parameter for your next request. This ensures you don't miss any logs and don't receive duplicates.

Recommended Poll Interval:

Poll every 1-2 seconds for responsive real-time updates. The nextSince value is either the timestamp of the most recent log returned, or the current server time if no logs were returned.

Polling Implementation
async function tailLogs(apiKey, onLogs) {
  let since = new Date(Date.now() - 10000).toISOString(); // Start 10s ago

  while (true) {
    const response = await fetch(`/api/tail?since=${since}`, {
      headers: { 'Authorization': `Bearer ${apiKey}` },
    });
    
    const { data } = await response.json();
    
    if (data.items.length > 0) {
      onLogs(data.items);
    }
    
    since = data.nextSince; // Use nextSince for next poll
    await new Promise(r => setTimeout(r, 1500)); // Poll every 1.5s
  }
}

Examples

cURL — Basic Tail
curl -X GET "https://your-domain/api/tail?since=2024-01-15T14:30:00Z" \
  -H "Authorization: Bearer lrk_your_api_key"
cURL — With Filters
curl -X GET "https://your-domain/api/tail?since=2024-01-15T14:30:00Z&level=error&streamId=cm5stream123" \
  -H "Authorization: Bearer lrk_your_api_key"

Streams API

Streams allow you to organize logs into logical groups (e.g., by service, environment, or feature). Each log event can optionally belong to a stream, and you can filter queries and tails by stream.

List Streams

GET/api/streams
Scope: streams:read
cURL
curl -X GET "https://your-domain/api/streams" \
  -H "Authorization: Bearer lrk_your_api_key"
200 OK
{
  "success": true,
  "data": {
    "streams": [
      {
        "id": "cm5stream123abc",
        "name": "api-logs",
        "description": "API server access logs",
        "createdAt": "2024-01-10T09:00:00.000Z",
        "updatedAt": "2024-01-10T09:00:00.000Z"
      },
      {
        "id": "cm5stream456def",
        "name": "worker-jobs",
        "description": "Background job processing logs",
        "createdAt": "2024-01-12T11:30:00.000Z",
        "updatedAt": "2024-01-14T15:45:00.000Z"
      }
    ],
    "total": 2
  }
}

Create Stream

POST/api/streams
Scope: streams:write
FieldTypeRequiredDescription
namestringYesUnique stream name within your tenant. Max 100 characters.
descriptionstringNoHuman-readable description.
cURL
curl -X POST "https://your-domain/api/streams" \
  -H "Authorization: Bearer lrk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "payment-service",
    "description": "Payment processing logs"
  }'
201 Created
{
  "success": true,
  "data": {
    "id": "cm5stream789ghi",
    "name": "payment-service",
    "description": "Payment processing logs",
    "createdAt": "2024-01-15T14:30:00.000Z",
    "updatedAt": "2024-01-15T14:30:00.000Z"
  }
}

Get Stream

GET/api/streams/:id
Scope: streams:read
cURL
curl -X GET "https://your-domain/api/streams/cm5stream123abc" \
  -H "Authorization: Bearer lrk_your_api_key"

Update Stream

PATCH/api/streams/:id
Scope: streams:write
FieldTypeRequiredDescription
namestringNoNew stream name (must be unique).
descriptionstring | nullNoNew description. Set to null to remove.
cURL
curl -X PATCH "https://your-domain/api/streams/cm5stream123abc" \
  -H "Authorization: Bearer lrk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "api-access-logs",
    "description": "Updated: API server access and error logs"
  }'
200 OK
{
  "success": true,
  "data": {
    "id": "cm5stream123abc",
    "name": "api-access-logs",
    "description": "Updated: API server access and error logs",
    "createdAt": "2024-01-10T09:00:00.000Z",
    "updatedAt": "2024-01-15T14:35:00.000Z"
  }
}

Delete Stream

DELETE/api/streams/:id
Scope: streams:write

Returns 204 No Content on success. Log events associated with the deleted stream will have their streamId set to null.

cURL
curl -X DELETE "https://your-domain/api/streams/cm5stream123abc" \
  -H "Authorization: Bearer lrk_your_api_key"

Authentication

All API requests must include an API key in the Authorization header using the Bearer scheme:

Authorization: Bearer lrk_your_api_key

API Key Scopes

API keys are scoped to specific operations. Request only the scopes you need:

ScopePermissions
ingest:writeSend log events via POST /api/ingest
query:readQuery logs, stats, and tail (GET /api/logs, /api/logs/stats, /api/tail)
streams:readList and view streams (GET /api/streams)
streams:writeCreate, update, delete streams (POST, PATCH, DELETE /api/streams)
keys:readList API keys (GET /api/api-keys)
keys:writeCreate and revoke API keys
Creating API Keys:

You can create API keys from the API Keys page. API keys are shown only once at creation time — store them securely.

Rate Limiting

API requests are rate limited per API key. When you exceed the rate limit, the API returns a 429 Too Many Requests response.

HeaderDescription
X-RateLimit-LimitMaximum requests per window
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when window resets
Retry-AfterSeconds to wait (only on 429 responses)

Error Codes

All error responses follow a consistent format with an error code and message:

{
  "success": false,
  "error": {
    "code": "INVALID_API_KEY",
    "message": "The provided API key is invalid or does not exist"
  }
}

Common Error Codes

HTTP StatusError CodeDescription
400VALIDATION_ERRORInvalid request body or missing required fields
400BATCH_TOO_LARGEBatch exceeds maximum size of 1000 events
400INVALID_JSONRequest body is not valid JSON
400MISSING_SINCEThe 'since' parameter is required for tail requests
401MISSING_AUTHNo Authorization header provided
401INVALID_API_KEYAPI key is invalid or does not exist
401REVOKED_API_KEYAPI key has been revoked
403INSUFFICIENT_SCOPEAPI key lacks the required scope for this operation
404NOT_FOUNDResource not found (log entry, stream, etc.)
404STREAM_NOT_FOUNDStream with the specified ID does not exist
409DUPLICATE_STREAM_NAMEA stream with this name already exists
429RATE_LIMIT_EXCEEDEDToo many requests; check Retry-After header
504QUERY_TIMEOUTQuery exceeded 30 second timeout