From customer intent to financially trustworthy settlement
A payment system is often introduced as a single API operation:
POST /payments
That API hides the real workflow.
A production payment platform coordinates:
- Customer intent
- Payment-method collection
- Authentication
- Fraud and risk decisions
- Payment processors
- Acquiring and issuing banks
- Asynchronous webhooks
- Financial ledger entries
- Refunds and disputes
- Settlement
- Reconciliation
Some stages complete in milliseconds. Others may remain unresolved for minutes, hours, or days.
The most important design principle is:
A payment is not one remote call. It is a durable sequence of financial state transitions.
The payment lifecycle
A typical payment moves through five broad stages.
- Create the payment intent.
- Collect a payment method.
- Authorize the payment.
- Capture the authorized amount.
- Settle the funds.

Figure 1: The main payment lifecycle, from customer intent to final settlement.
1. Create the payment intent
The payment intent represents the business intention to collect a specific amount from a customer.
It may contain:
Payment Intent ID
Merchant ID
Order ID
Customer ID
Amount
Currency
Payment status
Allowed payment methods
Capture strategy
Idempotency key
Creation time
Expiry time
Example:
{
"paymentIntentId": "pi_9014",
"orderId": "order_4821",
"amount": 4250,
"currency": "INR",
"captureMethod": "MANUAL",
"status": "REQUIRES_PAYMENT_METHOD"
}
The intent should exist before contacting a payment processor. This gives the platform an internal identifier and durable state that remain stable even if processor calls fail.
2. Collect the payment method
The customer selects a card, wallet, bank transfer, or another supported method.
The platform should avoid directly handling raw card credentials wherever possible.
A safer design uses:
- Hosted payment fields
- Processor-provided client libraries
- Tokenization
- Payment-method references
- Short-lived authentication tokens
The application stores a token or reference rather than the underlying sensitive credentials.
3. Authorize
Authorization asks the issuer or payment provider whether the transaction may proceed.
Depending on the payment method, authorization may involve:
- Balance or credit checks
- Fraud screening
- Strong customer authentication
- One-time passwords
- Device challenges
- Risk rules
- Merchant controls
An authorization does not always mean that funds have been fully transferred. It may represent an approval or reservation.
4. Capture
Capture confirms that the merchant wants to collect some or all of the authorized amount.
Capture may happen:
- Immediately after authorization
- When physical goods are shipped
- After a service has been delivered
- In multiple partial captures
- After a manual review
5. Settlement
Settlement is the external financial process through which funds move through processor and banking networks.
The customer-facing payment may appear complete before the merchant’s funds have fully settled.
This distinction is important:
Customer payment succeeded
does not always mean
merchant settlement completed
Core payment-system architecture
A production design should separate customer experience, payment workflow state, processor communication, risk, accounting, and reconciliation.

Figure 2: Core services involved in a payment platform.
The main components are described below.
Checkout or client application
The checkout interface:
- Collects customer intent
- Initiates payment
- Hosts or embeds secure payment fields
- Handles authentication challenges
- Displays the final customer-facing outcome
The client should not be responsible for deciding the authoritative payment state.
It should ask the payment service for that state.
Payment service
The Payment Service is the central domain service.
It owns:
- Payment intents
- Payment attempts
- State transitions
- Idempotency
- Processor routing
- Authorization
- Capture
- Cancellation
- Refund initiation
- Payment events
It should persist its decision before informing downstream systems that the payment succeeded.
Risk engine
The risk engine evaluates whether an operation should proceed.
Inputs may include:
- Customer history
- Merchant history
- Device signals
- Transaction velocity
- Country
- Currency
- Payment method
- Amount
- Previous disputes
- Processor feedback
A risk decision should record:
Decision
Policy or model version
Reason codes
Timestamp
Input reference
Manual-review result
Processor or acquirer integration
The processor connector translates the internal payment operation into a provider-specific request.
A common internal interface may expose:
Authorize
Capture
Void
Refund
Get Status
However, not every provider supports identical capabilities.
The platform should preserve provider-specific differences rather than forcing every processor into an inaccurate lowest-common-denominator model.
Webhook ingestion
Payment providers use webhooks to report asynchronous state changes.
Examples include:
- Authentication completed
- Authorization approved
- Capture completed
- Refund completed
- Dispute created
- Settlement updated
Webhook handling must be durable and idempotent.
Double-entry ledger
The ledger records the financial meaning of successful operations.
Payment state tells the system what operationally happened.
Ledger entries tell the system how money should be accounted for.
Reconciliation
Reconciliation compares:
- Processor data
- Internal payment attempts
- Ledger entries
- Settlement reports
Its purpose is to detect and repair divergence.
Model payment intent and payment attempt separately
A payment intent represents the business objective.
A payment attempt represents one execution against a payment method and processor.
One intent may have multiple attempts.
Example:
Payment Intent: pi_9014
Amount: ₹4,250
Attempt 1:
Card ending 7421
Processor A
Declined
Attempt 2:
UPI
Processor B
Succeeded
Keeping the objects separate allows the system to distinguish:
- One customer payment from several retries
- A processor decline from the overall intent
- A new payment method from a repeated request
- Failover from duplicate processing
Payment state machines
Payment state must be explicit.
Do not rely on loosely related boolean fields such as:
isPaid
isAuthorized
isCaptured
hasFailed
Those combinations can produce invalid states.
Use well-defined state transitions instead.

Figure 3: Payment intent and payment attempt have related but different lifecycles.
Example payment-intent states
CREATED
REQUIRES_PAYMENT_METHOD
REQUIRES_ACTION
PROCESSING
SUCCEEDED
FAILED
CANCELLED
Example payment-attempt states
INITIATED
SENT_TO_PROCESSOR
AUTHORIZED
DECLINED
UNKNOWN
CAPTURED
VOIDED
FAILED
Valid transitions
INITIATED → SENT_TO_PROCESSOR
SENT_TO_PROCESSOR → AUTHORIZED
AUTHORIZED → CAPTURED
AUTHORIZED → VOIDED
Invalid transitions
DECLINED → CAPTURED
CAPTURED → AUTHORIZED
VOIDED → CAPTURED
The service should validate every transition.
It should also retain state history:
Attempt initiated
Request sent to processor
Processor timed out
Status queried
Authorization confirmed
Capture requested
Capture completed
This timeline is valuable for:
- Support investigations
- Incident response
- Dispute analysis
- Reconciliation
- Auditability
Authorization and capture strategies
Not every business captures money at the same point.
Immediate digital purchase
Authorize
↓
Capture immediately
↓
Grant digital access
Physical goods
Authorize at checkout
↓
Reserve inventory
↓
Ship order
↓
Capture payment
Marketplace
Collect from buyer
↓
Record platform and seller obligations
↓
Wait for fulfilment conditions
↓
Create seller payable
Hotel or rental
Authorize estimated amount
↓
Adjust final amount
↓
Capture later
The payment model should support the business workflow rather than force all products into one payment sequence.
Idempotency
Network failures cause clients to retry.
Suppose this sequence occurs:
Client sends authorization request
Payment succeeds
Response is lost
Client retries
Without idempotency, the second request may create another charge.
Every mutating operation should accept or derive a stable idempotency key.
Example:
checkout-83:authorize
Store:
- Idempotency key
- Merchant or tenant scope
- Operation type
- Request fingerprint
- Current processing state
- Final response
- Creation and expiry times
If the same key is reused with different request details, reject it.
For example, do not silently accept the same key for both:
₹4,250 INR
and:
₹8,500 INR
That represents conflicting business intent.
Unknown outcomes
A timeout does not always mean the processor failed.
The processor may have:
- Never received the request.
- Received it but not completed it.
- Completed it but lost the response.
The correct internal status may therefore be:
UNKNOWN
rather than:
FAILED

Figure 4: After a timeout, query the existing operation before retrying.
Place Figure 4 after explaining the three possible timeout outcomes.
The recovery process is:
Send authorization
↓
Timeout
↓
Mark attempt UNKNOWN
↓
Query using operation ID
/ \
Authorized Not found
↓ ↓
Continue Retry safely
Treating every timeout as failure can create duplicate charges.
Treating every timeout as success can create unpaid orders.
Unknown outcomes must be resolved through:
- Provider status APIs
- Idempotency identifiers
- Webhooks
- Reconciliation
- Manual investigation when necessary
Processor routing
A payment platform may use multiple processors.
Routing may consider:
- Country
- Currency
- Payment method
- Merchant configuration
- Historical approval rate
- Processor health
- Cost
- Risk policy
- Data-residency requirements
Persist the selected route with the payment attempt.
Example:
{
"attemptId": "pa_7702",
"processor": "PROCESSOR_A",
"routingRuleVersion": "route-v12",
"paymentMethod": "CARD",
"country": "IN"
}
A retry should not automatically switch processors unless the business explicitly allows the creation of a new attempt.
Otherwise, one customer action could produce charges through two different providers.
Webhook processing
Provider callbacks are a core part of the payment lifecycle.
They are not optional notification messages.
A safe webhook flow should:
- Receive the callback.
- Verify its signature.
- Persist the raw event.
- Deduplicate it.
- Return success quickly.
- Process it asynchronously.
- Apply the state transition idempotently.
- Record the result.

Why persist the raw event?
Persisting the original callback helps with:
- Replay
- Provider disputes
- Debugging
- Schema changes
- Security investigations
- Reconciliation
Do not assume webhook ordering
A system may receive:
Payment Captured
before:
Payment Authorized
because of network delays or provider behaviour.
Use:
- Attempt versions
- Provider timestamps
- Valid state-transition checks
- Status reconciliation
Do not assume one delivery
The same webhook may arrive several times.
Deduplicate using a provider event ID or an equivalent stable identifier.
Double-entry ledger
Operational payment records alone are not sufficient for financial accounting.
A payment may be marked SUCCEEDED, but the platform still needs to represent:
- Processor receivable
- Merchant payable
- Platform fee
- Tax
- Refund liability
- Chargeback adjustment
Use a double-entry ledger.
Every financial transaction produces balanced debit and credit entries.

Figure 6: A ₹1,000 payment is represented through balanced financial entries.
Place Figure 6 after introducing double-entry accounting.
Suppose a customer pays ₹1,000 and the platform fee is ₹30.
The merchant receives ₹970.
Debit Processor Receivable ₹1,000
Credit Merchant Payable ₹970
Credit Platform Fee Revenue ₹30
The transaction balances:
Total debits = Total credits
Ledger principles
Ledger entries should be:
- Immutable
- Currency-aware
- Linked to a business operation
- Created idempotently
- Timestamped
- Auditable
Never edit financial history in place.
If a previous entry must be corrected, create a reversing entry and then post the corrected transaction.
Ledger and payment state are different
Payment state answers:
Did the processor authorize or capture the payment?
Ledger state answers:
Which accounts gained or lost value because of that operation?
Both are required.
Refunds and reversals
A refund is not simply changing:
payment.status = REFUNDED
It is a separate financial operation.
A refund may be:
- Full
- Partial
- Pending
- Failed
- Reversed
- Split across several captures
A payment can also have multiple partial refunds.
Example:
Captured: ₹1,000
Refund 1: ₹200
Refund 2: ₹150
Remaining captured amount: ₹650
The system must ensure:
Total successful refunds ≤ Refundable captured amount
Refund requests require their own:
- Idempotency key
- State machine
- Processor operation ID
- Ledger entries
- Webhook handling
- Reconciliation
Reconciliation
Even a well-designed payment system can diverge from external financial reality.
Common causes include:
- Missing webhooks
- Duplicate callbacks
- Processor-side manual actions
- Timeouts
- Partial captures
- Partial refunds
- Settlement adjustments
- Chargebacks
- Software defects
- Currency or fee differences
Reconciliation compares external and internal records.

Figure 7: Reconciliation compares processor reports, internal attempts, and ledger entries.
Typical mismatch categories
External success, internal missing
The processor completed the payment, but the internal attempt remains unknown or failed.
Internal success, external missing
The system believes the payment succeeded, but the processor has no matching transaction.
Amount mismatch
The internal amount differs from the processor amount.
Currency mismatch
The internal and external transactions use different currencies.
Settlement missing
The payment succeeded, but expected settlement has not appeared.
Fee mismatch
Processor fees differ from the expected fee calculation.
Refund mismatch
A refund exists externally but not internally, or vice versa.
Reconciliation outcomes
A reconciliation item may be classified as:
MATCHED
MISMATCH
INVESTIGATING
REPAIR_PENDING
RESOLVED
MANUAL_REVIEW
Every mismatch should record:
- Owner
- Evidence
- Classification
- Financial value
- Repair action
- Final resolution
- Audit history
Reconciliation is not a reporting feature added later.
It is how the system proves that its financial records match the outside world.
Reliability patterns
Payment reliability depends on explicit patterns.
Transactional outbox
When payment state changes, the system may need to publish an event.
These are two writes:
- Update the database.
- Publish the event.
Use a transactional outbox so the state change and event intent commit together.
Idempotent consumers
Downstream services must tolerate duplicate events such as:
Payment Succeeded
Fulfilment must not ship the same order twice.
Bounded retries
Retry only operations known to be safe.
Use:
- Exponential backoff
- Jitter
- Retry budgets
- Operation IDs
Circuit breakers
Stop sending requests to a failing processor when continued attempts would cause more damage.
A circuit breaker should not hide unknown outcomes. Existing ambiguous operations still require resolution.
Bulkheads
Isolate:
- Processors
- Payment methods
- Merchants
- Worker pools
One degraded integration should not consume every thread, connection, or retry worker.
Security and financial trust
Payment security is not one gateway feature. It applies across the entire system.

Figure 8: Reliability protects execution; security and reconciliation protect financial trust.
Important controls include:
Tokenization
Store payment-method tokens rather than raw sensitive credentials.
Webhook authentication
Verify callback signatures and reject unauthenticated requests.
Encryption
Protect sensitive information:
- In transit
- At rest
- In backups
- In logs and operational exports
Least privilege
Limit access for:
- Services
- Operators
- Support agents
- Reconciliation teams
- Data pipelines
Log hygiene
Never place sensitive payment credentials into:
- Application logs
- Traces
- Error messages
- Analytics events
- Support exports
Auditability
Record:
- Who initiated an action
- Which service executed it
- Which policy allowed it
- Which state changed
- Which amount and currency were involved
- Which processor operation was referenced
API design
A payment API should expose business operations rather than generic updates.
Example endpoints:
POST /payment-intents
POST /payment-intents/{id}/confirm
POST /payment-intents/{id}/capture
POST /payment-intents/{id}/cancel
POST /payments/{id}/refunds
GET /payment-intents/{id}
GET /payments/{id}/timeline
Avoid an endpoint such as:
PATCH /payment/{id}
{
"status": "SUCCEEDED"
}
Clients should not be able to arbitrarily assign authoritative payment states.
Useful response fields
Payment intent ID
Amount
Currency
Current state
Required next action
Payment attempt summary
Version
Safe failure category
Created time
Updated time
Do not expose raw processor responses as the public API contract.
That creates coupling and can reveal sensitive details.
Observability
A payment platform must measure both technical performance and financial correctness.
Technical metrics
- API latency
- Processor latency
- Webhook age
- Retry rate
- Timeout rate
- Queue backlog
- Worker failures
- Circuit-breaker state
Payment metrics
- Authorization approval rate
- Payment success rate
- Capture success rate
- Unknown-outcome rate
- Duplicate-prevention count
- Refund completion time
Financial metrics
- Reconciliation mismatch count
- Reconciliation mismatch value
- Missing settlement value
- Ledger imbalance count
- Unresolved refund value
- Manual adjustment value
Ledger imbalance should remain zero.
Useful dimensions
Segment metrics by:
- Merchant
- Country
- Currency
- Processor
- Payment method
- Client version
- Risk decision
- Failure category
A global success rate may hide a serious problem affecting one processor or one region.
Failure scenarios to test
A production payment system should be tested against failures deliberately.
Test:
- Client retry after timeout
- Processor succeeds but response is lost
- Duplicate authorization request
- Duplicate capture request
- Webhook arrives before API response
- Duplicate webhook
- Out-of-order webhook
- Partial capture
- Partial refund
- Processor outage
- Risk-engine timeout
- Ledger transaction failure
- Event publication failure after database commit
- External payment with no internal attempt
- Internal success with no external payment
- Refund succeeds externally but internal processing crashes
- Reconciliation repair fails
- Processor routing changes during a retry
The payment system is trustworthy only when its ambiguous and failure states are designed as carefully as its happy path.
Key design trade-offs
| Decision | Benefit | Cost |
|---|---|---|
| Separate intent and attempt | Clear retries and processor history | More domain objects |
| Explicit state machines | Prevent invalid transitions | More transition logic |
| Idempotency | Prevent duplicate financial effects | Requires durable operation records |
| Asynchronous webhooks | Handles delayed provider outcomes | Ordering and duplication complexity |
| Double-entry ledger | Strong financial auditability | Additional accounting model |
| Multiple processors | Coverage and resilience | Routing and reconciliation complexity |
| Event-driven integration | Decouples downstream services | Eventual consistency |
| Reconciliation | Detects financial drift | Operational investment |
| Strong security boundaries | Reduces exposure and abuse | More controls and review |
Design review checklist
Before approving a payment design, ask:
- Is payment intent separate from processor attempt?
- What is the authoritative state machine?
- What is the idempotency boundary?
- How are conflicting requests detected?
- How are unknown outcomes represented?
- How does the system query existing processor operations?
- How are webhooks verified and deduplicated?
- What happens when webhooks arrive out of order?
- Which system is financially authoritative?
- Are ledger entries immutable and balanced?
- How are refunds and partial captures represented?
- How does reconciliation detect and repair drift?
- Can one processor outage be isolated?
- Which operations require manual approval?
- Which metrics prove financial correctness.
Final perspective
A payment platform is a consistency, evidence, and recovery system.
Its job is not simply to send an authorization request to a processor.
It must:
- Preserve customer and merchant intent
- Prevent duplicate financial effects
- Represent ambiguous outcomes honestly
- Validate every state transition
- Account for every unit of money
- Process asynchronous external updates
- Detect divergence
- Recover when internal and external state disagree
The strongest design principle is:
Every payment outcome must be durable, explainable, idempotent, and financially reconcilable