Docs
API 2026-05-27.dahlia Dashboard

Payments

The payment form: its methods, layouts, look and options.

The Payment Element is Fluveo's payment form. fluveo.js puts it on your own page, in a frame of Fluveo's, so the card number never reaches your page or your server. The form shows the payment methods of one PaymentIntent, checks what the buyer types and shows each error where it belongs.

Load it with a script tag, or with the two npm packages when you use a bundler or React. Custom checkout builds a whole checkout around it.

The payment form with a test card typed in: the Card tab, then the card number, the expiration date, the security code, the country and the ZIP code.
The form, with a test card typed in

Compatible APIs#

The form works with the PaymentIntents API. Your server creates one PaymentIntent per order with its secret key and gives the page only the client_secret. Accept a payment explains the PaymentIntent and its states, and Custom checkout has the server route to copy.

Your codeThe form
Creates the PaymentIntent on your server and passes its client_secret to fluveo.elements().Reads the PaymentIntent and shows its payment methods.
Mounts the form in a container of your page.Draws its fields in a frame, checks each one and says what to fix.
Calls fluveo.confirmPayment() when the buyer presses your Pay button.Sends the card to Fluveo and confirms the PaymentIntent, through 3D Secure when the card asks for it.
Marks the order paid on the payment_intent.succeeded webhook.Nothing: the page's result is only for the buyer.
Or mounts the form from an amount and a currency, and creates the PaymentIntent when the buyer presses Pay.Shows before a PaymentIntent exists, and confirms the one your code passes then.

The last row is the second way to use the form: see Mount the form before its PaymentIntent.

Payment methods#

The form shows one payment method, the card. It asks for the card number, the expiration date, the security code, the country and, where cards have one, the postal code.

A PaymentIntent's payment_method_types says which methods it accepts. The form reads that list when it mounts and, with a test key, prints it to the browser console, as Test mode describes. Every other method is taken outside the form:

MethodWhere it is taken
CardIn this form, and on the hosted checkout page.
PixYour server creates it and your page shows its code.
BoletoYour server issues it and your page shows its line and its PDF.
Apple PayYour page sends the buyer's approval to Fluveo as a card token.

Layout#

The form lists its payment methods as tabs above the fields, or as an accordion whose open row holds the fields. Choose with the layout option of elements.create("payment").

The same payment form three times, side by side: with tabs, as an accordion with a radio button, and as an accordion without one.
The three layouts

Tabs

Each payment method is a box above the fields, and the open one is outlined. Tabs are the default, so layout can be left out.

checkout.js
const fluveo = Fluveo("pk_test_...");
const elements = fluveo.elements({ clientSecret });
const paymentElement = elements.create("payment", {
  layout: { type: "tabs" },
});
paymentElement.mount("#payment-element");

That is the whole script, once the page has its clientSecret. Custom checkout has the page around it.

The payment form in the tabs layout, empty, as the buyer first sees it on a narrow page.
Tabs

Accordion with radio buttons

The methods are rows, and the open row holds the fields. radios: "always" draws a radio button in each row, also when the form has one method. layout has four parts: type, defaultCollapsed, radios and spacedAccordionItems.

checkout.js
const fluveo = Fluveo("pk_test_...");
const elements = fluveo.elements({ clientSecret });
const paymentElement = elements.create("payment", {
  layout: { type: "accordion", radios: "always" },
});
paymentElement.mount("#payment-element");
The payment form as an accordion: one row with a radio button and the word Card, open, with the card fields inside it.
Accordion with radio buttons

Accordion without radio buttons

radios: "never" leaves the radio button out of every row. An accordion with one method draws none either when layout has no radios.

checkout.js
const fluveo = Fluveo("pk_test_...");
const elements = fluveo.elements({ clientSecret });
const paymentElement = elements.create("payment", {
  layout: { type: "accordion", radios: "never" },
});
paymentElement.mount("#payment-element");
The payment form as an accordion with no radio button: the row Card, open, with the card fields inside it.
Accordion without radio buttons

Appearance#

The form is a frame, so the CSS of your page does not reach it: its look is set in code, with the appearance option of fluveo.elements(). A theme is a whole look with a name. A variable changes one value of the theme, such as the main colour, the font or the corner radius, and every part of the form that uses that value follows it.

The payment form in its three themes, side by side: fluveo is light, night is dark, and flat has filled fields with no border.
The three themes
checkout.js
const fluveo = Fluveo("pk_test_...");
const elements = fluveo.elements({
  clientSecret,
  appearance: {
    theme: "flat",
    variables: { colorPrimary: "#0f766e" },
  },
});
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
The payment form in another theme, with a store's own main colour on the Card tab.
A theme and one variable

Appearance shows each theme and gives every variable's default in each theme.

Options#

Every option is optional: the form works with clientSecret alone. appearance, locale and loader go to fluveo.elements(). layout, fields and defaultValues go to elements.create("payment").

checkout.js
const fluveo = Fluveo("pk_test_...");
const elements = fluveo.elements({
  clientSecret,
  locale: "en",
  loader: "always",
});
const paymentElement = elements.create("payment", {
  layout: "accordion",
  defaultValues: { billingDetails: { address: { country: "CA" } } },
});
paymentElement.mount("#payment-element");
OptionWhat it does
appearanceSets the theme and the variables of the form's look.
localeSets the language of the form. Left out, it follows the buyer's browser.
loaderShows or hides the placeholder while the form loads.
layoutLists the payment methods as tabs or as an accordion.
fieldsHides the country or the postal code when your page already asked for it.
defaultValuesSets the country and the postal code the form opens with.

Errors#

The form shows the buyer's errors by itself, each one once:

  • a field that is incomplete or not valid, or that the API refused, under that field;
  • a declined card, right under the card number;
  • a form that could not load, in place of the fields.

With inputs: "condensed" in appearance, the fields are joined in one block, and the errors of the fields and of the card show under it: the fields' in their order, then the card's.

Its messages are in English and in Brazilian Portuguese, as locale picks. Where the form has no sentence of its own, it shows the API's message.

Your code reads the rest: confirmPayment() resolves with the error object, and Errors lists the API's codes. The form shows no message when the answer to a payment did not come back, so show that error's message on your page. A mistake in your code throws at the call; one the form learns only at the press, such as currency_mismatch, resolves as { error } of the type invalid_request_error. The options throw option_not_supported, appearance_value_invalid and billing_details_missing.

Type a test card into the form to see a decline or 3D Secure.

With other elements#

The Payment Element is the one element of fluveo.js: elements.create() takes "payment" and no other name. The rest of the checkout is your own page: the e-mail field, the address, the cart and the Pay button.

Pass what your page already knows about the buyer:

Your page hasPass it as
The buyer's name, e-mail or phoneconfirmParams, in the billing_details of payment_method_data.
The country or the postal code, asked in your own address fieldsThe address of that billing_details, with that field set to "never" in fields so the form does not ask again.
A country or a postal code to start fromdefaultValues. The buyer may still change it.

Move from the hosted checkout#

Hosted checkout sends the buyer to a page of Fluveo's. Move when the payment belongs inside your own page: your layout around the form, your cart beside it, and a declined card that leaves the buyer where they are. The hosted page also shows Pix and Boleto, so keep it for an order paid that way.

Your server keeps its secret key, its Idempotency-Key and its webhook endpoint. It creates a PaymentIntent in place of a Checkout Session, gives the page the client_secret and marks the order paid on payment_intent.succeeded, which a session's payment already sends. Your page gains the form and the calls that mount it and confirm the payment: Custom checkout has every file.