Core APIsEvents

Events API

Track user behavior and actions with the Flameup Events API

Overview

The Events API allows you to track user actions and behaviors in your application. Events power analytics, trigger campaigns, and help you understand how users interact with your product.

Permissions: writes (/track, /track/batch) need events:write; reads (/people/{external_id}/events, /events/search) need events:read. /identify is a people write — see that section.

Event Object

An event in Flameup has the following structure:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "type": "purchase_completed",
  "parameters": {
    "order_id": "order_789",
    "amount": 99.99,
    "currency": "USD",
    "items": ["product_a", "product_b"]
  },
  "created_at": "2024-01-15T10:30:01Z"
}

Field Reference

These are the fields accepted in a track request body:

FieldTypeRequiredDescription
eventstringYesName of the event (e.g., "signup", "purchase")
external_idstringYesYour identifier for the user. Also accepted as userId or user_id
parametersobjectNoAdditional data about the event. Also accepted as properties
timestamptimestampNoWhen the event occurred (defaults to now)

Identify a Person

Create or update one person and their traits. This is the other half of ingestion: /identify says who someone is, /track says what they did.

Endpoint: POST /api/v1/identify

FieldTypeRequiredDescription
userIdstringYesYour own user id. external_id and user_id are accepted aliases
emailstringNo
phonestringNo
anonymousIdstringNoAn anonymous id whose earlier events should belong to this person. Max 36 characters — a longer value rejects the whole request with 400. The merge itself runs asynchronously after the response
traitsobjectNoMerged with existing traits; new values win
timestampdatetimeNoDefaults to now
curl -X POST https://api.flameup.ai/api/v1/identify \
  -H "Authorization: Bearer {API_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{
    "userId": "user_12345",
    "email": "jane@example.com",
    "traits": { "plan": "premium", "exam": "RPSC" }
  }'

Send one identifier per request. If you send more than one of userId, external_id or user_id and they disagree, the request is rejected rather than one being chosen for you.

The 36-character anonymousId limit is checked before the person is written, so it is not a best-effort part of the async merge: an over-long value fails the entire call with 400 and "error": "Anonymous ID must be 36 characters or less" — no person is created or updated and no merge is scheduled. A bare UUID fits exactly at 36; prefixed UUIDs (anon_550e8400-…), brace-wrapped GUIDs ({…}) and SHA-1/SHA-256 hex digests all exceed it.

Permissions

people:write, or the narrower people:identify — which authorizes this route and nothing else. That narrowness is what makes it safe on a key shipped inside an app.

What comes back

{ "success": true, "person": { "id": "…", "workspace_id": "…", "userId": "user_12345" } }
The person object is trimmed to those three fields for any key without people:read. A write-scoped key cannot use identify to read a person back — send an id you do not own and you learn nothing about it.

Track an Event

Record a user action in Flameup.

Endpoint: POST /api/v1/track

The workspace is automatically determined from your API key, so you don't need to include it in the URL.
async function trackEvent(externalId, eventName, parameters = {}) {
  const response = await fetch(
    'https://api.flameup.ai/api/v1/track',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${API_KEY}`
      },
      body: JSON.stringify({
        external_id: externalId,
        event: eventName,
        parameters: parameters
      })
    }
  );

  return response.json();
}

// Track a page view
await trackEvent('user_123', 'page_viewed', {
  page: '/pricing',
  referrer: '/home'
});

// Track a purchase
await trackEvent('user_123', 'purchase_completed', {
  order_id: 'order_789',
  amount: 99.99,
  currency: 'USD',
  items: [
    { sku: 'PROD-001', name: 'Widget', quantity: 2 },
    { sku: 'PROD-002', name: 'Gadget', quantity: 1 }
  ]
});

// Track a feature usage
await trackEvent('user_123', 'feature_used', {
  feature: 'export_csv',
  duration_seconds: 45
});

Response (201 Created):

{
  "success": true,
  "data": {
    "event_id": "550e8400-e29b-41d4-a716-446655440000",
    "person_id": "550e8400-e29b-41d4-a716-446655440001",
    "event": "purchase_completed",
    "parameters": {
      "order_id": "order_789",
      "amount": 99.99,
      "currency": "USD"
    },
    "timestamp": "2024-01-15T10:30:00Z",
    "processed_at": "2024-01-15T10:30:01Z",
    "status": "processed"
  }
}

Two fields appear only when they apply:

  • person_created: true — the external_id was not a known person, so /track created a minimal one before storing the event. This is the only signal that a mistyped identifier just minted a ghost profile instead of attaching to the person you meant.
  • status: "accepted_with_warnings" with a warnings array — the event was stored durably, but a post-storage processor (workflow or campaign trigger) failed. The event exists and will read back; it may not have triggered campaigns. A storage failure is never reported this way — that is a 5xx.

Batch Track Events

Track multiple events in a single request (up to 100 events).

Endpoint: POST /api/v1/track/batch

const response = await fetch(
  'https://api.flameup.ai/api/v1/track/batch',
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${API_KEY}`
    },
    body: JSON.stringify({
      events: [
        {
          external_id: 'user_123',
          event: 'page_viewed',
          parameters: { page: '/home' }
        },
        {
          external_id: 'user_123',
          event: 'button_clicked',
          parameters: { button: 'signup' }
        },
        {
          external_id: 'user_456',
          event: 'purchase_completed',
          parameters: { amount: 99.99 }
        }
      ]
    })
  }
);

const result = await response.json();
Maximum 100 events per batch request. For larger volumes, split into multiple requests.

Response (201 Created when all events succeed):

{
  "success": true,
  "processed": 2,
  "total": 2,
  "results": [
    { "index": 0, "event_id": "550e8400-e29b-41d4-a716-446655440000", "person_id": "...", "event": "page_viewed", "status": "processed" },
    { "index": 1, "event_id": "660e8400-e29b-41d4-a716-446655440111", "person_id": "...", "event": "button_clicked", "status": "processed" }
  ]
}

If some events fail, the request returns 207 Multi-Status with an errors array and success: false. Every entry — success or failure — carries the index of the event in your submitted array, so retry the failed indexes only:

{
  "success": false,
  "processed": 1,
  "total": 2,
  "results": [
    { "index": 0, "event_id": "550e8400-e29b-41d4-a716-446655440000", "person_id": "...", "event": "page_viewed", "status": "processed" }
  ],
  "errors": [
    { "index": 1, "error": "external_id or userId is required" }
  ]
}

Get Person Events

Retrieve events for a specific person.

Endpoint: GET /api/v1/people/{external_id}/events

Query Parameters

ParameterTypeDefaultDescription
limitinteger50Number of results (max 500)
const params = new URLSearchParams({
  limit: '100'
});

const response = await fetch(
  `https://api.flameup.ai/api/v1/people/${externalId}/events?${params}`,
  {
    headers: {
      'Authorization': `Bearer ${API_KEY}`
    }
  }
);

const { events, total } = await response.json();

Search Events by Type

Find recent events of one type across the whole workspace, rather than for a single person.

Endpoint: GET /api/v1/events/search

ParameterRequiredDescription
eventYesThe event name to search for
sinceNoOnly events at or after this time (RFC 3339)
limitNoDefault 50, max 500
curl "https://api.flameup.ai/api/v1/events/search?event=purchase_completed&since=2026-01-01T00:00:00Z" \
  -H "Authorization: Bearer {API_KEY}"

Requires events:read.

Common Event Examples

Here are examples of commonly tracked events:

// User signed up
await trackEvent('user_123', 'signed_up', {
  method: 'email',           // or 'google', 'github'
  referral_code: 'FRIEND50'
});

// User logged in
await trackEvent('user_123', 'logged_in', {
  method: 'password',        // or 'sso', 'magic_link'
  device: 'mobile'
});

// User upgraded plan
await trackEvent('user_123', 'plan_upgraded', {
  from_plan: 'free',
  to_plan: 'premium',
  annual: true
});

// User churned
await trackEvent('user_123', 'subscription_cancelled', {
  reason: 'too_expensive',
  feedback: 'Great product but over budget'
});

Event Naming Conventions

Use consistent event naming for easier analysis and campaign targeting.

Use object_action format with snake_case:

GoodAvoid
user_signed_upUserSignedUp, user-signed-up
purchase_completedPurchase, bought
feature_usedFeatureUsed, used_feature
email_openedOpenedEmail, open

Standard Events

These events are recognized by Flameup for analytics:

EventDescription
signed_upUser created an account
logged_inUser authenticated
logged_outUser ended session
purchase_completedUser made a purchase
subscription_startedUser started a subscription
subscription_cancelledUser cancelled subscription

Using Events for Campaigns

Events can trigger automated campaigns. When setting up a campaign:

  1. Event-based triggers: Start a campaign when a specific event occurs
  2. Event conditions: Target users who have (or haven't) performed certain events
  3. Event parameters: Use event parameters for personalization

Example campaign triggers:

# Welcome series
Trigger: signed_up

# Abandoned cart
Trigger: cart_updated
Condition: NOT purchase_completed within 24 hours

# Re-engagement
Trigger: None
Condition: NOT logged_in within 30 days

# Upsell
Trigger: feature_limit_reached
Condition: plan = 'free'

Best Practices

Focus on events that indicate user intent or value:

  • Conversion events (signup, purchase, upgrade)
  • Feature engagement
  • Key user milestones

Avoid tracking every click or page view unless needed for specific analysis.

Data Storage

Events are stored in ClickHouse for high-performance analytics queries. Event data is retained according to your plan's data retention policy.

Events are optimized for:

  • Fast writes (track millions of events)
  • Efficient time-range queries
  • Aggregations and analytics
  • Real-time campaign triggering