<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Payneteasy</title>
    <description>The latest articles on DEV Community by Payneteasy (@payneteasy).</description>
    <link>https://dev.to/payneteasy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3902834%2Fd453c0d4-fa60-426a-8fad-988deb98e5d8.jpeg</url>
      <title>DEV Community: Payneteasy</title>
      <link>https://dev.to/payneteasy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/payneteasy"/>
    <language>en</language>
    <item>
      <title>The card number was in our error tracker, not our database</title>
      <dc:creator>Payneteasy</dc:creator>
      <pubDate>Mon, 26 Oct 2026 00:00:17 +0000</pubDate>
      <link>https://dev.to/payneteasy/the-card-number-was-in-our-error-tracker-not-our-database-3gfe</link>
      <guid>https://dev.to/payneteasy/the-card-number-was-in-our-error-tracker-not-our-database-3gfe</guid>
      <description>&lt;p&gt;We passed a PCI scoping review on the database side with no issues: no PANs stored, tokens only. Then someone searched our error tracker for a 6-digit BIN while debugging an unrelated decline and got hits.&lt;/p&gt;

&lt;p&gt;The cause was boring. A JSON parse error in the checkout handler threw before validation, and the tracker's default integration attached the raw request body to the event. Anything a customer typed into the card field, when the payload was malformed, was stored in plaintext for 90 days. We found 41 events with full 16-digit numbers. All of them came from a mobile client version that sent a trailing comma.&lt;/p&gt;

&lt;p&gt;What fixed it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scrub at the SDK before send, not in the tracker's UI. Server-side scrubbing still means the data crossed the wire to a third party.&lt;/li&gt;
&lt;li&gt;Drop request bodies on payment routes entirely. Keep the route, status, and a request ID.&lt;/li&gt;
&lt;li&gt;Add a Luhn-pattern check to the log pipeline as a tripwire. It catches the next leak, not the first one.&lt;/li&gt;
&lt;li&gt;Same for reverse proxy access logs if you ever put card data in a query string. Don't.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The part that bothered me most: our scope diagram showed three boxes. The tracker wasn't one of them, because nobody thinks of it as a data store.&lt;/p&gt;

&lt;p&gt;Where else have you found cardholder data you didn't expect: APM traces, support tool screenshots, analytics events?&lt;/p&gt;

&lt;p&gt;Payneteasy handles this kind of payment flow for merchants and PSPs — &lt;a href="https://payneteasy.com/solutions/payment-integration?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=the-card-number-was-in-our-error-tracker-not-our-database&amp;amp;utm_content=cta&amp;amp;service_type=payment_services" rel="noopener noreferrer"&gt;see how it works&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>payments</category>
      <category>security</category>
      <category>backend</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Checkout.com Expands Into In-Person Payments: A Strategic Shift Toward Omnichannel</title>
      <dc:creator>Payneteasy</dc:creator>
      <pubDate>Sun, 25 Oct 2026 00:00:16 +0000</pubDate>
      <link>https://dev.to/payneteasy/checkoutcom-expands-into-in-person-payments-a-strategic-shift-toward-omnichannel-45h7</link>
      <guid>https://dev.to/payneteasy/checkoutcom-expands-into-in-person-payments-a-strategic-shift-toward-omnichannel-45h7</guid>
      <description>&lt;p&gt;Checkout.com, a leading global payment provider, has announced its entry into the in-person payments segment. The company says it is responding to significant demand from enterprise merchants who want the same performance and reliability in physical stores that they experience with online acquiring.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters.&lt;/strong&gt; The payments market is moving toward convergence of online and offline channels. Merchants increasingly demand unified processing, unified reporting, and consistent fraud protection across all sales channels. Traditional PSPs that started with online acquiring now face the need to build or buy offline infrastructure. Checkout.com's expansion signals that even major online acquirers can no longer ignore the physical channel, especially in the enterprise segment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is affected and how
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PSPs and fintechs relying on white-label solutions.&lt;/strong&gt; This move intensifies competition from global brands that can now offer merchants a full omnichannel cycle. Previously, differentiation through offline acquiring was possible; now that advantage is eroding. To stay competitive, these companies must focus on flexibility, local expertise, and customization for niche markets where global giants are less agile.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enterprise merchants and marketplaces.&lt;/strong&gt; For merchants using Checkout.com or similar platforms, this is a positive signal: growing competition in acquiring may lead to better terms and technologies. However, Checkout.com targets the large enterprise segment, while niche and customized solutions for PSPs and banks remain a distinct space where specialized providers can thrive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Banks and financial institutions.&lt;/strong&gt; Banks partnering with PSPs may see new opportunities to offer omnichannel capabilities to their corporate clients without building their own infrastructure. The entry of a global player like Checkout.com could also push banks to accelerate their own digital transformation in payments.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;Checkout.com's expansion into in-person payments is a strategic move that transforms it from a purely online player into a universal omnichannel acquirer. For the industry, it underscores the necessity of unified payment solutions. For specialized providers, the key opportunity lies in offering more flexible integration, local market adaptation, and tailored services that global giants cannot easily replicate.&lt;/p&gt;

&lt;p&gt;How will your payments strategy adapt to the growing demand for omnichannel solutions?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://www.finextra.com/pressarticle/111375/checkoutcom-expands-into-in-person-payments" rel="noopener noreferrer"&gt;Finextra, 20 Oct 2026&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>payments</category>
      <category>fintech</category>
      <category>api</category>
      <category>banking</category>
    </item>
    <item>
      <title>Payment engineers: which ops task would you hand to AI first?</title>
      <dc:creator>Payneteasy</dc:creator>
      <pubDate>Sat, 24 Oct 2026 09:32:27 +0000</pubDate>
      <link>https://dev.to/payneteasy/payment-engineers-which-ops-task-would-you-hand-to-ai-first-33jj</link>
      <guid>https://dev.to/payneteasy/payment-engineers-which-ops-task-would-you-hand-to-ai-first-33jj</guid>
      <description>&lt;p&gt;Logs, reports, routing rules, or bulk config changes across 50 gateways: which one eats your sprint?&lt;/p&gt;

&lt;p&gt;We're polling payment teams on LinkedIn: &lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:7519316013973188611" rel="noopener noreferrer"&gt;https://www.linkedin.com/feed/update/urn:li:activity:7519316013973188611&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Drop your answer in the comments too. Tell us what tooling you use today and where it breaks.&lt;/p&gt;

&lt;p&gt;On Monday, 26 Oct, we'll post how AI handles each case. Live demo at SiGMA Rome, 3–5 Nov, stand 3080:&lt;br&gt;
&lt;a href="https://cal.com/payneteasy/payneteasy-sigma-2026-meetings?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=sigma_2026&amp;amp;utm_content=poll" rel="noopener noreferrer"&gt;https://cal.com/payneteasy/payneteasy-sigma-2026-meetings?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=sigma_2026&amp;amp;utm_content=poll&lt;/a&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>fintech</category>
      <category>ai</category>
      <category>stripe</category>
    </item>
    <item>
      <title>Our webhook dedupe check was a race, not a guard</title>
      <dc:creator>Payneteasy</dc:creator>
      <pubDate>Sat, 24 Oct 2026 00:00:15 +0000</pubDate>
      <link>https://dev.to/payneteasy/our-webhook-dedupe-check-was-a-race-not-a-guard-411a</link>
      <guid>https://dev.to/payneteasy/our-webhook-dedupe-check-was-a-race-not-a-guard-411a</guid>
      <description>&lt;p&gt;We deduplicated webhooks the obvious way. Handler receives an event, runs SELECT on processed_events by event_id, and if nothing is found, does the work and inserts the row at the end.&lt;/p&gt;

&lt;p&gt;It held for months. Then a customer got two receipt emails and a loyalty-points credit twice for the same payment.&lt;/p&gt;

&lt;p&gt;The cause: the gateway redelivered the event 40 ms after the first attempt, because our first response was slow (a cold DB connection pushed it to about 3 seconds, and their timeout was 2). Both deliveries landed on different pods. Both ran the SELECT before either had inserted. Both saw an empty table, and both did the work.&lt;/p&gt;

&lt;p&gt;In logs it looked like duplicate delivery, but the gateway was behaving correctly. Our check-then-act was the bug.&lt;/p&gt;

&lt;p&gt;The fix was to flip the order. Insert the event_id first, into a table with a unique constraint, inside the same transaction as the side effects. If the insert hits a conflict, return 200 and stop. If the transaction fails, the insert rolls back and the next redelivery gets a clean retry.&lt;/p&gt;

&lt;p&gt;Two details that mattered. We key on the event id, not the payment id, since one payment emits several events. And we return 200 on conflict, because a 4xx there makes the gateway keep retrying a event you've already handled.&lt;/p&gt;

&lt;p&gt;How do you handle side effects that can't live in the same transaction, like email sends? Outbox table, or something else?&lt;/p&gt;

&lt;p&gt;Payneteasy handles this kind of payment flow for merchants and PSPs — &lt;a href="https://payneteasy.com/solutions/payment-integration?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=our-webhook-dedupe-check-was-a-race-not-a-guard&amp;amp;utm_content=cta&amp;amp;service_type=payment_services" rel="noopener noreferrer"&gt;see how it works&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>payments</category>
      <category>api</category>
      <category>backend</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Our dunning job retried 'stolen card' declines every night</title>
      <dc:creator>Payneteasy</dc:creator>
      <pubDate>Fri, 23 Oct 2026 00:00:16 +0000</pubDate>
      <link>https://dev.to/payneteasy/our-dunning-job-retried-stolen-card-declines-every-night-h0c</link>
      <guid>https://dev.to/payneteasy/our-dunning-job-retried-stolen-card-declines-every-night-h0c</guid>
      <description>&lt;p&gt;Found this while looking at a scheme fee line that kept growing on a subscription product. The dunning job had one rule: if a renewal fails, retry at 24h, 72h and 7 days. It never looked at why the renewal failed.&lt;/p&gt;

&lt;p&gt;The decline codes were the problem. Code 51 (insufficient funds) is a decent retry candidate, because the balance can change by payday. Codes 41 (lost card) and 43 (stolen card), and 14 (invalid card number), are different. The issuer is telling you not to come back, and no amount of waiting changes that. We were sending those through the same schedule anyway.&lt;/p&gt;

&lt;p&gt;Visa and Mastercard both penalize this. As I understand Visa's rules, 'never approve' decline categories get no reattempts at all, and the other categories are capped at roughly 15 attempts in 30 days. Past that you pay per attempt, and the decline ratio on the merchant account climbs.&lt;/p&gt;

&lt;p&gt;The fix was small. We map the response code to one of three buckets: retry later, retry only after the customer updates the card, and never retry. The 'never' bucket cancels the schedule and sends the customer to a payment-update page.&lt;/p&gt;

&lt;p&gt;The lesson for me was that the gateway's raw response code belongs in your retry state, not just in the log line. If all you persist is 'failed', you can't build this.&lt;/p&gt;

&lt;p&gt;How do you handle it? Do you keep your own decline-code table, or trust the normalized category your gateway returns?&lt;/p&gt;

&lt;p&gt;Payneteasy handles this kind of payment flow for merchants and PSPs — &lt;a href="https://payneteasy.com/solutions/payment-integration?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=our-dunning-job-retried-stolen-card-declines-every-night&amp;amp;utm_content=cta&amp;amp;service_type=payment_services" rel="noopener noreferrer"&gt;see how it works&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>payments</category>
      <category>fintech</category>
      <category>backend</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Closing the Corporate Service Gap in Cross-Border Payments</title>
      <dc:creator>Payneteasy</dc:creator>
      <pubDate>Thu, 22 Oct 2026 00:00:16 +0000</pubDate>
      <link>https://dev.to/payneteasy/closing-the-corporate-service-gap-in-cross-border-payments-4ke</link>
      <guid>https://dev.to/payneteasy/closing-the-corporate-service-gap-in-cross-border-payments-4ke</guid>
      <description>&lt;p&gt;Corporate clients increasingly expect cross-border payments to feel as fast, transparent, and predictable as domestic ones. Yet traditional bank services often lag behind, creating what industry analysts call a 'service gap.' A recent Finextra analysis highlights how banks can adapt their products for international settlements to better meet corporate expectations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters.&lt;/strong&gt; For payment service providers (PSPs), merchants, banks, and fintechs, this shift directly impacts daily operations. When banks improve cross-border services, the entire payment chain benefits: faster settlements, fewer rejections, and a better experience for end customers. For partner banks, it's a chance to offer more competitive corporate products—especially as fintechs and neobanks aggressively capture market share.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is affected and how
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PSPs and merchants.&lt;/strong&gt; Improved bank services mean quicker fund flows and reduced friction in international transactions. This translates into lower operational overhead and higher satisfaction for merchants' own clients, who demand seamless global payments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Banks and corporate clients.&lt;/strong&gt; Banks that modernize their cross-border offerings can retain and attract corporate customers. The key levers include API-driven integration, transparent fee and timing structures, and flexible liquidity models—features that directly address the service gap.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fintechs and neobanks.&lt;/strong&gt; As banks close the gap, fintechs face both competition and opportunity. They can leverage white-label orchestration solutions to quickly align with evolving bank capabilities, without building infrastructure from scratch.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;The trend is clear: corporate clients want seamlessness in international payments, and banks that fail to invest in modernization risk losing a profitable segment. For payment providers, this is a chance to position themselves as the technological bridge between traditional banks and modern business requirements. The faster banks adapt, the more partnership and integration opportunities emerge across the ecosystem.&lt;/p&gt;

&lt;p&gt;How is your organization preparing for the shift toward more transparent and API-driven cross-border payments?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://www.finextra.com/event-info/645/cross-border-payments-how-banks-can-close-the-corporate-service-gap" rel="noopener noreferrer"&gt;Finextra, 12 Nov 2026&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>payments</category>
      <category>banking</category>
      <category>api</category>
      <category>fintech</category>
    </item>
    <item>
      <title>Your deploy can silently turn off your webhook endpoint</title>
      <dc:creator>Payneteasy</dc:creator>
      <pubDate>Wed, 21 Oct 2026 00:00:15 +0000</pubDate>
      <link>https://dev.to/payneteasy/your-deploy-can-silently-turn-off-your-webhook-endpoint-18bc</link>
      <guid>https://dev.to/payneteasy/your-deploy-can-silently-turn-off-your-webhook-endpoint-18bc</guid>
      <description>&lt;p&gt;We shipped a routine release on a Tuesday. Rolling restart, about 90 seconds where the webhook service returned 502 from the load balancer. Nobody noticed, because health checks were green again right after.&lt;/p&gt;

&lt;p&gt;Two days later, support asked why a batch of orders was stuck in "pending" even though the customers had been charged.&lt;/p&gt;

&lt;p&gt;The cause: the gateway retries failed deliveries on a schedule, and after enough consecutive failures it marks the endpoint as degraded and stops sending new events until someone re-enables it. Our 90-second window hit a burst of events, each one burned through its first retries, and the endpoint tripped. Everything after that point went nowhere. No alert fired on our side, because from our side there was simply no traffic.&lt;/p&gt;

&lt;p&gt;What we changed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Alert on the absence of webhooks, not only on errors. If zero events arrive for 15 minutes during business hours, page someone.&lt;/li&gt;
&lt;li&gt;Keep a daily job that pulls recent transactions through the API and compares them with what the webhooks delivered. The webhook is a hint, the API is the source of truth.&lt;/li&gt;
&lt;li&gt;Drain the webhook service last in the rollout, and never return 5xx while shutting down. Accept, queue, return 200.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do you monitor for silence, or only for failures? I suspect most setups only cover the second one.&lt;/p&gt;

&lt;p&gt;Payneteasy handles this kind of payment flow for merchants and PSPs — &lt;a href="https://payneteasy.com/solutions/payment-integration?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=your-deploy-can-silently-turn-off-your-webhook-endpoint&amp;amp;utm_content=cta&amp;amp;service_type=payment_services" rel="noopener noreferrer"&gt;see how it works&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>payments</category>
      <category>api</category>
      <category>backend</category>
      <category>devops</category>
    </item>
    <item>
      <title>Our amount helper assumed every currency has two decimals</title>
      <dc:creator>Payneteasy</dc:creator>
      <pubDate>Tue, 20 Oct 2026 00:00:15 +0000</pubDate>
      <link>https://dev.to/payneteasy/our-amount-helper-assumed-every-currency-has-two-decimals-f8b</link>
      <guid>https://dev.to/payneteasy/our-amount-helper-assumed-every-currency-has-two-decimals-f8b</guid>
      <description>&lt;p&gt;Ran into this when a merchant added Japan and Kuwait to their storefront. Our amount helper did one thing: multiply by 100, round, send as an integer. Fine for USD and EUR, so nobody looked at it for two years.&lt;/p&gt;

&lt;p&gt;JPY has zero decimal places in ISO 4217. A 1,000 yen basket went out as 100000, and the gateway read it as 100,000 yen. The 3DS challenge showed the customer the wrong number, which is the only reason we caught it in staging and not in a dispute queue.&lt;/p&gt;

&lt;p&gt;KWD and BHD are the opposite: three decimals. A 12.500 KWD order sent as 1250 is 1.250 KWD. The charge succeeds, the customer is undercharged by 90%, and nothing errors. Nothing in the response tells you the exponent was wrong, because the amount is a valid integer either way.&lt;/p&gt;

&lt;p&gt;The fix was boring: a lookup table of currency exponents, one function that converts to minor units, and a hard failure on unknown codes instead of a default of 2. We also added a test that round-trips every ISO 4217 code with a nonzero amount.&lt;/p&gt;

&lt;p&gt;Two side effects: our reconciliation export had the same hard-coded divisor, and a couple of acquirers cap amounts per currency in minor units, so the cap check was wrong too.&lt;/p&gt;

&lt;p&gt;Do you pull the exponent from a library, or maintain your own table? And how do you handle the currencies where the acquirer's exponent differs from ISO?&lt;/p&gt;

</description>
      <category>payments</category>
      <category>fintech</category>
      <category>backend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Vast Bank and Cliq: The Rise of Third-Party Payment Processors</title>
      <dc:creator>Payneteasy</dc:creator>
      <pubDate>Mon, 19 Oct 2026 06:45:15 +0000</pubDate>
      <link>https://dev.to/payneteasy/vast-bank-and-cliq-the-rise-of-third-party-payment-processors-5498</link>
      <guid>https://dev.to/payneteasy/vast-bank-and-cliq-the-rise-of-third-party-payment-processors-5498</guid>
      <description>&lt;p&gt;Vast Bank, a federally regulated national bank, has announced a multi-year partnership with fintech company Cliq. Under this agreement, Cliq will serve as a Third-Party Payment Processor (TPPP), providing the infrastructure to handle a wide range of transactions. The scope of services includes standard ACH payments, alternative payment methods, cryptocurrency and stablecoin solutions, and the issuance of business debit and prepaid cards.&lt;/p&gt;

&lt;p&gt;This move highlights the enduring trend of Banking-as-a-Service (BaaS) and the delegation of operational functions to specialized fintech partners. For Vast Bank, this allows for product scaling without the need to invest in complex proprietary payment infrastructure, particularly in the fast-growing crypto payment segment. For Cliq, it serves as validation of its maturity as an infrastructure player capable of serving regulated financial institutions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters.&lt;/strong&gt;&lt;br&gt;
This partnership underscores a significant shift in the payments landscape where the boundary between banks and fintechs is blurring. The key asset is no longer just the banking license, but the quality of the payment infrastructure and the speed of adopting new payment methods. It signals that regulators are increasingly accepting crypto and stablecoin models when they are integrated into the legal banking framework through reliable partners.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is affected and how
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PSPs and Banks&lt;/strong&gt;: The TPPP model is gaining traction as banks seek flexible partners offering "all-in-one" solutions, from ACH to crypto. This creates competition for traditional processors but opens niches for specialized solutions. PSPs working with banks must anticipate that their clients will actively seek external partners to expand functionality.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Merchants and Marketplaces&lt;/strong&gt;: New TPPP partnerships may expand payment method choices for end-users. If Vast Bank offers corporate clients access to crypto payments via Cliq, it could impact the B2B payment ecosystem. Marketplaces and large merchants are increasingly considering stablecoins as a tool for cross-border settlements, potentially lowering friction and costs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Regulatory Context&lt;/strong&gt;: Partnering with a federally regulated bank emphasizes that crypto and stablecoin solutions are gradually being integrated into the legal banking perimeter. For fintechs, this is a signal that such models are permissible when backed by a solid banking partner, reducing regulatory uncertainty for infrastructure providers.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;The Vast Bank and Cliq deal confirms that infrastructure quality and speed of innovation are now more critical than traditional banking barriers. As banks outsource complex processing to specialized fintechs, the market is moving toward a more modular and competitive payment ecosystem.&lt;/p&gt;

&lt;p&gt;How do you see the role of TPPPs evolving in the next five years?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://www.finextra.com/pressarticle/111298/vast-bank-forms-payment-partnership-with-cliq" rel="noopener noreferrer"&gt;Finextra, 15 Oct 2026&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>payments</category>
      <category>fintech</category>
      <category>banking</category>
      <category>architecture</category>
    </item>
    <item>
      <title>A client timeout is not a decline</title>
      <dc:creator>Payneteasy</dc:creator>
      <pubDate>Fri, 16 Oct 2026 08:00:15 +0000</pubDate>
      <link>https://dev.to/payneteasy/a-client-timeout-is-not-a-decline-3nme</link>
      <guid>https://dev.to/payneteasy/a-client-timeout-is-not-a-decline-3nme</guid>
      <description>&lt;p&gt;Our HTTP client timeout for the charge call was 10 seconds. The gateway's upstream timeout to the issuer was 30. Most auths come back in 1-2 seconds, so nobody noticed the gap.&lt;/p&gt;

&lt;p&gt;Then one issuer's processor started taking 12-15 seconds on a bad afternoon. Our client gave up at 10, logged "payment failed", and showed the customer a retry button. The auth was still in flight and succeeded at second 13. The customer clicked retry, the new attempt got a fresh order ID, and we ended up with two approved authorizations on one cart. A cleanup job voided one of them hours later, but the cardholder's available balance stayed held twice for days.&lt;/p&gt;

&lt;p&gt;The mistake was treating a timeout as a decline. A timeout is a third state: unknown. The fix was small:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On timeout, mark the payment pending_unknown, not failed&lt;/li&gt;
&lt;li&gt;Poll the gateway by our merchant order ID for up to 60 seconds before allowing a new attempt&lt;/li&gt;
&lt;li&gt;Reuse the same order ID and idempotency key on retry, so the gateway returns the original result&lt;/li&gt;
&lt;li&gt;Set the client timeout above the gateway's upstream timeout, not below it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Duplicate holds on slow-issuer days dropped to zero over the next two weeks.&lt;/p&gt;

&lt;p&gt;How do you handle the unknown state in your checkout? Do you block the retry button, or let the idempotency key sort it out?&lt;/p&gt;

</description>
      <category>payments</category>
      <category>api</category>
      <category>backend</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Webhook signature fails only when the payload has a slash in it</title>
      <dc:creator>Payneteasy</dc:creator>
      <pubDate>Thu, 15 Oct 2026 07:30:17 +0000</pubDate>
      <link>https://dev.to/payneteasy/webhook-signature-fails-only-when-the-payload-has-a-slash-in-it-1kfo</link>
      <guid>https://dev.to/payneteasy/webhook-signature-fails-only-when-the-payload-has-a-slash-in-it-1kfo</guid>
      <description>&lt;p&gt;Webhook signature check passed in staging for weeks, then started rejecting about 4% of production events. No pattern in event type, amount, or time of day.&lt;/p&gt;

&lt;p&gt;The handler used express.json() to parse the body, then verified the HMAC against JSON.stringify(req.body). Parse, re-serialize, compare. It looks harmless, and it matches the signature whenever the sender's serializer and ours produce identical bytes.&lt;/p&gt;

&lt;p&gt;They don't always. The gateway's backend escapes forward slashes ("https:\/\/shop.example\/return") and non-ASCII characters ("Jos\u00e9"). JSON.stringify does neither. So any event carrying a return URL, a cardholder name with an accent, or a descriptor with a slash got a different byte sequence and a different HMAC. Our staging fixtures were all ASCII names and had no URLs, so every test event passed.&lt;/p&gt;

&lt;p&gt;The bad fix is to normalize the output until it matches. It will break again the next time someone adds a field or the sender changes a library version.&lt;/p&gt;

&lt;p&gt;The actual fix: the signature is over the bytes that were sent, so verify the bytes that were received. Capture the raw body before any parser touches it (express.raw() or the verify callback on express.json()), compute HMAC-SHA256 over that buffer, compare with timingSafeEqual, and only then JSON.parse.&lt;/p&gt;

&lt;p&gt;We also added one fixture with a slash, an accented name, and an emoji in the descriptor. It fails loudly if anyone puts a parser back in front of the check.&lt;/p&gt;

&lt;p&gt;Has anyone hit a variant of this with a gateway that signs a canonicalized body instead of the raw one?&lt;/p&gt;

</description>
      <category>payments</category>
      <category>api</category>
      <category>webdev</category>
      <category>node</category>
    </item>
    <item>
      <title>Our synchronous response said success. The webhook disagreed four seconds later.</title>
      <dc:creator>Payneteasy</dc:creator>
      <pubDate>Sat, 10 Oct 2026 00:00:15 +0000</pubDate>
      <link>https://dev.to/payneteasy/our-synchronous-response-said-success-the-webhook-disagreed-four-seconds-later-b4f</link>
      <guid>https://dev.to/payneteasy/our-synchronous-response-said-success-the-webhook-disagreed-four-seconds-later-b4f</guid>
      <description>&lt;p&gt;Checkout flow: call charge endpoint, get back &lt;code&gt;status: approved&lt;/code&gt; synchronously, show the confirmation page, write the order to the DB as paid. Standard stuff.&lt;/p&gt;

&lt;p&gt;Then the webhook for the same transaction lands 2-6 seconds later. Most of the time it just confirms what we already knew. Except for a window where the issuer sends a late decline after the gateway already told us approved — card network risk check flagged it post-authorization, something like 1 in 3000 transactions on one acquirer.&lt;/p&gt;

&lt;p&gt;Our order write happened on the sync response. The webhook handler had no idea an order even existed yet when it tried to update status, because the DB write from the sync path hadn't committed. Webhook processed against a row that didn't exist, silently no-op'd, and we shipped a product against a transaction that got reversed six hours later in the settlement file.&lt;/p&gt;

&lt;p&gt;Fix was boring: webhook handler now upserts instead of updates, and order state transitions go through a queue instead of direct writes so ordering is enforced regardless of which path (sync response or webhook) arrives first.&lt;/p&gt;

&lt;p&gt;Curious how other people handle the case where your own synchronous API response can't be trusted as final. Do you delay fulfillment until the webhook confirms, even on providers where that adds real latency to checkout?&lt;/p&gt;

</description>
      <category>payments</category>
      <category>api</category>
      <category>backend</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
