Journey API
Base URL: https://qck.sh/public-api/v1
Ingest events
Section titled “Ingest events”POST /journey/eventsRate 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
| Field | Type | Required | Description |
|---|---|---|---|
events | array | Yes | Array 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.
Event object
Section titled “Event object”| Field | Type | Required | Description |
|---|---|---|---|
link_id | string | Yes | UUID of the QCK link |
visitor_id | string | Yes | Your visitor identifier |
session_id | string | No | Session ID (enables session analytics) |
event_type | string | Yes | page_view, scroll_depth, time_on_page, custom, conversion |
event_name | string | No | Name for custom/conversion events |
page_url | string | Yes | Page URL or screen name |
page_title | string | No | Page title |
scroll_percent | number | No | Scroll depth 0–100 |
time_on_page | number | No | Seconds on page |
timestamp | string | No | ISO 8601 (defaults to server time) |
conversion_name | string | No | Conversion name |
revenue_cents | integer | No | Revenue in cents ($49.99 = 4999) |
currency | string | No | ISO 4217 code: 3 uppercase letters (e.g. USD) |
country_code | string | No | 2-char ISO country code |
city | string | No | City name |
region | string | No | State/province (e.g. California) |
device_type | string | No | mobile, desktop, tablet |
browser | string | No | Browser name |
browser_version | string | No | Browser version |
os | string | No | OS name |
os_version | string | No | OS version |
properties | object | No | Arbitrary 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.
Limits and errors
Section titled “Limits and errors”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 summary
Section titled “Get summary”GET /journey/links/{link_id}/summary| Param | Type | Default |
|---|---|---|
period | string | 30d (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
List sessions
Section titled “List sessions”GET /journey/links/{link_id}/sessions| Param | Type | Default |
|---|---|---|
period | string | 30d (24h, 7d, 30d, 90d) |
page | integer | 1 |
limit | integer | 20 (max 100) |
visitor_id | string | None |
Permission: journey:read
List events
Section titled “List events”GET /journey/links/{link_id}/events| Param | Type | Default |
|---|---|---|
period | string | 30d (24h, 7d, 30d, 90d) |
page | integer | 1 |
limit | integer | 50 (max 200) |
event_type | string | None |
Permission: journey:read
Funnel analysis
Section titled “Funnel analysis”GET /journey/links/{link_id}/funnel| Param | Type | Required | Description |
|---|---|---|---|
steps | string | Yes | Comma-separated event names |
period | string | No | 24h, 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