Skip to content

Card payment with Payment components

A complete card payment built with Payment components: the backend creates a Checkout Session, shift4.js mounts the card fields in the page's own checkout form, and the Pay button confirms the payment. It follows the flow described in Card payments.

The email and cardholder name are regular inputs on the page. The card number, expiry, and CVC are Shift4-hosted components that render in Shift4's own secure frames, so card data never reaches the page and Shift4 handles it along with the PCI scope.

This example runs in the sandbox. Pay with one of the test cards below; no real payment is made.

Potted plant
Qty 1
$24.99

Pay with card

Card information

Card details are entered in fields hosted by Shift4.

Test cards

  • 4242 4242 4242 4242
    Payment succeeds
  • 4024 0071 1846 8684
    Declined: insufficient funds
  • 4012 0001 0000 0114
    Succeeds after frictionless 3D Secure
  • 4012 0018 0000 0016
    Succeeds after a 3D Secure challenge

Use any future expiry date and any 3-digit CVC. More scenarios in Test cards.

How it works

  1. 1

    Create a Checkout Session

    Your backend creates a Checkout Session for the order and passes its clientSecret to the page. The Access Token stays on the server; the clientSecret is the only value the browser needs. See Create a Checkout Session for all the options.

    # Run on your backend. SHIFT4_ACCESS_TOKEN is your Access Token - keep it on the server.
    curl -X POST https://api.shift4.com/api/rest/v1/checkoutsessions/create \
      -H "AccessToken: $SHIFT4_ACCESS_TOKEN" \
      -H "InterfaceVersion: 1.0" \
      -H "InterfaceName: YourApp" \
      -H "CompanyName: YourCompany" \
      -H "Content-Type: application/json" \
      -d '{
        "checkoutSession": {
          "lineItems": [
            {
              "product": {
                "name": "Potted plant",
                "currencyCode": "USD",
                "amount": { "total": 24.99 }
              }
            }
          ]
        }
      }'
  2. 2

    Mount the card fields and take the payment

    On the page, load shift4.js, initialise it with your Platform Public Key, and open the Checkout Session with its clientSecret. Each card field is a component mounted into an empty element of your own form. Your Pay button calls checkout.continue(), and the result of each attempt arrives as a checkout_session.succeeded or payment.failed event.

    The public key and clientSecret below are placeholders: use your own public key and the clientSecret returned in step 1. See Card payments and Events & error handling.

    <script src="https://js.shift4.com/v1/shift4.js"></script>
    
    <form id="payment-form">
      <input id="email" type="email" placeholder="Email" />
      <div id="number"></div>
      <div id="expiry"></div>
      <div id="cvc"></div>
      <input id="cardholder" type="text" placeholder="Cardholder name" />
      <button type="submit">Pay $24.99</button>
    </form>
    
    <script>
      (async function () {
        // Replace with your own values:
        // - your Platform Public Key (sandbox keys start with pk_sandbox_)
        // - the clientSecret your backend received in step 1
        var shift4 = Shift4('pk_sandbox_XXXXXXXXXXXXXXXXXXXX');
        var checkout = await shift4.createCheckout('{{clientSecret}}');
    
        checkout.createComponent('number').mount('#number');
        checkout.createComponent('expiry').mount('#expiry');
        checkout.createComponent('cvc').mount('#cvc');
    
        checkout.addEventListener('checkout_session.succeeded', function () {
          // show a confirmation, then confirm the Checkout Session on your backend
        });
        checkout.addEventListener('payment.failed', function (event) {
          // show event.error.message to the customer
        });
    
        document.getElementById('payment-form').addEventListener('submit', function (e) {
          e.preventDefault();
          checkout.continue({
            email: document.getElementById('email').value,
            billing: { name: document.getElementById('cardholder').value }
          });
        });
      })();
    </script>
  3. 3

    Confirm the payment

    When checkout_session.succeeded fires, show the customer a confirmation. The browser event is a convenience signal, not proof of payment. Before you fulfil the order, retrieve the Checkout Session on your backend and check that its status is paid, or receive Checkout Session webhooks so you don't depend on the customer's browser. See Confirm the payment.

    # Run on your backend: retrieve the Checkout Session and check that its status is paid.
    curl https://api.shift4.com/api/rest/v1/checkoutsessions/retrieve \
      -H "AccessToken: $SHIFT4_ACCESS_TOKEN" \
      -H "InterfaceVersion: 1.0" \
      -H "InterfaceName: YourApp" \
      -H "CompanyName: YourCompany" \
      -H "CheckoutSessionId: {{checkoutSessionId}}"