Orishare
Loyalty guides

Partner rewards and gift cards

Supply catalogue rewards through a gift-card supplier or a brand partner, share the cost with the partner, and settle per period.

A partner reward is a catalogue reward that someone else delivers: a gift-card supplier sells you a card, or a brand partner fulfils an experience and pays for part of it. Orishare keeps the supplier, what it sells, which rewards it supplies and who pays how much, places one supplier order per redemption, and reports what you owe and what the partner covers.

All amounts are integers in minor units of the item's ISO currency (cents for USD).

1. Register the supplier

curl -X POST "$ORISHARE_API/v1/reward_suppliers" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Idempotency-Key: supplier-giftly" -H "Content-Type: application/json" \
  -d '{"key":"giftly","name":"Giftly","kind":"gift_card","adapter":"manual"}'
  • kind: gift_card (a supplier that returns gift-card codes) or partner (a brand that fulfils the reward itself).
  • adapter: how orders reach the supplier. manual accepts every order as pending and you (or the partner) confirm it with the reconcile command. fake is a deterministic test supplier for test environments only. http is reserved for real supplier integrations; until one is installed in the deployment, creating such a supplier answers capability_unavailable.
  • credentials (optional): API keys for the supplier. They are encrypted with the deployment's dedicated key and never returned by any read; responses only say credentials_configured. Without that key, sending credentials answers capability_unavailable; suppliers without credentials still work. PATCH with "credentials": null erases them.

DELETE /v1/reward_suppliers/{id} disables the supplier and erases its credentials. Its links and orders stay for settlement.

2. Keep the supplier catalogue

curl -X POST "$ORISHARE_API/v1/reward_suppliers/$SUPPLIER/catalogue_items" \
  -H "Authorization: Bearer $SECRET_KEY" -H "Idempotency-Key: item-amz-25" \
  -H "Content-Type: application/json" \
  -d '{"sku":"AMZ-25","brand":"Amazon","title":"Amazon 25 USD","face_value_minor":2500,"face_currency":"USD","cost_minor":2375}'

face_value_minor is what the customer receives, cost_minor what the supplier charges. A change to an item applies to orders placed afterwards; placed orders keep their values.

A link says which catalogue item supplies an offer version (or a reward) and how much of the cost the partner funds: a percentage or a fixed amount per order.

curl -X POST "$ORISHARE_API/v1/reward_suppliers/$SUPPLIER/links" \
  -H "Authorization: Bearer $SECRET_KEY" -H "Idempotency-Key: link-amz" \
  -H "Content-Type: application/json" \
  -d '{"catalogue_item_id":"'$ITEM'","offer_version_id":"'$OFFER_VERSION'","funding":{"funded_percent":50}}'
  • funding.funded_percent (0 to 100): the partner pays that share of the cost, rounded half up to a whole minor unit; you pay the rest.
  • funding.funded_minor: the partner pays that amount per order, at most the cost; you pay the rest.

The two parts always add up to the cost. Links are never edited: posting a new link for the same offer version closes the open one at that instant. A redemption uses the terms in force when it was made, and every supplier order records the split it was placed with, so later changes never rewrite settled figures.

Offers delivered by a supplier use delivery: { "type": "webhook" } in their terms.

4. How a redemption reaches the supplier

The fulfilment job hands each pending webhook delivery to the supplier provider. For a redemption with a link it records one supplier order (never two, whatever is retried) and asks the supplier with an idempotency key derived from the redemption:

Supplier answerSupplier orderRedemption
fulfilledfulfilled; a gift-card code is stored encryptedfulfilled
pending (accepted, not done)pendingwaits for reconciliation
failed, try againpendingretried by the next run
failed for goodfailedstays pending, can be cancelled
no answer in timependingwaits for reconciliation

Only a link that was in force when the customer redeemed is used: a link added later never applies to earlier redemptions. A supplier is called by one worker at a time per redemption; a second caller, or a retry while the first call may still be at the supplier, waits for reconciliation instead of being treated as a failure. Suppliers that can return gift-card codes are only called when the deployment has its encryption key, so a code is never lost; until then their orders stay pending with the reason capability_unavailable. The fake adapter cannot exist in a live environment.

GET /v1/reward_suppliers/{id}/orders lists the orders (filter with status). To settle a pending order, call reconcile: Orishare asks the supplier again with the same idempotency key, or for a manual partner records the outcome you send, and then finishes the redemption. After a "retry later" answer the job waits longer before each new attempt and stops after a fixed number; reconcile retries at once and starts that count again.

curl -X POST "$ORISHARE_API/v1/reward_suppliers/$SUPPLIER/orders/$ORDER/reconcile" \
  -H "Authorization: Bearer $SECRET_KEY" -H "Idempotency-Key: reconcile-$ORDER" \
  -H "Content-Type: application/json" -d '{"outcome":"fulfilled"}'

A supplier is never asked while the redemption can still be cancelled: before the call, the redemption moves into a state that refuses cancellation (in delivery), and stays there while the supplier's answer is pending or missing, until reconcile settles it. Reconcile finishes the redemption when the supplier confirms. A cancelled redemption is never sent to the supplier: reconcile cancels its pending order at the supplier, or marks it cancelled. Should the supplier still confirm an order for a cancelled redemption, the order becomes fulfilled_after_cancel.

When a supplier cannot be asked (for example the encryption key is missing), the order waits and is retried later with a growing delay (30 seconds, doubling, at most an hour), so other redemptions keep moving.

GET /v1/reward_suppliers/{id}/reconciliation lists the orders that need your decision: fulfilled_after_cancel, cancelled_unverified (cancelled, but the supplier may hold the order and gave no id to check), outcome_unknown (the last supplier call got no answer, or the redemption waits for reconciliation), commerce_unsettled (the supplier settled but the redemption still waits; reconcile, or the next job run, finishes it) and supplier_unsettled (the redemption is fulfilled while the supplier order is not).

Showing a supplier's gift-card code to the customer is not available yet: the code is stored encrypted on the supplier order and no read returns it.

5. Settle

curl "$ORISHARE_API/v1/reward_suppliers/$SUPPLIER/settlement?from=2026-10-01T00:00:00Z&to=2026-11-01T00:00:00Z" \
  -H "Authorization: Bearer $SECRET_KEY"

The report covers the period from from (included) to to (excluded), at most 400 days:

  • items: per catalogue item, orders fulfilled in the period, supplier orders cancelled in the period, and the face value, cost, partner-funded and merchant-funded totals of the fulfilled ones.
  • totals: the same per currency.
  • adjustments: fulfilled orders whose redemption was cancelled and compensated, and orders the supplier fulfilled after the redemption was cancelled. They stay in the totals of the period they were fulfilled in (the supplier delivered and charged) and are listed in the period the cancellation was recorded (adjusted_at), so an earlier period never changes when you run it again; nothing is netted silently.

Every amount in the report is a string of whole minor units, exact at any size (for example "9999999999990000"); counts are numbers.

Add format=csv to also receive the report as CSV text in the csv field, with one item row per catalogue item, one total row per currency and one adjustment row per adjustment.

Scopes: reads need rewards:read, changes need rewards:write.

On this page