Skip to main content
POST
/
api
/
i
/
v1
/
{publicKey}
/
events
Ingest Events
curl --request POST \
  --url https://api.example.com/api/i/v1/{publicKey}/events \
  --header 'Content-Type: application/json' \
  --data '
{
  "visitorId": "<string>",
  "source": "<string>",
  "events": [
    {}
  ],
  "userIdentity": {},
  "customerIdentity": {},
  "type": "<string>",
  "title": "<string>",
  "eventName": "<string>",
  "properties": {},
  "formId": "<string>",
  "formFields": {},
  "email": "<string>",
  "userId": "<string>",
  "traits": {},
  "customerId": "<string>",
  "customerTraits": {},
  "activeTimeMs": 123,
  "totalTimeMs": 123,
  "sessionId": "<string>",
  "provider": "<string>",
  "eventType": "<string>",
  "startTime": "<string>",
  "endTime": "<string>",
  "duration": 123,
  "isRecurring": true,
  "inviteeEmail": "<string>",
  "inviteeName": "<string>",
  "stage": "<string>",
  "status": "<string>",
  "stripeCustomerId": "<string>"
}
'
{
  "success": true,
  "processed": 123,
  "errors": [
    {}
  ]
}

Endpoint

POST https://app.outlit.ai/api/i/v1/{publicKey}/events

Path Parameters

publicKey
string
required
Your organization’s public key. Starts with pk_.

Request Body

{
  "visitorId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "source": "client",
  "events": [
    {
      "type": "pageview",
      "url": "https://example.com/pricing",
      "path": "/pricing",
      "title": "Pricing - Example",
      "referrer": "https://google.com",
      "timestamp": 1699999999999
    }
  ]
}

Body Parameters

visitorId
string
Unique identifier for the visitor (UUID format). Required for browser (client) tracking. For server-side tracking (server source), this can be omitted; identity or attribution is derived from email, userId, fingerprint, customerId, or billing identifiers in the events.
source
string
default:"client"
Event source. One of: client (browser), server, integration.
events
array
required
Array of event objects to ingest (max 100 per request).
userIdentity
object
Optional user identity for immediate resolution. Used by browser SDK when user is logged in (via setUser()). Allows direct identity resolution instead of anonymous visitor flow.
PropertyTypeDescription
emailstringUser’s email address
userIdstringYour system-owned user/contact ID
traitsobjectUser/contact traits
customerIdentity
object
Optional customer/account attribution for the whole batch. Used by browser SDK when the current user carries account/workspace context.
PropertyTypeDescription
customerIdstringYour system-owned customer/account/workspace ID
customerTraitsobjectCustomer/account traits

Event Types

All events share these common fields:
FieldTypeRequiredDescription
typestringYesEvent type (see below)
timestampnumberNoUnix timestamp in milliseconds. Defaults to server time.
urlstringYesFull page URL
pathstringYesURL path (e.g., /pricing)
referrerstringNoReferrer URL
utmobjectNoUTM parameters (see below)

UTM Parameters

{
  "utm": {
    "source": "google",
    "medium": "cpc",
    "campaign": "spring_2024",
    "term": "pricing software",
    "content": "header_cta"
  }
}

Pageview Event

Track a page view.
{
  "type": "pageview",
  "url": "https://example.com/pricing?plan=pro",
  "path": "/pricing",
  "title": "Pricing - Example",
  "referrer": "https://google.com/search?q=example",
  "utm": {
    "source": "google",
    "medium": "cpc",
    "campaign": "spring_2024"
  },
  "timestamp": 1699999999999
}
type
string
required
Must be "pageview".
title
string
Page title.

Custom Event

Track any custom event.
{
  "type": "custom",
  "url": "https://example.com/pricing",
  "path": "/pricing",
  "eventName": "button_clicked",
  "properties": {
    "buttonId": "cta-hero",
    "page": "/pricing",
    "variant": "A"
  },
  "timestamp": 1699999999999
}
type
string
required
Must be "custom".
eventName
string
required
Name of the custom event.
properties
object
Key-value pairs of event properties. Values can be string, number, boolean, or null.

Form Event

Track a form submission.
{
  "type": "form",
  "url": "https://example.com/contact",
  "path": "/contact",
  "formId": "contact-form",
  "formFields": {
    "email": "jane@example.com",
    "name": "Jane Doe",
    "company": "Acme Inc",
    "message": "I'd like to learn more..."
  },
  "timestamp": 1699999999999
}
type
string
required
Must be "form".
formId
string
Identifier for the form (ID attribute or name).
formFields
object
Key-value pairs of form field values.
Sensitive fields (password, credit_card, ssn, etc.) are automatically stripped on the server. Don’t send them.

Identify Event

Identify the visitor with their email/userId.
{
  "type": "identify",
  "url": "https://example.com/signup",
  "path": "/signup",
  "email": "jane@example.com",
  "userId": "usr_12345",
  "customerId": "cust_123",
  "traits": {
    "name": "Jane Doe",
    "company": "Acme Inc",
    "plan": "enterprise",
    "role": "admin"
  },
  "customerTraits": {
    "plan": "enterprise",
    "seats": 50
  },
  "timestamp": 1699999999999
}
type
string
required
Must be "identify".
email
string
User’s email address. At least one of email or userId required.
userId
string
Your system-owned user/contact ID.
traits
object
Properties to set on the user profile.
customerId
string
Your system-owned customer/account/workspace ID. Send it with an identify event when you want that external account/workspace to link to the contact resolved from email or userId.
customerTraits
object
Properties to set on the customer profile.

Engagement Event

Track active time on a page. Automatically sent by the browser SDK.
{
  "type": "engagement",
  "url": "https://example.com/features",
  "path": "/features",
  "activeTimeMs": 45000,
  "totalTimeMs": 60000,
  "sessionId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "timestamp": 1699999999999
}
type
string
required
Must be "engagement".
activeTimeMs
number
required
Time in milliseconds the user was actively engaged (visible tab + user interactions).
totalTimeMs
number
required
Total wall-clock time in milliseconds on the page.
sessionId
string
required
Session ID (UUID) for grouping engagement events. Resets after 30 min of inactivity or tab close.

Calendar Event

Track calendar booking from embedded widgets (Cal.com, Calendly).
{
  "type": "calendar",
  "url": "https://example.com/demo",
  "path": "/demo",
  "provider": "cal.com",
  "eventType": "30 Minute Demo",
  "startTime": "2024-03-15T10:00:00Z",
  "endTime": "2024-03-15T10:30:00Z",
  "duration": 30,
  "isRecurring": false,
  "timestamp": 1699999999999
}
type
string
required
Must be "calendar".
provider
string
required
Calendar provider: "cal.com", "calendly", or "unknown".
eventType
string
Meeting type name (e.g., “30 Minute Demo”).
startTime
string
Scheduled start time (ISO 8601 format).
endTime
string
Scheduled end time (ISO 8601 format).
duration
number
Duration in minutes.
isRecurring
boolean
Whether this is a recurring meeting.
inviteeEmail
string
Invitee’s email (only available via server-side webhooks).
inviteeName
string
Invitee’s name (only available via server-side webhooks).

Stage Event

Track contact journey stage transitions. Use this to mark users as activated, engaged, or inactive.
{
  "type": "stage",
  "url": "https://example.com/onboarding",
  "path": "/onboarding",
  "stage": "activated",
  "properties": {
    "flow": "onboarding",
    "step": "completed"
  },
  "timestamp": 1699999999999
}
type
string
required
Must be "stage".
stage
string
required
The journey stage. One of: "activated", "engaged", "inactive".
properties
object
Additional context for the stage transition.
The discovered and signed_up stages are automatically inferred from identify events. Only use stage events for explicit milestone tracking.

Billing Event

Track account billing status for custom billing systems. If Stripe is connected, billing status is handled automatically.
{
  "type": "billing",
  "url": "server://cust_123",
  "path": "/",
  "status": "paid",
  "customerId": "cust_123",
  "properties": {
    "plan": "pro",
    "amount": 99
  },
  "timestamp": 1699999999999
}
type
string
required
Must be "billing".
status
string
required
The billing status. One of: "trialing", "paid", "churned".
customerId
string
Your system-owned customer/account/workspace ID. Public billing calls should use this identifier.
stripeCustomerId
string
Stripe customer identifier. Prefer customerId unless you are sending compatibility events that already use Stripe IDs.
properties
object
Additional billing context such as plan, amount, or cancellation reason.
Billing events require customerId or stripeCustomerId. They target the account, not an individual contact.

Response

Success Response

{
  "success": true,
  "processed": 3
}
success
boolean
Whether the request was successful.
processed
number
Number of events successfully processed.
errors
array
Array of processing errors (only present if some events failed).

Partial Success Response (HTTP 207)

When some events succeed and others fail:
{
  "success": false,
  "processed": 2,
  "errors": [
    {
      "index": 2,
      "message": "Invalid event type"
    }
  ]
}

Error Response

{
  "success": false,
  "processed": 0,
  "errors": [
    {
      "index": -1,
      "message": "Invalid or inactive tracking configuration"
    }
  ]
}

Examples

cURL - Browser Events

curl -X POST "https://app.outlit.ai/api/i/v1/pk_your_key/events" \
  -H "Content-Type: application/json" \
  -d '{
    "visitorId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "source": "client",
    "events": [
      {
        "type": "pageview",
        "url": "https://example.com/pricing",
        "path": "/pricing",
        "title": "Pricing",
        "timestamp": 1699999999999
      }
    ]
  }'

cURL - Server Events

curl -X POST "https://app.outlit.ai/api/i/v1/pk_your_key/events" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "server",
    "events": [
      {
        "type": "identify",
        "url": "server://jane@acme.com",
        "path": "/",
        "email": "jane@acme.com",
        "userId": "usr_123",
        "customerId": "cust_123",
        "traits": {
          "name": "Jane Doe",
          "plan": "pro"
        },
        "customerTraits": {
          "plan": "pro"
        }
      },
      {
        "type": "custom",
        "url": "server://jane@acme.com",
        "path": "/",
        "eventName": "subscription_created",
        "email": "jane@acme.com",
        "userId": "usr_123",
        "customerId": "cust_123",
        "properties": {
          "plan": "pro",
          "amount": 99
        }
      }
    ]
  }'

JavaScript (fetch)

const response = await fetch(
  'https://app.outlit.ai/api/i/v1/pk_your_key/events',
  {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      visitorId: 'visitor-123',
      source: 'client',
      events: [
        {
          type: 'pageview',
          url: window.location.href,
          path: window.location.pathname,
          title: document.title,
          timestamp: Date.now()
        }
      ]
    })
  }
)

const result = await response.json()
console.log(result)

Python

import requests
import time

response = requests.post(
    'https://app.outlit.ai/api/i/v1/pk_your_key/events',
    json={
        'source': 'server',
        'events': [
            {
                'type': 'identify',
                'url': 'server://jane@example.com',
                'path': '/',
                'email': 'jane@example.com',
                'customerId': 'cust_123',
                'traits': {'name': 'Jane Doe'},
                'customerTraits': {'plan': 'enterprise'},
                'timestamp': int(time.time() * 1000)
            }
        ]
    }
)

print(response.json())

Server-Side Events

For server-side tracking, the visitorId field can be omitted. Identity is resolved from the event data, including customer-only attribution when customerId is provided:
  • Identify events: Use email and/or userId fields, plus optional customer context
  • Custom events: Include top-level email, userId, fingerprint, and/or customerId fields
  • Billing events: Include customerId or stripeCustomerId
{
  "source": "server",
  "events": [
    {
      "type": "custom",
      "url": "server://user@example.com",
      "path": "/",
      "eventName": "payment_received",
      "email": "user@example.com",
      "userId": "usr_123",
      "customerId": "cust_123",
      "properties": {
        "amount": 99,
        "currency": "USD"
      }
    }
  ]
}
Server events require identity or account attribution. Custom events need at least one of email, userId, fingerprint, or customerId; identify events need email or userId; billing events need customerId or stripeCustomerId.

Batching Best Practices

For high-volume tracking:
  1. Batch events - Send multiple events per request (up to 100)
  2. Use background queue - Don’t block user actions
  3. Retry with backoff - Handle temporary failures
  4. Flush on shutdown - Send remaining events before exit
// Example batching implementation
const eventQueue = []
const FLUSH_INTERVAL = 5000
const MAX_BATCH_SIZE = 100

function track(event) {
  eventQueue.push({ ...event, timestamp: Date.now() })
  
  if (eventQueue.length >= MAX_BATCH_SIZE) {
    flush()
  }
}

async function flush() {
  if (eventQueue.length === 0) return
  
  const events = eventQueue.splice(0, MAX_BATCH_SIZE)
  
  try {
    await fetch('/api/i/v1/pk_xxx/events', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        visitorId: getVisitorId(),
        source: 'client',
        events
      })
    })
  } catch (error) {
    // Re-queue failed events
    eventQueue.unshift(...events)
  }
}

setInterval(flush, FLUSH_INTERVAL)
window.addEventListener('beforeunload', flush)