Integration flow
This page describes the standard way to accept Sevi as a payment provider. Sandbox (https://sandbox.sevi.io/graphql) behaves exactly like production (https://partner.sevi.io/graphql), so whatever you build and test against the sandbox works the same way in production.
The flow in one picture
Click a step number to jump to its explanation, or a link under it for the API / webhook reference.
PENDINGpayment PENDINGAWAITING_SHIPMENTPAIDDELIVEREDTOP_UP · COMPLETEDStep by step
1. Create the order
Call orderCreate with your invoice: items, buyer phone number, billing and shipping details and your own invoice number in platformReference. Store the returned order.id and order.referenceNumber — you need the id for orderDeliver and both appear on every webhook.
Authenticate with the API token of your seller account, see Authentication.
2. Let the buyer pay
How the payment is collected depends on the buyer's available Sevi credit:
- Credit available → automatic. If your seller account has seller-initiated payment enabled (ask Sevi to switch it on), Sevi charges the buyer as soon as the order is created, with no buyer action. The amount is taken from the buyer's available Sevi credit first, then from their Sevi wallet balance.
- Not enough credit → buyer interaction required. Whatever credit and wallet don't cover, the buyer pays through the payment link: Sevi sends them a top-up request, and they have 2 days to pay before the payment is cancelled and any partial funds are refunded. Without seller-initiated payment, the buyer always pays through the link.
orderCreate returns a paymentLink. Redirect the buyer to it, send it by SMS/email, or print it as a QR code on the invoice — see Payment link. On the payment page the buyer chooses M-Pesa, their Sevi wallet, or (if eligible) Sevi credit / pay later.
Either way you receive the same PAID webhook in step 3.
Optionally pass a returnURL so the buyer is sent back to your shop after paying — see Return URL. The return URL is for user experience only; the webhook is the source of truth.
3. Receive the "paid" notification
When the payment is complete Sevi sends an ORDER webhook with:
status: "AWAITING_SHIPMENT"paymentStatus: "PAID"paidAt: when the payment was captured
At this moment the buyer has paid but the money is held by Sevi until the goods are delivered. You can now release the goods.
4. Deliver and confirm delivery
Ship the goods, then confirm the delivery in one of these ways:
- Your ERP updates the order in Sevi as delivered by calling
orderDeliverwith the order id. This is the expected integration: trigger it automatically when your driver/ERP marks the delivery done, so the seller is paid without waiting for the buyer. For a partial delivery pass the deliveredamount. - The buyer confirms receipt in the Sevi mobile app.
Whichever happens first completes the order; the second one is a harmless no-op. So it is normal to receive a DELIVERED webhook for an order you have not called orderDeliver on yet — check deliveryConfirmedBy to see who confirmed it.
5. Receive the "delivered" and "credited" notifications
After delivery Sevi sends:
- an
ORDERwebhook withstatus: "DELIVERED",deliveredAtanddeliveryConfirmedBy(SELLER,BUYER,SEVIorSYSTEM); - a
TRANSACTIONwebhook for the seller wallet:transactionType: "TOP_UP",status: "COMPLETED",paymentType: "ORDER",orderIdset andhold.wasHeld: truewithhold.releasedAt. This is the moment the money is credited to your Sevi wallet.
The order is now complete. Mark the invoice as paid in your system.
6. Settlement
The available balance of your Sevi wallet is paid out automatically once a day (in the evening, East Africa Time) to your registered bank account, M-Pesa paybill or till. Each payout arrives on the transaction webhook as a DEDUCT with paymentType: "MONEY_REQUEST" and no orderId; a payout fee, if any, arrives as a separate DEDUCT.
Status reference
| What happened | order.status | order.paymentStatus | Seller wallet credited? |
|---|---|---|---|
| Order created, buyer has not paid | PENDING | PENDING | No |
| Buyer paid part (deposit for credit) | PENDING | PARTIALLY_PAID / CREDIT_PROPOSAL_INITIATED | No |
| Buyer paid in full / credit approved | AWAITING_SHIPMENT | PAID | No — held by Sevi |
| Delivery confirmed | DELIVERED | PAID | Yes |
Order abandoned before payment, or cancelled with orderCancel | ARCHIVED / CANCELLED | PENDING | No |
| Refunded / returned | REFUNDED / RETURNED | REFUNDED / PARTIALLY_REFUNDED | Reversed |
Rules of thumb
- Use webhooks, not polling. Configure the
ORDERandTRANSACTIONwebhooks (Webhooks). UseorderSearchonly to reconcile or to recover after downtime. - Webhooks can arrive out of order and can be retried. Always act on the current
status/paymentStatusin the payload, and make your handler idempotent (key onorder.id/ transactionid). PAID≠ seller paid. The seller wallet is credited only after delivery is confirmed. Use theTRANSACTIONwebhook (ororder.status = DELIVERED) for your "money received" bookkeeping.- Do not parse descriptions. Use
status,transactionType,orderIdand theholdobject. Descriptions are human-readable text and may change. - Only call
orderDeliverafterPAID. Earlier calls are rejected (not queued) — retry after the paid webhook. - Unpaid orders expire. If the buyer never pays, the order is archived automatically; call
orderCancelto close it immediately when the buyer abandons checkout.
Optional: show credit options up front
Before creating the order you can call orderPaymentProposals with the same input as orderCreate to show the buyer which pay-later options Sevi would offer. This is not required — the payment page shows the same options.