Profitability

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

QuestionEndpoint
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

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.

ParameterRequiredFormatDescription
organizationIdYesstringOrganization identifier. Without it the API returns 400.
startDateNoYYYY-MM-DDFirst day of the period (inclusive).
endDateNoYYYY-MM-DDLast 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, groupBy or breakBy also return 400.

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)

FieldWhat it meansHow it is calculatedUnit
revenue / totalRevenueGross revenueSum of order revenuecurrency
investment / totalInvestmentPaid media spendSum of Meta Ads and Google Ads spendcurrency
orders / totalOrdersOrdersNumber of orderscount
newCustomersNew customersCustomers whose first purchase fell in the periodcount
recurringCustomersReturning customersCustomers who bought in the period and had bought before itcount
customersActive customersnewCustomers + recurringCustomerscount
recurringOrdersRepeat ordersOrders from customers who had already bought before that ordercount
averageTicketAverage order valuerevenue ÷ orderscurrency
contributionContribution marginrevenue × margincurrency
contributionProfitContribution profitcontribution − investmentcurrency
cpvCost per saleinvestment ÷ orderscurrency
cprCost per repeat orderinvestment ÷ recurringOrderscurrency
cacCustomer acquisition cost (average)investment ÷ new customerscurrency
ltvLifetime value of customers acquired in the periodAverage total revenue per customer × margincurrency
ltvLifetimeLTV of the whole customer base, with no period filterAverage total revenue per customer × margincurrency
retentionLtvPart of the LTV that comes from repeat purchasesAverage revenue after the first-purchase month × margincurrency
ltvCacRatioHow many times the LTV pays for the CACltv ÷ cacratio (e.g. 5.43 = 5.43×)
roiReturn on media spend(contribution − investment) ÷ investmentratio (e.g. 1.19 = 119%)
clvNet value per customer after acquisition costltv − cac (can be negative)currency
paybackMonths until a cohort's accumulated margin pays for its acquisition costAverage weighted by customer count across the cohorts that already paid backmonths
conversionRateConversion from the Interest stage to the Decision stage of the configured funnelDecision ÷ Interest × 100% (0–100)

Indicators by campaign strategy (/cards)

These depend on the campaign classification done in the V4MOS.AI platform (acquisition, brand, monetization).

FieldWhat it meansHow it is calculatedUnit
campaignCacCAC counting only spend on acquisition campaignsAcquisition spend ÷ all new customerscurrency
acquisitionInvestmentSpend on campaigns classified as acquisitionSum of spendcurrency
acquisitionNewCustomersNew customers brought by acquisition campaignsCount by attribution (UTM) of the first purchasecount
acquisitionCacCAC of acquisition campaignsacquisitionInvestment ÷ acquisitionNewCustomerscurrency
acquisitionContributionMargin generated by those campaigns' customersRevenue of those customers × margincurrency
acquisitionLtvAverage LTV of those campaigns' customersAverage total revenue per customer × margincurrency
acquisitionLtvCacRatioLTV/CAC of acquisition campaignsacquisitionLtv ÷ acquisitionCacratio
acquisitionRoiROI of acquisition campaigns(acquisitionContribution − spend) ÷ spendratio
brandInvestmentSpend on brand campaignsSum of spendcurrency
brandImpressionsImpressions of brand campaignsSum of impressionscount
brandNewCustomersNew customers attributed to brand campaignsCount by first-purchase attributioncount
brandContributionMargin generated by those customersRevenue of those customers × margincurrency
brandRoiROI of brand campaigns(brandContribution − spend) ÷ spendratio
monetizationInvestmentSpend on monetization campaigns (selling to the existing base)Sum of spendcurrency
monetizationContributionMargin of orders attributed to monetization campaignsRevenue of those orders × margincurrency
monetizationRoiROI of monetization campaigns(monetizationContribution − monetizationInvestment) ÷ monetizationInvestmentratio
monetizationRecurringCustomersReturning customers with an order attributed to a monetization campaignCount of distinct customerscount
monetizationCprCost per repeat order of monetization campaignsmonetizationInvestment ÷ repeat orders attributed to themcurrency
unclassifiedInvestmentSpend on unclassified campaignsSum of spendcurrency
hasAcquisitionClassificationWhether the organization has ever classified a campaign as acquisition (in any period)—boolean

Cost of goods sold (/cards, /metrics-evolution, /cmv-evolution)

FieldWhat it meansHow it is calculatedUnit
cogsReal cost of goods sold (COGS)Sum of the cost reported by the e-commerce platform, only on orders that have a costcurrency
revenueWithCmvRevenue of orders that have real COGSSum of revenuecurrency
revenueWithoutCmvRevenue of orders without real COGSrevenue − revenueWithCmvcurrency
marginBasisWhere the period's margin came fromcmv_real, mixed, configured_percent or no_basisstring
blendedContributionContribution margin using real COGS where it exists and the configured margin elsewhereSee Important rulescurrency

Cohorts (/cohort)

FieldWhat it meansHow it is calculatedUnit
cohortMonthCohort: month of the first purchase of the row's customers—date (YYYY-MM-01)
initialValueCohort size in month 0Customers (view=logo) or revenue × margin (view=revenue)count or currency
months.{n}.pctRetention in period n relative to month 0value in period n ÷ value in month 0decimal (0.52 = 52%)
months.{n}.absoluteValue retained in period nCustomers or revenue × margincount or currency
months.{n}.complementaryThe other view's metric for the same cellRevenue × margin in the logo view; customers in the revenue viewcurrency or count
months.{n}.repurchaseRevenueGross repeat revenue in period nSum of revenue, before margin (null in month 0)currency
acquisitionInvestmentMedia spend in the cohort's monthSum of spendcurrency
roi (row)Cohort return in its entry month(month-0 revenue × margin − acquisitionInvestment) ÷ acquisitionInvestmentratio
directRevenue / directMarginRevenue of the first purchase (gross / × margin)Sum in month 0currency
totalRevenue / totalMarginTotal cohort revenue to date (gross / × margin)Sum over all periodscurrency
additionalRevenue / additionalMarginRevenue from repeat purchases (gross / × margin)total − directcurrency
firstPurchaseCustomersCustomers who entered through the row (product, channel, campaign or coupon)Countcount
repurchaseCustomersOf those, how many bought againCountcount
repurchasePctRepurchase raterepurchaseCustomers ÷ firstPurchaseCustomers × 100% (0–100)
investment, cac, ltv, payback, roiRow economics for breakBy=origem (and ltv in every dimension and product breakdown)See the endpoint pagevarious

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: true if the organization configured a margin; false if it did not.
  • marginCompleteness: complete, partial or none. Tells whether the margin was built item by item (gateway, tax, shipping and COGS) and whether every item is resolved. none when 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). null when 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 marginDo 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 is null when the previous value is 0 or null.

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

EndpointGranularity
/new-vs-recurringDaily 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-evolutionAlways monthly. The period is expanded to whole months.
/cmv-evolutionAlways daily. One point per day with a sale, a new customer or media spend.
/cohortMonthly 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; revenue measures it by revenue × margin.
  • groupBy: month (default), quarter or semester. 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) or cupom (coupon). In every breakdown other than cohort, 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 the Sem origem, Sem campanha or Sem cupom row.
  • Attribution of customers to campaigns and coupons depends on the UTMs and coupons recorded on orders. Always show the coverage field next to the numbers to indicate how much of the base was attributed.
  • With groupBy=quarter|semester and view=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).

marginBasisSituationblendedContribution
cmv_realEvery order in the period has real COGSrevenueWithCmv − cogs
mixedSome orders have real COGS(revenueWithCmv − cogs) + revenueWithoutCmv × margin; null if no margin is configured
configured_percentNo order has real COGS, but a margin is configuredrevenue × margin (equal to contribution)
no_basisNeither real COGS nor a configured marginnull

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

  • newCustomers and recurringCustomers in /cards match the requested dates exactly.
  • recurringCustomers (customers who had bought before the start of the period) and recurringOrders (orders from customers who had bought before that order) measure different things. Do not divide one by the other.
  • cac uses total media spend. campaignCac uses only acquisition campaigns but divides by all new customers. acquisitionCac restricts 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 from investment because of update timing and because zero or negative spend adjustments are included in the slices but not in investment.

Errors

StatusWhen it happens
400Missing organizationId, unknown parameter, or invalid value in view, groupBy or breakBy.
401Missing or invalid credentials. See Authentication.

On this page