Flute Elements is a drop-in JavaScript library that embeds PCI-compliant payment fields directly into your checkout page. It lets you collect card details without sensitive data ever touching your servers, as the embedded elements are securely rendered and managed by Flute's infrastructure.
Flute Elements renders secure, isolated payment input fields, such as card number, expiry, and CVV, inside your page by iframes managed by the flute.js library. This means:
- PCI-DSS compliance. Card data is captured and transmitted through Flute's secure infrastructure, not your servers.
- Custom user experience. You control the flow after submission, either by handling the result inline with a callback or redirecting the customer to a custom result page.
- Full styling control. Customize fonts, colors, borders, and layout to match your branding.
The integration with Flute Elements follows three steps:
- Step 1: Loading the flute.js library into your checkout page.
- Step 2: Building the payment form using a payment session identifier from your backend.
- Step 3: Submitting the form and retrieving the result from your backend.
Add the script tag to your checkout page:
<head>
<script src="https://public.flute.com/lib/v1.0/flute.mjs" type="module"></script>
</head>To build the payment form, you need to create a payment session from your backend process and then initialize the Flute Elements form in the front-end using the session ID.
Your backend process must create a payment session before initializing the Flute Elements form in the front-end. To create the session, call the payment session endpoint from your backend processer.
Sandbox Environment:
POST https://sandbox.api.flute.com/pay-int-api/payment-sessionsProduction Environment:
POST https://api.flute.com/pay-int-api/payment-sessionsAn API token is needed when creating payment sessions. For more information, see Generating an API Token in the API reference guide.
Request Body Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
| amount | number (float) | Yes | Specifies the base charge amount. For example, 129.50 for $129.50. |
| mode | string | No | Specifies what the session is allowed to do. Omit or set to null to use the default. Accepted values:• "Payment" (default) — processes a payment without storing the card.• "PaymentAndSave" — processes a payment and optionally or mandatorily stores the card.• "SaveMethod" — stores the card in the vault without processing a payment (requires amount: 0). |
| referenceId | string | No | Specifies the merchant-supplied identifier (max 100 characters) used for duplicate payment detection. When provided, payments with the same referenceId within the duplicate-detection window are rejected. Omit or set to null when not needed. |
| skipAddressVerification | boolean | No | Specifies using the AVS (address verification) system checks for this session. If true, skips the AVS system checks.If false, use the AVS system checks.The default is false. |
| tipAmount | number (float) | No | Specifies the tip amount charged on top of the base amount For example, 5.00 for $5.00. Omit or set to null when no tip applies. Only accepted when tips are enabled for the merchant. |
| customerId | string (UUID) | No | Specifies the customer identifier to associate vault entries with. Only relevant for vault-enabled sessions (SaveMethod or PaymentAndSave).• If omitted, a new customer is created automatically and the resulting customerId is returned in the confirm response through GET /pay-int-api/payment-sessions/{paymentSessionId}. Store it to reuse in future sessions.• If provided, the new payment method is vaulted under that existing customer. |
The following is a sample request for the sandbox environment.
curl -X POST 'https://sandbox.api.flute.com/pay-int-api/payment-sessions' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <ACCESS_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{
"amount": 129.50,
"mode": "PaymentAndSave",
"referenceId": "order-8675309",
"skipAddressVerification": false,
"tipAmount": 5.00,
"customerId": "123e4567-e89b-12d3-a456-426614174000"
}'The following is a sample response from the previous call.
{
"id": "0cdddcb6-fa98-4c46-b096-a2723b56c750"
}The payment session endpoint response contains the session identifier in the id field). The front-end process uses this value to initialize the form.
Add a wrapper element that will contain the Flute Elements embedded form. You can also add a submit button or use your existing checkout button to trigger the form submission.
<div id="flute-payment-form"></div>
<button id="flute-payment-submit-btn">Pay</button>The Flute Elements will render the payment fields inside the #flute-payment-form wrapper element. The tag IDs (#flute-payment-form and #flute-payment-submit-btn) can be customized, but they must match the IDs used in the mounting and event listener steps below.
Pass the session identifier (the id field returned by the backend process) to Flute Elements and mount the payment element.
const flute = new window.Flute();
const elements = flute.elements({
sessionId: 'SESSION_ID', // Requested - Payment session identifier from your backend process.
appearance: {}, // Optional — See Customizing the Appearance below.
});
const paymentElement = elements.create('payment');
paymentElement.mount({
component: 'flute-payment-form', // Identifier of the wrapper element in your page.
});Attach a click handler to your submit button.
const submitButton = document.getElementById('flute-payment-submit-btn');
submitButton.addEventListener('click', () => {
flute.submit({
confirmParams: {
submission_callback: () => {
// Payment interaction complete.
// Call your backend process to `GET /pay-int-api/payment-sessions/{flute_session_id}`
// to retrieve the transaction result.
},
error_callback: (message, code) => {
alert(message);
// If code is 3 or 4, generate a new payment session identifier from your backend process and refresh the form
if (code === 3 || code === 4) {
// Session is consumed, generate a new one and update the form
const newSessionId = 'NEW_SESSION_ID_FROM_BACKEND';
flute.updateSessionId(newSessionId);
}
},
},
});
});flute.confirmPayment() is deprecated. Use flute.submit() instead. It has the same interface.
return_url is deprecated. Use submission_callback instead and redirect manually when needed:
submission_callback: () => {
window.location.href = '/your-success-page';
},Always retrieve the Session Result from your backend process. Never trust the front-end process for session status or results, as it can be spoofed and manipulated.
After the customer completes the form submission, your backend process must call the Payment Session endpoint to get the actual status and details. This will return one of the following session statuses: Created, Completed, Cancelled or Failed. The response will also contain more information about the session, such as transaction or customer details.
GET /pay-int-api/payment-sessions/{flute_session_id}When a payment submission fails, the error_callback front-end callback method receives a message and the numeric error code. For error codes 1 and 2 the session has not been consumed and it can be retried, but for error codes 3 and 4, the session is consumed and cannot be reused. In this case, you need to generate a new session identifier from the backend process and call flute.updateSessionId(newSessionId) to retry.
Error Codes:
| Code | Message | Meaning |
|---|---|---|
| 1 | Something went wrong, check payment details and try again. | The payment was not submitted due to a validation error such as invalid BIN (card number) or duplicate transaction identified in a short time frame. Session remains open for new payment attempts. |
| 2 | An integration problem has been detected. Contact the administrator. | Integration or server-side error. Session stays open for retry. Recommended to review the payload data and mounted elements before retrying. |
| 3 | Something went wrong, check the payment session identifier and try again. | Invalid or expired payment session identifier. Generate a new payment session identifier from your backend process and update the form. |
| 4 | The payment could not be completed. Check payment details and try again. | Transaction declined, such as insufficient funds or an incorrect CVV. Generate a new payment session identifier to retry. |
AVS (address verification service) is a system that verifies the cardholder's billing address with the card issuer. It attempts to reduce fraud and improve transaction approval rates.
Flute Elements can collect cardholder name and ZIP Code and postal codes through dedicated elements that you create alongside the payment element. Each element supports a hidden option to control visibility and a values option to set predefined values to these fields.
After initializing elements with a session ID, use elements.create() to add the cardholder elements before mounting.
Collects the cardholder's first and last name.
// Visible — fields are shown empty for the customer to fill in
elements.create('customer-name');
// Visible and Pre-filled — fields are shown pre-filled; the customer can edit them
elements.create('customer-name', {
values: { firstName: 'John', lastName: 'Doe' },
});
// Hidden — values are submitted without displaying the fields
elements.create('customer-name', {
hidden: true,
values: { firstName: 'John', lastName: 'Doe' },
});| Option | Type | Required | Description |
|---|---|---|---|
| hidden | boolean | No | When true, the fields are not rendered in the UI. When false (or omitted), values act as optional defaults the customer can override. Defaults to false. |
| values.firstName | string | Conditional | Cardholder first name. Required when hidden is true. Both firstName and lastName must be provided together. |
| values.lastName | string | Conditional | Cardholder last name. Required when hidden is true. Both firstName and lastName must be provided together. |
Collects the cardholder's billing address for AVS (address verification service) verification.
// Visible — field is shown pre-filled; the customer can edit it
elements.create('address', {
values: { zipCode: '12345' },
});
// Hidden — value is submitted without displaying the field
elements.create('address', {
hidden: true,
values: { zipCode: '12345' },
});| Option | Type | Required | Description |
|---|---|---|---|
| hidden | boolean | No | When true, the field is not rendered in the UI. When false (or omitted), values acts as the default input value, which the customer can override. Defaults to false. |
| values.zipCode | string | Conditional | Postal or ZIP code. Required when hidden is true. |
After creating the payment, customer-name, and address elements, mount them all into a single secure iframe. You can create the elements in any order.
const flute = new window.Flute();
const elements = flute.elements({
sessionId: 'SESSION_ID',
appearance: {},
});
elements.create('customer-name');
elements.create('payment');
elements.create('address');
elements.mount('#flute-payment-form');Elements are rendered in the order they are created. If address is created before payment, the address fields will appear above the payment fields in the form. Adjust the order of your elements.create() calls to control the layout.
Flute Elements supports saving a card to the customer vault in addition to, or instead of, processing an immediate payment. The vault mode is controlled by the saveMethod option when creating the payment element, and by the mode set at session creation time on your backend.
The mode field (set when creating the session on the backend) and saveMethod (set on the front-end element) must be used together. The table below shows the valid combinations and their behavior.
mode (backend) | saveMethod (front-end) | Behavior |
|---|---|---|
"Payment" (default) | (not applicable) | Processes the payment only. Card is not stored. |
"SaveMethod" | "vaultOnly" | Stores the card in the vault without charging. A disclosure notice is shown. If no customerId is provided, a new customer record is created automatically. |
"PaymentAndSave" | "askConsent" | Processes the payment. A checkbox lets the customer opt-in to saving their card. |
"PaymentAndSave" | "implicit" | Processes the payment and always saves the card. A disclosure notice is shown. |
Payment session (default)
curl -X POST '.../pay-int-api/payment-sessions' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"amount": 129.50
}'Payment with optional or mandatory vaulting
curl -X POST '.../pay-int-api/payment-sessions' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"amount": 129.50,
"mode": "PaymentAndSave"
}'Vault-only card storage
curl -X POST '.../pay-int-api/payment-sessions' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"amount": 0,
"mode": "SaveMethod",
"customerId": "CUSTOMER_ID"
}'For vault-only sessions, the amount must be 0. Optionally provide a customerId to attach the card to an existing customer record. If omitted, a new customer record is created automatically. The resulting customerId can be retrieved with GET /pay-int-api/payment-sessions/{paymentSessionId}.
Set saveMethod when calling elements.create('payment', options):
// For Session mode "PaymentAndSave":
// Payment with optional vaulting — shows an opt-in checkbox
const paymentElement = elements.create('payment', {
saveMethod: 'askConsent',
});
// Payment with mandatory vaulting — shows a disclosure
const paymentElement = elements.create('payment', {
saveMethod: 'implicit',
});
// For Session mode "SaveMethod":
// Vault-only — shows a disclosure, no payment is processed
const paymentElement = elements.create('payment', {
saveMethod: 'vaultOnly',
});When using askConsent, implicit, or vaultOnly save methods, Flute Elements displays a checkbox or disclosure to inform the customer about card vaulting.
The checkbox label (for "askConsent") and the disclosure label (for "implicit" and "vaultOnly") can be overridden with the labels option. Values must not be empty strings.
| Option | Default Value | Shown for |
|---|---|---|
labels.saveConsent | "Save this card for future payments." | saveMethod: "askConsent" |
labels.disclosure | "This card will be saved for future payments." | saveMethod: "implicit" and saveMethod: "vaultOnly" |
Example with custom checkbox label:
const paymentElement = elements.create('payment', {
saveMethod: 'askConsent',
labels: {
saveConsent: 'Remember my card for next time.',
},
});To get the vaulted payment method identifier and customer identifier, you can retrieve these values by calling GET /pay-int-api/payment-sessions/{flute_session_id} from your backend.
Once a card is stored, your backend process can manage customers and their saved payment methods through the Customer API.
List your customers:
GET /v1/customersGet a specific customer:
GET /v1/customers/{customerId}List payment methods for a customer:
GET /v1/customers/{customerId}/payment-methodsSee the Customers API Reference for full request or response schemas and pagination options.
Flute Elements supports custom theming through the appearance option to make the form match your brand and design.
const elements = flute.elements({
sessionId: sessionId,
appearance: {
elements: {
formBackgroundColor: '#e1e9eb',
fontFamily: 'Verdana, sans-serif',
fontSizeBase: '16px',
labelColor: '#107b92',
labelAsteriskColor: '#0000ff',
inputTextColor: '#107b92',
inputBorder: 'none',
inputBackgroundColor: '#c8d6d9',
inputBorderRadius: '6px',
inputFocusedBottomBorderColor: '#107b92',
inputErrorBackgroundColor: '#ecc9c9',
errorFontSize: '14px',
errorColor: '#cd2424',
},
},
});Available Appearance Properties:
| Property | Description |
|---|---|
| formBackgroundColor | Background color of the payment form container. |
| fontFamily | Font family for all text elements. |
| fontSizeBase | Base font size for input fields |
| labelColor | Color of field labels. |
| labelAsteriskColor | Color of the required field asterisk. |
| inputTextColor | Color of text inside input fields. |
| inputBorder | Border style for input fields. |
| inputBackgroundColor | Background color of input fields. |
| inputBorderRadius | Border radius of input fields. |
| inputFocusedBottomBorderColor | Bottom border color when an input is focused. |
| inputErrorBackgroundColor | Background color of input fields in an error state. |
| errorFontSize | Font size for error messages. |
| errorColor | Color of error message text. |