OwlMetry
API Reference

Metrics

Metric definition CRUD and aggregation query endpoints.

Metric definition CRUD, raw event listing, and aggregation queries. All routes are nested under /v1/projects/:projectId.

GET /v1/projects/:projectId/metrics

List all metric definitions for a project.

Auth required: Yes (metrics:read permission or JWT)

// Response (200)
{
  "metrics": [
    {
      "id": "uuid",
      "project_id": "uuid",
      "name": "App Launch Time",
      "slug": "app-launch-time",
      "description": "Time from cold start to first interactive frame",
      "documentation": null,
      "schema_definition": null,
      "aggregation_rules": null,
      "status": "active",
      "created_at": "2024-01-01T00:00:00.000Z",
      "updated_at": "2024-01-01T00:00:00.000Z"
    }
  ]
}

GET /v1/projects/:projectId/metrics/:slug

Get a single metric definition by slug.

Auth required: Yes (metrics:read permission or JWT)

// Response (200)
{
  "id": "uuid",
  "project_id": "uuid",
  "name": "App Launch Time",
  "slug": "app-launch-time",
  "description": "Time from cold start to first interactive frame",
  "documentation": null,
  "schema_definition": null,
  "aggregation_rules": null,
  "status": "active",
  "created_at": "2024-01-01T00:00:00.000Z",
  "updated_at": "2024-01-01T00:00:00.000Z"
}

GET /v1/metrics/by-id/:id

Get a metric definition by UUID. Useful for the web dashboard where detail pages use UUID-based URLs.

Auth required: Yes (metrics:read permission or JWT)

Response shape is identical to the slug-based endpoint above.

POST /v1/projects/:projectId/metrics

Create a new metric definition.

Auth required: Yes (metrics:write permission or JWT, admin role required)

// Request
{
  "name": "App Launch Time",
  "slug": "app-launch-time",
  "description": "Time from cold start to first interactive frame",
  "documentation": "Measured from didFinishLaunchingWithOptions to first frame render.",
  "schema_definition": null,
  "aggregation_rules": null
}

// Response (201)
{
  "id": "uuid",
  "project_id": "uuid",
  "name": "App Launch Time",
  "slug": "app-launch-time",
  "description": "Time from cold start to first interactive frame",
  "documentation": "Measured from didFinishLaunchingWithOptions to first frame render.",
  "schema_definition": null,
  "aggregation_rules": null,
  "status": "active",
  "created_at": "2024-01-01T00:00:00.000Z",
  "updated_at": "2024-01-01T00:00:00.000Z"
}

Field reference

FieldTypeRequiredDescription
namestringYesDisplay name.
slugstringYesMust match ^[a-z0-9-]+$. Unique within a project.
descriptionstringNoShort description.
documentationstringNoExtended documentation or measurement notes.
schema_definitionobjectNoJSON schema for metric attributes.
aggregation_rulesobjectNoCustom aggregation configuration.

Returns 409 if a metric with the same slug already exists in the project.

PATCH /v1/projects/:projectId/metrics/:slug

Update a metric definition.

Auth required: Yes (metrics:write permission or JWT, admin role required)

// Request (all fields optional)
{
  "name": "Updated Name",
  "description": "Updated description",
  "documentation": "Updated docs",
  "schema_definition": null,
  "aggregation_rules": null,
  "status": "archived"
}

// Response (200)
{
  "id": "uuid",
  "project_id": "uuid",
  "name": "Updated Name",
  "slug": "app-launch-time",
  "description": "Updated description",
  "documentation": "Updated docs",
  "schema_definition": null,
  "aggregation_rules": null,
  "status": "archived",
  "created_at": "2024-01-01T00:00:00.000Z",
  "updated_at": "2024-01-15T12:00:00.000Z"
}

The status field accepts active or archived.

DELETE /v1/projects/:projectId/metrics/:slug

Soft-delete a metric definition.

Auth required: Yes (JWT only, admin role required. Agent keys receive 403.)

// Response (200)
{
  "deleted": true
}

GET /v1/projects/:projectId/metrics/:slug/events

List raw metric events for a specific metric, ordered by timestamp descending.

Auth required: Yes (metrics:read permission or JWT)

Query parameters

ParameterTypeDescription
phasestringFilter by phase: start, complete, fail, cancel, record.
tracking_idstringFilter by operation tracking ID (UUID).
user_idstringFilter by user ID.
environmentstringFilter by environment.
sincestringStart time. Relative (1h, 30m, 7d, 1w, 30s) or ISO 8601.
untilstringEnd time. Relative (1h, 30m, 7d, 1w, 30s) or ISO 8601.
data_modestringproduction (default), development, or all.
cursorstringCursor from previous response.
limitnumberItems per page (1-200, default 50).
// Response (200)
{
  "events": [
    {
      "id": "uuid",
      "app_id": "uuid",
      "session_id": "uuid",
      "user_id": "user-123",
      "api_key_id": "uuid",
      "metric_slug": "app-launch-time",
      "phase": "complete",
      "tracking_id": "uuid",
      "duration_ms": 1250,
      "error": null,
      "attributes": {
        "tracking_id": "uuid",
        "duration_ms": "1250"
      },
      "environment": "ios",
      "os_version": "17.4",
      "app_version": "1.2.0",
      "device_model": "iPhone15,2",
      "build_number": "42",
      "is_dev": false,
      "client_event_id": "uuid",
      "timestamp": "2024-01-15T10:30:00.000Z",
      "received_at": "2024-01-15T10:30:01.000Z"
    }
  ],
  "cursor": "2024-01-15T10:29:00.000Z",
  "has_more": true
}

GET /v1/projects/:projectId/metrics/:slug/query

Run an aggregation query over metric events.

Auth required: Yes (metrics:read permission or JWT)

Query parameters

ParameterTypeDescription
sincestringStart time (default: 24 hours ago). Relative (1h, 30m, 7d, 1w, 30s) or ISO 8601.
untilstringEnd time. Relative (1h, 30m, 7d, 1w, 30s) or ISO 8601.
app_idstringFilter to a specific app.
app_versionstringFilter by app version.
device_modelstringFilter by device model.
os_versionstringFilter by OS version.
user_idstringFilter by user ID.
environmentstringFilter by environment.
data_modestringproduction (default), development, or all.
group_bystringGroup results. See options below.

Group by options

ValueDescription
time:hourGroup by hour (ascending).
time:dayGroup by day (ascending).
time:weekGroup by week (ascending).
app_idGroup by app.
app_versionGroup by app version.
device_modelGroup by device model.
os_versionGroup by OS version.
environmentGroup by environment.

Response

{
  "slug": "app-launch-time",
  "aggregation": {
    "total_count": 500,
    "start_count": 200,
    "complete_count": 180,
    "fail_count": 15,
    "cancel_count": 5,
    "record_count": 100,
    "success_rate": 92.31,
    "duration_avg_ms": 1250.5,
    "duration_p50_ms": 1100.0,
    "duration_p95_ms": 2500.0,
    "duration_p99_ms": 4200.0,
    "unique_users": 150,
    "error_breakdown": [
      { "error": "NetworkTimeout", "count": 10 },
      { "error": "ServerError", "count": 5 }
    ],
    "groups": [
      {
        "key": "environment",
        "value": "ios",
        "total_count": 400,
        "complete_count": 160,
        "fail_count": 10,
        "success_rate": 94.12,
        "duration_avg_ms": 1100.0
      }
    ]
  }
}

Aggregation fields

FieldTypeDescription
total_countnumberTotal metric events matching the query.
start_countnumberEvents with phase start.
complete_countnumberEvents with phase complete.
fail_countnumberEvents with phase fail.
cancel_countnumberEvents with phase cancel.
record_countnumberEvents with phase record.
success_ratenumber or nullcomplete / (complete + fail) * 100, rounded to 2 decimals. Null if no completions or failures.
duration_avg_msnumber or nullAverage duration in milliseconds.
duration_p50_msnumber or nullMedian duration.
duration_p95_msnumber or null95th percentile duration.
duration_p99_msnumber or null99th percentile duration.
unique_usersnumberCount of distinct user IDs.
error_breakdownarrayTop 20 error messages with counts (from fail phase events).
groupsarrayPresent only when group_by is specified. Max 100 groups.

Ready to get started?

Install the CLI and let your agent handle the rest.