Read your merchant stats
Six counters, and what each one is not
One authenticated read returns six counters for a merchant you own. The call, its parameters and its response shape are on Merchant routes — this page is how to read the numbers, because four of the six mean something narrower than their names suggest.
Nothing is deployed on a public chain yet — see Quickstart.
What you will build
One GET against your own merchant id, and a correct reading of what came back.
Before you start
- The wallet that owns the merchant identity. This is the only owner-checked read on the
surface: the handler compares your signing address against
ownerOf(merchantId)and answers403otherwise. A teammate holdingPRODUCT_MANAGER_ROLEorCOMMISSION_MANAGER_ROLEcan list your products and change your rates but cannot read this. See Identity and commitments. - A signed request. Same signing scheme as every other
/v1write — see The API. - A merchant registered with us, not merely minted on-chain. See the
404note below.
Prompt mode
Show the prompt
Read my OpenSouk merchant stats and tell me what they mean. My merchant id is 42.
1. GET /v1/merchant/42/stats with a signed request from the wallet that owns merchant 42. Pass
chain_id explicitly — absent, the server uses its first configured chain, which the shipped
default makes Base Sepolia.
2. Report the six counters, and apply these corrections rather than reading the names literally:
- revenue_gross is what BUYERS PAID, in USDC base units (6 decimals). It is not my revenue:
the reviewer commission, the platform fee and any buyer cashback all come out of it. My net
is gross minus commission minus platform fee.
- conversions counts only purchases ATTRIBUTED through OpenSouk. Direct sales on my own pay
target are not here at all, so this is not my total sales figure.
- escrow_settled counts escrows the settlement worker has HANDLED — which includes ones it has
only enqueued, not just ones confirmed on-chain. Do not read it as money that has moved.
- product_count is all my products, active and inactive. active_product_count is the subset
that matches what a product listing returns. Do not compare product_count against a listing.
3. If it answers 403, I am not signing as the identity owner. If it answers 404, either the id
does not exist on-chain or the merchant was never registered with us — those are different
problems.Manual mode
curl -G "https://$OPENSOUK_API/v1/merchant/42/stats" \
--data-urlencode "chain_id=$CHAIN_ID" \
-H "X-Agent-Timestamp: $TS" -H "X-Agent-Signature: $SIG"The /v1 host is api.opensouk.ai. Zero is a valid merchant id here; a negative one is a
400.
How to read the six counters
| Counter | What it actually is |
|---|---|
revenue_gross | What buyers paid, not what you received. It sums the gross of each attributed purchase, so the reviewer commission, the platform fee and any cashback are all still inside it. Your net is gross minus commission minus fee — see Payment flow |
conversions | Attributed purchases only. One per purchase recorded against your merchant id. A direct sale on your own pay target never appears, so this is not a sales total |
escrow_holding | Attributed purchases whose escrow the settlement worker has not handled yet |
escrow_settled | Escrows the worker has handled — which includes ones it has merely enqueued, not only ones confirmed on-chain. Not a count of money that has moved |
product_count | All your products, active and inactive |
active_product_count | The active subset — the only one of the two comparable with a product listing, which filters to active |
The two revenue-shaped figures are the ones worth restating to anyone reading a dashboard built on
this: revenue_gross is a buyer-side number, and escrow_settled is a worker-side number.
Verify
Two cross-checks, using reads you already have:
conversionsshould equalescrow_holding + escrow_settled. Every attributed purchase is exactly one escrow record — there is no separate escrow table — so a mismatch means one of the three is stale rather than that a purchase lost its escrow.active_product_countshould equal the number of products a listing returns for you. Ifproduct_countmatches instead, you are comparing the wrong counter.
Errors and retries
| Status | Body | What to change |
|---|---|---|
400 | invalid merchant id | Unparseable or negative. Zero is valid |
401 | unauthorized | The request carried no usable signature |
403 | caller does not own this merchant | You signed as something other than ownerOf(merchantId) — a per-merchant role does not reach this read |
404 | merchant not found | Two different causes. Either no such token on-chain, or a token that exists but was never registered with us. The summary is built from our own merchant row, so an on-chain-only merchant answers 404 too |
500 | internal error | An RPC or database failure. Retry is yours to make |
This read is deliberately not retried for you. A dashboard load follows no transaction of yours, so there is no just-mined block to wait for, and retrying would add the whole stale-read budget to every genuinely unknown merchant. The register paths, which do follow a transaction you sent, retry instead.
Next steps
- Merchant routes — the route, parameter by parameter
- Payment flow — what turns gross into your net
- List a product — the counter behind
active_product_count