Bitcoin Payments with Sources

    Use Sources to accept payments using Bitcoin, the popular digital cryptocurrency.

    Stripe users in the United States can accept Bitcoin for USD payments from customers using Sources—a single integration path for creating payments using any supported method.

    During the payment process, a Source object is created and your customer is given a receiver address to send the required amount of bitcoin to. Your customer uses this information with their Bitcoin wallet service or app to send the bitcoin amount needed. After completing this, your integration uses the source to make a charge request and complete the payment.

    Bitcoin is a push-based and single-use method of payment. This means your customer must take action to send the required amount of bitcoin to you. The pushing of funds may take a few minutes since your customer must do this outside of your checkout flow, but the amount is immediately available as soon as the funds have been received. Once the source is chargeable, there can be immediate confirmation about the success or failure of a payment.

    Quickstart using Checkout

    The simplest way to accept Bitcoin is with Checkout. After integrating Checkout for card payments, only one code change is needed to begin accepting Bitcoin payments—the addition of data-bitcoin="true" in the form’s code:

    <form action="" method="POST">
      <script
        src="https://checkout.stripe.com/checkout.js" class="stripe-button"
        data-key="pk_test_6pRNASCoBOKtIshFeQd4XMUh"
        data-amount="2000"
        data-name="Demo Site"
        data-description="2 widgets ($20.00)"
        data-image="/img/documentation/checkout/marketplace.png"
        data-label="Pay with Card or Bitcoin"
        data-locale="auto"
        data-currency="usd"
        data-bitcoin="true">
      </script>
    </form>

    After specifying the amount in USD that you want to receive, Stripe handles displaying the converted amount in BTC that your customer needs to pay. Once a Bitcoin payment is received, Checkout submits the form with the following extra fields:

    • stripeToken: The ID of the chargeable Source object
    • stripeTokenType: The type of token returned—the value is source_bitcoin
    • stripeEmail: The email address provided by the customer

    You can then immediately make a charge request using the source.

    Step 1: Create a Source object

    If you want to build a custom integration for accepting Bitcoin, a Source object can be created client-side using Stripe.js or server-side using the API.

    To create a source with Stripe.js, first include the library within your payment page and set your publishable API key.

    Once included, use the following source.create method to create a source, providing the following information:

    Parameter Value
    type bitcoin
    amount A positive integer in the smallest currency unit representing the amount to charge the customer (e.g., 1099 for a $10.99 payment).
    currency usd (Bitcoin payments must be in US Dollars)
    owner[email] The full email address of the customer.
    stripe.createSource({
      type: 'bitcoin',
      amount: 1000,
      currency: 'usd',
      owner: {
        email: 'jenny.rosen@example.com',
      },
    }).then(function(result) {
      // handle result.error or result.source
    });
    

    Server-side source creation

    The use of Stripe.js to create this type of source is optional, but highly recommended. If you forgo this step and pass the information directly to Stripe when creating a Source object, you must take appropriate steps to safeguard any sensitive information that may pass through your servers.

    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    source = Stripe::Source.create(
      :type => "bitcoin",
      :amount => 1000,
      :currency => "usd",
      :owner => {
        :email => "jenny.rosen@example.com",
      },
    )
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    source=stripe.Source.create(
      type='bitcoin',
      amount=1000,
      currency='usd',
      owner={
        "email":'jenny.rosen@example.com'
      }
    )
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    \Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    $source = \Stripe\Source::create(array(
      "type" => "bitcoin",
      "amount" => 1000,
      "currency" => "usd",
      "owner" => array(
        "email" => "jenny.rosen@example.com"
      )
    ));
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.apiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2";
    
    Map<String, Object> ownerParams = new HashMap<String, Object>();
    ownerParams.put("email", "jenny.rosen@example.com");
    
    Map<String, Object> sourceParams = new HashMap<String, Object>();
    sourceParams.put("type", "bitcoin");
    sourceParams.put("amount", 1000);
    sourceParams.put("currency", "usd");
    sourceParams.put("owner", ownerParams);
    
    Source source = Source.create(sourceParams);
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    var stripe = require("stripe")("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    stripe.sources.create({
      type: "bitcoin",
      amount: 1000,
      currency: "usd",
      owner: {
        email: "jenny.rosen@example.com"
      }
    }, function(err, source) {
      // asynchronously called
    });
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.Key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    sourceParams := &stripe.SourceObjectParams{
      Type: "bitcoin",
      Amount: 1000,
      Currency: "usd",
      Owner: &stripe.SourceOwnerParams{
        Email: "jenny.rosen@example.com",
      },
    }
    
    s, err := source.New(sourceParams)
    
    if err != nil {
      // handle error
      return;
    }
    

    Using either method, Stripe returns a Source object containing the relevant details for the method of payment used. Information specific to Bitcoin is provided within the bitcoin subhash.

    {
      "id": "src_18h4EOEniDLYboM3JphgS37m",
      "object": "source",
      "amount": 1000,
      "client_secret": "src_client_secret_OkNv1HJ3melzdk2bgd2o4es8",
      "created": 1470864440,
      "currency": "usd",
      "flow": "receiver",
      "livemode": true,
      "metadata": {},
    See all 41 lines "owner": { "address": null, "email": "jenny.rosen@example.com", "name": "Jenny Rosen", "phone": null, "verified_address": null, "verified_email": null, "verified_name": null, "verified_phone": null }, "receiver": { "address": "1Nar8gbhZqahaKdoxLAnxVhGjd5YoHs8T1", "amount_charged": 0, "amount_received": 0, "amount_returned": 0, "refund_attributes_method": "email", "refund_attributes_status": "missing" }, "status": "pending", "type": "bitcoin", "usage": "single_use", "bitcoin": { "address": "1Nar8gbhZqahaKdoxLAnxVhGjd5YoHs8T1", "amount": 334400, "amount_charged": 0, "amount_received": 0, "amount_returned": 0, "uri": "bitcoin:1Nar8gbhZqahaKdoxLAnxVhGjd5YoHs8T1?amount=0.003344", "refund_address": null } }

    Error codes

    Source creation for Bitcoin payments may return any of the following errors:

    Error Description
    payment_method_not_available The payment method is currently not available. You should invite your customer to fallback to another payment method to proceed.
    processing_error An unexpected error occurred preventing us from creating the source. The source creation should be retried.

    Step 2: Have the customer push funds

    When creating a source, its status is initially set to pending and cannot yet be used to create a charge. Your customer must send the specified amount of bitcoin to make the source chargeable. Customers push bitcoin to the address provided within the receiver[address] attribute. The bitcoin[amount] specifies the amount, in BTC, the customer needs to send.

    There are three pieces of information you should display to the customer:

    • bitcoin[amount]: The amount (in Satoshi) that the customer must send. This amount, like all amounts used by the Stripe API, represents the smallest unit of currency. There are 108 (100,000,000) satoshi in one bitcoin, so the returned bitcoin[amount] must be divided by 100,000,000 to present the amount in BTC.
    • receiver[address]: The bitcoin address that is specific to this receiver
    • bitcoin[uri]: An encoding of the amount and address. If you encode this URI as a QR code, some Bitcoin apps can scan it. If this URI is presented as a hyperlink, customers can click on it to activate their preferred Bitcoin client, if installed.

    Step 3: Charge the Source

    Once the customer has pushed the necessary funds, the source’s status transitions to chargeable and it can be used to make a charge request. This transitions happens asynchronously as confirming a Bitcoin transaction on the blockchain can take minutes.

    For this reason it is essential that your integration rely on webhooks to determine when the source becomes chargeable in order to create a charge. Please refer to our best practices for more details on how to best integrate payment methods using webhooks.

    Webhooks

    The following webhook events are sent to notify you about changes to the source’s status:

    Event Description
    source.chargeable A Source object becomes chargeable after a customer has has sent the required funds for the payment.
    source.canceled A Source object expired and cannot be used to create a charge.

    Source expiration

    A Bitcoin source must be used within six hours of becoming chargeable. If it is not, its status is automatically transitioned to canceled and your integration receives a source.canceled webhook event.

    Similarly, a Bitcoin source’s guaranteed exchange rate expires after 10 minutes, after which point it is canceled. Your JavaScript handler is called client-side and the source’s status transitions to canceled. Any fund received after a source is canceled are automatically refunded back to the customer.

    Once a source is canceled, the customer’s bitcoin payment is refunded automatically—no funds are moved into your account. For this reason, make sure the order is canceled on your end and the customer is notified once you receive the source.canceled event.

    If you receive that callback, you can instruct your servers to create a new source, then update the payment page with the new receiver’s information and start polling.

    Make a charge request using the source

    Once the source is chargeable, from your source.chargeable webhook handler, you can make a charge request using the source ID as the value for the source parameter to complete the payment.

    curl https://api.stripe.com/v1/charges \
       -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
       -d amount=1000 \
       -d currency=usd \
       -d source=src_18eYalAHEMiOZZp1l9ZTjSU0
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    charge = Stripe::Charge.create({
      amount: 1000,
      currency: 'usd',
      source: 'src_18eYalAHEMiOZZp1l9ZTjSU0',
    })
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    charge = stripe.Charge.create(
      amount=1000,
      currency='usd',
      source='src_18eYalAHEMiOZZp1l9ZTjSU0',
    )
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    \Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    $charge = \Stripe\Charge::create(array(
      "amount" => 1000,
      "currency" => "usd",
      "source" => "src_18eYalAHEMiOZZp1l9ZTjSU0",
    ));
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.apiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2";
    
    Map<String, Object> chargeParams = new HashMap<String, Object>();
    chargeParams.put("amount", 1000);
    chargeParams.put("currency", "usd");
    chargeParams.put("source", "src_18eYalAHEMiOZZp1l9ZTjSU0");
    
    Charge charge = Charge.create(chargeParams);
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    var stripe = require("stripe")("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    stripe.charges.create({
      amount: 1000,
      currency: "usd",
      source: "src_18eYalAHEMiOZZp1l9ZTjSU0",
    }, function(err, charge) {
      // asynchronously called
    });
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.Key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    chargeParams := &stripe.ChargeParams{
      Amount: 1000,
      Currency: "usd",
    }
    chargeParams.SetSource("src_18eYalAHEMiOZZp1l9ZTjSU0")
    ch, err := charge.New(chargeParams)
    

    Bitcoin Sources are single-use and cannot not be used for recurring or additional payments. Refer to our Sources & Customers guide for more information on how single-use Sources interact with Customers.

    Step 4: Confirm that the charge has succeeded

    Since the customer has already pushed the funds at the time the Source is chargeable, unless there is an unexpected error, the Charge will immediately succeed.

    You will also receive the following webhook event as the charge is created:

    Event Description
    charge.succeeded The charge succeeded and the payment is complete.

    We recommend that you rely on the charge.succeeded webhook event to notify your customer that the payment process has been completed and their order is confirmed. Please refer to our best practices for more details on how to best integrate payment methods using webhooks.

    Refunding Bitcoin payments

    Bitcoin payments can be refunded through either the Dashboard or API. However, the Bitcoin address where to return the funds needs to be provided by the customer. By default, we automatically contact the customer at the email address provided during source creation when a refund is created (or the source is canceled and funds need to be returned). Once the customer provides us with their Bitcoin address, we process the refund automatically.

    Some users may want to manage the collection of the refund addresses themselves. Please contact us to learn more about this option.

    Handling mispayments

    The customer is responsible for sending the correct amount of bitcoin to fill the source. While uncommon, it is possible for a customer to send an unexpected amount that prevents a payment from being completed—resulting in a mispayment. This can happen when:

    • The customer sends too few bitcoin so the payment cannot be completed
    • The customer sends too many bitcoin and needs to be partially refunded
    • The customer sends the correct amount of bitcoin but they send it after too long a delay, or there’s a network error such that the source token is never posted to your server

    All mispayments are handled automatically by Stripe. When a source is charged, any unused bitcoin received in excess will be returned to the customer automatically (after collecting their refund address as described in the previous section). Similarly, if a source is never charged, it is eventually canceled and any unused bitcoin is also returned the customer automatically.

    You can help avoid the third possibility of mispayments through the use of webhooks. You can configure your integration to receive source.chargeable events, then subsequently create charges from those sources.

    Testing Bitcoin payments

    When creating a Source object using your test API keys, use one of Stripe’s test email addresses when you need to test Bitcoin payments under different conditions.

    Related resources