Skip to content

Flute Elements

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.

Using Flute Elements

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.

Step 1: Loading the flute.js Library

Add the script tag to your checkout page:

<head>
  <script src="https://public.flute.com/lib/v1.0/flute.mjs" type="module"></script>
</head>

Step 2: Building the Payment Form

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.

Creating a Payment Session (backend process)

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-sessions

Production Environment:

POST https://api.flute.com/pay-int-api/payment-sessions

An API token is needed when creating payment sessions. For more information, see Generating an API Token in the API reference guide.

Request Body Parameters:

FieldTypeRequiredDescription
amountnumber
(float)
YesSpecifies the base charge amount. For example, 129.50 for $129.50.
modestringNoSpecifies 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).
referenceIdstringNoSpecifies 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.
skipAddressVerificationbooleanNoSpecifies 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.
tipAmountnumber
(float)
NoSpecifies 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.
customerIdstring (UUID)NoSpecifies 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.

Adding the form wrapper element (front-end process)

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.

Mounting the Flute Elements Form (front-end process)

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.
});

Step 3: Submitting the Form

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);
        }
      },
    },
  });
});
Deprecated method

flute.confirmPayment() is deprecated. Use flute.submit() instead. It has the same interface.

Deprecated parameter

return_url is deprecated. Use submission_callback instead and redirect manually when needed:

submission_callback: () => {
  window.location.href = '/your-success-page';
},

Retrieving the Session Result (backend process)

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}

Error Handling

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:

CodeMessageMeaning
1Something 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.
2An 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.
3Something 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.
4The 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.

Address Verification Service (AVS)

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.

Creating the Elements

After initializing elements with a session ID, use elements.create() to add the cardholder elements before mounting.

Customer Name Element

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' },
});
OptionTypeRequiredDescription
hiddenbooleanNoWhen 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.firstNamestringConditionalCardholder first name. Required when hidden is true. Both firstName and lastName must be provided together.
values.lastNamestringConditionalCardholder last name. Required when hidden is true. Both firstName and lastName must be provided together.

Address Element

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' },
});
OptionTypeRequiredDescription
hiddenbooleanNoWhen 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.zipCodestringConditionalPostal or ZIP code. Required when hidden is true.

Mounting All Elements

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.

Card Vault

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.

Operating Modes

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.

Backend Session Setup for Vaulting

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}.

Front-end Element Setup for Vaulting

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',
});

Label Overrides

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.

OptionDefault ValueShown 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.',
  },
});

Retrieving the Vault Result

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.

Managing Customers and Vaulted Cards

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/customers

Get a specific customer:

GET /v1/customers/{customerId}

List payment methods for a customer:

GET /v1/customers/{customerId}/payment-methods

See the Customers API Reference for full request or response schemas and pagination options.

Customizing the Appearance

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:

PropertyDescription
formBackgroundColorBackground color of the payment form container.
fontFamilyFont family for all text elements.
fontSizeBaseBase font size for input fields
labelColorColor of field labels.
labelAsteriskColorColor of the required field asterisk.
inputTextColorColor of text inside input fields.
inputBorderBorder style for input fields.
inputBackgroundColorBackground color of input fields.
inputBorderRadiusBorder radius of input fields.
inputFocusedBottomBorderColorBottom border color when an input is focused.
inputErrorBackgroundColorBackground color of input fields in an error state.
errorFontSizeFont size for error messages.
errorColorColor of error message text.