---
updatedAt: 2025-11-13T14:20:24.000Z
agentTools:
  siteIndex: https://docs.affirm.com/llms.txt
  projectIndex: https://docs.affirm.com/payments/llms.txt
---

# Open Affirm Virtual Card Checkout

Enable Affirm Virtual Card Checkout on your website by integrating Affirm.js. Tokenize customer details, generate a virtual card, and process payments through your existing gateway. Learn how to set up, launch, and manage virtual card transactions with callback handling.

<HTMLBlock>{`
<style>
  .dropdown-menu {
    font-family: Arial, sans-serif;
    max-width: 250px;
    margin-left: auto; /* Align to the right */
  	margin-right: 0; /* Ensure it's flush to the right */
    border: 1px solid #ddd;
    border-radius: 8px;
    padding: 10px;
    background: #4A4AF4;
    overflow: hidden; /* Ensure the container grows with content */
  }

  .dropdown-item {
    margin-bottom: 10px;
  }

  .dropdown-toggle {
    display: block;
    width: 100%;
    text-align: left;
    padding: 10px;
    background: #fff;
    border: 1px solid #ddd;
    border-radius: 4px;
    cursor: pointer;
  }

  .dropdown-toggle:hover {
    background: #f0f0f0;
  }

  .dropdown-content {
    display: none;
    margin-top: 5px;
    padding: 10px;
    background: #fff;
    border: 1px solid #ddd;
    border-radius: 4px;
  }

  .dropdown-item.open .dropdown-content {
    display: block;
  }

  .flag-icon {
    width: 20px;
    height: 20px;
    margin-right: 10px;
  }

  .product-item {
    margin-bottom: 5px;
    color: black;
  }

  .product-icon {
    width: 20px;
    height: 20px;
    margin-right: 10px;
  }
  
  .country-title {
    font-family: Arial, sans-serif;
    font-size:20px;
    text-align: center;
    font-weight: bold;
    color: #ffffff;
  } 

</style>
  <div class="dropdown-menu">
    <p class="country-title" alt="Countries where this product is available">Country Availability</p>

    <div class="dropdown-item">
      <button class="dropdown-toggle" onclick="toggleDropdown(event)" alt="Drop down menu displaying the available countries for this product">
        <b>Country List</b> ⬇️
      </button>
      <div class="dropdown-content">
        <div class="product-item">
          <img src="https://files.readme.io/a4c8b3d6596d943e2b93c82cb1d432a2edaf6998667835c2e97ef4a31d460c7e-us-circle-01.png" alt="USA" class="flag-icon">
          USA
        </div>
        <div class="product-item">
          <img src="https://files.readme.io/3ca294a1b4b8b8506c3ff32876abc6e3e33d0e65a509dab81398915094bdbc5c-61TcZ33ZrJL._AC_UY1000_.jpg" alt="Canada" class="flag-icon">
          Canada
        </div>
      </div>
    </div>

  </div>
`}</HTMLBlock>

## Overview

Starting a payment with Affirm on the web with a virtual card consists of creating a checkout form, tokenizing customer information securely, and generating a virtual card. You can then process the card through your existing payment gateway.

This guide shows you how to include `Affirm.js` and Affirm Checkout on your web page to create an Affirm virtual card.

***

## Implementation Steps

### **Step 1: Set up Affirm.js**

Include the following script in the head section on every page on your site. This script should always be loaded directly from the Affirm domain.

> 🚧 Use only your sandbox API keys and domain for testing and development
>
> This ensures that you don't accidentally modify your live transactions. Affirm does **not** generate real virtual cards in the sandbox environment. If applicable, please work with your technical account manager on live testing.

<Recipe slug="embed-affirmjs" title="Embed Affirm.js" />

```javascript
<script>
const _affirm_config = {
		public_api_key: "YOUR_PUBLIC_API_KEY", /* replace with public api key */
		script: "https://cdn1-sandbox.affirm.com/js/v2/affirm.js",
		locale: "en_US",
		country_code: "USA",
	};

(function(m,g,n,d,a,e,h,c){var b=m[n]||{},k=document.createElement(e),p=document.getElementsByTagName(e)[0],l=function(a,b,c){return function(){a[b]._.push([c,arguments])}};b[d]=l(b,d,"set");var f=b[d];b[a]={};b[a]._=[];f._=[];b._=[];b[a][h]=l(b,a,h);b[c]=function(){b._.push([h,arguments])};a=0;for(c="set add save post open empty reset on off trigger ready setProduct".split(" ");a<c.length;a++)f[c[a]]=l(b,d,c[a]);a=0;for(c=["get","token","url","items"];a<c.length;a++)f[c[a]]=function(){};k.async=
  !0;k.src=g[e];p.parentNode.insertBefore(k,p);delete g[e];f(g);m[n]=b})(window,_affirm_config,"affirm","checkout","ui","script","ready","jsReady");
</script>
```

[See supported locale and country codes](https://docs.affirm.com/developers/v1.0-Global-Integration/docs/global-affirm-integration-guide#supported-values).

After you add the script above, a defined instance of Affirm is created on your client. You will gain access to methods within the affirm object to trigger multiple actions.

***

### **Step 2: Create the Checkout Object**

When a customer chooses Affirm to pay for a purchase, a [checkout object](https://docs.affirm.com/developers/reference/the-checkout-object) containing the order details is created with `affirm.checkout.open_vcn()` so that Affirm can render the checkout flow. When the customer completes their purchase, you must handle the callbacks or leverage redirects. See below for a sample checkout object:

```javascript Open Affirm Virtual Card Checkout Object
const checkoutObject = {
  merchant: {
    user_confirmation_url: 'https://merchantsite.com/confirm',
    user_cancel_url: 'https://merchantsite.com/cancel',
    user_confirmation_url_action: 'POST',
    name: 'Your Customer-Facing Merchant Name',
    use_vcn: true,
  },
  shipping: {
    name: {
      first: 'Joe',
      last: 'Doe',
    },
    address: {
      street1: '633 Folsom St',
      street2: 'Floor 7',
      city: 'San Francisco',
      state: 'CA',
      zipcode: '94107',
      country: 'USA',
    },
    phone_number: '4153334567',
    email: 'joedoe@123fakedomain.com',
  },
  billing: {
    name: {
      first: 'Joe',
      last: 'Doe',
    },
    address: {
      street1: '633 Folsom St',
      street2: 'Floor 7',
      city: 'San Francisco',
      state: 'CA',
      zipcode: '94107',
      country: 'USA',
    },
    phone_number: '4153334567',
    email: 'joedoe@123fakedomain.com',
  },
  items: [
    {
      display_name: 'Awesome Pants',
      sku: 'ABC-123',
      unit_price: 10000,
      qty: 3,
      item_image_url: 'http://merchantsite.com/images/awesome-pants.jpg',
      item_url: 'http://merchantsite.com/products/awesome-pants.html',
      categories: [
        ['Apparel', 'Pants'],
        ['Mens', 'Apparel', 'Pants'],
      ],
    },
  ],
  discounts: {
    RETURN5: {
      discount_amount: 500,
      discount_display_name: 'Returning customer 5% discount',
    },
    PRESDAY10: {
      discount_amount: 1000,
      discount_display_name: "President's Day 10% off",
    },
  },
  metadata: {
    shipping_type: 'UPS Ground',
    mode: 'modal',
  },
  order_id: 'JKLMO4321',
  currency: 'USD',
  financing_program: 'zero_pct_promo',
  shipping_amount: 1000,
  tax_amount: 600,
  total: 30100,
};

affirm.checkout.open_vcn(checkoutObject)
```

For additional information, see [Checkout Object](https://docs.affirm.com/developers/reference/the-checkout-object) or the Checkout Object recipe linked below.

<Recipe slug="configure-the-checkout-object-1" title="Configure the Checkout Object" />

***

#### Method Arguments

<Table align={["left","left","left"]}>
  <thead>
    <tr>
      <th>
        Method
      </th>

      <th>
        Data type
      </th>

      <th>
        Description
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        `checkoutObject` <span style={{ color: "Crimson" }}>required</span>
      </td>

      <td>
        *object*
      </td>

      <td>
        The object containing the customer's checkout data. [See details](https://docs.affirm.com/developers/reference/the-checkout-object).
      </td>
    </tr>
  </tbody>
</Table>

> 🚧
>
> **Note:**
>
> * Our virtual card product only supports modal mode. The Affirm checkout opens in a modal that floats on top of your checkout page. This is indicated in the checkout object when setting the mode parameter to modal.
> * Set the use\_vcn parameter to true to enable card details to be generated on loan origination.
> * affirm.checkout() validates the required data in the checkout object.

***

### **Step 3: Launch Checkout and Handle Callbacks**

After you create the checkout object, you can launch the Affirm checkout modal using the `affirm.checkout.open_vcn()` function. When the customer confirms their Affirm loan, we send a javascript callback on success or on error, depending on the outcome. In the event of a successful checkout, you can retrieve the card details and the `checkout_id` from the callback.

> 🚧
>
> **Note:**
>
> If you don't want to retrieve the card details from the client-side, we can pass them back via the server-side only using our [Read Card API](https://docs.affirm.com/developers/reference/read_card) (for PCI reasons). Contact Merchant Help for further information.

### Returns

Returns callbacks that resolve in a:

* `card_checkout`: A card object was successfully created.
* `error_response`: There was an error. Includes the `checkout_id` for the attempt and the `reason` why it failed.
* `checkout_validation_error`: There was a validation error with the checkout request submitted.

```javascript
affirm.checkout.open_vcn({
      success: function(card_checkout) {
         console.log(card_checkout);
      },
      error: function(error_response) {
        console.log(error_response);
      },
      onValidationError: function(checkout_validation_error) {
      console.log(checkout_validation_error)
    }
 });
```

#### Retrieve full [card details](https://docs.affirm.com/payments/reference/the-card-object) via success callback

```javascript
{
    billing_address: {
        city: "San Francisco",
        line1: "650 California St.",
        line2: "12th Floor",
 		state: "CA",
        zipcode: "94108"
    },
   callback_id: "b67350e8-ad14-4844-8230-adc6e5f3e490",
   cardholder_name: "AffirmInc John Doe",
   charge_ari: "GDC3-MKAG",
   checkout_token: "RTKS63U383SZ9GY7",
   created: "2023-05-18T16:10:57.300017",
   cvv: "123",
   expiration: "0122",
   id: "RTKS63U383SZ9GY7",
   number: "4111111111111111"
}
```

#### Alternative success callback: Omit card details retrieve the `checkout_token` client-side and obtain card details via your server

```javascript
{
  callback_id: "b67350e8-ad14-4844-8230-adc6e5f3e490",
  charge_ari: "GDC3-MKAG",
  checkout_token: "RTKS63U383SZ9GY7",
  created: "2023-05-18T16:10:57.300017",
  id: "RTKS63U383SZ9GY7"
}
```

***

### **Step 4: Card Management**

When you receive the card details from the checkout response or [Read Card](https://docs.affirm.com/developers/v1.0-Global-Integration/reference/read_card) API, you can submit authorizations, captures, and refunds to the virtual card using your existing payment rails.

***

### FAQ

<Callout icon="🚩" theme="default">
  ### Resolving "affirm.checkout.open\_vcn is not a function" Error in VCN Integration

  **Q**: How do I fix the error "**affirm.checkout.open\_vcn is not a function**" when using Affirm's checkout methods?

  **A**: This error typically occurs when the Affirm script hasn't fully loaded before the checkout and open\_vcn methods are called. To resolve this, wrap the Affirm checkout and open\_vcn method calls within the `affirm.ui.ready` method. Below is a solution that has assisted multiple merchants:

  ```javascript
  affirm.ui.ready(function() {
    affirm.checkout(checkoutObj);
    affirm.checkout.open_vcn({
        success: function(card_checkout) {
            //On successful loan confirmation Affirm will trigger this function
            //This function will be used to pass CC number to your CC processor
            //You will need to handle redirecting to a success page here as well
            console.log(card_checkout);
        },
        error: function(error_response) {
            //On Cancel or decline Affirm will trigger the following function
            //You will need to handle redirecting to an error page here
            console.log(error_response);
        }
    });
  });
  ```

  In this solution, the success function is used for processing successful loan confirmations, including passing credit card details to your processor and redirecting to a success page. The error function handles cancellations or declines by redirecting to an error page. This workaround ensures that Affirm's methods are only called after the script is fully loaded, effectively preventing the error.
</Callout>