Skip to content

Conversions API

A conversion is an ordered list of steps. The first step decides who enters the funnel; the last step is the conversion. This API manages the definition and reads the same numbers the dashboard shows.

MethodPathScope
GET/v2/property/conversions/schemaconversions:read
GET/v2/property/conversionsconversions:read
POST/v2/property/conversionsconversions:write
GET/v2/property/conversions/{conversion}conversions:read
POST/v2/property/conversions/{conversion}conversions:write
POST/v2/property/conversions/{conversion}/stepsconversions:write
POST/v2/property/conversions/{conversion}/publishconversions:write
POST/v2/property/conversions/{conversion}/toggleconversions:write
DELETE/v2/property/conversions/{conversion}conversions:write
POST/v2/property/conversions/{conversion}/summaryconversions:read
POST/v2/property/conversions/{conversion}/segmentsconversions:read
POST/v2/property/conversions/{conversion}/cyclesconversions:read
POST/v2/property/conversions/{conversion}/sessionsconversions:read

A {conversion} id from another property returns 404 with conversion not found.

GET /v2/property/conversions/schema

Call this first. It returns every valid value for the fields below, so nothing has to be hardcoded.

{
"code": 200,
"status": "OK",
"data": {
"conversion_types": [
{ "value": "lead", "label": "Lead", "color": "primary", "icon": "conversion-lead", "description": "Contact form, inquiry, or lead capture" },
{ "value": "sale", "label": "Sale", "...": "..." }
],
"trigger_types": [
{ "value": "page_view", "label": "Page Visit", "description": "Visitor reaches a specific page", "config": { "kind": "path", "defaults": { "type": "page", "field": "path", "match": "contains", "value": "" }, "fieldOptions": [], "matchOptions": [] } }
],
"cycle_intervals": ["day", "week", "month"],
"segment_dimensions": [{ "value": "channel_category", "label": "Channel" }],
"page_match_modes": [{ "id": "contains", "name": "Contains" }],
"event_value_match_modes": [{ "id": "exists", "name": "Exists" }]
}
}

The current values:

CatalogValues
conversion_typeslead, sale, signup, activation, download, custom
trigger_typesentry_page, page_view, event, form_submit, short_link, all_traffic, acquisition
cycle_intervalsday, week, month
segment_dimensionschannel_category, source_id, utm_medium, utm_campaign, utm_content, utm_term, request_country, request_device, entry_path, short_link_id
page_match_modescontains, exact, starts_with, regex
event_value_match_modesexists, equals, gte, lte, gt, lt

Summary shape (list rows):

FieldNotes
id, name, description
typeOne of conversion_types
statedraft, active, paused
conversion_valueFixed value per conversion in whole currency units (not cents), or null
value_from_eventboolean. When true the value is read from the conversion step’s event value or acquisition value instead
steps_countinteger
starting_fromISO 8601 or null. Analytics never look before this date
default_period, default_cycleDashboard defaults

Full shape = summary shape plus steps[], each { id, name, order, trigger_type, trigger_config, is_required }.

Every step has name, trigger_type, trigger_config (object) and optional is_required (boolean, default true). The contents of trigger_config depend on the trigger type. The API enforces these keys; the rest of the object follows the defaults published by the schema endpoint.

trigger_typeRequired in trigger_configFull default config
page_viewvalue (string, max 500){ "type": "page", "field": "path" or "url", "match": "contains", "value": "/pricing" }
entry_pagevalue (string, max 500){ "type": "entryPage", "field": "entry_path" or "entry_url", "match": "contains", "value": "/pricing" }
eventname (string, max 255){ "type": "event", "name": "purchase", "value": "", "valueMatch": "exists" }
short_linkscope (link or group), value (the link or group id){ "type": "shortLink", "scope": "link", "value": "..." }
form_submitsnipFormId (string){ "type": "formSubmit", "snipFormId": "..." }
all_trafficnothing{ "type": "allTraffic" }
acquisitionnothing enforced{ "type": "acquisition", "field": "value", "match": "exists", "value": "" }. field is value, cost or currency_code; numeric matches are exists, equals, gte, lte, gt, lt; currency_code takes exists or equals

Validation errors point at the step index: steps.1.trigger_config.name.

POST /v2/property/conversions

FieldRules
namerequired, string, max 255
descriptionstring, max 500
typerequired, one of conversion_types
conversion_valuenumeric, min 0
value_from_eventboolean
starting_fromdate
default_periodstring
default_cycleday, week, month
stepsarray of steps (see above)
publishboolean. Publishes immediately if at least one step is supplied
Terminal window
curl -X POST https://api.snipform.io/v2/property/conversions \
-H "Authorization: Bearer $SNIPFORM_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Pricing to signup",
"type": "signup",
"publish": true,
"steps": [
{ "name": "Saw pricing", "trigger_type": "page_view",
"trigger_config": { "type": "page", "field": "path", "match": "starts_with", "value": "/pricing" } },
{ "name": "Signed up", "trigger_type": "event",
"trigger_config": { "type": "event", "name": "signup", "value": "", "valueMatch": "exists" } }
]
}'
  • GET /v2/property/conversions returns { "conversions": [summary shape, ...] }.
  • GET /v2/property/conversions/{conversion} returns { "conversion": full shape }.

POST /v2/property/conversions/{conversion}

Same fields as create minus steps and publish; all optional. Does not touch steps.

Terminal window
curl -X POST https://api.snipform.io/v2/property/conversions/66c4e0a1b2c3d4e5f6a7b8c9 \
-H "Authorization: Bearer $SNIPFORM_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "conversion_value": 49, "default_cycle": "week" }'

POST /v2/property/conversions/{conversion}/steps with { "steps": [...] } (required, at least one). Replaces the whole list; order is the array order. Returns the full shape.

CallEffectErrors
POST .../publishdraft becomes active. No-op when already published422 Add at least one funnel step before publishing
POST .../toggleactive becomes paused, paused becomes active
DELETE ...Removes the conversion and its steps. Returns { "deleted": true }

The four read endpoints below share two inputs:

FieldRulesNotes
from, tointeger unix secondsDefault: the last 7 days ending now. from is clamped to starting_from when set
filterobjectEquality filters, { "field": "value" } or { "field": ["a", "b"] }. Keys are the alias names country, country_code, continent, region, city, lang, timezone, device, device_brand, device_model, browser, browser_family, os, os_version, entry_path, entry_subdomain, entry_title, exit_path, exit_subdomain, referrer_domain, utm_source, utm_medium, utm_campaign, channel_category, channel_name, source_name

Only real-user sessions are counted; bots are excluded.

POST /v2/property/conversions/{conversion}/summary

{
"code": 200,
"status": "OK",
"data": {
"window": { "from": 1755177600, "to": 1755782400 },
"summary": {
"conversions": 42,
"sessions": 1180,
"rate": 3.6,
"value": 205800,
"value_currency": "USD",
"value_formatted": "$2,058.00",
"value_usd": 205800
},
"funnel": [
{ "step_id": "66c4e0a1b2c3d4e5f6a7b8d0", "name": "Saw pricing", "order": 0, "trigger_label": "Page Visit", "trigger_summary": "Path starts with /pricing",
"count": 1180, "drop_off": 0, "drop_off_count": 0, "conversion_rate": 100, "is_conversion": false },
{ "step_id": "66c4e0a1b2c3d4e5f6a7b8d1", "name": "Signed up", "order": 1, "trigger_label": "Event Fired", "trigger_summary": "signup",
"count": 42, "drop_off": 96.4, "drop_off_count": 1138, "conversion_rate": 3.6, "is_conversion": true }
]
}
}
  • rate and conversion_rate are percentages (0 to 100) rounded to one decimal. drop_off is the percentage lost against the previous step.
  • value is in minor units when the conversion has a currency (value_currency set); with no currency it is the plain fixed-value sum with no USD side (value_usd: null).
  • funnel is empty for a single-step conversion.

POST /v2/property/conversions/{conversion}/segments

FieldRules
dimensionone of segment_dimensions, max 64
tag_keystring, max 64. Segments by the values of that session tag
from, to, filteras above

One of dimension or tag_key is required; otherwise 422 dimension or tag_key required. Up to 50 segments, sorted by converted descending.

Terminal window
curl -X POST https://api.snipform.io/v2/property/conversions/66c4e0a1b2c3d4e5f6a7b8c9/segments \
-H "Authorization: Bearer $SNIPFORM_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "dimension": "channel_category" }'
{
"code": 200,
"status": "OK",
"data": {
"window": { "from": 1755177600, "to": 1755782400 },
"dimension": "channel_category",
"tag_key": null,
"segments": [
{ "value": "paid_search", "label": "Paid Search", "icon": "channel-paid-search", "sessions": 410, "converted": 22, "rate": 5.4,
"sessions_label": "Paid Search - Sessions", "converted_label": "Paid Search - Converted",
"browse": { "clauses": [{ "id": "channel", "op": "equals", "value": "paid_search" }] } }
]
}
}

browse.clauses is ready to paste into the Signals sessions endpoint to list exactly those sessions. It is null for values that cannot be expressed as a clause (empty or (none)).

POST /v2/property/conversions/{conversion}/cycles

The same funnel recomputed per calendar bucket, newest first.

FieldRules
intervalrequired: day, week, month
pageinteger, min 0, default 0
per_pageinteger, 1 to 24, default 6
filteras above
{
"code": 200,
"status": "OK",
"data": {
"cycles": [
{ "id": "w-0", "label": "This week", "from_ts": 1755475200, "to_ts": 1755782400, "date_from": "2026-08-18", "date_to": "2026-08-21", "is_current": true,
"conversions": 9, "sessions": 240, "rate": 3.8, "value": 44100, "value_currency": "USD", "delta": 0.4 }
],
"has_more": true,
"page": 0,
"interval": "week"
}
}

id is stable (w-3 is the fourth weekly bucket back). delta is the change in rate against the next older cycle in percentage points, or null when there is no older cycle. Buckets never start before starting_from.

POST /v2/property/conversions/{conversion}/sessions

Sessions that reached a given step in the window.

FieldRules
step_ida step id. Omit for sessions that reached the final step (converted)
pageinteger, min 1, default 1
per_pageinteger, 1 to 100, default 25
from, to, filteras above

The response is a paginator spread at the root (data, current_page, last_page, total, next_page_url, …) plus window and step_id. Each row:

{
"id": "9f1c2c1e-7b1a-4f0e-9f2b-1d2c3b4a5e6f",
"sid": "3a0c...",
"entry_ts": 1755780000,
"last_ts": 1755780420,
"entry_url": "https://acme.com/pricing",
"views": 3,
"channel_category": "paid_search",
"channel_name": "Google Ads",
"source_name": "google.com",
"utm": { "source": "google", "medium": "cpc", "campaign": "brand", "content": null, "term": null },
"country": "South Africa",
"device": "desktop"
}