Skip to main content
Who this is for: Backend developers and integrators sending server-side events. Mobile/web app actions should use an SDK instead.
Complete reference for all Zixflow event ingress API endpoints — what each one does, when to use it, how to authenticate, and what to send. For Mintlify API playground pages (request/response fields), see the Events API Reference under Zixflow AI.

API vs SDK: When to Use Which

Zixflow exposes two surfaces for sending data: the client/server SDKs and the HTTP API.
SDKsHTTP API
Who uses itWeb and mobile apps (JavaScript, Flutter, React Native, iOS, Android, Node.js)Backend servers, scripts, integrations
AuthAPI key in SDK initializationAuthorization: Basic base64(api_key:)
BatchingAutomatic (typically ~20 events or ~30s)Manual (you control when to call /batch)
Offline supportBuilt-in queue + retry on mobile/web SDKsYour responsibility
When to useUser-facing app actionsServer-side events (order shipped, subscription renewed), user lifecycle management (delete, suppress), device registration from backend
Rule of thumb: If the event happens because a user tapped something in your app, use an SDK. If the event happens on your server (fulfillment, billing, fraud detection), use the API directly.

Authentication

Both API groups use the same scheme:
Authorization: Basic <base64(api_key:)>
The API key goes in the username field of HTTP Basic Auth. The password is always empty — note the trailing colon before base64 encoding. Example:
# API key: ws_abc123
echo -n "ws_abc123:" | base64
# → d3NfYWJjMTIzOg==

curl -X POST https://api-events.zixflow.com/v1/track \
  -H "Authorization: Basic d3NfYWJjMTIzOg==" \
  -H "Content-Type: application/json" \
  -d '{"userId": "user_123", "event": "Button Clicked"}'
Getting your API key: Dashboard → Workspace Settings → API Keys Auth error responses:
HTTP StatusReason
401 UnauthorizedMissing, invalid, or unrecognised API key
503 Service UnavailableAuth cache (Redis) temporarily unavailable

Two API Groups

The service exposes two distinct API groups, each serving a different use case:
GroupBase pathUsed byTraffic
Data Pipelines API/v1/Mobile/web SDKs, server-to-server event tracking~98%
Track API v1/api/v1/customers/Backend servers for user/device lifecycle management~2%

Data Pipelines API (/v1/)

These endpoints accept event data in Segment-compatible format. All endpoints under /v1/ share the same auth middleware and rate limiter. All requests accept: Content-Type: application/json
All success responses: HTTP 200 with empty body {}

POST /v1/identify (alias: /v1/i)

Purpose: Create or update a user profile. Call this when a user signs up, logs in, or when you want to update their attributes. When to use:
  • User signs up or logs in → call identify with their userId and traits
  • User updates their profile (name, email, plan) → call identify with updated traits
  • Merging anonymous pre-signup activity → call identify with both userId and anonymousId
Request body:
{
  "userId": "user_12345",
  "anonymousId": "anon_abc-123",
  "traits": {
    "email": "sarah@example.com",
    "name": "Sarah Johnson",
    "plan": "enterprise",
    "company": "Acme Corp"
  },
  "timestamp": "2026-05-04T10:00:00.000Z",
  "messageId": "msg_unique_id",
  "context": {
    "ip": "203.0.113.1"
  }
}
Fields:
FieldTypeRequiredDescription
userIdstringYes*Your application’s stable identifier for this user
anonymousIdstringYes*Anonymous ID from SDK (required if no userId)
traitsobjectNoKey-value user attributes to set/update
timestampISO 8601NoWhen the identify happened (defaults to server time)
messageIdstringNoDeduplication ID (SDK generates this automatically)
contextobjectNoDevice/platform context (SDK populates this automatically)
*At least one of userId or anonymousId is required. Providing both triggers identity merge. What happens:
  1. If userId is new → creates a new user profile
  2. If userId exists → merges traits with existing profile (additive, not replace)
  3. If both userId + anonymousId provided → links all anonymous events to the identified profile

POST /v1/track (alias: /v1/t)

Purpose: Record a user action or business event. The most commonly used endpoint for custom event tracking. When to use:
  • Any user action: button tapped, purchase completed, feature used
  • Business events from your server: subscription renewed, payment failed
  • Device lifecycle: Application Installed, Application Opened (SDK sends these automatically)
Request body:
{
  "userId": "user_12345",
  "event": "Order Completed",
  "properties": {
    "order_id": "ord_789",
    "revenue": 129.99,
    "currency": "USD",
    "product_name": "Nike Air Max 90"
  },
  "timestamp": "2026-05-04T14:32:15.000Z"
}
Fields:
FieldTypeRequiredDescription
userIdstringYes*Identified user ID
anonymousIdstringYes*Anonymous user ID (if user not identified)
eventstringYesName of the event (e.g. "Order Completed")
propertiesobjectNoEvent-specific data
timestampISO 8601NoWhen the event occurred
*At least one of userId or anonymousId is required. Semantic events — certain event names trigger special handling beyond the standard event pipeline:
Event nameSpecial behavior
Device Created or UpdatedRoutes to device registration pipeline
Device DeletedSoft-deletes device record (sets active=false)
Device RegisteredRoutes to device logs table
Device UpdatedRoutes to device logs table
User DeletedSets is_deleted=true on profile, deactivates all devices
User SuppressedSets is_suppressed=true, blocks all channel delivery
User UnsuppressedClears suppression flag
Application InstalledRoutes to device logs table
Application OpenedRoutes to device logs table
Application BackgroundedRoutes to device logs table
Application ForegroundedRoutes to device logs table
Application CrashedRoutes to device logs table

POST /v1/screen (alias: /v1/s)

Purpose: Record a mobile screen view. Used by the Flutter SDK automatically when autoTrackScreenViews: true is configured, or manually when you want to attach screen-specific properties. When to use:
  • Mobile apps to track navigation flow
  • Attribute screen-level data (product ID, category) to the view event
Request body:
{
  "userId": "user_12345",
  "name": "Product Detail",
  "properties": {
    "product_id": "prod_789",
    "category": "Footwear",
    "price": 129.99
  }
}
Fields:
FieldTypeRequiredDescription
userIdstringYes*Identified user ID
anonymousIdstringYes*Anonymous user ID
namestringNoScreen name (e.g. "Product Detail")
categorystringNoScreen category
propertiesobjectNoScreen-specific properties

POST /v1/page (alias: /v1/p)

Purpose: Record a web page view. Equivalent to /v1/screen but for web apps. When to use:
  • Web apps and marketing sites
  • Track specific page metadata (title, URL, referrer)
Request body:
{
  "userId": "user_12345",
  "name": "Pricing",
  "properties": {
    "path": "/pricing",
    "url": "https://app.example.com/pricing",
    "referrer": "https://google.com",
    "title": "Pricing — Example"
  }
}
Fields:
FieldTypeRequiredDescription
userIdstringYes*Identified user ID
anonymousIdstringYes*Anonymous user ID
namestringNoPage name
propertiesobjectNoPage metadata (path, url, referrer, title)

POST /v1/batch (alias: /v1/b)

Purpose: Send multiple events in a single HTTP request. This is what the Flutter SDK uses under the hood — the SDK queues events locally and sends them as a batch every 30 seconds or after 20 events accumulate. When to use:
  • The SDK handles this for you automatically
  • If calling the API directly from a server and you have multiple events to send, prefer /batch over individual calls to reduce latency and network overhead
Request body:
{
  "batch": [
    {
      "type": "identify",
      "userId": "user_12345",
      "traits": { "plan": "enterprise" }
    },
    {
      "type": "track",
      "userId": "user_12345",
      "event": "Plan Upgraded",
      "properties": { "from_plan": "pro", "to_plan": "enterprise" }
    },
    {
      "type": "screen",
      "userId": "user_12345",
      "name": "Home"
    }
  ],
  "sentAt": "2026-05-04T10:00:30.000Z"
}
Batch item type values:
TypeEquivalent endpointNotes
identify/v1/identifytraits field
track/v1/trackevent + properties fields
screen/v1/screenname + properties fields
page/v1/pagename + properties fields
Group and Alias are not supported. Do not send type: "group" or type: "alias". Limits:
  • Minimum: 1 item per batch
  • Maximum: 100 items per batch
  • Items are processed concurrently
Each batch item shares the same fields as its corresponding individual endpoint, plus a type field to identify the kind.

Track API v1 (/api/v1/customers/)

Server-side endpoints for user and device lifecycle management. Use these from your backend — not from mobile apps. Auth: Same as Data Pipelines — Authorization: Basic base64(api_key:)
User identifier: Passed in the URL path (/:identifier), not the request body

PUT /api/v1/customers/:identifier

Purpose: Create or update a user profile. Server-side equivalent of /v1/identify. When to use:
  • Your backend creates a user and wants to push their profile to Zixflow
  • Updating user attributes from your server (plan change, billing update)
Request body:
{
  "email": "sarah@example.com",
  "name": "Sarah Johnson",
  "plan": "enterprise",
  "created_at": 1746352800
}
Notes:
  • Attributes are flat key-value (not nested under traits)
  • Timestamps must be Unix seconds (not ISO 8601)
  • :identifier is your user ID

POST /api/v1/customers/:identifier/events

Purpose: Track an event for a specific user. Server-side equivalent of /v1/track. When to use:
  • Order fulfilled (triggered by your fulfillment system, not the user’s app)
  • Payment received / payment failed (from billing system)
  • Subscription renewed (from subscription service)
  • Any event your server generates, not the user’s device
Request body:
{
  "name": "Order Fulfilled",
  "data": {
    "order_id": "ord_789",
    "tracking_number": "USPS-1Z999AA10123456784",
    "carrier": "USPS"
  },
  "timestamp": 1746352800
}
Notes:
  • Event name goes in name (not event)
  • Event data goes in data (not properties)
  • Timestamp is Unix seconds

PUT /api/v1/customers/:identifier/devices

Purpose: Register a push notification device token for a user. When to use:
  • Your server manages push token registration (less common — the Flutter SDK handles this automatically via registerDeviceToken())
  • Server-side integrations that need to register tokens on behalf of users
Request body:
{
  "device": {
    "id": "fcm_token_abc123...",
    "platform": "android",
    "last_used": 1746352800
  }
}

DELETE /api/v1/customers/:identifier/devices/:token

Purpose: Remove a specific device token from a user. Call this when a user logs out of a device (so they don’t receive push on a device they’re no longer signed in to). Request body: Empty Effect: Soft-deletes the device record — sets active=false, push_enabled=false.

DELETE /api/v1/customers/:identifier

Purpose: Delete a user profile. Request body: Empty Effect: Sets is_deleted=true on the profile and deactivates all linked devices. The profile record and event history are preserved for analytics — this is a soft delete. When to use:
  • User requests account deletion (GDPR right to erasure)
  • Account cleanup / fraud removal

POST /api/v1/customers/:identifier/suppress

Purpose: Suppress all outbound messages for a user across every channel simultaneously. Request body: Empty Effect: Sets is_suppressed=true on the profile. No push notifications, emails, SMS, WhatsApp, or RCS will be sent to this user until unsuppressed. When to use:
  • User has opted out of all communications
  • Account is suspended or in bad standing
  • Compliance hold
Note: Suppression is different from channel opt-out. Channel opt-out (email_opt_out, push_opt_out, etc.) is per-channel. Suppression blocks everything with a single flag.

POST /api/v1/customers/:identifier/unsuppress

Purpose: Lift suppression and resume message delivery for a user. Request body: Empty Effect: Clears is_suppressed flag. Message delivery resumes on all channels the user hasn’t individually opted out of.

GET /api/v1/customers/:identifier/subscription_preferences

Purpose: Retrieve the current channel opt-out state for a user. Query parameters:
ParameterValuesDefaultDescription
id_typeid, email, cio_ididHow to interpret the :identifier
Example:
GET /api/v1/customers/sarah@example.com/subscription_preferences?id_type=email
Response: User’s current opt-out state per channel (email_opt_out, sms_opt_out, push_opt_out, whatsapp_opt_out, rcs_opt_out) with their opt-out timestamps.

Error Responses

All endpoints return consistent error shapes:
{
  "error": "VALIDATION_FAILED",
  "details": [
    {
      "reason": "REQUIRED",
      "field": "userId",
      "message": "userId is required"
    }
  ]
}
HTTP StatusMeaning
200Success — event accepted
400Bad request — invalid JSON or failed validation
401Unauthorized — missing or invalid API key
404Not found — user identifier not found (Track API v1 only)
503Service unavailable — auth cache temporarily unavailable
500Internal error — unexpected failure

Complete Endpoint Map

API Reference pages: Events Introduction

Data Pipelines (/v1/)

POST  /v1/identify    (alias: /v1/i)   — Create/update user profile
POST  /v1/track       (alias: /v1/t)   — Track event
POST  /v1/screen      (alias: /v1/s)   — Track mobile screen view
POST  /v1/page        (alias: /v1/p)   — Track web page view
POST  /v1/batch       (alias: /v1/b)   — Send multiple events at once

Track API v1 (/api/v1/customers/)

PUT    /api/v1/customers/:id                          — Create/update user
POST   /api/v1/customers/:id/events                   — Track server-side event
PUT    /api/v1/customers/:id/devices                  — Register device token
DELETE /api/v1/customers/:id/devices/:token           — Remove device token
DELETE /api/v1/customers/:id                          — Delete user (soft)
POST   /api/v1/customers/:id/suppress                 — Suppress all channels
POST   /api/v1/customers/:id/unsuppress               — Resume delivery
GET    /api/v1/customers/:id/subscription_preferences — Get channel opt-out state

Utility

GET /health   — Health check
GET /         — Service info