<?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: mcduffin</title>
    <description>The latest articles on DEV Community by mcduffin (@mcduffin).</description>
    <link>https://dev.to/mcduffin</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F840644%2F2d5f3d31-fd3f-436e-8d76-9848fec18dbd.png</url>
      <title>DEV Community: mcduffin</title>
      <link>https://dev.to/mcduffin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mcduffin"/>
    <language>en</language>
    <item>
      <title>Enhancing Payment Fraud Detection with Rapyd Protect</title>
      <dc:creator>mcduffin</dc:creator>
      <pubDate>Thu, 09 Apr 2026 14:00:00 +0000</pubDate>
      <link>https://dev.to/rapyd/enhancing-payment-fraud-detection-with-rapyd-protect-5dap</link>
      <guid>https://dev.to/rapyd/enhancing-payment-fraud-detection-with-rapyd-protect-5dap</guid>
      <description>&lt;p&gt;By: &lt;strong&gt;Manish Hatwalne&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Rapyd provides a platform for embedding payment services into your applications. To help you combat payment fraud, &lt;a href="https://docs.rapyd.net/en/rapyd-protect-overview.html" rel="noopener noreferrer"&gt;Rapyd Protect&lt;/a&gt; is included for Rapyd accounts (verify plan eligibility) that offers protection for transactions involving credit cards, bank transfers, and e-wallets, while maintaining a seamless checkout experience for legitimate customers. &lt;/p&gt;

&lt;p&gt;Powered by machine learning (ML) and advanced risk models, Rapyd Protect works in real time to identify suspicious patterns, from unusual spending behavior to mismatched user information. It also allows you to maintain full control with customizable rules that can automatically block high-risk transactions or flag them for manual review.&lt;/p&gt;

&lt;p&gt;In this article, you'll learn how you can enhance payment fraud detection in your applications with Rapyd Protect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rapyd Protect
&lt;/h2&gt;

&lt;p&gt;Rapyd Protect helps you minimize chargebacks and protect your revenue. It provides protection via two approaches:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Machine learning&lt;/li&gt;
&lt;li&gt;Fraud rules&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  How Rapyd Protect Uses Machine Learning to Prevent Fraudulent Transactions
&lt;/h3&gt;

&lt;p&gt;Rapyd Protect uses ML models that have been trained on Rapyd's historical transaction data to recognize patterns that indicate fraud. When a transaction comes through, the models analyze various signals, like the customer's location, device fingerprint, transaction amount, and payment method, to assign a specific risk score. &lt;/p&gt;

&lt;p&gt;For example, if someone attempts multiple small test transactions from different IP addresses using the same card within a short timeframe (a common card-testing pattern), the velocity engine typically tracks this behavior while the ML model evaluates the overall risk profile. Similarly, if a card’s Bank Identification Number (BIN) belongs to a U.S. bank but is used for a high-value transaction from an IP in another country, Rapyd Protect may flag it as suspicious. &lt;/p&gt;

&lt;p&gt;The ML models are continuously retrained with new data to detect evolving fraud tactics, like shifts in geographic attack patterns or new account takeover techniques.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fraud Rules
&lt;/h3&gt;

&lt;p&gt;Rapyd Protect also includes a &lt;a href="https://www.rapyd.net/blog/fraud-rules-engine/" rel="noopener noreferrer"&gt;rules engine&lt;/a&gt; for &lt;a href="https://docs.rapyd.net/en/creating-a-fraud-rule.html" rel="noopener noreferrer"&gt;creating custom fraud policies&lt;/a&gt; based on parameters like IP addresses, card types, amount, geographic locations, and 3D Secure requirements. The platform maintains reference lists of known fraudulent entities, suspicious IP addresses, restricted countries, and high-risk BIN  ranges. Transactions can be blocked or routed to manual review queues based on configurable criteria such as transaction amount or origin country. &lt;/p&gt;

&lt;p&gt;The system provides interfaces for reviewing flagged transactions, approving or declining payments, viewing triggered rules, and accessing blocked transaction logs. These rules work alongside ML to enhance fraud detection and adapt to evolving threats.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Custom Fraud Rules in Rapyd Protect
&lt;/h2&gt;

&lt;p&gt;While ML used by Rapyd Protect prevents common fraudulent transactions, sometimes you need custom rules to address your specific business requirements. For example, you might want to block customers making more than a specified number of card transactions within three days, block card transactions from regions where you don't operate, or block high-value card transactions over 2,500 EUR. &lt;/p&gt;

&lt;p&gt;Let's look at how you can create this amount-based blocking rule in Rapyd Protect.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rules Engine
&lt;/h3&gt;

&lt;p&gt;The Rapyd Protect Rules Engine lets you create custom fraud prevention rules based on various transaction attributes like IP addresses, card types, countries, transaction amounts, BIN ranges, and 3D Secure requirements. These rules provide an additional layer of protection tailored to your specific business needs. Each rule consists of two components: &lt;em&gt;the triggering conditions&lt;/em&gt; (what to look for) and &lt;em&gt;the action&lt;/em&gt; (allow, block, or review) to take when those conditions are met.&lt;/p&gt;

&lt;p&gt;Rules fall into three categories with a specific hierarchy: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Allow rules&lt;/strong&gt; takes highest priority and permits transactions matching their criteria, overriding any other rules. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Block rules&lt;/strong&gt; automatically rejects transactions that meet their conditions, unless an "Allow" rule applies. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review rules&lt;/strong&gt; flags transactions for manual evaluation and routes them to an "Under Review" queue where you must approve or decline them within seven days. These rules only trigger if the transaction doesn't match any "Allow" or "Block" rules and they are only available for bank payments, not for card payments.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The following diagram shows how rule processing takes place in Rapyd Protect:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhsq7z05isk34ce4mipud.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhsq7z05isk34ce4mipud.png" alt="Rule processing in Rapyd Protect" width="390" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating an Amount-Based Blocking Rule
&lt;/h3&gt;

&lt;p&gt;Now that you understand how Rapyd Protect rule processing works, let's create a blocking rule for high-value transactions. We'll build a rule that automatically blocks any transaction exceeding 2,500 EUR.&lt;/p&gt;

&lt;p&gt;Log in to your &lt;a href="https://dashboard.rapyd.net/login" rel="noopener noreferrer"&gt;Rapyd account&lt;/a&gt; and select &lt;strong&gt;Protect&lt;/strong&gt; from the left-hand navigation menu. The &lt;strong&gt;Rules&lt;/strong&gt; page displays all your existing rules and lets you create new ones:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47pqlstm34qg82a8iwfj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47pqlstm34qg82a8iwfj.png" alt="Rapyd Protect **Rules** Page" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the &lt;strong&gt;Add rule&lt;/strong&gt; button in the &lt;strong&gt;Block&lt;/strong&gt; section at the bottom of the page. In the dialog that appears, define your blocking condition: "Amount EUR Greater than 2,500". Then, add a meaningful description for your rule. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Rapyd Protect supports complex rule logic, so you can combine multiple conditions using &lt;code&gt;and&lt;/code&gt; or &lt;code&gt;or&lt;/code&gt; clauses if needed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F54gm3m1pbosh4bnjedax.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F54gm3m1pbosh4bnjedax.png" alt="Rapyd Protect: Block high-value transactions" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After configuring your conditions, click the &lt;strong&gt;Create rule&lt;/strong&gt; button (this becomes active once you've added at least one condition). A confirmation dialog will appear asking you to enable the rule:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7sxpcb6jhbg4hq08n92.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7sxpcb6jhbg4hq08n92.png" alt="Rapyd Enable rule" width="444" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Enable&lt;/strong&gt; to activate your rule. If you skip this step, the rule will be created but remain inactive (&lt;em&gt;aka&lt;/em&gt; disabled). It won't affect any transactions until you manually enable it later.&lt;/p&gt;

&lt;p&gt;You can create additional blocking rules based on your specific business needs. For instance, if you only accept US-issued cards, create a rule with the condition &lt;code&gt;Card country Not Equal to US&lt;/code&gt; to block all international card transactions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing the Blocking Rule
&lt;/h3&gt;

&lt;p&gt;After creating your amount-based blocking rule, you can test it using Rapyd's &lt;a href="https://www.rapyd.net/products/payments/virtual-terminals/" rel="noopener noreferrer"&gt;Virtual Terminal&lt;/a&gt;. Navigate to the &lt;strong&gt;Getting started&lt;/strong&gt; page and select the &lt;strong&gt;Collect payments&lt;/strong&gt; tab. This page provides multiple options, including payment links, card payment simulation, and branding customization. &lt;/p&gt;

&lt;p&gt;Rapyd provides a sandbox mode for development, so all transactions use test data, no real cards or money are involved. Click the &lt;strong&gt;Collect virtually&lt;/strong&gt; button under the &lt;strong&gt;Virtual terminal&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8734umxt3fqk0ud49r8c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8734umxt3fqk0ud49r8c.png" alt="Rapyd dashboard" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the &lt;a href="https://docs.rapyd.net/en/virtual-terminal.html" rel="noopener noreferrer"&gt;Virtual Terminal&lt;/a&gt;, you can simulate a card payment by following these steps:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enter payment details:&lt;/strong&gt; Select the customer's country, payment method (card type: Visa or Mastercard), amount (enter a value above your rule threshold, such as: &lt;code&gt;2501 EUR&lt;/code&gt;), currency, then click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fasa0mxob50kisaairmx2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fasa0mxob50kisaairmx2.png" alt="Rapyd Virtual Terminal 1" width="781" height="607"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enter card information:&lt;/strong&gt; Provide the cardholder name, card number (use test card &lt;code&gt;4111 1111 1111 1111&lt;/code&gt;), a future expiration month and year, and any 3-digit CVV number (any digits work in Sandbox), then click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feda33tfz7br40984v5zw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feda33tfz7br40984v5zw.png" alt="Rapyd Virtual Terminal 2" width="792" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skip additional details:&lt;/strong&gt; Click &lt;strong&gt;Create payment&lt;/strong&gt; to bypass the optional &lt;strong&gt;Additional details&lt;/strong&gt; dialog.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvzhubuvzauhkno4c8qr4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvzhubuvzauhkno4c8qr4.png" alt="Rapyd virtual terminal 3" width="797" height="601"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;View the blocking result:&lt;/strong&gt; Since the transaction amount exceeds EUR 2,500, the Rapyd Protect rules engine marks the payment as blocked or routes it to the Under Review queue; see your dashboard for the block reason. You'll see a &lt;strong&gt;Payment blocked&lt;/strong&gt; dialog with the message: "Your transaction has been blocked by Rapyd Protect. It can be viewed under the "Blocked" tab."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8o4j24h68pblgo3xfpz5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8o4j24h68pblgo3xfpz5.png" alt="Rapyd virtual terminal 4: Blocked payment" width="486" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Close&lt;/strong&gt; to dismiss this dialog. Your blocking rule has successfully triggered and prevented the high-value transaction.&lt;/p&gt;

&lt;p&gt;To verify the rule works correctly, test a few more transactions. Use amounts at or below 2,500 EUR (which should process successfully) and amounts above 2,500 EUR (which should be blocked). This confirms your rule is enforcing the threshold properly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Your application can integrate the payment collection using &lt;a href="https://docs.rapyd.net/en/card-payments.html#id298679_body" rel="noopener noreferrer"&gt;Rapyd APIs&lt;/a&gt; as well.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Monitoring Blocked and Successful Transactions
&lt;/h3&gt;

&lt;p&gt;After testing your rule, you can review the results in the Rapyd dashboard. Navigate to &lt;strong&gt;Collect&lt;/strong&gt; in the left-hand navigation, then under &lt;strong&gt;Review &amp;amp; Protect&lt;/strong&gt;, select &lt;strong&gt;Blocked&lt;/strong&gt;. &lt;a href="https://docs.rapyd.net/en/view-all-blocked-transactions.html" rel="noopener noreferrer"&gt;This page&lt;/a&gt; displays all transactions that were rejected by your blocking rules. You can filter the list by date range and other criteria.&lt;/p&gt;

&lt;p&gt;Click on any transaction row to view its details in the right-hand panel. The detail view shows the transaction amount, currency, timestamp, customer information, and other relevant data:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3or1lkfgk43gjt4twg7l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3or1lkfgk43gjt4twg7l.png" alt="Rapyd Protect: Blocked transactions" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the bottom of the detail panel, you'll see a &lt;strong&gt;Triggered rules&lt;/strong&gt; section. Click the &lt;strong&gt;View&lt;/strong&gt; link to see which rule(s) caused the transaction to be blocked. A dialog will display the specific blocking rule that triggered it, which is your high-value transaction rule:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffjb11qvgtrgk5kns49v1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffjb11qvgtrgk5kns49v1.png" alt="Rapyd Protect: Triggering rule for the blocked transaction" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To verify that legitimate transactions are processing correctly, navigate to the &lt;strong&gt;Payments&lt;/strong&gt; page under &lt;strong&gt;Collect&lt;/strong&gt;. This page shows all successfully processed transactions. As shown in the following screenshot, transactions at or below 2,500 EUR complete successfully and are not blocked by your rule:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmqy1atpeawzfeblz9lgz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmqy1atpeawzfeblz9lgz.png" alt="Rapyd Protect: Valid transaction" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; These transactions may take up to 15 minutes to appear in this dashboard.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Advanced Features of Rapyd Protect
&lt;/h3&gt;

&lt;p&gt;Beyond basic blocking rules, Rapyd Protect offers several advanced features for more sophisticated fraud prevention strategies. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://docs.rapyd.net/en/card-payment-with-3ds-verification.html" rel="noopener noreferrer"&gt;3D Secure rules&lt;/a&gt;&lt;/strong&gt; allow you to conditionally trigger additional authentication for card transactions based on specific criteria. For example, requiring 3D Secure verification for all transactions above a certain amount or from particular countries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://docs.rapyd.net/en/view-all-transactions-under-review.html" rel="noopener noreferrer"&gt;Review rules&lt;/a&gt;&lt;/strong&gt; work differently from blocking rules by placing transactions in a manual review queue rather than automatically rejecting them. This is available for bank payments (inbound or outbound) where you want human oversight before approving high-risk transactions. Reviewers have seven days to approve or decline each flagged transaction from the &lt;strong&gt;Under Review&lt;/strong&gt; dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.rapyd.net/blog/safeguard-your-business-with-rapyd-protect/#:~:text=Rules%20Library" rel="noopener noreferrer"&gt;Rule Library&lt;/a&gt;&lt;/strong&gt; provides a collection of pre-configured fraud prevention rules that you can activate and customize for your business. Instead of building common rules from scratch, you can select templates from the library, adjust their parameters to match your requirements, and add them to your active rule set. This speeds up the implementation of standard fraud prevention patterns while still allowing full customization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.rapyd.net/blog/safeguard-your-business-with-rapyd-protect/#:~:text=Lists" rel="noopener noreferrer"&gt;Lists&lt;/a&gt;&lt;/strong&gt; Rapyd Protect offers several lists that your rules can reference for more granular control. 

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Allowed Cards&lt;/strong&gt; and &lt;strong&gt;Blocked Cards&lt;/strong&gt; lists use card fingerprints to whitelist or 
blacklist specific cards. &lt;/li&gt;
&lt;li&gt;For bank transactions, you can manage &lt;strong&gt;Approved Bank Accounts&lt;/strong&gt; (always allow) and 
&lt;strong&gt;Blocked Bank Accounts&lt;/strong&gt; (always reject) based on customer (or beneficiary) account 
details. &lt;/li&gt;
&lt;li&gt;Geographic controls are available through &lt;strong&gt;Country Codes to Block&lt;/strong&gt; (for card-issuing 
countries) and &lt;strong&gt;Blocked Beneficiary Bank Country&lt;/strong&gt; (for bank transfer destinations).
These lists provide a flexible way to maintain exception-based policies without creating individual rules for each case. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Programmatic access&lt;/strong&gt; Rapyd Protect provides &lt;a href="https://docs.rapyd.net/en/payment.html" rel="noopener noreferrer"&gt;&lt;strong&gt;API endpoints&lt;/strong&gt;&lt;/a&gt; and &lt;a href="https://docs.rapyd.net/en/rapyd-protect.html#:~:text=Rapyd%20Protect%20Webhooks" rel="noopener noreferrer"&gt;&lt;strong&gt;Webhooks&lt;/strong&gt;&lt;/a&gt; that allow you to integrate fraud prevention directly into your application. The APIs allow you to handle payments, while webhooks send real-time alerts when your fraud rules trigger, allowing your system to respond automatically to fraud events. &lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;For detailed integration guides and API documentation, visit the &lt;a href="https://docs.rapyd.net/" rel="noopener noreferrer"&gt;Rapyd Developer Portal&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, you learned how Rapyd Protect combines ML with customizable fraud prevention rules to safeguard your payment operations. You not only learned how to create those custom rules, but also test those rules using the Virtual Terminal, and then monitor their performance through the dashboard. &lt;/p&gt;

&lt;p&gt;Rapyd Protect is an important component of Rapyd's comprehensive payment platform. Whether you're processing cards, bank transfers, or e-wallets, Rapyd provides the tools to accept payments globally while maintaining security and compliance. &lt;/p&gt;

&lt;p&gt;If you're looking to implement fraud prevention in your application, sign up for &lt;a href="https://dashboard.rapyd.net/sign-up" rel="noopener noreferrer"&gt;Rapyd's trial account&lt;/a&gt; to access the Sandbox environment, explore the full Rapyd API capabilities, and start building secure payment flows today. &lt;/p&gt;

</description>
      <category>fintech</category>
      <category>ai</category>
      <category>fraud</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>AI for Regulatory Compliance in Payments</title>
      <dc:creator>mcduffin</dc:creator>
      <pubDate>Wed, 11 Mar 2026 18:30:37 +0000</pubDate>
      <link>https://dev.to/rapyd/ai-for-regulatory-compliance-in-payments-11g9</link>
      <guid>https://dev.to/rapyd/ai-for-regulatory-compliance-in-payments-11g9</guid>
      <description>&lt;p&gt;By: &lt;strong&gt;Manish Hatwalne&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Rapyd Protect is an AI-powered fraud detection service built into Rapyd's payment platform. It monitors transactions in real time across bank transfers, cards, and e-wallets, using machine learning (ML) models to identify suspicious patterns and potential compliance violations. &lt;/p&gt;

&lt;p&gt;For developers building payment applications, regulatory compliance requirements like Anti-Money Laundering (AML) monitoring, suspicious activity reporting, and transaction screening can be difficult to implement. Rapyd Protect addresses these challenges through automated checks, ML-based risk scoring, and configurable review workflows. When a transaction triggers compliance (or fraud) concerns, the system automatically quarantines it and notifies your application via webhook, helping you maintain audit trails for regulatory purposes.&lt;/p&gt;

&lt;p&gt;In this article, you'll learn how to use Rapyd Protect's fraud rules for compliance monitoring. You'll see how ML flags high-risk transactions for you review, and how to implement review workflows that meet regulatory requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rapyd Protect and Regulatory Compliance
&lt;/h2&gt;

&lt;p&gt;Payment systems operate under multiple regulatory frameworks designed to prevent financial crime and protect consumers. &lt;a href="https://www.rapyd.net/blog/aml-kyc-differences/#:~:text=AML%20Requirements" rel="noopener noreferrer"&gt;AML regulations&lt;/a&gt; require monitoring for suspicious transaction patterns that could indicate money laundering or terrorist financing. Know Your Customer (KYC) and &lt;a href="https://docs.rapyd.net/en/activating-your-account--kyb-.html" rel="noopener noreferrer"&gt;Know Your Business (KYB)&lt;/a&gt; rules mandate identity verification for individuals and companies conducting transactions. The &lt;a href="https://www.rapyd.net/blog/what-businesses-need-to-know-about-psd2/" rel="noopener noreferrer"&gt;Payment Services Directive 2 (PSD2)&lt;/a&gt; in Europe enforces Strong Customer Authentication and secure communication standards, while the &lt;a href="https://en.wikipedia.org/wiki/General_Data_Protection_Regulation" rel="noopener noreferrer"&gt;General Data Protection Regulation (GDPR)&lt;/a&gt; governs how personal data is collected and processed. Regional frameworks like the &lt;a href="https://www.oag.ca.gov/privacy/ccpa" rel="noopener noreferrer"&gt;California Consumer Privacy Act (CCPA)&lt;/a&gt; and Brazil's &lt;a href="https://www.gov.br/esporte/pt-br/acesso-a-informacao/lgpd" rel="noopener noreferrer"&gt;Lei Geral de Proteção de Dados (LGPD)&lt;/a&gt; add additional layers of compliance requirements based on geographic location.&lt;/p&gt;

&lt;p&gt;Rapyd Protect handles these compliance challenges using ML models that analyze transaction data in real time by evaluating each transaction against patterns learned from Rapyd's global payment network, identifying anomalies that may indicate compliance violations. These models consider multiple factors including transaction velocity, geographic origin, payment amounts, and behavioral patterns. Based on this analysis, the system assigns risk scores to each transaction. When a transaction exceeds acceptable risk thresholds or matches suspicious activity patterns, Rapyd Protect automatically halts it and places it in quarantine for review.&lt;/p&gt;

&lt;p&gt;This approach detects compliance issues that static rules alone might miss. The system adapts to emerging fraud trends and regulatory risks as they develop, giving you continuous protection without constant manual updates.&lt;/p&gt;

&lt;p&gt;When Rapyd Protect quarantines a transaction, it communicates the status through a series of &lt;a href="https://docs.rapyd.net/en/quarantine-webhooks.html" rel="noopener noreferrer"&gt;webhooks&lt;/a&gt; sent to your application. These webhooks provide the detailed information you need to maintain compliance audit trails, update transaction statuses, and communicate with customers about delayed payments. &lt;/p&gt;

&lt;h3&gt;
  
  
  How Machine Learning Benefits Compliance Monitoring
&lt;/h3&gt;

&lt;p&gt;Rapyd Protect's machine learning capabilities handle a challenge that's impossible to solve manually: analyzing &lt;em&gt;massive&lt;/em&gt; amounts of transaction data in real time spotting suspicious patterns that human compliance officers would miss.&lt;/p&gt;

&lt;p&gt;The Rapyd Protect ML system runs 24/7, analyzing transaction ledgers even when your compliance teams are offline. This constant surveillance is critical for meeting regulatory requirements. Each transaction creates a ledger entry with detailed information like the payment amount, parties involved, geographic locations, timestamps, and payment methods. The ML models scan these ledgers for discrepancies and anomalies, comparing new transactions against historical patterns to catch deviations that might signal compliance violations.&lt;/p&gt;

&lt;p&gt;A major advantage of Rapyd's machine learning approach is its ability to spot subtle patterns in vast datasets.The system can detect small changes in transaction timing, gradual increases in payment amounts, or unusual connections between seemingly unrelated accounts. These patterns often indicate attempts to evade detection. Activities that look normal individually may reveal suspicious intent when analyzed collectively. The &lt;a href="https://docs.rapyd.net/en/rapyd-protect-overview.html#:~:text=Velocity%20Engine" rel="noopener noreferrer"&gt;Velocity Engine&lt;/a&gt; tracks purchase frequency and usage patterns across multiple timeframes, flagging sudden spikes in transaction velocity or suspicious pattern shifts that need investigation.&lt;/p&gt;

&lt;p&gt;When the ML models identify a potential compliance issue, they don't just flag the transaction. They also provide context that helps human reviewers make informed decisions. The system analyzes patterns across your entire payment network, correlating data from multiple sources to build a complete risk profile for each flagged transaction.&lt;/p&gt;

&lt;p&gt;This gives your compliance officers much greater reach. Each team member can effectively monitor far more transactions than manual review would allow. The system catches regulatory violations quickly, creating a stronger defense against financial crime. And because the ML models adapt to new threats automatically, your payment application stays compliant even as regulations and fraud tactics evolve. This means less ongoing maintenance work for your team.&lt;/p&gt;

&lt;p&gt;The diagram below illustrates how Rapyd Protect's machine learning engine evaluates each transaction and determines the appropriate compliance action:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff045k262tv2f0evhgjie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff045k262tv2f0evhgjie.png" alt="Rapyd Protect Transaction Review Process" width="594" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up Compliance Review Workflows with Rapyd
&lt;/h3&gt;

&lt;p&gt;When Rapyd Protect identifies a transaction that requires investigation, it automatically halts the payment flow and places it in quarantine. This quarantine system serves as a critical checkpoint for regulatory compliance (or fraud detection), ensuring that potentially problematic transactions receive proper scrutiny before processing. It's built directly into Rapyd's payment infrastructure and communicates transaction status changes through a standardized webhook system (calling your predefined URL with a payload) that you can integrate into your application.&lt;/p&gt;

&lt;p&gt;Rapyd Protect uses four distinct &lt;a href="https://docs.rapyd.net/en/rapyd-protect.html" rel="noopener noreferrer"&gt;quarantine webhooks&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Quarantine Under Review&lt;/strong&gt; webhook triggers immediately when a transaction is placed in quarantine, providing your application with the transaction details and the reason for the hold. This notification allows you to update your system's transaction status, inform customers about the delay, and route the case to appropriate compliance personnel for investigation. The webhook payload includes essential information needed for compliance tracking and customer communication.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After a compliance officer reviews the quarantined transaction, Rapyd Protect sends one of three resolution webhooks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Quarantine Released&lt;/strong&gt; webhook indicates that the transaction has been approved and will proceed to completion. &lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Quarantine Declined&lt;/strong&gt; webhook signals that the transaction has been rejected due to compliance (or fraud) concerns and will not be processed. &lt;/li&gt;
&lt;li&gt;In cases where a transaction is approved but encounters technical issues during release, the &lt;strong&gt;Quarantine Release Failed&lt;/strong&gt; webhook notifies your application that manual intervention may be required to resolve the processing error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsj81v2844wvyx5b7ja9o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsj81v2844wvyx5b7ja9o.png" alt="Rapyd Protect Webhooks" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The manual review process must take place within a &lt;strong&gt;7-day window&lt;/strong&gt;. During this time, compliance officers should examine quarantined transactions against regulatory requirements. They should evaluate customer transaction history, geographic risk indicators, and regulatory alignment before making approval or decline decisions. This timeframe balances thorough compliance scrutiny with maintaining reasonable payment processing speeds.&lt;/p&gt;

&lt;p&gt;For developers, integrating this workflow requires proper webhook handling within your application architecture. When receiving a Quarantine Under Review webhook, you should update the transaction status in your database, trigger customer notifications about the delay, and route case details to your compliance dashboard for tracking. The webhook payload contains identifiers that correlate the quarantined transaction with your original payment request, ensuring accurate status updates across your system.&lt;/p&gt;

&lt;p&gt;A typical webhook payload looks like this for a &lt;code&gt;QUARANTINE_UNDER_REVIEW&lt;/code&gt; event:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wh_540b8a22cd77283ec2a721362e4de32d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"qm_a5169383ddd6f0e04f716601dbc7375e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"target_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"payout_71987d8e65a4e7a68a5ea000e1984a24"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"limits"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"compliance"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"compliance"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HLD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1646532379&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"error_code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"updated_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1646532379&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"action_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"create_payout"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"resolved_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"action_flow_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"6a8840f9-5ebd-423c-8eab-b397b5ef81f1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"duplicated_action_flow_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"QUARANTINE_UNDER_REVIEW"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NEW"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1646532379&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"extended_timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1646532379934&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"trigger_operation_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"f0c9ecbf-a238-4fa9-b0d5-a00aa3e322e6"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These webhooks allow you to build compliant payment applications with proper audit trails. Each webhook provides timestamped records of compliance decisions, creating an immutable log of when transactions were flagged, who reviewed them, and what actions were taken. This documentation is essential for regulatory examinations. By storing webhook data, your application can maintain a complete compliance history that demonstrates due diligence in monitoring suspicious transactions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Did you know?&lt;/strong&gt; Rapyd Protect also allows developers to create custom fraud rules that complement ML-based detection, so you can configure business-specific compliance checks like geographic restrictions or transaction amount thresholds. For detailed guidance, see this article about &lt;a href="https://docs.rapyd.net/en/rapyd-protect-fraud-rules.html" rel="noopener noreferrer"&gt;Enhancing Payment Fraud Detection with Rapyd Protect&lt;/a&gt;. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Benefits Of Automated Compliance Monitoring With Rapyd Protect
&lt;/h3&gt;

&lt;p&gt;When you integrate Rapyd's payment APIs, compliance monitoring through machine learning and rule-based detection automatically applies to every transaction your application processes. This automation makes it possible to keep pace with evolving regulations and emerging fraud patterns. As regulatory bodies like &lt;a href="https://www.fincen.gov/" rel="noopener noreferrer"&gt;FinCEN&lt;/a&gt; update AML requirements or new compliance risks emerge, Rapyd updates its machine learning models and detection logic without requiring changes to your application code. Your payment system continues meeting current compliance standards through automatic model updates informed by Rapyd's global transaction network and regulatory monitoring.&lt;/p&gt;

&lt;p&gt;The webhook system makes integration easy. Instead of constantly polling for transaction statuses or building complex compliance logic into your application, you simply respond to webhook events when compliance attention is needed. For example, you can automatically trigger emails to specific compliance team members based on the type of webhook event received. This keeps your compliance monitoring separate from your core business logic. Rapyd's infrastructure handles the regulatory monitoring work while your application focuses on what matters most: payment processing and customer experience.&lt;/p&gt;

&lt;p&gt;The following screenshot shows &lt;strong&gt;Under Review&lt;/strong&gt; transactions detected by the Rapyd Protect system:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe9iphhqwcpkcztb99erc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe9iphhqwcpkcztb99erc.png" alt="Rapyd Under Review Transactions" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every quarantined transaction, compliance decision, and status change generates logged records accessible through your Rapyd account. These automated logs provide the audit trails required during regulatory examinations, documenting your payment system's compliance monitoring activities without manual record-keeping. The logs capture timestamps, decision rationale, and transaction details that demonstrate adherence to AML regulations and other compliance frameworks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Rapyd Protect transforms regulatory compliance by combining machine learning risk assessment with configurable workflows and real-time webhooks. The platform helps you build payment applications that meet complex regulatory requirements without constant manual oversight. The system monitors transactions continuously, flags compliance issues automatically, and maintains the audit trails necessary for regulatory examinations.&lt;/p&gt;

&lt;p&gt;For developers, this means faster time to market and reduced compliance overhead. Enterprise-grade compliance monitoring is built directly into Rapyd's infrastructure with no additional integration required. As regulations evolve, Rapyd Protect adapts automatically, keeping your applications aligned with current standards.&lt;/p&gt;

&lt;p&gt;If you're looking to automate compliance monitoring in your payment application, sign up for the &lt;a href="https://dashboard.rapyd.net/sign-up" rel="noopener noreferrer"&gt;Rapyd trial account&lt;/a&gt; and start using Rapyd Protect to experience AI-powered regulatory compliance firsthand.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>developer</category>
      <category>ai</category>
      <category>fintech</category>
    </item>
    <item>
      <title>Mastering 3DS: Balancing Security, UX, and Authentication Rates</title>
      <dc:creator>mcduffin</dc:creator>
      <pubDate>Tue, 11 Nov 2025 09:00:00 +0000</pubDate>
      <link>https://dev.to/rapyd/mastering-3ds-balancing-security-ux-and-authentication-rates-19pc</link>
      <guid>https://dev.to/rapyd/mastering-3ds-balancing-security-ux-and-authentication-rates-19pc</guid>
      <description>&lt;p&gt;By: &lt;strong&gt;Adeyinka Adegbenro&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;3-D Secure (3DS) is an authentication protocol that adds an extra layer of security for card payments. It helps verify that the legitimate owner of a card is the one making the purchase. It also often serves as a mechanism to fulfill &lt;a href="https://www.mastercard.com/gateway/payment-solutions/secure-payments/strong-customer-authentication.html" rel="noopener noreferrer"&gt;Strong Customer Authentication (SCA)&lt;/a&gt;, particularly in regions subject to regulations like the &lt;a href="https://www.ecb.europa.eu/press/intro/mip-online/2018/html/1803_revisedpsd.en.html" rel="noopener noreferrer"&gt;revised Payment Services Directive (PSD2)&lt;/a&gt;, which mandates at least two forms of customer authentication.&lt;/p&gt;

&lt;p&gt;While 3DS facilitates two-factor authentication for online payments, it's designed to assess risk. This means not every payment requires an explicit challenge. Low-risk transactions can be completed through a frictionless flow without extra customer input. The protocol is meant to gauge if further security is needed for a specific transaction, and if so, the customer may be asked to input a PIN or a one-time password (OTP) sent to their device.&lt;/p&gt;

&lt;p&gt;The challenge when integrating 3DS into a payment flow is creating a balance between security, user experience, and high authorization rates. While 3DS can enhance security, it can also introduce friction that leads to user abandonment and lower approval rates if not implemented carefully.&lt;/p&gt;

&lt;p&gt;In this article, you'll go through the process of implementing 3DS and learn how to strike the balance between security, user experience, and authentication rates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the 3DS Flow: Frictionless vs. Challenge
&lt;/h2&gt;

&lt;p&gt;The original 3DS protocol, 3-D Secure 1 (3DS1), was designed to protect merchants from fraudulent chargebacks by verifying cardholder identity, but it frequently led to significant user friction. Mobile browser incompatibility, slow authentication page loads, and a perceived lack of necessity often led to transaction abandonment.&lt;/p&gt;

&lt;p&gt;Recognizing these challenges, 3-D Secure 2 (3DS2) leveraged a broader range of data to enable more accurate risk assessment and a smoother mobile experience. It introduced two main authentication paths: the frictionless flow and the challenge flow. In the frictionless flow, transactions can be approved without requiring any additional input from the cardholder. This occurs when a transaction is deemed low-risk through real-time risk-based analysis (RBA). On the flip side, if the RBA identifies a transaction as potentially high-risk, a challenge flow is initiated, prompting the user for further verification, such as an OTP, biometric authentication, or a PIN.&lt;/p&gt;

&lt;p&gt;Choosing between a frictionless or challenge flow depends on numerous data points at the time of the transaction by both merchants and issuers. These data points can include device information, transaction amount, customer status (new or existing), transactional history, and geolocation. For instance, if a new card is used by a customer with no prior transaction history or an existing card is used on an unfamiliar device, the risk can be elevated, leading to a 3DS challenge. However, a customer with a card on file and a history of successful, non-fraudulent transactions can trigger a low-risk assessment, allowing the transaction to proceed via the frictionless flow, bypassing explicit 3DS authentication.&lt;/p&gt;

&lt;p&gt;Developers should strive to minimize challenge flows and maximize frictionless outcomes by transmitting rich contextual data alongside payment information. The richer the data, the more accurately issuers can assess the customer's true risk profile. This not only aids in satisfying issuer rules and regulatory requirements but also reduces checkout friction and improves conversion rates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Balancing Security and User Experience
&lt;/h2&gt;

&lt;p&gt;Minimizing challenge flows and maximizing frictionless outcomes keeps customers happy while still preventing fraud. In this section, you will learn strategies you can use to strike that balance when implementing 3DS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using 3DS Exemptions to Reduce Friction
&lt;/h3&gt;

&lt;p&gt;3DS exemptions are specific provisions under regulations like PSD2 that allow certain transactions to bypass active cardholder authentication. These exemptions are primarily designed to reduce friction and enhance the user experience for lower-risk transactions.&lt;/p&gt;

&lt;p&gt;Here are some common exemption types:&lt;/p&gt;

&lt;h4&gt;
  
  
  Low-Value Transactions
&lt;/h4&gt;

&lt;p&gt;Developers can request a low-value exemption (LVE) for payments less than or equal to €30 (or its equivalent after currency conversion). This exemption applies as long as the cumulative sum of previous transactions by the same cardholder, since their last SCA, does not exceed a certain threshold (&lt;em&gt;eg&lt;/em&gt; €100) or the number of consecutive low-value transactions does not exceed five, depending on the issuer's enforcement policy.&lt;/p&gt;

&lt;p&gt;To programmatically request this exemption, depending on your Payment Service Provider's (PSP) API, you can set an exemption indicator. For example, with some APIs, you set &lt;code&gt;payment_method_options.sca_exemption&lt;/code&gt; to &lt;code&gt;LowValue&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Transaction Risk Analysis
&lt;/h4&gt;

&lt;p&gt;Through transaction risk analysis (TRA), merchants or their payment providers can request a 3DS exemption for transactions they've internally assessed as low-risk. This exemption is useful for promoting customer retention by ensuring known or trusted customers are not subjected to unnecessary authentication. Merchants must analyze a transaction's risk profile and confirm it as low-risk through their internal systems before requesting a TRA exemption.&lt;/p&gt;

&lt;p&gt;For instance, a $20 USD order from a long-time customer using the same known device, IP address, and billing address, with no history of chargebacks, would be a strong candidate. The merchant would then flag this as low-risk and request the exemption via TRA. Programmatically, this can involve setting &lt;code&gt;payment_method_options.sca_exemption&lt;/code&gt; to &lt;code&gt;TransactionRiskAnalysis&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Credentials on File
&lt;/h4&gt;

&lt;p&gt;Credentials on File (CoF) exemptions apply when charging a stored card from a returning customer. This typically involves the merchant or PSP securely storing a customer's card details for future payments, such as recurring subscriptions, top-ups, or one-click reorders. There are two primary types of CoF transactions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Merchant-initiated transactions (MIT):&lt;/strong&gt; This is for payments like a Netflix subscription, where the user is not actively present at the time of payment. The transaction is inherently exempt from SCA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customer-initiated transactions (CIT):&lt;/strong&gt; When a customer with their card on file chooses to reorder with a single click, they may qualify for a frictionless flow, provided the transaction meets other low-risk criteria.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While other exemptions, such as trusted beneficiaries, exist, they often require direct customer action (&lt;em&gt;eg&lt;/em&gt; whitelisting a merchant on their issuer's platform) and are less directly controlled by the merchant. This article focuses on merchant-initiated strategies.&lt;/p&gt;

&lt;p&gt;Properly utilizing the exemptions mentioned here helps maximize frictionless flows and leads to a more seamless customer experience and faster payment approvals. However, note that requesting an exemption does not guarantee a frictionless flow. The issuer ultimately retains the right to override the exemption and mandate a challenge if they deem the transaction high risk.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fine-Tuning the Challenge Indicator
&lt;/h3&gt;

&lt;p&gt;Challenge indicators are optional parameters that merchants send to issuing banks to influence whether a transaction should undergo additional authentication (a challenge flow). This parameter is typically included within the payment request to your PSP. While specific implementations may vary between PSPs, a common representation can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"3DRequestorChallengeInd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"02"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Following are some common challenge indicators:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Challenge Indicator Value&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;01&lt;/td&gt;
&lt;td&gt;No preference&lt;/td&gt;
&lt;td&gt;You let the issuer decide&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;02&lt;/td&gt;
&lt;td&gt;No challenge requested&lt;/td&gt;
&lt;td&gt;You want a frictionless flow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;03&lt;/td&gt;
&lt;td&gt;Challenge requested (merchant preference)&lt;/td&gt;
&lt;td&gt;You prefer a challenge flow (&lt;em&gt;eg&lt;/em&gt; suspicious activity, first-time user, new device)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;04&lt;/td&gt;
&lt;td&gt;Challenge requested (mandate)&lt;/td&gt;
&lt;td&gt;You need a challenge flow as required by law (regulations the merchant is bound by or internal business rule)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It's important to note that issuers make the final decision. Even if you request a frictionless flow (&lt;code&gt;02&lt;/code&gt;), the issuer may still challenge the transaction based on their risk analysis.&lt;/p&gt;

&lt;p&gt;While requesting a challenge (&lt;code&gt;03&lt;/code&gt; or &lt;code&gt;04&lt;/code&gt;) can reduce fraud and liability, doing so unnecessarily may negatively impact your conversion rates. In contrast, strategically using &lt;code&gt;02&lt;/code&gt; for low-risk transactions can improve authorization rates, but applying it too broadly to transactions that should have been challenged may lead to more chargebacks or soft declines.&lt;/p&gt;

&lt;p&gt;A good starting point is to default to &lt;code&gt;01&lt;/code&gt; (no preference) or &lt;code&gt;02&lt;/code&gt; (no challenge requested) and adjust your strategy based on observation, user behavior, and fraud risk.&lt;/p&gt;

&lt;h3&gt;
  
  
  Passing More PII Means Fewer Challenges
&lt;/h3&gt;

&lt;p&gt;Personally identifiable information (PII) comprises any data that can identify a specific individual. In the context of 3DS transactions, passing more PII can significantly increase the likelihood of a frictionless flow and improve the authentication experience for users.&lt;/p&gt;

&lt;p&gt;Issuing banks heavily rely on the RBA to determine whether a 3DS transaction should proceed via a frictionless flow or require a challenge. The more context an issuer receives, the more accurately its risk engine (often powered by artificial intelligence (AI) / machine learning (ML) models) can assess the legitimacy of a transaction.&lt;/p&gt;

&lt;p&gt;Merchants can significantly increase the likelihood of a frictionless flow by including a rich set of PII and other contextual data in their 3DS requests. When the issuing bank receives this detailed information, its RBA model can confidently look for signals of legitimacy and fraud, such as the following: Is this a known device? Is there a history of fraudulent activity associated with this IP address, email, or card? Is the transaction amount unusually high?&lt;/p&gt;

&lt;p&gt;The more detailed PII the merchant provides, the better the RBA model performs, leading to more confident risk scoring and, ultimately, higher rates of frictionless authentication.&lt;/p&gt;

&lt;p&gt;Here are some examples of valuable PII and metadata to include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Email address&lt;/li&gt;
&lt;li&gt;Phone number&lt;/li&gt;
&lt;li&gt;Billing address&lt;/li&gt;
&lt;li&gt;Device fingerprint&lt;/li&gt;
&lt;li&gt;Browser metadata&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Developers should make every effort to provide as much optional customer metadata as possible in their 3DS requests to ensure the best outcomes and maximize frictionless flows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling 3DS Failures and Soft Declines
&lt;/h3&gt;

&lt;p&gt;It's important to understand that a 3DS failure is not always the same as a final payment authorization decline. 3DS failures in online payments typically occur when a cardholder fails to correctly authenticate their transaction due to incorrect information input or because of technical issues within the authentication process itself. These outcomes can generally be categorized into two main types: hard declines and soft declines.&lt;/p&gt;

&lt;h4&gt;
  
  
  Hard Declines
&lt;/h4&gt;

&lt;p&gt;Hard declines are final rejections of a payment where retrying the transaction is unlikely to succeed. Common scenarios include the following: the card not being enrolled in 3DS, the authentication explicitly rejected by the cardholder, or the issuer refusing to honor the transaction due to a card issue (&lt;em&gt;eg&lt;/em&gt; lost, stolen, or account closed).&lt;/p&gt;

&lt;p&gt;For hard declines, it's best not to retry to avoid potential chargebacks or issuer penalties. For example, if a payment declines with a code like &lt;code&gt;63 - Cardholder not Enrolled&lt;/code&gt;, you should return a clear message to the customer, such as "Your card is not enrolled in secure authentication. Please use a different payment method."&lt;/p&gt;

&lt;h4&gt;
  
  
  Soft Declines
&lt;/h4&gt;

&lt;p&gt;Soft declines are usually not final and present an opportunity for retry. For instance, a merchant may initially attempt a frictionless flow for a payment, but the issuer can soft decline the transaction, requesting SCA on retry.&lt;/p&gt;

&lt;p&gt;When faced with soft declines, issuers may require merchants to retry soft declined transactions with 3DS within a specific timeframe, often indicated by a Merchant Advice Code (MAC). MACs are signals sent by card networks like Mastercard in response to a declined transaction. They help merchants understand whether to retry a transaction or not.&lt;/p&gt;

&lt;p&gt;Developers should build logic to handle these soft declines gracefully by retrying the same transaction but adjusting parameters to force a challenge on the second attempt (&lt;em&gt;eg&lt;/em&gt; by setting the 3DS challenge indicator appropriately, which is platform dependent).&lt;/p&gt;

&lt;p&gt;MACs are typically returned in the response of a failed 3DS transaction. These codes provide crucial guidance on the next steps to take. Here are a few examples of common MAC and their meanings:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;MAC&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;What to Do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;62&lt;/td&gt;
&lt;td&gt;Restricted card&lt;/td&gt;
&lt;td&gt;Do not retry the transaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;65&lt;/td&gt;
&lt;td&gt;Exceeds withdrawal count limit&lt;/td&gt;
&lt;td&gt;Retry with a 3DS challenge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;70&lt;/td&gt;
&lt;td&gt;Contact card issuer&lt;/td&gt;
&lt;td&gt;Retry is not advised; may indicate final failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;91&lt;/td&gt;
&lt;td&gt;Authentication not available; 3DS service down&lt;/td&gt;
&lt;td&gt;Retry later or through different processor&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Keep in mind that the codes can vary slightly depending on the payment processor. Always consult your provider's specific documentation. Decoding the MAC after a 3DS request has failed is essential for guiding developers to handle declines gracefully and optimize their payment flows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Leveraging AI to Optimize 3DS Strategy
&lt;/h3&gt;

&lt;p&gt;AI and ML offer a powerful avenue for optimizing your 3DS strategy. By combining data analysis and continuous learning, AI can help merchants and payment providers make smarter, adaptive decisions across the entire authentication funnel.&lt;/p&gt;

&lt;p&gt;AI/ML can provide value in the following ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Exemption prediction:&lt;/strong&gt; AI can analyze historical transaction data, issuer behavior, transaction context, and user history to predict when an exemption (like TRA or LVE) is most likely to succeed or even when to avoid requesting an exemption entirely to avoid soft declines. For example, if an AI model learns that a specific issuer frequently declines TRA exemptions after 10 PM, it can dynamically adjust future attempts during that timeframe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic challenge indicator selection:&lt;/strong&gt; Instead of relying on static, hard-coded values for the 3DS challenge indicator, an AI algorithm can analyze real-time data points, such as device information, customer behavior, and transaction amount, to assess the risk level of each payment. This assessment informs the selection of the most appropriate challenge indicator (&lt;em&gt;eg&lt;/em&gt; &lt;code&gt;no_challenge_requested&lt;/code&gt; for low-risk, &lt;code&gt;challenge_requested&lt;/code&gt; for high-risk). This approach helps developers better align with issuer policies, reduce friction for low-risk transactions, and avoid unnecessary declines due to mismatched challenge expectations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PII level tuning:&lt;/strong&gt; AI/ML can learn which specific PII and contextual data are most valued by different issuers. Some issuers can heavily weigh device data, while others prioritize email, IP location, or account tenure. An AI model can dynamically adjust the depth and type of information sent with each transaction to improve trust scores and increase the likelihood of frictionless flow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These AI-driven optimizations thrive on real transaction feedback loops. Models continuously learn from outcomes, such as successes, declines, and fraud flags, to identify evolving risk patterns and refine their logic over time. This approach ensures that authentication strategies are constantly improving based on real-time transactions and customer context, rather than static rules.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.rapyd.net/blog/using-ai-to-optimise-payments-performance/" rel="noopener noreferrer"&gt;benefits of integrating AI&lt;/a&gt; into your 3DS strategy include higher conversion rates, effective fraud management, improved issuer alignment, and more frictionless flows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample Project: 3DS Optimization Playground
&lt;/h2&gt;

&lt;p&gt;To help developers visualize the concepts of 3DS optimization, this section explores a simple web-based simulator called the &lt;strong&gt;3DS Optimization Playground&lt;/strong&gt;. This application demonstrates how various parameters, such as transaction amount, CoF status, challenge indicators, and the presence of PII, can influence the outcome of a 3DS flow. All the source code is available on &lt;a href="https://github.com/Rapyd-Samples/Rapyd_3ds_example/blob/main/simulator.html" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;simulator.html&lt;/code&gt; file is designed to run directly in a web browser without requiring a server-side component. Here's a brief explanation of its key components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DOM element selection:&lt;/strong&gt; The logic starts by selecting all the necessary HTML elements using &lt;code&gt;document.getElementById&lt;/code&gt; and storing them in constants for easy access:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;amountInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;amount&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cofStatusSelect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cofStatus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;challengeIndicatorSelect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;challengeIndicator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;piiPresenceCheckbox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;piiPresence&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;aiModelToggle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aiModelToggle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;simulateBtn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;simulateBtn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;outputSection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;outputSection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;outcomeSpan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;outcome&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;frictionlessRateSpan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;frictionlessRate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;challengeRateSpan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;challengeRate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;failureRateSpan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;failureRate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;exemptionReasonDiv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;exemptionReason&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;failureReasonDiv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;failureReason&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Global rates for AI model persistence:&lt;/strong&gt; The &lt;code&gt;currentFrictionlessRate&lt;/code&gt;, &lt;code&gt;currentChallengeRate&lt;/code&gt;, and &lt;code&gt;currentFailureRate&lt;/code&gt; variables are the base rates that define the probabilities of friction, challenge, and failure occurring in 3DS. They also get tuned in real time after every transaction so that the AI model simulator simulates a cumulative effect on the rates over time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Event listener:&lt;/strong&gt; The &lt;code&gt;simulateBtn.addEventListener('click', simulate3DS)&lt;/code&gt; line attaches an event listener to the "&lt;strong&gt;Simulate 3DS Flow&lt;/strong&gt;" button in the UI. When the button is clicked, the &lt;code&gt;simulate3DS&lt;/code&gt; function is called.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;simulate3DS&lt;/code&gt; function:&lt;/strong&gt; This is the main function that performs the simulation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Input retrieval:&lt;/strong&gt; The function initially reads the current value of all input fields (&lt;code&gt;amount&lt;/code&gt;, &lt;code&gt;cofStatus&lt;/code&gt;, &lt;code&gt;challengeIndicator&lt;/code&gt;, &lt;code&gt;piiPresence&lt;/code&gt;, &lt;code&gt;aiModelToggle&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Initialization:&lt;/strong&gt; This sets up variables to store the outcome and any specific reasons for the current run in variable &lt;code&gt;outcome&lt;/code&gt;, &lt;code&gt;exemptionReason&lt;/code&gt;, and &lt;code&gt;failureReason&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exemption evaluation:&lt;/strong&gt; The next part of the function (lines 314–343) determines if the transaction is eligible for various 3DS exemptions (TRA, LVE, recurring payments). It sets &lt;code&gt;exemptionApplied&lt;/code&gt; and &lt;code&gt;exemptionReason&lt;/code&gt; according to the exemption triggered.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ACS random challenge logic:&lt;/strong&gt; Access Control Server (ACS) in payments is a system operated by the issuer to verify the cardholder's identity. In the function, the ACS code block (lines 346–352) implements a one-in-four chance for the ACS to mandate a challenge if no exemption applies and the challenge indicator is "no preference" or "no challenge".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outcome determination:&lt;/strong&gt; Based on the combination of the challenge indicator, exemption eligibility, and the ACS-mandated challenge, the code block determines the final &lt;code&gt;outcome&lt;/code&gt; of the 3DS flow (e.g., "Frictionless (Exempted)", "Challenge (Mandated)", "Frictionless", "Failure").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI model impact (simplified):&lt;/strong&gt; If the "Enable AI model" toggle is enabled, this section simulates how an AI may auto-tune parameters. It heuristically adjusts the global frictionless, challenge, and failure rates to favor more frictionless outcomes, demonstrating the concept of optimization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate normalization:&lt;/strong&gt; Ensure the sum of frictionless, challenge, and failure rates always adds up to 100 percent to maintain probability consistency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Display results:&lt;/strong&gt; Updates the application's output section with the calculated outcome and rates. It also displays the &lt;code&gt;exemptionReason&lt;/code&gt; or &lt;code&gt;failureReason&lt;/code&gt; if applicable.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Test Cases for the 3DS Simulator
&lt;/h3&gt;

&lt;p&gt;The following scenarios are designed to help you visualize the logic in the simulation. Open &lt;code&gt;simulator.html&lt;/code&gt; with your preferred (modern) browser to play around with it. For each test case, enter the specified input values and click the &lt;strong&gt;Simulate 3DS Flow&lt;/strong&gt; button to see the expected outcome.&lt;/p&gt;

&lt;h4&gt;
  
  
  Low-Value Exemption
&lt;/h4&gt;

&lt;p&gt;This test case demonstrates a transaction that is automatically exempted from a challenge because the transaction value is low.&lt;/p&gt;

&lt;h5&gt;
  
  
  Inputs
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transaction amount:&lt;/strong&gt; &lt;code&gt;$25.00&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CoF status:&lt;/strong&gt; &lt;code&gt;Not CoF&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Challenge indicator:&lt;/strong&gt; &lt;code&gt;No Preference&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PII present?:&lt;/strong&gt; Unchecked&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable AI model:&lt;/strong&gt; Unchecked&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Expected Outcome
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Outcome:&lt;/strong&gt; &lt;code&gt;Frictionless (Exempted)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exemption/optimization info:&lt;/strong&gt; &lt;code&gt;Low Value Exemption (LVE): Transaction amount is below the low value threshold.&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The simulator's logic checks for the LVE initially. Since the amount is less than or equal to $30 USD, the transaction is immediately classified as frictionless without any further checks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0bkcskscunfejnsasgml.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0bkcskscunfejnsasgml.png" alt="Image of test case 1 with results" width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  CoF Exemption
&lt;/h4&gt;

&lt;p&gt;This scenario shows how a recurring payment from a trusted customer can be exempted from a challenge, even with a higher transaction amount.&lt;/p&gt;

&lt;h5&gt;
  
  
  Inputs
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transaction amount:&lt;/strong&gt; &lt;code&gt;$75.00&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CoF status:&lt;/strong&gt; &lt;code&gt;Merchant Initiated Transaction (MIT)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Challenge indicator:&lt;/strong&gt; &lt;code&gt;No Preference&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PII present?:&lt;/strong&gt; Unchecked&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable AI model:&lt;/strong&gt; Unchecked&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Expected Outcome
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Outcome:&lt;/strong&gt; &lt;code&gt;Frictionless (Exempted)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exemption/optimization info:&lt;/strong&gt; &lt;code&gt;Recurring Payments/MIT Exemption: Transaction is a CoF payment.&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The simulator prioritizes CoF transactions as a valid exemption reason. Even though the amount is above the LVE threshold, the &lt;code&gt;cofStatus&lt;/code&gt; of merchant-initiated signals a recurring payment, which is considered low-risk and therefore frictionless:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv5nck7rpwhiu5yl44m3m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv5nck7rpwhiu5yl44m3m.png" alt="Image of test case 2 with results" width="800" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Challenge Mandated
&lt;/h4&gt;

&lt;p&gt;This demonstrates a scenario where a challenge is unavoidable, regardless of other factors, because it has been explicitly requested.&lt;/p&gt;

&lt;h5&gt;
  
  
  Inputs
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transaction amount:&lt;/strong&gt; &lt;code&gt;$15.00&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CoF status:&lt;/strong&gt; &lt;code&gt;Not CoF&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Challenge indicator:&lt;/strong&gt; &lt;code&gt;Challenge Mandated&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PII present?:&lt;/strong&gt; Checked&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable AI model:&lt;/strong&gt; Unchecked&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Expected Outcome
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Outcome:&lt;/strong&gt; &lt;code&gt;Challenge (Mandated)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exemption/optimization info:&lt;/strong&gt; No message&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;Challenge (Mandated)&lt;/code&gt; indicator acts as an override. It bypasses all exemption logic and forces a challenge, which is useful for transactions deemed high-risk by the merchant or when required by regulations:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2321hwenhfz7vhxzvgt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2321hwenhfz7vhxzvgt.png" alt="Image of test case 3 with results" width="800" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  AI Model Tuning
&lt;/h4&gt;

&lt;p&gt;This test highlights the dynamic nature of the AI model. You have to run this simulation with the AI toggle checked multiple times to see the effect.&lt;/p&gt;

&lt;h5&gt;
  
  
  Inputs
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transaction amount:&lt;/strong&gt; &lt;code&gt;$100.00&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CoF status:&lt;/strong&gt; &lt;code&gt;Not CoF&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Challenge indicator:&lt;/strong&gt; &lt;code&gt;No Preference&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PII present?:&lt;/strong&gt; Checked&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable AI model:&lt;/strong&gt; Checked&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Expected Outcome
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Outcome:&lt;/strong&gt; Over multiple runs, the &lt;code&gt;Frictionless Rate&lt;/code&gt; gradually increases, and the &lt;code&gt;Challenge Rate&lt;/code&gt; and &lt;code&gt;Failure Rate&lt;/code&gt; decrease with each successful frictionless or challenged outcome.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exemption/optimization info:&lt;/strong&gt; If a frictionless outcome occurs without an exemption, the message is &lt;code&gt;AI Model Optimization: Transaction identified as low risk for frictionless flow.&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the AI model enabled, it learns from each transaction outcome by adjusting the underlying success rates:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwatda9m3k49e3f2rsii8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwatda9m3k49e3f2rsii8.png" alt="Image of test case 4 with results" width="800" height="537"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;When implementing 3DS, it's easy to become focused on the enhanced security that additional authentication layers provide, inadvertently overlooking the friction that comes with it. A balance must be struck: merchants who lean too heavily toward either extreme risk, rampant insecurity, and fraud in their payment funnel, or those who suffer from high abandonment rates due to excess customer friction.&lt;/p&gt;

&lt;p&gt;In this article, you learned how to achieve the optimal balance between security and a great user experience. You saw strategies, like 3DS exemptions, challenge indicator parameters, data enrichment in payment requests using PII, and 3DS failure management, and you learned how to harness the power of AI and ML models for 3DS optimization.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>webdev</category>
      <category>programming</category>
      <category>3ds</category>
    </item>
    <item>
      <title>Mastering Dispute Resolution with Mastercard Collaboration</title>
      <dc:creator>mcduffin</dc:creator>
      <pubDate>Tue, 28 Oct 2025 16:44:29 +0000</pubDate>
      <link>https://dev.to/rapyd/mastering-dispute-resolution-with-mastercard-collaboration-5f70</link>
      <guid>https://dev.to/rapyd/mastering-dispute-resolution-with-mastercard-collaboration-5f70</guid>
      <description>&lt;p&gt;By: &lt;strong&gt;Vivek Kumar Maskara&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As a security measure, card issuers allow their users to dispute a transaction in case of fraud, theft, or other legitimate scenarios. When a customer disputes a transaction, you, as the merchant, need to act fast to review the dispute before it escalates into a &lt;a href="https://www.rapyd.net/blog/chargeback-fraud/" rel="noopener noreferrer"&gt;chargeback&lt;/a&gt;, which refers to a forced reversal of funds initiated by the cardholder's bank. If your chargeback ratio rises too high, you could face penalties or even lose your ability to receive card payments altogether.&lt;/p&gt;

&lt;p&gt;Rapid Dispute Resolution (RDR) enables merchants to automate their dispute response with predefined rules that allow instant review and automatic refunds for certain scenarios. &lt;a href="https://www.rapyd.net/" rel="noopener noreferrer"&gt;Rapyd&lt;/a&gt; is an all-in-one payment platform that integrates directly with &lt;a href="https://usa.visa.com/" rel="noopener noreferrer"&gt;Visa&lt;/a&gt; and &lt;a href="https://www.mastercard.us/en-us.html" rel="noopener noreferrer"&gt;Mastercard&lt;/a&gt; acquirers, helping merchants improve their authorization rates and act against chargebacks.&lt;/p&gt;

&lt;p&gt;In this article, you'll learn how to use the &lt;a href="https://www.rapyd.net/developers/" rel="noopener noreferrer"&gt;Rapyd API&lt;/a&gt; to automatically resolve low-value Mastercard transaction disputes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand Dispute Resolution with Mastercard Collaboration
&lt;/h2&gt;

&lt;p&gt;RDR is a fully automated dispute management solution for merchants that was initially championed by Visa in collaboration with &lt;a href="https://www.verifi.com/rapid-dispute-resolution-is-here/" rel="noopener noreferrer"&gt;Verifi&lt;/a&gt;. &lt;a href="https://developer.mastercard.com/mastercom/documentation/getting-started/#collaboration" rel="noopener noreferrer"&gt;Mastercard Collaboration&lt;/a&gt; offers a similar capability for Mastercard-issued cards, enabling merchants to resolve disputes before a chargeback can occur. The following diagram illustrates the dispute resolution flow with Mastercard Collaboration:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F862q341qvniikzgubqmu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F862q341qvniikzgubqmu.png" alt="Dispute resolution with Mastercard Collaboration, courtesy of Vivek Maskara" width="800" height="1068"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Collaboration alerts the merchant as soon as the transaction is disputed, allowing merchants to review the cardholder complaint and issue a refund if needed. If the merchant refunds the transaction, a chargeback is no longer needed, and Mastercard marks the dispute as resolved. If the refund is not processed, the dispute advances to the chargeback step, and the Collaboration process is completed.&lt;/p&gt;

&lt;p&gt;As a merchant receiving payments through multiple payment methods, including Visa and Mastercard, integrating with multiple dispute resolution solutions can be challenging. Rapyd simplifies this by offering direct integration with both Visa and Mastercard, enabling seamless dispute resolution implementation within your application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5wotop2xvtdy3any6c4b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5wotop2xvtdy3any6c4b.png" alt="Mastercard dispute resolution with Rapyd, courtesy of Vivek Maskara" width="800" height="1686"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rapyd lets merchants define automatic refund rules using the Client Portal to determine the conditions under which an automatic refund should be issued. When Rapyd receives a dispute notification from Mastercard Collaboration, it evaluates the merchant-defined rules, and if the criteria are met, it issues an automatic refund without merchant intervention. Otherwise, it notifies the merchant by sending a &lt;code&gt;PAYMENT_DISPUTE_CREATED&lt;/code&gt; &lt;a href="https://docs.rapyd.net/en/dispute-created-webhook.html" rel="noopener noreferrer"&gt;webhook event&lt;/a&gt;, and the merchant can perform additional checks before deciding the outcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implement Mastercard Dispute Resolution with Rapyd
&lt;/h2&gt;

&lt;p&gt;In this tutorial, you'll create an &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express&lt;/a&gt; application that makes a Mastercard card payment request using &lt;a href="https://docs.rapyd.net/en/api-reference.html" rel="noopener noreferrer"&gt;Rapyd APIs&lt;/a&gt; and listens to &lt;a href="https://docs.rapyd.net/en/webhook-format.html" rel="noopener noreferrer"&gt;webhook events&lt;/a&gt; for dispute resolution. By the end of the tutorial, you'll learn how to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make a signed Rapyd API request for payment and disputes.&lt;/li&gt;
&lt;li&gt;Set up a webhook that listens to payment and dispute creation events and lets you take custom actions.&lt;/li&gt;
&lt;li&gt;Send an email to the merchant notifying them about the dispute details.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prepare Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting, you need to complete the following actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sign up for a &lt;a href="https://dashboard.rapyd.net/sign-up/" rel="noopener noreferrer"&gt;Rapyd account&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.rapyd.net/en/set-up-your-account.html" rel="noopener noreferrer"&gt;Set up your Rapyd account&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Install &lt;a href="https://nodejs.org/en/download" rel="noopener noreferrer"&gt;Node.js 18.0 or above&lt;/a&gt; on your development machine.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ngrok.com/docs/getting-started/" rel="noopener noreferrer"&gt;Install and set up ngrok&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tutorial uses &lt;a href="https://github.com/Rapyd-Samples/dispute-resolution-mastercard" rel="noopener noreferrer"&gt;this starter code&lt;/a&gt; from GitHub that has a barebones Node.js app set up. To follow along, clone the GitHub repo and switch to the &lt;code&gt;starter&lt;/code&gt; branch by following these steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Rapyd-Samples/dispute-resolution-mastercard
&lt;span class="nb"&gt;cd &lt;/span&gt;rapyd-payments
git checkout starter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's go over the structure of the codebase:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;package.json&lt;/code&gt; file defines the Express project dependencies and the &lt;code&gt;npm start&lt;/code&gt; script.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;src&lt;/code&gt; directory contains the main source code, including the &lt;code&gt;index.js&lt;/code&gt; entry point, which initializes the Express server by creating a new instance of the &lt;code&gt;App&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;src/services/rapyd.utilities.js&lt;/code&gt; file defines methods to make a signed HTTPS request to Rapyd servers. It defines the &lt;code&gt;makeRequest&lt;/code&gt; method that takes the HTTP &lt;code&gt;method&lt;/code&gt; type, &lt;code&gt;url&lt;/code&gt;, and &lt;code&gt;body&lt;/code&gt; as parameters, and it returns the Rapyd API response to the caller. This method uses the &lt;code&gt;sign&lt;/code&gt; method to sign the payload before making the REST API call. If you want to learn more about the signing process, check out &lt;a href="https://docs.rapyd.net/en/request-signatures.html" rel="noopener noreferrer"&gt;this Rapyd guide&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Set Up Your Rapyd Access Key and Secret Key
&lt;/h3&gt;

&lt;p&gt;Notice that the source contains &lt;code&gt;.env.example&lt;/code&gt;, which is a sample environment file. Rename the file to &lt;code&gt;.env&lt;/code&gt; and replace the values for &lt;code&gt;RAPYD_API_KEY&lt;/code&gt; and &lt;code&gt;RAPYD_SECRET_KEY&lt;/code&gt; with your &lt;a href="https://docs.rapyd.net/en/access-keys.html" rel="noopener noreferrer"&gt;credentials&lt;/a&gt;, which you can access on the Rapyd Client Portal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;RAPYD_API_KEY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;REPLACE_WITH_RAPYD_ACCESS_KEY&amp;gt;&lt;/span&gt;
&lt;span class="py"&gt;RAPYD_SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;REPLACE_WITH_RAPYD_SECRET_KEY&amp;gt;&lt;/span&gt;
&lt;span class="py"&gt;BASERAPYDAPIURL&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;https://sandboxapi.rapyd.net&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Dependencies and Run the App
&lt;/h3&gt;

&lt;p&gt;After familiarizing yourself with the code, install the npm dependencies by executing the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now run the starter code to verify your setup. Execute the following command to run the app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your output looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;App initialized
🚀 Server running on http://localhost:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since the &lt;code&gt;.env&lt;/code&gt; file defines the application port as &lt;code&gt;8000&lt;/code&gt;, the server starts running on this port. You can open a new terminal window and use curl to verify that the default endpoint is accessible by executing the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://localhost:8000/api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your output looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Welcome to the Rapyd Payment API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that the starter code is set up, you can proceed to integrate Rapyd payment and dispute resolution APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrate Rapyd APIs to Receive Payments
&lt;/h2&gt;

&lt;p&gt;This section explains how to integrate Rapyd APIs to receive payments, retrieve dispute status, and issue refunds. For this tutorial, the Node.js application doesn't define strict request schemas and simply relays the request payload to Rapyd. You'll integrate the following Rapyd APIs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;POST v1/payments/&lt;/code&gt;&lt;/strong&gt; to &lt;a href="https://docs.rapyd.net/en/create-payment.html" rel="noopener noreferrer"&gt;create a new card payment&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;GET v1/payments/&lt;/code&gt;&lt;/strong&gt; to &lt;a href="https://docs.rapyd.net/en/retrieve-payment.html" rel="noopener noreferrer"&gt;retrieve details of a payment&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;GET v1/payments/&lt;/code&gt;&lt;/strong&gt; to &lt;a href="https://docs.rapyd.net/en/retrieve-payment.html" rel="noopener noreferrer"&gt;retrieve details of a payment&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;POST v1/refunds&lt;/code&gt;&lt;/strong&gt; to &lt;a href="https://docs.rapyd.net/en/create-refund.html" rel="noopener noreferrer"&gt;create a refund&lt;/a&gt; (Note that this tutorial doesn't directly use the refund endpoint, but the integration details are covered here for completeness.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;GET v1/disputes/{disputeID}&lt;/code&gt;&lt;/strong&gt; to &lt;a href="https://docs.rapyd.net/en/retrieve-dispute.html" rel="noopener noreferrer"&gt;retrieve details of a dispute&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before starting the integration, refer to the linked API docs earlier for details about the request parameters.&lt;/p&gt;

&lt;p&gt;You can utilize the &lt;code&gt;makeRequest&lt;/code&gt; method defined in the starter code to send a signed request to Rapyd servers. To integrate the APIs, update the &lt;code&gt;src/services/rapyd.service.js&lt;/code&gt; file with the following code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;makeRequest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./rapyd.utilities.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RapydService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;createPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paymentData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/v1/payments&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;makeRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;paymentData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getPaymentStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paymentId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`/v1/payments/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;paymentId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;makeRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;refundPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;refundData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/v1/refunds&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;makeRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refundData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getDisputeById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;disputeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`/v1/disputes/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;disputeId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;makeRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;RapydService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The newly defined methods relay the request payload to the &lt;code&gt;makeRequest&lt;/code&gt; method and return the response received from it. Next, you need to update the controller to use the service methods for payment, disputes, and refunds. Update the &lt;code&gt;src/controllers/payment.controller.js&lt;/code&gt; with the following code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;RapydService&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../services/rapyd.service.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;createPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;RapydService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payment&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getPaymentStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;paymentStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;RapydService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPaymentStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;paymentStatus&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;refundPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;refund&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;RapydService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refundPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;refund&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getDisputeById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dispute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;RapydService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDisputeById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dispute&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createPayment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;getPaymentStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;refundPayment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;getDisputeById&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PaymentController&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;PaymentController&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code snippet, every controller method parses the &lt;code&gt;req&lt;/code&gt; object and utilizes the &lt;code&gt;RapydService&lt;/code&gt; methods to define &lt;code&gt;createPayment&lt;/code&gt;, &lt;code&gt;getPaymentStatus&lt;/code&gt;, &lt;code&gt;refundPayment&lt;/code&gt;, and &lt;code&gt;getDisputeById&lt;/code&gt; methods. If the &lt;code&gt;RapydService&lt;/code&gt; throws an error, the controller method catches the error and returns a &lt;code&gt;next(error)&lt;/code&gt; API error response.&lt;/p&gt;

&lt;p&gt;Update the &lt;code&gt;src/routes.js&lt;/code&gt; file to define the new API routes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Add this import statement&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;createPayment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;getPaymentStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;refundPayment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;getDisputeById&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./controllers/payment.controller.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Add payment routes&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/payment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createPayment&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/payment/:id/refund&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refundPayment&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/status/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getPaymentStatus&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/disputes/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getDisputeById&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After these routes are added, the Express application can be used to create card payments and check their status.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test Payment Integration
&lt;/h2&gt;

&lt;p&gt;Now that you've added the payment endpoints in the Node.js application, you can test payments using &lt;a href="https://developer.mastercard.com/mastercard-send/documentation/implementation/sandbox-test-cards/" rel="noopener noreferrer"&gt;Mastercard sandbox cards&lt;/a&gt;. Execute the following curl command that uses one of the sandbox cards to create a payment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="s1"&gt;'http://localhost:8000/api/payment'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--data-raw&lt;/span&gt; &lt;span class="s1"&gt;'{
    "amount": 26.51,
    "currency": "ZAR",
    "merchant_reference_id": "042620221450",
    "payment_method": {
        "type": "gb_mastercard_card",
        "fields": {
            "number": "5102589999999913",
            "expiration_month": "11",
            "expiration_year": "26",
            "cvv": "123",
            "name": "John Doe"
        }
    },
    "ewallets": [
        {
            "ewallet": "&amp;lt;YOUR_RAPYD_EWALLET_ID&amp;gt;",
            "percentage": 100
        }
    ],
    "metadata": {
        "merchant_defined": "created"
    },
    "capture": true,
    "payment_method_options": {
        "3d_required": false
    }
}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to replace &lt;code&gt;&amp;lt;YOUR_RAPYD_EWALLET_ID&amp;gt;&lt;/code&gt; with a &lt;a href="https://docs.rapyd.net/en/rapyd-wallet.html" rel="noopener noreferrer"&gt;Rapyd Wallet ID&lt;/a&gt;. You can create a new wallet or retrieve an existing wallet ID using the &lt;a href="https://dashboard.rapyd.net/ewallets/accounts" rel="noopener noreferrer"&gt;Rapyd Developer Portal&lt;/a&gt;. Refer to the &lt;a href="https://docs.rapyd.net/en/create-payment.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Create Payment&lt;/strong&gt; API reference&lt;/a&gt; to learn more about the request payload.&lt;/p&gt;

&lt;p&gt;After you execute the curl command, you should receive a success response with payment details and status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"statusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"payment_1e8c9b2cf200882954bfe49fa550476c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;26.51&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"original_amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;26.51&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"customer_token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cus_33ea7f84366b2b092a2c210faa5c31b1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"payment_method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also check the payment details using the &lt;a href="https://dashboard.rapyd.net/collect/payments/list" rel="noopener noreferrer"&gt;&lt;strong&gt;Collect &amp;gt; Payments&lt;/strong&gt; page&lt;/a&gt; on the Rapyd Client Portal. Similarly, you can test other API endpoints by grabbing sample payloads from the &lt;a href="https://docs.rapyd.net/en/api-reference.html" rel="noopener noreferrer"&gt;API docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up a Webhook to Notify the Merchant About Disputes
&lt;/h2&gt;

&lt;p&gt;Now that you have the payment integration set up, you can create a &lt;a href="https://docs.rapyd.net/en/webhooks.html" rel="noopener noreferrer"&gt;webhook&lt;/a&gt; to listen to Rapyd payment and dispute events, and send an email with dispute details to the merchant.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure Email Service
&lt;/h3&gt;

&lt;p&gt;In this tutorial, you'll learn how to send emails using &lt;a href="https://nodemailer.com/" rel="noopener noreferrer"&gt;Nodemailer&lt;/a&gt;, but in a real-world application, you can perform other custom actions upon receiving a webhook event.&lt;/p&gt;

&lt;p&gt;To start, install the &lt;code&gt;nodemailer&lt;/code&gt; npm package by executing the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;nodemailer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command installs the package and updates &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;package-lock.json&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;Next, create a &lt;code&gt;services/email.service.js&lt;/code&gt; file and add the following code snippet to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;nodemailer&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nodemailer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;emailConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;merchantEmail&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../config.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transporter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nodemailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTransport&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;emailConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;emailConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;emailConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pass&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;sendDisputeNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;disputeData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;original_dispute_amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;original_transaction_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currency&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;disputeData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emailContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
        Payment Dispute Alert

        Dispute Details:
        - Dispute ID: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
        - Original Transaction ID: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;original_transaction_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
        - Dispute Amount: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;original_dispute_amount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currency&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
        - Date: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;

        Action Required:
        A dispute has been created for one of your transactions. Please review the dispute details and take appropriate action.

        This is an automated notification for demonstration purposes.`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mailOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;emailConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;merchantEmail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Payment Dispute Created - &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;emailContent&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transporter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mailOptions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dispute notification email sent:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;messageId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageId&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error sending dispute notification email:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EmailService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code creates a new &lt;a href="https://nodemailer.com/smtp/envelope#complete-example" rel="noopener noreferrer"&gt;mail transport&lt;/a&gt; by calling the &lt;code&gt;createTransport&lt;/code&gt; method in the service constructor. This transport is used to deliver an email over SMTP.&lt;/p&gt;

&lt;p&gt;This code also defines a &lt;code&gt;sendDisputeNotification&lt;/code&gt; method that takes &lt;code&gt;disputeData&lt;/code&gt; as input, constructs the email &lt;code&gt;body&lt;/code&gt; and &lt;code&gt;subject&lt;/code&gt;, and calls the &lt;code&gt;sendMail&lt;/code&gt; to send an email to the merchant.&lt;/p&gt;

&lt;p&gt;Note that the email service requires an &lt;code&gt;emailConfig&lt;/code&gt; to be defined with sender and receiver email details. Add the following details in the &lt;code&gt;config.js&lt;/code&gt; file to configure the email details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emailConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EMAIL_SERVICE&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gmail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EMAIL_USER&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EMAIL_PASS&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;merchantEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MERCHANT_EMAIL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following environment variables to the &lt;code&gt;.env&lt;/code&gt; file to configure the email service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EMAIL_SERVICE=gmail
EMAIL_USER=your_email@gmail.com
EMAIL_PASS=your_email_password_here
MERCHANT_EMAIL=merchant@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that if you're using Gmail, you need to &lt;a href="https://nodemailer.com/usage/using-gmail" rel="noopener noreferrer"&gt;configure OAuth 2.0 or generate an app password&lt;/a&gt;. This tutorial uses Gmail, but you can &lt;a href="https://nodemailer.com/transports" rel="noopener noreferrer"&gt;refer to the Nodemailer docs&lt;/a&gt; if you need to configure a custom SMTP transport.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handle the Dispute Webhook
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;PAYMENT_DISPUTE_CREATED&lt;/code&gt; &lt;a href="https://docs.rapyd.net/en/dispute-created-webhook.html" rel="noopener noreferrer"&gt;webhook event&lt;/a&gt; contains information about the dispute, payment, and payment method. For example, you can retrieve the &lt;code&gt;original_transaction_id&lt;/code&gt; to fetch transaction details.&lt;/p&gt;

&lt;p&gt;Add the &lt;code&gt;handleDisputeCreated&lt;/code&gt; method in the &lt;code&gt;controllers/webhook.controller.js&lt;/code&gt; file as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// add import&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;EmailService&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../services/email.service.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleDisputeCreated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;disputeData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;disputeData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Dispute ID: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;EmailService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendDisputeNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;disputeData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Email notification sent for dispute: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error handling dispute:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The method calls the &lt;code&gt;EmailService.sendDisputeNotification&lt;/code&gt; method with the &lt;code&gt;disputeData&lt;/code&gt; to notify the merchant about the dispute.&lt;/p&gt;

&lt;p&gt;Next, update the &lt;code&gt;handleWebhook&lt;/code&gt; method to call the dispute handler like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleWebhook&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PAYMENT_DISPUTE_CREATED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Payment dispute created:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nf"&gt;handleDisputeCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that the webhook is configured to send emails automatically, you can proceed to test the integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test Automatic Dispute Resolution for Mastercard Transactions
&lt;/h2&gt;

&lt;p&gt;Before testing the integration, you need to register the webhook endpoint on the Rapyd Client Portal to receive dispute events.&lt;/p&gt;

&lt;h3&gt;
  
  
  Register the Webhook
&lt;/h3&gt;

&lt;p&gt;You need to expose Express on a public URL so that Rapyd can send webhook events to it. You can use &lt;a href="https://ngrok.com/docs/getting-started/" rel="noopener noreferrer"&gt;ngrok&lt;/a&gt; to expose your web server as a public URL by executing the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ngrok http http://localhost:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you execute the command, it creates a public proxy, and your output looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ngrok
...
Session Status                online
---OUTPUT TRUNCATED---
Forwarding                    https://3939-2601-602-9700-5c30-b883-8d8b-8def-708b.ngrok-free.app -&amp;gt; http://localhost:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the forwarding URL and navigate to the Rapyd Client Portal to register it. Under &lt;strong&gt;Developers &amp;gt; Webhooks &amp;gt; Management&lt;/strong&gt;, click &lt;strong&gt;Edit URL&lt;/strong&gt; and update the endpoint to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://&amp;lt;YOUR_FORWARDING_HOST_NAME&amp;gt;/api/webhook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;&amp;lt;YOUR_FORWARDING_HOST_NAME&amp;gt;&lt;/code&gt; with the forwarding URL's hostname. Make sure you save the changes for it to take effect:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F881naqa9q1z17ghzy833.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F881naqa9q1z17ghzy833.png" alt="Register webhook" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure that under &lt;strong&gt;Collect&lt;/strong&gt;, the &lt;strong&gt;Dispute Created&lt;/strong&gt; webhook event is checked to ensure that your web server receives it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test Automatic Dispute Resolution
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://docs.rapyd.net/en/simulating-cardholder-disputes.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Simulating Cardholder Disputes&lt;/strong&gt;&lt;/a&gt; guide lists a few card numbers that you can use to simulate a card payment dispute. When one of these cards is used to create a payment, Rapyd simulates a dispute flow by automatically creating a dispute for the completed payment.&lt;/p&gt;

&lt;p&gt;To simulate a transaction dispute with a &lt;a href="https://docs.rapyd.net/en/mastercard.html" rel="noopener noreferrer"&gt;Mastercard card&lt;/a&gt;, execute the following curl command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="s1"&gt;'https://&amp;lt;YOUR_FORWARDING_HOST_NAME&amp;gt;/api/payment'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--data-raw&lt;/span&gt; &lt;span class="s1"&gt;'{
    "amount": 26.51,
    "currency": "ZAR",
    "merchant_reference_id": "042620221450",
    "payment_method": {
        "type": "gb_mastercard_card",
        "fields": {
            "number": "5132803130357186",
            "expiration_month": "11",
            "expiration_year": "26",
            "cvv": "123",
            "name": "John Doe"
        }
    },
    "ewallets": [
        {
            "ewallet": "&amp;lt;YOUR_RAPYD_EWALLET_ID&amp;gt;",
            "percentage": 100
        }
    ],
    "metadata": {
        "merchant_defined": "created"
    },
    "capture": true,
    "payment_method_options": {
        "3d_required": false
    }
}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;&amp;lt;YOUR_FORWARDING_HOST_NAME&amp;gt;&lt;/code&gt; with the ngrok hostname and &lt;code&gt;&amp;lt;YOUR_RAPYD_EWALLET_ID&amp;gt;&lt;/code&gt; with your Rapyd wallet ID before executing the curl command. Once you execute the command, a payment is created, and within seconds, you'll receive a payment dispute webhook event for it. The dispute details are logged by the web server and look similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="err"&gt;d&lt;/span&gt;&lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="err"&gt;f&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="err"&gt;ca&lt;/span&gt;&lt;span class="mi"&gt;-0e7&lt;/span&gt;&lt;span class="err"&gt;d&lt;/span&gt;&lt;span class="mi"&gt;-4&lt;/span&gt;&lt;span class="err"&gt;c&lt;/span&gt;&lt;span class="mi"&gt;27-8476-2&lt;/span&gt;&lt;span class="err"&gt;d&lt;/span&gt;&lt;span class="mi"&gt;3309e465&lt;/span&gt;&lt;span class="err"&gt;b&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'dispute_&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="err"&gt;b&lt;/span&gt;&lt;span class="mi"&gt;36175&lt;/span&gt;&lt;span class="err"&gt;b&lt;/span&gt;&lt;span class="mi"&gt;2121&lt;/span&gt;&lt;span class="err"&gt;c&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="err"&gt;f&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="err"&gt;dffa&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="err"&gt;b&lt;/span&gt;&lt;span class="mi"&gt;624&lt;/span&gt;&lt;span class="err"&gt;eb&lt;/span&gt;&lt;span class="mi"&gt;73&lt;/span&gt;&lt;span class="err"&gt;b&lt;/span&gt;&lt;span class="mi"&gt;49&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'ACT'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;26.51&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'ZAR'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dispute_category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'Cardholder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Dispute'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dispute_reason_description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'Cardholder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Dispute'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"original_transaction_currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'ZAR'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"original_transaction_amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;26.51&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"original_dispute_amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;26.51&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"original_dispute_currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'ZAR'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"original_transaction_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'payment_e&lt;/span&gt;&lt;span class="mi"&gt;5e014&lt;/span&gt;&lt;span class="err"&gt;d&lt;/span&gt;&lt;span class="mi"&gt;419632&lt;/span&gt;&lt;span class="err"&gt;d&lt;/span&gt;&lt;span class="mi"&gt;428023&lt;/span&gt;&lt;span class="err"&gt;fcd&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="err"&gt;c&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="err"&gt;c&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="err"&gt;af&lt;/span&gt;&lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because you configured the &lt;code&gt;handleDisputeCreated&lt;/code&gt; method for &lt;strong&gt;Dispute Created&lt;/strong&gt; events, it sends an email and logs the following to the console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dispute notification email sent: 250 2.0.0 OK  1751833493 d9443c01a7336-23c8455d09esm68323335ad.90 - gsmtp
Email notification sent for dispute: dispute_e9388a0a90c7366a96541f6b759c7de4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The configured &lt;code&gt;MERCHANT_EMAIL&lt;/code&gt; receives an email as shown here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff54waxi7c057gvxohg7t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff54waxi7c057gvxohg7t.png" alt="Email notification when a dispute is created" width="800" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also review the dispute details using the &lt;strong&gt;Collect &amp;gt; Review &amp;amp; Protect &amp;gt; Disputes&lt;/strong&gt; tabs on the &lt;a href="https://dashboard.rapyd.net/collect/payments/disputes" rel="noopener noreferrer"&gt;Rapyd Client Portal&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1p627xrkixvn0aqwd2s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1p627xrkixvn0aqwd2s.png" alt="Review disputes using the Rapyd Client Portal" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Client Portal lets you update the status of the dispute, submit evidence, or refund a dispute.&lt;/p&gt;

&lt;p&gt;You can find the entire &lt;a href="https://github.com/Rapyd-Samples/dispute-resolution-mastercard" rel="noopener noreferrer"&gt;source code&lt;/a&gt; used in this tutorial on GitHub.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Merchants need to proactively review and resolve card disputes to avoid chargebacks and revenue loss. They can leverage automatic dispute resolution tools like RDR and &lt;a href="https://developer.mastercard.com/mastercom/documentation/getting-started/" rel="noopener noreferrer"&gt;Mastercard Collaboration&lt;/a&gt; to configure rules that instantly evaluate dispute requests and issue automatic refunds if the criteria are met.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.rapyd.net/" rel="noopener noreferrer"&gt;Rapyd&lt;/a&gt; enables businesses to automate dispute resolution by offering direct integration with Visa and Mastercard Collaboration programs, industry-leading authorization rates, and a robust all-in-one payment platform.&lt;/p&gt;

&lt;p&gt;Try the &lt;a href="https://docs.rapyd.net/en/api-reference.html" rel="noopener noreferrer"&gt;Rapyd API&lt;/a&gt; and explore the &lt;a href="https://github.com/Rapyd-Samples/dispute-resolution-mastercard" rel="noopener noreferrer"&gt;code sample&lt;/a&gt; to see how Rapyd offers you the best in dispute resolution.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>webdev</category>
      <category>programming</category>
      <category>disputes</category>
    </item>
    <item>
      <title>Client Portal: Stablecoin Payouts</title>
      <dc:creator>mcduffin</dc:creator>
      <pubDate>Thu, 16 Oct 2025 21:32:05 +0000</pubDate>
      <link>https://dev.to/rapyd/client-portal-stablecoin-payouts-2pbk</link>
      <guid>https://dev.to/rapyd/client-portal-stablecoin-payouts-2pbk</guid>
      <description>&lt;p&gt;Stablecoin payouts are the next evolution of the financial world: using cryptocurrency to make cross border transactions, using a digital, decentralized currency that allows you true financial freedom. By signing up for a Client Portal account, you can integrate with Rapyd today and begin using stablecoin payouts. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is Stablecoin?
&lt;/h2&gt;

&lt;p&gt;Stablecoin is a specific type of cryptocurrency that functions slightly differently than most cryptocurrencies. Most crypto derives their entire value from a form of digital scarcity. A limited number of the cryptocurrency is released and the users have to “mine” for this cryptocurrency by using algorithms to “search” for the cryptocurrency. When the crypto is found and verified, the user gets to keep the cryptocurrency. The most recognizable cryptocurrency that uses this model is Bitcoin. &lt;/p&gt;

&lt;p&gt;An issue with cryptocurrency is its volatility. Although crypto can and does hold value, the value does not remain stable over time, but fluctuates wildly. This is partly due to cryptocurrency exchanges, and how the users treat crypto like an asset instead of a currency. When crypto is traded like an asset, it is bought and sold based on its perceived value. When crypto is treated like a currency, it is used to purchase everyday goods and services. &lt;/p&gt;

&lt;p&gt;But Stablecoin is different. Although it uses the blockchain to verify transactions like all cryptocurrency, its value is pegged to both gold and fiat currency. This allows stablecoin to be “stable” and not experience sudden fluctuations in its value. This stability makes it favorable to be used as a currency in transactions such as payments and payouts. Rapyd now offers stablecoin payouts, allowing you to pay others using cryptocurrency.   &lt;/p&gt;

&lt;h2&gt;
  
  
  Stablecoin Payout Features
&lt;/h2&gt;

&lt;p&gt;When logging into the Client Portal, you can navigate to Disburse &amp;gt; Payouts and click the Create Payout button in the upper right corner. From there, you can create a payout, selecting UDSC as the payout currency. &lt;/p&gt;

&lt;p&gt;When creating a payout, you can select the crypto account that has the stablecoin. And then define the beneficiary that will receive the payout. Fiat currency can also be converted to stablecoin when making the payout. The beneficiary can either be an individual or a company. You also need to agree to the provided Terms and Conditions before completing the crypto payout. &lt;/p&gt;

&lt;p&gt;See &lt;a href="https://docs.rapyd.net/en/creating-a-crypto-payout.html" rel="noopener noreferrer"&gt;Creating a Crypto Payout&lt;/a&gt; for more detailed information.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Rapyd and Using Stablecoin
&lt;/h2&gt;

&lt;p&gt;Rapyd now offers stablecoin payouts through the Client Portal, and through the Rapyd API using the &lt;a href="https://docs.rapyd.net/en/create-payout.html" rel="noopener noreferrer"&gt;Create Payout&lt;/a&gt; endpoint. See &lt;a href="https://docs.rapyd.net/en/stablecoin-payout.html" rel="noopener noreferrer"&gt;Stablecoin Payout&lt;/a&gt; for more detailed information about how to complete a stablecoin payout using the API. Using stablecoins is useful because it gives you another financial tool that you can use. Both USDC and USDT are offered as payout currencies, and are now supported currencies. &lt;/p&gt;

&lt;p&gt;Fintech and stablecoin blend together perfectly because both represent moving outside of the traditional financial establishment and represent the efforts to try and create a better path for all parties involved. &lt;/p&gt;

&lt;p&gt;When using the Rapyd Client Portal, you can have a chance to enter the cryptocurrency world using a no-code solution. The process of using stablecoin is simplified. Rapyd provides the best available options to broaden your financial horizons.&lt;/p&gt;

</description>
      <category>fintech</category>
      <category>cryptocurrency</category>
      <category>stablecoin</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Client Portal: The No-Code Solution to Your Financial Needs</title>
      <dc:creator>mcduffin</dc:creator>
      <pubDate>Thu, 02 Oct 2025 18:46:43 +0000</pubDate>
      <link>https://dev.to/rapyd/client-portal-the-no-code-solution-to-your-financial-needs-mmm</link>
      <guid>https://dev.to/rapyd/client-portal-the-no-code-solution-to-your-financial-needs-mmm</guid>
      <description>&lt;p&gt;The Rapyd Client Portal is a self-service product that allows developers and merchants to manage the financial information and services that Rapyd provides. Users can quickly view the information they need, generate a useful report, or create a payment. The Client Portal turns complex financial operations into simple tasks. &lt;/p&gt;

&lt;h2&gt;
  
  
  No-Code Solutions
&lt;/h2&gt;

&lt;p&gt;Rapyd offers a no-code solution to our customers through the Client Portal. The portal is a point-and-click interface with various fields where important information can be entered. Files can be uploaded and downloaded. The Client Portal is a key component for merchants who wish to integrate with Rapyd. The KYB or Know Your Business Form is a required form used to verify a new business working with Rapyd. This form can be completed from the Client Portal. &lt;/p&gt;

&lt;p&gt;For developers that wish to integrate with Rapyd via code, they can use the Rapyd API. But the Client Portal is also important to these developers. Your API access key and secret key are securely stored in your Client Portal account, and are needed to make calls via the Rapyd API. &lt;/p&gt;

&lt;h2&gt;
  
  
  Client Portal Features
&lt;/h2&gt;

&lt;p&gt;The Client Portal has a wide range of features that allows users to interact with Rapyd’s core product offerings: Collect, Disburse, Issuing, and Rapyd Wallets. The first set of features center around viewing financial information. For example, users can view their payments, payouts, or a list of issued cards. Each line item in those lists can be expanded to provide additional details and financial information. The second set of features center around performing financial operations. This can include creating a payment, creating a payment link, creating a payout, creating a beneficiary, issuing a card, or creating a Rapyd Wallet. The third set of features center around file downloads, file uploads, and generating financial reports. &lt;/p&gt;

&lt;p&gt;Developers can manage their API Keys, whitelist IP addresses, and manage their webhooks in the sandbox environment under the &lt;strong&gt;Developers&lt;/strong&gt; section of the Client Portal. Users can also rotate their API keys as an added security measure. Other tools are available to use via the Client Portal such as Rapyd Protect. You can use machine learning to flag and block fraudulent transactions. &lt;/p&gt;

&lt;h2&gt;
  
  
  How Rapyd Can Help You
&lt;/h2&gt;

&lt;p&gt;The Rapyd Client Portal can meet your financial needs because it simplifies the complex. It allows the user to quickly find needed financial information, and streamline tasks like initiating a cross-border payout. The portal provides a central place for all of your financial information, and allows you to manage linked accounts, card disputes, and generate hosted pages to name a few examples. The accurate financial reports allow you to plan for a successful financial future and identify patterns that can be used to boost your business performance. Even repetitive tasks like managing subscriptions become easy when you use the Client Portal. You can create an account &lt;a href="https://dashboard.rapyd.net/sign-up" rel="noopener noreferrer"&gt;here&lt;/a&gt; and begin by experimenting in the sandbox environment. The Client Portal represents an opportunity to create a better financial future.&lt;/p&gt;

</description>
      <category>fintech</category>
      <category>nocode</category>
      <category>tutorial</category>
      <category>finance</category>
    </item>
    <item>
      <title>Fintech and SWIFT: How Fintech and Traditional Finance Work Together</title>
      <dc:creator>mcduffin</dc:creator>
      <pubDate>Fri, 19 Sep 2025 15:43:59 +0000</pubDate>
      <link>https://dev.to/rapyd/fintech-and-swift-how-fintech-and-traditional-finance-work-together-3jk</link>
      <guid>https://dev.to/rapyd/fintech-and-swift-how-fintech-and-traditional-finance-work-together-3jk</guid>
      <description>&lt;p&gt;SWIFT is a facet of the traditional financial system, facilitating international payments and payouts. The SWIFT network is most often used by a wide range of organizations, from large banks and corporations to small businesses. &lt;/p&gt;

&lt;p&gt;Fintech is a newer addition to the financial world. Fintech companies often build their own financial network that provide similar services. This is an effort to help reduce the red tape involved and improve the settlement times for transactions. &lt;/p&gt;

&lt;p&gt;But sometimes, these two different systems need to work together to take advantage of their strengths. The traditional financial systems usually have a farther reach, and have a larger number of users. Fintech companies have unique product offerings that are tailored to their customer base, and are often more lean and efficient when compared to traditional finance. &lt;/p&gt;

&lt;p&gt;When fintech networks integrate with the larger traditional financial system, it can allow a wider base of customers to create payments and payouts that have the widest reach and the fastest settlements with the least amount of compliance issues. The two types of financial networks can work together to form a greater whole.  &lt;/p&gt;

&lt;h2&gt;
  
  
  What is SWIFT?
&lt;/h2&gt;

&lt;p&gt;SWIFT or the Society for Worldwide Interbank Financial Telecommunication is an important element of the traditional financial system. SWIFT is a network of financial institutions that facilitate cross-border payments and disbursements. It is the main system used for international payments and payouts between countries.&lt;/p&gt;

&lt;p&gt;An important data standard, called ISO 20022, is used to standardize financial information that is used for a transaction. This enables a uniform system that can be used by financial institutions across the globe. Another important element of the SWIFT system is the BIC SWIFT code. The BIC (Business Identifier Code) is used to identify financial institutions and businesses when making a transaction. Including the BIC in the payment or payout request ensures that the transaction is routed to the correct beneficiary bank or beneficiary business.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Rapyd and SWIFT
&lt;/h2&gt;

&lt;p&gt;Rapyd offers a payout method type through SWIFT using the Rapyd API. You can call the Rapyd API to use the &lt;code&gt;xx_swift_bank&lt;/code&gt; payout method and create a cross-border payout using SWIFT. &lt;/p&gt;

&lt;p&gt;The user documentation for &lt;a href="https://docs.rapyd.net/en/swift-payout.html" rel="noopener noreferrer"&gt;SWIFT payouts&lt;/a&gt; includes information about regex, workflows, supported sender currencies, and required fields by country that are needed to create a SWIFT payout. Examples of a SWIFT payout are included. Additional information about purpose codes are included. Purpose codes are required for specific countries.    &lt;/p&gt;

&lt;h2&gt;
  
  
  Fintech and Traditional Finance Working Together
&lt;/h2&gt;

&lt;p&gt;Fintech and traditional finance are like two sides of the same coin. Both systems share some similarities and differences. When fintech becomes integrated with traditional financial systems, this allows you to experience the greatest benefits by having increased options, decreased settlements times, and a secure, reliable way to disburse funds across the globe. When fintech services become integrated with traditional financial services, a unified financial network is created that can best meet your financial needs. &lt;/p&gt;

</description>
      <category>fintech</category>
      <category>payments</category>
      <category>tutorial</category>
      <category>finance</category>
    </item>
    <item>
      <title>The Rapyd Partnership Program: What Rapyd Brings to Partners</title>
      <dc:creator>mcduffin</dc:creator>
      <pubDate>Fri, 12 Sep 2025 20:50:21 +0000</pubDate>
      <link>https://dev.to/rapyd/the-rapyd-partnership-program-what-rapyd-brings-to-partners-4800</link>
      <guid>https://dev.to/rapyd/the-rapyd-partnership-program-what-rapyd-brings-to-partners-4800</guid>
      <description>&lt;p&gt;Rapyd offers a unique opportunity through the Partnership Program. In this program, partners can work with Rapyd and gain access to the Rapyd API, the Partner Portal and other features aimed to smooth their operational flows, enable better tracking of merchants and transactions, and a system to manage their financial information with ease. &lt;/p&gt;

&lt;p&gt;Rapyd stands apart from the competition by providing an experience that is tailored to partners. For example, Rapyd provides a faster onboarding experience for partners. The &lt;a href="https://docs.rapyd.net/en/partner-api-reference.html" rel="noopener noreferrer"&gt;Partner API Reference&lt;/a&gt; documents how partners can manage their KYB applications via the API. Partners can view account information such as offerings and organizations by making an API call. &lt;/p&gt;

&lt;p&gt;Rapyd provides the Partner Portal, a self service option that allows partners to: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Add and invite merchants&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create custom pricing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Manage sign-up links for your merchants&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Rapyd Partnership Program
&lt;/h2&gt;

&lt;p&gt;The Rapyd Partnership Program serves three different partner types: Independent Sales Organizations (ISOs), Payment Facilitators (PayFacs) and Referral Partners. &lt;/p&gt;

&lt;p&gt;A partner can sign an agreement with Rapyd, and then begin the integration and onboarding process. Rapyd is an ideal solution for partners. We can provide the services and financial infrastructure that partners need.  &lt;/p&gt;

&lt;p&gt;Rapyd provides extensive support to each partner that works with Rapyd. Our support teams ensure that each partner has a smooth experience and quick resolution times to any problems that could arise.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Partnership Types
&lt;/h2&gt;

&lt;p&gt;Here is some additional information about each partner type:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Independent Sales Organization&lt;/strong&gt; - An Independent Sales Organization (ISO) helps to contract and manage payment services for their merchants. ISOs directly interact with payment service providers like Rapyd to help manage the financial needs of their merchants.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Payment Facilitator&lt;/strong&gt; - Payment Facilitators (PayFacs) help to facilitate payments for their merchants. They provide a specific range of services. PayFacs partner with payment service providers like Rapyd to contract and settle on behalf of their merchants.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Referral Partner&lt;/strong&gt; - Referral partners are payment experts who refer merchants to a payment service provider, like Rapyd. Each merchant adheres to the agreement with the payment service provider, so the Referral Partner doesn’t need to manage the merchants directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Rapyd Brings to Partners
&lt;/h2&gt;

&lt;p&gt;Join the Rapyd Certified Partner Program and reap the benefits of our partnership expertise. Rapyd supports Independent Sales Organization (ISO), Payment Facilitator (PayFac) and Referral Partners.&lt;/p&gt;

&lt;p&gt;Rapyd provides an array of support and benefits for partners that only get better as their business with Rapyd grows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ISOs and Referral Partners&lt;/strong&gt; can utilize the Rapyd API and the Partner Portal. The Partner Portal is a self-service option that enables the partner to manage their merchants, signup links, and pricing. Partners can easily onboard merchants and link them to their account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PayFacs&lt;/strong&gt; are supported via the Rapyd API. They can create card payments, APM payments, and create payouts with Rapyd.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The Rapyd Certified Partner Program is an excellent opportunity for partners to integrate with Rapyd. Rapyd provides the best solution for partners, including support via the Partner Portal and the Rapyd API. &lt;/p&gt;

&lt;p&gt;Rapyd helps partners to manage their merchants, track financial information, and offer custom pricing structures, in addition to signup links. Such features are financial tools that partners can use to build a better financial future.&lt;/p&gt;

</description>
      <category>iso</category>
      <category>payfac</category>
      <category>fintech</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Multi-Currency Payment Systems: Using Rapyd’s Global Payment APIs</title>
      <dc:creator>mcduffin</dc:creator>
      <pubDate>Fri, 12 Sep 2025 20:34:53 +0000</pubDate>
      <link>https://dev.to/rapyd/multi-currency-payment-systems-using-rapyds-global-payment-apis-al9</link>
      <guid>https://dev.to/rapyd/multi-currency-payment-systems-using-rapyds-global-payment-apis-al9</guid>
      <description>&lt;p&gt;A UK-based SaaS company wants to pay its freelance designer in Brazil. They invoice in GBP, but she wants BRL in her account. Here’s how Rapyd makes that happen in seconds, not weeks.&lt;/p&gt;

&lt;p&gt;Multi-currency payment systems are crucial for creating cross-border solutions and integrating into a globalized financial network. Creating payments where funds are collected, or creating payouts where funds are disbursed is a staple feature of Rapyd’s core offering. The ability to use multiple currencies through FX or Foreign Exchange allows merchants across the globe to use a solution that meets their financial needs. &lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Multi-Curency Payment Systems?
&lt;/h2&gt;

&lt;p&gt;A multi-currency payment system is a network comprising several elements including payment processors, payment gateways, forex exchanges, payment service providers, and banks. All of these elements form a network to facilitate payments that use multiple different currencies. &lt;/p&gt;

&lt;p&gt;The key features of a multi-currency payment system include the ability to use different currencies in the same payment or payout. For example, a merchant could create a payout and select USD as the sender currency. But their employee lives in France, and would like to be paid in EUR. So the beneficiary currency would be EUR, and the funds would be converted into EUR via FX or Foreign Exchange. &lt;/p&gt;

&lt;p&gt;Payment systems that allow multiple currencies to be used allow a truly globalized system to form. The benefits of using multiple currencies include customers using their local currency, ease of use for cross-border transactions, and using payment and payout methods that are faster and more efficient. &lt;/p&gt;

&lt;h2&gt;
  
  
  Foreign Exchange (FX) in Fintech
&lt;/h2&gt;

&lt;p&gt;Foreign exchange (FX) is the act of converting one currency to another during a transaction. A payment gateway is used in the conversion process. The latest currency conversions and rates are used. &lt;/p&gt;

&lt;p&gt;The fintech industry has helped to revolutionize FX by offering real-time transactions that use different currencies. The overall process has less red tape, and is easier to use when compared to using a more traditional bank or financial institution. &lt;/p&gt;

&lt;p&gt;The ability to make settlements using your preferred currency is beneficial, especially when using local bank accounts and banking institutions. &lt;/p&gt;

&lt;h2&gt;
  
  
  Global Payment APIs
&lt;/h2&gt;

&lt;p&gt;Rapyd offers a flexible and easy to use solution through our global payment APIs. The two main API calls used are &lt;a href="https://docs.rapyd.net/en/create-payment.html" rel="noopener noreferrer"&gt;Create Payment&lt;/a&gt; and &lt;a href="https://docs.rapyd.net/en/create-payout.html" rel="noopener noreferrer"&gt;Create Payout&lt;/a&gt;. Creating payments is under the Collect product offering, while creating payouts is under the Disburse product offering. &lt;/p&gt;

&lt;p&gt;Additional elements include a variety of &lt;a href="https://docs.rapyd.net/en/payment-method-types.html" rel="noopener noreferrer"&gt;payment method types&lt;/a&gt;, &lt;a href="https://docs.rapyd.net/en/payout-method-types.html" rel="noopener noreferrer"&gt;payout method types&lt;/a&gt;, and &lt;a href="https://docs.rapyd.net/en/supported-currencies.html" rel="noopener noreferrer"&gt;supported currencies&lt;/a&gt;. Rapyd offers a wide variety of supported currencies for payments, payouts, settlements, and virtual accounts. &lt;/p&gt;

&lt;p&gt;For example, your business based in Europe sells merchandise on your online store. A customer from the United States wants to purchase a product from you that costs 370 EUR (Euros). But the customer uses a payment method that only supports USD (U.S. Dollars). You would &lt;a href="https://docs.rapyd.net/en/payment-with-fx.html" rel="noopener noreferrer"&gt;Create a Payment with FX&lt;/a&gt; using the Rapyd API.&lt;/p&gt;

&lt;p&gt;You can use hundreds of different payment method types with Rapyd, which include ewallets, bank transfers, bank redirects, cash payments, and card payments. Supported regions include the Americas, APAC, and EMEA. You can use your preferred payment method types with the Rapyd API. &lt;/p&gt;

&lt;p&gt;Multi-currency payment systems are a key component of globalized financial networks. They allow the merchant to use multiple different currencies for both payments and payouts. This kind of system can offer the flexibility and ease of use for merchants that operate on a global scale and need cross-border financial solutions. Rapyd is a leader in providing multi-currency payment systems accessible through the Rapyd API. Learn &lt;a href="https://docs.rapyd.net/en/index-en.html" rel="noopener noreferrer"&gt;more&lt;/a&gt; about Rapyd and integrate with us today. Leave a comment below about your experience using our APIs. &lt;/p&gt;

</description>
      <category>api</category>
      <category>fintech</category>
      <category>multicurrency</category>
      <category>payments</category>
    </item>
    <item>
      <title>🗞️ Rapyd Developer Newsletter: April 2025 💥 One-Click Checkout, Global Payouts, and What’s New for Devs</title>
      <dc:creator>mcduffin</dc:creator>
      <pubDate>Sat, 19 Apr 2025 19:11:43 +0000</pubDate>
      <link>https://dev.to/rapyd/rapyd-developer-newsletter-april-2025-one-click-checkout-global-payouts-and-whats-new-for-1073</link>
      <guid>https://dev.to/rapyd/rapyd-developer-newsletter-april-2025-one-click-checkout-global-payouts-and-whats-new-for-1073</guid>
      <description>&lt;p&gt;💾 &lt;strong&gt;Essential Updates&lt;/strong&gt; &lt;br&gt;
Be code-ready – our updated &lt;a href="https://docs.rapyd.net/en/api-changelog.html" rel="noopener noreferrer"&gt;&lt;strong&gt;API&lt;/strong&gt;&lt;/a&gt; and &lt;a href="https://docs.rapyd.net/en/product-changelog.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Product&lt;/strong&gt;&lt;/a&gt; changelogs are your go-to for changes impacting your work.&lt;/p&gt;

&lt;p&gt;🤝 &lt;a href="https://community.rapyd.net/t/partner-models-for-payments-how-rapyd-powers-partner-payment-solutions/59737/1" rel="noopener noreferrer"&gt;&lt;strong&gt;Partner Models for Payments: How Rapyd Powers Partner Payment Solutions&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
Discover how to build flexible payment systems with Rapyd’s partner model, ideal for platforms scaling globally.&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://community.rapyd.net/t/payment-links-a-one-click-solution/59735" rel="noopener noreferrer"&gt;&lt;strong&gt;Payment Links: A One-Click Solution&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
Simplify checkout with one-click payment links. Fast to implement, easy for your customers.&lt;/p&gt;

&lt;p&gt;🛡️ &lt;a href="https://community.rapyd.net/t/navigating-regulatory-compliance-in-api-development/59738" rel="noopener noreferrer"&gt;&lt;strong&gt;Navigating Regulatory Compliance in API Development&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
Ensure your APIs are compliant with GDPR, PSD2, and global regulations. Get the tools and tips for secure, audit-ready development.&lt;/p&gt;

&lt;p&gt;📱 &lt;a href="https://docs.rapyd.net/en/using-rapyd-dashboard.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Rapyd Dashboard App&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
View your settlements and payments from your iOS device. The Rapyd Dashboard App is available to CNP merchants in Europe, UK, and Israel.&lt;/p&gt;

&lt;p&gt;🌍 &lt;a href="https://docs.rapyd.net/en/swift-payout.html" rel="noopener noreferrer"&gt;&lt;strong&gt;SWIFT Payout - Now Available in Singapore&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
Send cross-border payouts with ease. Learn how SWIFT through Rapyd supports your global business growth.&lt;/p&gt;

&lt;p&gt;See you next month, &lt;br&gt;
The Rapyd Dev Community Team&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S.&lt;/strong&gt; Do you have ideas to improve this newsletter or want to contribute an article or join a panel? Let us know by replying. &lt;/p&gt;

</description>
      <category>fintech</category>
      <category>tutorial</category>
      <category>rapydnews</category>
      <category>api</category>
    </item>
    <item>
      <title>POS Terminals: Fintech Reinvented</title>
      <dc:creator>mcduffin</dc:creator>
      <pubDate>Wed, 16 Apr 2025 22:52:37 +0000</pubDate>
      <link>https://dev.to/rapyd/pos-terminals-fintech-reinvented-2ipf</link>
      <guid>https://dev.to/rapyd/pos-terminals-fintech-reinvented-2ipf</guid>
      <description>&lt;p&gt;Point-Of-Sale (POS) Terminals are an essential way to make payments in the real world. Countless brick-and mortar businesses use POS terminals to capture card payments and facilitate other payment methods such as cash payments via a voucher or QR code. The latest terminals also support contactless card payments, and contactless payments using an ewallet on a mobile device. &lt;/p&gt;

&lt;h2&gt;
  
  
  POS Terminals and Fintech
&lt;/h2&gt;

&lt;p&gt;Two main elements are needed for a successful POS terminal experience. The physical terminal is needed, and the connection to a payments processor. Fintech companies are offering POS APIs and connections to physical POS terminals to help expand payments to businesses everywhere. &lt;/p&gt;

&lt;p&gt;Using a POS that can accept a wider variety of cards and payment methods can help customers to make payments their way, and offer a wider range of choices in countries where traditional banking services are less available. &lt;/p&gt;

&lt;p&gt;Fintech companies also allow the merchant greater flexibility, transparency, and control over their POS experience when running their business.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why POS Terminals Are Important
&lt;/h2&gt;

&lt;p&gt;POS terminals are important because they provide vital infrastructure to help facilitate digital payments. A business that runs an online store-front can easily collect payment details, or use a hosted checkout experience to manage online payments. But businesses that have a physical location have more limited options for collecting payment. &lt;/p&gt;

&lt;p&gt;POS terminals are the go-to solution for merchants that run businesses at physical locations. But the experience is heavily influenced by how easily they can collect payments, or issue refunds when needed.  &lt;/p&gt;

&lt;h2&gt;
  
  
  POS Solutions
&lt;/h2&gt;

&lt;p&gt;Fintech companies such as Rapyd transform the POS experience because a larger financial network can be connected to the devices. Rapyd offers a wide variety of payment methods that are accepted in many countries.&lt;/p&gt;

&lt;p&gt;In addition, you can manage your POS terminals using the Rapyd App. You can gain access to a wider variety of features to manage your POS terminals from your mobile device. See the documentation for the Rapyd App &lt;a href="https://docs.rapyd.net/en/rapyd-app-guide.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Merchants can easily view a list of their POS transactions from their mobile device. Pre-authorized sales can also be created.  &lt;/p&gt;

</description>
      <category>fintech</category>
      <category>pos</category>
      <category>payments</category>
      <category>developer</category>
    </item>
    <item>
      <title>Partner Models for Payments: How Rapyd Powers Partner Payment Solutions</title>
      <dc:creator>mcduffin</dc:creator>
      <pubDate>Tue, 08 Apr 2025 17:00:00 +0000</pubDate>
      <link>https://dev.to/rapyd/partner-models-for-payments-how-rapyd-powers-partner-payment-solutions-59p3</link>
      <guid>https://dev.to/rapyd/partner-models-for-payments-how-rapyd-powers-partner-payment-solutions-59p3</guid>
      <description>&lt;p&gt;By: &lt;strong&gt;Gourav Bais&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SaaS platforms and online marketplaces have revolutionized the way businesses operate. While SaaS platforms provide cloud-based solutions, marketplaces connect buyers and sellers within a shared ecosystem. Both models rely on a strong partner ecosystem, where third-party businesses, service providers, and merchants collaborate to deliver value to their customers. This ecosystem supports tasks like onboarding, revenue models, and payment processes.&lt;/p&gt;

&lt;p&gt;However, managing payments across these networks can be challenging due to fragmented systems, regulatory issues, and cross-border complexities. To address these challenges, businesses need a reliable payment infrastructure that supports global operations and ensures smooth transactions. It's possible to establish this infrastructure manually following a partner model or to opt for a reliable payment solution like &lt;a href="https://www.rapyd.net/" rel="noopener noreferrer"&gt;Rapyd&lt;/a&gt;. Rapyd offers a flexible API and partner-friendly infrastructure, enabling you to create tailored payment experiences, onboard merchants, and automate payouts, all while avoiding the complexities of cross-border payments.&lt;/p&gt;

&lt;p&gt;This article introduces some different partner payment models and explains the main components of an effective partner payment flow. You'll then learn how to implement partner-based payment with Rapyd and Python.&lt;/p&gt;

&lt;h2&gt;
  
  
  Partner Models for Payments
&lt;/h2&gt;

&lt;p&gt;When businesses expand to support multiple merchants, service providers, or third-party vendors, they should have their payment system designed in a way that will ensure seamless transactions across the ecosystem. Partner payment models help businesses manage these complex financial interactions since they often support handling customer payments, distributing payments to merchants, and splitting revenue with partners.&lt;/p&gt;

&lt;p&gt;Businesses using SaaS or marketplaces often integrate partner payment models to manage transactions and compliance. These models can greatly simplify the effort of handling challenges like regulatory compliance, fraud prevention, and operational complexity. Two common models are independent sales organization (ISO) and payment facilitator (PayFac).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An ISO is a third-party company that resells &lt;a href="https://www.rapyd.net/blog/the-comprehensive-guide-to-iso-payments/" rel="noopener noreferrer"&gt;credit card processing&lt;/a&gt; from established providers but doesn't process payments directly.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://www.rapyd.net/blog/the-payfac-model-a-simplified-approach-to-payment-processing/" rel="noopener noreferrer"&gt;PayFac&lt;/a&gt; model, also known as payment aggregation, involves a third party acting as a merchant of record. In other words, it processes transactions for sub-merchants under a single master account. This model includes payment processing, risk management, and fraud prevention.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Components of a Partner Payment Flow
&lt;/h2&gt;

&lt;p&gt;If you want to implement and use a partner payment flow, you need a strong understanding of its key components. An effective partner payment system involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Partner onboarding&lt;/li&gt;
&lt;li&gt;Revenue sharing and tracking&lt;/li&gt;
&lt;li&gt;Compliance and taxation considerations&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Partner Onboarding
&lt;/h3&gt;

&lt;p&gt;Partner onboarding is the first step for integrating merchants, vendors, or service providers into a payment system. The process begins with verifying their identity, then setting up their accounts and enabling transactions. A smooth onboarding process can help minimize drop-off rates and ensure that partners can quickly start using the platform. For example, the &lt;a href="https://www.rapyd.net/company/partners/" rel="noopener noreferrer"&gt;Rapyd Partner Portal&lt;/a&gt; streamlines this process by offering automated registration and verification, ensuring compliance with Know Your Customer (KYC) and Anti-Money Laundering (AML) requirements, and providing tools for partners to track transactions, monitor payouts, and manage accounts from a single interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  Revenue Sharing and Tracking
&lt;/h3&gt;

&lt;p&gt;Once onboarding is complete, you'll need to share revenue and track payments. This is particularly important, as you'll probably be owed an agreed percentage of each partner transaction. A payment platform should support automated revenue splits based on pre-agreed models, real-time tracking of earnings, transaction history, payout schedules, and commission breakdowns. It should also offer flexible payout options, such as instant, scheduled, or milestone-based payments, and support multicurrency payments to reduce conversion fees. A few common revenue-sharing models include equal split, royalty-based, percentage of gross revenue, and percentage of net revenue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compliance and Taxation Considerations
&lt;/h3&gt;

&lt;p&gt;Handling payments at scale requires compliance with financial regulations and tax obligations across different regions. Compliance is nonnegotiable in partner payments and ensures that businesses and their partners operate legally and avoid financial penalties. This involves verifying partner identities, monitoring transactions for suspicious activity, and, depending on the jurisdiction, withholding taxes and reporting earnings to tax authorities. Additionally, payment flows must adhere to &lt;a href="https://www.pcisecuritystandards.org/standards/" rel="noopener noreferrer"&gt;PCI DSS standards&lt;/a&gt; to protect sensitive financial data and comply with privacy regulations like &lt;a href="https://gdpr-info.eu/" rel="noopener noreferrer"&gt;GDPR&lt;/a&gt; and &lt;a href="https://oag.ca.gov/privacy/ccpa" rel="noopener noreferrer"&gt;CCPA&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing a Partner-Based Payment System with Rapyd and Python
&lt;/h2&gt;

&lt;p&gt;As you can see, manually managing partner payments can become quite a complex and time-consuming task. Rapyd's payment solution can simplify partner payments for SaaS platforms, marketplaces, and fintech businesses. It supports multiple currencies and handles issues like banking restrictions, currency conversion, and varying country regulations. It also provides built-in compliance tools for automated KYC verification, fraud detection, and adherence to tax compliance. For developers, Rapyd provides easy integration with RESTful APIs and SDKs in languages like Python, Node.js, and Java.&lt;/p&gt;

&lt;p&gt;Let's look at how to use Rapyd to build a simple system where you can onboard merchants, add products, receive payments, and receive payouts, all powered by Rapyd's API. To fully integrate this system, businesses can sign up as a &lt;a href="https://www.rapyd.net/company/partners/" rel="noopener noreferrer"&gt;Rapyd partner&lt;/a&gt; to access additional capabilities for managing merchant transactions. In this tutorial, you'll see how to use the &lt;a href="https://fastapi.tiangolo.com/" rel="noopener noreferrer"&gt;FastAPI framework&lt;/a&gt; in Python to create endpoints for each step: onboarding merchants, adding products, receiving payments, and receiving payouts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before you start, you'll need a &lt;a href="https://dashboard.rapyd.net/" rel="noopener noreferrer"&gt;working Rapyd Client Portal account&lt;/a&gt; to set up a sandbox environment for testing payments. Once you're logged in, you can get your &lt;a href="https://docs.rapyd.net/en/developers.html" rel="noopener noreferrer"&gt;access key and secret key&lt;/a&gt; under the API credentials section in the Client Portal. You'll need these later.&lt;/p&gt;

&lt;p&gt;You'll also need to have &lt;a href="https://www.python.org/downloads/" rel="noopener noreferrer"&gt;Python&lt;/a&gt; installed. Any version 3.8 or later will work for this tutorial.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Python app
&lt;/h3&gt;

&lt;p&gt;Before you begin, install the necessary Python dependencies with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;fastapi uvicorn requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a project folder to store all your development scripts. Inside this folder, create a new Python file called &lt;code&gt;merchant_rapyd_app.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;merchant_rapyd_app.py&lt;/code&gt;, first import the necessary Python dependencies as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HTTPException&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hmac&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the imports are ready, initialize the FastAPI app and define some dummy databases for merchants, products, payments, and payouts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Dummy database
&lt;/span&gt;&lt;span class="n"&gt;merchants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;payments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;payouts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To connect to the Rapyd API, define your credentials as follows, making sure to replace the placeholders with your actual access key and secret key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;RAPYD_ACCESS_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_ACCESS_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;RAPYD_SECRET_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_SECRET_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;RAPYD_BASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://sandboxapi.rapyd.net&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, define a function named &lt;code&gt;generate_rapyd_headers&lt;/code&gt; that will generate the necessary headers for making the authenticated requests to the Rapyd payment platform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Utility function to generate Rapyd headers
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_rapyd_headers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http_method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="n"&gt;salt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;body_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;

    &lt;span class="n"&gt;to_sign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http_method&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;salt&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;RAPYD_ACCESS_KEY&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;RAPYD_SECRET_KEY&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;body_string&lt;/span&gt;
    &lt;span class="n"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RAPYD_SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;to_sign&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;access_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RAPYD_ACCESS_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;salt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;signature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;signature&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code helps you interact securely with Rapyd's API, where each request must be authenticated using a signature-based mechanism. Here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;timestamp&lt;/code&gt; saves the current UNIX time (in seconds). Rapyd requires a valid timestamp to ensure that the request is fresh and prevent replay attacks.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;salt&lt;/code&gt; is a randomly generated unique identifier (UUID). This makes sure that each request is unique and adds an extra layer of security.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;body_string&lt;/code&gt; represents the request payload, which is converted to a JSON string. If there is no request body, it will remain an empty string.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;to_sign&lt;/code&gt; is a concatenation of the HTTP method, request path, salt, timestamp, access key, secret key, and body content. This string is what you sign to generate the authentication signature.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;hmac.new()&lt;/code&gt; function creates a cryptographic hash-based message authentication code (HMAC) using the SHA-256 hashing algorithm. It signs the &lt;code&gt;to_sign&lt;/code&gt; string with the &lt;code&gt;RAPYD_SECRET_KEY&lt;/code&gt;, ensuring that people with a secret key can generate valid signatures.&lt;/li&gt;
&lt;li&gt;The HMAC result is always a binary output, so you need &lt;code&gt;base64.b64encode&lt;/code&gt; to encode it to Base64 and make it a readable string, which is suitable for transmissions in HTTP headers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Create an Endpoint for Merchant Onboarding
&lt;/h3&gt;

&lt;p&gt;The first stage in the partner payment solution is to onboard a merchant. Each merchant should have a unique ID that identifies them.&lt;/p&gt;

&lt;p&gt;Create an endpoint for merchant onboarding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/merchant/register&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;register_merchant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;merchant_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;merchants&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;merchant_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;merchant_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;merchant_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Merchant registered successfully&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The merchant IDs are generated using the &lt;code&gt;uuid&lt;/code&gt; module. These unique IDs ensure there are no conflicts or duplications when processing transactions and are essential for managing merchant-specific payments and payouts.&lt;/p&gt;

&lt;p&gt;This is just a basic example; onboarding a merchant is a far more detailed process and can also involve KYC steps. But don't worry—Rapyd has a product called &lt;a href="https://www.rapyd.net/blog/how-rapyd-verify-can-help-global-businesses-with-robust-kyc/" rel="noopener noreferrer"&gt;Rapyd Verify&lt;/a&gt; to help with that as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create an Endpoint for Adding a Product
&lt;/h3&gt;

&lt;p&gt;Once the merchant is onboarded, it can list products for customers to buy. To enable this, create an endpoint where merchants can add products:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/merchant/{merchant_id}/add_product&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;merchant_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;merchant_id&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;merchants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Merchant not found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;product_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;merchant_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;merchant_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;product_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Product added successfully&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the product is linked to the merchant. This ensures that when multiple customers make purchases simultaneously, each product is correctly associated with the right merchant, avoiding payment confusion. This example is only a simplified version; in real-world applications, products will likely include additional details such as descriptions, categories, stock levels, and images to provide a rich customer experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create an Endpoint to Receive Payments Using Rapyd
&lt;/h3&gt;

&lt;p&gt;Once a customer purchases something, the next step is to forward them to an endpoint where they can complete the payment for the product they're buying from the merchant. To process the payment, you need to integrate with the Rapyd API, which will handle the transaction. This example uses a card payment method with the currency set to USD. Before proceeding, you need to enable the &lt;a href="https://docs.rapyd.net/en/card-payments.html" rel="noopener noreferrer"&gt;Card Payment API&lt;/a&gt; for payments and payouts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/pay/{product_id}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;collect_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;payment_method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;platform_fee_percentage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;10.0&lt;/span&gt;  &lt;span class="c1"&gt;# Default fee is 10%
&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;product_id&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Product not found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;merchant_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;merchant_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Validate platform fee percentage (should be between 0% and 100%)
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;platform_fee_percentage&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid platform fee percentage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Convert percentage to decimal
&lt;/span&gt;    &lt;span class="n"&gt;platform_fee_decimal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;platform_fee_percentage&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;

    &lt;span class="c1"&gt;# Calculate platform fee and merchant payout
&lt;/span&gt;    &lt;span class="n"&gt;platform_fee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;platform_fee_decimal&lt;/span&gt;
    &lt;span class="n"&gt;merchant_payout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;platform_fee&lt;/span&gt;  &lt;span class="c1"&gt;# Amount merchant receives
&lt;/span&gt;
    &lt;span class="c1"&gt;# Prepare payment data for Rapyd API
&lt;/span&gt;    &lt;span class="n"&gt;payment_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;currency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment_method&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;payment_method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Payment for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_rapyd_headers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/v1/payments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payment_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;RAPYD_BASE_URL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/v1/payments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payment_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to create payment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;payment_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;payment_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payment_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Store payment record
&lt;/span&gt;    &lt;span class="n"&gt;payments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;payment_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;merchant_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;merchant_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;platform_fee&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;platform_fee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;merchant_payout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;merchant_payout&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# Update merchant balance
&lt;/span&gt;    &lt;span class="n"&gt;merchants&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;merchant_id&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;merchant_payout&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;payment_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;platform_fee_percentage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;platform_fee_percentage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;platform_fee&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;platform_fee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;merchant_payout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;merchant_payout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Payment successful&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The endpoint initiates the payment for the selected products. You might notice that &lt;code&gt;platform_fee_percentage&lt;/code&gt; is a requested parameter (10 percent by default) that allows merchants or platform admins to set a custom percentage for the platform fee for each transaction. This allows them to customize the fee based on factors such as transaction type (card-based vs. non-card transactions), debit vs. credit cards, merchant category code, and commercial vs. consumer cards to determine the right platform cost based on the transaction overheads and risks. This fee is then deducted from the total product amount, and the remaining amount is updated in the merchant's balance.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's possible for the client to disconnect after the API request is initiated but before a response can be received. This would mean that the payment is processed, but since the client (&lt;em&gt;ie&lt;/em&gt; the Python app) doesn't know about it, the purchase will fail. In such situations, &lt;a href="https://docs.rapyd.net/en/webhooks.html" rel="noopener noreferrer"&gt;webhooks&lt;/a&gt; can help by sending a callback message to your app every time a payment is processed. In a real-world app, you must implement these to make your payments reliable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Create an Endpoint to Automate Merchant Payouts
&lt;/h3&gt;

&lt;p&gt;Finally, once the payment is successful, merchants should be able to withdraw their funds using the Rapyd payout system. To implement this functionality, create the final endpoint as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/merchant/{merchant_id}/payout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;payout_merchant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;merchant_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;merchant_id&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;merchants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Merchant not found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;merchants&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;merchant_id&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No funds available for payout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;payout_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;currency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;USD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payout_method_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bank_transfer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sender_currency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;USD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;beneficiary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;merchants&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;merchant_id&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_rapyd_headers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/v1/payouts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payout_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;RAPYD_BASE_URL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/v1/payouts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payout_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to process payout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;payout_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;payout_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payout_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;payouts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;payout_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;merchant_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;merchant_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;merchants&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;merchant_id&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payout_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;payout_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Payout successful&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This endpoint allows you to pay merchants without having to worry about manually calculating their earnings and initiating transfers for those amounts. Moreover, it also automates compliance with payout regulations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run the App
&lt;/h3&gt;

&lt;p&gt;That's it! You've just created a partner payments solution where merchants can be onboarded and add products, and customers can make payments for purchased products using Rapyd. The next step is to run your app and test the endpoints.&lt;/p&gt;

&lt;p&gt;To run the app, open a command prompt and run the &lt;code&gt;merchant_rapyd_app.py&lt;/code&gt; file as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uvicorn merchant_rapyd_app:app &lt;span class="nt"&gt;--host&lt;/span&gt; 0.0.0.0 &lt;span class="nt"&gt;--port&lt;/span&gt; 8000 &lt;span class="nt"&gt;--reload&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl720h4d9obbq17kwth65.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl720h4d9obbq17kwth65.png" alt="Run FastAPI" width="800" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will start your application, which you can access in your browser at &lt;code&gt;http://localhost:8000/docs&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5yjw4r9d9btjyd4gfdmx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5yjw4r9d9btjyd4gfdmx.png" alt="Running application" width="800" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to test the endpoints that you've created with &lt;code&gt;curl&lt;/code&gt; commands.&lt;/p&gt;

&lt;p&gt;This command registers the merchant and creates a new merchant account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"http://localhost:8000/merchant/register?name=John's%20Store"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "merchant_id": "550e8400-e29b-41d4-a716-446655440000", "message": "Merchant registered successfully" }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save this merchant ID for additional tests.&lt;/p&gt;

&lt;p&gt;List a product for the merchant (with the appropriate merchant ID) using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"http://localhost:8000/merchant/550e8400-e29b-41d4-a716-446655440000/add_product?name=Wireless%20Headphones&amp;amp;price=50.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "product_id": "c1a7f2d5-3e3a-49c6-bc15-22a5dc5e2a80", "message": "Product added successfully" }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save this product ID for the next test.&lt;/p&gt;

&lt;p&gt;Payment processing should happen as soon as the customer buys a product. You can test this with the following endpoint hit (using the product ID):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"http://localhost:8000/pay/c1a7f2d5-3e3a-49c6-bc15-22a5dc5e2a80?currency=USD&amp;amp;payment_method=card&amp;amp;platform_fee_percentage=10.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "payment_id": "pay_12345", "platform_fee_percentage": 10.0, "platform_fee": 5.0, "merchant_payout": 45.0, "message": "Payment successful" }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since you set the platform fee to 10 percent, it's deducted from the total product amount, and the remaining amount is reflected in the merchant payout. The payment ID is useful for tracking payments.&lt;/p&gt;

&lt;p&gt;Finally, test the merchant payout with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"http://localhost:8000/merchant/550e8400-e29b-41d4-a716-446655440000/payout"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "payout_id": "payout_567e4567-e89b-12d3-a456-426614174003", "message": "Payout successful" }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can access the full code in &lt;a href="https://github.com/Rapyd-Samples/Partner-Models-for-Payments-How-Rapyd-Powers-Partner-Payment-Solutions" rel="noopener noreferrer"&gt;this GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;After reading this article, you now know how to implement a partner-based payment system using Rapyd. You've explored various partner models (ISO and PayFac), the key components of a partner payment flow, and a step-by-step guide to building a payment solution with Rapyd and Python.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.rapyd.net/" rel="noopener noreferrer"&gt;Rapyd&lt;/a&gt; offers a simplified solution for payment processing that makes it easier for SaaS platforms, marketplaces, and fintech businesses to onboard partners, receive payments, and automate revenue sharing. Ready to integrate Rapyd into your platform? &lt;a href="https://dashboard.rapyd.net/sign-up" rel="noopener noreferrer"&gt;Sign up for a free Rapyd account&lt;/a&gt; and check out the &lt;a href="https://docs.rapyd.net/en/index-en.html" rel="noopener noreferrer"&gt;Rapyd API documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>iso</category>
      <category>payfac</category>
      <category>payments</category>
    </item>
  </channel>
</rss>
