Skip to main content
The events query explorer lets you run SQL queries directly against your ingested usage events. Instead of scrolling through paginated event lists, you can write queries to filter, aggregate, and analyze your event data in real time. This is useful for debugging integrations, validating metric logic, or answering ad-hoc questions about usage patterns. The query explorer uses the same SQL engine that powers Orb’s billable metrics, so the queries you write here can inform how you build and refine your metrics.

Getting started

Navigate to Events > Query in the Orb dashboard. The explorer opens with a default query that counts events by name:
SELECT event_name, COUNT(1)
FROM events
GROUP BY event_name
The query runs automatically against the last 7 days of data. You’ll see a results table with the event names in your account and how many of each were ingested. From here, you can modify the query, adjust the time range, and scope results to a specific customer.

Writing queries

Queries follow standard SQL syntax against the events table. Every event you’ve ingested is available as a row in this table, with the following columns:
ColumnTypeDescription
event_namestringThe name of the event (e.g. transaction_processed).
timestamp_millisdatetimeWhen the event occurred, in epoch milliseconds.
idempotency_keystringThe unique identifier for the event.
customer_idstringThe Orb customer ID the event is attributed to.
propertiesobjectThe full properties dictionary sent with the event.
In addition to these built-in columns, every key in your event properties is available as a column. If you ingested events with a region property, you can reference region directly in your query without extracting it from the properties object.

SELECT *

You can use SELECT * to return all default columns. This is a convenient starting point when you want to inspect raw events:
SELECT * FROM events
WHERE event_name = 'api_call'
This expands to event_name, timestamp_millis, idempotency_key, customer_id, and properties.

Filtering with WHERE

Use WHERE clauses to filter to the events you care about. You can combine conditions with AND and OR:
SELECT * FROM events
WHERE event_name = 'transaction_processed'
AND payment_method = 'ach'
AND amount_cents > 1000

Aggregations

The explorer supports the following aggregation functions:
FunctionDescription
COUNT(...)Count of rows.
SUM(...)Sum of values.
AVG(...)Average of values.
MIN(...)Minimum value.
MAX(...)Maximum value.
EARLIEST_BY(value, order)Returns the first value, ordered by order.
LATEST_BY(value, order)Returns the last value, ordered by order.
When using aggregation functions, any non-aggregated columns in your SELECT must appear in a GROUP BY clause:
SELECT event_name, COUNT(1), SUM(amount_cents)
FROM events
WHERE event_name = 'transaction_processed'
GROUP BY event_name

Scalar functions

You can use the following functions within expressions:
FunctionDescription
COALESCE(...)Returns the first non-null argument.
LEAST(...)Returns the minimum of its arguments.
GREATEST(...)Returns the maximum of its arguments.
CEIL(...)Rounds up to the nearest integer.
FLOOR(...)Rounds down to the nearest integer.
ROUND(...)Rounds a number to a specified number of decimal places.
CONCAT(...)Concatenates strings.
HOUR_FLOOR_TIMESTAMP_MILLIS(...)Floors a timestamp (in milliseconds) to the start of the hour.

Operators

Standard comparison and logical operators are supported:
  • Arithmetic: +, -, *, /
  • Comparison: =, !=, >, <, >=, <=
  • Pattern matching: LIKE, NOT LIKE
  • Logical: AND, OR, IS, IS NOT
  • Conditionals: CASE WHEN ... THEN ... ELSE ... END

DISTINCT

Use SELECT DISTINCT to return unique rows:
SELECT DISTINCT event_name FROM events

LIMIT

You can specify a LIMIT to return fewer rows:
SELECT * FROM events
WHERE event_name = 'api_call'
LIMIT 100
The maximum is 1,000 rows per query, regardless of the LIMIT you specify.

Subqueries

You can use subqueries in the FROM clause for multi-step aggregations:
SELECT AVG(daily_count) FROM (
  SELECT COUNT(1) as daily_count
  FROM events
  WHERE event_name = 'api_call'
  GROUP BY FLOOR(timestamp_millis / 86400000)
)

Query controls

Time range

Every query is scoped to a time range. Select from preset ranges (Last 1 hour, Last 1 day, Last 7 days, Last 30 days) or specify a custom start and end date. The maximum time range is 90 days. The time range is applied as an automatic filter on timestamp_millis. You do not need to include it in your WHERE clause.

Customer filter

Optionally scope your query to a specific customer. When selected, only events attributed to that customer are included in results. This is useful for debugging a specific customer’s usage or validating that events are being attributed correctly.

Honor amendments

When you’ve amended events for a customer (e.g. deprecated incorrect events or backfilled corrected ones), the Honor amendments toggle controls whether the query reflects those changes. When enabled:
  • Deprecated events are excluded from results.
  • Backfilled events are included.
This requires a customer to be selected, since amendments are scoped to individual customers. When disabled (the default), the query returns all raw events as originally ingested.

Builder mode

If you prefer a visual interface, switch to Builder mode using the toggle at the top of the editor. The builder lets you construct queries without writing SQL:
  • Columns: Choose which columns to include in results.
  • Filters: Add conditions with a column, operator, and value.
  • Aggregation: Select an aggregation function (COUNT, SUM, AVG, MIN, MAX) and the column to aggregate.
  • Group by: Choose columns to group results by.
  • Time bucket: Bucket results by minute, hour, or day to spot trends.
  • Limit: Set the maximum number of rows.
The builder generates a SQL preview that updates as you configure the query, so you can see exactly what will be executed. You can switch to SQL mode at any time to refine the generated query further.

Results

Query results are displayed in a table below the editor. The status bar shows:
  • Row count: How many rows were returned.
  • Query time: How long the query took to execute.
  • Truncated indicator: Whether results were capped at the limit.
You can click any cell to copy its value to your clipboard.

Datetime display

The timestamp_millis column and other datetime values are displayed as human-readable timestamps by default. Toggle the raw display mode to see the original epoch millisecond values.

CSV export

Click the Download CSV button to export the current results. The CSV includes column headers and properly escapes values containing commas, quotes, or newlines.

Examples

Count events by name over the last 7 days
SELECT event_name, COUNT(1)
FROM events
GROUP BY event_name
Total transaction volume by payment method
SELECT payment_method, SUM(amount_cents) as total_cents, COUNT(1) as num_transactions
FROM events
WHERE event_name = 'transaction_processed'
GROUP BY payment_method
Hourly API call volume
SELECT
  HOUR_FLOOR_TIMESTAMP_MILLIS(timestamp_millis) as hour,
  COUNT(1) as call_count
FROM events
WHERE event_name = 'api_call'
GROUP BY HOUR_FLOOR_TIMESTAMP_MILLIS(timestamp_millis)
Distinct customers who used a feature
SELECT COUNT(DISTINCT customer_id)
FROM events
WHERE event_name = 'feature_used'
AND feature_name = 'advanced_search'
Average compute time, excluding the longest job
SELECT (SUM(compute_ms) - MAX(compute_ms)) / (COUNT(compute_ms) - 1)
FROM events
WHERE event_name = 'job_completed'
Most recent event per customer
SELECT customer_id, LATEST_BY(event_name, timestamp_millis) as last_event
FROM events
GROUP BY customer_id

Limits

  • Results are capped at 1,000 rows per query.
  • Time range cannot exceed 90 days.
  • ORDER BY is not supported. Use aggregations and GROUP BY to organize results.
  • JOIN, WITH (CTEs), and LATERAL are not supported. Queries can only access the events table.
  • WHERE clauses cannot contain aggregation functions. Use subqueries for post-aggregation filtering.