MerchantFlowMerchantFlow Docs
IntegrationsPublic API

MerchantFlow Public API - Read a Merchant's Profitability Data

How third-party applications connect to MerchantFlow with OAuth 2.1 and read order economics, products, and profit and loss on a merchant's behalf.

MerchantFlow Public API

The Public API lets your application read a MerchantFlow merchant's order economics, products, and profit and loss - with their explicit permission, and without ever receiving customer names, email addresses, phone numbers, or shipping addresses.

It is built for the case where you already know something about a merchant's store and want to attach real profit to it: a funnel or experiment platform matching a Shopify order to the campaign that produced it, an inventory tool that needs true landed cost, a reporting product consolidating several systems.

This API is read-only. Every endpoint is GET. There are no write scopes to request, so connecting your application can never change a merchant's data.

Who can connect

Partner applications are provisioned by MerchantFlow. You cannot self-register: an application that has not been provisioned is refused at the consent screen and its tokens are refused by the API, even if it completes an OAuth flow.

To get credentials, contact MerchantFlow with your application name, the redirect URI you will use, and the scopes you need. You will receive a client_id and a client_secret.

Merchants on every paid plan can connect your application. Plans differ in how far back their history goes, not in whether the API works - see Incremental sync.

The shape of an integration

  1. Send the merchant through the OAuth flow. They sign in, choose which store to share, and approve the scopes you asked for. Include store:read so the next step works. See Authentication.
  2. Call /api/v1/account to confirm which store you are connected to, what currency it reports in, and how far back its plan lets you read.
  3. Backfill with GET /api/v1/orders, paging through cursors.
  4. Stay current by re-calling the same endpoint with updated_after. This is the important part, and it is not the same as "orders created since": an order's COGS or fulfilment cost can change days after it was placed, and updated_after will bring it back to you when it does.

Base URL and contract

https://merchantflow.ai/api/v1

A machine-readable OpenAPI 3.1 description is published, unauthenticated, at:

https://merchantflow.ai/api/v1/openapi.json

You can point a code generator at it directly.

A first request

curl https://merchantflow.ai/api/v1/account \
  -H "Authorization: Bearer $ACCESS_TOKEN"
{
  "success": true,
  "data": {
    "store": {
      "id": "ten_9f2b...",
      "name": "Northbound Supply",
      "platform": "shopify",
      "shop_domain": "northbound-supply.myshopify.com",
      "currency": "AUD",
      "timezone": "Australia/Adelaide"
    },
    "data_availability": {
      "history_days": 365,
      "available_from": "2025-09-03",
      "last_sync_at": "2026-09-03T04:11:00Z",
      "stale": false
    }
  },
  "meta": {
    "store_id": "ten_9f2b...",
    "currency": "AUD",
    "timezone": "Australia/Adelaide",
    "as_of": "2026-09-03T04:11:00Z",
    "stale": false,
    "history_available_from": "2025-09-03",
    "truncated": false
  }
}

Response envelope

Every response has the same shape.

FieldMeaning
successtrue on a 2xx response
dataThe payload - an object for single resources, an array for lists
metaProvenance: store, currency, timezone, data freshness, plan window
pagePresent on list endpoints: has_more, next_cursor, limit

meta.as_of is when the store last synced with its commerce and ad platforms - not when you made the request. If meta.stale is true, that sync is more than 24 hours old and the numbers you are reading may lag the merchant's actual storefront. Surfacing that to your own users is usually worth doing.

Errors use the same envelope inverted:

{
  "success": false,
  "error": { "code": "insufficient_scope", "message": "This endpoint requires the \"orders:read\" scope." }
}

Two numbers to be careful with

MerchantFlow deliberately tells you when a figure is an estimate rather than a measurement. If you display these to a merchant, carry the caveat with them.

ad_spend_allocated is an allocation, not measured spend. No ad platform reports spend at order granularity, so a day's total is divided across that day's eligible orders. Every order says so in ad_spend_basis. Presenting it as the ad spend for one specific order - or one specific funnel - is a claim MerchantFlow's data does not support.

cogs_coverage_pct below 100 means the margin is overstated. It is the percentage of units on an order that actually have cost data. An order showing a 92% margin and 10% coverage is not a profitable order; it is an order with missing costs.

Both are covered in Data and privacy.

What you never receive

No customer names, email addresses, phone numbers, or shipping addresses. Orders carry shipping_country_code and a pseudonymous customer_ref, and nothing else that identifies a person.

This is a structural guarantee, not a filter applied on the way out - the fields are never read from the database. See Data and privacy.

Next

Last updated: September 22, 2026

Last updated on

On this page