- You charged the user off-platform (credits flow)
- You collected an on-chain USDC payment
Most integrators pre-fund Chipi credits and charge their own users by card,
transfer, or in-app balance — that side is yours. When a purchase fails:
- Chipi restores your credits automatically and sends
sku-purchase.refunded(so your ledger reconciles off one signal). - You refund the user in your own payment system (reverse the card charge, credit their in-app balance, etc.) — Chipi never touched the user’s money, so only you can return it.
sku-purchase.failed / sku-purchase.refunded and trigger your
own refund. No on-chain work is involved.Returning the user’s money is always the integrator’s responsibility — you
collected it, so you control where it sits. Chipi restores your credits and
gives you the signal + data to make the user whole.
Webhook events
Configure a webhook at/configure/notifications in the dashboard. Every body is
HMAC-signed (see Verifying the signature).
| Event | Meaning |
|---|---|
sku-purchase.completed | Fulfilled successfully. |
sku-purchase.failed | Terminal failure. Refund the user in your payment system if you charged them off-platform. |
sku-purchase.refunded | Your Chipi credits were restored (internal accounting) — not the user’s money. |
sku-purchase.refund-due | You collected the user’s payment on-chain and owe it back. Carries a refund instruction. |
Verifying the signature
Each delivery includes achipi-signature header: HMAC-SHA256(rawBody, signingKey)
as hex. Verify it against the raw request body before trusting the event.
Executing an on-chain refund
Only relevant if you collected an on-chain USDC payment. Onsku-purchase.refund-due
the payload carries everything you need:
Verify settlement by the Transfer event — never the tx status
A Starknet tx can report
execution_status = SUCCEEDED while the inner
transfer no-op’d (a “phantom success”). Read the receipt and confirm a USDC
Transfer event into your wallet actually fired. No event → no money
arrived → do not refund. This doubles as the ownership gate: only refund
payments that settled into your wallet.Be idempotent on the payment hash
Reserve
refund-<paymentTransactionHash> before sending; if it already
exists, skip. Webhooks can deliver more than once — refund exactly once.Cap the amount
refund.amount is advisory; verify the actual settled Transfer amount and
never exceed it, bounded by a sane maximum. Above the cap, escalate to manual
review instead of auto-paying.Avoid charging twice in the first place
Refunds are the safety net — the better fix is not double-charging:- Reuse the idempotency key on retry.
transactionHashonPOST /v1/sku-purchasesis the idempotency key. Persist it per(skuId, reference, amount)and reuse it when the user taps “try again” — a repeated key returns the existing purchase instead of creating a second charge. - Lock the buy action while a purchase is in flight to prevent a double-submit.
- Chipi also rejects an exact
(skuId, reference, amount)repeat within the carrier’s dedup window before any new debit, as a server-side backstop.
