REST API Reference

Send data to GoodLogs from any language using HTTP. All endpoints accept JSON and return JSON.

Authentication

Include your API key in the Authorization header:

bash
Authorization: Bearer gl_sk_eu_your_key_here
Key TypeFormatPermissions
Publicgl_pk_{region}_...Events only (/v1/events). Safe for client-side.
Secretgl_sk_{region}_...Logs + events. Server-side only.

Base URLs

Requests are routed to the regional API matching your key's region prefix:

POST /v1/events

Ingest product analytics events. Works with both public and secret keys.

bash
curl -X POST https://api.goodlogs.ajaysharma.dev/v1/events \
  -H "Authorization: Bearer gl_pk_eu_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "batch": [
      {
        "event": "signup",
        "distinctId": "user_123",
        "properties": {
          "plan": "pro",
          "source": "google",
          "amount": 29.99
        }
      },
      {
        "event": "page_view",
        "properties": {
          "path": "/pricing",
          "referrer": "https://google.com"
        }
      }
    ]
  }'

Event Fields

FieldTypeRequiredDescription
eventstringYesEvent name (e.g. 'signup', 'purchase')
distinctIdstringNoUser ID for analytics. Stored as distinct_id in properties.
propertiesobjectNoAny key-value data — all fields are searchable via GQL
timestampISO 8601NoOverride timestamp (default: server time)

Tip: Pass any properties you want — they're stored flat and queryable. No schema required.

POST /v1/logs

Ingest structured log entries. Requires a secret key.

bash
curl -X POST https://api.goodlogs.ajaysharma.dev/v1/logs \
  -H "Authorization: Bearer gl_sk_eu_your_secret" \
  -H "Content-Type: application/json" \
  -d '{
    "batch": [
      {
        "severity": "error",
        "message": "Payment failed: card_declined",
        "properties": {
          "orderId": "ord_123",
          "amount": 29,
          "service": "billing",
          "env": "prod"
        }
      },
      {
        "severity": "info",
        "message": "User signed up",
        "properties": {
          "userId": "u_456",
          "method": "google"
        }
      }
    ]
  }'

Log Fields

FieldTypeRequiredDescription
severitystringYesdebug, info, warn, error, fatal
messagestringYesLog message (max 64KB)
propertiesobjectNoAny key-value data — all fields are searchable via GQL
timestampISO 8601NoOverride timestamp (default: server time)

Legacy fields (metadata, context, code_location) are still accepted for backward compatibility — they get flattened into properties automatically.

Response Format

json
{
  "accepted": 5,
  "rejected": 0
}

Status 202 Accepted on success.

API Key Endpoints (/v1)

These endpoints authenticate with API keys (no JWT needed). The project is determined from the key.

GET /v1/info

Get project info, org details, usage, and key count. Scope: data:read.

GET /v1/schema

Get discovered schema — event names, property fields, types, and volumes. Scope: data:read.

POST /v1/gql/query

Run a single GQL query. Scope: data:read.

bash
curl -X POST https://api.goodlogs.ajaysharma.dev/v1/gql/query \
  -H "Authorization: Bearer gl_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"q": "count | where severity = '\''error'\'' | last 1h"}'

Response: {query, data} — direct result. Errors return standard error format.

POST /v1/gql

Batch: run multiple GQL queries in one request. Max 10 queries. Scope: data:read.

bash
curl -X POST https://api.goodlogs.ajaysharma.dev/v1/gql \
  -H "Authorization: Bearer gl_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"queries": [
    "from:events | count_distinct(distinct_id) | last:1d",
    "from:events | count | last:30d",
    "from:events | count by event_name | top 10 | last:30d"
  ]}'

Response: array [{status: "ok", query, data}, ...] — partial failures return {status: "error", error: "msg"} per query.

GET /v1/gql/autocomplete

GQL autocomplete suggestions. Pass q (partial query) and optional cursor position.

POST /v1/gql/nl

Convert natural language to GQL. Body: {"prompt": "...", "mode": "explorer"}. Scope: data:read.

GET /v1/info

Project info, org, usage, and key count. Scope: data:read.

GET /v1/schema

Discovered schema — event names, property fields, types, and volumes. Scope: data:read.

Alerts (CRUD)

MethodPathScopeDescription
GET/v1/alertsalerts:readList all alert rules
POST/v1/alertsalerts:writeCreate alert rule
PUT/v1/alerts/:idalerts:writeUpdate alert rule
DELETE/v1/alerts/:idalerts:writeDelete alert rule

For alert timeline, use GQL: from:alert_events | last 7d

For analytics (DAU, trends), use GQL batch:

json
{"queries": [
  "count distinct $distinct_id from:events | last 1d",
  "count from:events | last 30d",
  "count by event from:events | sort count desc | limit 10"
]}

AI Chat

MethodPathScopeDescription
POST/v1/ai/chatai:chatSend message, get response
POST/v1/ai/chat/streamai:chatSSE streaming response

Body: {"message": "...", "session_id": "..."}.

Session Replay

MethodPathScopeDescription
POST/v1/replay/sessionsingest:writeUpsert session metadata
POST/v1/replay/chunks?session_id=...&seq=N&start_ts=...&end_ts=...&event_count=Ningest:writeUpload gzipped rrweb chunk

Continuous Profiling

MethodPathScopeDescription
POST/v1/profiles/chunks?profiler_id=...&profile_type=cpu&sample_count=N&...ingest:writeUpload profile chunk (JSON body, up to 10 MiB)

Public Status Pages (no auth)

MethodPathDescription
GET/v1/status/{slug}JSON status snapshot (status, uptime, incidents)
GET/v1/status/{slug}/incidents?days=NPaged incident history
GET/v1/status-pages/{slug}/resolveResolve slug → region + title

Dashboard Endpoints (/api)

These endpoints use JWT authentication (from login/signup).

GET /api/orgs/:org/projects/:project/gql

Execute a GQL query. Requires JWT auth (from login). Pass the query as a URL parameter.

bash
# Search
curl "https://api.goodlogs.ajaysharma.dev/api/orgs/{org_id}/projects/{project_id}/gql?q=severity:error%20last:24h" \
  -H "Authorization: Bearer {jwt_token}"

# Aggregate
curl "https://api.goodlogs.ajaysharma.dev/api/orgs/{org_id}/projects/{project_id}/gql?q=severity:error%20|%20count%20by%20message%20|%20top%2010" \
  -H "Authorization: Bearer {jwt_token}"

Response

json
{
  "query": {
    "source": "logs",
    "mode": "aggregate",
    "filters": [{"field": "severity", "op": "eq", "value": "error"}],
    "pipeline": [{"type": "aggregate", "func": "count", "group_by": ["message"]}]
  },
  "data": {
    "mode": "aggregate",
    "table": "logs",
    "results": [
      {"message": "Connection timeout", "value": 42},
      {"message": "Payment declined", "value": 15}
    ],
    "total_groups": 2
  }
}

GET /api/orgs/:org/projects/:project/gql/autocomplete

Schema-aware GQL autocomplete and validation.

bash
curl "https://api.goodlogs.ajaysharma.dev/api/orgs/{org_id}/projects/{project_id}/gql/autocomplete?q=severity:&cursor=9" \
  -H "Authorization: Bearer {jwt_token}"
json
{
  "suggestions": [
    {"text": "error", "description": "12,345 logs", "kind": "value"},
    {"text": "warning", "description": "5,678 logs", "kind": "value"}
  ],
  "valid": true,
  "parsed": { "source": "logs", "filters": [] }
}

POST /api/orgs/:org/projects/:project/gql/nl

Convert natural language to a GQL query using AI. Consumes 1 AI query from quota.

bash
curl -X POST "https://api.goodlogs.ajaysharma.dev/api/orgs/{org_id}/projects/{project_id}/gql/nl" \
  -H "Authorization: Bearer {jwt_token}" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "show me errors from the last hour", "mode": "explorer"}'
json
{
  "gql": "severity:error last:1h",
  "valid": true,
  "parsed": { "source": "logs", "filters": [] }
}
FieldTypeDescription
promptstringNatural language query (max 500 chars)
modestring"explorer" (search/aggregate) or "alert" (threshold conditions)

GET /api/orgs/:org/projects/:project/schema

Get discovered schema — all property keys, types, example values, and event names.

json
{
  "log_properties": [
    {"key": "orderId", "type": "string", "examples": ["ord_123"], "volume": 1500},
    {"key": "duration_ms", "type": "number", "examples": [125, 340], "volume": 8200}
  ],
  "event_properties": [
    {"key": "plan", "type": "string", "examples": ["pro", "free"], "volume": 3400}
  ],
  "event_names": [
    {"name": "signup", "volume": 1200},
    {"name": "purchase", "volume": 890}
  ]
}

Schema is auto-discovered as you ingest data — no manual configuration needed.

Server-Injected Fields

The API automatically parses the User-Agent header and adds these fields to every log and event:

FieldExample
$browserChrome 125
$osmacOS 14
$deviceDesktop
$ip203.0.113.42

Limits

LimitValue
Max batch size500 items per request
Max request body2 MB
Max log message64 KB per entry
Rate limit (Free)10 req/s
Rate limit (Starter)20 req/s
Rate limit (Pro)50 req/s
Rate limit (Team)100 req/s

Error Codes

StatusCodeMeaning
400VALIDATION_ERRORInvalid request body or GQL parse error
401UNAUTHORIZEDMissing or invalid API key / JWT
402QUOTA_EXCEEDEDPlan limit reached
403FORBIDDENInsufficient permissions or CORS blocked
404NOT_FOUNDResource not found
422VALIDATION_ERRORGQL query error or invalid input
429RATE_LIMITEDToo many requests
500INTERNAL_ERRORServer error

Warning: Error responses include a descriptive message in error.message — use it for debugging.