ROI and revenue
See what members spend compared with everyone else, what rewards cost, what you owe in points and store credit, and the return of the program.
GET /v1/loyalty/roi answers "is the program paying for itself?" for one period. It reads the
orders you already send as events, the ledger, store credit and partner rewards, and returns
every money figure per ISO currency, in integer minor units (cents for USD). Amounts in
different currencies are never added together.
1. Send orders as events
Orders are events with an integer amount_minor and an ISO currency property. The Shopify and
Stripe connectors send order.completed this way; from your own backend:
curl -X POST "$ORISHARE_API/v1/events" -H "Authorization: Bearer $SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"id":"order-1001","name":"order.completed","customer_id":"user_42",
"properties":{"order_id":"1001","amount_minor":4200,"currency":"USD",
"discount_codes":["SAVE-5"]}}'order_id lets the report count an order once even if it was sent twice. discount_codes lets
it see orders paid with a reward code or store credit. Orders with "test": true are left out.
2. Tell the report what an order is and what a point is worth
By default only order.completed counts. Add your own order events, and give each points
currency a value so that redemptions and the outstanding balance have a money cost:
curl -X POST "$ORISHARE_API/v1/loyalty/reporting_settings" \
-H "Authorization: Bearer $SECRET_KEY" -H "Idempotency-Key: reporting-1" \
-H "Content-Type: application/json" \
-d '{"order_events":["order.completed","pos.sale"],
"point_values":[{"currency":"points","iso_currency":"USD","minor_per_unit":"0.5"}]}'minor_per_unit is a decimal string: "0.5" means one point is worth half a cent. A currency
without a value is still reported in points, with no money cost.
3. Read the report
curl "$ORISHARE_API/v1/loyalty/roi?from=2026-09-01T00:00:00Z&to=2026-10-01T00:00:00Z" \
-H "Authorization: Bearer $SECRET_KEY"from and to default to the last 30 days; a period is at most 400 days. Add
currency=USD to keep only one ISO currency in the money sections.
| Section | What it holds |
|---|---|
revenue | Per ISO currency: orders and revenue, split into members and non_members with the average order value of each, and the orders influenced by rewards. |
repeat_purchase | Customers with an order in the period and how many ordered twice or more, for everyone, members and non-members. |
reward_cost | Per ISO currency: store credit captured less refunded, the merchant-funded cost of partner rewards, points redeemed at their value, and the total. Partner-funded cost is shown apart and not counted. |
points | Per currency: issued, redeemed, expired and transferred in the period, outstanding now, and the money value when configured. |
store_credit_liability | Store credit customers hold now, per wallet. |
roi | Per ISO currency: incremental revenue, reward cost and their ratio, or a reason when it cannot be computed. |
method, limitations | How the numbers were computed and what they do not account for, in plain words. |
How the numbers are computed
- A member is a customer (with every profile merged into it) that had any ledger entry before the order. Everyone else is a non-member for that order, so a customer's first order before joining counts as a non-member order.
- An order is influenced by rewards when its
order_idor one of itsdiscount_codesis the order reference of store credit that was not voided, or one of itsdiscount_codesis a reward code that was handed out. - Incremental revenue = member revenue minus member orders times the non-member average order value, never below zero.
- ROI = incremental revenue / reward cost. With no member orders, no non-member orders or no
reward cost in a currency,
roiisnullandreasonsays which.
Limitations
- Members choose to join, so part of the difference between members and non-members is not caused by the program. Treat incremental revenue as an estimate.
- Revenue is gross: refunds are not subtracted.
- Order events are kept for 90 days in a live environment (30 in a test environment).
coverage.completeisfalsewhen the period starts earlier, and only the retained orders are counted. - Outstanding points and store credit are today's balances, not the balances at the end of the period.
The response carries the same method and limitations, so an AI agent reading it can explain
the numbers without this page.