Orishare
Loyalty guides

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.

SectionWhat it holds
revenuePer 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_purchaseCustomers with an order in the period and how many ordered twice or more, for everyone, members and non-members.
reward_costPer 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.
pointsPer currency: issued, redeemed, expired and transferred in the period, outstanding now, and the money value when configured.
store_credit_liabilityStore credit customers hold now, per wallet.
roiPer ISO currency: incremental revenue, reward cost and their ratio, or a reason when it cannot be computed.
method, limitationsHow 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_id or one of its discount_codes is the order reference of store credit that was not voided, or one of its discount_codes is 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, roi is null and reason says 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.complete is false when 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.

On this page