# Pay in 3 Integration Guide div div ⏱ 8 min div 👤 Product Team ###### Technical integration guidance for the Ratepay Pay in 3 payment method ## Overview This guide explains how to integrate Ratepay Pay in 3 across the buyer journey. It covers: - how to calculate Pay in 3 plan values - how to display Pay in 3 on product, cart, and checkout pages - how to connect the checkout flow to Ratepay APIs - when to use client-side calculation and when to use `CALCULATION_REQUEST` This page focuses on technical integration. For mandatory legal disclosure requirements, see [Pay in 3 legal requirements](/docs/legal/a_legal_requirements_for_the_integration/pay_in_3_integration). **Recommended approach:** calculate Pay in 3 plan details client-side for display purposes, and use the standard Ratepay checkout API flow for payment processing. ## Integration summary | Topic | Recommended approach | Alternative approach | | --- | --- | --- | | Product page plan display | Client-side calculation | `CALCULATION_REQUEST` | | Cart page plan display | Client-side calculation | `CALCULATION_REQUEST` | | Checkout plan display | Client-side calculation | `CALCULATION_REQUEST` | | Payment processing | `PAYMENT_INIT` + `PAYMENT_REQUEST` | Same | | Final order confirmation | `PAYMENT_CONFIRM`, if required for your setup | Same | ## Visual overview The examples below illustrate the main integration contexts and UI states in the buyer journey. | Screen | Stage | Purpose | Notes | | --- | --- | --- | --- | | | Product page | Show Pay in 3 teaser near the product price | Optional from a legal perspective, but recommended for transparency and conversion | | | Cart page | Recalculate and show Pay in 3 based on the current cart total | Update whenever quantity or cart contents change | | | Product / Cart | Show detailed plan values in a modal or detail view | Typically opened through a “Learn more” interaction | | | Checkout | Show Pay in 3 as the selected payment method in the default checkout state | Example of the main payment method view before expanding additional instalment details | | | Checkout | Show the expanded checkout state with additional instalment breakdown details | Example of an expanded buyer-facing checkout view | ## Core credit terms to show | Label in UI | German label | Description | | --- | --- | --- | | **Per month** | Monatliche Rate | Monthly instalment amount | | **Duration** | Laufzeit | Number of instalments and duration | | **Effective Interest** | Effektiver Jahreszins | Annual percentage rate of charge (APR) | | **Interest** | Zinsbetrag | Total interest amount | | **Total** | Gesamtbetrag | Total amount payable | | Monthly instalment amount | Monatliche Rate | Regular instalment amount shown to the buyer | | Final instalment amount | Letzte Rate | Final instalment amount, which may differ slightly because of rounding | For Pay in 3, these values are typically: - **Duration** = `3 months` - **Effective Interest** = `0%` - **Interest** = `0` - **Total** = basket amount - **Monthly instalment amount** = regular instalment amount calculated from the basket amount - **Final instalment amount** = last instalment amount, which may differ slightly because of rounding ## Integration ### 1. Choose your calculation approach Before showing Pay in 3 to the buyer, you need to obtain the plan values for the current amount. #### Option A — Client-side calculation This is the recommended approach for display purposes. Pay in 3 is a fixed product: - `3` monthly instalments - `0%` interest - `0` fees Because most parameters are static, the display values can be calculated client-side from the basket amount. The final instalment absorbs any rounding remainder. The calculation function can also accept an optional `shipmentDate` (`YYYY-MM-DD`). If your shop has a reliable delivery estimate, you can use it to generate a more accurate estimated instalment schedule. If omitted, the function uses today’s date and returns a general estimate. Use the following helper function to calculate Pay in 3 plan values directly in your frontend or backend application code. ```js calculatePayIn3.js function calculatePayIn3(amount, shipmentDate) { // --- Configuration: Pay in 3 is a 0% interest, 0-fee product --- const NUMBER_OF_INSTALLMENTS = 3; const DURATION_UNIT = "months"; const INTEREST_RATE = 0; const INTEREST_AMOUNT = 0; const FEES_AMOUNT = 0; const HAS_INTEREST = false; const HAS_FEES = false; // --- Calculate installment amounts --- // Split evenly; any rounding remainder goes to the final installment const regularAmount = Math.round((amount / NUMBER_OF_INSTALLMENTS) * 100) / 100; const finalAmount = Math.round((amount - regularAmount * (NUMBER_OF_INSTALLMENTS - 1)) * 100) / 100; // --- Determine the first due date --- // First instalment is due on the 2nd of the month following shipment, // provided there are at least 28 days between shipment and that date. // Otherwise, it is pushed to the 2nd of the subsequent month. function getFirstDueDate(shipment) { let next2nd = new Date(Date.UTC(shipment.getUTCFullYear(), shipment.getUTCMonth() + 1, 2)); const shipmentUTC = Date.UTC(shipment.getUTCFullYear(), shipment.getUTCMonth(), shipment.getUTCDate()); const next2ndUTC = Date.UTC(next2nd.getUTCFullYear(), next2nd.getUTCMonth(), next2nd.getUTCDate()); const diffDays = Math.floor((next2ndUTC - shipmentUTC) / (1000 * 60 * 60 * 24)); if (diffDays >= 28) return next2nd; return new Date(Date.UTC(shipment.getUTCFullYear(), shipment.getUTCMonth() + 2, 2)); } // Parse shipmentDate string (YYYY-MM-DD) or default to today, using UTC for consistency let shipment; if (shipmentDate) { const parts = shipmentDate.split("-"); shipment = new Date(Date.UTC(+parts[0], +parts[1] - 1, +parts[2])); } else { const today = new Date(); shipment = new Date(Date.UTC(today.getFullYear(), today.getMonth(), today.getDate())); } const firstDue = getFirstDueDate(shipment); // --- Build the installment schedule --- const schedule = []; let remaining = amount; for (let i = 1; i <= NUMBER_OF_INSTALLMENTS; i++) { const dueDate = new Date(Date.UTC(firstDue.getUTCFullYear(), firstDue.getUTCMonth() + (i - 1), 2)); const payment = i < NUMBER_OF_INSTALLMENTS ? regularAmount : finalAmount; remaining = Math.round((remaining - payment) * 100) / 100; schedule.push({ installmentNumber: i, estimatedDueDate: dueDate.getUTCFullYear() + "-" + String(dueDate.getUTCMonth() + 1).padStart(2, "0") + "-" + String(dueDate.getUTCDate()).padStart(2, "0"), paymentAmount: payment, principalAmount: payment, interestAmount: INTEREST_AMOUNT, feesAmount: FEES_AMOUNT, remainingPrincipalBalanceAmount: remaining, }); } // --- Return the complete plan object --- return { planMetadata: { hasInterest: HAS_INTEREST, hasFees: HAS_FEES }, repaymentPlan: { numberOfInstallments: NUMBER_OF_INSTALLMENTS, durationOfInstallments: DURATION_UNIT, regularInstallmentAmount: regularAmount, finalInstallmentAmount: finalAmount, }, creditTerms: { totalPayableAmount: amount, totalCostOfCreditAmount: INTEREST_AMOUNT + FEES_AMOUNT, totalInterestAmount: INTEREST_AMOUNT, totalFeesAmount: FEES_AMOUNT, nominalInterestRatePercentage: INTEREST_RATE, annualPercentageRate: INTEREST_RATE, }, fees: { serviceFeeAmount: FEES_AMOUNT }, installmentSchedule: schedule, }; } ``` ```json example-output.json { "planMetadata": { "hasInterest": false, "hasFees": false }, "repaymentPlan": { "numberOfInstallments": 3, "durationOfInstallments": "months", "regularInstallmentAmount": 66.67, "finalInstallmentAmount": 66.66 }, "creditTerms": { "totalPayableAmount": 200, "totalCostOfCreditAmount": 0, "totalInterestAmount": 0, "totalFeesAmount": 0, "nominalInterestRatePercentage": 0, "annualPercentageRate": 0 }, "fees": { "serviceFeeAmount": 0 }, "installmentSchedule": [ { "installmentNumber": 1, "estimatedDueDate": "2026-05-02", "paymentAmount": 66.67, "principalAmount": 66.67, "interestAmount": 0, "feesAmount": 0, "remainingPrincipalBalanceAmount": 133.33 }, { "installmentNumber": 2, "estimatedDueDate": "2026-06-02", "paymentAmount": 66.67, "principalAmount": 66.67, "interestAmount": 0, "feesAmount": 0, "remainingPrincipalBalanceAmount": 66.66 }, { "installmentNumber": 3, "estimatedDueDate": "2026-07-02", "paymentAmount": 66.66, "principalAmount": 66.66, "interestAmount": 0, "feesAmount": 0, "remainingPrincipalBalanceAmount": 0 } ] } ``` Example function usage ```js productPage.js const productAmount = 200; const plan = calculatePayIn3(productAmount); ``` ```js cartPage.js const cartTotal = 200; const plan = calculatePayIn3(cartTotal); ``` ```js checkout.js const basketTotal = 200; const plan = calculatePayIn3(basketTotal); ``` ```js checkoutWithShipmentDate.js const basketTotal = 200; const planWithDate = calculatePayIn3(basketTotal, "2026-03-15"); ``` #### Key output fields | JSON field | UI label | Meaning | | --- | --- | --- | | `repaymentPlan.regularInstallmentAmount` | **Per month** | Regular monthly instalment amount | | `repaymentPlan.numberOfInstallments` + `repaymentPlan.durationOfInstallments` | **Duration** | Number and duration of instalments | | `creditTerms.annualPercentageRate` | **Effective Interest** | Effective interest rate shown to the buyer | | `creditTerms.totalInterestAmount` | **Interest** | Total interest amount | | `creditTerms.totalPayableAmount` | **Total** | Total amount payable | | `repaymentPlan.finalInstallmentAmount` | **Final instalment** | Final instalment amount, if it differs due to rounding | | `installmentSchedule[].estimatedDueDate` | — | Estimated due date for each instalment, if a shipment date is used to generate the schedule | #### Option B — Server-side calculation Use the Ratepay XML API `CALCULATION_REQUEST` operation if you prefer to retrieve plan values from the server instead of calculating them client-side. The response contains the core instalment values needed for display and checkout mapping. See also: [CALCULATION_REQUEST](/docs/developer/api_integration/payment_1.8/payment_api_documentation/the_ratepay_gateway_operations/instalment_calculator/calculation_request) For Pay in 3, both approaches can support the same buyer-facing disclosure values. Choose the option that best fits your architecture. ```xml CALCULATION_REQUEST.xml MyTestsystem CALCULATION_REQUEST INTEGRATION_TE_DACH 4c0a11923fa3433fb168f9c7176429e9 200.00 3 ``` ```xml CALCULATION_RESPONSE.xml MyTestsystem CALCULATION_REQUEST INSTALLMENT_PLAN 2026-03-29T13:37:08.000 Successfully Calculation reason: FULFILLED_CONDITION: The payment plan fulfilled the conditions. Calculation successful 200 200 0 0 0 0 0 3 66.67 66.66 2 ``` #### Key response fields For Pay in 3, you can ignore `` and `` because these values are always `0`. | XML field | UI label | Meaning | | --- | --- | --- | | `` | **Per month** | Regular monthly instalment amount | | `` | **Duration** | Number of monthly instalments | | `` | **Effective Interest** | Effective interest rate shown to the buyer | | `` | **Interest** | Total interest amount | | `` | **Total** | Total amount payable | | `` | **Final instalment** | Final instalment amount, if it differs due to rounding | | `` | — | Day of month used for collection and for installment schedule logic | ### 2. Product page integration On the product page, you may show a Pay in 3 teaser near the product price. #### Recommended product page behavior - calculate Pay in 3 plan details using **chosen calculation approach** (see [Calculation Approaches](/docs/developer/api_integration/payment_1.8/payment_api_documentation/how_to_integrate_ratepay/pay_in_3#1-choose-your-calculation-approach)) - show the **monthly instalment amount** - show the **duration** - provide a **Learn more** link or similar interaction - open a modal or detail view with the full plan values - update values dynamically when the product price changes, for example after variant selection #### Required detail values for the modal or expanded view | Label | Description | | --- | --- | | Per month | Monthly instalment amount | | Duration | Number and duration of instalments | | Effective Interest | Annual percentage rate | | Interest | Total interest amount | | Total | Total amount payable | #### Example UI | Product page teaser | Product page modal | | --- | --- | | | | ### 3. Cart page integration The cart page follows the same principle as the product page, but the amount must always reflect the current cart total. #### Recommended cart page behavior - calculate Pay in 3 plan details using **chosen calculation approach** (see [Calculation Approaches](/docs/developer/api_integration/payment_1.8/payment_api_documentation/how_to_integrate_ratepay/pay_in_3#1-choose-your-calculation-approach)) - update the values whenever quantity or items change - show the teaser in the cart summary area - provide a “Learn more” interaction with the detailed values #### Example UI | Cart page teaser | Cart page modal | | --- | --- | | | | ### 4. Checkout integration | Step | Purpose | | --- | --- | | `PAYMENT_INIT` | Initialize the Ratepay transaction and receive `transaction-id` | | Plan calculation | Generate the display values and instalment details | | Buyer-facing checkout display | Show the selected Pay in 3 plan and required inputs | | `PAYMENT_REQUEST` | Send customer, basket, and payment data to Ratepay | | `PAYMENT_CONFIRM` | Finalize the transaction if required for your setup | #### Submit `PAYMENT_INIT` The first step of the checkout workflow is `PAYMENT_INIT`. This operation initializes the transaction and returns a `transaction-id` that must be included in subsequent API calls. See also: [PAYMENT_INIT](/docs/developer/api_integration/payment_1.8/payment_api_documentation/the_ratepay_gateway_operations/payment_init) ```xml PAYMENT_INIT_REQUEST.xml myshop PAYMENT_INIT INTEGRATION_TE_DACH 4c0a11923fa3433fb168f9c7176429e9 ``` ```xml PAYMENT_INIT_RESPONSE.xml MyTestsystem xx-xxxxxxxxxxxxxx 3EQP.SBYM.CBSR.3302 PAYMENT_INIT STATUS_RESPONSE 2026-01-06T16:56:19.000 Successfully Processing successful Transaction initialized ``` #### Calculate plan details for checkout Use the final checkout basket amount to generate the Pay in 3 plan values using **chosen calculation approach**. See [Calculation Approaches](/docs/developer/api_integration/payment_1.8/payment_api_documentation/how_to_integrate_ratepay/pay_in_3#1-choose-your-calculation-approach) #### Display Pay in 3 in checkout When the buyer selects Pay in 3 as the payment method, your checkout should render the Pay in 3 plan values and collect the required payment data. Checkout UI for Pay in 3 should generally include - credit term values for the selected plan - instalment amount breakdown - date of birth input - Terms of Payment and Privacy / Risk Check links near the order button. For Pay in 3 with payments via direct debit, additionally these inputs are needed: - IBAN input - bank account owner input - SEPA mandate text and consent checkbox The legal requirements for what must be shown at checkout are defined on the [Pay in 3 legal requirements](/docs/legal/a_legal_requirements_for_the_integration/pay_in_3_integration) page. By default, checkout should avoid fixed due dates because the actual schedule depends on shipment timing. A buyer-friendly simplified breakdown is acceptable, or you may show estimated due dates only if they are based on a reliable shipment date. #### Example UI | Checkout compact view | Checkout expanded view | | --- | --- | | | | #### Map values into `PAYMENT_REQUEST` After the buyer selects Pay in 3 and provides the required data, send `PAYMENT_REQUEST`. #### Mapping from client-side calculation result | `PAYMENT_REQUEST` field | Source from `calculatePayIn3()` | | --- | --- | | `` | `repaymentPlan.numberOfInstallments` | | `` | `repaymentPlan.regularInstallmentAmount` | | `` | `repaymentPlan.finalInstallmentAmount` | | `` | `creditTerms.nominalInterestRatePercentage` | | `` | Constant value `2` for direct debit, `28` for bank transfer | | `` | `creditTerms.totalPayableAmount` | #### Mapping from `CALCULATION_REQUEST` response | `PAYMENT_REQUEST` field | Source from XML response | | --- | --- | | `` | `` | | `` | `` | | `` | `` | | `` | `` | | `` | `` | | `` | `` | #### Submit `PAYMENT_REQUEST` `PAYMENT_REQUEST` is the main checkout operation. It sends the customer details, basket data, and selected Pay in 3 payment details to Ratepay. See also: [PAYMENT_REQUEST](/docs/developer/api_integration/payment_1.8/payment_api_documentation/the_ratepay_gateway_operations/payment_request) #### Main request areas Pay in 3 via direct debit (recommended) | Area | Examples | | --- | --- | | Customer data | Name, gender, date of birth, IP address, email, phone | | Addresses | Billing and shipping addresses | | Bank account | IBAN, BIC, account holder | | Shopping basket | Items, discounts, shipping, total amount | | Payment | Installment details and debit pay type | ```xml PAYMENT_REQUEST.xml MyTestsystem xx-xxxxxxxxxxxxxx PAYMENT_REQUEST INTEGRATION_TE_DACH 4c0a11923fa3433fb168f9c7176429e9 O-1234-HDZ 12345 xxxxxxxxxxxxxxxxxxxxxxxx Max Mustermann M 1982-10-31 127.0.0.1 test@test.de 030123456
Nicht-Versenden-Strasse 1 12345 Testhausen DE
Strasse der Lieferadresse 2 54321 Testhausen DE
Max Mustermann DE44100500001654698497 BELADEBEXXX DE yes
Example Product Versandkosten 200.00 3 66.67 66.66 0 2 DIRECT-DEBIT
``` ```xml PAYMENT_REQUEST_RESPONSE.xml MyTestsystem xx-xxxxxxxxxxxxxx PAYMENT_REQUEST PAYMENT_PERMISSION 12345 2026-01-06T16:30:20.000 Successfully Request successful Transaction result pending
Nicht-Versenden-Strasse 1 12345 Testhausen DE
200.00 3 66.67 66.66 0 2 DIRECT-DEBIT DG0479414D0
``` Pay in 3 via bank transfer | Area | Examples | | --- | --- | | Customer data | Name, gender, date of birth, IP address, email, phone | | Addresses | Billing and shipping addresses | | Shopping basket | Items, discounts, shipping, total amount | | Payment | Installment details and debit pay type | ```xml PAYMENT_REQUEST.xml MyTestsystem xx-xxxxxxxxxxxxxx PAYMENT_REQUEST INTEGRATION_TE_DACH 4c0a11923fa3433fb168f9c7176429e9 O-1234-HDZ 12345 xxxxxxxxxxxxxxxxxxxxxxxx Max Mustermann M 1982-10-31 127.0.0.1 test@test.de 030123456
Nicht-Versenden-Strasse 1 12345 Testhausen DE
Strasse der Lieferadresse 2 54321 Testhausen DE
DE yes
Example Product Versandkosten 200.00 3 66.67 66.66 0 28 BANK-TRANSFER
``` ```xml PAYMENT_REQUEST_RESPONSE.xml MyTestsystem xx-xxxxxxxxxxxxxx PAYMENT_REQUEST PAYMENT_PERMISSION 12345 2026-01-06T16:30:20.000 Successfully Request successful Transaction result pending
Nicht-Versenden-Strasse 1 12345 Testhausen DE
200.00 3 66.67 66.66 0 28 BANK-TRANSFER DG0479414D0
``` #### Submit `PAYMENT_CONFIRM` After a successful `PAYMENT_REQUEST`, finalize the transaction with `PAYMENT_CONFIRM` if this step is required for your integration setup. See also: [PAYMENT_CONFIRM](/docs/developer/api_integration/payment_1.8/payment_api_documentation/the_ratepay_gateway_operations/place_order/payment_confirmation) The necessity of `PAYMENT_CONFIRM` depends on your integration setup. Please confirm with your Ratepay counterpart whether this step is required. ```xml PAYMENT_CONFIRM_REQUEST.xml MyTestsystem xx-xxxxxxxxxxxxxx PAYMENT_CONFIRM INTEGRATION_TE_DACH 4c0a11923fa3433fb168f9c7176429e9 O-1234-HDZ ``` ```xml PAYMENT_CONFIRM_RESPONSE.xml MyTestsystem xx-xxxxxxxxxxxxxx PAYMENT_CONFIRM STATUS_RESPONSE O-1234-HDZ 2026-04-09T17:57:07.000 Successfully No RMS reason code Transaction result successful ``` ## Recommended implementation pattern If you want a pragmatic setup with low complexity, use this pattern: | Stage | Suggested implementation | | --- | --- | | Product page | Client-side calculation + teaser + “Learn more” modal | | Cart page | Reuse the same function with cart total | | Checkout display | Reuse the same function with final basket amount | | Checkout API flow | `PAYMENT_INIT` → `PAYMENT_REQUEST` → `PAYMENT_CONFIRM` if required | | Legal compliance | Keep the displayed fields aligned with the legal requirements page | ## Further resources - [Pay in 3 legal requirements](/docs/legal/a_legal_requirements_for_the_integration/pay_in_3_integration) - [CALCULATION_REQUEST](/docs/developer/api_integration/payment_1.8/payment_api_documentation/the_ratepay_gateway_operations/instalment_calculator/calculation_request) - [PAYMENT_INIT](/docs/developer/api_integration/payment_1.8/payment_api_documentation/the_ratepay_gateway_operations/payment_init) - [PAYMENT_REQUEST](/docs/developer/api_integration/payment_1.8/payment_api_documentation/the_ratepay_gateway_operations/payment_request) - [PAYMENT_CONFIRM](/docs/developer/api_integration/payment_1.8/payment_api_documentation/the_ratepay_gateway_operations/place_order/payment_confirmation)