Everything a store that is not on Shopify needs — a custom cart, WooCommerce, Magento, a till or a mobile app — in the order you will build it. Use a sticky_test_… key throughout: it writes to a sandbox that mirrors your live rules and tiers, and you can wipe it from the admin.
1. Use your own customer ids
Give every member your customer id as external_ref. From then on, anywhere the API takes a member id you can send ref:<your id> (or phone:<number>) — you never need to store ours.
curl -X POST https://stickytier.com/v1/members \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: signup-CUST-1001" \
-d '{"email":"asha@example.com","phone":"+919812345678","external_ref":"CUST-1001",
"accepted_terms_version":"1","marketing_consent":true}'
curl https://stickytier.com/v1/members/ref:CUST-1001 -H "Authorization: Bearer $KEY"Enrolling records that the customer accepted your programme terms. If you only need to look someone up (or create a silent prospect who has not agreed to anything yet), use POST /v1/members/resolve. Update profile fields with PATCH /v1/members/{id}; honour an erasure request with DELETE /v1/members/{id}.
2. Send orders as events
Send an event when an order is placed, paid, fulfilled, cancelled or refunded. Processing is asynchronous: you get 202 and an event id. Identify the customer with customer_ref, email or phone. gross_cents is the amount points are earned on — send your eligible merchandise total, in minor units.
curl -X POST https://stickytier.com/v1/events \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"type":"order.paid","order_ref":"ORD-5001","customer_ref":"CUST-1001",
"gross_cents":249900,"tax_cents":38100,"currency":"INR","payment_method":"prepaid",
"aggregate_version":2,
"lines":[{"product_ref":"SKU-1","amount_cents":249900,"quantity":1,"tags":["apparel"]}]}'Retrying is always safe: the same order_ref and type is the same event. Send aggregate_version (any number that only goes up per order) so a late, older event can never overwrite a newer one. Backfilling history? Send batches of up to 100 — a batch costs one request per 10 events against your rate limit.
Points may stay pending until your return window passes. To see what became of what you sent — and why an event was ignored — list them:
curl "https://stickytier.com/v1/events?status=failed" -H "Authorization: Bearer $KEY"
curl "https://stickytier.com/v1/events?order_ref=ORD-5001" -H "Authorization: Bearer $KEY"3. Show the balance
GET /v1/members/{id} returns balances.spendable_cents (what can be spent right now), pending_cents, the member's tier and their referral code. GET /v1/programmes returns your earning rules and the whole tier ladder for a “how it works” page. Call these from your server — API keys must never reach a browser.
4. Redeem at checkout
Never debit points while the customer is still paying. Reserve them, take payment, then confirm — or release if the payment fails. A reservation expires on its own (15 minutes by default), so an abandoned cart costs the customer nothing.
# a) What may this customer spend on this cart?
curl -X POST https://stickytier.com/v1/redemption-quotes -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"member_id":"ref:CUST-1001","eligible_total_cents":249900,"payment_method":"prepaid"}'
# → spendable_cents, minimum_cents, maximum_cents, tender_blocked
# b) Hold the points while they pay
curl -X POST https://stickytier.com/v1/redemption-reservations -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" -H "Idempotency-Key: cart-88431" \
-d '{"member_id":"ref:CUST-1001","amount_cents":50000,"cart_ref":"cart-88431",
"eligible_total_cents":249900,"payment_method":"prepaid"}'
# c) Payment succeeded → burn them d) Payment failed → give them back
curl -X POST .../v1/redemption-reservations/$ID/confirm -d '{"order_ref":"ORD-5001"}'
curl -X POST .../v1/redemption-reservations/$ID/releaseOr skip (c): put "reservation_id" on the order event and we confirm it when the order lands. 422 rule-ineligible means your own programme rules said no (minimum, share of the order, payment method) — the quote tells you the allowed range up front.
5. Or issue a voucher code
For a till or a phone order: POST /v1/members/{id}/redemptions debits the points and returns a single-use code (valid 72 hours by default). Whoever takes the payment looks it up and confirms it — no need to have stored anything:
curl "https://stickytier.com/v1/redemptions?code=RWD-7K2M-Q9XA" -H "Authorization: Bearer $KEY"
curl -X POST https://stickytier.com/v1/redemptions/$ID/confirm -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" -d '{"order_ref":"POS-7781"}'Unconfirmed vouchers return their points automatically when they expire; /void does it at once.
6. Refunds and cancellations
curl -X POST https://stickytier.com/v1/events -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"type":"order.refunded","order_ref":"ORD-5001","refund_ref":"RF-220","refunded_cents":249900}'Points earned on the refunded amount are taken back; a partial refund takes back a proportional share. If the customer already spent them, their balance goes negative until they earn again — your programme settings decide what happens next. order.cancelled reverses the whole order.
7. Referrals from your own signup form
Show each member their referral_code. When a new customer signs up with a code, enrol them and then tell us:
curl -X POST https://stickytier.com/v1/referrals -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"code":"K7Q2M9XA","friend_member_id":"ref:CUST-1002"}'The advocate is rewarded when the friend's first qualifying order arrives. A referral our fraud checks distrust comes back held and pays nothing until someone reviews it.
8. Stay in sync with webhooks
Subscribe to balance.updated and you hear about every change to a balance — earns, releases from pending, redemptions, expiries, tier and referral credits — within seconds, however it happened. Verify the signature (see Webhooks), make the handler idempotent on the delivery id, and use Send test event in the admin (or POST /v1/webhook_endpoints/{id}/test) to check your receiver before going live.
9. Go live
Swap the test key for a sticky_live_… key with only the scopes that server needs. Every response carries an X-Request-Id; rejected calls are listed for 14 days under Developers → API activity. Watch X-RateLimit-Remaining, back off on 429, and retry 5xx with the same Idempotency-Key.