iPay integration: where payment breaks in a mobile app
iPay integration is not the "Pay" screen but the consistency of three parties: the app, the payment service, and your backend.
A payment is considered successful only when all three see the same status, and almost any payment failure in the app occurs at the junction between them, not in the card entry form itself.
The most expensive failure is double charging.
The user did not wait for a response on a weak network, tapped "Pay" again, and the request turned into a separate operation: duplicate protection was either not built in or tied to a session that had already been recreated by that point.
A lost webhook looks quieter but hurts more. Confirmation from iPay did not arrive — due to a timeout, service restart, or dropped incoming request — and the order remains in the "awaiting payment" status, even though the customer's money has already been charged. Then come manual reconciliations, support requests, and refunds.
With unstable connectivity, a third class appears — a stuck payment status. The app closed before receiving a response, and on the next launch it does not find a local order, so the operation exists but is not linked to the user and is not visible in their history.
All three failures are treated at the architecture level: idempotency keys, redelivery of notifications with acknowledgment, scheduled status reconciliation, and the server as the single source of truth. We explain how this is addressed.
What changes after correct iPay integration
The changes are visible not in the interface but in the numbers: how many payments complete, how quickly the system recovers after a failure, and which support requests disappear.
Share of completed payments
Timeout limits, request retries, and error code handling remove false declines: the customer receives confirmation upon actual charge, not "payment processing." In practice, the share of successful payments rises from 80–85% to 95%+ and stays at that level without manual support intervention.
A retry does not turn into a double charge
Each operation is assigned a unique key, so a retry during a connection drop does not create a second charge — the order goes through exactly once, no matter how many times the customer presses the button. The "charged twice" class of requests and manual reconciliations for them disappear.
Recovery after a failure
A queue of unsent operations and retries with increasing delay allow waiting for iPay instead of losing the order. Recovery time after unavailability shrinks from hours of manual corrections to minutes of automatic re-launch — accounting simply sees the final reconciliation.
Refunds and reversals without manual work
Refunds, partial refunds, and reversals are initiated from the admin panel with real-time status, and reconciliation matches on schedule. Support and accounting work with a single source of truth instead of exports and manual spreadsheets.
iPay connection schemes: choosing a mode for the task
The payment acceptance method determines not only the payment screen but also which scenarios the app can cover without rework.
One option handles subscription payments with automatic renewal, another handles one-time charges, and a third is needed where in-app purchase is restricted by store rules. Below are four schemes that are actually chosen between when connecting iPay.
| Option | When it fits | Limitations |
|---|---|---|
| In-app purchase | Subscriptions and one-time purchases of digital content | Store commission; system payment screen instead of your own |
| Subscription payments via gateway | Recurring revenue, your own renewal and pause rules | Need to store consent to charge and handle declines |
| One-time charges via payment link | Balance top-up, one-time access payment | User leaves to the browser, some payments are lost on return |
| Payment on the business side | Services and goods outside digital content | Account linking is needed, otherwise the status will not reach the app |
The choice is dictated by the monetization model: a subscription requires stored consent to recurring charges and handling of failed attempts, while one-time purchases require a quick return of the user to the app.
Schemes can be mixed, but the payment state must be unified, otherwise some users will pay twice and contact support.
Work stages: from payment flow audit to handover
We start work with an audit of the payment flow: we analyze which screens initiate payment, where order identifiers are stored, and how the app learns about the payment result.
We separately check behavior when the app is closed in the middle of an operation and during a connection drop — these scenarios most often produce a charge without credit.
Based on the audit, a payment scheme appears: the sequence of calls, return points to the app, and decline handling rules.
- Payment flow audit. Inventory of payment call sites, analysis of current order statuses and the failed payments log — we record exactly where operations are lost.
- Payment scheme. We agree on the sequence of steps, the required order data set, and screen behavior on decline — before writing code.
- Integration setup. We connect iPay, describe parsing of payment system responses, retries, and re-entry into payment after a failure.
- Scenario verification. We run successful payment, decline, user cancellation, connection drop, repeat payment, and refund — in the test environment and on real operations.
- Pilot operation. We review logs from the first days on real traffic and fix rare combinations of conditions that are not reproduced on the test bench.
- Acceptance and handover. We show the customer the log of performed checks and hand over the payment status map, support instructions, and the procedure for handling disputed operations.
We do not close a stage until all deviations from expected behavior are analyzed. After handover, an instruction remains that helps support distinguish a payment system failure from an app error — without contacting a developer.
What remains with the customer: configurations and procedures
Integration is considered complete not at the moment when payment passes in a test scenario, but when six months later it can be changed without code archaeology.
Therefore each stage is closed with artifacts that remain in your environment: a new developer reads them, support uses them, and audit relies on them. Below is the minimum set that we hand over together with iPay.
- Integration configuration — a single description of parameters: separation of test and production environments, merchant keys and their rotation order, request timeouts, supported payment methods, and currency pairs. Not in a chat thread, but in a file next to the project.
- Payment flow diagram — the path from tapping "Pay" to confirmation, including success, user cancellation, bank decline, and retry. For each branch, it states what status the order receives and what the user sees.
- Access policies — which employees can view and change keys, where secrets are stored, how permissions are granted and revoked, and what happens when a person leaves the team.
- Documentation — a dictionary of statuses and response codes, app behavior for each of them, and the procedure for adding a new payment branch.
- Failure investigation procedure — what data is collected from the device and the server, by what sign we distinguish a payment decline from a network or client issue, and to whom and how quickly it is escalated.
- Acceptance checklist — scenarios run before each release: refund, repeat payment, connection drop in the middle of an operation.
The set lives in your repository and is updated along with the code — it can be used to hand over maintenance to another team or expand the integration on your own.
Payment failure analysis: how stuck orders were reduced threefold
The client came with a symptom: users complain that money was charged but the order was not created.
The share of successful payments stayed around 89%, and every week support manually investigated dozens of stuck orders — while a payment hangs in an uncertain status, neither fulfillment nor refund starts.
The analysis showed: the app considered payment successful based on its own-side response, not on confirmation from iPay. When the screen closed, the connection dropped, or the user left, the confirmation was lost, and the order remained stuck.
Notification reprocessing was not enabled due to duplicates — it produced a second order instead of one.
What was changed in the integration
- Payment confirmation was moved to server-side reconciliation with the gateway: order status changes only on a confirmed event.
- We implemented idempotent retry handling — one charge does not turn into two orders.
- We created a payment state log with background reconciliation: discrepancies surface on their own, not through user complaints.
- We added automatic retry for orders in an uncertain status and duty officer notifications for deviations.
A month after release, the share of successful payments grew from 89% to 99.2%, and the number of stuck orders fell threefold.
Recovery time dropped from 40 minutes of manual investigation to a few minutes of automatic status completion — an engineer gets involved only when there is a real reconciliation discrepancy.
How does in-app payment differ from website payment?
On a website, payment goes directly through acquiring: the user enters a card, the bank confirms the charge, the server receives a notification and grants access.
In an app, the money is accepted by the store, and the customer only receives a purchase confirmation — access is granted after verification on the store side.
Store verifications are the main difference. Each purchase comes with a signed receipt, and paid content must not be granted before it is validated: otherwise a spoofed response from a modified client opens the subscription for free. The server must accept receipts and correctly handle repeated store notifications.
Subscription restoration works differently. The store returns the list of active purchases by account, not by device: after reinstalling the app or changing phones, the subscription is restored by querying the store and reconciling with internal records — without a repeat charge.
Device binding adds another layer. On a website, access is tied to an account and email; in an app, it is tied to a store account that is active on several devices at once.
To prevent a person from getting two independent accesses and losing what they paid for when changing platforms, the purchase is linked to the internal user identifier, and iPay integration serves as a unified registry of rights.
Bottom line: subscription logic lives in one place, and the store and website only supply confirmed events to it. Then payment from phone and from page converges into one status, and the user does not pay twice.
Common technical concerns about iPay integration
Concerns at the start are usually the same: what to do with an already working payment flow, how customers will behave in the subway, roaming, and on poor connectivity, and what confirms reliability before release to app stores. Below are short answers to the ones that most often come up in meetings.
We already have a working payment flow — do we need to rewrite everything?
No. The new payment method is connected alongside the old one: the order and cart screens remain, only the layer that calls the payment service changes.
The old flow continues to accept payments until there is not a single operation left in the reports for the new one — after that we disable it as a separate step.
What does the customer see with weak internet or a connection drop?
The request is placed in a local queue and retried with increasing delay, and the screen displays the "payment processing" state instead of an error.
When connectivity returns, the app sends the request and pulls the current order status — the customer does not lose the payment and does not pay twice.
How is reliability verified before release?
In the test environment, we reproduce failures: connection drop in the middle of payment, delayed service response, app relaunch during an operation, prolonged absence of network. Then we run on real devices and reconcile operation logs with order states.
Can we switch without downtime for customers?
Yes, the switch happens by user percentages: part of the audience works through the new flow, part through the previous one.
The share grows based on successful payment metrics, and rollback comes down to returning the previous value, without stopping the app and without notifying customers.
How are repeated taps on "Pay" handled?
Each attempt is assigned an operation identifier, and a retry with the same identifier is recognized as the same operation — the second charge does not go through.
The customer ultimately sees one order and one payment, and discrepancies are investigated through logs, not manually through support.
Let's discuss the task and come back with an estimate and plan
To come back with a work estimate rather than generalities, we need substantive inputs: the app platform, which payment scenarios are already covered in iPay, how the backend is structured, and whether the provider has a test environment.
If there is no integration yet, describe what should happen on subscription, one-time purchase, and refund; that will be enough for a first estimate.
The estimate is prepared by the engineers who will later lead the implementation, so contentious points surface during the analysis stage, not in the middle of the work.
Based on the analysis, you receive:
- scope of work — which modules we touch in the app and on the server, and what remains unchanged;
- implementation plan by stages: test environment, implementation, checks, release to stores;
- stage timelines with a note on what depends on payment provider responses and moderation;
- work estimate separately for each stage, so you can move in parts rather than all at once;
- collision handling scheme: repeat charges, cancellations, refunds, connection drop at the moment of payment;
- list of accesses, keys, and data needed from you to start.
Describe the task in a convenient form — correspondence, a short call, or repository access. We will come back with an estimate and implementation plan, and we will close unresolved integration questions before work begins.







