Pay
Payment Form

Building Custom Payment Forms

Learn how to create fully-customized payment forms with secure input fields


The Payment Form SDK provides secure, PCI-compliant input fields that you can embed into custom-built payment forms. Unlike drop-in checkout solutions, the Payment Form gives you complete control over your form's HTML, styling, and user experience while keeping sensitive payment data secure through isolated secure input fields.

Prerequisites

Before building payment forms, it's helpful to learn about the following topics.


When to Use Payment Forms


Use the Payment Form SDK when you need complete control over your checkout form's design and user experience while maintaining PCI compliance. The SDK provides secure input fields that handle sensitive card and bank account data, isolating this data from your application while giving you full control over the surrounding UI, layout, and styling.

Common use cases

  • Custom-Branded Checkout: Build checkout experiences that perfectly match your brand guidelines and design system
  • Complex Form Layouts: Create multi-step checkout flows or custom field arrangements
  • Integrated Checkout Flows: Embed payment fields directly within existing forms alongside shipping, billing, and order details
  • Multi-Language Forms: Build fully localized checkout experiences with custom labels and error messages

How Payment Forms Work


Payment Forms use a combination of regular HTML inputs and secure input fields:

  1. Secure Input Fields: Sensitive data like card numbers, CVV, and bank account numbers are rendered in isolated iframes that communicate with Payload's secure environment. These fields appear as <div> elements with special attributes.

  2. Regular Input Fields: Non-sensitive data like amount, description, and billing address use standard HTML <input> elements with special attributes to identify them to the SDK.

  3. Form Submission: When the form is submitted, the SDK collects data from both secure and regular fields, sends sensitive data directly to Payload's servers, and returns a transaction ID or payment method ID to your application.

Building a Payment Form


Creating a payment form requires three steps: building the HTML form, creating an intent on your backend, and initializing the form with JavaScript.

import payload
pl = payload.Session('secret_key_3bW9...', api_version='v2')
 
from flask import Flask, jsonify
 
app = Flask(__name__)
 
@app.route('/payment-form-intent', methods=['POST'])
def create_payment_intent():
    # Create a payment form intent
    intent = pl.Intent.create(
        type='payment_form',
        payment_form={
            'payment_template': {
                'amount': 100.00,
                'description': 'Order #12345',
                'receiver': {
                    'account_id': 'acct_receiver123'
                }
            }
        }
    )
 
    # Send the token to your frontend
    return jsonify({'token': intent.token})
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Payment Form - Vanilla JS</title>
  <script src="https://payload.com/Payload.js"></script>
</head>
<body>
  <form id="payment-form" pl-form="payment">
    <!-- Hidden payment details -->
    <input type="hidden" pl-input="amount" value="100.00">
    <input type="hidden" pl-input="description" value="Order #12345">
 
    <!-- Card input field (combined) -->
    <label>Card Details</label>
    <div pl-input="card" class="card-input"></div>
 
    <!-- Billing information -->
    <label>Cardholder Name</label>
    <input type="text" pl-input="account_holder" placeholder="John Doe">
 
    <label>Postal Code</label>
    <input type="text" pl-input="billing_address[postal_code]" placeholder="12345">
 
    <button type="submit">Pay Now</button>
  </form>
 
  <script src="payment-form.js"></script>
</body>
</html>
// Fetch token from backend
fetch('/payment-form-intent')
  .then(r => r.json())
  .then(data => {
    // Initialize Payload with token
    Payload(data.token);
 
    // Create the form
    const form = new Payload.Form(document.getElementById('payment-form'));
 
    // Handle successful payment
    form.on('processed', (evt) => {
      console.log('Payment successful!', evt.transaction_id);
      window.location.href = `/payment/success?txn=${evt.transaction_id}`;
    });
 
    // Handle payment errors
    form.on('error', (evt) => {
      console.error('Payment failed:', evt.message);
      alert(`Payment failed: ${evt.message}`);
    });
  })
  .catch(err => console.error('Failed to load payment form:', err));

This example shows the complete flow for building a custom payment form:

  1. Backend: Create an intent with type='payment_form' and configure payment details
  2. Frontend HTML: Build your form with pl-form="payment" attribute and secure input fields using pl-input attributes
  3. Frontend JavaScript: Initialize with Payload(token) and new Payload.Form(formElement), or use React components like <PaymentForm>, <CardNumber>, <Expiry>, and <CardCode>
  4. Event Handling: Listen for success or declined events (or use React props like onSuccess, onDeclined)

The secure input fields (pl-input="card" or individual fields like pl-input="card_number") render as iframes that capture sensitive data without exposing it to your application.

Secure Input Fields


The Payment Form SDK provides secure input components for capturing sensitive payment data. These fields are rendered as isolated iframes that communicate directly with Payload's secure environment.

Card Input Fields

Use a single combined card input

The combined card input provides all card fields in one input element:

<!DOCTYPE html>
<html>
<head>
  <script src="https://payload.com/Payload.js"></script>
</head>
<body>
  <form id="payment-form" pl-form="payment">
    <input type="hidden" pl-input="amount" value="100" />
    <!-- Single combined card input -->
    <label>Card Details</label>
    <div pl-input="card"></div>
 
    <!-- Postal code field -->
    <label>Postal Code</label>
    <input pl-input="billing_address[postal_code]" placeholder="12345" />
 
    <button type="submit">Pay Now</button>
  </form>
 
  <script src="single-card.js"></script>
</body>
</html>
Payload('your_token');
new Payload.Form(document.getElementById('payment-form'));

This creates a single input field that accepts card number, expiration, and CVV in a combined interface. This is the simplest option for card payments.

Use individual card input fields

Individual card fields give you more control over layout:

<!DOCTYPE html>
<html>
<head>
  <script src="https://payload.com/Payload.js"></script>
</head>
<body>
  <form id="payment-form" pl-form="payment">
    <input type="hidden" pl-input="amount" value="100.00">
 
    <!-- Individual card input fields -->
    <label>Card Number</label>
    <div pl-input="card_number"></div>
 
    <label>Expiration</label>
    <div pl-input="expiry"></div>
 
    <label>CVC</label>
    <div pl-input="card_code"></div>
 
    <button type="submit">Pay Now</button>
  </form>
 
  <script src="split-card.js"></script>
</body>
</html>
Payload('your_token');
new Payload.Form(document.getElementById('payment-form'));

This creates three separate input fields for card number, expiration, and CVV, allowing you to arrange them in custom layouts.

Use Google Pay for checkout

Google Pay allows customers to pay using cards stored in their Google account:

<!DOCTYPE html>
<html>
<head>
  <script src="https://payload.com/Payload.js"></script>
  <script src="https://pay.google.com/gp/p/js/pay.js"></script>
</head>
<body>
  <form id="payment-form" pl-form="payment">
    <label>Amount</label>
    <input type="number" pl-input="amount" value="100.00" required />
 
    <label>Description</label>
    <input type="text" pl-input="description" value="Purchase" required />
 
    <label>Account Holder Name</label>
    <input type="text" pl-input="account_holder" required />
 
    <label>Billing ZIP Code</label>
    <input type="text" pl-input="billing_address[postal_code]" required />
 
    <div id="google-pay-button"></div>
  </form>
 
  <script src="googlepay.js"></script>
</body>
</html>
// Fetch client token from your server
fetch('/payment-form-intent', { method: 'POST' })
  .then(res => res.json())
  .then(data => {
    // Initialize Payload with the client token
    Payload(data.token)
 
    // Initialize the payment form
    const form = new Payload.Form(document.getElementById('payment-form'))
 
    // Create Google Pay button
    const paymentsClient = new google.payments.api.PaymentsClient({
      environment: 'PRODUCTION' // Use 'TEST' for testing
    })
 
    const button = paymentsClient.createButton({
      onClick: () => {} // Handled by Payload.googlepay
    })
 
    document.getElementById('google-pay-button').appendChild(button)
 
    // Activate Google Pay on the button
    form.googlepay(button, function(active) {
      if (!active) {
        // Google Pay is not available on this device
        button.style.display = 'none'
        console.log('Google Pay is not available')
      }
    })
 
    // Handle successful payment
    form.on('processed', (evt) => {
      console.log('Payment processed:', evt.transaction_id)
      window.location.href = `/payment/success?txn=${evt.transaction_id}`
    })
 
    // Handle declined payment
    form.on('declined', (evt) => {
      console.error('Payment declined:', evt.message)
      alert('Payment declined. Please try a different payment method.')
    })
 
    // Handle errors
    form.on('error', (evt) => {
      console.error('Error:', evt.message)
      alert('Payment failed: ' + evt.message)
    })
  })

This creates a Google Pay button that opens Google's payment sheet. When the customer selects a card from their Google Pay wallet and confirms, the payment is processed immediately. The .googlepay() method activates the button and includes a callback to detect if Google Pay is available on the device.

Use Apple Pay for checkout

Apple Pay allows customers to pay using cards stored in their Apple Wallet:

<!DOCTYPE html>
<html>
<head>
  <script src="https://payload.com/Payload.js"></script>
  <style>
    .apple-pay-button {
      -webkit-appearance: -apple-pay-button;
      -apple-pay-button-type: plain;
      -apple-pay-button-style: black;
      width: 100%;
      height: 44px;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <form id="payment-form" pl-form="payment">
    <label>Amount</label>
    <input type="number" pl-input="amount" value="100.00" required />
 
    <label>Description</label>
    <input type="text" pl-input="description" value="Purchase" required />
 
    <label>Account Holder Name</label>
    <input type="text" pl-input="account_holder" required />
 
    <label>Billing ZIP Code</label>
    <input type="text" pl-input="billing_address[postal_code]" required />
 
    <div id="apple-pay-button" class="apple-pay-button"></div>
  </form>
 
  <script src="applepay.js"></script>
</body>
</html>
// Fetch client token from your server
fetch('/payment-form-intent', { method: 'POST' })
  .then(res => res.json())
  .then(data => {
    // Initialize Payload with the client token
    Payload(data.token)
 
    // Initialize the payment form
    const form = new Payload.Form(document.getElementById('payment-form'))
 
    // Get the Apple Pay button element
    const button = document.getElementById('apple-pay-button')
 
    // Activate Apple Pay on the button
    form.applepay(button, function(active) {
      if (!active) {
        // Apple Pay is not available on this device
        button.style.display = 'none'
        console.log('Apple Pay is not available')
      }
    })
 
    // Handle successful payment
    form.on('processed', (evt) => {
      console.log('Payment processed:', evt.transaction_id)
      window.location.href = `/payment/success?txn=${evt.transaction_id}`
    })
 
    // Handle declined payment
    form.on('declined', (evt) => {
      console.error('Payment declined:', evt.message)
      alert('Payment declined. Please try a different payment method.')
    })
 
    // Handle errors
    form.on('error', (evt) => {
      console.error('Error:', evt.message)
      alert('Payment failed: ' + evt.message)
    })
  })

This creates an Apple Pay button that opens Apple's payment sheet. When the customer authorizes with Face ID, Touch ID, or passcode, the payment is processed immediately. The .applepay() method activates the button and includes a callback to detect if Apple Pay is available on the device.

Bank Account Input Fields

Use manual bank account entry

Manually enter routing number and account number for bank payments:

<!DOCTYPE html>
<html>
<head>
  <script src="https://payload.com/Payload.js"></script>
</head>
<body>
  <form id="payment-form" pl-form="payment">
    <input type="hidden" pl-input="amount" value="100.00">
 
    <!-- Bank account input fields -->
    <label>Routing Number</label>
    <div pl-input="routing_number"></div>
 
    <label>Account Number</label>
    <div pl-input="account_number"></div>
 
    <label>Account Type</label>
    <select pl-input="account_type">
      <option value="checking" selected>Checking</option>
      <option value="savings">Savings</option>
    </select>
 
    <label>Account Holder Name</label>
    <input type="text" pl-input="account_holder" placeholder="John Doe">
 
    <button type="submit">Pay Now</button>
  </form>
 
  <script src="bank-account.js"></script>
</body>
</html>
Payload('your_token');
new Payload.Form(document.getElementById('payment-form'));

This creates secure input fields for routing number and account number, along with selects for account type (checking/savings) for bank payments.

Use Plaid for instant bank payment

Plaid allows customers to pay using their bank account by logging into their bank:

<!DOCTYPE html>
<html>
<head>
  <script src="https://payload.com/Payload.js"></script>
</head>
<body>
  <form id="payment-form" pl-form="payment">
    <label>Amount</label>
    <input type="number" pl-input="amount" value="100.00" required />
 
    <label>Description</label>
    <input type="text" pl-input="description" value="Purchase" required />
 
    <label>Account Holder Name</label>
    <input type="text" pl-input="account_holder" required />
 
    <button type="button" id="plaid-button">
      Pay with Bank Account via Plaid
    </button>
  </form>
 
  <script src="plaid.js"></script>
</body>
</html>
// Fetch client token from your server
fetch('/payment-form-intent', { method: 'POST' })
  .then(res => res.json())
  .then(data => {
    // Initialize Payload with the client token
    Payload(data.token)
 
    // Initialize the payment form
    const form = new Payload.Form(document.getElementById('payment-form'))
 
    // Get the Plaid button element
    const plaidButton = document.getElementById('plaid-button')
 
    // Activate Plaid on the button
    form.plaid(plaidButton)
 
    // Handle successful payment
    form.on('processed', (evt) => {
      console.log('Payment processed:', evt.transaction_id)
      window.location.href = `/payment/success?txn=${evt.transaction_id}`
    })
 
    // Handle declined payment
    form.on('declined', (evt) => {
      console.error('Payment declined:', evt.message)
      alert('Payment declined. Please try a different payment method.')
    })
 
    // Handle errors
    form.on('error', (evt) => {
      console.error('Error:', evt.message)
      alert('Payment failed: ' + evt.message)
    })
  })

This creates a button that opens Plaid's Link interface. When the customer selects their bank and logs in, the payment is processed immediately using their connected bank account. The .plaid() method activates the button and includes a callback to detect if Plaid is available and configured.

Regular Input Fields


Non-sensitive data uses standard HTML inputs with pl-input attributes. These fields can be any HTML input type and are used for payment details, billing information, and custom data.

Payment Details

<!DOCTYPE html>
<html>
<head>
  <script src="https://payload.com/Payload.js"></script>
</head>
<body>
  <form id="payment-form" pl-form="payment">
    <!-- Payment detail fields -->
    <input type="hidden" pl-input="amount" value="100.00">
    <input type="hidden" pl-input="description" value="Order #12345">
 
    <!-- Card input -->
    <div pl-input="card"></div>
 
    <button type="submit">Pay Now</button>
  </form>
 
  <script src="payment-details.js"></script>
</body>
</html>
Payload('your_token');
new Payload.Form(document.getElementById('payment-form'));

Common payment detail fields:

  • amount - Payment amount
  • description - Payment description
  • processing_id - Processing account ID (for routing payments to specific accounts)

Billing Information

<!DOCTYPE html>
<html>
<head>
  <script src="https://payload.com/Payload.js"></script>
</head>
<body>
  <form id="payment-form" pl-form="payment">
    <input type="hidden" pl-input="amount" value="100.00">
 
    <!-- Card input -->
    <div pl-input="card"></div>
 
    <!-- Billing information fields -->
    <label>Cardholder Name</label>
    <input type="text" pl-input="account_holder" placeholder="John Doe">
 
    <label>Postal Code</label>
    <input type="text" pl-input="billing_address[postal_code]" placeholder="12345">
 
    <label>Street Address</label>
    <input type="text" pl-input="billing_address[street_address]" placeholder="123 Main St">
 
    <label>City</label>
    <input type="text" pl-input="billing_address[city]" placeholder="San Francisco">
 
    <label>State</label>
    <input type="text" pl-input="billing_address[state_province]" placeholder="CA">
 
    <button type="submit">Pay Now</button>
  </form>
 
  <script src="billing-info.js"></script>
</body>
</html>
Payload('your_token');
new Payload.Form(document.getElementById('payment-form'));

Common billing fields:

  • account_holder - Name on card/account
  • billing_address[postal_code] - Postal/ZIP code
  • billing_address[line1] - Street address
  • billing_address[city] - City
  • billing_address[state] - State/province
  • billing_address[country] - Country code

Customer Information

For linking payments to customer accounts:

<!DOCTYPE html>
<html>
<head>
  <script src="https://payload.com/Payload.js"></script>
</head>
<body>
  <form id="payment-form" pl-form="payment">
    <input type="hidden" pl-input="amount" value="100.00">
 
    <div pl-input="card"></div>
 
    <button type="submit">Pay Now</button>
  </form>
 
  <script src="customer-info.js"></script>
</body>
</html>
fetch('/payment-form-intent')
  .then(r => r.json())
  .then(data => {
    Payload(data.token);
 
    const form = new Payload.Form(document.getElementById('payment-form'));
 
    form.on('processed', (evt) => {
      console.log('Payment successful!', evt.transaction_id);
    });
 
    form.on('error', (evt) => {
      console.error('Payment failed:', evt.message);
    });
  });

Use customer_id or account_id to associate the payment with an existing customer account.

Handling Form Events


The Payment Form SDK emits events throughout the payment lifecycle. Listen for these events to handle successful payments, errors, and validation.

Success Events

form.on('success', (evt) => {
  console.log('Payment successful:', evt.transaction_id)
  window.location.href = `/payment/success?txn=${evt.transaction_id}`
})

Error Events

form.on('declined', (evt) => {
  console.error('Payment declined:', evt.message)
  alert('Your payment was declined. Please try a different payment method.')
})
 
form.on('error', (evt) => {
  console.error('Payment error:', evt.message)
  alert(`Payment failed: ${evt.message}`)
})

Validation Events

form.on('invalid', (evt) => {
  console.log('Invalid:', evt.message)
  if (evt.target) evt.target.classList.add('pl-invalid')
})
 
form.on('valid', (evt) => {
  if (evt.target) evt.target.classList.remove('pl-invalid')
})

Styling Secure Input Fields


You can style secure input fields to match your form's design using several approaches. While secure inputs are rendered in isolated iframes for PCI compliance, the SDK provides multiple ways to apply custom styling.

Extend Payload Classes

Style secure inputs by targeting Payload's default CSS classes:

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="./styles.css">
</head>
<body>
  <form id="payment-form" pl-form="payment">
    <input pl-input="amount" type="hidden" value="100.00">
 
    <!-- Secure inputs will automatically use the pl-* classes -->
    <div>
      <label>Card Number</label>
      <div pl-input="card_number"></div>
    </div>
 
    <div>
      <label>Expiration</label>
      <div pl-input="expiry"></div>
    </div>
 
    <div>
      <label>CVC</label>
      <div pl-input="card_code"></div>
    </div>
 
    <button type="submit">Pay Now</button>
  </form>
 
  <script src="https://payload.com/Payload.js"></script>
  <script src="style-extend-classes.js"></script>
</body>
</html>
Payload('your_token')
 
new Payload.Form({ form: document.getElementById('payment-form') })
/* Extend Payload's default classes */
.pl-input {
  color: #495057;
  background-color: #fff;
  border: 1px solid #ced4da;
  padding: .375rem .75rem;
  border-radius: .25rem;
  outline: none;
}
 
.pl-input-sec {
  /* Additional styles for secure fields */
  font-family: Arial, sans-serif;
  font-size: 16px;
}
 
.pl-focus {
  border-color: #80bdff;
  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
 
.pl-invalid {
  border-color: #dc3545;
  box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}

Payload provides default classes that you can extend with custom CSS rules:

  • pl-input - Base input styling
  • pl-input-sec - Secure field styling
  • pl-focus - Focused input state
  • pl-invalid - Invalid input state

Override Default Classes

Replace Payload's default classes with your own:

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="./custom-styles.css">
</head>
<body>
  <form id="payment-form" pl-form="payment">
    <input pl-input="amount" type="hidden" value="100.00">
 
    <div>
      <label>Card Number</label>
      <div class="custom-input" pl-input="card_number"></div>
    </div>
 
    <div>
      <label>Expiration</label>
      <div class="custom-input" pl-input="expiry"></div>
    </div>
 
    <div>
      <label>CVC</label>
      <div class="custom-input" pl-input="card_code"></div>
    </div>
 
    <button type="submit">Pay Now</button>
  </form>
 
  <script src="https://payload.com/Payload.js"></script>
  <script src="style-override-classes.js"></script>
</body>
</html>
Payload('your_token')
 
new Payload.Form({
  form: document.getElementById('payment-form'),
  // Override default Payload class names with custom ones
  styles: {
    invalid: 'custom-invalid',
    focus: 'custom-focus'
  }
})
.custom-input {
  padding: .375rem .75rem;
  border: 1px solid #ced4da;
  border-radius: .25rem;
  font-size: 1rem;
}
 
.custom-invalid {
  border-color: #dc3545;
  background-color: #fff5f5;
}
 
.custom-focus {
  border-color: #80bdff;
  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}

This is useful when integrating with CSS frameworks like Bootstrap or Tailwind.

Schema Reference


The following fields are available when configuring the Payment Form intent:

Intent Configuration

Configuration options passed when creating the payment form intent on your backend. For complete API reference, see Intents API Reference.

payment_form
object
Configuration for the payment form intent. Use this type to create a native payment collection form in your application using the Payload JavaScript SDK. The payment form allows customers to enter payment details and complete a transaction. Returns a token for rendering with the SDK. Required when type is payment_form.
payment_template
object
Payment details and configuration including amount, receiver, sender, invoice allocations, and transaction settings. Defines what payment is being collected, from whom, and to whom. Required to specify the payment that will be processed through the form.
amount
number (double)
The payment amount to charge. This is the total amount that will be charged to the customer, before any convenience fees if enabled.
attrs
object
Custom attributes for the transaction as a JSON object. Use this to store additional metadata or custom fields specific to your application. These attributes are stored with the transaction and can be retrieved later for reporting or integration purposes.
clearing_timing
enum[string]Immutable
The clearing speed for this transaction, determining how quickly funds are made available to the recipient. Instant clearing makes funds available immediately, same_day within the same business day, and next_day by the following business day. Defaults to next_day if not specified. Same-day and instant are only available in certain circumstances.
Values: instant, same_day, next_day
description
string
Description of what the payment is for. This appears on receipts, transaction records, and bank statements. Examples include "Order #1234", "Monthly subscription", or "Invoice payment". Helps customers identify the transaction.
funding_timing
enum[string]Immutable
The funding speed for this transaction, determining how quickly the merchant or processing account receives settlement of funds. Standard timing follows normal settlement schedules, while rapid timing accelerates the funding process for faster access to funds. Defaults to standard if not specified. Rapid and instant funding only available in certain circumstances.
Values: standard, instant, rapid
invoice_allocations
array
List of invoices that this payment should be applied to. When provided, the payment will be allocated across these invoices, reducing their outstanding balances. Use this for paying multiple invoices with a single payment or specifying which invoice a payment is for.
order_number
string
Custom order or transaction number for this payment. Use this to link the payment to an order in your system or to provide a customer-facing transaction reference. Providing this value ensures duplicate protection is applied per order; otherwise, duplicate protection applies across payments without an order reference.
receiver
object
Information about who will receive the payment and optionally the specific payment method for receiving funds. The receiver is the party being paid.
account_id
string
The unique identifier of the account that will receive this payment. This may represent a merchant, service provider, vendor, or other authorized recipient of funds. Required to identify who is receiving the funds.
method_id
string
The unique identifier of the payment method where funds will be deposited. If not specified, the receiver account's default method will be used.
sender
object
Information about who is making the payment. Includes the account and optionally pre-filled payment method details. The sender is the party being charged.
account_id
string
The unique identifier of the account making the payment. This is the payer who will be charged or the party who will fund the transfer. Used to associate the payment with the correct account.
method
object
Pre-filled values for the payment method that will be created or used for this payment. Allows you to set defaults like billing address, account holder name, or transfer type. These values populate the checkout form or are used when creating the payment method.
account_defaults
object
Default transaction types that this payment method will be used for. Controls whether the payment method is the default for paying or funding transactions, and which specific types of transactions it applies to.
funding
enum[string]
Controls which funding transaction types this payment method can be used for. Possible values: "all" (use for all funding transactions), "deposits" (use only for receiving deposits), or "withdraws" (use only for withdrawals). Determines the default usage for receiving funds.
Values: all, deposits, withdraws
paying
enum[string]
Controls which paying transaction type this payment method will be the default for. Possible values: "all" (use for all paying transactions), "payments" (use only for sending payments), or "payouts" (use only for receiving payouts). Determines the default usage for sending funds. If the account default is set for payments, that payment method will be used for any automatic invoice payments.
Values: all, payments, payouts
account_holder
string
Pre-filled name of the account holder for the payment method. For bank accounts, this is the name on the account. For cards, this is the cardholder name. When provided, this value will be used to populate the form.
account_id
string
The ID of the account that will own this payment method. Links the payment method to a specific customer or processing account. Used to associate the payment method with the correct account when it is created.
bank_account
object
Configuration specific to bank account payment methods. Contains bank account-specific settings such as the currency.
currency
enum[string]
The currency for bank account transactions. Must be either "USD" (US Dollars) or "CAD" (Canadian Dollars). Determines the currency for transactions using this bank account.
Values: USD, CAD
billing_address
object
Pre-filled billing address for the payment method. When provided, these values will be used to populate the address fields in the checkout form. Customers may be able to edit these values depending on checkout configuration.
address_line_1
string
Street address of the address
address_line_2
string
Unit number of the address
city
string
City of the company
country_code
string
Country code of the address
postal_code
string
Postal code of the address
state_province
string
State of the address
id
string
The unique identifier of an existing payment method to update. When provided, the form will be used to update the payment method, such as revalidating the CVV, updating the expiration date, or changing the billing address.
transfer_type
enum[string]
The transfer capabilities for this payment method. Possible values: "send_only" (can only send payments/fund payouts), "receive_only" (can only receive payouts/deposits), or "two_way" (can both send and receive). Controls how the payment method can be used for transactions.
Values: send_only, receive_only, two_way
source
enum[string]Immutable
The method by which this transaction was initiated or captured. This indicates whether the transaction was manually keyed, initiated via digital wallets like Google Pay or Apple Pay, or processed as a check conversion.
Values: keyed, googlepay, applepay, check
status
object
Target status configuration for the payment transaction. Controls whether the payment should be authorized only or immediately processed and captured.
value
enum[string]
The desired final status for the transaction. Possible values: "authorized" (authorize the payment but do not capture funds yet, useful for delayed capture), or "processed" (immediately process and capture the payment). Determines whether the payment is captured immediately or held for later capture.
Values: authorized, processed
transfers
array
List of transfer allocations for splitting a payment across multiple receivers. Each transfer specifies a receiver and an amount, allowing a single payment to be distributed to multiple accounts. Useful for marketplace or platform payments where funds need to be split between multiple parties.

Next Steps

Enhance your payment form implementation


Store Payment Methods

Create and manage payment methods to enable saved cards and bank accounts for faster checkout and recurring payments.

Handle Refunds

Process refunds and voids for cancellations and returns after payments complete.

Monitor Payment Events

Subscribe to webhook notifications to track payment status and automate order fulfillment.


Related articles