Data and Privacy - What the MerchantFlow API Shares and What It Does Not
What customer data the MerchantFlow Public API excludes, how the pseudonymous customer reference works, and how to present allocated ad spend and COGS coverage honestly.
Data and privacy
Two separate things live on this page: what customer data you do and do not receive, and how to present two MerchantFlow figures without overstating what they mean.
Both matter to merchants, and both are things MerchantFlow states plainly on the consent screen. Your integration should not contradict them.
What you never receive
The Public API never returns:
- Customer names
- Email addresses
- Phone numbers
- Shipping addresses - street, city, state, postcode
- Order notes or order tags, which merchants often use for free-text customer details
- Tracking numbers and tracking URLs, which a carrier will resolve to a delivery address
This is structural rather than a filter. Those columns are never read from the database when building an API response, so there is no code path - including a future bug - that can emit them.
You do receive shipping_country_code (ISO 3166-1 alpha-2), which is
country-level only and is what makes market analysis possible.
customer_ref
Orders carry customer_ref, an opaque string like kQ7xR2mN8vTpL4wZ.
What it is for. Grouping a customer's orders together so you can tell a repeat buyer from a new one, and measure repeat behaviour over time.
What it is not. It is not an email address, not a hash of one you could reverse, and not an identifier shared with anyone else.
How it behaves
| Property | Behaviour |
|---|---|
| Stable | The same customer has the same customer_ref across all their orders, for your application and this merchant |
| Not portable | A different application connected to the same merchant sees a completely different value for the same customer |
| Not reversible | Derived with a keyed function using a secret only MerchantFlow holds. You cannot compute it from an email address, even if you already know the address |
| Resettable | If the merchant disconnects and later reconnects your application, values change |
| Sometimes null | Orders with no customer email - some guest checkouts, manual wholesale orders |
The "not portable" property is deliberate. Two applications connected to the same store cannot combine their exports to build a shared picture of that merchant's customers, because they never share an identifier.
Your obligations
customer_ref is pseudonymous personal data under GDPR, not anonymous data.
That distinction is legal, not cosmetic:
- It stays in scope for data protection obligations, including deletion requests.
- You must not attempt to re-identify the person behind it.
- Your privacy policy and your data processing agreement with MerchantFlow need to cover it.
MerchantFlow is deliberate about not describing it as anonymous, and asks that you are too.
You may not need it
Two fields answer "new or returning customer" with no identifier at all, and both are on every order:
is_first_order- whether this is the customer's first order with this storecustomer_order_sequence-1for a first purchase,2for the second, and so on
If those cover your use case, use them and ignore customer_ref. Fewer
identifiers is a better position for both of us.
When a merchant erases a customer
If a merchant processes a GDPR erasure request, MerchantFlow redacts that
customer's data and the affected orders reappear in your updated_after feed
with customer_ref set to null.
That is your signal. Handle it the same way on your side - the merchant has exercised a legal obligation and it needs to propagate.
Allocated ad spend
ad_spend_allocated is an allocation, not a measurement, and every order says
so in ad_spend_basis: "blended_daily_allocation".
No advertising platform reports spend at the level of an individual order. Meta, Google, TikTok and Snapchat report at campaign and day level. So MerchantFlow takes a day's total spend and divides it across that day's eligible orders.
What that means for you. The figure is sound at day, week and month level - that is real money, correctly totalled. It is not a measurement of what was spent to acquire one particular order, and it cannot be, because that number does not exist in any upstream system.
If your product attributes revenue to funnels, campaigns or experiments, this distinction is the one most likely to cause a problem. Presenting an allocated figure as "ad spend for this funnel" is a claim the underlying data does not support, and merchants who check it against their ad platform will find the discrepancy.
Label it. "Allocated ad spend" or "estimated ad spend" is accurate and costs you nothing.
COGS coverage
cogs_coverage_pct is the percentage of units on an order that actually have cost
data. It appears per order and on the profitability summary.
Below 100 means the reported margin is overstated, because some units are being counted as costing nothing.
An order showing 92% margin with 15% coverage is not a highly profitable order. It is an order where the merchant has not entered costs for most of what they sold. Merchants add COGS gradually, so partial coverage is common, especially on newer stores.
If you surface margin or profit, surface coverage alongside it, or suppress the margin below some threshold. A merchant acting on a fabricated 92% margin is a worse outcome than a blank cell.
The same applies to products: a cogs of null means unknown, not free.
Product costs are more complex than one number
GET /api/v1/products returns a single base cost per SKU, with two flags:
cost_is_tiered- the SKU also has quantity-tier pricingcost_is_market_specific- the SKU also has per-market costs
When either is true, the number you have is the default case, not the whole
picture. For the cost actually applied to a specific sale, use the order line's
cogs - that has been resolved through the full pricing engine including tiers
and market.
Profitability basis
GET /api/v1/profitability/summary returns a basis object. Read it before
comparing MerchantFlow's numbers to anything computed elsewhere:
refund_recognition: "sale_date"- a refunded order's costs are recognised on the order date, matching its revenue, so revenue and cost never sit in different periods.tax_treated_as_cost- whether sales tax is deducted from profit. This follows the merchant's own setting, so the figures match their dashboard. Two merchants can legitimately have different values here.
Data retention and deletion
If a merchant disconnects your application, your access ends within about a minute. What you have already stored is governed by your own agreement with them and with MerchantFlow - MerchantFlow cannot reach into your systems.
Your data processing agreement should say what you retain, for how long, and how a merchant asks for deletion.
Related
- Scopes - what each permission grants
- Endpoints - field-level reference
- Privacy policy
Last updated: 3 September 2026
Last updated on
Public API Endpoint Reference - Orders, Products, Profitability
Complete reference for the MerchantFlow Public API: account, stores, orders with order-level economics, products with COGS, and profit and loss.
UTM Tracking for Revenue Attribution
Set up UTM parameters to attribute e-commerce revenue to specific marketing channels and campaigns in MerchantFlow. Includes recommended UTM structures.