Skip to main content

Analytics API

The Analytics API provides access to metrics and reporting data using a flexible DSL (Domain Specific Language) for querying.

Query Analytics

Execute an analytics query using the metrics DSL. POST /api/v1/analytics/query

Authentication

  • Secret key required

Request Body

interface QueryRequest {
  measures: Measure[];
  timeRange: string; // e.g., "7d", "30d", "90d"
  granularity?: "hour" | "day" | "week" | "month";
  filters?: Filter[];
  groupBy?: string[];
}

interface Measure {
  name: string; // Unique name for this measure
  event: string; // Event type to measure
  op: "count" | "sum" | "avg" | "min" | "max";
  field?: string; // Field for sum/avg operations
  unit?: "number" | "currency";
  filters?: Filter[];
}

interface Filter {
  field: string;
  operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "contains";
  value: string | number | string[];
}

Supported Events

EventDescription
queue_entryConsumer entered a queue
queue_admitConsumer admitted from queue
queue_exitConsumer left queue
draw_entryConsumer entered a draw
draw_winConsumer won a draw
auction_bidBid placed on auction
auction_winAuction won
order_createdOrder was created
order_completedOrder was completed

Supported Fields for Aggregation

EventFields
order_createdorderValue, itemCount
order_completedorderValue, itemCount
auction_bidbidAmount
auction_winwinningBid

Response

interface QueryResponse {
  measures: MeasureResult[];
  timeRange: {
    start: string;
    end: string;
  };
  currencyCode: string;
}

interface MeasureResult {
  name: string;
  value: number;
  unit: "number" | "currency";
  series?: SeriesPoint[];
}

interface SeriesPoint {
  timestamp: string;
  value: number;
}

Example: Basic Query

Query queue entries and admissions for the last 7 days:
curl -X POST https://admin.fanfare.io/api/v1/analytics/query \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "measures": [
      {
        "name": "total_queue_entries",
        "event": "queue_entry",
        "op": "count"
      },
      {
        "name": "total_admissions",
        "event": "queue_admit",
        "op": "count"
      }
    ],
    "timeRange": "7d"
  }'
Response:
{
  "measures": [
    {
      "name": "total_queue_entries",
      "value": 15420,
      "unit": "number"
    },
    {
      "name": "total_admissions",
      "value": 12850,
      "unit": "number"
    }
  ],
  "timeRange": {
    "start": "2024-11-24T00:00:00Z",
    "end": "2024-12-01T00:00:00Z"
  },
  "currencyCode": "USD"
}

Example: Time Series Query

Query order revenue by day:
curl -X POST https://admin.fanfare.io/api/v1/analytics/query \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "measures": [
      {
        "name": "daily_revenue",
        "event": "order_completed",
        "op": "sum",
        "field": "orderValue",
        "unit": "currency"
      }
    ],
    "timeRange": "30d",
    "granularity": "day"
  }'
Response:
{
  "measures": [
    {
      "name": "daily_revenue",
      "value": 125000.0,
      "unit": "currency",
      "series": [
        { "timestamp": "2024-11-01T00:00:00Z", "value": 4250.0 },
        { "timestamp": "2024-11-02T00:00:00Z", "value": 3800.0 },
        { "timestamp": "2024-11-03T00:00:00Z", "value": 5100.0 }
      ]
    }
  ],
  "timeRange": {
    "start": "2024-11-01T00:00:00Z",
    "end": "2024-12-01T00:00:00Z"
  },
  "currencyCode": "USD"
}

Example: Filtered Query

Query queue entries for a specific experience:
curl -X POST https://admin.fanfare.io/api/v1/analytics/query \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "measures": [
      {
        "name": "experience_entries",
        "event": "queue_entry",
        "op": "count",
        "filters": [
          {
            "field": "experienceId",
            "operator": "eq",
            "value": "exp_01HXYZ123456789"
          }
        ]
      }
    ],
    "timeRange": "7d"
  }'

Example: Multiple Measures

Query conversion funnel metrics:
curl -X POST https://admin.fanfare.io/api/v1/analytics/query \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "measures": [
      {
        "name": "queue_entries",
        "event": "queue_entry",
        "op": "count"
      },
      {
        "name": "admissions",
        "event": "queue_admit",
        "op": "count"
      },
      {
        "name": "orders",
        "event": "order_created",
        "op": "count"
      },
      {
        "name": "revenue",
        "event": "order_completed",
        "op": "sum",
        "field": "orderValue",
        "unit": "currency"
      },
      {
        "name": "avg_order_value",
        "event": "order_completed",
        "op": "avg",
        "field": "orderValue",
        "unit": "currency"
      }
    ],
    "timeRange": "30d"
  }'

Guardrails

The analytics API enforces the following limits:
LimitValue
Maximum measures per query10
Maximum time range90 days
Rate limit100 queries per minute

Error Responses

StatusErrorDescription
400Too many measures (max 10)Exceeded measure limit
400Requested timeRange exceeds the allowed maximum (90d)Time range too large
400Event 'xxx' is not supportedInvalid event type
400Measure 'xxx' requires a field when using 'sum'Missing field for aggregation
400Field 'xxx' is not allowed for event 'yyy'Invalid field for event
401UnauthorizedMissing or invalid authentication
404Organization not foundInvalid organization

SDK Usage

import { FanfareAdmin } from "@fanfare/admin-sdk";

const admin = new FanfareAdmin({
  secretKey: process.env.FANFARE_SECRET_KEY,
});

// Basic query
const result = await admin.analytics.query({
  measures: [
    { name: "total_entries", event: "queue_entry", op: "count" },
    { name: "total_revenue", event: "order_completed", op: "sum", field: "orderValue", unit: "currency" },
  ],
  timeRange: "30d",
});

console.log(`Total Entries: ${result.measures[0].value}`);
console.log(`Total Revenue: ${result.measures[1].value} ${result.currencyCode}`);

// Time series query
const timeSeries = await admin.analytics.query({
  measures: [{ name: "daily_entries", event: "queue_entry", op: "count" }],
  timeRange: "7d",
  granularity: "day",
});

// Access series data
timeSeries.measures[0].series?.forEach((point) => {
  console.log(`${point.timestamp}: ${point.value}`);
});

Common Use Cases

Conversion Rate

const result = await admin.analytics.query({
  measures: [
    { name: "entries", event: "queue_entry", op: "count" },
    { name: "orders", event: "order_created", op: "count" },
  ],
  timeRange: "30d",
});

const conversionRate = (result.measures[1].value / result.measures[0].value) * 100;
console.log(`Conversion Rate: ${conversionRate.toFixed(2)}%`);

Daily Active Users

const result = await admin.analytics.query({
  measures: [{ name: "daily_users", event: "queue_entry", op: "count" }],
  timeRange: "30d",
  granularity: "day",
});

Revenue by Day

const result = await admin.analytics.query({
  measures: [{ name: "revenue", event: "order_completed", op: "sum", field: "orderValue", unit: "currency" }],
  timeRange: "30d",
  granularity: "day",
});