Back to Documentation
api

Event-ingestion

API endpoint for receiving batched events from the SDK EventTracker.

Endpoint

POST /api/tracking/events/batch

Authentication

Header: X-API-Key: sk_live_...

Request

Headers

X-API-Key: sk_live_your-api-key
Content-Type: application/json

Body

{
  "events": [
    {
      "eventName": "page_viewed",
      "properties": {
        "page": "/dashboard"
      },
      "timestamp": "2025-01-25T10:30:00Z",
      "sessionId": "sess_abc123",
      "userId": "user_123",
      "accountId": "acct_456",
      "context": {
        "url": "https://example.com/dashboard",
        "pathname": "/dashboard",
        "userAgent": "Mozilla/5.0...",
        "screenWidth": 1920,
        "screenHeight": 1080
      }
    }
  ],
  "vendorId": "vendor-uuid",
  "batchId": "batch_1234567890_xyz"
}

Event structure

{
  eventName: string; // Required, non-empty
  properties?: object; // Optional, defaults to {}
  timestamp: string; // Required, ISO 8601 format
  sessionId: string; // Required, non-empty
  userId?: string | null; // Optional
  accountId?: string | null; // Optional
  context?: {
    url: string;
    pathname: string;
    referrer?: string;
    userAgent: string;
    screenWidth: number;
    screenHeight: number;
    timestamp: string;
  };
}

Response

Success

{
  "success": true,
  "batchId": "batch_1234567890_xyz",
  "processed": 20,
  "failed": 0,
  "results": [
    {
      "index": 0,
      "success": true,
      "eventId": "550e8400-e29b-41d4-a716-446655440000"
    },
    {
      "index": 1,
      "success": true,
      "eventId": "660e8400-e29b-41d4-a716-446655440001"
    }
  ]
}

Partial failure

{
  "success": true,
  "batchId": "batch_1234567890_xyz",
  "processed": 18,
  "failed": 2,
  "results": [
    {
      "index": 0,
      "success": true,
      "eventId": "550e8400-e29b-41d4-a716-446655440000"
    },
    {
      "index": 1,
      "success": false,
      "error": "Invalid timestamp format"
    }
  ]
}

Error responses

400 bad request

Empty events array:

{
  "success": false,
  "error": "Invalid request body",
  "batchId": "unknown",
  "processed": 0,
  "failed": 0,
  "results": []
}

Large batch (>100 events):

{
  "success": false,
  "error": "Batch size exceeds maximum (100 events)",
  "batchId": "batch_123...",
  "processed": 0,
  "failed": 101,
  "results": []
}

Invalid event structure:

{
  "success": false,
  "error": "Invalid request body",
  "details": [
    {
      "path": "events.0.timestamp",
      "message": "Required"
    }
  ],
  "batchId": "batch_123...",
  "processed": 0,
  "failed": 1,
  "results": []
}

401 unauthorized

{
  "error": "Invalid API key",
  "valid": false
}

403 forbidden

{
  "success": false,
  "error": "Vendor ID mismatch",
  "batchId": "batch_123...",
  "processed": 0,
  "failed": 1,
  "results": []
}

429 too many requests

{
  "error": "Rate limit exceeded"
}

Rate limiting

  • Limit: 100 batches per minute per API key
  • Window: 1 minute rolling window
  • Response: 429 Too Many Requests

Cors

The API supports CORS for cross-origin SDK requests:

  • Allowed Origins: *
  • Allowed Methods: POST, OPTIONS
  • Allowed Headers: Content-Type, X-API-Key

Batch processing

Events are processed in batches:

  • Maximum batch size: 100 events
  • Recommended batch size: 20 events (SDK default)
  • Partial failures: Some events may succeed while others fail
  • Per-event status: Response includes success/failure for each event

Database storage

Events are stored in the product_events table:

  • Table: product_events
  • Indexes: vendor_id, account_id, user_id, event_name
  • Retention: Indefinite (for health scoring)

Sdk integration

The SDK EventTracker automatically:

  1. Queues events (up to 20 per batch)
  2. Flushes batches every 5 seconds
  3. Flushes on page unload using sendBeacon()
  4. Retries failed requests (max 3 retries)

You don't need to call this API directly - the SDK handles it!

Examples

Sdk usage

// SDK automatically batches and sends events
firstDistro.track('page_viewed', { page: '/dashboard' });
firstDistro.track('feature_used', { feature: 'export' });
// ... 18 more events
// → Automatically sends batch of 20 events

Manual api call

const response = await fetch('https://firstdistro.com/api/tracking/events/batch', {
  method: 'POST',
  headers: {
    'X-API-Key': 'sk_live_your-api-key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    events: [
      {
        eventName: 'custom_event',
        properties: { custom: 'data' },
        timestamp: new Date().toISOString(),
        sessionId: 'sess_123',
        userId: 'user_123',
        accountId: 'acct_456',
        context: {
          url: window.location.href,
          pathname: window.location.pathname,
          userAgent: navigator.userAgent,
          screenWidth: window.screen.width,
          screenHeight: window.screen.height,
          timestamp: new Date().toISOString()
        }
      }
    ],
    vendorId: 'your-vendor-id',
    batchId: `batch_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
  })
});

const data = await response.json();
console.log(`Processed: ${data.processed}, Failed: ${data.failed}`);

See also