Skip to content

Journey API

Base URL: https://qck.sh/public-api/v1


POST /journey/events

Rate limit exempt: this endpoint does not count toward your hourly quota. Events do count against your monthly journey event limit (see Limits and errors).

Permission: journey:write

FieldTypeRequiredDescription
eventsarrayYesArray of event objects (max 100 per request)

Headers: send an optional X-Idempotency-Key header to deduplicate batches. Duplicate batches within a 5-minute window return 202 with {"already_processed": true} instead of re-ingesting.

FieldTypeRequiredDescription
link_idstringYesUUID of the QCK link
visitor_idstringYesYour visitor identifier
session_idstringNoSession ID (enables session analytics)
event_typestringYespage_view, scroll_depth, time_on_page, custom, conversion
event_namestringNoName for custom/conversion events
page_urlstringYesPage URL or screen name
page_titlestringNoPage title
scroll_percentnumberNoScroll depth 0–100
time_on_pagenumberNoSeconds on page
timestampstringNoISO 8601 (defaults to server time)
conversion_namestringNoConversion name
revenue_centsintegerNoRevenue in cents ($49.99 = 4999)
currencystringNoISO 4217 code: 3 uppercase letters (e.g. USD)
country_codestringNo2-char ISO country code
citystringNoCity name
regionstringNoState/province (e.g. California)
device_typestringNomobile, desktop, tablet
browserstringNoBrowser name
browser_versionstringNoBrowser version
osstringNoOS name
os_versionstringNoOS version
propertiesobjectNoArbitrary key-value data

Response 202 Accepted

{ "success": true, "data": { "message": "Events queued for processing", "count": 5 } }

Batches with more than 100 events return 400 with code VALIDATION_ERROR.

Events count against your monthly tier limit at ingestion. Between 100% and 150% of your limit, batches are still accepted (202) but include warning headers: x-journey-warning (soft_limit at 100–120%, hard_limit_approaching at 120–150%) and x-journey-usage (used/limit), plus a usage object in the body:

{
"success": true,
"data": {
"message": "Events queued for processing",
"count": 5,
"usage": { "events_this_month": 16200, "limit": 15000, "status": "soft_limit" }
}
}

Past 150% of your limit, ingestion returns 429 with a Retry-After header (seconds until the calendar month resets):

{
"success": false,
"error": {
"code": "JOURNEY_LIMIT_EXCEEDED",
"message": "Monthly journey event limit exceeded. ...",
"details": { "events_this_month": 22500, "limit": 15000, "status": "blocked" }
},
"meta": { "request_id": "...", "timestamp": "...", "status": 429 }
}

GET /journey/links/{link_id}/summary
ParamTypeDefault
periodstring30d (24h, 7d, 30d, 90d)

Response 200

{
"success": true,
"data": {
"total_visitors": 450,
"total_sessions": 620,
"total_events": 3200,
"avg_session_duration_seconds": 85.4,
"top_pages": [{ "url": "/landing", "count": 900 }],
"top_events": [{ "name": "signup", "count": 120 }]
}
}

Permission: journey:read


GET /journey/links/{link_id}/sessions
ParamTypeDefault
periodstring30d (24h, 7d, 30d, 90d)
pageinteger1
limitinteger20 (max 100)
visitor_idstringNone

Permission: journey:read


GET /journey/links/{link_id}/events
ParamTypeDefault
periodstring30d (24h, 7d, 30d, 90d)
pageinteger1
limitinteger50 (max 200)
event_typestringNone

Permission: journey:read


GET /journey/links/{link_id}/funnel
ParamTypeRequiredDescription
stepsstringYesComma-separated event names
periodstringNo24h, 7d, 30d, 90d

Response 200

{
"success": true,
"data": {
"steps": [
{ "step_name": "page_view", "visitors": 1000, "conversion_rate": 100.0 },
{ "step_name": "scroll_depth", "visitors": 720, "conversion_rate": 72.0 },
{ "step_name": "conversion", "visitors": 150, "conversion_rate": 20.8 }
],
"total_visitors": 1000
}
}

conversion_rate is the percentage of visitors who converted from the previous step (e.g. 150 of 720 = 20.8%), not from the first step.

Permission: journey:read