Every Public API path in the reference is relative to it. {workspace} is the workspace UUID and must be the token's own workspace, otherwise the API answers 403 forbidden.
https://api.leadjourney.io/api/v1/public/workspaces/{workspace}Developer API
Run reports, read lead journeys, manage tags, tracking domains, channels and client workspaces with a workspace token. Plus the Integrations API behind the Zapier app.
Getting started
Where requests go, how they authenticate, what a token may do, how fast you may call and what comes back.
Every Public API path in the reference is relative to it. {workspace} is the workspace UUID and must be the token's own workspace, otherwise the API answers 403 forbidden.
https://api.leadjourney.io/api/v1/public/workspaces/{workspace}POST /api-tokens, scope tokens), and one is issued automatically when an agency creates a client workspace.Send the workspace token as a Bearer credential on every request. A token is ljw_ followed by 40 random characters, and it reaches exactly one workspace. These are not session tokens.
Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX{"success": false, "error": "unauthenticated", "message": "Missing API token. Send it as: Authorization: Bearer ljw_..."}{"success": false, "error": "unauthenticated", "message": "Invalid, revoked or expired API token."}{"success": false, "error": "forbidden", "message": "This token is not valid for the requested workspace."}{"success": false, "error": "insufficient_scope", "message": "This token does not have the \"tags\" scope.", "required_scope": "tags", "granted_scopes": ["reports"]}A token carries one or more scopes. Each covers reads and writes in its area; a call outside the token's scopes answers 403 insufficient_scope. Minting a token in the dashboard needs the permission in the last column.
| Scope | Label | Covers | Permission to issue |
|---|---|---|---|
reports | Reports & Dashboards | /reports/*, /dashboards/* | Report Builder |
tags | Tags | /tags/* | Tags |
leads | Leads & Attribution (read) | /leads/*, returns personal data (email, phone) | Lead Overview |
tracking | Tracking | /tracking-domains/*, /tracking/* | Tracking |
traffic_channels | Traffic Channels | /traffic-channels/*, /utm/*, /short-links | Traffic Channels |
agency.workspaces | Create Client Workspaces | /agency/workspaces | None, but the issuer must hold the agency role and the workspace must be the agency HQ |
tokens | Manage API Tokens | /api-tokens/* | None |
| Limit | Requests | Window |
|---|---|---|
| Per workspace | 60 | 1 minute |
| Per token | 30 | 1 minute |
| Per IP, before authentication | 120 | 1 minute |
| Agency client workspace creation | 1 | 30 minutes per agency HQ |
Every bucket is checked before any is counted, so a request refused with 429 costs no budget. A successful answer carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Scope (workspace or token), taken from whichever bucket has the least headroom.
A 429 from the workspace or token bucket carries Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining: 0 and X-RateLimit-Scope:
{"success": false, "error": "rate_limited", "message": "Rate limit exceeded for this workspace (60 requests per minute). Retry in 12 second(s).", "scope": "workspace", "retry_after": 12}Success answers carry success: true, the payload usually under data; some endpoints add meta or other top-level keys. Errors carry success: false, a machine readable error code and a message.
{"success": true, "data": { ... }}{"success": false, "error": "<code>", "message": "<text>"}List endpoints take page (default 1, minimum 1) and per_page (default 20, maximum 50). A larger per_page is clamped to 50, not rejected; a value below 1 falls back to 20.
{"success": true, "data": [...], "meta": {"current_page": 1, "per_page": 20, "last_page": 3, "total": 47, "max_per_page": 50}}Every error answers with its HTTP status and the error envelope above. The codes shared across endpoints are unauthenticated (401), forbidden and insufficient_scope (403), not_found (404) and rate_limited (429); each endpoint card lists its own. Two answers differ from the envelope, and they are documented as they are:
{"message": "...", "errors": {"field": ["..."]}}.{"message": "...", "error": "plan_limit_reached", "limit": "...", "used": n, "allowed": n}, with no success key.confirm: true: deleting a tracking domain or a traffic channel without it answers 409 confirmation_required. Deleting a tracking domain breaks every link on that host.Your first call: ask the workspace for its report vocabulary. Any token with the reports scope can make it.
curl "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/reports/describe" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"{
"success": true,
"data": {
"metrics": [
"<metric_id>",
"..."
],
"metric_windows": {
"note": "Append a window as metric@window. At most 6 distinct windows per report.",
"ids": [
"last_7d",
"last_14d",
"last_30d",
"last_60d",
"last_90d"
]
},
"group_by": [
"time",
"day_of_week",
"sources",
"channel_category",
"country",
"campaign",
"custom_field:<key>"
],
"channel_category": [
"<channel category>",
"..."
],
"secondary_group_by": [
"time",
"sources",
"channel_category",
"country",
"campaign"
],
"granularity": [
"Hour",
"Day",
"Week",
"Month",
"Quarter",
"Year"
],
"filter_fields": [
"country",
"device",
"landing_page",
"campaign_name",
"traffic_channel",
"tag"
],
"filter_conditions": [
"is_equal_to",
"is_not_equal_to",
"contains",
"does_not_contain",
"starts_with",
"ends_with"
],
"attribution_method": [
"first_click",
"last_click",
"Linear",
"Time Decay",
"U-Shaped",
"Progressive"
],
"attribution_date_mode": [
"click_date",
"conversion_date"
],
"chart_types": [
"line",
"column",
"bar",
"area",
"donut",
"table"
],
"time_periods": [
"allTime",
"today",
"yesterday",
"thisWeek",
"lastWeek",
"thisMonth",
"lastMonth",
"thisQuarter",
"lastQuarter",
"thisYear",
"lastYear",
"rollingDateRange",
"customRange"
],
"traffic_channels": [
{
"key": "google_ads",
"label": "Google Ads",
"is_active": true
}
],
"pagination": {
"default_per_page": 20,
"max_per_page": 50
}
}
}38 endpoints
Workspace tokens (ljw_) with scopes: reports and dashboards, leads, tags, tracking, traffic channels, tokens and agency client workspaces. Paths below are relative to the Public API base URL.
https://api.leadjourney.io/api/v1/public/workspaces/{workspace}Describe the report vocabulary, run a report ad hoc, and manage dashboards and their saved report cards. Scope: reports.
/reports/describeEverything a report can be built from: metrics, windows, dimensions, filters, attribution settings, chart types and time periods. Not paginated.
Scope reports
Example request
curl "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/reports/describe" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Example response
{
"success": true,
"data": {
"metrics": [
"<metric_id>",
"..."
],
"metric_windows": {
"note": "Append a window as metric@window. At most 6 distinct windows per report.",
"ids": [
"last_7d",
"last_14d",
"last_30d",
"last_60d",
"last_90d"
]
},
"group_by": [
"time",
"day_of_week",
"sources",
"channel_category",
"country",
"campaign",
"custom_field:<key>"
],
"channel_category": [
"<channel category>",
"..."
],
"secondary_group_by": [
"time",
"sources",
"channel_category",
"country",
"campaign"
],
"granularity": [
"Hour",
"Day",
"Week",
"Month",
"Quarter",
"Year"
],
"filter_fields": [
"country",
"device",
"landing_page",
"campaign_name",
"traffic_channel",
"tag"
],
"filter_conditions": [
"is_equal_to",
"is_not_equal_to",
"contains",
"does_not_contain",
"starts_with",
"ends_with"
],
"attribution_method": [
"first_click",
"last_click",
"Linear",
"Time Decay",
"U-Shaped",
"Progressive"
],
"attribution_date_mode": [
"click_date",
"conversion_date"
],
"chart_types": [
"line",
"column",
"bar",
"area",
"donut",
"table"
],
"time_periods": [
"allTime",
"today",
"yesterday",
"thisWeek",
"lastWeek",
"thisMonth",
"lastMonth",
"thisQuarter",
"lastQuarter",
"thisYear",
"lastYear",
"rollingDateRange",
"customRange"
],
"traffic_channels": [
{
"key": "google_ads",
"label": "Google Ads",
"is_active": true
}
],
"pagination": {
"default_per_page": 20,
"max_per_page": 50
}
}
}Lists shortened. group_by: time, day_of_week, sources, channel_category, country, city, device, browser, os, isp, landing_page, domain, form, keyword, url_parameters, campaign, ad_group, ad, affiliate_campaign, affiliate_offer, affiliate_network, custom_field:<key>. secondary_group_by: time, sources, channel_category, country, city, device, browser, os, isp, landing_page, domain, keyword, url_parameters, campaign, ad_group, ad. filter_fields: country, device, landing_page, domain, campaign_name, ad_group, ad, keyword, traffic_channel, medium, tag, campaign_id, adset_id, ad_id. The affiliate_* entries only appear when affiliate features are on for the workspace. metrics are the known base metric ids of the workspace.
/reports/runRuns an ad-hoc report and returns its rows. Nothing is saved.
Scope reports
Request body
metricsstring[]At least one. Each item is at most 100 characters, matches ^[a-z0-9_]+(@(last_7d|last_14d|last_30d|last_60d|last_90d))?$ and names a known base metric (see /reports/describe). Append @window for a rolling window, at most 6 distinct windows per report. A _trend suffix (with no @) requests a trend series, returned under trends.
group_bystringOne entry of the group_by list from /reports/describe, or custom_field:<key> (key matching [a-z][a-z0-9_]*).
granularitystringTime bucket.
Allowed: Hour, Day, Week, Month, Quarter, Year
secondary_group_bystringOne entry of the secondary_group_by list from /reports/describe.
secondary_granularitystringTime bucket of the secondary dimension.
Allowed: Day, Week, Month, Quarter, Year
date_fromstringStart date, Y-m-d.
date_tostringEnd date, Y-m-d.
traffic_channelsstring[]Channel keys. Empty means all channels.
filtersarrayArray of { field, condition, value }. field is one of filter_fields, condition one of the six filter_conditions from /reports/describe, value is required.
attribution_methodstringDefaults to last_click. First and Last are accepted as aliases; an unknown value falls back to last_click.
Allowed: first_click, last_click, Linear, Time Decay, U-Shaped, Progressive
attribution_windowstringDefaults to lifetime.
attribution_date_modestringDefaults to click_date.
Allowed: click_date, conversion_date
sort_directionstringDefaults to desc.
Allowed: asc, desc
sort_columnstringA known metric id.
limitintegerDefaults to 10.
Allowed: 5, 10, 15, 20
display_only_dates_with_databooleanDefaults to true.
pageintegerMinimum 1. Accepted in the body or the query string.
per_pageintegerValidated as 1 to 100, then clamped to 50. Defaults to 20. Accepted in the body or the query string.
Errors
report_too_largeThe query timed out. Narrow the date range or the dimensions.
report_failedAny other failure while running the report.
Validation errors, including an unknown base metric, in the standard message and errors shape.
Example request
curl -X POST "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/reports/run" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{
"metrics": [
"<metric_id>"
],
"group_by": "sources",
"date_from": "2026-10-01",
"date_to": "2026-10-24",
"attribution_method": "first_click"
}'Example response
{
"success": true,
"data": {
"labels": [
"Google Ads",
"Meta Ads",
"LinkedIn Ads"
],
"primary_labels": null,
"secondary_labels": null,
"secondary_group_by": null,
"secondary_granularity": null,
"pagination": {
"page": 1,
"per_page": 20,
"total": 3,
"has_more": false
}
},
"meta": {
"current_page": 1,
"per_page": 20,
"max_per_page": 50
}
}Example trimmed. data also carries dimension_meta, datasets, totals, previous_totals and metric_meta, plus trends when _trend metrics are requested. The secondary keys are null unless a secondary dimension is used.
/dashboardsLists the workspace's dashboards, ordered by order, each with its report cards.
Scope reports
Query parameters
pageintegerPage number. Defaults to 1, minimum 1.
per_pageintegerItems per page. Defaults to 20, maximum 50. A larger value is clamped to 50, a value below 1 falls back to 20.
Example request
curl "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/dashboards" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Example response
{
"success": true,
"data": [
{
"id": "b2c3d4e5-f607-4819-2a3b-4c5d6e7f8091",
"name": "Paid channels",
"icon_key": "google_ads",
"column_layout": 2,
"order": 1,
"reports": [
{
"id": "d4e5f607-1829-4a3b-5c6d-7e8f90a1b2c3",
"order": 1,
"name": "Leads by source",
"chart_type": "column",
"metrics": [
"<metric_id>"
],
"group_by": "sources"
}
]
}
],
"meta": {
"current_page": 1,
"per_page": 20,
"last_page": 1,
"total": 1,
"max_per_page": 50
}
}/dashboardsCreates an empty dashboard.
Scope reports
Request body
namestringMax 255 characters.
icon_keystringA traffic channel key, for example meta_ads, google_ads, bing_ads, linkedin_ads, reddit_ads, chatgpt_ads, x_ads, taboola_ads, outbrain_ads, tiktok_ads, email, gmb, plus direct, referral and the organic keys.
Example request
curl -X POST "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/dashboards" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{
"name": "Paid channels",
"icon_key": "google_ads"
}'Example response
{
"success": true,
"data": {
"id": "b2c3d4e5-f607-4819-2a3b-4c5d6e7f8091",
"name": "Paid channels",
"icon_key": "google_ads"
}
}/dashboards/{dashboard}Returns one dashboard with every report card and its full report configuration.
Scope reports
Path parameters
dashboarduuidDashboard id.
Errors
not_foundThe dashboard is not in this workspace.
Example request
curl "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/dashboards/DASHBOARD_ID" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Example response
{
"success": true,
"data": {
"id": "b2c3d4e5-f607-4819-2a3b-4c5d6e7f8091",
"name": "Paid channels",
"icon_key": "google_ads",
"column_layout": 2,
"order": 1,
"reports": [
{
"id": "d4e5f607-1829-4a3b-5c6d-7e8f90a1b2c3",
"order": 1,
"name": "Leads by source",
"chart_type": "column",
"report_config": {
"...": "the frontend's camelCase report configuration"
}
}
]
}
}report_config is the full configuration in the frontend's camelCase shape.
/dashboards/{dashboard}Deletes the dashboard and detaches its icon.
Scope reports
Path parameters
dashboarduuidDashboard id.
Errors
not_foundThe dashboard is not in this workspace.
Example request
curl -X DELETE "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/dashboards/DASHBOARD_ID" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Example response
{
"success": true,
"data": {
"id": "b2c3d4e5-f607-4819-2a3b-4c5d6e7f8091",
"name": "Paid channels",
"deleted": true
}
}/dashboards/{dashboard}/reportsSaves a report card on a dashboard. Takes the fields of /reports/run (without page and per_page) plus the card's own.
Scope reports
Path parameters
dashboarduuidDashboard id.
Request body
report_namestringMax 255 characters.
chart_typestringDefaults to line.
Allowed: line, column, bar, area, donut, table
time_periodstringOne of time_periods from /reports/describe. Defaults to customRange when dates are given, otherwise lastMonth.
rolling_valueintegerMinimum 1.
rolling_unitstringUnit of a rolling range.
Allowed: days, weeks, months, quarters, years
metricsstring[]At least one. Each item is at most 100 characters, matches ^[a-z0-9_]+(@(last_7d|last_14d|last_30d|last_60d|last_90d))?$ and names a known base metric (see /reports/describe). Append @window for a rolling window, at most 6 distinct windows per report. A _trend suffix (with no @) requests a trend series, returned under trends.
group_bystringOne entry of the group_by list from /reports/describe, or custom_field:<key> (key matching [a-z][a-z0-9_]*).
granularitystringTime bucket.
Allowed: Hour, Day, Week, Month, Quarter, Year
secondary_group_bystringOne entry of the secondary_group_by list from /reports/describe.
secondary_granularitystringTime bucket of the secondary dimension.
Allowed: Day, Week, Month, Quarter, Year
date_fromstringStart date, Y-m-d.
date_tostringEnd date, Y-m-d.
traffic_channelsstring[]Channel keys. Empty means all channels.
filtersarrayArray of { field, condition, value }. field is one of filter_fields, condition one of the six filter_conditions from /reports/describe, value is required.
attribution_methodstringDefaults to last_click. First and Last are accepted as aliases; an unknown value falls back to last_click.
Allowed: first_click, last_click, Linear, Time Decay, U-Shaped, Progressive
attribution_windowstringDefaults to lifetime.
attribution_date_modestringDefaults to click_date.
Allowed: click_date, conversion_date
sort_directionstringDefaults to desc.
Allowed: asc, desc
sort_columnstringA known metric id.
limitintegerDefaults to 10.
Allowed: 5, 10, 15, 20
display_only_dates_with_databooleanDefaults to true.
Errors
not_foundThe dashboard is not in this workspace.
Example request
curl -X POST "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/dashboards/DASHBOARD_ID/reports" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{
"report_name": "Leads by source",
"chart_type": "column",
"metrics": [
"<metric_id>"
],
"group_by": "sources",
"time_period": "lastMonth"
}'Example response
{
"success": true,
"data": {
"id": "d4e5f607-1829-4a3b-5c6d-7e8f90a1b2c3",
"dashboard_id": "b2c3d4e5-f607-4819-2a3b-4c5d6e7f8091",
"dashboard_name": "Paid channels",
"name": "Leads by source",
"order": 1
}
}/dashboards/{dashboard}/reports/{report}Removes a report card from a dashboard.
Scope reports
Path parameters
dashboarduuidDashboard id.
reportuuidReport card id.
Errors
not_foundThe dashboard is not in this workspace, or it has no such card.
Example request
curl -X DELETE "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/dashboards/DASHBOARD_ID/reports/REPORT_ID" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Example response
{
"success": true,
"data": {
"id": "d4e5f607-1829-4a3b-5c6d-7e8f90a1b2c3",
"name": "Leads by source",
"deleted": true
}
}Resolve a lead from a click id, email or phone, and read its full journey. Read-only, and the answers carry personal data (email, phone). Scope: leads.
/leads/findResolves a lead from a click id, an email or a phone number and returns its first and last touch. The click id is tried first, following merges for up to 5 hops; if the email or phone passed contradicts the lead behind the click id, identity matching wins, email first, then phone.
Scope leads
Query parameters
click_idstringMax 255. Required unless email or phone is given.
emailstringMax 255.
phonestringMax 64.
Example request
curl "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/leads/find?click_id=0c1d2e3f-4a5b-6c7d-8e9f-a0b1c2d3e4f5" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Example response
{
"success": true,
"data": {
"lead": {
"id": "5d6e7f80-1a2b-3c4d-5e6f-708192a3b4c5",
"click_id": "0c1d2e3f-4a5b-6c7d-8e9f-a0b1c2d3e4f5",
"email": "[email protected]",
"phone": "+4915112345678",
"is_unattributed": false,
"matched_by": "click_id",
"created_at": "2026-10-02T08:16:40Z",
"first_touch": {
"clicked_at": "2026-10-02T08:14:03Z",
"channel": "Google Ads",
"channel_key": "google_ads",
"utm_source": "google",
"utm_medium": "cpc",
"utm_campaign": "brand-search",
"utm_content": null,
"utm_term": "lead attribution",
"campaign": "Brand Search",
"campaign_id": "1234567890",
"ad_set": "Brand Exact",
"ad_set_id": "2345678901",
"ad": "RSA 1",
"ad_id": "3456789012",
"keyword": "lead attribution",
"keyword_id": "4567890123",
"placement": null,
"gclid": "EAIaIQobChMI_example",
"wbraid": null,
"gbraid": null,
"fbclid": null,
"li_fat_id": null,
"msclkid": null,
"rdt_cid": null,
"twclid": null,
"oppref": null,
"tblci": null,
"obclid": null,
"ttclid": null,
"landing_page": "/pricing",
"full_url": "https://acme.com/pricing?utm_source=google&utm_medium=cpc",
"referrer_domain": "google.com",
"device_type": "desktop",
"os": "macOS",
"browser": "Chrome",
"country": "DE",
"city": "Berlin"
},
"last_touch": {
"clicked_at": "2026-10-02T08:14:03Z",
"channel": "Google Ads",
"channel_key": "google_ads",
"utm_source": "google",
"utm_medium": "cpc",
"utm_campaign": "brand-search",
"utm_content": null,
"utm_term": "lead attribution",
"campaign": "Brand Search",
"campaign_id": "1234567890",
"ad_set": "Brand Exact",
"ad_set_id": "2345678901",
"ad": "RSA 1",
"ad_id": "3456789012",
"keyword": "lead attribution",
"keyword_id": "4567890123",
"placement": null,
"gclid": "EAIaIQobChMI_example",
"wbraid": null,
"gbraid": null,
"fbclid": null,
"li_fat_id": null,
"msclkid": null,
"rdt_cid": null,
"twclid": null,
"oppref": null,
"tblci": null,
"obclid": null,
"ttclid": null,
"landing_page": "/pricing",
"full_url": "https://acme.com/pricing?utm_source=google&utm_medium=cpc",
"referrer_domain": "google.com",
"device_type": "desktop",
"os": "macOS",
"browser": "Chrome",
"country": "DE",
"city": "Berlin"
}
}
}
}When nothing matches, data.lead is null with status 200, not a 404. matched_by is click_id, email or phone. Every key of a touch object is always present; timestamps are ISO 8601 UTC.
/leads/{lead}/journeyThe full timeline behind a lead: its conversions whole, its clicks paged oldest first.
Scope leads
Path parameters
leadstringThe lead id (uuid) or a click_id.
Query parameters
pageintegerPage number. Defaults to 1, minimum 1.
per_pageintegerItems per page. Defaults to 20, maximum 50. A larger value is clamped to 50, a value below 1 falls back to 20.
Errors
not_foundThe lead is not in this workspace.
Example request
curl "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/leads/LEAD_ID/journey" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Example response
{
"success": true,
"data": {
"lead": {
"id": "5d6e7f80-1a2b-3c4d-5e6f-708192a3b4c5",
"click_id": "0c1d2e3f-4a5b-6c7d-8e9f-a0b1c2d3e4f5",
"email": "[email protected]",
"phone": "+4915112345678",
"is_unattributed": false,
"matched_by": "click_id",
"created_at": "2026-10-02T08:16:40Z",
"first_touch": {
"clicked_at": "2026-10-02T08:14:03Z",
"channel": "Google Ads",
"channel_key": "google_ads",
"utm_source": "google",
"utm_medium": "cpc",
"utm_campaign": "brand-search",
"utm_content": null,
"utm_term": "lead attribution",
"campaign": "Brand Search",
"campaign_id": "1234567890",
"ad_set": "Brand Exact",
"ad_set_id": "2345678901",
"ad": "RSA 1",
"ad_id": "3456789012",
"keyword": "lead attribution",
"keyword_id": "4567890123",
"placement": null,
"gclid": "EAIaIQobChMI_example",
"wbraid": null,
"gbraid": null,
"fbclid": null,
"li_fat_id": null,
"msclkid": null,
"rdt_cid": null,
"twclid": null,
"oppref": null,
"tblci": null,
"obclid": null,
"ttclid": null,
"landing_page": "/pricing",
"full_url": "https://acme.com/pricing?utm_source=google&utm_medium=cpc",
"referrer_domain": "google.com",
"device_type": "desktop",
"os": "macOS",
"browser": "Chrome",
"country": "DE",
"city": "Berlin"
},
"last_touch": {
"clicked_at": "2026-10-02T08:14:03Z",
"channel": "Google Ads",
"channel_key": "google_ads",
"utm_source": "google",
"utm_medium": "cpc",
"utm_campaign": "brand-search",
"utm_content": null,
"utm_term": "lead attribution",
"campaign": "Brand Search",
"campaign_id": "1234567890",
"ad_set": "Brand Exact",
"ad_set_id": "2345678901",
"ad": "RSA 1",
"ad_id": "3456789012",
"keyword": "lead attribution",
"keyword_id": "4567890123",
"placement": null,
"gclid": "EAIaIQobChMI_example",
"wbraid": null,
"gbraid": null,
"fbclid": null,
"li_fat_id": null,
"msclkid": null,
"rdt_cid": null,
"twclid": null,
"oppref": null,
"tblci": null,
"obclid": null,
"ttclid": null,
"landing_page": "/pricing",
"full_url": "https://acme.com/pricing?utm_source=google&utm_medium=cpc",
"referrer_domain": "google.com",
"device_type": "desktop",
"os": "macOS",
"browser": "Chrome",
"country": "DE",
"city": "Berlin"
}
},
"conversions": [
{
"id": "11223344-5566-4788-99aa-bbccddeeff00",
"type": "Deal won",
"occurred_at": "2026-10-21T14:00:00Z",
"revenue": 4800,
"cash_collected": 4800,
"currency": "EUR",
"original_revenue": 4800,
"original_currency": "EUR",
"form_name": null,
"first_source_channel": "Google Ads",
"first_source_channel_key": "google_ads",
"last_source_channel": "LinkedIn Ads",
"last_source_channel_key": "linkedin_ads"
}
],
"clicks": [
{
"id": "aa00bb11-cc22-4d33-8e44-ff5566778899",
"clicked_at": "2026-10-02T08:14:03Z",
"channel": "Google Ads",
"channel_key": "google_ads",
"utm_source": "google",
"utm_medium": "cpc",
"utm_campaign": "brand-search",
"utm_content": null,
"utm_term": "lead attribution",
"campaign": "Brand Search",
"campaign_id": "1234567890",
"ad_set": "Brand Exact",
"ad_set_id": "2345678901",
"ad": "RSA 1",
"ad_id": "3456789012",
"keyword": "lead attribution",
"keyword_id": "4567890123",
"placement": null,
"gclid": "EAIaIQobChMI_example",
"wbraid": null,
"gbraid": null,
"fbclid": null,
"li_fat_id": null,
"msclkid": null,
"rdt_cid": null,
"twclid": null,
"oppref": null,
"tblci": null,
"obclid": null,
"ttclid": null,
"landing_page": "/pricing",
"full_url": "https://acme.com/pricing?utm_source=google&utm_medium=cpc",
"referrer_domain": "google.com",
"device_type": "desktop",
"os": "macOS",
"browser": "Chrome",
"country": "DE",
"city": "Berlin"
}
]
},
"meta": {
"current_page": 1,
"per_page": 20,
"last_page": 1,
"total": 1,
"max_per_page": 50
}
}meta paginates the clicks; the conversions come whole.
Tracking domains, the onboarding state, the script check, stack detection and the CRM webhook details. Scope: tracking.
/tracking-domainsLists the workspace's tracking domains, oldest first.
Scope tracking
Query parameters
pageintegerPage number. Defaults to 1, minimum 1.
per_pageintegerItems per page. Defaults to 20, maximum 50. A larger value is clamped to 50, a value below 1 falls back to 20.
Example request
curl "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/tracking-domains" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Example response
{
"success": true,
"data": [
{
"id": "c3d4e5f6-0718-293a-4b5c-6d7e8f901a2b",
"url": "track.acme.com",
"root_url": "acme.com",
"status": "success",
"status_meaning": "...",
"free_ssl": true,
"cname_destination": "package.leadjourney.io",
"created_at": "2026-09-01T10:00:00Z"
}
],
"meta": {
"current_page": 1,
"per_page": 20,
"last_page": 1,
"total": 1,
"max_per_page": 50
}
}status is initialize, process, fail, success or disabled.
/tracking-domainsAdds a tracking domain and starts its verification. Point a CNAME at package.leadjourney.io.
Scope tracking
Request body
urlstringA bare host: no https://, no www., at least one dot, 5 to 253 characters. Must be unique across LeadJourney.
root_urlstringMinimum 5 characters.
Example request
curl -X POST "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/tracking-domains" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{
"url": "track.acme.com",
"root_url": "acme.com"
}'Example response
{
"success": true,
"data": {
"id": "c3d4e5f6-0718-293a-4b5c-6d7e8f901a2b",
"url": "track.acme.com",
"status": "initialize",
"cname_destination": "package.leadjourney.io",
"next_step": "..."
}
}/tracking-domains/{domain}Returns one tracking domain and its verification status.
Scope tracking
Path parameters
domainuuidDomain id.
Errors
not_foundThe domain is not in this workspace.
Example request
curl "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/tracking-domains/DOMAIN_ID" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Example response
{
"success": true,
"data": {
"id": "c3d4e5f6-0718-293a-4b5c-6d7e8f901a2b",
"url": "track.acme.com",
"root_url": "acme.com",
"status": "success",
"status_meaning": "...",
"free_ssl": true,
"cname_destination": "package.leadjourney.io",
"created_at": "2026-09-01T10:00:00Z"
}
}/tracking-domains/{domain}Changes the host or the root URL. Verification runs again for the new host.
Scope tracking
Path parameters
domainuuidDomain id.
Request body
urlstringSame rules as on create.
root_urlstringSame rules as on create.
Errors
not_foundThe domain is not in this workspace.
invalid_requestNeither url nor root_url was sent.
Example request
curl -X PATCH "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/tracking-domains/DOMAIN_ID" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{
"url": "go.acme.com"
}'Example response
{
"success": true,
"data": {
"id": "c3d4e5f6-0718-293a-4b5c-6d7e8f901a2b",
"url": "go.acme.com",
"root_url": "acme.com",
"status": "initialize",
"note": "..."
}
}/tracking-domains/{domain}/retryResets a failed domain to initialize and queues its verification again.
Scope tracking
Path parameters
domainuuidDomain id.
Errors
not_foundThe domain is not in this workspace.
invalid_stateThe domain's status is not fail.
Example request
curl -X POST "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/tracking-domains/DOMAIN_ID/retry" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Example response
{
"success": true,
"data": {
"id": "c3d4e5f6-0718-293a-4b5c-6d7e8f901a2b",
"url": "track.acme.com",
"status": "initialize",
"note": "..."
}
}/tracking-domains/{domain}Deletes a tracking domain. Destructive: every link on that host stops working immediately.
Scope tracking
Path parameters
domainuuidDomain id.
Request body
confirmbooleanMust be true. Read from the body or the query string.
Destructive. Requires confirm: true, otherwise 409 confirmation_required. Deleting a tracking domain breaks every link on that host, at once.
Errors
not_foundThe domain is not in this workspace.
confirmation_requiredconfirm: true was not sent. The message says how many short links are on the host.
Example request
curl -X DELETE "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/tracking-domains/DOMAIN_ID" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{
"confirm": true
}'Example response
{
"success": true,
"data": {
"id": "c3d4e5f6-0718-293a-4b5c-6d7e8f901a2b",
"url": "track.acme.com",
"deleted": true
}
}/tracking/onboarding-statusThe workspace's onboarding state, the live tracking state and what still blocks it.
Scope tracking
Example request
curl "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/tracking/onboarding-status" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Example response
{
"success": true,
"data": {
"onboarding": {
"current_step": "tracking_script",
"completed_steps": [
"account_created",
"profile_setup",
"traffic_channels",
"ad_platforms",
"tracking_domain"
],
"is_completed": false,
"checklist": {
"account_created": true,
"profile_setup": true,
"traffic_channels": true,
"ad_platforms": true,
"tracking_domain": true,
"tracking_script": false,
"events": false,
"contact_forms": false,
"crm_webhooks": false
},
"stack": "...",
"existing_events": [],
"owner_profile": {
"first_name": "Maria",
"last_name": "Schulz",
"phone": "+4915112345678",
"email": "[email protected]"
},
"company_info": {
"name": "Acme GmbH",
"country": "DE",
"region": "Berlin",
"city": "Berlin",
"street": "Example Street 1",
"postal_code": "10115"
},
"timezone_info": {
"time_zone": "Europe/Berlin",
"currency": "EUR",
"time_format": "24h"
}
},
"live_state": {
"tracking_domains": [
{
"url": "track.acme.com",
"status": "success"
}
],
"verified_domains": 1,
"conversion_events": 0
},
"blockers": [
"..."
]
}
}The onboarding object is shown with the keys documented here; it may carry more.
/tracking/verify-scriptChecks whether the tracking script is installed on a page.
Scope tracking
Request body
urlstringMax 2048. https:// is prepended when no scheme is given, and a trailing / is stripped.
Example request
curl -X POST "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/tracking/verify-script" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{
"url": "acme.com/pricing"
}'Example response
{
"success": true,
"data": {
"is_installed": true,
"message": "...",
"checked_url": "https://acme.com/pricing",
"caveat": "..."
}
}Shown with the keys documented here; the check may return more.
/tracking/detect-stackDetects the CMS of a site and the form builders on up to five pages, with instructions for each.
Scope tracking
Request body
urlstringMax 2048.
form_urlsstring[]At most 5 items, each max 2048. Defaults to [url].
Example request
curl -X POST "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/tracking/detect-stack" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{
"url": "https://acme.com",
"form_urls": [
"https://acme.com/contact"
]
}'Example response
{
"success": true,
"data": {
"url": "https://acme.com",
"cms": "...",
"cms_error": null,
"note": "...",
"form_builders": [
{
"url": "https://acme.com/contact",
"builder": "...",
"has_form": true,
"has_lj_clickid": false,
"instructions": "...",
"details": "...",
"knowledge_base_url": "..."
}
]
}
}A form_builders item carries error when that page could not be checked.
/tracking/crm-webhook-infoThe postback URL and secret, the parameters a CRM webhook sends, an example payload, the affiliate networks and the CRM's instructions. The answer contains the workspace's postback secret: treat it like a password.
Scope tracking
Query parameters
crmstringMax 100. Selects which CRM's instructions are returned.
Example request
curl "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/tracking/crm-webhook-info?crm=hubspot" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Example response
{
"success": true,
"data": {
"postback_url": "...",
"postback_secret": "<postback secret>",
"authentication": {
"method": "...",
"header_example": "...",
"query_example": "..."
},
"parameters": {
"required_one_of": [
"..."
],
"required": [
"..."
],
"optional": [
"..."
]
},
"conversion_types": [
"..."
],
"example_payload": {
"...": "..."
},
"affiliate_networks": [
{
"slug": "...",
"label": "...",
"postback_url": "...",
"configured": false,
"sources": [
{
"name": "...",
"api_key": "<api key>"
}
]
}
],
"crm_instructions": "..."
}
}Custom traffic channels, tracking link templates per channel, and short links on a verified tracking domain. Scope: traffic_channels.
/traffic-channelsLists the workspace's traffic channels, built-in and custom, ordered by order. Deleted channels are left out.
Scope traffic_channels
Query parameters
pageintegerPage number. Defaults to 1, minimum 1.
per_pageintegerItems per page. Defaults to 20, maximum 50. A larger value is clamped to 50, a value below 1 falls back to 20.
Example request
curl "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/traffic-channels" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Example response
{
"success": true,
"data": [
{
"id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"key": "close_crm",
"label": "Close CRM",
"description": "Leads from Close's referral links",
"type": "other",
"is_active": true,
"is_custom": true,
"referrer_domains": [
"close.com"
],
"order": 12
}
],
"meta": {
"current_page": 1,
"per_page": 20,
"last_page": 1,
"total": 1,
"max_per_page": 50
}
}/traffic-channelsCreates a custom traffic channel. Its key is derived from the label: snake case, lower case.
Scope traffic_channels
Request body
labelstringMax 255.
descriptionstringMax 1000.
traffic_channel_typestringThe channel's type.
Allowed: paid, organic_search, ai_search, organic_social, other
referrer_domainsstring[]At most 20, each max 255 and a valid domain such as close.com.
Errors
key_conflictThe derived key collides with a built-in key, or a channel with that name exists.
referrer_conflictAnother channel already claims one of the domains.
Example request
curl -X POST "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/traffic-channels" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{
"label": "Close CRM",
"traffic_channel_type": "other",
"referrer_domains": [
"close.com"
]
}'Example response
{
"success": true,
"data": {
"id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"key": "close_crm",
"label": "Close CRM",
"type": "other",
"is_active": true,
"is_custom": true,
"referrer_domains": [
"close.com"
],
"next_step": "..."
}
}/traffic-channels/{channel}Changes a channel. On a built-in channel only is_active can change. Renaming re-derives the key, and links published with the old key are no longer classified.
Scope traffic_channels
Path parameters
channeluuidChannel id.
Request body
labelstringMax 255. Renaming re-derives the key.
descriptionstringMax 1000.
traffic_channel_typestringThe channel's type.
Allowed: paid, organic_search, ai_search, organic_social, other
is_activebooleanThe one field a built-in channel accepts.
referrer_domainsstring[]Replaces the whole list; [] clears it. Same limits as on create.
Renaming a channel re-derives its key. The answer's note warns that links published with the old key will no longer be classified.
Errors
not_foundThe channel is not in this workspace.
built_in_channelAnything other than is_active was sent for a built-in channel.
key_conflictThe new key collides with an existing one.
referrer_conflictAnother channel already claims one of the domains.
invalid_requestNothing to change.
Example request
curl -X PATCH "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/traffic-channels/CHANNEL_ID" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{
"is_active": false
}'Example response
{
"success": true,
"data": {
"id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"key": "close_crm",
"label": "Close CRM",
"type": "other",
"is_active": false,
"is_custom": true,
"referrer_domains": [
"close.com"
],
"note": null
}
}/traffic-channels/{channel}Soft deletes a custom channel. Built-in channels cannot be deleted.
Scope traffic_channels
Path parameters
channeluuidChannel id.
Request body
confirmbooleanMust be true. Read from the body or the query string.
Destructive. Requires confirm: true, otherwise 409 confirmation_required.
Errors
not_foundThe channel is not in this workspace.
confirmation_requiredconfirm: true was not sent.
built_in_channelThe channel is built in.
Example request
curl -X DELETE "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/traffic-channels/CHANNEL_ID" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{
"confirm": true
}'Example response
{
"success": true,
"data": {
"id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"key": "close_crm",
"label": "Close CRM",
"deleted": true
}
}/utm/channelsEvery channel a tracking link can be built for, by kind, with where its template goes. Not paginated.
Scope traffic_channels
Example request
curl "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/utm/channels" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Example response
{
"success": true,
"data": {
"paid": [
{
"channel": "meta_ads",
"name": "Meta Ads",
"kind": "paid",
"where_to_add": "..."
}
],
"organic": [
{
"channel": "linkedin_organic",
"name": "LinkedIn",
"kind": "organic",
"default_source": "...",
"default_medium": "...",
"suggested_contexts": [
"..."
]
}
],
"email": {
"channel": "email",
"kind": "email",
"merge_tag_tools": [
"mailchimp",
"..."
],
"note": "..."
},
"fixed": [
{
"channel": "gmb",
"name": "Google Business Profile",
"kind": "fixed",
"lj_channel": "gmb",
"where_to_add": "..."
}
],
"custom": [
{
"channel": "close_crm",
"name": "Close CRM",
"kind": "custom"
}
]
}
}Lists shortened. paid: meta_ads, linkedin_ads, google_ads, bing_ads, reddit_ads, x_ads, taboola_ads, outbrain_ads, tiktok_ads, chatgpt_ads. organic: linkedin_organic, youtube_organic, facebook_organic, instagram_organic, tiktok_organic, pinterest_organic, snapchat_organic. fixed: gmb. custom: the workspace's own channels.
/utm/buildBuilds the tracking parameters or the full link for a channel. Pure computation, nothing is stored. The answer's shape depends on the channel's kind.
Scope traffic_channels
Request body
channelstringMax 190. A channel from /utm/channels.
destination_urlstringA URL, max 2048. Ignored for paid channels.
with_utmbooleanPaid channels only. Defaults to true: adds utm parameters to the platform's lj parameters.
campaignstringMax 190. Becomes utm_campaign, or lj_c_id on fixed and custom channels.
contentstringMax 190. Becomes utm_content, or lj_ad_id on fixed and custom channels.
termstringMax 190. Becomes utm_term, or lj_as_id on fixed and custom channels.
mediumstringMax 190. Becomes utm_medium, or lj_placement on fixed and custom channels.
sourcestringMax 190. Becomes utm_source.
email_toolstringEmail channel: sets the email parameter to this tool's merge tag.
Allowed: activecampaign, aweber, brevo, cleverreach, clickfunnels, convertkit, drip, everwebinar, getresponse, hubspot, intercom, kajabi, kartra, keap, klaviyo, lemlist, mailchimp, maropost, omnisend, ontraport, sendgrid, sendlane, sendy
Errors
unknown_channelThe channel is not one of /utm/channels.
Example request
curl -X POST "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/utm/build" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{
"channel": "linkedin_organic",
"destination_url": "https://acme.com/webinar",
"campaign": "october-webinar"
}'Example response
{
"success": true,
"data": {
"channel": "linkedin_organic",
"kind": "organic",
"parameters": {
"utm_source": "...",
"utm_medium": "...",
"utm_campaign": "october-webinar"
},
"url": "https://acme.com/webinar?utm_source=...&utm_medium=...&utm_campaign=october-webinar",
"suggested_contexts": [
"..."
]
}
}By kind. paid: { channel, kind, template, destination_url: null, where_to_add, note }, template being the platform's lj parameters plus utm ones when with_utm is true. organic: { channel, kind, parameters, url, suggested_contexts }. email: { channel, kind, parameters, url, note }, utm_source defaulting to email. fixed and custom: { channel, kind, parameters, url }, fixed adding where_to_add and note; the channel becomes lj_channel.
/short-linksCreates a short link on a verified tracking domain.
Scope traffic_channels
Request body
domain_iduuidA tracking domain of this workspace whose status is success.
slugstringMax 64. Lowercased, spaces and underscores become -, other characters are stripped; the result must match ^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$.
destination_urlstringA URL, max 2048.
Errors
invalid_slugNothing valid is left of the slug after sanitising.
not_foundThe domain is unknown.
domain_not_verifiedThe domain's status is not success.
slug_takenThe slug is already used on that domain.
Example request
curl -X POST "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/short-links" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{
"domain_id": "c3d4e5f6-0718-293a-4b5c-6d7e8f901a2b",
"slug": "october-webinar",
"destination_url": "https://acme.com/webinar?utm_source=linkedin"
}'Example response
{
"success": true,
"data": {
"id": "7b6a5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
"short_url": "https://track.acme.com/october-webinar",
"destination_url": "https://acme.com/webinar?utm_source=linkedin",
"domain": "track.acme.com",
"slug": "october-webinar"
}
}List, create and revoke the workspace's API tokens over the API itself. Scope: tokens.
/api-tokensLists the workspace's tokens, newest first. is_current marks the token making the request.
Scope tokens
Query parameters
pageintegerPage number. Defaults to 1, minimum 1.
per_pageintegerItems per page. Defaults to 20, maximum 50. A larger value is clamped to 50, a value below 1 falls back to 20.
Example request
curl "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/api-tokens" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Example response
{
"success": true,
"data": [
{
"id": "e5f6a7b8-c9d0-4e1f-8a2b-3c4d5e6f7a8b",
"name": "Reporting script",
"last_four": "XXXX",
"scopes": [
"reports",
"leads"
],
"active": true,
"last_used_at": "2026-10-24T17:40:00Z",
"expires_at": "2027-10-01T23:59:59Z",
"revoked_at": null,
"created_at": "2026-10-01T09:00:00Z",
"is_current": true
}
],
"meta": {
"current_page": 1,
"per_page": 20,
"last_page": 1,
"total": 1,
"max_per_page": 50
}
}The hash and the plaintext never appear here.
/api-tokensMints a token for this workspace. The plaintext is in the answer once and never again. A token can only grant scopes the acting token holds.
Scope tokens
Request body
namestringMax 255.
scopesstring[]At least one valid scope.
Allowed: reports, tags, leads, tracking, traffic_channels, agency.workspaces, tokens
expires_atdateAfter now and at most 360 days ahead. Left out, the token never expires.
The plaintext token is returned once, in this answer. Store it before you do anything else.
Errors
scope_escalationA requested scope is one the acting token does not hold.
scope_unavailableagency.workspaces on a workspace that is not an agency HQ.
token_limit_reachedThe workspace already has 5 active tokens.
Example request
curl -X POST "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/api-tokens" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{
"name": "Reporting script",
"scopes": [
"reports",
"leads"
],
"expires_at": "2027-10-01"
}'Example response
{
"success": true,
"data": {
"token": "ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"warning": "...",
"id": "e5f6a7b8-c9d0-4e1f-8a2b-3c4d5e6f7a8b",
"name": "Reporting script",
"last_four": "XXXX",
"scopes": [
"reports",
"leads"
],
"active": true,
"last_used_at": "2026-10-24T17:40:00Z",
"expires_at": "2027-10-01T23:59:59Z",
"revoked_at": null,
"created_at": "2026-10-01T09:00:00Z"
}
}created_by_user_id is copied from the token making the request.
/api-tokens/{token}Revokes a token (it is kept with revoked_at set). A token may revoke itself; was_current says it did.
Scope tokens
Path parameters
tokenuuidToken id.
Errors
not_foundThe token is not in this workspace.
Example request
curl -X DELETE "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/api-tokens/TOKEN_ID" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Example response
{
"success": true,
"data": {
"id": "e5f6a7b8-c9d0-4e1f-8a2b-3c4d5e6f7a8b",
"name": "Reporting script",
"last_four": "XXXX",
"scopes": [
"reports",
"leads"
],
"active": false,
"last_used_at": "2026-10-24T17:40:00Z",
"expires_at": "2027-10-01T23:59:59Z",
"revoked_at": "2026-10-25T10:00:00Z",
"created_at": "2026-10-01T09:00:00Z",
"was_current": false
}
}List an agency's client workspaces and create new ones, each with its own provisioning token. Scope: agency.workspaces, on the agency HQ workspace only.
/agency/workspacesLists the agency's client workspaces and its plan quota. Not paginated. The answer contains each workspace's postback secret.
Scope agency.workspaces
Errors
not_an_agencyThe workspace has no agency owner.
not_agency_hqThe workspace is not the agency HQ.
Example request
curl "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/agency/workspaces" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Example response
{
"success": true,
"data": [
{
"id": "3a4b5c6d-7e8f-4091-a2b3-c4d5e6f70819",
"name": "Client: Nordholm",
"postback_secret": "<postback secret>",
"role": "agency",
"has_full_access": true,
"permissions": [],
"report_permissions": [],
"allowed_traffic_channel_ids": [],
"onboarding_required": true,
"monthly_advertising_spend": null,
"tracking_v2_enabled": true,
"link_decoration_enabled": false,
"cookieless_tracking_enabled": false,
"affiliate_features_enabled": false,
"call_tracking_enabled": false,
"chat_tracking_enabled": false,
"audience_sync_enabled": false,
"automations_enabled": false,
"meta_postback_mode_enabled": false,
"postback_timing_enabled": false,
"blocked": {
"is_blocked": false,
"type": null,
"reason": null,
"blocked_at": null
},
"trial": {
"is_on_trial": false,
"trial_expired": false,
"trial_ends_at": null,
"has_subscription": true
}
}
],
"quota": {
"used": 4,
"allowed": 10,
"is_unlimited": false,
"remaining": 6,
"within_quota": true
}
}role, has_full_access, permissions, report_permissions and allowed_traffic_channel_ids describe the agency's access to that workspace.
/agency/workspacesCreates a real user account and workspace for a client, sends the invitation email and, by default, issues a provisioning token for it.
Scope agency.workspaces
Request body
workspace_namestringMax 255.
first_namestringMax 255.
last_namestringMax 255.
emailstringA deliverable address (checked against DNS). The invitation goes here.
phonestringMax 50.
issue_api_tokenbooleanDefaults to true: the answer carries a provisioning token for the new workspace.
One creation every 30 minutes per agency HQ (the cooldown starts only after a successful creation), and the plan's workspace quota applies. The provisioning token is named Agency provisioning, carries every scope except agency.workspaces (tokens included) and expires in 360 days.
Errors
not_an_agencyThe workspace has no agency owner.
not_agency_hqThe workspace is not the agency HQ.
rate_limitedThe 30 minute cooldown is running. Body carries scope: agency_workspace_creation and retry_after, plus a Retry-After header.
plan_limit_reachedThe plan's workspace quota is used up. Body: { message, error, limit, used, allowed }, with no success key. Until enforcement is switched on for the workspace the quota is recorded but not refused.
Example request
curl -X POST "https://api.leadjourney.io/api/v1/public/workspaces/YOUR_WORKSPACE_ID/agency/workspaces" \
-H "Authorization: Bearer ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{
"workspace_name": "Client: Nordholm",
"first_name": "Jana",
"last_name": "Lorenz",
"email": "[email protected]"
}'Example response
{
"success": true,
"data": {
"id": "3a4b5c6d-7e8f-4091-a2b3-c4d5e6f70819",
"name": "Client: Nordholm",
"...": "the workspace object, as in the list"
},
"api_token": {
"token": "ljw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"warning": "...",
"expires_in_days": 360,
"id": "e5f6a7b8-c9d0-4e1f-8a2b-3c4d5e6f7a8b",
"name": "Agency provisioning",
"last_four": "XXXX",
"scopes": [
"reports",
"tags",
"leads",
"tracking",
"traffic_channels",
"tokens"
],
"active": true,
"last_used_at": "2026-10-24T17:40:00Z",
"expires_at": "2027-10-01T23:59:59Z",
"revoked_at": null,
"created_at": "2026-10-01T09:00:00Z"
}
}api_token is left out when issue_api_token is false.
19 endpoints
The API the LeadJourney Zapier app runs on. It authenticates with a user token from Settings, then API & Integrations, which reaches every workspace that user can open, rather than a workspace token (ljw_) limited to one workspace and its scopes. Paths below are relative to the base URL https://api.leadjourney.io/api.
https://api.leadjourney.io/apiIdentify the authenticated token and list the workspaces it can act on.
/v1/profileReturns the user that owns the API token. Used to validate a connection.
Requires Bearer token
Example request
curl "https://api.leadjourney.io/api/v1/profile" \
-H "Authorization: Bearer YOUR_TOKEN"Example response
{
"success": true,
"data": {
"user": {
"id": "9b1c0e2a-3f4d-4a6b-8c7e-1d2f3a4b5c6d",
"email": "[email protected]",
"has_verified_email": true,
"current_workspace_id": "2f8a1b3c-4d5e-6f70-8192-a3b4c5d6e7f8"
},
"has_verified_email": true,
"profile": {
"first_name": "Jamie",
"last_name": "Rivera",
"company_name": "Acme Inc.",
"phone": "+15551234567"
},
"user_hash": "a1b2c3d4e5f6"
}
}/v1/profile/workspacesLists every workspace the token can act on. The workspace id is used in the path of all workspace-scoped endpoints.
Requires Bearer token
Example request
curl "https://api.leadjourney.io/api/v1/profile/workspaces" \
-H "Authorization: Bearer YOUR_TOKEN"Example response
{
"success": true,
"data": {
"workspaces": [
{
"id": "2f8a1b3c-4d5e-6f70-8192-a3b4c5d6e7f8",
"name": "Acme Marketing",
"role": "owner",
"has_full_access": true,
"onboarding_required": false,
"tracking_v2_enabled": true,
"trial": {
"is_on_trial": false,
"trial_expired": false,
"trial_ends_at": null,
"has_subscription": true
}
}
]
}
}Read conversion types and push leads or revenue conversions into a workspace.
/v1/workspaces/{workspace}/conversionsReturns the conversion types defined in the workspace.
Requires Bearer token
Path parameters
workspaceuuidWorkspace id.
Example request
curl "https://api.leadjourney.io/api/v1/workspaces/YOUR_WORKSPACE_ID/conversions" \
-H "Authorization: Bearer YOUR_TOKEN"Example response
{
"success": true,
"data": {
"conversions": [
{
"id": "7c9e6a1b-2d3f-4051-8627-a8b9c0d1e2f3",
"type": "Purchase",
"default_key": null,
"category": "Sales",
"mode": 1,
"send_to_ads": true,
"include_revenue": true,
"include_personal_details": false,
"created_at": "2026-05-01T10:15:00Z",
"events_count": 128,
"latest_event_at": "2026-06-08T19:02:11Z"
}
]
}
}/v1/workspaces/{workspace}/conversionsCreates a new conversion type in the workspace.
Requires Bearer token
Path parameters
workspaceuuidWorkspace id.
Request body
typestringConversion type name. Minimum 2 characters, unique per workspace.
modeintegerHandling mode: 1 = create, 2 = ignore, 3 = edit, 4 = keep.
Allowed: 1, 2, 3, 4
send_to_adsbooleanForward matching conversions to connected ad platforms.
descriptionstringFree-text description. Max 255 characters.
categorystringOptional grouping category. Max 100 characters.
include_revenuebooleanWhether conversions of this type carry revenue.
include_personal_detailsbooleanWhether personal details are captured with this conversion.
Example request
curl -X POST "https://api.leadjourney.io/api/v1/workspaces/YOUR_WORKSPACE_ID/conversions" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "<type>",
"mode": "1"
}'Example response
{
"success": true
}/v1/workspaces/{workspace}/conversions/trackRecords a conversion event against a lead. The lead is resolved by click_id, then email, then phone, creating a synthetic lead when none matches. Provide a type to record a conversion, or a tag to only apply a webhook tag.
Requires Bearer token
Path parameters
workspaceuuidWorkspace id.
Request body
click_iduuidLeadJourney click id. One of click_id, email, or phone is required.
emailstringLead email. Max 255 characters.
phonestringLead phone. Max 50 characters.
typestringConversion type name. Required unless a tag is provided.
revenuestringRevenue amount. Required when the conversion type carries revenue.
cash_collectedstringCash collected amount.
currencystringISO 4217 currency code (3 letters), e.g. USD.
first_namestringFirst name. Max 255 characters.
last_namestringLast name. Max 255 characters.
full_namestringFull name. Split into first/last when those are absent. Max 511 characters.
tagstringTag name to apply when no conversion type is sent. Max 50 characters.
zipstringPostal code. Max 20 characters.
custom_fieldsobjectKey-value pairs validated against the workspace custom fields.
At least one of click_id, email, or phone must identify the lead.
Example request
curl -X POST "https://api.leadjourney.io/api/v1/workspaces/YOUR_WORKSPACE_ID/conversions/track" \
-H "Authorization: Bearer YOUR_TOKEN"Example response
{
"success": true
}/v1/workspaces/{workspace}/conversions/track-leadCaptures a lead's identity without a revenue conversion, using the workspace default lead conversion. Resolution and de-duplication run downstream.
Requires Bearer token
Path parameters
workspaceuuidWorkspace id.
Request body
click_iduuidLeadJourney click id. One of click_id, email, or phone is required.
emailstringLead email. Max 255 characters.
phonestringLead phone. Max 50 characters.
first_namestringFirst name. Max 255 characters.
last_namestringLast name. Max 255 characters.
full_namestringFull name. Split into first/last when those are absent. Max 511 characters.
zipstringPostal code. Max 20 characters.
At least one of email, phone, or click_id must be provided.
Example request
curl -X POST "https://api.leadjourney.io/api/v1/workspaces/YOUR_WORKSPACE_ID/conversions/track-lead" \
-H "Authorization: Bearer YOUR_TOKEN"Example response
{
"success": true
}Read, create, update and delete the custom fields stored on each lead.
/v1/workspaces/{workspace}/custom-fieldsReturns the custom fields defined in the workspace.
Requires Bearer token
Path parameters
workspaceuuidWorkspace id.
Example request
curl "https://api.leadjourney.io/api/v1/workspaces/YOUR_WORKSPACE_ID/custom-fields" \
-H "Authorization: Bearer YOUR_TOKEN"Example response
{
"success": true,
"data": {
"custom_fields": [
{
"id": 14,
"name": "Plan",
"key": "plan",
"type": "text",
"available_in_reports": true,
"is_default": false,
"is_locked": false,
"sort_order": 3,
"created_at": "2026-03-20T09:30:00Z",
"updated_at": "2026-03-20T09:30:00Z"
}
]
}
}/v1/workspaces/{workspace}/custom-fieldsCreates a custom field. Up to 50 user-defined fields per workspace.
Requires Bearer token
Path parameters
workspaceuuidWorkspace id.
Request body
namestringDisplay name. 1 to 80 characters.
typestringField data type.
Allowed: text, number, currency
keystringWebhook key (lowercase, starts with a letter, max 64, unique). Auto-generated from name when omitted.
available_in_reportsbooleanShow the field in reports. Defaults to true.
Example request
curl -X POST "https://api.leadjourney.io/api/v1/workspaces/YOUR_WORKSPACE_ID/custom-fields" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "<name>",
"type": "text"
}'Example response
{
"success": true,
"data": {
"custom_field": {
"id": 21,
"name": "Plan",
"key": "plan",
"type": "text",
"available_in_reports": true,
"is_default": false,
"is_locked": false,
"sort_order": 4,
"created_at": "2026-06-09T12:00:00Z",
"updated_at": "2026-06-09T12:00:00Z"
}
}
}/v1/workspaces/{workspace}/custom-fields/{customField}Updates a custom field's name, type or report visibility. The key cannot be changed.
Requires Bearer token
Path parameters
workspaceuuidWorkspace id.
customFieldintegerCustom field id.
Request body
namestringDisplay name. 1 to 80 characters.
typestringField data type.
Allowed: text, number, currency
available_in_reportsbooleanShow the field in reports.
Every field is optional. The key cannot be changed.
Errors
Fields managed by LeadJourney (is_locked: true): {"message": "This custom field is managed by LeadJourney and cannot be edited."}
Example request
curl -X POST "https://api.leadjourney.io/api/v1/workspaces/YOUR_WORKSPACE_ID/custom-fields/CUSTOM_FIELD_ID" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Plan tier",
"available_in_reports": false
}'Example response
{
"success": true,
"data": {
"custom_field": {
"id": 21,
"name": "Plan tier",
"key": "plan",
"type": "text",
"available_in_reports": false,
"is_default": false,
"is_locked": false,
"sort_order": 4,
"created_at": "2026-06-09T12:00:00Z",
"updated_at": "2026-06-10T08:30:00Z"
}
}
}/v1/workspaces/{workspace}/custom-fields/{customField}Deletes a custom field from the workspace.
Requires Bearer token
Path parameters
workspaceuuidWorkspace id.
customFieldintegerCustom field id.
Errors
Fields managed by LeadJourney (is_locked: true): {"message": "This custom field is managed by LeadJourney and cannot be deleted."}
The field belongs to another workspace.
Example request
curl -X DELETE "https://api.leadjourney.io/api/v1/workspaces/YOUR_WORKSPACE_ID/custom-fields/CUSTOM_FIELD_ID" \
-H "Authorization: Bearer YOUR_TOKEN"Example response
The body of a successful delete is not documented here.
Find a single lead by click id, email, or phone.
/v1/workspaces/{workspace}/zapier/leads/findLooks up a single lead by click id, email, or phone. Returns null in data.lead when no match is found.
Requires Bearer token
Path parameters
workspaceuuidWorkspace id.
Query parameters
click_idstringLeadJourney click id. One of click_id, email, or phone is required.
emailstringLead email.
phonestringLead phone.
Example request
curl "https://api.leadjourney.io/api/v1/workspaces/YOUR_WORKSPACE_ID/zapier/leads/find" \
-H "Authorization: Bearer YOUR_TOKEN"Example response
{
"success": true,
"data": {
"lead": {
"id": "5d6e7f80-1a2b-3c4d-5e6f-708192a3b4c5",
"click_id": "0c1d2e3f-4a5b-6c7d-8e9f-a0b1c2d3e4f5",
"email": "[email protected]",
"phone": null,
"first_name": "Sam",
"last_name": "Lee",
"created_at": "2026-06-01T14:22:00Z",
"revenue": 199,
"conversions_count": 2,
"first_source": "google",
"last_source": "email",
"status": "converted",
"tags": [
{
"id": "a1f2e3d4-5c6b-7a89-90b1-c2d3e4f5a6b7",
"name": "Newsletter",
"color": "#03c879",
"type": "source",
"source": "rule"
}
],
"custom_fields": {
"plan": "pro"
}
}
}
}Subscribe and unsubscribe webhook targets. Zapier uses these to power instant triggers.
/v1/workspaces/{workspace}/zapier/subscriptionsRegisters a target URL to receive events. The response id is used to unsubscribe.
Requires Bearer token
Path parameters
workspaceuuidWorkspace id.
Request body
eventstringEvent to subscribe to.
Allowed: lead.created, conversion.created, click.created
target_urlstringHTTPS URL that receives the event payload. Max 2048 characters.
Example request
curl -X POST "https://api.leadjourney.io/api/v1/workspaces/YOUR_WORKSPACE_ID/zapier/subscriptions" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"event": "lead.created",
"target_url": "<target_url>"
}'Example response
{
"success": true,
"data": {
"id": "9f8e7d6c-5b4a-3210-fedc-ba9876543210"
}
}/v1/workspaces/{workspace}/zapier/subscriptions/{subscription}Removes a webhook subscription by id.
Requires Bearer token
Path parameters
workspaceuuidWorkspace id.
subscriptionuuidSubscription id returned when it was created.
Example request
curl -X DELETE "https://api.leadjourney.io/api/v1/workspaces/YOUR_WORKSPACE_ID/zapier/subscriptions/SUBSCRIPTION_ID" \
-H "Authorization: Bearer YOUR_TOKEN"Example response
{
"success": true
}Most recent items per type. Used for trigger sample data and as a polling fallback.
/v1/workspaces/{workspace}/zapier/recent/leadsReturns the most recent leads. Used for trigger sample data and polling.
Requires Bearer token
Path parameters
workspaceuuidWorkspace id.
Example request
curl "https://api.leadjourney.io/api/v1/workspaces/YOUR_WORKSPACE_ID/zapier/recent/leads" \
-H "Authorization: Bearer YOUR_TOKEN"Example response
{
"success": true,
"data": {
"leads": [
{
"id": "5d6e7f80-1a2b-3c4d-5e6f-708192a3b4c5",
"click_id": "0c1d2e3f-4a5b-6c7d-8e9f-a0b1c2d3e4f5",
"email": "[email protected]",
"phone": null,
"first_name": "Sam",
"last_name": "Lee",
"created_at": "2026-06-08T14:22:00Z",
"revenue": 199,
"conversions_count": 2,
"first_source": "google",
"last_source": "email",
"status": "converted",
"tags": []
}
]
}
}/v1/workspaces/{workspace}/zapier/recent/conversionsReturns the most recent conversion events.
Requires Bearer token
Path parameters
workspaceuuidWorkspace id.
Example request
curl "https://api.leadjourney.io/api/v1/workspaces/YOUR_WORKSPACE_ID/zapier/recent/conversions" \
-H "Authorization: Bearer YOUR_TOKEN"Example response
{
"success": true,
"data": {
"conversions": [
{
"id": "11223344-5566-7788-99aa-bbccddeeff00",
"click_id": "0c1d2e3f-4a5b-6c7d-8e9f-a0b1c2d3e4f5",
"email": "[email protected]",
"phone": null,
"conversion_type": "Purchase",
"revenue": 199,
"currency": "USD",
"first_name": "Sam",
"last_name": "Lee",
"created_at": "2026-06-08T15:10:00Z"
}
]
}
}/v1/workspaces/{workspace}/zapier/recent/clicksReturns the most recent click and pageview events.
Requires Bearer token
Path parameters
workspaceuuidWorkspace id.
Example request
curl "https://api.leadjourney.io/api/v1/workspaces/YOUR_WORKSPACE_ID/zapier/recent/clicks" \
-H "Authorization: Bearer YOUR_TOKEN"Example response
{
"success": true,
"data": {
"clicks": [
{
"id": "aa00bb11-cc22-dd33-ee44-ff5566778899",
"click_id": "0c1d2e3f-4a5b-6c7d-8e9f-a0b1c2d3e4f5",
"entry_page": "/pricing",
"entry_full_url": "https://acme.com/pricing?utm_source=email",
"referer": "https://mail.google.com/",
"source": "email",
"campaign": "june-newsletter",
"created_at": "2026-06-08T13:05:00Z"
}
]
}
}