Payment orchestration software has nine jobs. Route each payment by rules you can read. Retry the declines worth retrying. Hold card tokens in a form you can take with you. Sign and de-duplicate every API call. Deliver webhooks with real retries. Translate provider codes into one status vocabulary. Match money to payments after settlement. Show you why it picked what it picked. Keep test traffic away from live traffic.

That is the checklist. The rest of this guide turns each item into a question you can ask on a demo, and gives you real numbers from a working codebase as a yardstick.

One caveat before the numbers. They come from a codebase I work in daily and from its beta environment, not from a production fleet — there is no production fleet yet. Use them as a reference point for what “specific” sounds like, not as an industry benchmark.

If you are still working out whether you need this class of software at all, read what payment orchestration is first and come back here to choose.

What is payment orchestration software?

It is the software that sits between your checkout and several payment providers, decides where each payment goes, and reports on all of them in one vocabulary.

Two words often get mixed up here. Orchestration is the practice. Payment orchestration software is the thing you buy or build to do it. A payment orchestration platform is the same software sold as a hosted service, with the provider connections already written.

Who uses payment orchestration? Merchants who hold more than one acquirer, subscription businesses that live on renewals, and platforms that move money for other businesses. Marketplaces inherit the geography and the risk profile of every seller at once, so they usually reach two providers earlier than anyone expects.

Do I need a payment orchestration platform? Not if you have one provider, one market and no complaints. The forcing functions are boring and specific: a second acquirer, a market where your current one is weak, or a board question about fees per transaction. If none of those is true this month, spend the effort on your checkout instead.

A fourth group rarely shows up in vendor decks: software companies adding embedded payments to their own product. A vertical SaaS that starts paying out to its users needs routing, tokens and reconciliation on day one, and it has no payments team. For them the checklist below is not a buying guide, it is a build spec.

Before the demo: what has to be ready on your side

Every failed evaluation I have watched failed for the same reason. The buyer could not describe their own traffic, so every answer sounded good.

Bring four things to the first call:

  • Your provider list, with the contract rate per card type — not the headline rate.
  • Last month’s declines, grouped by reason code, top three by count.
  • Your volume split by country and card brand. Domestic debit and foreign credit behave differently everywhere.
  • The operations you actually use. Refunds, partial refunds, holds, payouts, chargebacks, recurring.

That last one decides more than routing does. The adapter contract I maintain has nine operations — create, complete 3DS, capture, void, refund, status, handle webhook, payout to card, payout to account. Every connector must answer all nine, even when the provider behind it cannot do the job. Of the five acquirers wired into it, four can pay out to a card and only one can pay out to an IBAN. One of them supports neither payout type and returns a plain “not supported” for both.

That asymmetry is the norm, not bad luck. Ask any vendor for the same matrix, operation by operation, provider by provider. A single “supported” column is a warning sign.

The nine things the software must do

1. Route on rules a human can read

Routing rules decide who gets the payment. You should be able to read the whole set out loud in a minute.

The engine behind these examples loads rules scoped to one legal entity, and rules can be time-bound: a weekend-only rule simply is not in the set on a Tuesday. A BLOCK rule stops the payment before any provider is chosen. A ROUTE rule names a pool of providers, and that pool becomes the candidate list. No ROUTE rule matched? Then every provider account on the entity is a candidate.

The part worth copying is where conflicts are caught. Only one ROUTE rule may match a payment, and that is enforced when a rule is saved, not when a payment runs. Overlapping rules are a config bug, and config bugs belong at config time.

Ask on the demo: create two rules that overlap, save them, and see what happens. If both save cleanly, ask which one wins at 3am. If the answer is “the first one”, you now own an ordering problem that nobody will document.

2. Retry the declines worth retrying

Cascading to a second provider after a decline sounds like free money. It is not free.

Some declines are final. A stolen card stays stolen at the next provider. You will have paid for a second request, added seconds to the checkout, and created a second entry in your reports. Some issuers also read repeated attempts on one card as a fraud signal.

So the retry list matters more than the retry engine. The cascade here runs only when the first result maps to declined, excludes the account that just failed, and stops at the first provider that answers with anything other than a decline. That is deliberately narrow.

The hard part is the mapping underneath. Look at four real codes from those connectors:

ProviderCodeMeansNaive reading
UPC131Additional authentication required (SCA)decline
UPC290Issuer bank unavailabledecline
PayLink406Operation in progress, ask again laterdecline
PayLink4003DS verification requireddecline

None of those four is a decline. Two mean “the customer has more to do”, one means “the bank is down, try elsewhere”, one means “ask me again”. Treat them as declines and you fail live payments; treat them all as retryable and you hammer issuers with attempts that cannot succeed.

What to ask: show me the retry list as data, not as a sentence. Which codes are on it, who can edit it, and does the edit need a deploy?

3. Give you tokens you can leave with

A card token is a reference that stands in for a card number, so the number itself lives in one place.

Two questions decide whether tokens are an asset or a leash. Where does the card number sit, and what happens to the tokens if you leave.

In P26M the card number lives in exactly one service. Everything else — the payment record, the reports, the routing — carries a UUID. The number is encrypted with an AES-256-GCM96 key inside HashiCorp Vault, and the key rotates automatically every 2160 hours — the 90-day cryptoperiod we set for it. The key never leaves Vault, so a database dump is a pile of ciphertext.

Storage is the easy half. The half vendors skip is lifecycle. A vault that can only create and read tokens is half a vault. Ours also exposes info, suspend, resume and delete for a stored card, and every call is checked against a registry that says which merchant may perform which operation on which token.

Three questions here. Can you suspend a single token without deleting it? Can you export your tokens if the contract ends? And are network tokens — the ones issued by Visa or Mastercard — held in your name or the vendor’s? The answer to that one is the whole lock-in question in a sentence.

4. Sign the whole request, not just the body

This one is invisible on a slide and expensive in production.

An earlier signing scheme of ours covered the request body and a timestamp. It looked fine. It was not: a signature made for POST /payments/{A}/refund stayed valid for POST /payments/{B}/void with the same body. The method, the path, the query string and the resource UUID were all outside the signature.

The replacement signs a canonical string of eight lines: version, HTTP method, path, canonical query, SHA-256 of the body, timestamp, nonce, and the idempotency key. The timestamp window is 300 seconds either way. The nonce is remembered for twice that, scoped per API key, and a repeat comes back as HTTP 409 with SIGNATURE_REPLAYED.

The idempotency key inside that signed string is the detail to check. If the key sits outside the signature, it becomes a free parameter on a signed request.

Idempotency itself is simple and easy to get subtly wrong. Ours is opt-in: send an Idempotency-Key header and the response is cached for 24 hours; send nothing and the request runs normally. The cache key includes the API key UUID. I know exactly what happens when that scoping breaks, because a header rename nearly broke it: every merchant would have collapsed onto one bucket, and one merchant’s cached response could have been returned to another.

Try this in the room: send the same request twice with one idempotency key and show me both responses. Then send it with a signature borrowed from a different endpoint.

5. Deliver webhooks like a queue, not a hope

Webhooks are how your systems learn that a payment changed. Most demos show one arriving. Ask what happens when yours is down.

Ours used to be a single HTTP POST with a 10-second timeout, sent inside the request the payer was waiting on. Two consequences, both measured. A slow endpoint added up to 10 seconds to the checkout response, and subscriptions were processed one after another, so three subscriptions meant up to 30 seconds. There were no retries at all: one failure wrote a log line and the notification was gone.

What replaced it is the shape you should expect from any serious product:

PropertyValue
Attempts1 + 4 retries
Backoff10 s → 1 min → 5 min → 15 min
HTTP timeout per attempt10 s
After the last failuredead-letter record, status exhausted
Journal per attemptattempt number, HTTP status, duration in ms, target URL

Two design details are worth stealing. The payload is frozen when the event happens and never rebuilt on retry — otherwise a webhook delivered after a 15-minute backoff would describe the payment as it is now, and your events would arrive out of order. The signature, on the other hand, is recomputed on every attempt with a fresh timestamp, because a signature from 15 minutes ago is a replay and your own code should reject it.

Break it deliberately: point the webhook at an endpoint that returns 500, then show me the delivery log. If there is no delivery log, there is no way to answer “did it go out” during an incident, and that question always gets asked.

6. Keep one status vocabulary — and the provider’s own words

Every provider has its own dialect, and the dialects are bigger than you think.

One provider in that set documents 66 result codes. The connector collapses them into four states: 100, 101 and 102 are success, 400 and 401 are pending, 406 is processing, everything starting with 2, 3 or 4 is a decline, and the 500s are errors. Another one answers with 22 different status strings, ten of which contain the word “wait”: waiting for 3DS, waiting for cash at a terminal, waiting for a QR scan. Collapse those ten into a single “pending” and your support team can no longer tell a customer what to do next.

Here is a trap from a third connector, and it is the kind you only meet in production. The word hold appears in two of its responses. In the order status it means funds are held. In the capture response it means the capture was refused. Same word, opposite meaning, one letter of difference in the code that reads it. That is why status mapping has to be written per operation, not per word.

And an honest one about the code behind this article. Those PayLink codes 101 and 102 mean “succeeded, but for part of the amount”. Today that mapper puts them in the same bucket as a plain success, so the payment record keeps the amount that was requested. I know about it. You should look for the same seam in any product you evaluate: ask where a partial capture shows up in the record, and watch whether the answer comes from the demo or from the roadmap.

Ask to see a payment record that carries both your normalised status and the raw provider code. If the raw code is not stored, every future dispute is a guess.

7. Reconcile money, not just payments

Orchestration unifies the payment view. It does not automatically unify the money view, and that gap is where finance teams lose their evenings.

Reconciliation for account-to-account payments here works on bank statement events. The behaviour is worth describing because each rule exists for a reason someone learned:

  • Matching is by order reference inside the payment purpose text, plus amount, plus currency. Live payments are preferred over completed ones.
  • If the reference is missing, the matcher falls back to amount and currency inside a 30-minute window around the booking time.
  • If that fallback finds more than one live candidate, it stops and leaves the event unmatched. Two customers paying 500 UAH a minute apart is not a rare case, and guessing there means crediting the wrong invoice.
  • A repeat delivery of the same bank transaction is caught by a uniqueness constraint on source and external transaction id, and marked duplicate before anything touches the payment.
  • A credit that lands after the payment expired reopens it, but only inside a 30-minute grace window. Outside it, the event stays in the reconciliation queue for a human.
  • Everything else lands in one of five states, including manual for the ones an operator matched by hand.

None of that is clever. It is bookkeeping written down once instead of argued about monthly. The reason it belongs in the software rather than in a spreadsheet is volume: a rule that a person applies correctly on thirty events per day stops being applied correctly at three hundred.

A second half rarely makes it into a demo, and it is the one your finance team lives in. Five providers means five settlement files, five schedules, five names for a refund, and five ways of deducting fees before the money lands. Ask what the layer does with those files, not just with the payments. If the answer is “we expose an API and you build the import”, that is a fair answer — but now you know the project is yours.

Demand a screen: an unmatched credit and the place where a human resolves it. Every real reconciliation has a manual path. A product without one has simply not met a bank statement yet.

8. Show its work

When a payment goes wrong, you have one question: why did it go there.

Answering it needs one record per provider call. That record holds the request and response, the HTTP code, the execution time in milliseconds, and — the part most systems miss — the routing rule id that selected this account, plus the full set of rules that applied. So “why did this payment go to that provider” is a lookup, not an investigation.

On the API side every request gets a UUID that comes back in a response header, and the whole exchange goes to a separate structured audit channel. That channel exists because PCI DSS Requirement 10.2.1 wants an audit trail of access to system components, and it stays useful for everyday debugging. Sensitive values are stripped before writing: card numbers, obviously, but also capability tokens that live inside a URL, because a log that leaks a token turns your log archive into a set of spare keys.

Time this one. Give me a payment id and show me, in one screen, every call that payment made and the rule that chose the provider. Count the clicks. On incident night you will have three minutes.

9. Keep sandbox and production apart

This sounds like a checkbox and is not.

Candidates from the wrong environment are removed for every operation type, not just for card payments. If nothing survives the filter, the payment fails with “no provider” rather than quietly using a test account. Silent substitution is worse than a failure: a failure is visible today, a substitution is found at month end.

One more test: try to route a live payment to a test provider account and show me the error. If it works, the barrier is a label, not a rule.

Parameters and values: what to ask for in numbers

Vendors answer adjectives with adjectives. Ask for numbers, and compare them to these — not because ours are right for you, but because a vendor who cannot state theirs has not thought about it.

ParameterReference valueWhy you care
Health scoring window1 hour, recomputed every 5 minShorter reacts to noise, longer misses a provider failing now
Health score formula70% success rate, 30% response timeSub-1s scores full marks, 10s scores zero
Health threshold40 of 100Below it a provider drops out of routing
Score with no recent traffic50, neutralA quiet provider is not a broken one
All providers unhealthyFilter is dropped, payment still goes outPurity over revenue is the wrong trade
Timeout per provider call30 sOne provider needs two calls per payment, so budget twice
Webhook retries5 attempts over ~21 minSee the backoff table above
Idempotency cache24 h, scoped per API keyLonger is a memory bill, shorter loses safety
Signature freshness window±300 sClock skew tolerance versus replay window
API rate limit60 requests/min per merchantAsk for the number and the burst behaviour
Checkout session lifetime30 minToo short kills real customers mid-payment
Credential fields per provider3 to 10Onboarding effort is not equal across providers

The bottom row surprises people. Connecting one of those five acquirers takes three fields. Another takes ten, and only three of them are required, which means seven ways to configure it almost right. When a vendor says “we support 200 providers”, the useful follow-up is how many fields their newest connector needs and who fills them in.

Common mistakes, and how to catch them early

Buying a router when you need a vault. If your real problem is that card data is spread across three systems, routing rules will not help. Fix the data first; the routing is the easy part afterwards.

Trusting a capability table. “Supported” in a marketing table and “supported” in the code path that runs at 3am are different words. One capability table I know well lists a wallet method on all five acquirers, while only two of them take the wallet cryptogram directly on the hosted checkout — the other three support the wallet on their own payment page. Ask which source the routing code reads.

Flat-rate cost routing. Real cost depends on brand, subtype, amount and method. A provider that is cheaper on domestic debit is often dearer on foreign credit. Sorting on a single contract percentage will pick the wrong provider all day and show you a tidy report while doing it.

Forgetting that one integration is one dependency. You removed five integrations and added one thing every payment passes through. Usually the right trade. Still a trade — ask about the deploy process, the uptime record, and whether you can reach a provider directly if the layer is down.

Letting nobody own it. Rules encode decisions; somebody still has to make them. A platform does not replace the person who makes the call. Teams that buy a platform and assign no owner get a more expensive version of what they had.

Assuming compliance transfers. A vendor’s certificate covers the vendor. Your own scope depends on where card data flows in your setup. PCI DSS Requirement 12.8 expects you to keep a list of your third-party service providers and evidence of their status — so ask for their attestation document and their responsibility matrix in writing, at evaluation time, not at audit time.

Your demo script, in six steps

Two hours with a real system tells you more than a month of decks. Run this in order, and take notes in the room.

  1. Connect a sandbox provider yourself. Not a shared demo account — a fresh one, with you typing the credentials. Time it. This is the closest thing to a preview of your integration.
  2. Push one card payment through. Then open the record and find: the raw provider code, the normalised status, the routing rule that chose the provider, and the response time.
  3. Break something on purpose. Point the webhook at a URL that returns 500. Watch the retries. Ask to see the delivery journal and the dead-letter entry.
  4. Replay a request. Send the same call twice with one idempotency key. Then send it once more with a signature made for a different endpoint. The second one must fail.
  5. Make routing choose wrongly, then fix it without a deploy. Add a rule that sends everything to the more expensive provider, watch it take effect, then remove it. Measure how long the change takes to apply.
  6. Ask the reconciliation question. Show me an unmatched incoming credit and the screen where a person resolves it.

Score the six honestly the same day, before the next call blurs them together. Anything you could not do yourself, in the room, is something you will be waiting on later.

How to tell it is working after go-live

Buying is not the finish line. Four checks in the first quarter tell you whether the layer earns its place.

Your decline mix changed shape. Not the headline rate — the mix. If the same reason codes appear in the same proportions as before, routing is not doing anything and something upstream is the real constraint.

A provider incident was boring. The first time one acquirer degrades, nothing should happen to your revenue except a line in a dashboard. If people had to meet about it, the automation is not there yet.

Finance stopped asking engineering for numbers. Approval rates by country, cost per transaction, refunds by provider — these should be reports, not tickets.

Somebody changed a routing rule without a deploy. If the answer after three months is “nobody touched them”, either the defaults are perfect or nobody owns the layer. It is rarely the first one.

There is one more check, and it is the least comfortable. Try to leave. Not really — on paper. Write down what you would take with you: tokens, mandates, provider contracts, historical records. If that list is short, you did not buy software, you rented a dependency. What the box looks like from the inside — the parts that make those answers possible — is opened up in what is a payment orchestration layer, and the gap between a gateway and a layer is unpacked in payment orchestration vs payment gateway.

What this software will not do for you

Worth saying plainly, because the category is sold as though it fixes everything.

It will not repair a bad approval rate on its own. A router does not cure the reason, it only moves the attempt. Routing moves payments to the provider most likely to approve them. If every provider you hold declines the same traffic for the same reason, routing spreads the declines around. The fix lives in the reason code.

Your PCI scope does not move because a layer exists. How card data flows through your checkout decides that. A layer that passes raw card numbers through leaves you exactly as in-scope as you were.

A weak acquirer stays weak. If your provider has poor coverage in a market, a router in front of it does not give it coverage. It only makes it easier to send that traffic somewhere else.

And nothing on this list chooses for you. The nine items above are a spec, not a ranking. A product can score badly on reconciliation and still be right for a company that has one settlement file a week.

Before you shortlist anyone, put a number on what the change is worth: current provider fees, the volume you would reroute, the declines a retry might recover. The ROI calculator on this site walks that arithmetic in about five minutes, and the output is a figure you can take into the first vendor call instead of an adjective.