Payment orchestration · Lifecycle, routing and failure safety

The 60-second model#

A payment orchestrator presents a unified integration while selecting/interacting with payment providers according to merchant configuration and eligibility. It must normalize results without losing provider-specific meaning. Merchant UX success, an orchestration API response, PSP authorization, capture and bank settlement are different observations.

Interviewers can assess whether you recognize financial integrity and unknown outcomes, not whether you have memorized a provider's API. The supplied JD establishes orchestration and multiple PSPs; the model below is general and must be checked against actual product contracts.

Participants and identifiers#

Concept Meaning QA observation
Merchant Business accepting payment Tenant ownership, configuration, permissions
Customer / payer Initiates the purchase Correct amount, currency, redirects and communication
Orchestrator Unified flow, provider selection and normalization Correct route, stable operation identity, accurate final state
PSP / acquirer / issuer Provider processing, merchant acquiring and customer bank roles Provider response, scheme/network and issuer decision; roles vary by integration
Payment ID Business operation in the platform Remains correlated across attempts
Attempt ID One provider-processing attempt Route, timing, normalized and raw outcome
Provider reference PSP-side identifier Reconcile uncertain attempts and provider reports
Idempotency key Contract-supported duplicate submission identity Scope, same/different payload, concurrency and expiry behavior
Event ID Callback/message identity Deduplication and auditability; not necessarily one per payment

Do not use “transaction ID” without identifying its system and grain. One payment may have several attempts, captures or refunds. A duplicate at one grain may be legitimate at another.

Lifecycle and invariants#

Operation Meaning Required tests
Authorization Approval/reservation, not settlement Approve/decline, expiry, amount/currency, no assumed final transfer
Capture Request to collect authorized funds Full/partial capture, remaining amount, duplicate protection
Void / cancellation Cancel before a relevant processing boundary Allowed states, races with capture, provider confirmation
Settlement Financial clearing/funding stage Report reconciliation, fees/time windows and provider-specific timing
Refund Return against a captured payment Full/partial, cumulative cap, pending/failure, duplicate callback
Dispute / chargeback Separate dispute process State/notification/permissions; not identical to a voluntary refund

Illustrative state graph: CREATED → PENDING → REQUIRES_ACTION / AUTHORIZED / DECLINED; AUTHORIZED → CAPTURED / VOIDED; refund has its own lifecycle. This is not an OMNO state specification. Ask whether automatic capture exists, which transitions are terminal, and how partial operations are represented.

Invariants: captured total does not exceed the authorized/allowed total under the contract; refunded total does not exceed eligible captured amount; currency is preserved; events do not duplicate ledger effects; tenant A cannot read/refund tenant B's payment; historical audit facts are not erased by a later state change.

Routing and fallback decisions#

Condition Test design Unsafe shortcut
Merchant/currency/provider eligibility Eligible candidate selected; ineligible providers excluded Assume every provider supports every currency/method
Rule priority / default Boundary and conflicting rule tests; no-match behavior Only test first happy-path route
Weighted distribution Controlled seed/config or statistically justified sample Assert exact 50/50 from two random payments
Provider definitely unavailable before submission Verify configured fallback policy Treat every timeout as a safe decline
Provider outcome unknown after submission Reconcile original attempt before another charge Blindly route the same payment to another PSP
Hard decline / soft failure Follow explicit retry/fallback policy and reason classification Automatically bypass every decline
Config update Version, cache propagation and rollback behavior Change shared routing rules during unrelated tests

Provider health, geography, currency, cost or historical acceptance can be possible routing inputs in an orchestrator. The JD does not confirm which OMNO implements. Present them as questions or hypothetical test dimensions.

Ambiguous timeout: the highest-value scenario#

Scenario: PSP A may have accepted a payment, but the orchestrator timed out before receiving its response. A second attempt through PSP B could create a duplicate charge.

Ideal reasoning: distinguish “not sent,” “explicitly declined,” and “sent but unknown.” Retain operation/attempt/provider references and query the supported PSP/reconciliation path. Keep an explicit unknown/pending state if necessary. Apply only the documented, enforced idempotency/retry/fallback policy. Verify late success/decline callbacks, callbacks arriving after a retry decision, duplicate events and one logical financial effect.

typescript
// Standalone decision model, illustrative policy rather than a payment engine.
export type Attempt =
  | { kind: 'not-submitted'; reason: string }
  | { kind: 'declined'; retryAllowed: boolean }
  | { kind: 'unknown'; reference: string }
  | { kind: 'succeeded'; reference: string };
export function nextAction(attempt: Attempt): string {
  switch (attempt.kind) {
    case 'not-submitted': return 'consult-fallback-policy';
    case 'declined': return attempt.retryAllowed ? 'consult-retry-policy' : 'stop';
    case 'unknown': return 'reconcile-original-attempt';
    case 'succeeded': return 'record-success';
  }
}

Wrong: “Retry until the payment passes.” Right: “Determine whether the first attempt committed and follow the agreed safe-retry contract.” An idempotency key at the orchestrator boundary does not automatically deduplicate two different providers unless the system implements that coordination.

Amounts, currency and concurrency#

Do not compare decimal currency with floating-point equality after repeated arithmetic. Use integer minor units or a defined decimal library; currency scale varies and must come from the contract. Check minimum/maximum/zero/negative values, precision, unsupported currency, large values, rounding rules, and JSON serialization limits. Do not assume every currency has two decimal places.

typescript
// Standalone exercise: amounts already expressed in declared integer minor units.
export function canRefund(captured: number, refunded: number, requested: number): boolean {
  const values = [captured, refunded, requested];
  if (!values.every(Number.isSafeInteger)) return false;
  return captured >= 0 && refunded >= 0 && requested > 0 && refunded <= captured &&
    requested <= captured - refunded;
}

The function checks a local invariant only. Two concurrent refunds can each pass a stale client-side check and together exceed the remaining balance. A backend transactional/concurrency mechanism must enforce the invariant. Test competing requests against one deliberately owned payment and inspect accepted totals and conflict responses.

3DS, redirects and sensitive data#

3-D Secure authentication can introduce browser challenges/redirects and asynchronous outcomes; it is not the same as card authorization or a guarantee of successful payment. In provider sandboxes test frictionless/challenge success, challenge failure, cancellation, timeout, return URL tampering and refresh/back behavior. Do not promise a specific challenge path for every issuer/provider.

Use only test-mode provider instructions and approved synthetic tokens. Prevent raw card/security-code data from appearing in logs, traces, screenshots, URLs or assertions. Do not store payment secrets in fixtures or commit saved authentication state. Compliance scope belongs to the actual integration/security process, not an invented interview claim.

A risk-first sandbox matrix#

Priority Scenario Evidence
P0 Approved payment One business payment, correct amount/currency, agreed final state, proper merchant
P0 Double-click / repeated request Deduplication under actual key contract, one intended effect
P0 Timeout after possible commit Reconciliation and late callback; no blind second charge
P0 Cross-merchant lookup/refund No unauthorized data/action, safe error
P0 Duplicate/out-of-order webhook No state regression or duplicate ledger effect
P1 Partial capture/refund limits Correct cumulative totals and concurrency behavior
P1 Provider outage/fallback Correct eligible route and policy, preserved attempt identity
P1 Routing config change Controlled version/caching effects and isolated test configuration
P1 UI says success but service pending Truthful user feedback; authoritative state reconciliation

Interview answer and references#

30 seconds: “For an orchestrator I test routing correctness and financial integrity. I separate authorization, capture and settlement, track payment versus provider-attempt identity, and prioritize duplicate submissions, uncertain PSP timeouts, webhooks and merchant isolation. A timeout is not proof of failure, so I reconcile before another financial attempt.”

90-second answer: how would you test fallback?

I ask which provider outcomes allow fallback and whether submission definitely happened. With controlled PSP simulators I cover success, explicit rejection, connection failure before submission and timeout after possible acceptance. I inspect route choice, attempt identity, normalized result and audit evidence. In the unknown case I verify the reconciliation and late-callback policy instead of requiring immediate fallback. I test duplicate submissions and conflicting callbacks, then confirm one logical charge in the authoritative sandbox evidence. Real PSP sandbox integration complements simulator tests because mocks cannot prove actual provider contracts or network configuration. I isolate merchant routing configuration and redact sensitive data from reports.

Memory hook: one payment, many observations; unknown is not declined. Provider-specific further reading: Stripe idempotency, Stripe webhooks. These illustrate one provider's contract, not OMNO's or every PSP's semantics. Next: test design.

Quick practice#

What is payment orchestration?
  • A unified merchant integration coordinates provider selection and processing
  • Verify normalization, configuration and financial effects across provider attempts.

Pitfall: Assuming every PSP has identical semantics.

Full explanation.

Authorization versus capture versus settlement?
  • Authorization approves or reserves under the contract, capture requests collection and settlement is a later financial stage
  • Test each boundary and its own evidence.

Pitfall: Calling an authorization response settled funds.

Full explanation.

Payment ID versus attempt ID?
  • A payment is a business operation while an attempt represents one provider interaction
  • Correlate provider references and effects without treating every attempt as a new purchase.

Pitfall: An ambiguous transaction ID with no system/grain.

Full explanation.

Mid-Level QA Automation Engineer — Payment Orchestration · CV refreshed 2026-10-16. Prepared from reviewed role-specific sources.