Profitability: overview
How much it costs to acquire a customer, how much that customer returns and when the investment pays back: profitability metrics, time series and retention cohorts.
What this analysis answers
The Profitability API combines your store's revenue with your paid media spend (Meta Ads and Google Ads) to show whether acquiring and retaining customers is profitable. Every revenue-derived value can be converted into contribution margin, using the margin the organization configured in the V4MOS.AI platform.
Questions you can answer:
- How much does it cost to acquire a new customer (CAC)? And how much does each sale cost (CPV)?
- Does the value a customer generates over their lifetime (LTV) pay for acquiring them (LTV/CAC)?
- What is the return on media spend (ROI), and how many months does it take to pay back?
- How many customers buy for the first time, and how many come back?
- How much of each customer cohort's revenue comes back in the following months?
- Which entry products, channels, campaigns or coupons bring the customers who repurchase the most?
- How much of the revenue goes to the real cost of goods sold (COGS)?
Which endpoint to use
| Question | Endpoint |
|---|---|
| What are the consolidated indicators for the period, and how do they compare with the previous period? | GET /v1/profitability/cards |
| How many new and returning customers bought on each day or month? | GET /v1/profitability/new-vs-recurring |
| How did CAC, LTV, CPV, revenue and spend evolve month by month? | GET /v1/profitability/metrics-evolution |
| What were COGS and the average ticket on each day? | GET /v1/profitability/cmv-evolution |
| How many customers (or how much revenue) from each cohort come back in the following months? | GET /v1/profitability/cohort |
Available endpoints
- getGet Profitability Summary Cards
/v1/profitability/cardsReturns the organization's consolidated profitability indicators for the period: revenue, media spend, orders, customers, CAC, CPV, LTV,… - getGet New vs Recurring Customers Over Time
/v1/profitability/new-vs-recurringReturns a time series of new customers (first purchase in the point's period) and returning customers (had bought before) who placed an… - getGet Profitability Metrics Evolution
/v1/profitability/metrics-evolutionReturns a monthly series with CAC, LTV, CPV, LTV/CAC, revenue, orders, spend, new customers and the real COGS block for each month. - getGet Daily CMV Evolution
/v1/profitability/cmv-evolutionReturns a daily series with each day's revenue, orders, average ticket and real cost of goods sold (COGS), using the same COGS fields as… - getGet Profitability Cohort Analysis
/v1/profitability/cohortReturns a retention matrix by cohort: each row groups customers by the start of their relationship with the store, and each column shows…
Authentication
Send the x-client-id and x-client-secret headers on every request, together with the organizationId query parameter. See Authentication.
Common parameters
All endpoints use the base URL https://data.v4mos.ai and accept the parameters below.
| Parameter | Required | Format | Description |
|---|---|---|---|
organizationId | Yes | string | Organization identifier. Without it the API returns 400. |
startDate | No | YYYY-MM-DD | First day of the period (inclusive). |
endDate | No | YYYY-MM-DD | Last day of the period (inclusive). |
The /cohort endpoint also accepts view, groupBy and breakBy (see Cohorts).
startDate and endDate are applied only when sent together. If either one is missing, the API uses the organization's entire history. Always send plain calendar dates (2025-01-31), without a time.
- Unknown query parameters return
400. - Values outside the allowed list for
view,groupByorbreakByalso return400.
Examples
# Consolidated indicators from January to March 2025
curl "https://data.v4mos.ai/v1/profitability/cards?organizationId=YOUR_ORG&startDate=2025-01-01&endDate=2025-03-31" \
-H "x-client-id: YOUR_CLIENT_ID" \
-H "x-client-secret: YOUR_CLIENT_SECRET"
# Monthly metrics evolution in 2025
curl "https://data.v4mos.ai/v1/profitability/metrics-evolution?organizationId=YOUR_ORG&startDate=2025-01-01&endDate=2025-12-31" \
-H "x-client-id: YOUR_CLIENT_ID" \
-H "x-client-secret: YOUR_CLIENT_SECRET"
# Revenue retention by cohort, with quarterly columns
curl "https://data.v4mos.ai/v1/profitability/cohort?organizationId=YOUR_ORG&startDate=2024-01-01&endDate=2024-12-31&view=revenue&groupBy=quarter" \
-H "x-client-id: YOUR_CLIENT_ID" \
-H "x-client-secret: YOUR_CLIENT_SECRET"Metrics
Monetary values are in the store's currency, rounded to 2 decimal places. "× margin" means multiplied by marginPercent / 100 (see Contribution margin).
General indicators (/cards, /metrics-evolution)
| Field | What it means | How it is calculated | Unit |
|---|---|---|---|
revenue / totalRevenue | Gross revenue | Sum of order revenue | currency |
investment / totalInvestment | Paid media spend | Sum of Meta Ads and Google Ads spend | currency |
orders / totalOrders | Orders | Number of orders | count |
newCustomers | New customers | Customers whose first purchase fell in the period | count |
recurringCustomers | Returning customers | Customers who bought in the period and had bought before it | count |
customers | Active customers | newCustomers + recurringCustomers | count |
recurringOrders | Repeat orders | Orders from customers who had already bought before that order | count |
averageTicket | Average order value | revenue ÷ orders | currency |
contribution | Contribution margin | revenue × margin | currency |
contributionProfit | Contribution profit | contribution − investment | currency |
cpv | Cost per sale | investment ÷ orders | currency |
cpr | Cost per repeat order | investment ÷ recurringOrders | currency |
cac | Customer acquisition cost (average) | investment ÷ new customers | currency |
ltv | Lifetime value of customers acquired in the period | Average total revenue per customer × margin | currency |
ltvLifetime | LTV of the whole customer base, with no period filter | Average total revenue per customer × margin | currency |
retentionLtv | Part of the LTV that comes from repeat purchases | Average revenue after the first-purchase month × margin | currency |
ltvCacRatio | How many times the LTV pays for the CAC | ltv ÷ cac | ratio (e.g. 5.43 = 5.43×) |
roi | Return on media spend | (contribution − investment) ÷ investment | ratio (e.g. 1.19 = 119%) |
clv | Net value per customer after acquisition cost | ltv − cac (can be negative) | currency |
payback | Months until a cohort's accumulated margin pays for its acquisition cost | Average weighted by customer count across the cohorts that already paid back | months |
conversionRate | Conversion from the Interest stage to the Decision stage of the configured funnel | Decision ÷ Interest × 100 | % (0–100) |
Indicators by campaign strategy (/cards)
These depend on the campaign classification done in the V4MOS.AI platform (acquisition, brand, monetization).
| Field | What it means | How it is calculated | Unit |
|---|---|---|---|
campaignCac | CAC counting only spend on acquisition campaigns | Acquisition spend ÷ all new customers | currency |
acquisitionInvestment | Spend on campaigns classified as acquisition | Sum of spend | currency |
acquisitionNewCustomers | New customers brought by acquisition campaigns | Count by attribution (UTM) of the first purchase | count |
acquisitionCac | CAC of acquisition campaigns | acquisitionInvestment ÷ acquisitionNewCustomers | currency |
acquisitionContribution | Margin generated by those campaigns' customers | Revenue of those customers × margin | currency |
acquisitionLtv | Average LTV of those campaigns' customers | Average total revenue per customer × margin | currency |
acquisitionLtvCacRatio | LTV/CAC of acquisition campaigns | acquisitionLtv ÷ acquisitionCac | ratio |
acquisitionRoi | ROI of acquisition campaigns | (acquisitionContribution − spend) ÷ spend | ratio |
brandInvestment | Spend on brand campaigns | Sum of spend | currency |
brandImpressions | Impressions of brand campaigns | Sum of impressions | count |
brandNewCustomers | New customers attributed to brand campaigns | Count by first-purchase attribution | count |
brandContribution | Margin generated by those customers | Revenue of those customers × margin | currency |
brandRoi | ROI of brand campaigns | (brandContribution − spend) ÷ spend | ratio |
monetizationInvestment | Spend on monetization campaigns (selling to the existing base) | Sum of spend | currency |
monetizationContribution | Margin of orders attributed to monetization campaigns | Revenue of those orders × margin | currency |
monetizationRoi | ROI of monetization campaigns | (monetizationContribution − monetizationInvestment) ÷ monetizationInvestment | ratio |
monetizationRecurringCustomers | Returning customers with an order attributed to a monetization campaign | Count of distinct customers | count |
monetizationCpr | Cost per repeat order of monetization campaigns | monetizationInvestment ÷ repeat orders attributed to them | currency |
unclassifiedInvestment | Spend on unclassified campaigns | Sum of spend | currency |
hasAcquisitionClassification | Whether the organization has ever classified a campaign as acquisition (in any period) | — | boolean |
Cost of goods sold (/cards, /metrics-evolution, /cmv-evolution)
| Field | What it means | How it is calculated | Unit |
|---|---|---|---|
cogs | Real cost of goods sold (COGS) | Sum of the cost reported by the e-commerce platform, only on orders that have a cost | currency |
revenueWithCmv | Revenue of orders that have real COGS | Sum of revenue | currency |
revenueWithoutCmv | Revenue of orders without real COGS | revenue − revenueWithCmv | currency |
marginBasis | Where the period's margin came from | cmv_real, mixed, configured_percent or no_basis | string |
blendedContribution | Contribution margin using real COGS where it exists and the configured margin elsewhere | See Important rules | currency |
Cohorts (/cohort)
| Field | What it means | How it is calculated | Unit |
|---|---|---|---|
cohortMonth | Cohort: month of the first purchase of the row's customers | — | date (YYYY-MM-01) |
initialValue | Cohort size in month 0 | Customers (view=logo) or revenue × margin (view=revenue) | count or currency |
months.{n}.pct | Retention in period n relative to month 0 | value in period n ÷ value in month 0 | decimal (0.52 = 52%) |
months.{n}.absolute | Value retained in period n | Customers or revenue × margin | count or currency |
months.{n}.complementary | The other view's metric for the same cell | Revenue × margin in the logo view; customers in the revenue view | currency or count |
months.{n}.repurchaseRevenue | Gross repeat revenue in period n | Sum of revenue, before margin (null in month 0) | currency |
acquisitionInvestment | Media spend in the cohort's month | Sum of spend | currency |
roi (row) | Cohort return in its entry month | (month-0 revenue × margin − acquisitionInvestment) ÷ acquisitionInvestment | ratio |
directRevenue / directMargin | Revenue of the first purchase (gross / × margin) | Sum in month 0 | currency |
totalRevenue / totalMargin | Total cohort revenue to date (gross / × margin) | Sum over all periods | currency |
additionalRevenue / additionalMargin | Revenue from repeat purchases (gross / × margin) | total − direct | currency |
firstPurchaseCustomers | Customers who entered through the row (product, channel, campaign or coupon) | Count | count |
repurchaseCustomers | Of those, how many bought again | Count | count |
repurchasePct | Repurchase rate | repurchaseCustomers ÷ firstPurchaseCustomers × 100 | % (0–100) |
investment, cac, ltv, payback, roi | Row economics for breakBy=origem (and ltv in every dimension and product breakdown) | See the endpoint page | various |
Important rules
Contribution margin
The organization can configure its contribution margin in the platform, that is, the share of revenue left after variable costs (product, taxes, shipping, payment fees). Every response that uses this margin reports:
marginPercent: the percentage applied (0–100).marginConfigured:trueif the organization configured a margin;falseif it did not.marginCompleteness:complete,partialornone. Tells whether the margin was built item by item (gateway, tax, shipping and COGS) and whether every item is resolved.nonewhen there is no item-by-item composition.marginItemStatus: the status of each item (synced= comes from orders,configured= entered by the user,pending= not configured or missing data).nullwhen there is no item-by-item composition.
Without a configured margin, the API uses marginPercent = 100 and marginConfigured = false. In that case fields such as contribution, ltv and roi reflect gross revenue, not the real margin. Check marginConfigured before presenting these numbers as profit.
| Multiplied by the margin | Do not use the margin |
|---|---|
contribution, contributionProfit, ltv, ltvLifetime, retentionLtv, ltvCacRatio, roi, clv, acquisitionContribution, acquisitionLtv, acquisitionLtvCacRatio, acquisitionRoi, brandContribution, brandRoi, monetizationContribution, monetizationRoi, cohort revenue values (absolute in view=revenue, initialValue, *Margin, ltv, roi) | revenue, investment, orders, customer counts, averageTicket, cpv, cpr, cac, campaignCac, acquisitionCac, monetizationCpr, conversionRate, cohort *Revenue, repurchaseRevenue, retention percentages (pct) |
The retention percentage (pct) does not change with the margin, because the margin cancels out in the division.
null is not 0
Many fields can be null. null means "could not be calculated" (there is no base, the division is undefined or the data is unavailable), while 0 is a measured value. Show a dash or "N/A" for null and never convert it to 0.
Exception: for the general indicators in /cards (cac, cpv, cpr, roi, ltvCacRatio, campaignCac, averageTicket), a division by zero returns 0. For example, cac = 0 with newCustomers = 0 means there were no new customers, not that acquisition was free. In those situations acquisitionCac, acquisitionRoi, brandRoi, monetizationRoi and monetizationCpr return null instead.
Comparison with the previous period
In /cards, when startDate and endDate are sent, the response includes:
previousPeriod: the same indicators calculated for the period immediately before, with the same number of days. Example: for Mar 1 to Mar 31 (31 days), the previous period is Jan 29 to Feb 28.changes: the percentage change of each indicator:(current − previous) ÷ previous × 100. Each field isnullwhen the previous value is0ornull.
Exceptions: ltv and retentionLtv do not use the previous period. They compare the customer base acquired up to the end of the selected period with the base acquired up to its start. margin is the configured margin, which does not depend on the period, so its change is always 0.
Without startDate/endDate, previousPeriod and changes are null.
Time series granularity
| Endpoint | Granularity |
|---|---|
/new-vs-recurring | Daily for periods of up to 31 days, matching the requested dates exactly. Monthly for longer periods or no dates, with the period expanded to whole months. The granularity field tells which one was used. |
/metrics-evolution | Always monthly. The period is expanded to whole months. |
/cmv-evolution | Always daily. One point per day with a sale, a new customer or media spend. |
/cohort | Monthly cohorts. The period filters the entry months, expanded to whole months. |
In monthly series, the month field is the first day of the month (2025-03-01). In the daily series of /new-vs-recurring, the same month field holds the day itself.
Cohorts
view:logo(default) measures retention by number of customers;revenuemeasures it by revenue × margin.groupBy:month(default),quarterorsemester. Changes only the size of the period columns (M1, M2… become Q1, Q2… or S1, S2…). Rows remain monthly cohorts. Column 0 is always the entry month.breakBy:cohort(default, one row per monthly cohort),product(one row per first-purchase product),origem(channel),campanha(campaign) orcupom(coupon). In every breakdown other thancohort, each customer starts at their own month 0, regardless of the calendar month.
Maturing: a cell whose period has not ended on the calendar yet (the current month is still accumulating) has maturing: true. Its value is partial and will likely grow. With breakBy=cohort and groupBy=month, this field is not sent.
- With
breakBy=product, rows overlap: a customer whose first order has several products appears in several rows. Do not add rows together (overlappingRows: true). - With
breakBy=origem|campanha|cupom, each customer falls into exactly one row, so rows can be added together (overlappingRows: false). Customers with no identified value go into theSem origem,Sem campanhaorSem cupomrow. - Attribution of customers to campaigns and coupons depends on the UTMs and coupons recorded on orders. Always show the
coveragefield next to the numbers to indicate how much of the base was attributed. - With
groupBy=quarter|semesterandview=logo, counts add up the customers of each month. A customer active in several months of the same quarter counts once per month, so the number is an upper bound of distinct customers. Revenue sums are exact.
Real COGS and blendedContribution
When the e-commerce platform reports product costs, the API splits revenue into two parts: with real COGS (revenueWithCmv) and without real COGS (revenueWithoutCmv).
marginBasis | Situation | blendedContribution |
|---|---|---|
cmv_real | Every order in the period has real COGS | revenueWithCmv − cogs |
mixed | Some orders have real COGS | (revenueWithCmv − cogs) + revenueWithoutCmv × margin; null if no margin is configured |
configured_percent | No order has real COGS, but a margin is configured | revenue × margin (equal to contribution) |
no_basis | Neither real COGS nor a configured margin | null |
If the margin was configured item by item and is complete (marginCompleteness = complete), each part deducts its own costs (gateway, tax, shipping and COGS) instead of the single percentage.
contribution is always revenue × margin, even when real COGS exists. When marginBasis is null, cost data was not available at query time, which is different from no_basis. In /cmv-evolution, this situation is flagged with degraded: true and data: [].
How customers are counted
newCustomersandrecurringCustomersin/cardsmatch the requested dates exactly.recurringCustomers(customers who had bought before the start of the period) andrecurringOrders(orders from customers who had bought before that order) measure different things. Do not divide one by the other.cacuses total media spend.campaignCacuses only acquisition campaigns but divides by all new customers.acquisitionCacrestricts both sides to acquisition campaigns. These are three different CACs, on purpose.- The four spend slices by strategy (
acquisitionInvestment + brandInvestment + monetizationInvestment + unclassifiedInvestment) add up to the organization's campaign spend, but may differ slightly frominvestmentbecause of update timing and because zero or negative spend adjustments are included in the slices but not ininvestment.
Errors
| Status | When it happens |
|---|---|
400 | Missing organizationId, unknown parameter, or invalid value in view, groupBy or breakBy. |
401 | Missing or invalid credentials. See Authentication. |