Documentation

API reference

Ingest logs by sending a POST request to the ingestion endpoint with a Bearer API key. Current API version: v1 (path versioning).

Endpoints

1. Batch Ingestion (POST /v1/logs)

Used by the SDK to send multiple logs in a single request. Max 100 events.

Batch request body
{
  "events": [
    {
      "message": "User signed in",
      "level": "info",
      "metadata": { "userId": 123 }
    },
    {
      "message": "Payment failed",
      "level": "error",
      "metadata": { "orderId": "abc", "amount": 50 }
    }
  ]
}

2. Single Event Ingestion (POST /v1/ingest)

Perfect for manual HTTP requests or simple scripts where you don't want to wrap logs in an array.

Single event request body
{
  "message": "Server started",
  "level": "info",
  "metadata": { "region": "us-east-1" }
}

Examples (SDK-less)

cURL

curl example
curl -X POST https://logger-api-dxqb.onrender.com/v1/ingest \
  -H "Authorization: Bearer <your_api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Testing from curl",
    "level": "info",
    "metadata": { "tag": "test" }
  }'

JavaScript (Fetch API)

fetch example
fetch('https://logger-api-dxqb.onrender.com/v1/ingest', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <your_api_key>',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    message: 'Logging from fetch',
    level: 'warn',
    metadata: { browser: 'Chrome' }
  })
});

Python (Requests)

python example
import requests

url = "https://logger-api-dxqb.onrender.com/v1/ingest"
headers = {
    "Authorization": "Bearer <your_api_key>",
    "Content-Type": "application/json"
}
data = {
    "message": "Hello from Python",
    "level": "info",
    "metadata": {"source": "script"}
}

response = requests.post(url, json=data, headers=headers)

Headers

  • Authorization: Bearer <api_key> (required)
  • Content-Type: application/json
  • Idempotency-Key: (optional) Unique value for critical logs to avoid duplicates on retry
  • X-Request-Id: (optional) Request ID for tracing

Field Reference

Fields: message (required); level (debug | info | warn | error); timestamp (ISO 8601); metadata, env, source (optional).

Dynamic Metadata & Errors

The metadata field accepts any valid JSON object. This is ideal for logging "unknown" data like mobile device info, app state, or complex server errors.

Tip: Formatting Errors

In many languages, JSON.stringify(error) returns an empty object {}. To log errors correctly via the Direct Ingestion API, you should manually extract the properties you care about.

Recommended error pattern (JS)
const logError = (err) => {
  return fetch('https://logger-api-dxqb.onrender.com/v1/ingest', {
    method: 'POST',
    headers: { 'Authorization': 'Bearer <key>', 'Content-Type': 'application/json' },
    body: JSON.stringify({
      message: err.message,
      level: 'error',
      metadata: {
        name: err.name,
        stack: err.stack, // capture the stack trace
        code: err.code    // if available
      }
    })
  });
};

Flexible Schemas

You don't need to define fields in advance. Just send whatever context helps you debug.

Dynamic context example
{
  "message": "User checkout failed",
  "metadata": {
    "cart": { "items": ["sku_1", "sku_2"], "total": 45.99 },
    "device": { "os": "Android", "version": "14" },
    "experiment_group": "variant_b"
  }
}

Responses

  • 202 Accepted – Body: { "accepted": N } (N = number of events accepted)
  • 400 Bad Request – Invalid JSON, missing events, or more than 100 events
  • 401 Unauthorized – Missing or invalid API key
  • 403 Forbidden – API key revoked or disabled
  • 429 Too Many Requests – Rate limit exceeded; Retry-After header may be set
  • 503 Service Unavailable – Queue full; retry later

Rate limit

Per API key; when exceeded the API returns 429. Use the Retry-After response header when present. Back off and do not retry in a tight loop. The SDK throws an error with message "Too many requests; retry after X seconds" when 429 is received (X from Retry-After), so your app can catch and display it.

Quotas

Free tier: 10,000 logs per month per project, 7-day retention. If you need a higher limit, use the dashboard or contact support.

Validation and error responses

API errors return JSON with error and optional message: { "error": "Bad Request", "message": "description" }. Always validate on the server; client-side checks are for UX only.

  • Ingestion (POST /v1/logs): message required per event; level one of debug | info | warn | error; events array max 100.
  • Auth (signup / login): email and password required; password minimum 8 characters. Signup returns 409 if email already registered.
  • Profile (PATCH /api/dashboard/me): At least one field required. Returns 409 with message "Username already taken." if username is taken.
  • Destination (PATCH project destination): When type is webhook, webhook_url required; when logger, read_api_url required; when direct_db_*, direct_db_url required.

Testing with the SDK or test-backend

The @logship/logger SDK and the examples/test-backend app both send requests in this format. Use them to verify your API key and see logs in the dashboard. See Getting started and SDK reference.