Stripe direct integration

Stripe allows you to collect credit card payments for recurring or one-time payments.
Learn more about Stripe

In this guide:

 

How to send correct data to Octobat:

Integration requirements

The first thing that you have to do is to .
Then, you have to own a Stripe account .
To ensure that all your invoices are correctly generated, you must follow the way of this guide to make Stripe API calls.

Connect your Octobat and Stripe accounts

Stripe connect

During your registration, you will be able to connect your Stripe account. At this moment, Octobat asks you read and write accesses to your Stripe account.

Testing

The best way for testing the Stripe integration with Octobat is to make API calls or create some objects within your Stripe dashboard and look what is happening on Octobat.

Collecting the customer's billing address

Octobat needs at least the billing country of your customer as an evidence in order to calculate the right tax rate.
(If your business is based in the US, Octobat also needs the billing postal code of your customer)

  1. In the front-end (token)

    Via Stripe.js v3

    // Handle form submission
    var form = document.getElementById('payment-form');
    form.addEventListener('submit', function(event) {
      event.preventDefault();
    
      var extraDetails = {
        name: form.querySelector('input[name=cardholder-name]').value,
        address_line1: form.querySelector('input[name=billing_address_line1]').value,
        address_line2: form.querySelector('input[name=billing_address_line2]').value,
        address_city: form.querySelector('input[name=billing_address_city]').value,
        address_state: form.querySelector('input[name=billing_address_state]').value, // State/County/Province/Region
        address_zip: form.querySelector('input[name=billing_address_zip]').value, // billing ZIP code as a string (e.g., "94301")
        address_country: form.querySelector('input[name=billing_address_country]').value // 2-letter ISO 3166-1 alpha-2 code
      };
    
      stripe.createToken(card, extraDetails).then(function(result) {
        // handle result.error or result.token
      });
    });
    

    Via Stripe.js v2

    Stripe.card.createToken({
      number: $('.card-number').val(),
      cvc: $('.card-cvc').val(),
      exp_month: $('.card-expiry-month').val(),
      exp_year: $('.card-expiry-year').val(),
      name: $('.cardholder-name').val(),
      address_line1: $('.billing-address-line1').val(),
      address_line2: $('.billing-address-line2').val(),
      address_city: $('.billing-address-city').val(),
      address_state: $('.billing-address-state').val(), // State/County/Province/Region
      address_zip: $('.billing-address-zip').val(), // billing ZIP code as a string (e.g., "94301")
      address_country: $('.billing-address-country').val() // 2-letter ISO 3166-1 alpha-2 code
    }, stripeResponseHandler);
    
     
  2. In the back-end (API calls)
    curl https://api.stripe.com/v1/customers \
      -u sk_test_oCRWOhpjMI3qPvPoYYgbiWHI: \
      -d description="John Doe" \
      -d email="billing@johndoe.it" \
      -d source=tok_h2mE320ZFnqlEf8abECRANpJ \
      -d business_vat_id='IT01709820995' \
      -d metadata[address_line1]='801 Via dei Condotti' \
      -d metadata[address_line2]='Secondo piano' \
      -d metadata[address_city]='Roma' \
      -d metadata[address_state]='' \
      -d metadata[address_zip]='10000' \
      -d metadata[address_country]='IT' \
      -d metadata[tax_number]='IT01709820995' \
      -d metadata[business_type]='B2B'
    
    
    customer = Stripe::Customer.create(
      :description => 'John Doe',
      :email => 'billing@johndoe.it',
      :source => params[:stripeToken], # Using Rails
      :business_vat_id => 'IT01709820995', # if valid, business type is B2B else B2C
      :metadata => {
        :address_line1 => '801 Via dei Condotti',
        :address_line2 => 'Secondo piano',
        :address_city => 'Roma',
        :address_state => '', # State/County/Province/Region
        :address_zip => '10000', # billing ZIP code as a string (e.g., "94301")
        :address_country => 'IT', # 2-letter ISO 3166-1 alpha-2 code
        :tax_number => 'IT01709820995', # can replace business_vat_id
        :business_type => 'B2B' # Force the customer business type even if the 'business_vat_id' is not valid
      }
    )
    
    
    
    $customer = \Stripe\Customer::create(array(
      'description' => 'John Doe',
      'email' => 'billing@johndoe.it',
      'source'  => $_POST['stripeToken'],
      'business_vat_id' => 'IT01709820995', // if valid, business type is B2B else B2C
      'metadata' => array(
        'address_line1' => '801 Via dei Condotti',
        'address_line2' => 'Secondo piano',
        'address_city' => 'Roma',
        'address_state' => '', // State/County/Province/Region
        'address_zip' => '10000', // billing ZIP code as a string (e.g., "94301")
        'address_country' => 'IT', // 2-letter ISO 3166-1 alpha-2 code
        'tax_number' => 'IT01709820995', // can replace business_vat_id
        'business_type' => 'B2B' // Force the customer business type even if the 'business_vat_id' is not valid
      )
    ));
    
    
    customer = stripe.Customer.create(
      description="John Doe",
      email="billing@johndoe.it",
      source=request.form['stripeToken'], # Using Flask
      business_vat_id="IT01709820995", # if valid, business type is B2B else B2C
      metadata={
        "address_line1": "801 Via dei Condotti",
        "address_line2": "Secondo piano",
        "address_city": "Roma",
        "address_state": "", # State/County/Province/Region
        "address_zip": "10000", # billing ZIP code as a string (e.g., "94301")
        "address_country": "IT", # 2-letter ISO 3166-1 alpha-2 code
        "tax_number": "IT01709820995", # can replace business_vat_id
        "business_type": "B2B", # Force the customer business type even if the 'business_vat_id' is not valid
      },
    )
    
    
    var stripe = require("stripe")(
      "sk_test_oCRWOhpjMI3qPvPoYYgbiWHI"
    );
    
    stripe.customers.create({
      description: 'John Doe',
      email: "billing@johndoe.it",
      source: request.body.stripeToken, // Using Express
      business_vat_id: "IT01709820995", // if valid, business type is B2B else B2C
      metadata: {
        address_line1: "801 Via dei Condotti",
        address_line2: "Secondo piano",
        address_city: "Roma",
        address_state: "", // State/County/Province/Region
        address_zip: "10000", // billing ZIP code as a string (e.g., "94301")
        address_country: "IT", // 2-letter ISO 3166-1 alpha-2 code
        tax_number: "IT01709820995", // can replace business_vat_id
        business_type: "B2B" // Force the customer business type even if the 'business_vat_id' is not valid
      }
    }, function(err, customer) {
      // asynchronously called
    });
    
    
    

VAT compliance data

That's better to send us the IP address of the customer as another piece of evidence (added to the customer's billing country and credit card country) in order to deduct the right location.

  1. Subscriptions
    curl https://api.stripe.com/v1/subscriptions \
      -u sk_test_oCRWOhpjMI3qPvPoYYgbiWHI: \
      -d customer=cus_NO8K3C7wYRfSUv \
      -d plan=basic-monthly \
      -d metadata[ip_address]="90.90.71.253"
    
    
    Stripe::Subscription.create(
      :customer => customer.id,
      :plan => "basic-monthly",
      :metadata    => {
        :ip_address => request.remote_ip # An evidence of the customer's localization
      }
    )
    
    
    \Stripe\Subscription::create(array(
      'customer' => $customer->id,
      'plan'     => "basic-monthly",
      'metadata' => array(
        'ip_address' => $_SERVER['REMOTE_ADDR'] // An evidence of the customer's localization
      )
    ));
    
    import socket
    
    stripe.Subscription.create(
      customer=customer.id,
      plan="basic-monthly",
      metadata={
        "ip_address": socket.gethostbyname(socket.gethostname()), # An evidence of the customer's localization
      },
    )
    
    var stripe = require("stripe")(
      "sk_test_oCRWOhpjMI3qPvPoYYgbiWHI"
    );
    
    stripe.subscriptions.create({
      customer: customer.id,
      plan: "basic-monthly",
      metadata: {
        ip_address: request.connection.remoteAddress // An evidence of the customer's localization
      }
    }, function(err, subscription) {
        // asynchronously called
      }
    );
    
     
  2. One-time charges attached to a customer
    curl https://api.stripe.com/v1/charges \
      -u sk_test_oCRWOhpjMI3qPvPoYYgbiWHI: \
      -d customer=cus_NO8K3C7wYRfSUv \
      -d amount=999 \
      -d currency=eur \
      -d description="One-Time Charge" \
      -d metadata[ip_address]="90.90.71.253"
    
    Stripe::Charge.create(
      :customer    => customer.id,
      :amount      => 999,
      :description => 'One-Time Charge',
      :currency    => 'eur',
      :metadata    => {
        :ip_address => request.remote_ip # An evidence of the customer's localization
      }
    )
    
    \Stripe\Charge::create(array(
      'customer'    => $customer->id,
      'amount'      => 999,
      'description' => 'One-Time Charge',
      'currency'    => 'eur',
      'metadata' => array(
        'ip_address' => $_SERVER['REMOTE_ADDR'] // An evidence of the customer's localization
      )
    ));
    
    import socket
    
    stripe.Charge.create(
      customer=customer.id,
      amount=999,
      description="One-Time Charge",
      currency="eur",
      metadata={
        "ip_address": socket.gethostbyname(socket.gethostname()), # An evidence of the customer's localization
      },
    )
    
    var stripe = require("stripe")(
      "sk_test_oCRWOhpjMI3qPvPoYYgbiWHI"
    );
    
    stripe.charges.create({
      customer: customer.id,
      amount: 999,
      description: "One-Time Charge",
      currency: "eur",
      metadata: {
        ip_address: request.connection.remoteAddress // An evidence of the customer's localization
      }
    }, function(err, charge) {
        // asynchronously called
      }
    );
    
     
  3. One-time charges without customer
    curl https://api.stripe.com/v1/charges \
      -u sk_test_oCRWOhpjMI3qPvPoYYgbiWHI: \
      -d source=tok_189gLz2eZvKYlo2C8WdPMBzS \
      -d receipt_email='billing@johndoe.it' \
      -d amount=999 \
      -d currency=eur \
      -d description="One-Time Charge" \
      -d metadata[ip_address]="90.90.71.253" \
      -d metadata[tax_number]='IT01709820995'
    
    
    Stripe::Charge.create(
      :source          => params[:stripeToken],
      :receipt_email  => 'billing@johndoe.it',
      :amount         => 999,
      :description    => 'One-Time Charge',
      :currency       => 'eur',
      :metadata       => {
        :ip_address => request.remote_ip, # An evidence of the customer's localization
        :tax_number => 'IT01709820995' # Proof that your customer is a business in European Union
      }
    )
    
    
    \Stripe\Charge::create(array(
      'source'         => $_POST['stripeToken'],
      'receipt_email' => 'billing@johndoe.it',
      'amount'        => 999,
      'description'   => 'One-Time Charge',
      'currency'      => 'eur',
      'metadata'      => array(
        'ip_address' => $_SERVER['REMOTE_ADDR'], // An evidence of the customer's localization
        'tax_number' => 'IT01709820995' // Proof that your customer is a business in European Union
      )
    ));
    
    
    import socket
    
    stripe.Charge.create(
      source=request.form['stripeToken'], # Using Flask
      receipt_email="billing@johndoe.it",
      amount=999,
      description="One-Time Charge",
      currency="eur",
      metadata={
        "ip_address": socket.gethostbyname(socket.gethostname()), # An evidence of the customer's localization
        "tax_number": 'IT01709820995', # Proof that your customer is a business in European Union
      },
    )
    
    
    var stripe = require("stripe")(
      "sk_test_oCRWOhpjMI3qPvPoYYgbiWHI"
    );
    
    stripe.charges.create({
      source: request.body.stripeToken, // Using Express
      receipt_email: "billing@johndoe.it",
      amount: 999,
      description: "One-Time Charge",
      currency: "eur",
      metadata: {
        ip_address: request.connection.remoteAddress, // An evidence of the customer's localization
        tax_number: 'IT01709820995' // Proof that your customer is a business in European Union
      }
    }, function(err, charge) {
        // asynchronously called
      }
    );
    
    
    

Others metadata for Charge and Subscription

Metadata Description
quantity Put the quantity on the invoice and calculate the unit price automatically.
tax_rate Force the tax rate. Default is calculated by Octobat.
product_type Can be 'eservice', 'standard' or 'ebook'. Default is into your tax settings .
business_type Default: 'B2B' if vat number is filled else 'B2C'
It will force your customer to be a business ('B2B') or a consumer ('B2C').
sequence Octobat's Numbering Sequence ID.
There is one by default in your documents settings
notes Some notes added to the end of the invoice