Marlo API & MCP
Read your workspace’s Shopify customers and reporting data from your own integrations or an MCP client.
Authentication
A workspace owner or admin can generate a key in API & MCP settings. Copy the key when it is created; Marlo stores only its hash. Send it in the Authorization: Bearer YOUR_API_KEY header. The key identifies your workspace automatically.
Keep keys in a server environment variable or your client’s secret store. Never put them in browser code, a URL, or a public repository. Keys can read all selected apps in their workspace and also authorize Marlo’s ingestion endpoints. Create a separately named key for each integration. Generating another key keeps existing keys working; revoking a key immediately invalidates only that key. To rotate one integration, create a replacement, update the integration, then revoke its old key.
Workspace summary and metrics
GET https://app.withmarlo.app/api/v1/summary
GET https://app.withmarlo.app/api/v1/metrics/{metric}
The summary includes MRR, ARR, ARPU per paying customer, retention, concentration, usage earnings and received usage activity. Use a specific metric for a focused response: mrr, arr, usage, net-revenue-retention, or customer-concentration.
Use a workspace API key in the Authorization: Bearer header (authentication details). The first example returns the last 30 days across all selected apps, with each currency reported separately.
curl 'https://app.withmarlo.app/api/v1/summary' \ -H "Authorization: Bearer $MARLO_API_KEY" curl 'https://app.withmarlo.app/api/v1/summary?from=2026-09-01&to=2026-09-16¤cy=USD' \ -H "Authorization: Bearer $MARLO_API_KEY" curl 'https://app.withmarlo.app/api/v1/metrics/net-revenue-retention?from=2026-09-01&to=2026-09-16' \ -H "Authorization: Bearer $MARLO_API_KEY"
fromandto: supply both as realYYYY-MM-DDUTC dates, inclusive, in ascending order and covering at most 366 days. The end cannot be later than today. Omit both for the last 30 days including today. Historical requests remain limited by available source history.currency: optional uppercase three-letter currency code. Money always appears inbyCurrency, including when one currency is requested. Omit to return each observed currency separately; no exchange-rate conversion or total across currencies is performed.customerScope:includedorpaying, defaulting to the workspace’s saved scope. Excluded and non-commercial stores are omitted. Paying includes customers with qualifying billing activity during the range, including customers who churned.appId: optionally restrict to one of the workspace’s selected apps. Use an app ID from a customer response. Other app IDs are rejected.
{
"range": { "from": "2026-09-01", "to": "2026-09-16" },
"asOf": "2026-09-16",
"generatedAt": "2026-09-16T12:00:00.000Z",
"appId": null,
"customerScope": "included",
"currencies": ["USD"],
"mixedCurrencies": false,
"byCurrency": {
"USD": {
"mrrCents": 120000, "subscriptionMrrCents": 100000, "usageMrrCents": 20000,
"arrCents": 1440000, "payingCustomers": 40, "arpuCents": 3000,
"netRevenueRetentionRate": 1.05,
"largestCustomerShare": 0.2, "topFiveCustomerShare": 0.6, "topTenCustomerShare": 0.8,
"usage": {
"usageMrrCents": 20000,
"billedUsage": { "grossCents": 18000, "feesCents": 1800, "netCents": 16200, "transactionCount": 4, "complete": true },
"observedUsageCharges": { "grossCents": 20000, "count": 5 }
}
}
},
"metricBases": { "netRevenueRetention": "subscription_mrr", "customerConcentration": "total_mrr" },
"usageActivity": {
"source": "received_usage_events", "eventCount": 2, "totalCount": 200,
"byName": [{ "name": "search", "eventCount": 2, "totalCount": 200 }],
"lastOccurredAt": "2026-09-15T12:00:00.000Z", "loaded": true, "complete": null
},
"source": "marlo_synced_partner_data", "staleDataWarning": null
}This abbreviated example omits other dashboard fields and coverage. Every summary or metric response includes range, the closing date in asOf, the response timestamp in generatedAt, source, staleDataWarning, and source coverage. Coverage records transaction and charge history start dates, transaction truncation, and lifecycle history completeness and dates. Inspect it before treating missing historical activity as zero. generatedAt does not mean Shopify was synced at that instant.
mrrreturns closingmrrCents,subscriptionMrrCentsandusageMrrCents. Annual subscriptions are normalized monthly.arrreturnsarrCents= closing MRR × 12, alongsidemrrCents; ARR is an annualized run rate.- ARPU per paying customer is available in the summary as
byCurrency.USD.arpuCents(replaceUSDwith your currency). It equalsMath.round(mrrCents / payingCustomers), including subscription and usage MRR, and is0when there are no paying customers. Both MRR andpayingCustomersare measured at the closingasOfdate within the selected app and currency. Free plans and trials do not count, even withcustomerScope=included. Customers are counted once per customer ID; a shop using multiple apps can have multiple customer IDs. Amounts are integer minor units: the example’s3000is $30 per paying customer per month. usagereturns the same monetary fields as each summary’susageobject.billedUsagecontains usage earnings transactions in the selected range.observedUsageChargescontains Shopify usage charge events; these may overlap with billed earnings and must not be added to them.usageMrrCentsis the current usage component of MRR.usageActivity, present on summary and usage responses, counts ingested events and sums theircountvalues by name within the requested dates and customer/app scope. Activity has no currency and is reported once outsidebyCurrency. Itscompleteis alwaysnull: Marlo cannot verify your integration sent every event.net-revenue-retentioncompares closing subscription MRR from merchants paying on the day beforefromwith that cohort’s opening subscription MRR. Expansion, contraction and churn affect the rate; new merchants do not. Usage is excluded because historical usage snapshots cannot be reliably reconstructed. The response includesbasis: subscription_mrr, cohort amounts,baselineComplete,complete, andwarnings. A rate of1.05means 105%; the rate is absent when no reliable, positive opening baseline exists.customer-concentrationranks merchants by closing total MRR, including usage, and returnslargestCustomerShare,topFiveCustomerShare,topTenCustomerShare, and customer rows with MRR, share and cumulative share.0.2means 20%. Both retention and concentration combine matching normalized shop domains across selected apps, with app filters applied first. Concentration includescompleteandwarnings; shares are absent without positive MRR.
List customers
GET https://app.withmarlo.app/api/v1/customers
curl 'https://app.withmarlo.app/api/v1/customers?limit=20' \ -H "Authorization: Bearer $MARLO_API_KEY"
limit: integer from 1 to 50; defaults to 20.cursor: thenextCursorreturned by the previous page. Keep other filters the same. A null cursor means there are no more results.customerScope:includedorpaying; defaults to the workspace’s saved reporting scope. Included omits customers excluded from reports and non-commercial stores.
Customers are ordered by ID. Pagination reflects the current synced data, so changes between requests can change which customers match.
{
"customers": [{
"id": "CUSTOMER_ID",
"appId": "APP_ID",
"name": "Example shop",
"domain": "example.myshopify.com",
"status": "active",
"paying": true,
"reportExcluded": false
}],
"nextCursor": null,
"range": { "from": "2026-08-18", "to": "2026-09-16" },
"customerScope": "included",
"source": "customers"
}The example shows a subset of fields. Customer objects also include country, plan, tags, health, firstSeen, lastActive, lifetime revenue and store classification where available. Monetary fields ending in Cents are integer minor units; ltvByCurrencyCents separates currencies when available. amrCents is the latest monthly subscription estimate and is zero for non-paying customers; use the customer detail endpoint below for calculated subscription and usage MRR by currency. Do not sum different currencies.
Get a customer
GET https://app.withmarlo.app/api/v1/customers/{customerId}
curl 'https://app.withmarlo.app/api/v1/customers/CUSTOMER_ID' \ -H "Authorization: Bearer $MARLO_API_KEY"
Use the ID from the list response, or a unique example.myshopify.com domain. The response contains customer, analytics, timeline, range, and source. limit controls timeline entries (1–50, default 20), newest first; it does not limit analytics. A domain shared by multiple apps returns 409 with matching customer IDs; retry with an ID.
Customer detail can include excluded customers, but only from the workspace’s selected apps. paying uses the same current billing calculation as Marlo, independently of the install status. reportExcluded tells you whether a customer is excluded from aggregate reporting. These endpoints are read-only; customer updates are not supported.
Customer MRR, earnings and usage
Every customer detail request includes this analytics structure automatically. The example abbreviates the customer object. MCP’s get_customer returns the same analytics.
{
"customer": { "id": "CUSTOMER_ID", "paying": true, "reportExcluded": false },
"analytics": {
"asOf": "2026-09-16T12:00:00.000Z",
"paying": { "paying": true, "reason": "Paying because an active positive-value monthly subscription with recurring payment evidence is in effect on 2026-09-16. Trials and zero-value plans do not count." },
"currencies": ["USD"],
"current": {
"asOf": "2026-09-16",
"byCurrency": {
"USD": { "mrrCents": 12000, "subscriptionMrrCents": 10000, "usageMrrCents": 2000 }
}
},
"last30Days": {
"range": { "from": "2026-08-18", "to": "2026-09-16" },
"byCurrency": {
"USD": {
"grossCents": 12200, "feeCents": 1220, "netCents": 10980, "totalDeductionsCents": 1220,
"subscriptionCents": 10000, "usageCents": 2000,
"oneTimeCents": 500, "refundCents": 300, "transactionCount": 4,
"observedUsageCharges": { "grossCents": 600, "count": 1, "lastOccurredAt": "2026-09-15T12:00:00.000Z" }
}
},
"usageActivity": {
"eventCount": 2, "totalCount": 200,
"byName": [{ "name": "search", "eventCount": 2, "totalCount": 200 }],
"lastOccurredAt": "2026-09-15T12:00:00.000Z"
}
},
"coverage": {
"transactions": { "complete": true, "coverageFrom": "2026-06-19", "coverageThrough": "2026-09-16", "truncated": false },
"lifecycle": { "complete": true, "coverageFrom": "2020-01-01", "coverageThrough": "2026-09-16" },
"observedUsageCharges": { "complete": true, "coverageFrom": "2026-06-19", "coverageThrough": "2026-09-16" },
"usageActivity": { "source": "received_usage_events", "loaded": true, "complete": null }
}
},
"timeline": [],
"range": { "from": "2026-08-18", "to": "2026-09-16" },
"source": "customer_detail"
}analytics.payingincludes the current billing decision and its explanation. Canceling renewal sets current MRR to zero while historical payments remain in last-30-day earnings.current.byCurrencycontains calculatedmrrCents, split into the recurring subscription price (subscriptionMrrCents) and usage component (usageMrrCents). Annual plans are normalized monthly and rounded to minor units. This uses the same financial calculation as the dashboard.last30Days.rangecovers exactly 30 inclusive UTC dates, including today.grossCents,feeCentsandnetCentspreserve the source transaction amounts using billed dates.feeCentsis the reported fee component, not the subscription price or necessarily all deductions.totalDeductionsCentsequals gross − net and includes deductions the source does not itemize as fees; net can therefore differ from gross − reported fees.subscriptionCents,usageCentsandoneTimeCentsare billed gross earnings by transaction type.refundCentsis refunds and credits deducted from gross, normally positive; a reversed credit can be negative. Gross equals subscription + usage + one-time − refunds, and net equals gross − total deductions. Annual charges retain their full billed value here.observedUsageChargesdescribes Shopify usage charge events, which can precede earnings transactions or refer to the same charges. Never add these amounts to billed earnings.usageActivitycounts events your integration sent to Marlo and sums theircountvalues, grouped by name; it is not a monetary total or a visitor count.- Money always remains in separate
byCurrencyentries. There is no total across currencies, and a currency with no observed financial data is omitted. Unknown source currencies follow Marlo’s USD fallback.
coverage identifies partial or stale source data. A complete: true financial or charge range requires coverage of all 30 dates and completed Shopify history through the current reporting date. truncated indicates the loaded transaction history reached its row limit, though the requested range may still be covered. Usage activity can only show received events: its completeness remains null because Marlo cannot verify that your integration sent everything. Zero received usage does not prove the customer was inactive.
Errors and freshness
Errors return JSON with error and message. 400 means invalid parameters, 401 means a missing, invalid or revoked key, 403 means the workspace needs an active subscription, 404 means an unknown metric or a customer unavailable in this workspace, 409 means an ambiguous domain, and 503 means a temporary service failure. Retry 503 responses with exponential backoff.
Responses use the latest Shopify data synced into Marlo. When present, staleDataWarning explains freshness limits; this API does not trigger a live Shopify sync. All API responses disable caching.
Connect an MCP client
Add a remote server with Streamable HTTP transport and this URL:
https://app.withmarlo.app/api/mcp
Configure the HTTP header Authorization: Bearer YOUR_API_KEY in your client’s secure connection settings. Your client must support bearer headers for remote MCP servers; OAuth sign-in is not currently supported. No repository checkout, local server or team slug is required.
Available tools: list_customers, get_customer, get_summary, query_metrics, get_report, compare_periods, and list_sync_runs. get_summary returns the same response as the summary REST endpoint. Customer list and reporting tools accept customerScope; reporting tools also accept currency, from, to, and appId. get_report supports net-revenue-retention and customer-concentration. Customer tools have the same limits and data access as the REST API.