OwlMetry
API Reference

Ingest

POST /v1/ingest — send events from SDKs and backends. Supports gzip compression and batch payloads.

Send events from SDKs and backends. This is the primary endpoint used by OwlMetry SDKs.

POST /v1/ingest

Accept a batch of events for a specific app.

Auth required: Yes (client API key with events:write permission)

Rate limited: Yes (token bucket: 100 max tokens, 10 tokens/sec refill)

Request body

{
  "bundle_id": "com.example.myapp",
  "events": [
    {
      "client_event_id": "550e8400-e29b-41d4-a716-446655440000",
      "session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "user_id": "owl_anon_xyz789",
      "level": "info",
      "message": "screen_viewed",
      "source_module": "HomeViewController",
      "screen_name": "Home",
      "custom_attributes": {
        "button_color": "blue",
        "experiment_group": "variant_a"
      },
      "environment": "ios",
      "os_version": "17.4",
      "app_version": "1.2.0",
      "build_number": "42",
      "device_model": "iPhone15,2",
      "locale": "en_US",
      "is_dev": false,
      "experiments": {
        "onboarding_flow": "variant_b"
      },
      "timestamp": "2024-01-15T10:30:00.000Z"
    }
  ]
}

Field reference

FieldTypeRequiredDescription
bundle_idstringConditionalRequired for non-backend apps. Must match the app's registered bundle_id.
eventsarrayYesArray of event objects (max 100 per batch).

Event fields

FieldTypeRequiredDescription
messagestringYesEvent name or description.
levelstringYesOne of: info, debug, warn, error.
session_idstringYesUUID generated per SDK session.
client_event_idstringNoUUID for deduplication. Events with duplicate IDs (within 48h) are silently skipped.
user_idstringNoUser identifier. Anonymous IDs use owl_anon_ prefix.
source_modulestringNoModule or class that emitted the event.
screen_namestringNoCurrent screen/page name.
custom_attributesobjectNoKey-value string pairs. Values truncated to 200 characters.
environmentstringNoRuntime environment. Must match the app's platform. See table below.
os_versionstringNoOperating system version.
app_versionstringNoApplication version string.
build_numberstringNoBuild number.
device_modelstringNoDevice model identifier.
localestringNoUser locale (e.g., en_US).
is_devbooleanNoWhether this event is from a development build. Default false.
experimentsobjectNoA/B experiment assignments as { name: variant } pairs.
timestampstringNoISO 8601 timestamp. Defaults to server time if omitted.

Allowed environments by platform

App platformAllowed environments
appleios, ipados, macos
androidandroid
webweb
backendbackend

Validation rules

  • Batch size: Maximum 100 events per request.
  • Timestamps: Must be valid ISO 8601. Cannot be more than 5 minutes in the future or more than 30 days in the past.
  • Custom attributes: Values are strings, truncated to 200 characters.
  • Deduplication: Events with a client_event_id that matches an existing event (within the last 48 hours) are silently skipped.
  • Bundle ID: For non-backend apps, the bundle_id in the request must match the app's registered bundle_id exactly.

Gzip compression

The endpoint accepts gzip-compressed request bodies. Set the Content-Encoding: gzip header. Both the compressed input and the decompressed output are limited to 1 MiB each. The compressed size is enforced via Content-Length check; the decompressed size is enforced during streaming decompression to prevent gzip bomb attacks (HTTP 413 if exceeded). The Swift SDK compresses payloads automatically.

Dual-write behavior

Events matching specific message patterns are automatically written to specialized tables:

  • Metric events: Messages matching metric:<slug>:<phase> are parsed and inserted into the metric_events table.
  • Funnel events: Events from track() calls are parsed and inserted into the funnel_events table.

These dual-writes are fire-and-forget and do not block the ingest response.

Response

// Success (200)
{
  "accepted": 5,
  "rejected": 1,
  "errors": [
    {
      "index": 3,
      "message": "events[3]: level must be one of info, debug, warn, error"
    }
  ]
}

The errors array is only present when rejected > 0. Each error includes the event's array index and a description.

FieldTypeDescription
acceptednumberNumber of events successfully stored.
rejectednumberNumber of events that failed validation.
errorsarrayValidation errors, one per rejected event. Only present when rejected > 0.

Ready to get started?

Install the CLI and let your agent handle the rest.