8Merch Ecommerce API (1.0.0)

Download OpenAPI specification:

Read your monthly statements, sales, refunds, payouts and stock - for your accounting and royalty software.

Part of the 8Merch API documentation - Services > Ecommerce.

When 8Merch runs your store, we sell and ship your merch, keep our commission and pay out your share every month on a statement. This API gives you the same figures as the Statements tab of your portal, in a form your accounting software - or the spreadsheet you split artist royalties with - can read directly. It is especially useful if you run several stores with us: one key can read all of them.

The API is read-only. Every endpoint documented here is live at https://api.8merch.com/ecommerce/v1.

Getting started

1. Get a key. Keys are issued by 8Merch - ask your account manager. A key can read all your stores (including ones you connect later) or only the ones you choose. You receive it once; keep it on your server, never in a browser or app. Every request sends it:

curl https://api.8merch.com/ecommerce/v1/account \
  -H "Authorization: Bearer $EIGHTMERCH_ECOMMERCE_KEY"

2. List your statements for a period - one per store per month:

curl "https://api.8merch.com/ecommerce/v1/statements?period_from=2026-07&period_to=2026-09" \
  -H "Authorization: Bearer $EIGHTMERCH_ECOMMERCE_KEY"

3. Read one in full - totals, sales by product, refunds, extra costs and the payout: GET /statements/{id}. Its orders, each with its own figures, are at GET /statements/{id}/orders.

4. Or pull a whole quarter at once across every store: GET /sales?period_from=2026-07&period_to=2026-09 gives one row per product per store per month, with the product's vendor (normally the artist) on each row - ready to group for royalties. GET /refunds is its counterpart for refunds.

5. Reconcile payouts with GET /payouts: what we owe or have paid for each statement.

How a statement adds up

Every figure is frozen when the statement is generated and never changes afterwards. Amounts are in the statement's currency (the currency of the region the store sells from), rounded to 2 decimals.

Line Meaning
gross_value What customers paid for the goods after discounts, including VAT. Shipping is not included.
vat_amount VAT within gross_value.
net_value gross_value - vat_amount.
cost_of_goods What the goods cost to make, at the cost agreed for each product.
refunded_net Refunds deducted on this statement (net of VAT).
extra_costs_before_commission Agreed costs (freight, artwork, samples...) shared before our commission.
profit net_value - cost_of_goods - refunded_net - extra_costs_before_commission
commission 8Merch's share of profit.
extra_costs_after_commission Agreed costs that come out of your share only.
payout profit - commission - extra_costs_after_commission - what you are paid.

Which month an order belongs to. A sale is on the statement for the month it was fulfilled (shipped), not the month it was ordered. A refund is on the statement for the month it was made, once its order has been fulfilled - a refund made before shipping waits for the statement of the month the order ships.

Extra costs that are bigger than the payout are part-deducted and the rest is carried to the next statement. Each extra cost line shows amount (deducted here), original_amount and carried_amount.

Sales by product. Inside an order with several products, the order's frozen net value, VAT and cost of goods are shared across its products in proportion to price and product cost. The per-product lines always add up to the order's figures, and the orders always add up to the statement.

When statements appear. A statement is visible here once 8Merch has reviewed and approved it - the same moment it appears in your portal. A month with no sales and no costs still gets a statement, with status no_activity and every figure zero.

Several stores and royalties

Each statement belongs to one store (store, store_name). Filter any list with store=st_..., or leave it out to read every store your key covers (GET /stores lists them).

For royalties, GET /sales is the endpoint you want. Every row carries product_vendor - the vendor field of the product in the store, which is normally the artist or brand - and you can filter to one with product_vendor=.... Subtract that artist's rows from GET /refunds' items (matched by SKU) for the same period to get their net.

Sales are reported per statement currency. If your stores sell in different regions you will see USD, EUR and GBP rows side by side - we never convert between them.

Marketplace stores (is_marketplace: true), which settle with each vendor separately, are not covered by this version of the API.

Errors

Errors share one shape, with a stable code to branch on and a request_id to quote to us:

{"error":{"type":"invalid_request","code":"invalid_period","message":"period must be YYYY-MM.",
          "param":"period","request_id":"req_8sK2..."}}
HTTP type code What to do
401 authentication_error missing_api_key Send Authorization: Bearer <key>.
401 authentication_error invalid_api_key The key is wrong.
401 authentication_error api_key_revoked Ask us for a new key.
401 authentication_error wrong_api That is a Fulfillment API key (8m_...); this API takes 8me_live_....
403 permission_error missing_scope The key cannot read this; ask us to add the scope.
403 permission_error account_inactive The account is closed.
404 not_found statement_not_found Not yours, not approved yet, or not a statement id.
404 not_found store_not_found The store is not covered by your key.
404 not_found unknown_endpoint Check the path.
422 invalid_request invalid_period Periods are YYYY-MM.
422 invalid_request invalid_period_range period_to is before period_from.
422 invalid_request period_required /sales and /refunds need period, or both period_from and period_to.
422 invalid_request period_range_too_long At most 12 months per /sales or /refunds request.
422 invalid_request invalid_status See the endpoint's status values.
429 rate_limited rate_limited 60 requests a minute per key; wait Retry-After seconds.

Every response carries a Request-Id header, and RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset.

Pagination

Lists return {"data": [...], "has_more": true, "next_cursor": "..."}. Pass cursor=<next_cursor> for the next page until has_more is false. /sales and /refunds are bounded by their period instead and return everything at once.

FAQ

Can I see this month's sales so far? No - only statements, which are generated after the month ends. Your portal's Orders tab shows live orders.

Why does a statement's per-product cost look slightly different from the product's cost? Inside multi-product orders the order's frozen cost is shared across its products (see above); single-product orders always match exactly. The statement totals are the figures that were paid.

Will a statement ever change? Not once it is approved - that is when it appears here. Its figures are frozen.

When was a payout paid? payout.status becomes paid once the money has been sent. The exact transfer date is on your Stripe Express dashboard.

Is there a sandbox? Not for this API: it is read-only, so a key can safely be pointed at your real data from day one.

Account

Who the key belongs to and which stores it covers.

The account this key reads

Authorizations:
apiKey

Responses

Response samples

Content type
application/json
{
  • "id": "acc_cm1x2y3z4a5b6c7d8e9f0g1h2",
  • "object": "account",
  • "name": "string",
  • "key": {
    },
  • "stores": [
    ]
}

The stores this key covers

Authorizations:
apiKey

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "has_more": true,
  • "next_cursor": "string"
}

Statements

Monthly statements - one per store per month - in full.

List statements

Newest period first. Needs statements:read.

Authorizations:
apiKey
query Parameters
store
string

Only this store (st_...). Leave out for every store your key covers.

period
string
Example: period=2026-09

One month, YYYY-MM. Overrides period_from / period_to.

period_from
string
Example: period_from=2026-07

First month, inclusive, YYYY-MM.

period_to
string
Example: period_to=2026-09

Last month, inclusive, YYYY-MM.

status
string
Example: status=approved,paid

Comma-separated - approved (payout still to come), paid, no_activity.

cursor
string

The next_cursor from the previous page.

limit
integer [ 1 .. 100 ]
Default: 50

Responses

Request samples

curl "https://api.8merch.com/ecommerce/v1/statements?period_from=2026-07&period_to=2026-09" \
  -H "Authorization: Bearer $EIGHTMERCH_ECOMMERCE_KEY"

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "has_more": true,
  • "next_cursor": "string"
}

A statement in full

The totals plus every section of the statement: sales by product, refunds, refunded products and extra costs. Its orders are at /statements/{id}/orders. Needs statements:read.

Authorizations:
apiKey
path Parameters
id
required
string
Example: stmt_cm1x2y3z4a5b6c7d8e9f0g1h2

Responses

Response samples

Content type
application/json
{
  • "id": "string",
  • "object": "statement",
  • "store": "string",
  • "store_name": "string",
  • "period": "2026-09",
  • "currency": "USD",
  • "status": "approved",
  • "order_count": 0,
  • "item_count": 0,
  • "totals": {
    },
  • "payout": {
    },
  • "approved_at": "2019-08-24T14:15:22Z",
  • "generated_at": "2019-08-24T14:15:22Z",
  • "products": [
    ],
  • "refunds": [
    ],
  • "refunded_products": [
    ],
  • "refunds_unattributed_net": 0,
  • "extra_costs": {
    }
}

The orders on a statement

Oldest fulfilment first, each with its frozen figures and its products' share of them. Needs statements:read.

Authorizations:
apiKey
path Parameters
id
required
string
Example: stmt_cm1x2y3z4a5b6c7d8e9f0g1h2
query Parameters
cursor
string

The next_cursor from the previous page.

limit
integer [ 1 .. 500 ]
Default: 100

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "has_more": true,
  • "next_cursor": "string"
}

Reports

Sales and refunds flattened across stores and months, for accounting and royalties.

Sales by product, across stores and months

One row per product per statement for the period - the "sales by product" section of every statement in range, flattened. Up to 12 months per request; no_activity statements contribute nothing. Needs statements:read.

Authorizations:
apiKey
query Parameters
period
string
Example: period=2026-09

One month, YYYY-MM. Overrides period_from / period_to.

period_from
string
Example: period_from=2026-07

First month, inclusive, YYYY-MM.

period_to
string
Example: period_to=2026-09

Last month, inclusive, YYYY-MM.

store
string

Only this store (st_...). Leave out for every store your key covers.

product_vendor
string

Only rows whose product_vendor matches (case-insensitive) - usually an artist.

Responses

Request samples

curl "https://api.8merch.com/ecommerce/v1/sales?period_from=2026-07&period_to=2026-09" \
  -H "Authorization: Bearer $EIGHTMERCH_ECOMMERCE_KEY"

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "statements": [
    ]
}

Refunds, across stores and months

Every refund deducted on a statement in the period, with its items. Up to 12 months per request. Needs statements:read.

Authorizations:
apiKey
query Parameters
period
string
Example: period=2026-09

One month, YYYY-MM. Overrides period_from / period_to.

period_from
string
Example: period_from=2026-07

First month, inclusive, YYYY-MM.

period_to
string
Example: period_to=2026-09

Last month, inclusive, YYYY-MM.

store
string

Only this store (st_...). Leave out for every store your key covers.

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "statements": [
    ]
}

Payouts

What we owe you, and what we have paid.

List payouts

The payout side of each statement, newest period first. no_activity statements have no payout and are not listed. Needs statements:read.

Authorizations:
apiKey
query Parameters
store
string

Only this store (st_...). Leave out for every store your key covers.

period
string
Example: period=2026-09

One month, YYYY-MM. Overrides period_from / period_to.

period_from
string
Example: period_from=2026-07

First month, inclusive, YYYY-MM.

period_to
string
Example: period_to=2026-09

Last month, inclusive, YYYY-MM.

status
string
Example: status=pending

Comma-separated - pending, paid, nothing_due.

cursor
string

The next_cursor from the previous page.

limit
integer [ 1 .. 100 ]
Default: 50

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "has_more": true,
  • "next_cursor": "string"
}

Products

Your products, their cost and the stock we hold.

Products and stock

Your products with their agreed cost and the stock we hold. Needs products:read.

Authorizations:
apiKey
query Parameters
store
string

Only this store (st_...). Leave out for every store your key covers.

sku
string

Comma-separated SKUs (up to 200).

cursor
string

The next_cursor from the previous page.

limit
integer [ 1 .. 500 ]
Default: 100

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "has_more": true,
  • "next_cursor": "string"
}