How to Handle Refund, Cancel, and Expired OTP API Orders
In OTP API integration, the hardest part is often not creating an order, but settling it after it starts. An order can succeed, receive OTP, be cancelled by the user, fail on the server side, or expire. If this flow is poorly designed, reseller systems may create double refunds, mismatched balances, or orders that appear active even after they are finished.
This guide explains how developers should handle refund, cancel, expired, failed, and success states safely. The main principles are idempotency, clear terminal statuses, and auditable balance ledgers.
Understand order statuses
Different systems may use different names, but conceptually there are three groups. First, active statuses such as pending or waiting. Second, successful statuses such as OTP received or success. Third, terminal failure statuses such as cancelled, expired, or failed.
Once an order enters a terminal status, your system must stop performing balance-changing actions more than once. Terminal means the final decision has been made.
Do not assume every cancel means full refund
Cancellation can mean several things. The user cancelled before OTP arrived, the server failed, the target app did not send OTP, or the order took too long. Some products may refund fully. Others may have specific settlement rules. Your backend should follow the API response and product rules instead of inventing assumptions.
Use a ledger, not only balance updates
Every balance change should create a balance log. At minimum, store user_id, type add/subtract, amount, before, after, order reference, note, and timestamp. With a ledger, you can audit user complaints and worker bugs.
Updating the balance column directly without logs makes problems hard to trace. The ledger is your evidence.
Design refund idempotency
Refunds need a guard. For example, store a refund_key derived from the order reference. When refund processing starts, check whether that refund_key was already used. If yes, do not add balance again. This protects against double click, worker retry, timeout, and parallel requests.
The same principle applies to cancellation. If a user clicks cancel twice, the second response may say the order is already cancelled, but the balance must not increase twice.
Safe cancel flow
- Load local order by user and order reference.
- Check whether the status is already terminal.
- If not terminal, call the cancel API.
- Reload order status from the API if needed.
- Calculate settlement based on response and rules.
- Acquire a lock or refund guard.
- Write refund balance log once.
- Update local status to terminal.
Expired order flow
Expired orders should be processed by a scheduled worker. The worker finds active orders past their time limit, checks the latest API status, and settles them. Do not rely only on the user keeping the page open. Settlement must continue even if the browser is closed.
Failed order flow
Failed means the order cannot continue. Causes may include unavailable stock, unsupported service, or the target app not sending OTP. For resellers, the important part is showing a clear message and making sure the balance follows the settlement result.
Success flow
If OTP is received and the order succeeds, do not allow automatic refund for that order unless a specific rule says otherwise. Mark the order as complete, store OTP if needed, and stop polling. If a cancel request comes after success, respond clearly that the order is already completed.
Required audit data
- Unique order reference.
- Create-order idempotency key.
- Refund guard key.
- Complete balance logs.
- Worker logs for polling and settlement.
- Admin logs for manual adjustments.
FAQ
Why does double refund happen?
Usually because cancel requests are sent more than once, workers retry after timeout, or the refund process has no unique guard.
Can frontend update balance directly?
No. Frontend should only request an action. All balance changes must happen on the backend after validation and logging.
What if the cancel API times out?
Do not refund based on assumption. Check the order status again, then settle based on the latest state.
With idempotent flows and a clean ledger, OTP API integration becomes much safer against retries, timeouts, and user complaints. OTPZap provides order status and cancel/refund flows that resellers can use as a foundation for safer systems.