• When a payment fails, it almost never ends there. Merchants retry. PSPs retry. Authorisers retry. And sometimes all three do it simultaneously — without knowing the others are doing the same. If an authoriser retries and the transaction succeeds, the analyst at the PSP may never know. If the PSP reroutes to a backup processor, the merchant’s analytics table will never show it.

    The result is the same in every analytics table: one billing attempt shows up as separate rows — each with its own transaction ID, timestamp, and status. Without the right deduplication logic, you are not measuring what you think you are.

    That logic looks different depending on where you sit in the payment chain. This post walks through how to build it — for merchants, PSPs, card networks, and issuers — and why each one needs a different approach.

    1. Why this matters: the true success rate problem

    For merchants: the goal is to understand the effectiveness of their retry strategies. Imagine a merchant retries a failed subscription payment three times before it succeeds. Naively, that is a 25% approval rate (1 success out of 4 attempts). But from a business perspective, the payment succeeded, the customer was charged and the invoice was closed. The true success rate for that invoice is 100%.

    For PSPs: the goal is to understand the true success rate associated with the processor connections they use stripped of retry noise that was never really a new transaction.

    Getting to either number requires knowing that all the retry rows belong to the same billing cycle. That is what deduplication does.

    If you count a retry as a new transaction, you overcount volume and overstate failure rates — making your payment performance look worse than it actually is.

    2. The key parameters

    Before looking at each party’s query, here are the building blocks and what each one means:

    3. The merchant perspective

    Merchants have the best context. They know the invoice cycle, the customer, the grace period, and whether a payment method was updated mid-cycle. This makes their dedupe query the most precise.

    Dedupe query

    WITH attempts AS (
    SELECT
    customer_id,
    invoice_id,
    card_id,
    status,
    attempt_ts,
    ROW_NUMBER() OVER (
    PARTITION BY customer_id, invoice_id
    ORDER BY attempt_ts ASC
    ) AS attempt_vintage
    FROM transactions
    )
    SELECT
    customer_id,
    invoice_id,
    card_id,
    COUNT(*) AS total_attempts,
    COUNTIF(status = 'success') AS successful_attempts,
    MAX(CASE
    WHEN status = 'success' THEN 1
    ELSE 0
    END) AS invoice_resolved,
    MIN(attempt_ts) AS first_attempt_ts,
    MAX(attempt_ts) AS last_attempt_ts,
    -- which attempt number finally succeeded
    MAX(CASE
    WHEN status = 'success'
    THEN attempt_vintage
    END) AS winning_attempt_vintage
    FROM attempts
    GROUP BY
    customer_id,
    invoice_id,
    card_id

    Note: when you drop card_id from the group key, you see whether the invoice was eventually paid — regardless of which funding instrument succeeded. This is usually the right question for subscription businesses.

    4. The PSP perspective

    A payment service provider processes transactions on behalf of many merchants. They don’t see invoice IDs or customer IDs. They can’t tell if a retry was triggered by a dunning system or a customer clicking “try again.” But they do see something powerful: the actual card numbers — which they store as hashed values (card hashes or tokenised PANs).

    The MID problem. Large merchants often operate under multiple merchant IDs (MIDs) — one per geography, product line, or entity. If you group by raw merchant_id, you will undercount success for those merchants. The fix is to create a unified merchant ID that normalises all of a merchant’s MIDs into a single entity before any grouping happens.

    The PAN vs network token problem. Some merchants retry declined transactions using a network token where the original attempt used a raw PAN, or vice versa. This breaks the uniqueness of card_hash as an identifier — the same card appears as two different values depending on how the merchant submitted it. Using PAR (Payment Account Reference) solves this: PAR is a stable value that links a PAN and all its associated network tokens back to the same underlying account, regardless of how the transaction was submitted.

    The first attempt problem. PSPs and authorisers have no access to invoice IDs, and merchants often retry transactions well beyond 30 days depending on their dunning strategy. This makes it genuinely hard to identify where a retry chain begins. The practical approach: for a given card_hash or PAR and merchant combination, find the earliest attempt and treat that as the origin. If that attempt is successful, the transaction reached a terminal state in a single try. If it is not, every subsequent attempt within a defined window counts as a retry — and you can track how far into the chain a success eventually arrives, or whether it arrives at all.

    -- Step 1: identify first attempt per chain using QUALIFY
    WITH first_attempts AS (
    SELECT
    unified_merchant_id,
    card_par,
    amount,
    currency,
    psp_txn_id,
    attempt_ts AS first_attempt_ts,
    status AS first_attempt_status
    FROM psp_transactions
    QUALIFY ROW_NUMBER() OVER (
    PARTITION BY unified_merchant_id, card_par, amount, currency
    ORDER BY attempt_ts ASC
    ) = 1
    ),
    -- Step 2: subset only chains where first attempt was declined
    first_declined AS (
    SELECT *
    FROM first_attempts
    WHERE first_attempt_status != 'success'
    ),
    -- Step 3: for declined chains, find all retries within 60 days
    -- then pick the last attempt status using QUALIFY
    last_retry_status AS (
    SELECT
    t.unified_merchant_id,
    t.card_par,
    t.amount,
    t.currency,
    t.attempt_ts AS last_attempt_ts,
    t.status AS last_attempt_status,
    ROW_NUMBER() OVER (
    PARTITION BY t.unified_merchant_id, t.card_par, t.amount, t.currency
    ORDER BY t.attempt_ts ASC
    ) AS attempt_vintage,
    COUNT(*) OVER (
    PARTITION BY t.unified_merchant_id, t.card_par, t.amount, t.currency
    ) AS total_retries_in_window
    FROM psp_transactions t
    INNER JOIN first_declined d
    ON t.unified_merchant_id = d.unified_merchant_id
    AND t.card_par = d.card_par
    AND t.amount = d.amount
    AND t.currency = d.currency
    -- exclude the first attempt itself, only retries
    AND t.attempt_ts > d.first_attempt_ts
    -- only within 60 day window from first attempt
    AND TIMESTAMP_DIFF(t.attempt_ts, d.first_attempt_ts, DAY) <= 60
    QUALIFY ROW_NUMBER() OVER (
    PARTITION BY t.unified_merchant_id, t.card_par, t.amount, t.currency
    ORDER BY t.attempt_ts DESC
    ) = 1
    ),
    -- Step 4: join first attempt table with last retry status
    -- to get final transaction outcome after 60 day window
    final_status AS (
    -- chains that succeeded on first attempt (terminal immediately)
    SELECT
    f.unified_merchant_id,
    f.card_par,
    f.amount,
    f.currency,
    f.first_attempt_ts,
    f.first_attempt_status,
    NULL AS last_attempt_ts,
    NULL AS last_attempt_status,
    1 AS total_attempts,
    0 AS total_retries,
    'success_first_attempt' AS chain_outcome
    FROM first_attempts f
    WHERE f.first_attempt_status = 'success'
    UNION ALL
    -- chains that were declined on first attempt
    -- final status determined by last retry within 60 days
    SELECT
    d.unified_merchant_id,
    d.card_par,
    d.amount,
    d.currency,
    d.first_attempt_ts,
    d.first_attempt_status,
    r.last_attempt_ts,
    r.last_attempt_status,
    r.total_retries_in_window + 1 AS total_attempts,
    r.total_retries_in_window AS total_retries,
    CASE
    WHEN r.last_attempt_status = 'success' THEN 'success_after_retry'
    WHEN r.last_attempt_status IS NULL THEN 'declined_no_retry'
    ELSE 'declined_exhausted'
    END AS chain_outcome
    FROM first_declined d
    LEFT JOIN last_retry_status r
    ON d.unified_merchant_id = r.unified_merchant_id
    AND d.card_par = r.card_par
    AND d.amount = r.amount
    AND d.currency = r.currency
    )
    -- Step 5: final output — one row per chain, status anchored to first attempt date
    SELECT
    unified_merchant_id,
    card_par,
    amount,
    currency,
    first_attempt_ts,
    first_attempt_status,
    last_attempt_ts,
    last_attempt_status,
    total_attempts,
    total_retries,
    chain_outcome,
    -- summary flags
    CASE
    WHEN chain_outcome IN ('success_first_attempt',
    'success_after_retry') THEN 1
    ELSE 0
    END AS ultimately_successful,
    CASE
    WHEN chain_outcome = 'success_first_attempt' THEN 0
    WHEN chain_outcome = 'success_after_retry' THEN total_retries
    ELSE NULL
    END AS retries_needed_to_succeed
    FROM final_status
    ORDER BY
    first_attempt_ts,
    unified_merchant_id

    Amount caution: some merchants offer a discount on retry success (e.g. 5% off if the second attempt succeeds). In those cases, grouping on amount will break your dedupe chain — remove amount from the key or use an amount range bucket instead.

    5. The card network perspective

    Card networks see a different slice: every transaction that flows through their rails, regardless of PSP. This means they can observe cross-PSP retry patterns — something no individual PSP can see. They can also detect cross-processor retry behavior. If a merchant tries PSP A, fails, then tries PSP B, both transactions land at the card network (as long as they are on the same network). The network can group them — and see that acquirers_tried > 1

    6. The issuer perspective

    Issuers have the most complex view and the least context. They see every transaction that hits a funding instrument — from every merchant, every PSP, on and off their network — but with no invoice ID, no customer ID, and no visibility into dunning strategies. Where a merchant sees a rational retry sequence, an issuer sees a burst of repeated attempts on the same card, a pattern that is difficult to distinguish from fraud or account takeover.

    This is why issuer behaviour matters to merchants even though merchant analysts never see issuer data directly. An aggressive dunning strategy that makes sense on the merchant’s P&L can trigger blanket declines on the issuer side — catching legitimate transactions in the same net. And if an issuer places a restriction against a specific merchant ID, retrying through a different PSP may succeed temporarily, but once the rule propagates the benefit disappears. Understanding the issuer’s vantage point is not about having their data — it is about designing retry strategies that do not look like fraud from the outside.

    End note:

    Every party in the payment chain is looking at the same transaction and drawing different conclusions from it. That is not a data quality problem — it is a structural one. The dedupe key you choose determines which version of the truth you are measuring.

    Get it wrong and your approval rate is a fiction. Get it right and you have a foundation for every optimisation decision that follows — retry strategy, PSP routing, dunning cadence, decline recovery.

    Start with your vantage point. Build your key from there.

    Part 3 will cover how to use true approval rates to benchmark your payment performance against industry peers. Follow along at paymentscafe.com

  • Did you know that consumers return about 20% of the products they purchase online? Online return rates have significantly increased over the years, and they’re especially high compared to in-store purchases. In fact, online return rates are often two to three times higher than digital (in-store) return rates.

    According to research from Capital One, in 2024 alone, consumers in the U.S. returned around $362 billion worth of merchandise from online sales.

    But how exactly are these refunds processed behind the scenes?

    Before 2021: Refunds Were Simple—but Risky

    Prior to 2021, processing refunds was fairly straightforward. Merchants could simply push refund transactions back to customers’ bank accounts without any prior authorization from the card issuer.

    However, this approach had significant drawbacks:

    • Lack of visibility for customers. Many consumers had no way of knowing whether the merchant had actually initiated the refund.
    • Fraud risk. Fraudsters could exploit the system to push credits to unrelated cards, launder money, or create other financial abuse.
    • Delayed processing. Refunds often took 2–3 business days, leading to confusion and increased calls to merchants’ customer service centers.

    Let’s examine how refunds impact payments, risk, and customer experience, comparing before and after the introduction of refund authorization mandates.

    Refunds: Comparing Before vs. After Refund Authorization

    AspectWithout Refund AuthorizationWith Refund Authorization
    PaymentsMerchants could easily process refunds without issuer approval. However, if the card account was closed, the issuer had to figure out how to handle the refund. This only worked if the customer still maintained a relationship with the bank. If the customer severed the relationship entirely, the issuer might either return the refund to the acquirer or leave the payment in limbo.Merchants must first run a refund authorization. If the authorization is successful, they proceed to send the refund to the customer’s account. If the authorization is declined, merchants can reach out to the customer for an alternative card, issue a check, or offer store credit.
    Payments RiskSeveral fraud scenarios existed:
    1. Fraudulent Credits to Random Cards: An employee colluding with fraudsters could key in a refund to a card that never made a purchase.
    2. Money Laundering: Fraudsters could use refunds to “clean” illicit funds by buying expensive goods and refunding them—sometimes even to different cards.
    3. Refund Flipping: A fraudster makes a legitimate purchase, disputes it, and demands a refund. They collect both the chargeback and keep the goods, resulting in a “double dip” fraud loss for the merchant.
    The issuer can verify whether the card was used for the original purchase, check for suspicious activity, and decline transactions to random cards or known refund abusers. This protects both genuine customers and merchants from fraud.
    CustomersWithout refund authorization, customers often had no visibility into the status of a refund after the merchant agreed to process it. If a card was closed due to loss or fraud, customers had to rely on the issuer’s best efforts to receive their money. Even if the merchant offered to issue a check, there was no guarantee, leaving customers confused or even financially stranded if they had severed their relationship with the bank.With refund authorization, as soon as the merchant runs the refund authorization, the customer can see a pending credit on their card. If the transaction is declined, merchant customer service teams can assist the customer by offering alternative options like a check or refund to another card.

    Important Note

    Refunds and reversals are not the same thing.

    • Refunds apply when the original transaction has already been settled (i.e. the funds have moved from the customer to the merchant).
    • Reversals or voids happen when the customer cancels the transaction before settlement—the funds never leave the customer’s account.

    In this article, we’re focusing specifically on refunds.

    Refund Authorization Declines

    Just like regular purchase authorizations, refund authorizations can also be declined. Industry estimates suggest that 6% to 10% of refund authorizations get declined, depending on the quality of the cards involved in the original transactions.

    Common decline reasons include:

    • Account Closed
    • Invalid Transaction
    • Transaction Refused
    • Invalid Account Number
    • Transaction Not Permitted to Cardholder

    Don’t be surprised if you see vague responses like “Insufficient Response” on a refund transaction. Sometimes issuers suppress the true reason for a decline for security or privacy reasons, or technical issues may occur on the issuer’s side.

    What Should Merchants Do If a Refund Authorization Is Declined?

    Both Visa and Mastercard recommend that merchants handle refunds manually in such cases—for example:

    • Issuing a check to the customer.
    • Providing store credit for a future purchase.

    What Happens if a Merchant Sends Refunds Without Authorization?

    If merchants skip the required refund authorization, they’re subject to fees from the card networks:

    • Visa: Charges $0.10 for every refund transaction submitted without authorization.
    • Mastercard: Charges a Processing Integrity Fee ranging from $0.04 to $0.25, depending on the region and program.

    Many merchants choose to perform refund authorizations to avoid these fees. However, some continue paying the penalties because they don’t want to invest in manual refund processes like issuing checks.

    Key KPIs for Refund Authorization

    Refund transactions often don’t get the attention they deserve. However, as discussed, they can signal underlying fraud trends. Regular monitoring helps mitigate fraud risk and keep merchant accounts (MIDs) healthy for normal payment processing.

    Important KPIs include:

    Stay tuned for my next post: How to Implement Refund Authorizations.

  • When investigating a spike in card declines, the first instinct for many payments analysts and product managers is to check the decline response codes. Terms like “Insufficient Funds”, “Do Not Honor”, and “Transaction Refused” are now part of the shared language across the payments industry. Even senior leaders often ask, “Which response code is spiking?”

    Is that a wrong approach? Not entirely—but relying on response codes too heavily can be misleading.

    To understand why, let’s trace how a decline message travels back through the system:

    When a card issuer declines a transaction, the response is passed back through multiple hops:
    Issuer → Card Network (Visa/Mastercard) → Processor → Payment Service Provider (PSP) → Merchant.

    All of this happens in milliseconds, but to optimize speed and reduce complexity, each player in the chain may normalize or simplify the decline response. The level of detail a merchant receives ultimately depends on each player’s philosophy and technical capability.

    Years ago, I spoke with a major U.S. authorizer. I asked why 70% of their declines were labeled as “51 – Insufficient Funds.” Their answer surprised me:

    “Most merchants just want to know if a transaction was approved or declined—they don’t care why. So we simplify.”

    They advised us to start consuming network response codes, which are passed directly from the card networks and tend to be more granular. But that required PSPs to modify their systems to expose those codes.

    Today, most leading PSPs in the U.S. (and likely worldwide) support network response codes. If you’re a merchant not receiving them, ask your PSP.

    Let’s now look at some scenarios where response codes can mislead your analysis:

    1. Processor Switch: If your PSP switches processors (e.g., from one with generic codes to one with granular codes), it might look like certain decline types are suddenly spiking—when in fact, nothing changed except visibility.
    2. Carding or Bot Attacks: Issuers often mask real decline reasons during fraud attempts to avoid helping attackers fine-tune their bots.
    3. Aggressive Retry Strategies: If your dunning partner triggers multiple retries per day, the same decline reason may flood your logs—without providing any new insight.
    4. New PSP or Processor Integration: Any onboarding of a new provider may change the way responses are logged and categorized.
    5. Market Expansion: Launching in a new country may introduce new issuer behaviors that you haven’t previously encountered.

    These are just a few examples. Feel free to comment if you’ve seen other situations that impacted decline response patterns.

    So, if decline response codes aren’t always reliable, what should you look at to begin a proper decline analysis?

    I’ll share my experience in the next blog post. Stay tuned!

  • When I joined PayPal in 2014, I was new to the payments industry—but not new to analytics. I had been working in data analytics for over a decade, so when I was asked to analyze approval rate trends and transaction declines in Brazil, I expected it to be a fairly straightforward task.

    After all, most analytics work boils down to three things:

    • Business understanding
    • Data understanding
    • Basic programming skills

    How hard could it be? All I needed to do was answer two questions:

    1. Who declines a card-funded transaction?
    2. Why do they decline it?

    But answering even the first question—who—turned out to be more complicated than I imagined.

    I spoke with veteran analytics colleagues, product managers, and business leads. They walked me through the transaction flow: the transaction goes from the merchant to the authorizer, to the card network, and finally to the issuer. Initially, I assumed that each player in this chain might influence the approval or decline decision. But after much digging, I learned that in reality, it is the card issuer who makes the final approval or decline decision—not the other players.

    Today, this is fairly well understood—thanks to the wealth of LinkedIn articles and PSP educational content. But in 2014, such information was much harder to find.

    In the specific case of Brazil, I eventually uncovered that the fluctuations in approval rates were not being driven by players in the payments ecosystem at all. Instead, they were caused by merchant-side factors—such as merchant churn, acquisition strategies, and changes in the merchant landscape.

    Later that year, I attended Glenbrook Partners’ Payments 101 training, a three-day deep dive into the payments ecosystem. That experience dramatically improved my understanding of how the ecosystem really works and made me a far more effective payments analyst.

    The biggest lesson? To be a great payments analyst, it takes more than data and programming skills—you need a deep understanding of the payments industry itself: the ecosystem, the players, and the dynamics that influence data trends.

    What has your payments analytics journey been like? I would love to hear your experience!