Skip to main content
Both FlowPilot SDKs (iOS and Expo) talk to two endpoints: resolve (fetch the flow for a placement and user, with a batch variant that warms several placements in one round-trip) and events (send analytics). Most developers never call these directly. This page is here for debugging and advanced use. Treat the SDK as the supported surface; this contract is owned by the backend and can change.

Base URLs

Authentication

Every request carries an SDK API key as a bearer token:
Keys are workspace-scoped and must be type sdk. A key of any other type is rejected with 401. Key prefixes:
  • fp_live_ for production keys.
  • fp_test_ for staging/test keys.
Create and manage keys in the dashboard (see API keys). The workspace is derived from the key; you never send a workspace ID.

Resolve

Fetch the flow for a placement and user.
  • appId is the app UUID (the App ID from the dashboard).
  • placementId is the human-readable placement key (for example onboarding).

Request

string
required
Stable identifier for the user. The SDK uses a persistent per-install UUID by default.
string
required
Identifier for this session.
string
required
One of ios, android, web.
object
Targeting attributes for audience matching (for example {"country": "US", "app.version": "2.1.0"}). See Audience targeting.

Response (200)

A match returns the flow. No match returns 200 with flow_id: null (and the backend records a resolve_no_flow event server-side).
string | null
The matched flow ID, or null when no flow matched.
string
The specific published version served.
number
The version number.
number
The wire format version (see Schema versions).
object
The full flow JSON. See Flow schema reference.
string
Base URL for relative image and media paths.
string
Base URL for icon SVGs.
array
Font files to download and register. Each item is { family, weight, style, url }.
string
Set when an experiment is active on the placement.
string
The assigned variant, when in an experiment.
string
The assigned variant’s name.
number
How long the SDK may treat the result as fresh. The SDK uses 300 (5 minutes) when omitted.

Status codes

Variations

  • Offline export: add ?export=true to get the deterministic default flow for the placement. The resolver skips the audience filter and A/B assignment and always returns the placement’s default flow version, so the export is stable. Used to snapshot a flow for offline bundling.
  • Legacy route: POST /v1/placements/{placementId}/resolve exists for backward compatibility and is deprecated. Prefer the app-scoped route.

Example

Batch resolve

Resolve several placements for one identity in a single round-trip. The SDK uses this for launch prefetch (when prefetchOnLaunch declares two or more placements) so it can warm many placements without one request per placement. If the call fails, the SDK falls back to per-placement resolves, so launch prefetch never depends on it.

Request

The identity fields (user_id, session_id, device_platform, attributes) apply to every key in placement_keys, exactly as a single resolve personalizes one placement.
string[]
required
The placement keys to resolve (for example ["onboarding", "paywall"]). Must be non-empty. Duplicates are removed server-side, and the de-duplicated set is capped at 50 placements.
string
required
Stable identifier for the user.
string
required
Identifier for this session.
string
required
One of ios, android, web.
object
Targeting attributes for audience matching, applied to every placement. See Audience targeting.

Response (200)

A results array with one entry per de-duplicated placement key. Each entry is the same shape as a single resolve response (flow_id, flow_version_id, flow_schema, fonts, cache_ttl_seconds, and so on), tagged with its placement_key. Resolution is best-effort per placement, so one placement never sinks the batch:
  • A placement that matched no flow returns flow_id: null (and the backend records a resolve_no_flow event server-side, as with a single resolve).
  • A placement that failed to resolve returns flow_id: null and an error string. The overall response is still 200.
array
One result per requested placement key.
string
The placement key this result is for. Use it to correlate results regardless of order.
string
Present only when that one placement failed to resolve. Absent on success and on the no-flow case.
Every other field on a result matches the single resolve response (flow_id, flow_version_id, flow_version, schema_version, flow_schema, media_base_url, icon_base_url, fonts, experiment_id, variant_id, variant_name, cache_ttl_seconds).

Status codes

Example

Events

Send one analytics event or a batch.
The body is either a single event object or an array of them.

Request fields (EventInput)

Required:
string (uuid)
required
Unique event ID.
string (uuid)
required
Must match the appId in the URL (mismatches are rejected).
string (uuid)
required
The flow the event belongs to.
string (uuid)
required
Must reference a real flow version in the app, or the event is rejected.
string
required
Stable user identifier.
string
required
Session identifier.
string
required
One of ios, android, web.
string
required
One of the recognized event types.
string (RFC3339)
required
When the event happened.
string
required
The SDK version that produced the event.
Optional: placement_id, flow_version, experiment_id, variant_id, variant_name, screen_id, screen_name, screen_index, element_id, element_type, interaction_type, revenue, currency, time_since_flow_start_ms, time_on_screen_ms, app_version, country, properties.

Limits

  • Up to 100 events per request.
  • Up to 256 KB payload.

Response (202)

number
Events buffered for storage.
number
Events dropped (validation failure, app_id mismatch, or out-of-scope flow version).
The endpoint returns 202 Accepted; events are written to analytics asynchronously.

Variations

  • Legacy route: POST /v1/events exists for backward compatibility and is deprecated. Prefer the app-scoped route.

Example

Notes

  • The app-scoped routes are authoritative for app_id: the value in the URL wins, and a conflicting body app_id is rejected.
  • This contract may change. Build against the SDK, not raw HTTP, for production apps.