{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-documentation/get_started/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["admonition"]},"type":"markdown"},"seo":{"title":"Field Collection","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"field-collection","__idx":0},"children":["Field Collection"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"overview","__idx":1},"children":["Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This guide provides an overview of how to ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["collect payment fields"]}," using the embedded SDK v3. It covers the setup and integration of payment fields into your web application, allowing you to securely capture payment information from your customers."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["It is highly recommended to have a basic understanding of how to set up the embedded SDK and create a simple checkout experience before diving into field collection. If you haven't already, please refer to the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/documentation/get_started/process_payments/embedded_sdk_v3/quick_start"},"children":["Quick Start Guide"]}," to get up and running with the embedded SDK."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"collect-billing-address","__idx":2},"children":["Collect Billing Address"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In this guide, we will continue building on the example from the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/documentation/get_started/process_payments/embedded_sdk_v3/quick_start"},"children":["Quick Start Guide"]}," to demonstrate how to collect the customer's billing address along with the card details using the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["fieldCollection"]}," feature of the embedded SDK."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["fieldCollection"]}," component allows three modes of collecting the billing address:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["full"]},": Collects the full billing address, including ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["firstName"]},", ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["lastName"]},", ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["lineOne"]},", ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["lineTwo"]}," (optional), ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["country"]},", ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["postal/zipCode"]}," and ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["region"]}," (optional unless country is CA or US)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["minimum"]},": Collects only the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["country"]},", ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["postal/zipCode"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["hidden"]},": Hides the billing address fields from the customer and allows you to supply the billing address information directly to the SDK if you already have it from a previous step in your checkout process (see the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#supply-billing-address-manually"},"children":["Supply Billing Address Manually"]}," section below for more details)."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["It is generally recommended to listen to the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["validationChange"]}," event emitted by the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["fieldCollection"]}," component to determine the validity of the fields collected by this component, and to enable or disable the payment submission button accordingly."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Alternatively, you can listen to the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["validationChange"]}," event emitted by the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["controller"]},", which provides the overall validation status of all components managed by the controller, including both the card form and the field collection form."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Here's an example of how to configure the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["fieldCollectionForm"]}," component to collect the billing address:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","data-title":"Collect Full Billing Address Example","header":{"title":"Collect Full Billing Address Example","controls":{"copy":{}}},"source":"// Initialise the fieldCollectionForm component\n// and configure it to collect the full billing address\nconst fieldCollectionForm = createFieldCollectionForm(controller, {\n    fieldCollection: {\n        customerAddress: {\n            displayMode: \"full\"  // or \"minimum\" depending on your needs\n        }\n    }\n});\n\n// Listen to validation changes to enable/disable the PAY button\n// based on the validity of the fields in the field collection form\nfieldCollectionForm.on(\"validationChange\", (event) => {\n    payButton.disabled = !event.isValid;\n});\n\n// Mount the field collection form component to the desired container in your HTML\nfieldCollectionForm.mount('#field-collection-form-container');\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"supply-billing-address-manually","__idx":3},"children":["Supply Billing Address Manually"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In some cases, you may ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["already have the customer's billing address information"]}," from a previous step in your checkout process. In such scenarios, you can supply the billing address directly to the embedded SDK."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["At this stage, you can choose to pre-fill the billing address fields with the known information, allowing the customer to review and edit if necessary, or you can choose to hide the billing address fields entirely and use the provided values for the transaction without displaying them to the customer."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Here's an example of how to supply the billing address manually:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","data-title":"Supply Billing Address Manually Example","header":{"title":"Supply Billing Address Manually Example","controls":{"copy":{}}},"source":"const fieldCollectionForm = createFieldCollectionForm(controller, {\n    fieldCollection: {\n        customerAddress: {\n            // Set `displayMode` to 'hidden'\n            // to hide the billing address fields from the customer.\n            displayMode: \"hidden\",  \n            value: {\n                firstName: \"John\",\n                lastName: \"Doe\",\n                lineOne: \"123 Main St\",\n                city: \"London\",\n                country: \"GB\",\n                postalCode: \"SW1A 1AA\",\n            }\n        }\n    }\n});\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When supplying the billing address manually, ensure that the provided values are valid against our API validation rules. Invalid values may lead to transaction failures."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"collect-name-on-card","__idx":4},"children":["Collect Name on Card"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The embedded SDK can also collect the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Name on Card"]}," as part of the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["card form component"]},". To enable this feature, you can use the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["collectNameOnCard"]}," option in the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["paymentFieldConfig"]}," when initializing the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cardForm"]}," component. This will add an additional field to the card form where customers can enter the name as it appears on their card."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","data-title":"Collect Name on Card Example","header":{"title":"Collect Name on Card Example","controls":{"copy":{}}},"source":"const cardForm = createCardForm(controller, {\n    paymentFieldConfig: {\n        collectNameOnCard: true\n    }\n});\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Once enabled, the card form will include a field for the name on card, and the collected value will be included in the payment information sent to Ryft when the payment is attempted."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"complete-example","__idx":5},"children":["Complete Example"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following is a complete working example that combines:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["all the features covered in the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/documentation/get_started/process_payments/embedded_sdk_v3/quick_start#complete-example"},"children":["Quick Start"]}," guide"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["collecting the full billing address with the field collection component"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["collecting the name on card"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["validating the fields before enabling the payment submission button"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"html","data-title":"Complete Fields Collection Example","header":{"title":"Complete Fields Collection Example","controls":{"copy":{}}},"source":"<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Ryft Card Form</title>\n\n    <!-- Only if using the script tag method to install the SDK -->\n    <script src=\"https://web-sdk.ryftpay.com/embedded/latest/ryft.min.js\"></script>\n\n    <style>\n        #pay-btn {\n            background-color: #0070f3;\n            color: white;\n            border: none;\n            padding: 14px 22px;\n            /* slightly bigger */\n            font-size: 16px;\n            /* slightly larger text */\n            border-radius: 4px;\n            cursor: pointer;\n            margin-top: 12px;\n        }\n\n        #pay-btn:disabled {\n            background-color: #cccccc;\n            cursor: not-allowed;\n        }\n\n        .spinner {\n            border: 4px solid rgba(0, 0, 0, 0.1);\n            width: 36px;\n            height: 36px;\n            border-radius: 50%;\n            border-left-color: #09f;\n            animation: spin 1s ease infinite;\n            display: none;\n            /* Initially hidden */\n            margin: 10px auto;\n        }\n\n        @keyframes spin {\n            0% {\n                transform: rotate(0deg);\n            }\n\n            100% {\n                transform: rotate(360deg);\n            }\n        }\n    </style>\n</head>\n\n<body>\n\n    <div class=\"Ryft--paysection\">\n        <form id=\"ryft-pay-form\" class=\"Ryft--payform\">\n            <div id=\"card-form-container\"></div>\n            <div id=\"field-collection-form-container\"></div>\n\n            <button id=\"pay-btn\" disabled>PAY NOW</button>\n\n            <div id=\"ryft-pay-error\"></div>\n            <div id=\"spinner-container\" class=\"spinner\"></div>\n        </form>\n    </div>\n\n    <script type=\"module\">\n        import { createController, createCardForm, createFieldCollectionForm } from '@ryftpay/web';  // If using npm to install the SDK\n        // const { createController, createCardForm, createFieldCollectionForm } = window.Ryft;  // If using the script tag method to install the SDK\n\n        // Returned when creating a Payment Session\n        const clientSecret = \"\";\n        // Available in the Ryft Portal\n        const publicKey = \"\";\n        // The unique identifier for the Sub-Account, if using the Platform Fee model\n        const accountId = \"\";\n\n        // Get a reference to the pay button\n        const payButton = document.getElementById(\"pay-btn\");\n        // Get a reference to the error div\n        const errorDiv = document.getElementById(\"ryft-pay-error\");\n        // Get a reference to the spinner container\n        const spinner = document.getElementById(\"spinner-container\");\n\n        // Initialise Controller\n        const controller = createController({\n            publicKey,\n            clientSecret,\n            // accountId  // Uncomment if using the Platform Fee model\n        });\n\n        // Create Card Form instance\n        const cardForm = createCardForm(controller, {\n            paymentFieldConfig: {\n                collectNameOnCard: true\n            }\n        });\n\n        // Create Field Collection Form instance\n        const fieldCollectionForm = createFieldCollectionForm(controller, {\n            fieldCollection: {\n                customerAddress: {\n                    displayMode: \"full\",\n                    value: {\n                        firstName: \"John\",\n                        lastName: \"Doe\",\n                        lineOne: \"123 Main St\",\n                        city: \"London\",\n                        country: \"GB\",\n                        postalCode: \"SW1A 1AA\",\n                    }\n                }\n            }\n        });\n        \n        // Listen to `controller` validation changes\n        // to enable/disable the PAY button based on the validity of the forms\n        controller.on(\"validationChange\", (event) => {\n            payButton.disabled = !event.isValid;\n        });\n\n        // Disable the PAY button when the payment is being processed to prevent multiple submissions\n        payButton.disabled = true;\n\n        // Handle the payment result after attempting payment\n        function handlePaymentResult(result) {\n            spinner.style.display = \"none\";\n            const session = result.paymentSession;\n\n            // Check the payment session status to determine the outcome of the payment\n            // If the status is Approved or Captured, the payment was successful\n            if (session.status === \"Approved\" || session.status === \"Captured\") {\n                console.log(\"Payment Successful\", session);\n                errorDiv.innerHTML = \"<p style='color: green;'>Payment Successful!</p>\";\n                return;\n            }\n\n            // If there is a lastError, display the error message to the user and log the error for debugging\n            if (session.lastError) {\n                payButton.disabled = false;\n                const lastError = session.lastError;\n                const message = result.userFacingErrorMessage;\n                console.error(\"Payment Error\", lastError);\n                errorDiv.innerHTML = `<p style='color: red;'>${message}</p>`;\n            }\n        }\n\n        // Add event listener to the PAY button to handle form submission and attempt payment\n        payButton.addEventListener(\"click\", async (e) => {\n            e.preventDefault();\n\n            errorDiv.innerHTML = \"\";\n            payButton.disabled = true;\n            spinner.style.display = \"block\";\n\n            // Attempt the payment using the card form instance and handle the result\n            try {\n                const result = await cardForm.attemptPayment();\n                handlePaymentResult(result);\n            } catch (error) {\n                spinner.style.display = \"none\";\n                payButton.disabled = false;\n\n                console.error(\"System Error:\", error);\n                errorDiv.innerHTML = \"<p style='color: red;'>An unexpected error occurred.</p>\";\n            }\n        });\n\n        // Mount the card form to the specified container in the HTML\n        cardForm.mount(\"#card-form-container\");\n        // Mount the field collection form to the specified container in the HTML\n        fieldCollectionForm.mount(\"#field-collection-form-container\");\n\n    </script>\n\n</body>\n\n</html>\n","lang":"html"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"next-steps","__idx":6},"children":["Next Steps"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Now that you have successfully integrated field collection into your checkout experience, you can explore additional features and configurations to further customize the payment experience for your customers."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Here are some suggested next steps:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Refer to the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://web-sdk.ryftpay.com/docs/web/latest/interfaces/Web_SDK.RyftFieldCollectionFormConfig.html"},"children":["RyftFieldCollectionFormConfig"]}," documentation for more details on the available configuration options for the field collection form."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Adding support for other payment methods like ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/documentation/get_started/process_payments/embedded_sdk_v3/apple_pay"},"children":["Apple Pay"]}," and ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/documentation/get_started/process_payments/embedded_sdk_v3/google_pay"},"children":["Google Pay"]}," to provide a seamless checkout experience for your customers."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Enabling additional configuration options for the checkout component to further customise the payment form and flow according to your business needs. You can refer to the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/documentation/get_started/process_payments/embedded_sdk_v3/additional_config"},"children":["Additional Configuration"]}," page for more details on the available options and how to use them."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Using the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["checkout"]}," component to easily enable multiple payment methods and additional features all in a single component. You can refer to the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://web-sdk.ryftpay.com/docs/web/latest/documents/checkout.html"},"children":["Checkout Component"]}," page for more details."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Handling SDK errors: Implement comprehensive error handling to manage different types of errors that may occur during the payment process, such as validation errors, network issues, or unexpected system errors. This will help you provide a better user experience and ensure that customers are informed about any issues that arise during checkout. You can refer to the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/documentation/get_started/process_payments/sdk_errors"},"children":["SDK Errors"]}," page for best practices and examples on how to implement effective error handling in your integration."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Webhook handling: Set up webhooks to receive real-time notifications about payment events, such as successful payments, refunds, or chargebacks. This allows you to automate order fulfillment, update inventory, and keep customers informed about their transactions. You can refer to the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/documentation/get_started/webhooks"},"children":["Webhooks documentation"]}," for more details on how to set up and manage webhooks with Ryft."]}]}]},"headings":[{"value":"Field Collection","id":"field-collection","depth":1},{"value":"Overview","id":"overview","depth":2},{"value":"Collect Billing Address","id":"collect-billing-address","depth":2},{"value":"Supply Billing Address Manually","id":"supply-billing-address-manually","depth":3},{"value":"Collect Name on Card","id":"collect-name-on-card","depth":2},{"value":"Complete Example","id":"complete-example","depth":2},{"value":"Next Steps","id":"next-steps","depth":2}],"frontmatter":{"seo":{"title":"Field Collection"}},"lastModified":"2026-03-19T09:26:05.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/documentation/get_started/process_payments/embedded_sdk_v3/field_collection","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}