title: Stripe.js / stripe.php - All card errors work (expiry, cvc, incorrect #) except for declined card
body: <p>I'm testing a simple checkout form using stripe for payments.  I followed tutorial examples ( <a href="https://stripe.com/docs/tutorials/forms" rel="nofollow">https://stripe.com/docs/tutorials/forms</a> ) and everything works except the declined card error.  As per the api, use 4000000000000002 to simulate a declined card.  It just crashes my charge.php file.  Here is the code from the html form and charge.php file.  </p>
  
  <p>live version here:  <a href="http://www.getwebshark.com/trial/step3" rel="nofollow">http://www.getwebshark.com/trial/step3</a></p>
  
  <p>form.html - </p>
  
  <p></p>
  
  <pre><code>&lt;html lang="en" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"&gt;
  &lt;head&gt;
    &lt;meta name="generator" content=
    "HTML Tidy for Linux/x86 (vers 11 February 2007), see www.w3.org" /&gt;
    &lt;meta http-equiv="Content-type" content="text/html; charset=us-ascii" /&gt;
  
    &lt;title&gt;Stripe Getting Started Form&lt;/title&gt;
    &lt;script type="text/javascript" src="https://js.stripe.com/v1/"&gt;
  &lt;/script&gt;&lt;!-- jQuery is used only for this example; it isn't required to use Stripe --&gt;
  
    &lt;script type="text/javascript" src=
    "https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"&gt;
  &lt;/script&gt;
    &lt;script type="text/javascript"&gt;
  //&lt;![CDATA[
                                  // this identifies your website in the createToken call below
                                  Stripe.setPublishableKey('ihidthis');
  
                                  function stripeResponseHandler(status, response) {
                                          if (response.error) {
                                                  // re-enable the submit button
                                                  $('.submit-button').removeAttr("disabled");
                                                  // show the errors on the form
                                                  $(".payment-errors").html(response.error.message);
                                          } else {
                                                  var form$ = $("#payment-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("&lt;input type='hidden' name='stripeToken' value='" + token + "' /&gt;");
                                                  // and submit
                                                  form$.get(0).submit();
                                          }
                                  }
  
                                  $(document).ready(function() {
                                          $("#payment-form").submit(function(event) {
                                                  // disable the submit button to prevent repeated clicks
                                                  $('.submit-button').attr("disabled", "disabled");
                                                  // createToken returns immediately - the supplied callback submits the form if there are no errors
                                                  Stripe.createToken({
                                                  name: $('.card-name').val(),
                                                  number: $('.card-number').val(),
                                                  cvc: $('.card-cvc').val(),
                                                  exp_month: $('.card-expiry-month').val(),
                                                  exp_year: $('.card-expiry-year').val()
                                                  }, stripeResponseHandler);
                                                  return false; // submit from callback
                                          });
                                  });
  
                                  if (window.location.protocol === 'file:') {
                                          alert("stripe.js does not work when included in pages served over file:// URLs. Try serving this page over a webserver. Contact support@stripe.com if you need assistance.");
                                  }
    //]]&gt;
    &lt;/script&gt;
  &lt;/head&gt;
  
  &lt;body&gt;
    &lt;h1&gt;Trial $4.99 with recurring $74.98 after 18 days&lt;/h1&gt;
    &lt;!-- to display errors returned by createToken --&gt;
  
    &lt;form action="charge.php" method="post" id="payment-form" name="payment-form"&gt;
      &lt;div class="form-row"&gt;
        &lt;label&gt;Name on Card&lt;/label&gt; &lt;input type="text" size="20" autocomplete="off" class=
        "card-name" /&gt;
      &lt;/div&gt;
  
      &lt;div class="form-row"&gt;
        &lt;label&gt;Email&lt;/label&gt; &lt;input type="text" size="20" autocomplete="off" name=
        "email" /&gt;
      &lt;/div&gt;
  
      &lt;div class="form-row"&gt;
        &lt;label&gt;Card Number&lt;/label&gt; &lt;input type="text" size="20" autocomplete="off" class=
        "card-number" /&gt;
      &lt;/div&gt;
  
      &lt;div class="form-row"&gt;
        &lt;label&gt;CVC&lt;/label&gt; &lt;input type="text" size="4" autocomplete="off" class=
        "card-cvc" /&gt;
      &lt;/div&gt;
  
      &lt;div class="form-row"&gt;
        &lt;label&gt;Expiration (MM/YYYY)&lt;/label&gt; &lt;input type="text" size="2" class=
        "card-expiry-month" /&gt; &lt;span&gt;/&lt;/span&gt; &lt;input type="text" size="4" class=
        "card-expiry-year" /&gt;
      &lt;/div&gt;
  
      &lt;div class="form-row"&gt;
        &lt;label&gt;Shipping address&lt;/label&gt; &lt;input type="text" size="20" autocomplete="off"
        name="address" /&gt;
      &lt;/div&gt;
  
      &lt;div class="form-row"&gt;
        &lt;label&gt;City&lt;/label&gt; &lt;input type="text" size="20" autocomplete="off" name="city" /&gt;
      &lt;/div&gt;
  
      &lt;div class="form-row"&gt;
        &lt;label&gt;State&lt;/label&gt; &lt;input type="text" size="20" autocomplete="off" name=
        "state" /&gt;
      &lt;/div&gt;
  
      &lt;div class="form-row"&gt;
        &lt;label&gt;Zip Code&lt;/label&gt; &lt;input type="text" size="20" autocomplete="off" name=
        "zip" /&gt;
      &lt;/div&gt;&lt;button type="submit" class="submit-button"&gt;Submit Payment&lt;/button&gt;
    &lt;/form&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>charge.php -</p>
  
  <pre><code>&lt;?php
  
  require_once('stripe-php/lib/Stripe.php');
  
  Stripe::setApiKey("ihidthis");
  
  // get the single use token from the form submitted by stripeResponseHandler
  // set your secret key: remember to change this to your live secret key in production
  // see your keys here https://manage.stripe.com/account
  
  // get the credit card details submitted by the form
  $token = $_POST['stripeToken'];
  $email = $_POST['email'];
  
  //combine these variables and post them all to stripe's customer description
  $address = $_POST['address'];
  $city    = $_POST['city'];
  $state   = $_POST['state'];
  $zip     = $_POST['zip'];
  
  $description = $address . " " . $city . " " . $state . " " . $zip;
  
  
  $customer = Stripe_Customer::create(array(
      "card" =&gt; $token,
      "plan" =&gt; "001",
      "description" =&gt; $description,
      "email" =&gt; $email
  ));
  
  Stripe_Charge::create(array(
      "amount" =&gt; 499, # amount in cents, again
      "currency" =&gt; "usd",
      "customer" =&gt; $customer-&gt;id
  ));
  
  
  
  echo '&lt;h1&gt;Thank you for your business!&lt;/h1&gt;';
  ?&gt;
  </code></pre>