Conversions & Revenue
Conversion counts, daily trends, attributed revenue, and cash collected by source.
Four endpoints for querying conversion activity and revenue attribution. All
require the conversions:read scope.
Revenue means cash only
Revenue in all endpoints below refers exclusively to confirmed payments from Stripe and MercadoPago. GHL pipeline values (deal stages, closed-won projections) are never included in revenue or ROAS calculations -- they are projections, not confirmed cash.
Conversion Counts
GET /api/v1/conversionsReturns total conversions grouped by event type for the requested period.
Scope: conversions:read
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
date_from | string | Yes | Start date in YYYY-MM-DD format. |
date_to | string | Yes | End date in YYYY-MM-DD format. |
Request
curl -H "Authorization: Bearer atb_live_YOUR_KEY" \
"https://www.atribu.app/api/v1/conversions?date_from=2026-03-01&date_to=2026-03-25"const res = await fetch(
"https://www.atribu.app/api/v1/conversions?date_from=2026-03-01&date_to=2026-03-25",
{ headers: { Authorization: "Bearer atb_live_YOUR_KEY" } }
);
const { data } = await res.json();import requests
res = requests.get(
"https://www.atribu.app/api/v1/conversions",
headers={"Authorization": "Bearer atb_live_YOUR_KEY"},
params={"date_from": "2026-03-01", "date_to": "2026-03-25"},
)
data = res.json()["data"]Response
{
"data": [
{ "event_type": "lead_created", "count": 85 },
{ "event_type": "appointment_booked", "count": 42 },
{ "event_type": "payment_received", "count": 28 },
{ "event_type": "closed_won", "count": 15 }
],
"meta": {
"date_from": "2026-03-01",
"date_to": "2026-03-25",
"profile_id": "uuid"
}
}Response fields
| Field | Type | Description |
|---|---|---|
event_type | string | Conversion type (e.g., lead_created, payment_received). |
count | number | Total conversions of this type in the period. |
Daily Conversions
GET /api/v1/conversions/timeseriesReturns daily conversion counts broken down by event type. Use this to chart conversion trends over time.
Scope: conversions:read
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
date_from | string | Yes | Start date in YYYY-MM-DD format. |
date_to | string | Yes | End date in YYYY-MM-DD format. |
Request
curl -H "Authorization: Bearer atb_live_YOUR_KEY" \
"https://www.atribu.app/api/v1/conversions/timeseries?date_from=2026-03-20&date_to=2026-03-25"const res = await fetch(
"https://www.atribu.app/api/v1/conversions/timeseries?date_from=2026-03-20&date_to=2026-03-25",
{ headers: { Authorization: "Bearer atb_live_YOUR_KEY" } }
);
const { data } = await res.json();import requests
res = requests.get(
"https://www.atribu.app/api/v1/conversions/timeseries",
headers={"Authorization": "Bearer atb_live_YOUR_KEY"},
params={"date_from": "2026-03-20", "date_to": "2026-03-25"},
)
data = res.json()["data"]Response
{
"data": [
{ "date": "2026-03-20", "event_type": "lead_created", "count": 12 },
{ "date": "2026-03-20", "event_type": "payment_received", "count": 3 },
{ "date": "2026-03-21", "event_type": "lead_created", "count": 15 },
{ "date": "2026-03-21", "event_type": "appointment_booked", "count": 7 }
],
"meta": {
"date_from": "2026-03-20",
"date_to": "2026-03-25",
"profile_id": "uuid"
}
}Response fields
| Field | Type | Description |
|---|---|---|
date | string | Calendar date (YYYY-MM-DD). |
event_type | string | Conversion type. |
count | number | Number of conversions of this type on this day. |
Revenue by Day
GET /api/v1/revenueReturns daily attributed revenue and ad spend. Revenue is computed using the selected attribution model and includes cash payments only.
Scope: conversions:read
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
date_from | string | Yes | Start date in YYYY-MM-DD format. |
date_to | string | Yes | End date in YYYY-MM-DD format. |
model | string | No | Attribution model. Default last_touch. Options: first_touch, linear, time_decay, last_non_direct. |
Request
curl -H "Authorization: Bearer atb_live_YOUR_KEY" \
"https://www.atribu.app/api/v1/revenue?date_from=2026-03-20&date_to=2026-03-25&model=last_touch"const res = await fetch(
"https://www.atribu.app/api/v1/revenue?date_from=2026-03-20&date_to=2026-03-25&model=last_touch",
{ headers: { Authorization: "Bearer atb_live_YOUR_KEY" } }
);
const { data } = await res.json();import requests
res = requests.get(
"https://www.atribu.app/api/v1/revenue",
headers={"Authorization": "Bearer atb_live_YOUR_KEY"},
params={
"date_from": "2026-03-20",
"date_to": "2026-03-25",
"model": "last_touch",
},
)
data = res.json()["data"]Response
{
"data": [
{ "date": "2026-03-20", "revenue": 2400.00, "spend": 680.00 },
{ "date": "2026-03-21", "revenue": 1800.00, "spend": 720.00 },
{ "date": "2026-03-22", "revenue": 3200.00, "spend": 650.00 }
],
"meta": {
"date_from": "2026-03-20",
"date_to": "2026-03-25",
"profile_id": "uuid"
}
}Response fields
| Field | Type | Description |
|---|---|---|
date | string | Calendar date (YYYY-MM-DD). |
revenue | number | Attributed cash revenue in reporting currency. |
spend | number | Total ad spend across all platforms. |
Cash Collected
GET /api/v1/revenue/cashReturns total cash payments grouped by payment source and currency. Unlike the attributed revenue endpoint above, this shows raw payment totals regardless of attribution model.
Scope: conversions:read
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
date_from | string | Yes | Start date in YYYY-MM-DD format. |
date_to | string | Yes | End date in YYYY-MM-DD format. |
Request
curl -H "Authorization: Bearer atb_live_YOUR_KEY" \
"https://www.atribu.app/api/v1/revenue/cash?date_from=2026-03-01&date_to=2026-03-25"const res = await fetch(
"https://www.atribu.app/api/v1/revenue/cash?date_from=2026-03-01&date_to=2026-03-25",
{ headers: { Authorization: "Bearer atb_live_YOUR_KEY" } }
);
const { data } = await res.json();import requests
res = requests.get(
"https://www.atribu.app/api/v1/revenue/cash",
headers={"Authorization": "Bearer atb_live_YOUR_KEY"},
params={"date_from": "2026-03-01", "date_to": "2026-03-25"},
)
data = res.json()["data"]Response
{
"data": [
{ "source": "stripe", "currency": "USD", "total_cash": "9800.00", "count": 35 },
{ "source": "mercadopago", "currency": "MXN", "total_cash": "45000.00", "count": 12 }
],
"meta": {
"date_from": "2026-03-01",
"date_to": "2026-03-25",
"profile_id": "uuid"
}
}Response fields
| Field | Type | Description |
|---|---|---|
source | string | Payment provider (stripe, mercadopago). |
currency | string | ISO 4217 currency code. |
total_cash | string | Exact decimal string. Sum of payments in the original currency (ADR 0018 — parse before doing arithmetic). Renamed from total. |
count | number | Number of payments. |
Cash collected vs. attributed revenue
Cash collected (/revenue/cash) is the raw sum of payments, independent
of any attribution model. Attributed revenue (/revenue) distributes
payment value across the marketing touchpoints that contributed to the
conversion, based on the selected model. Use cash collected for financial
reconciliation and attributed revenue for marketing performance analysis.
Winning Campaign per Conversion
GET /api/v1/conversions/attributionEvery conversion of the window with the campaign that wins its credit, in one
keyset-paginated walk. It replaces reading
GET /api/v1/campaigns/{id}/conversions once per campaign and folding the rows:
per campaign the credit is grouped exactly as that route groups it, and the
winner is the campaign with the highest credited_weight; on a tie a direct
credit beats an inherited one, then the most recent last_touch_time, then the
lowest campaign_external_id. Only conversions credited to at least one
campaign appear.
Scope: analytics:read or campaigns:read (either one). Unlike the other
endpoints on this page it does not need conversions:read.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
date_from | string | Yes | First day, YYYY-MM-DD, in the profile's timezone. |
date_to | string | Yes | Last day, inclusive. At most 366 days after date_from. |
model | string | No | Attribution model. Defaults to last_touch. |
limit | integer | No | Conversions per page, 1–1000. Defaults to 500. Anything else is a 400. |
cursor | string | No | pagination.cursor from the previous page, unchanged. |
Request
curl -H "Authorization: Bearer atb_live_YOUR_KEY" \
"https://api.atribu.app/api/v1/conversions/attribution?date_from=2026-01-01&date_to=2026-10-15&limit=1000"// Walk every page.
const rows = [];
let cursor;
do {
const params = new URLSearchParams({ date_from: "2026-01-01", date_to: "2026-10-15", limit: "1000" });
if (cursor) params.set("cursor", cursor);
const res = await fetch(`https://api.atribu.app/api/v1/conversions/attribution?${params}`, {
headers: { Authorization: "Bearer atb_live_YOUR_KEY" },
});
const page = await res.json();
rows.push(...page.data);
cursor = page.pagination.has_next ? page.pagination.cursor : undefined;
} while (cursor);import requests
rows, cursor = [], None
while True:
params = {"date_from": "2026-01-01", "date_to": "2026-10-15", "limit": 1000}
if cursor:
params["cursor"] = cursor
page = requests.get(
"https://api.atribu.app/api/v1/conversions/attribution",
headers={"Authorization": "Bearer atb_live_YOUR_KEY"},
params=params,
).json()
rows += page["data"]
if not page["pagination"]["has_next"]:
break
cursor = page["pagination"]["cursor"]Response
{
"data": [
{
"conversion_id": "00000000-0000-4000-8000-000000000001",
"outcome_event_id": "00000000-0000-4000-8000-000000000002",
"campaign_external_id": "120200000000000001",
"campaign_name": "Implants — Leads",
"credited_weight": 1,
"credited_value": "50000",
"touch_count": 3,
"campaign_touch_count": 1,
"path_length": 3,
"event_time": "2026-09-30T14:03:11.123+00:00",
"first_touch_time": "2026-09-21T22:10:05+00:00",
"last_touch_time": "2026-09-21T22:10:05+00:00",
"is_inherited": false,
"event_type": "payment_received",
"revenue_type": "cash",
"value_amount": "50000",
"currency": "CLP",
"customer_key": "ghl_contact_0001",
"is_first_payment": true
}
],
"pagination": { "has_next": true, "cursor": "eyJrIjoiY2EiLCJ0Ijo..." },
"meta": {
"model": "last_touch",
"recomputed_at": "2026-10-15T12:00:00+00:00",
"date_from": "2026-01-01",
"date_to": "2026-10-15",
"profile_id": "00000000-0000-4000-8000-0000000000aa"
}
}Response fields
| Field | Type | Description |
|---|---|---|
conversion_id | string | Atribu's conversion id. |
outcome_event_id | string | null | The outcome event id returned at ingest. outcome_event_id ?? conversion_id is a stable key. |
campaign_external_id | string | The winning campaign's platform id. |
campaign_name | string | The campaign's current name. |
credited_weight | number | The winning campaign's share of the conversion, 0–1. |
credited_value | string | null | Its credited share of the value. Exact decimal string. |
touch_count | integer | Touches in the whole path (path_length), else campaign_touch_count. |
campaign_touch_count | integer | Credited touches on the winning campaign. |
path_length | integer | null | Touches in the whole path. |
event_time | string | When the conversion happened (ISO 8601). |
first_touch_time | string | null | Earliest credited touch on the winning campaign. |
last_touch_time | string | null | Latest credited touch on the winning campaign. |
is_inherited | boolean | Credit came via a bridged lead→cash touch — never counted in ROAS. |
event_type | string | lead_created, appointment_booked, payment_received, closed_won, … |
revenue_type | string | cash, pipeline, … |
value_amount | string | null | The conversion's full value. Exact decimal string. |
currency | string | null | Reporting currency (ISO 4217). |
customer_key | string | null | CRM contact id (not a name or email). |
is_first_payment | boolean | null | The customer's first payment. null unless revenue_type is cash. |
Newest first. While pagination.has_next is true, pass pagination.cursor
back as cursor with the same other parameters; a cursor this endpoint did not
issue is a 400 invalid_parameter. There is no updated_since: an attribution
recompute re-credits conversions without changing them, so re-walk the window
(meta.recomputed_at says when the profile's attribution last changed).