diff --git a/commerce_stripe.js b/commerce_stripe.js
index dab7021..1effd12 100755
--- a/commerce_stripe.js
+++ b/commerce_stripe.js
@@ -9,6 +9,51 @@
       if (settings.stripe.fetched == null) {
         settings.stripe.fetched = true;
 
+        var createToken = function (cardFieldMap, optionalFieldMap, responseHandler) {
+          Stripe.setPublishableKey(settings.stripe.publicKey);
+
+          var cardValues = {
+            number: $('[id^=' + cardFieldMap.number +']').val(),
+            cvc: $('[id^=' + cardFieldMap.cvc +']').val(),
+            exp_month: $('[id^=' + cardFieldMap.exp_month +']').val(),
+            exp_year: $('[id^=' + cardFieldMap.exp_year +']').val(),
+            name: $('[id^=' + cardFieldMap.name +']').val()
+          };
+
+          for (var stripeName in optionalFieldMap) {
+            if (optionalFieldMap.hasOwnProperty(stripeName)) {
+              var formInputElement = $('[id^=' + optionalFieldMap[stripeName] + ']');
+              if (formInputElement.length) {
+                cardValues[stripeName] = formInputElement.val();
+              }
+            }
+          }
+
+          Stripe.createToken(cardValues, responseHandler);
+        };
+
+        var makeResponseHandler = function (form$, errorDisplay$, onError, onSuccess) {
+          return function (status, response) {
+            if (response.error) {
+              // Show the errors on the form.
+              errorDisplay$.html($("<div class='messages error'></div>").html(response.error.message));
+
+              onError && onError(form$);
+            }
+            else {
+              // Token contains id, last4, and card type.
+              var token = response['id'];
+              // Insert the token into the form so it gets submitted to the server.
+              form$.append("<input type='hidden' name='stripeToken' value='" + token + "'/>");
+
+              onSuccess && onSuccess(form$);
+
+              // And submit.
+              form$.get(0).submit(form$);
+            }
+          };
+        };
+
         $('#edit-continue').live('click', function(event) {
 
           // Prevent the Stripe actions to be triggered if Stripe is not selected.
@@ -31,18 +76,14 @@
             // Disable the submit button to prevent repeated clicks.
             $('.form-submit').attr("disabled", "disabled");
 
-            Stripe.setPublishableKey(settings.stripe.publicKey);
-
-            var cardValues = {
-              number: $('[id^=edit-commerce-payment-payment-details-credit-card-number]').val(),
-              cvc: $('[id^=edit-commerce-payment-payment-details-credit-card-code]').val(),
-              exp_month: $('[id^=edit-commerce-payment-payment-details-credit-card-exp-month]').val(),
-              exp_year: $('[id^=edit-commerce-payment-payment-details-credit-card-exp-year]').val(),
-              name: $('[id^=edit-commerce-payment-payment-details-credit-card-owner]').val()
+            var cardFields = {
+              number: 'edit-commerce-payment-payment-details-credit-card-number',
+              cvc: 'edit-commerce-payment-payment-details-credit-card-code',
+              exp_month: 'edit-commerce-payment-payment-details-credit-card-exp-month',
+              exp_year: 'edit-commerce-payment-payment-details-credit-card-exp-year',
+              name: 'edit-commerce-payment-payment-details-credit-card-owner'
             };
 
-            // Check if the optional address fields are present in
-            // the form and include them in the token if so.
             var optionalFields = {
               address_line1: 'edit-customer-profile-billing-commerce-customer-address-und-0-thoroughfare',
               address_line2: 'edit-customer-profile-billing-commerce-customer-address-und-0-premise',
@@ -52,48 +93,54 @@
               address_country: 'edit-customer-profile-billing-commerce-customer-address-und-0-country'
             };
 
-            for (var stripeName in optionalFields) {
-              if (optionalFields.hasOwnProperty(stripeName)) {
-                var formInputElement = $('[id^=' + optionalFields[stripeName] + ']');
-                if (formInputElement.length) {
-                  cardValues[stripeName] = formInputElement.val();
-                }
+            var responseHandler = makeResponseHandler(
+              $("#edit-continue").parents("form"),
+              $('div.payment-errors'),
+              function () {
+                $(this).removeClass('auth-processing');
+                // Enable the submit button to allow resubmission.
+                $('.form-submit').removeAttr("disabled");
+                // Hide progress animated gif.
+                $('.checkout-processing').hide();
+              },
+              function (form$) {
+                var $btnTrigger = $('.form-submit.auth-processing').eq(0);
+                var trigger$ = $("<input type='hidden' />").attr('name', $btnTrigger.attr('name')).attr('value', $btnTrigger.attr('value'));
+                form$.append(trigger$);
               }
-            }
+            );
 
-            Stripe.createToken(cardValues, Drupal.behaviors.stripe.stripeResponseHandler);
+            createToken(cardFields, optionalFields, responseHandler);
 
             // Prevent the form from submitting with the default action.
             return false;
           }
         });
-      }
-    },
 
-    stripeResponseHandler: function (status, response) {
-      if (response.error) {
-        $(this).removeClass('auth-processing');
-
-        // Show the errors on the form.
-        $("div.payment-errors").html($("<div class='messages error'></div>").html(response.error.message));
-
-        // Enable the submit button to allow resubmission.
-        $('.form-submit').removeAttr("disabled");
-        // Hide progress animated gif.
-        $('.checkout-processing').hide();
-      }
-      else {
-        var form$ = $("#edit-continue").parents("form");
-        // Token contains id, last4, and card type.
-        var token = response['id'];
-        // Insert the token into the form so it gets submitted to the server.
-        form$.append("<input type='hidden' name='stripeToken' value='" + token + "'/>");
-        $btnTrigger = $('.form-submit.auth-processing').eq(0);
-        var trigger$ = $("<input type='hidden' />").attr('name', $btnTrigger.attr('name')).attr('value', $btnTrigger.attr('value'));
-        form$.append(trigger$);
-
-        // And submit.
-        form$.get(0).submit();
+        $('#commerce-stripe-cardonfile-create-form #edit-submit').live('click', function (event) {
+          var cardFields = {
+            number: 'edit-credit-card-number',
+            cvc: 'edit-credit-card-code',
+            exp_month: 'edit-credit-card-exp-month',
+            exp_year: 'edit-credit-card-exp-year',
+            name: 'edit-credit-card-owner'
+          };
+
+          var optionalFields = {
+            address_line1: 'edit-thoroughfare',
+            address_line2: 'edit-premise',
+            address_ciy: 'edit-locality',
+            address_state: 'edit-administrative-area',
+            address_zip: 'edit-postal-code',
+            address_country: 'edit-country'
+          };
+
+          var responseHandler = makeResponseHandler($('#commerce-stripe-cardonfile-create-form'), $('#card-errors'));
+
+          createToken(cardFields, optionalFields, responseHandler);
+
+          return false;
+        });
       }
     }
   }
diff --git a/commerce_stripe.module b/commerce_stripe.module
index a2b028b..8630a7a 100755
--- a/commerce_stripe.module
+++ b/commerce_stripe.module
@@ -47,6 +47,8 @@ function commerce_stripe_commerce_payment_method_info() {
     'offsite' => FALSE,
     'cardonfile' => array(
       'charge callback' => 'commerce_stripe_cardonfile_charge',
+      'create form callback' => 'commerce_stripe_cardonfile_create_form',
+      'create callback' => 'commerce_stripe_cardonfile_create',
       'update callback' => 'commerce_stripe_cardonfile_update',
       'delete callback' => 'commerce_stripe_cardonfile_delete',
     ),
@@ -117,10 +119,7 @@ function commerce_stripe_settings_form($settings) {
   return $form;
 }
 
-/**
- * Payment method callback: checkout form.
- */
-function commerce_stripe_submit_form($payment_method, $pane_values, $checkout_pane, $order) {
+function _commerce_stripe_credit_card_form() {
   module_load_include('inc', 'commerce_payment', 'includes/commerce_payment.credit_card');
 
   $credit_card_fields = array(
@@ -146,10 +145,19 @@ function commerce_stripe_submit_form($payment_method, $pane_values, $checkout_pa
     $credit_card_field['#post_render'][] = '_commerce_stripe_credit_card_field_remove_name';
   }
 
+  return $form;
+}
+
+/**
+ * Payment method callback: checkout form.
+ */
+function commerce_stripe_submit_form($payment_method, $pane_values, $checkout_pane, $order) {
+  $form = _commerce_stripe_credit_card_form();
+
   // Add the total amount.
   $form['total'] = array(
     '#type' => 'hidden',
-    '#value' => field_get_items('commerce_order', $order, 'commerce_order_total_amount'),
+    '#value' => field_get_items('commerce_order', $order, 'commerce_order_total'),
     '#attributes' => array(
       'name' => '',
       'class' => array('stripe-order-total'),
@@ -217,43 +225,11 @@ function commerce_stripe_submit_form_submit($payment_method, $pane_form, $pane_v
   if (module_exists('commerce_cardonfile') && !empty($payment_method['settings']['cardonfile']) &&
     !empty($pane_values['credit_card']['cardonfile_store']) && $pane_values['credit_card']['cardonfile_store']) {
     $save_card = TRUE;
-    // If there is no existing customer id, use the Stripe form token to create one.
-    $stripe_customer_id = commerce_stripe_customer_id($order->uid, $payment_method['instance_id']);
-    if (!$stripe_customer_id) {
-      $account = user_load($order->uid);
-      try {
-        $customer = Stripe_Customer::create(array(
-          'card' => $_POST['stripeToken'],
-          'email' => $account->mail,
-        ));
-        $stripe_customer_id = $customer->id;
-        // Use the newly created customer id for the subsequent charge request.
-        $c['customer'] = $stripe_customer_id;
-        unset($c['card']);
-      }
-      catch (Exception $e) {
-        drupal_set_message(t('We received the following error processing your card: %error. Please enter your information again or try a different card.', array('%error' => $e->getMessage())), 'error');
-        watchdog('commerce_stripe', 'Following error received when creating Stripe customer: @stripe_error.', array('@stripe_error' => $e->getMessage()), WATCHDOG_NOTICE);
-        return FALSE;
-      }
-    }
-    // If the customer id already existed, use the Stripe form token to create the new card.
-    else {
-      try {
-        $customer = Stripe_Customer::retrieve($stripe_customer_id);
-        $response = $customer->cards->create(array('card' => $_POST['stripeToken']));
-        $stripe_card_id = $response->id;
-        // Now both the customer id and card id are available.  Add them both to the charge parameters.
-        // The card id is needed so that the customer's default card (which may be different) is not charged instead.
-        $c['card'] = $stripe_card_id;
-        $c['customer'] = $stripe_customer_id;
-      }
-      catch (Exception $e) {
-        drupal_set_message(t('We received the following error processing your card: %error. Please enter your information again or try a different card.', array('%error' => $e->getMessage())), 'error');
-        watchdog('commerce_stripe', 'Following error received when adding a card to customer: @stripe_error.', array('@stripe_error' => $e->getMessage()), WATCHDOG_NOTICE);
-        return FALSE;
-      }
-    }
+    $card = _commerce_stripe_create_card($_POST['stripeToken'], $order->uid, $payment_method);
+    $stripe_card_id = $card->id;
+    $stripe_customer_id = $card->customer;
+    $c['card'] = $stripe_card_id;
+    $c['customer'] = $stripe_customer_id;
   }
 
   $transaction = commerce_payment_transaction_new('commerce_stripe', $order->order_id);
@@ -282,10 +258,6 @@ function commerce_stripe_submit_form_submit($payment_method, $pane_form, $pane_v
 
   // If so instructed by the customer, save the card.
   if (!empty($save_card)) {
-    // If the customer id was created above, need to fetch the card id from the subsquent charge.
-    if (!isset($stripe_card_id)) {
-      $stripe_card_id = $response->card->id;
-    }
 
 /**
     // Try fetching the name to store with the card from the billing pane.
@@ -299,26 +271,77 @@ function commerce_stripe_submit_form_submit($payment_method, $pane_form, $pane_v
  *
  */
 
-    // Store the Stripe customer and card ids in the remote id field of {commerce_cardonfile} table
-    $remote_id = (string) $stripe_customer_id . '|' . (string) $stripe_card_id;
-
-    // Populate and save the card
-    $card_data = commerce_cardonfile_new();
-    $card_data->uid = $order->uid;
-    $card_data->payment_method = $payment_method['method_id'];
-    $card_data->instance_id = $payment_method['instance_id'];
-    $card_data->remote_id = $remote_id;
-    $card_data->card_type = $response->card->type;
-    $card_data->card_name = $response->card->name;
-    $card_data->card_number = $response->card->last4;
-    $card_data->card_exp_month = $response->card->exp_month;
-    $card_data->card_exp_year = $response->card->exp_year;
-    $card_data->status = 1;
-    commerce_cardonfile_save($card_data);
-    watchdog('commerce_stripe', 'Stripe Customer Profile @profile_id created and saved to user @uid.', array('@profile_id' => (string) $customer->id, '@uid' => $order->uid));
+    _commerce_stripe_save_cardonfile($response->card, $order->uid, $payment_method, $pane_values['cardonfile_instance_default']);
+  }
+}
+
+function _commerce_stripe_create_card($stripe_token, $uid, $payment_method) {
+  if (!commerce_stripe_load_library()) {
+    return FALSE;
+  }
+  Stripe::setApiKey($payment_method['settings']['secret_key']);
+
+  // If there is no existing customer id, use the Stripe form token to create one.
+  $stripe_customer_id = commerce_stripe_customer_id($uid, $payment_method['instance_id']);
+  if (!$stripe_customer_id) {
+    $account = user_load($uid);
+    try {
+      $customer = Stripe_Customer::create(array(
+        'card' => $stripe_token,
+        'email' => $account->mail,
+      ));
+      foreach ($customer->cards->data as $card) {
+        if ($card->id == $customer->default_card) {
+          return $card;
+        }
+      }
+    }
+    catch (Exception $e) {
+      drupal_set_message(t('We received the following error processing your card: %error. Please enter your information again or try a different card.', array('%error' => $e->getMessage())), 'error');
+      watchdog('commerce_stripe', 'Following error received when creating Stripe customer: @stripe_error.', array('@stripe_error' => $e->getMessage()), WATCHDOG_NOTICE);
+      return FALSE;
+    }
+  }
+  // If the customer id already existed, use the Stripe form token to create the new card.
+  else {
+    try {
+      $customer = Stripe_Customer::retrieve($stripe_customer_id);
+      $card = $customer->cards->create(array('card' => $stripe_token));
+      return $card;
+    }
+    catch (Exception $e) {
+      drupal_set_message(t('We received the following error processing your card: %error. Please enter your information again or try a different card.', array('%error' => $e->getMessage())), 'error');
+      watchdog('commerce_stripe', 'Following error received when adding a card to customer: @stripe_error.', array('@stripe_error' => $e->getMessage()), WATCHDOG_NOTICE);
+      return FALSE;
+    }
   }
 }
 
+function _commerce_stripe_save_cardonfile($card, $uid, $payment_method, $set_default) {
+  // Store the Stripe customer and card ids in the remote id field of {commerce_cardonfile} table
+  $remote_id = (string) $card->customer . '|' . (string) $card->id;
+
+  // Populate and save the card
+  $card_data = commerce_cardonfile_new();
+  $card_data->uid = $uid;
+  $card_data->payment_method = $payment_method['method_id'];
+  $card_data->instance_id = $payment_method['instance_id'];
+  $card_data->remote_id = $remote_id;
+  $card_data->card_type = $card->type;
+  $card_data->card_name = $card->name;
+  $card_data->card_number = $card->last4;
+  $card_data->card_exp_month = $card->exp_month;
+  $card_data->card_exp_year = $card->exp_year;
+  $card_data->status = 1;
+  commerce_cardonfile_save($card_data);
+
+  if ($set_default) {
+    commerce_cardonfile_set_default_card($card_data->card_id);
+  }
+
+  watchdog('commerce_stripe', 'Stripe Customer Profile @profile_id created and saved to user @uid.', array('@profile_id' => (string) $card->customer, '@uid' => $uid));
+}
+
 /**
  * Implements hook_commerce_payment_method_info_alter().
  *
@@ -411,6 +434,69 @@ function commerce_stripe_cardonfile_charge($payment_method, $card_data, $order,
 }
 
 /**
+ * Card on file callback: create form
+ */
+function commerce_stripe_cardonfile_create_form($form, &$form_state, $op, $card_data) {
+  // Pass along information to the validate and submit handlers.
+  $form_state['card_data'] = $card_data;
+  $form_state['op'] = $op;
+
+  // Set our key to settings array.
+  drupal_add_js(array('stripe' => array('publicKey' => _commerce_stripe_load_setting('public_key'))), 'setting');
+
+  // Include the stripe.js from stripe.com.
+  drupal_add_js('https://js.stripe.com/v1/', 'external');
+
+  // Load commerce_stripe.js.
+  $form['#attached']['js'] = array(
+    drupal_get_path('module', 'commerce_stripe') . '/commerce_stripe.js',
+  );
+
+  $form['errors'] = array(
+    '#markup' => '<div id="card-errors"></div>'
+  );
+
+  $form += _commerce_stripe_credit_card_form();
+
+  $payment_method = commerce_payment_method_instance_load($card_data->instance_id);
+  $form['credit_card']['cardonfile_instance_default'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Use as default card for payments with %method', array('%method' => $payment_method['display_title'])),
+    '#default_value' => FALSE,
+  );
+
+  $form['address'] = addressfield_generate(
+    addressfield_default_values(),
+    array('address' => 'address'),
+    array('mode' => 'form'));
+
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Add card')
+  );
+
+  return $form;
+}
+
+function commerce_stripe_cardonfile_create_form_submit($form, &$form_state) {
+  $card_data = $form_state['card_data'];
+  $payment_method = commerce_payment_method_instance_load($card_data->instance_id);
+  commerce_stripe_cardonfile_create($form, $form_state, $payment_method, $card_data);
+  $form_state['redirect'] = 'user/' . $card_data->uid . '/cards';
+}
+
+/**
+ * Card on file callback: create
+ */
+function commerce_stripe_cardonfile_create($form, &$form_state, $payment_method, $card_data) {
+  $card = _commerce_stripe_create_card($_POST['stripeToken'], $card_data->uid, $payment_method);
+  if (!$card) {
+    return;
+  }
+  _commerce_stripe_save_cardonfile($card, $card_data->uid, $payment_method, $form_state['values']['credit_card']['cardonfile_instance_default']);
+}
+
+/**
  * Card on file callback: updates the associated customer payment profile.
  */
 function commerce_stripe_cardonfile_update($form, &$form_state, $payment_method, $card_data) {
