NAV Navbar
js

Introduction

Quaderno is a set of APIs to automate and improve tax management in businesses of all sizes. Here are some resources that will help you understand the basics of all of them.

The documentation is organized into three major areas:

Not a developer?

A custom Quaderno integration requires you to either be or hire a developer. But you can use Quaderno through any number of third-parties plugins and libraries built by our community, such as for Shopify, Amazon FBA, and WooCommerce.

Need more help?

Just send us an email. We’re always happy to help out with code or any other questions you might have.

The Sandbox

The Quaderno Sandbox mirrors the features found on the Quaderno Production servers and let you to test our API and/or connect your trial accounts from other services like Stripe, PayPal, Braintree, etc.

The Sandbox has parity with the Quaderno main feature set supported by the live environment. This means you can test your Quaderno processes and know they will behave the same on the production servers as they do in the Sandbox environment.

Your credentials for the Production environment does not work on the Sandbox. You need to create a new account.

By using your Sandbox account, you can test and debug your application without referencing any real Quaderno users or their live Quaderno accounts. The Sandbox lets you operate your application in a safe environment and provides you a way to fine tune your Quaderno routines before moving your product into production.

We’re always happy to help out with code or any other questions you might have. Please drop us a line.

Quaderno.js

Introduction

This is the API reference for Quaderno.js. Use Quaderno.js’ APIs to calculate taxes, and accept payments with Stripe and Paypal.

Including Quaderno.js

However you’re using Quaderno.js, you always begin by including the library and setting your API key. To get started, include this script on your pages — it should always be loaded directly from https://js.quaderno.io:

  <script src="https://js.quaderno.io/v3/"></script>

If you are using Stripe as your gateway you should also include Stripe-js library.

  <script src="https://js.stripe.com/v3/"></script>

Supported browsers

Quaderno.js strives to support all recent versions of major browsers. For the sake of security and providing the best experience to the majority of customers, we do not support browsers that are no longer receiving security updates and represent a small minority of traffic.

If you have an issue with Quaderno.js on a specific browser, please contact us so we can improve its support.

Reference

Quaderno.publishableKey = "pk_test00112233445566";
Quaderno.productId = "prod_0011223344556677";
Quaderno.gateway = "stripe";
Quadeno.firstName = "Perro";
Quaderno.lastName = "Muchacho";
Quaderno.email = "perro@muchacho.com";
Quaderno.streetLine1 = "C/Enrique Jardiel Poncela 4 ";
Quaderno.city = "Madrid";
Quaderno.postalCode = "28016";
Quaderno.region = "Madrid";
Quaderno.country = "ES";
Quaderno.redirectUrl = "https://your-webpage.com/thank-you";

When you include the Quaderno.js script in your page, a global Quaderno object will be available with the following attributes:

Attribute Description
publishableKey Your Quaderno publishable key.
productId The Quaderno code of the product you want to sell.
gateway The payment gateway to process the transaction. Supported values are: stripe and `paypal. Default is stripe.
firstName
lastName
email
companyName
streetLine1
streetLine2
city
postalCode
region
country ISO 3166-1 alpha-2
businessNumber A valid business number. Supported values are: EU VAT numbers, ABN, and NZBN.
coupon A valid Stripe subscription percent off discount coupon mapped in your Quaderno account.
redirectUrl URL to which redirect your customers after finishing the checkout process in PayPal. Mandatory if gateway value is set to paypal.

init( publishableKey, productId [, options] )

  Quaderno.init(publishableKey, productId, {
    gateway: "stripe",
    firstName: "Marcial",
    lastName: "Ruiz Escribano"
  }).then(function(response){
    console.log(response.gateway, response.product);
  }).catch(function(error){
    console.log(error.description, error.messages);
  });

Async request. Use this method to initialize the global object Quaderno.

It accepts an optional options object. Available options are documented below:

Attribute Description
gateway The payment gateway to process the transaction. Supported values are: stripe and paypal. Default is stripe.
firstName
lastName
email
companyName
streetLine1
streetLine2
city
postalCode
region
country ISO 3166-1 alpha-2
businessNumber A valid business number. Supported values are: EU VAT numbers, ABN, and NZBN.
redirectUrl URL to which redirect your customers after finishing the checkout process in PayPal. Mandatory if gateway value is set to paypal.

This method returns a Promise which resolves with a result object. This object has either:

If there's any issue, this method returns a Promise which rejects with an error object. This object has either:

initForm( formId )

  Quaderno.initForm("#formId").then(function(response){
    console.log(response.gateway, response.product);
  }).catch(function(error){
    console.log(error.description, error.messages);
  });

Async request. This method also initializes the global object Quaderno from a form object.

This method returns a Promise which resolves with a result object. This object has either:

If there's any issue, this method returns a Promise which rejects with an error object. This object has either:

calculateTaxes()

  Quaderno.calculateTaxes().then(function(taxObject){
    console.log(taxObject.name, taxObject.rate, taxObject.country); // ie. "VAT", 20, "GB"
  })

Async request. Calculates the taxes based on the billing data from the Quaderno object.

This method returns a Promise which resolves with a tax object.

calculatePrice()

  priceObject = Quaderno.calculatePrice();

  priceObject.subtotal;
  priceObject.taxes;

Calculates the final price of the product, tax inclusive.

This method returns a price object with the following attributes:

createTransaction( cardToken )

  Quaderno.createTransaction(cardToken).then(function(transactionDetails){
    console.log(transactionDetails)
  }).catch(function(error){
    // Show the error message if the transaction couldn't be created
    alert(error.description);
  })

Async request. Creates either a subscription or a one-off charge if the payment gateway is Stripe. This method returns a Promise which resolves with an object with information related to the recently created transaction.

redirectToPayPal()

  Quaderno.redirectToPayPal().catch(function(error){
    // Show the error message if the redirection cannot be done
    alert(error.description);
  })

Async request. Automatically redirect your customer to the PayPal checkout page.

Remember to specify a value for redirectURL field in order to be able to use this method.

destroy()

  Quaderno.destroy();

Remove event listeners from the DOM elements. It might be useful if you have single-page apps and have tied the Quaderno object to a form via initForm or the simple initialization.

getGateway()

  Quaderno.gateway = "stripe";

  Quaderno.getGateway().then(function(gateway){
    // Stripe publishable key needed for card tokenization
    console.log(gateway.gatewayKey);
  });

Async request. Retrieves the payment gateway public key. Returns a gateway object in the resolve function.

getProduct()

  Quaderno.productId = "productId";

  Quaderno.getProduct().then(function(product){
    console.log(product.name);
  });

Async request. Retrieve the product info identified by productId. Returns a product object in the resolve function.

getTaxes()

  taxes = Quaderno.getTaxes();

  taxes.name;
  taxes.rate;
  taxe.country;

Reads the taxes cache and returns a tax object.

reload()

  Quaderno.gateway = "stripe";
  Quaderno.productId = "anotherProduct";

  Quaderno.reload().then(function(response){
    console.log(response.gateway, response.product);
  }).catch(function(error){
    console.log(error.description, error.messages);
  });

Async request. Reloads the object Quaderno if any notable configuration options (mainly publishableKey and productId) have been modified.

This method returns a Promise with the same behavior as Quaderno.init

validateBusinessNumber()

  Quaderno.businessNumber = "GB1234567";
  Quaderno.country = "GB";

  Quaderno.validateBusinessNumber().then(function(response){
    console.log(response.valid);
  }).catch(function(error){
    console.log(error.descriptions);
  });

Async request. This method validates the customer's business number. Currently Quaderno validates EU VAT numbers, ABN, and NZBN.

This method returns a result object with the following attribute:

The Tax object

This object is passed by the resolve function of the Promise returned by the Quaderno.calculateTaxes method or by invoking Quaderno.readTaxes.

Attribute Description
country A valid ISO 3166-1 alpha-2 code.
region
county
name
rate
extraName
extraRate
taxClass The tax class of the transaction. Can be one of the following: standard, eservice or ebook.
invalidCoupon Boolean. If a coupon was passed, indicates wether it was valid or not.
discountedAmount The original amount minus discounts.
percentOff The discount rate applied.

The Gateway object

Contains relevant information about the payment gateway. Currently, it only works for Stripe. It's returned by the resolve function of Quaderno.init, Quaderno.initForm (in conjunction with the product object) or Quaderno.getGateway. It contains just an attribute:

Attribute Description
gatewayKey Your Stripe publishable key.

The Product object

This object contains the relevant information related to the productID you've set. It's returned by the resolve function of Quaderno.init, Quaderno.initForm (in conjunction with the gateway object) or Quaderno.getProduct.

Attribute Description
name A valid ISO 3166-1 alpha-2 code.
image
gateway The payment gateway to process the transaction. Supported values are: stripe and paypal. Default is stripe.
unitCost
currency
kind Indicate if the product is either a subscription or a one-off.
extraRate
taxClass The tax class of the transaction. Can be one of the following: standard, eservice or ebook.
taxType Indicates if the tax is included or excluded from the unitCost

How to initialize Quaderno.js

Simple automatic init

Automatically loads quaderno.js if the form has the quaderno-payment-form ID and a valid data-publishable-key and data-product-id.

The input fields will be automatically detected as long as they have the data-quaderno with their definition:

    <head>
      <script src="https://js.quaderno.io/v3/"></script>
    </head>

    <body>
      <form id="quaderno-payment-form" data-publishable-key="pk_xxxxxxxx" data-product-id="prod_xxxxxxxx">
        <input data-quaderno="firstName" />
        <input data-quaderno="lastName" />
        <select data-quaderno="country"> <!--options … --> </select>
        <!-- … -->
      </form>
    </body>

Deferred automatic init

If you don't want the form to load automatically, you can load it later by not using the "quaderno-payment-form" id, and calling the initForm method whenever you want.

    <head>
      <script src="https://js.quaderno.io/v3/"></script>
    </head>

    <body>
      <form id="payment-form" data-publishable-key="pk_xxxxxxxx" data-product-id="prod_xxxxxxxx">
        <input data-quaderno="firstName" />
        <input data-quaderno="lastName" />
        <!-- … -->
      </form>

      <script>
        Quaderno.initForm('#payment-form').then(function(response) {
          console.log(response.gateway, response.product);
        }).catch(function(error){
          console.log(error.description, error.messages);
        });
      </script>
    </body>

Custom init

Futhermore, you can also dissociate Quaderno from the DOM by setting the Quaderno object properties by yourself. This means you need to explicitly set the minimum mandatory configuration options during the init call.

    <label for="country">
      <span>Country</span>
      <input id="country" name="country" value="ES" />
    </label>

    <label for="postal-code">
      <span>Postal code</span>
      <input id="postal-code" name="postal-code" value="35007" />
    </label>

    <script>
      Quaderno.init(publishableKey, productId,
        {
          gateway: 'stripe',
          country: $('#country').val(),
          postalCode: $('#postal-code').val(),
        }
      ).then(function(response) {
        console.log(response.gateway, response.product);
      }).catch(function(error) {
        console.log(error.description, error.messages);
      });
    </script>

By using the custom init, you can also programmatically swap configuration options by setting the Quaderno attributes and reloading it. In this example we are swapping the product and reloading so we can get the new product information:

    Quaderno.productId = 'newProductId';

    // As the new product might have a different price and/or taxes configurations, we must call "reload" to retrieve the missing information
    Quaderno.reload().then(function(response) {
      console.log(response.gateway, response.product);
    }).catch(function(error) {
      console.log(error.description, error.messages);
    });

Usually you want to reload the checkout when one of those values has changed:

How to use Quaderno.js to calculate taxes

In this example, we are going to handle updates on the relevant tax-related fields to force taxes calculations and show it in a <span>:

  <label for="country">
    Country
    <select id="country">
      <option value="US" selected>United States</option>
      <option value="GB">United Kingdom</option>
      <option value="DE">Germany</option>
      <option value="FR">France</option>
      <option value="IT">Italy</option>
      <option value="ES">Spain</option>
      <option value="CA">Canada</option>
      <option value="AU">Australia</option></select>
  </label>

  <label for="postal-code">
    Postal code
    <input id="postal-code">
  </label>

  <label for="business-number">
    <input id="business-number">
  </label>

  Taxes: <span id="tax-rate"></span>

  <script>
    function reloadTaxes(){
      Quaderno.calculateTaxes().then(function(taxObject){
        document.querySelector('tax-rate').innerHTML = taxObject.name + " " + taxObject.rate + "%"; // ie.: VAT 20%
      })
    }

    // Handle the change events on the relevant user-inputs
    document.querySelector('#country').addEventListener('change', function () {
      Quaderno.country = this.value
      reloadTaxes()
    })

    document.querySelector('#postal-code').addEventListener('change', function () {
      Quaderno.postalCode = this.value
      reloadTaxes()
    })

    document.querySelector('#business-number').addEventListener('change', function () {
      Quaderno.businessNumber = this.value
      reloadTaxes()
    })
  </script>

You can use Quaderno.js to calculate taxes by invoking the method Quaderno.calculateTaxes.

If you are showing real time taxes calculations it's usually a good idea to force taxes calculations when the country, postal code or business number has changed.

How to use Quaderno.js to charge your customers

All the methods described in this page needs at least two mandatory attributes:

Whether your transaction is a recurring charge or a one-off charge is determined by the way you've registered the product in Quaderno. Choose "subscription" if you want a recurring charge or "one-off" if you want a one-off charge.

With simple automatic init or deferred automatic init

The simple automatic init is the most simple way to integrate Quaderno.js with your page. You just need to set some attributes on your checkout form and Quaderno.js will automatically link to it in order to show live taxes calculations and grab the necessary data from your customer input. Then you will only need to tokenize the card and handle the success or the errors.

The deferred automatic init is almost the same but it let you decides when and to which form should Quaderno.js be initialized by providing the function Quaderno.initForm (more information here).

Either way, in order to create a transaction first, grab the code of your subscription product and paste it as the data-product-id in your form. For example:

  <div id="payment-errors"></div>

  <form id="quaderno-payment-form"
    data-publishable-key="pk_test_publishable_key"
    data-product-id="prod_code"
    data-gateway="stripe">
    <label>
      <span> First name </span>
      <input data-quaderno="firstName">
    </label>

    <label>
      <span> Last name </span>
      <input data-quaderno="lastName">
    </label>

    <label>
      <span> Country </span>
      <input data-quaderno="country">
    </label>

    <label>
      <span> Postal code </span>
      <input data-quaderno="postalCode">
    </label><div id="card-element"></div>
    <button type="submit" id="submit-button">Pay now</button>
  </form>

When the customer submits the form, in case you are using a card payment method such as Stripe, you'll need to first tokenize the card and pass the resulting token to Quaderno.createTransaction. In the following example we are loading our core after the page has been properly loaded in order to tokenize the card:

  <script>
    window.addEventListener('load', function(){
      var form = document.getElementById('quaderno-payment-form');
      var errorPanel = document.getElementById('payment-errors');

      // Setup the form handlers after Quaderno.js has been initialized
      form.addEventListener('initialized.Quaderno', function() {
        var stripe = Stripe(Quaderno.gatewayKeys.stripe);
        var elements = stripe.elements();
        var card = elements.create('card', { hidePostalCode: true });
        card.mount('#card-element');

        // Handle submit event on the form
        form.addEventListener('submit', function(event) {
          event.preventDefault();

          var button = document.getElementById('submit-button');
          // Disable the submit button to prevent multiple clicks
          button.disabled = true;

          // Tokenize the card
          stripe.createToken(card).then(function(result) {
            if (result.error) {
              // Inform the customer that there was an error.
              errorPanel.textContent = result.error.message;
              button.disabled = false;
            } else {
              // If the tokenization was a success then send the token to your server.
              Quaderno.createTransaction(result.token.id).then(function(response){
                // Submit the form to your backend if everything was correct
                form.submit();
              }).catch(function(error){
                // Show the error message if the transaction couldn't be created
                errorPanel.textContent = error.description;
                button.disabled = false;
              })
            }
          });
        })
      })
    })
  </script>

Please note the relevant parts in the snippet from above, first we call stripe.createToken in order to tokenize the card, as it's a JS promise, we expect the result inside the resolve function. Only if there isn't any errors we attempt to create the transaction in Stripe by calling Quaderno.createTransaction.

If you use PayPal then it's much simpler as it doesn't require any card tokenization, you just need to redirect your customer to PayPal after they submit the form. As a downside as the customer is redirected outside of our checkout, we are no longer able to return the PayPal in the promise:

  <script>
    window.addEventListener('load', function(){
      var form = document.getElementById('quaderno-payment-form');
      var errorPanel = document.getElementById('payment-errors');

      // Setup the form handlers after Quaderno.js has been initialized
      form.addEventListener('initialized.Quaderno', function() {
          // Handle submit event on the form
        form.addEventListener('submit', function(event) {
          event.preventDefault();

          var button = document.getElementById('submit-button');
          // Disable the submit button to prevent multiple clicks
          button.disabled = true;

          // Redirect your customer to PayPal
          Quaderno.redirectToPayPal().catch(function(error){
            // Handle possible errors
            errorPanel.textContent = error.description;
            button.disabled = false;
          });
        })
      })
    })
  </script>

In this case the relevant function is Quaderno.redirectToPayPal, in case of success it automatically redirects the customer to the PayPal payment page, otherwise we will catch the error in the reject block and show it to the customer.

Remember that in order to use Paypal, you should have set the value of the payment form attribute data-gateway to paypal. In addition to that, you should have set a value for redirectURL so you can use Quaderno.redirectToPayPal. If you are using the automatic initialization method, you should use the data-redirect-url attribute in the form tag so it is automatically detected.

With custom init

  <h1>James Tiberius Kirk</h1>
  <span id="country">CH</span>
  <label>
    Postal code
    <input id="postal-code" />
  </label>

  <script>
    var publishableKey = 'pk_test_0123456789';
    var productId = 'prod_0123456789';

    Quaderno.init(publishableKey, productId,
      {
        gateway: 'stripe',
        firstName: $('h1').html(),
        streetLine1: 'USS Enterprise',
        country: $('#country').val(),
      }
    ).then(function(response) {
      console.log(response.gateway, response.product);
    }).catch(function(error) {
      console.log(error.description, error.messages);
    });
  </script>

The custom init provides you all the flexibility you need in order to integrate Quaderno.js with your system. Unlike the automatic init or the deferred automatic init, it doesn't require the rigid schema of data attributes, it doesn't even require to be linked to any element from the DOM if you don't want to!

The way it operates is very simple, you just need the global Quaderno object and assign your customer attributes to its accepted fields.

First we need to initialize the Quaderno object:

After you have the Quaderno object correctly configured, all you need is to tokenize the card (if you are using a card payment method) and create the transaction via Quaderno.createTransaction :

  <h1>James Tiberius Kirk</h1>
  <span id="country">CH</span>
  <label>
    Postal code
    <input id="postal-code" />
  </label>

  <!-- Card container for Stripe elements. You can get more information here: https://stripe.com/docs/stripe-js-->
  <div id="card-element"></div>

  <button id="pay-button">Pay now!</button>

  // Tokenize the card with Stripe and create the transaction.
  <script>
    var publishableKey = 'pk_test_0123456789';
    var productId = 'prod_0123456789';
    var stripe = null;

    // Initialize the Quaderno object
    Quaderno.init(publishableKey, productId,
      {
        gateway: 'stripe',
        firstName: $('h1').html(),
        streetLine1: 'USS Enterprise',
        country: $('#country').html(),
        postalCode: $('#postal-code').val(),
      }
    ).then(function(response) {
      // After a successful initialization we can mount Stripe elements
      stripe = Stripe(Quaderno.gatewayKeys.stripe);
      elements = stripe.elements();
      card = elements.create('card', { hidePostalCode: true });
      card.mount('#card-element');

      // Tokenize the card and create the transaction when the customer clicks the button
      $('#pay-button').on('click', function(){
        // Disable the button in order to prevent multiple clicks
        $(this).attr('disabled', 'disabled');

        // Tokenize the card
        stripe.createToken(card).then(function(result) {
          if (result.error) {
            //Tokenization error: inform the customer that there was an error.
            alert(result.error.message);
            button.disabled = false
          } else {
            // Just an example of updating the postal code
            Quaderno.postalCode = $('#postal-code').val();

            // Tokenization success: create the transaction.
            Quaderno.createTransaction(result.token.id).then(function(response){
              // Submit the form to your backend if everything was correct
              form.submit();
            }).catch(function(error){
              // Show the error message if the transaction couldn't be created
              alert(error.description);
              button.disabled = false;
            })
          }
        });
      })
    }).catch(function(error) {
      console.log(error.description, error.messages);
    });
  </script>

If you are using PayPal as the configured gateway, rather than using Quaderno.createTransaction, you need to call Quaderno.redirectToPayPal:

  <h1>James Tiberius Kirk</h1>
  <span id="country">CH</span>
  <label>
    Postal code
    <input id="postal-code" />
  </label>

  <!-- Card container for Stripe elements. You can get more information here: https://stripe.com/docs/stripe-js-->
  <div id="card-element"></div>

  <button id="pay-button">Pay now!</button>

  // Tokenize the card with Stripe and create the transaction.
  <script>
    var publishableKey = 'pk_test_0123456789';
    var productId = 'prod_0123456789';

    // Initialize the Quaderno object
    Quaderno.init(publishableKey, productId,
      {
        gateway: 'paypal',
        firstName: $('h1').html(),
        streetLine1: 'USS Enterprise',
        country: $('#country').html(),
        postalCode: $('#postal-code').val(),
        redirectUrl: 'https://your-webpage.com/thank-you'
      }
    ).then(function(response) {
      // Redirect to PayPal when the customer clicks the button
      $('#pay-button').on('click', function(){
        // Disable the button in order to prevent multiple clicks
        var button = $(this).attr('disabled', 'disabled');
        // Just an example of updating the postal code
        Quaderno.postalCode = $('#postal-code').val();

        // Redirect your customer to PayPal
        Quaderno.redirectToPayPal().catch(function(error){
          // Handle possible errors
          alert(error.description);
          button.disabled = false;
        });
      });
    }).catch(function(error) {
      console.log(error.description, error.messages);
    });
  </script>

Checkout

Introduction

Checkout is the best billing flow, on web and mobile. Checkout builds on top of Quaderno.js to provide your users with a streamlined, mobile-ready payment experience that is constantly improving.

Try the demo below with this test card number: 4111 1111 1111 1111

Reference

When you include the Quaderno Checkout script in your page, a global QuadernoCheckout object will be available with the following methods:

configure(options = {})

QuadernoCheckout.configure({
  publishableKey: 'pk_test_00112233445566778899',
  paypal: true,
  cardGateway: 'stripe',
  locale: 'es',
  callback: function(e){
    // Transaction successfully created
    console.log(e)
  }
});

Configures the basic checkout options that cannot be changed (unless close() is invoked). Accepts the following options:

Option Mandatory Description
publishableKey Yes Your Quaderno publishable key.
charge No A JWT with extra information about the transaction.
cardGateway No String (only stripe). Specify if you want to activate the Stripe card inputs
paypal No Boolean. Specify if you want to activate PayPal as payment method
color No The RGB color for the Checkout interface. The default is #4C7800.
locale No Localize the Checkout interface (2-letter ISO code). The default is auto`.
callback No (Recommendable) A function to handle the response details after the transaction for a card payment has been made.
tosUrl No (Yes if privacyUrl is present) An url pointing to a page with your Terms of Service
privacyUrl No (Yes if tosUrl is present) An url pointing to a page with your privacy policy

open([options = {}])

QuadernoCheckout.open({
  redirectUrl: 'https://your-webpage.com/thank-you',
  discount: true,
  firstName: 'Steve',
  lastName: 'Rogers',
  email: 'the@nomad.com',
  country: 'US',
  postalCode: '11201',
  productId: '123456',
  billingAddress: true
});

Programmatically opens the checkout with the options passed. The parameters supported by the open() method are the following:

Option Mandatory Description
redirectUrl Yes (only if paypal has been set to true) URL to which redirect your customers after finishing the checkout process in PayPal.
productId Yes The ID of the product you want to sell.
charge No A JWT with extra information about the transaction.
billingAddress No The checkout form ask for the customer’s full billing address and tax ID. The default is false.
panelLabel No The label of the payment button in the Checkout (e.g. “Subscribe now”, “Pay {{amount}}”, etc.). If you include {{amount}}, it will be replaced by the provided amount. Otherwise, the amount will be appended to the end of your label.
company No Boolean. Toggle the company name input. Default is false
firstName No Your customer’s first name, to pre-fill the checkout form.
lastName No Your customer’s last name, to pre-fill the checkout form.
companyName No Your customer’s company name, to pre-fill the checkout form.
email No Your customer’s email address, to pre-fill the checkout form.
country No 2-letter ISO code. Set it if you want to preload the customer's country.
discount No Customers can enter a coupon code (only works for Stripe subscriptions). The default is false.

close()

QuadernoCheckout.close();

Programmatically close the checkout form and remove it from your DOM. After this, you can call configure again if you want to set up basic configuration options again or open() to reopen the checkout form.

Integration

Depending on your needs, you can either integrate Checkout as just a copy and paste snippet with almost zero coding with the simple integration or you can get more flexibility by using the custom integration.

Simple integration

<form action="/response-handler" method="POST">
  <script src="https://checkout.quaderno.io/v3/checkout.js" class="quaderno-button"
  data-company="false"
  data-publishable-key="pk_test_LNpesCnUBN6Ax__xbmc4"
  data-card-gateway="stripe"
  data-paypal="true"
  data-product-id='prod_61ffa845b4a0b8'
  data-locale="en"
  data-label="A demo button"
  data-billing-address="true"
  data-panel-label="Pay {{amount}} now!"
  ></script>
</form>

You can integrate Checkout in as little as a single line of client-side code. As we release new features, we’ll automatically roll them out to your existing Checkout integration, so that you will always be using our latest technology without needing to change a thing. Just add this <script> tag inside your checkout <form> to render the payment button. When a user clicks the button and completes the payment, we will create a charge or a subscription and submit your form with the transaction details along with any other <input> fields in your form.

Once the transction is complete, a new transactionDetails input will be added to the form and it will be submitted to your form’s action endpoint, along with any other <input> in the form.

The transactionDetails value is a JWT string encoded with your Quaderno private key that contains the transaction details. The transactionDetails input contains the following data:

{
  customer: 'CUSTOMER_ID',
  transaction: 'TRANSACTION_ID',
  type: 'subscription or charge',
  gateway: 'stripe',
  product_id: 'PRODUCT_CODE'
  iat: UNIX timestamp
}

You can use this data to sync the transaction in your back-end.

These are the accepted data attributes for configuring checkout in the simple integration:

Option Mandatory Description
data-publishable-key Yes Your Quaderno publishable key.
data-product-id Yes The ID of the product you want to sell.
data-charge No A JWT with extra information about the transaction.
data-card-gateway No String (only stripe). Specify if you want to activate the Stripe card inputs
data-paypal No Boolean. Specify if you want to activate PayPal as payment method
data-billing-address No The checkout form ask for the customer’s full billing address and tax ID. The default is false.
data-panel-label No The label of the payment button in the Checkout (e.g. “Subscribe now”, “Pay {{amount}}”, etc.). If you include {{amount}}, it will be replaced by the provided amount. Otherwise, the amount will be appended to the end of your label. Only works for Stripe.
data-tos-url No (Yes if data-privacy-url is present) An url pointing to a page with your Terms of Service
data-privacy-url No (Yes if data-tos-url is present) An url pointing to a page with your privacy policy
data-company No Boolean. Toggle the company name input. Default is false
data-first-name No Your customer’s first name, to pre-fill the checkout form.
data-last-name No Your customer’s last name, to pre-fill the checkout form.
data-company-name No Your customer’s company name, to pre-fill the checkout form.
data-email No Your customer’s email address, to pre-fill the checkout form.
data-country No 2-letter ISO code. Set it if you want to preload the customer's country.
data-label No The text to be shown on the button the customer presses to show the checkout form.
data-color No The RGB color for the Checkout interface. The default is #4C7800.
data-locale No Localize the Checkout interface (2-letter ISO code). The default is EN.
data-coupon No Customers can enter a coupon code (only works for Stripe subscriptions). The default is false.

Custom Integration

The custom integration lets you create a custom DOM element and bind it to the Quaderno Checkout. This permits any HTML element or JavaScript event to start a Checkout payment.

When your page loads, you should create a handler object using QuadernoCheckout.configure(). You can call open() on the handler in response to any event.

If you need to abort the Checkout process—for example, when navigation occurs in a single-page application—you can call close() on the QuadernoCheckout global object.

The publishableKey, cardGateway, paypal, locale, color and callback parameter must be passed to configure(). Any other options should be passed to open().

<head>
  <script src="https://checkout.quaderno.io/v3/checkout.js"></script>
</head>

<button id="customButton">Pay with card</button>

<script>
  QuadernoCheckout.configure({
    publishableKey: 'pk_test_LNpesCnUBN6Ax__xbmc4',
    paypal: true,
    cardGateway: 'stripe',
    locale: 'es',
    callback: function(e){
      console.log(e);
    }
  });

  $('#customButton').on('click', function(e) {
    QuadernoCheckout.open({
      redirectUrl: 'https://your-webpage.com/thank-you',
      discount: true,
      firstName: 'Steve',
      lastName: 'Rogers',
      email: 'the@nomad.com',
      country: 'US',
      postalCode: '11201',
      productId: '123456',
      billingAddress: true
    })
  });

</script>

In case of successful payment, the callback set in the handler will be invoked. It should accept an argument which contains a JS object with two methods: description and details.

The description should contain a brief message about the transaction , while the details contain a JWT with a the transaction details such as the customer ID or the transaction ID (see the Response Parameters section above for more details).

{
  address: "",
  businessNumber: "",
  companyName: "",
  country: "ES",
  description: "Charge successfully created.",
  details: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJnYXRld2F5Ijoic3RyaXBlIiwidHlwZSI6ImNoYXJnZSIsImN1c3RvbWVyIjoiY3VzX0R4eU5SQ3djUXRYeVVwIiwiZW1haWwiOiJkYWNhc2Nvc0Bvay5jb20iLCJ0cmFuc2FjdGlvbiI6ImNoXzFEZ1ZvWkVqVkh2SU5LbGNWZVJkQWtqSSIsInByb2R1Y3RfaWQiOiIxMjM0NTYiLCJ0YXhfbmFtZSI6IklWQSIsInRheF9yYXRlIjoyMS4wLCJleHRyYV90YXhfbmFtZSI6IklSUEYiLCJleHRyYV90YXhfcmF0ZSI6LTE5LjAsImlhdCI6MTU0NDYxMzgyNH0.LgE7i_PHDVGH881HforhADlS2GbjlrXoDD7Pq4TC_5Y",
  email: "magic@taco.com",
  firstName: "Super",
  lastName: "Nacho",
  postalCode: "123456",
  taxId: "0011223344",
  type: "QCheckout.success"
}

Billing

Billing is the simplest way to give your customers access to all their receipts & billing history. They can easily download past receipts and update their billing data by themselves. Improve your billing support with a single line of code.

Reference

When you include the Quaderno Billing script in your page, a global QuadernoBilling object will be available with the following methods:

configure(options = {})

QuadernoBilling.configure({
  key: 'QUADERNO_PUBLIC_KEY',
  customer_id: 'CUSTOMER_SECURE_ID_OR_PAYMENT_GATEWAY_ID',
  editable: true
})

Configures the basic checkout options that cannot be changed (unless close() is invoked). Accepts the following options:

Option Mandatory Description
key Yes Your Quaderno publishable key.
customer_id Yes The customer ID. You can also use their Stripe, Braintree, Paymill, or PayPal IDs if the customer was created via those gateways
editable No Select wether or not your user can edit the invoices he opens

open()

QuadernoBilling.open();

Programmatically opens the billing modal.

close()

QuadernoBilling.close();

Programmatically close the billing modal form and remove it from your DOM. After this, you can call configure again if you want to set up basic configuration options again or open() to reopen the billing modal.

Integration

You can integrate Billing in as little as a single line of client-side code. As we release new features, we’ll automatically roll them out to your existing Billing integration, so that you will a be using our latest technology without needing to change a thing.

Simple integration

<script
  src="https://billing.quaderno.io/billing.js" class="quaderno-billing-button"
  data-key="YOUR_QUADERNO_PUBLISHABLE_KEY"
  data-customer-id="YOUR_QUADERNO_CUSTOMER_ID"
  data-label="View billing">
</script>

Just add this <script> tag in your HTML page to render the billing button. When users click the button we’ll show them their past receipts.

Configuration options:

Option Required Description
data-key Yes Your publishable key.
data-customer-id Yes The customer ID. You can also use their Stripe, Braintree, Paymill, or PayPal IDs if the customer was created via those gateways.
data-label No The text to be shown on the default green button.
data-editable No Allow your users to edit their billing data. The default is true.

Custom integration

<head>
  <script src="https://billing.quaderno.io/billing.js"></script>
</head>

<button id="billing">Check your invoices</button>

<script>
  QuadernoBilling.configure({
    key: 'QUADERNO_PUBLIC_KEY',
    customer_id: 'CUSTOMER_SECURE_ID_OR_PAYMENT_GATEWAY_ID',
    editable: true
  })

  $('#billing').on('click', function(e) {
    e.preventDefault();
    QuadernoBilling.open();
  });
</script>

The custom integration lets you create a custom button and bind it to Quaderno Billing. This permits any HTML element or JavaScript event to start launch the modal. When your page loads, you should create a handler object using QuadernoBilling.configure(). You can call open() on the handler in response to any event. If you need to reload the modal-for example, when navigation occurs in a single-page application—you can call close() on the handler. The key and customer_id parameter must be passed to configure(). Any other options can be passed to either configure() or open().

Apps

With the Quaderno API, it’s easy to build a partner integration to add tax management and billing features to your product.

For example, if you are a marketplace, you can integrate sales tax calculation using the Quaderno API so your users can calculate taxes automatically in their checkout forms depending on their customers' locations. But it’s not just marketplaces that work great with Quaderno - we’ve seen partner integrations built with all kinds of software from tools to manage sport clubs to WordPress blogs.

Integrating with Quaderno has the power to add huge value for your users, streamlining their businesses processes and providing a great experience.

Every partner integration is different, so this document can’t tell you exactly what to do, but we’ll explain the flows you should handle, and give you some ideas of how to provide the best experience for your users.

Connecting your users' accounts

To calculate taxes or issue receipts for your users, you’ll need access to their Quaderno account so you can make API requests on their behalf.

Our OAuth flow allows you to securely obtain an access token for a Quaderno account without having to have your user’s password or do any manual setup.

There are four key benefits to getting access to your users’ accounts using OAuth:

The process for your user looks like this:

  1. Your user clicks a button in your UI to start the process of connecting with Quaderno.
  2. You generate a link to the authorization page, embedding details of your app (which we’ll set up next) as well as a scope to specify the level of access you want your user to give you.
  3. You redirect your user to the generated link. Your user lands on our site, where they create a Quaderno account or log in to their existing one, and agree to grant your app access.
  4. We redirect your user’s browser back to you with a code query parameter.
  5. You exchange the code for a permanent access token, which you store so that you can use it to make API requests on your user’s behalf.

Creating an app

Before we can get started, you need to create an "app" which represents your partner integration in the Quaderno system. You’ll be issued with a client ID and secret, which you’ll use to identify yourself when sending users to the OAuth flow and swapping codes for access tokens.

First sign up for a Quaderno account in our sandbox testing environment and then create an app.

You’ll need to provide a name and the URL of your website (where users can go to read more about your product or your integration with Quaderno).

Once your user has completed the OAuth flow, they will be redirected to your application using the redirect_url parameter you provide. For security reasons, this can’t be just any internet URL, so you will also need to configure one callback URL here (which must exactly match the parameter).

Once you’ve created an app, you’ll see it in the list of your apps. Click on your newly-created app, and take a note of the Client ID and Client Secret.

First, you need to install an Oauth client library. For example, in Ruby you can use the oauth2 gem:

echo "gem 'oauth2'" >> Gemfile
bundle install

Once we’ve installed the library, we can build a link to the authorization page. We’ll have to pass in a number of parameters, including the client_id and client_secret, as well as a few parameters that will vary by library. These can include:

Option Required  Description
redirect_uri Yes The URL to send your users to once they've agreed to connect their account to Quaderno (as well if they deny authorisation or something goes wrong, in which case we'll pass you details of the error). This must exactly match one of the callback URLs you specified above.
scope No The level of access you want to your users' Quaderno accounts - this may either be read_write or read_only. Default is read_only.
state No Any value you pass in here will be included as a querystring parameter when we redirect back to your redirect URL. Please note that this value can be tampered with by your user, and so shouldn't be trusted implicitly. We recommend using this parameter for a CSRF token.
require 'oauth2'

# You should store your client ID and secret in environment variables rather than
# committing them with your code
oauth = OAuth2::Client.new(ENV['QUADERNO_CLIENT_ID'],
                           ENV['QUADERNO_CLIENT_SECRET'],
                           site: 'https://sandbox-quadernoapp.com',
                           authorize_url: '/oauth/authorize',
                           token_url: '/oauth/token')

authorize_url = oauth.auth_code.authorize_url(redirect_uri: 'https://yourapp.com/redirect', 
                                              scope: 'read_only')

redirect_to authorize_url

Run this code to generate a link to the OAuth flow. Head over to the link you’ve just generated in an Incognito window, and you’ll see our OAuth flow.

Getting an access token

On the signup form, we recommend creating a second sandbox account using a different email address. This will replicate what your users will experience when connecting to your partner integration, and will give you an example account which you can use from the perspective of one of your users.

Once your user has either signed up or logged in, and then approved your app’s access to their account, they’ll be sent to your app’s redirect URI with a temporary code which you’ll see in the query parameters, as well as any state you provided.

You should use the OAuth client library we set up earlier to fetch an access token using the code. This is a permanent access token which allows you to use the API on behalf of your merchant at any time.

require 'oauth2'

oauth = OAuth2::Client.new(ENV['QUADERNO_CLIENT_ID'],
                           ENV['QUADERNO_CLIENT_SECRET'],
                           site: 'https://sandbox-quadernoapp.com',
                           authorize_url: '/oauth/authorize',
                           token_url: '/oauth/token')

response = oauth.auth_code.get_token(
  params[:code], # use exactly the same access token as you did in the last step
  redirect_uri: 'https://yourapp.com/redirect'
)

# You should store the user's access token - you'll need it to make API requests on their
# behalf in future. If you want to handle webhooks for your users, you should also store
# their account ID which will allow you to identify webhooks belonging to them.
current_user.update!(quaderno_access_token: response.token,
                     quaderno_account_id: response['account_id'])

Whether you are developing a mobile, web, or desktop application, it is important not to pass the client secret to your user’s device as it could be used to impersonate your app. The process of exchanging a code for an access token should be done on your server so your client secret can be kept private.

You’ll want to store this access token in your database for use in the future to make requests to the Quaderno API on your user’s behalf. Make sure you keep it safe and secure, as it gives full access to your user’s account.

js