Easy Invoice
A product by
Build for Web and Backend 💪
If this package helped you out please star us on Github!
Much appreciated!
Important
- Please note that this package is a wrapper for an API, so it's logic runs on external servers.
- Your data is secure and will not be shared with third parties.
- We try to keep the API up and running at all times, but we cannot guarantee 100% uptime. Please build in a retry
mechanism in case the API is down for maintenance.
- Make sure to upgrade your package to either >2.4.0 or >3.0.25 for apiKey support.
Installation
Using npm:
$ npm install easyinvoice
Using yarn:
$ yarn add easyinvoice
Using PNPM:
$ pnpm install easyinvoice
CDN
Using unkpg CDN:
<script src="https://unpkg.com/easyinvoice/dist/easyinvoice.min.js"></script>
Using jsDelivr CDN:
<script src="https://cdn.jsdelivr.net/npm/easyinvoice/dist/easyinvoice.min.js"></script>
Platform support
Platform | Repository | Supported | Link |
---|
PHP | Composer | Yes! | |
Javascript | NPM | Yes! | |
Python | PIP | Yes! | |
Step-by-step guide
Read our step-by-step guide on Medium.
Click here!
And gives us a clap if it helped you! 😉
Demo
JS Fiddle: Plain Javascript
JS Fiddle: Vue
JS Fiddle: React
JS Fiddle: Angular
Sample
JSON Configs used for above samples:
Plans
Plan | Rate | Price | Link |
---|
Free | 25 invoices / 15 days | $0 | Not required to register |
Paid | Unlimited | - 30 day free trial - 1st month $1.99 - $17.99 per month *Prices include VAT | |
To use paid
- Register through:
- Create an API key through the app: settings -> API keys
- Make sure to upgrade your package to either >2.4.0 or >3.0.25 for apiKey support.
- Use the API Key as shown in the complete example below. Add the apiKey property to the data object.
Note: The GUI is not (yet) fully translated to English, though the path to getting an apiKey should mostly be in
English. Also this will allow you to use the in app purchase mechanism to pay for the subscription.
Development mode
When using the free version, you can set the mode to 'development' to make sure you are not running into rate limits
while testing this package or developing your invoices. The free version is limited to 25 invoices per 15 days. When
your
invoice looks good, you can switch to 'production' mode to create your production invoices. Production mode is activated
by either not setting the mode or setting the mode to 'production'.
Direct REST API access
In case you don't want to use NPM, but you want to call our invoice creation api directly.
# HTTPS POST
https://api.budgetinvoice.com/v2/free/invoices
# POST Data
Format: JSON
Structure: {
"data": { # Parent parameter must be 'data'
"mode": "development", # Production or development, defaults to production
"products": [
{
"quantity": 2,
"description": "Test product",
"taxRate": 6,
"price": 33.87
}
],
}
}
# Optionally add your paid apiKey to the header
Header: "Authorization": "Bearer 123abc" # Please register to receive a production apiKey: https://app.budgetinvoice.com/register
Import
CommonJS
var easyinvoice = require('easyinvoice');
ES6 =<
import easyinvoice from 'easyinvoice';
Getting Started - Basic Example
NodeJS
var easyinvoice = require('easyinvoice');
var data = {
apiKey: "free",
mode: "development",
products: [
{
quantity: 2,
description: "Test product",
taxRate: 6,
price: 33.87
}
]
};
easyinvoice.createInvoice(data, function (result) {
console.log('PDF base64 string: ', result.pdf);
});
Web
<html>
<head>
// Import the library into your project
<script src="https://unpkg.com/easyinvoice/dist/easyinvoice.min.js"></script>
</head>
<body>
<script>
var data = {
apiKey: "free",
mode: "development",
products: [
{
quantity: 2,
description: "Test product",
taxRate: 6,
price: 33.87
}
]
};
easyinvoice.createInvoice(data, function (result) {
console.log('PDF base64 string: ', result.pdf);
});
</script>
</body>
</html>
High volume: asynchronous invoice creation
Our API is able to handle high volumes of requests. If you need to create a lot of invoices fast, make sure to create
them asynchronously. This will allow you to create multiple invoices at the same time.
Note: using async/await for this example
var easyinvoice = require('easyinvoice');
const promises = [];
for (let i = 0; i < 25; i++) {
promises[i] = easyinvoice.createInvoice({
apiKey: "free",
mode: "development",
});
}
const invoices = await Promise.all(promises);
Complete Example (NodeJS)
var easyinvoice = require('easyinvoice');
var data = {
apiKey: "free",
mode: "development",
images: {
logo: "https://public.budgetinvoice.com/img/logo_en_original.png",
background: "https://public.budgetinvoice.com/img/watermark-draft.jpg"
},
sender: {
company: "Sample Corp",
address: "Sample Street 123",
zip: "1234 AB",
city: "Sampletown",
country: "Samplecountry"
},
client: {
company: "Client Corp",
address: "Clientstreet 456",
zip: "4567 CD",
city: "Clientcity",
country: "Clientcountry"
},
information: {
number: "2021.0001",
date: "12-12-2021",
dueDate: "31-12-2021"
},
products: [
{
quantity: 2,
description: "Product 1",
taxRate: 6,
price: 33.87
},
{
quantity: 4.1,
description: "Product 2",
taxRate: 6,
price: 12.34
},
{
quantity: 4.5678,
description: "Product 3",
taxRate: 21,
price: 6324.453456
}
],
bottomNotice: "Kindly pay your invoice within 15 days.",
settings: {
currency: "USD",
},
translate: {
},
};
easyinvoice.createInvoice(data, function (result) {
console.log('PDF base64 string: ', result.pdf);
});
Return values
Key | Value | Data Type |
---|
result.pdf | The PDF file as base64 string | String |
result.calculations.products | Array of objects reflecting the products used in creation | Array |
result.calculations.products[key].subtotal | Rounded price without tax per product | Number |
result.calculations.products[key].tax | Rounded tax per product | Number |
result.calculations.products[key].total | Rounded price including tax per product | Number |
result.calculations.tax | Object containing total calculated tax per unique tax rate | Array |
result.calculations.tax[rate] | Total tax for all products with same tax rate | Number |
result.calculations.subtotal | Rounded price without tax for all products | Number |
result.calculations.total | Rounded price with tax for all products | Number |
Error handling
Callback
var easyinvoice = require('easyinvoice');
var data = {
apiKey: "free",
mode: "development",
};
easyinvoice.createInvoice(data, function (invoice) {
console.log(invoice);
}).catch((error) => {
console.log(error);
});
Async/await
var easyinvoice = require('easyinvoice');
var data = {
apiKey: "free",
mode: "development",
};
try {
const invoice = await easyinvoice.createInvoice(data);
console.log(invoice);
} catch (error) {
console.log(error);
}
Locales and Currency
Used for number formatting and the currency symbol:
const data = {
apiKey: "free",
mode: "development",
settings: {
locale: 'de-DE',
currency: 'EUR'
}
};
const data = {
apiKey: "free",
mode: "development",
settings: {
locale: 'en-US',
currency: 'USD'
}
};
Formatting and symbols are applied through
the ECMAScript Internationalization API
Click here for a list of locale codes
Click here for a list of currency codes
Disclaimer: Not all locales and currency codes found in the above lists might be supported by the ECMAScript
Internationalization API.
Logo and Background
The logo and background inputs accept either a URL or a base64 encoded file.
Supported file types:
- Logo: image
- Background: image, pdf
URL
const data = {
apiKey: "free",
mode: "development",
images: {
logo: "https://public.budgetinvoice.com/img/logo_en_original.png",
background: "https://public.budgetinvoice.com/img/watermark_draft.jpg",
}
};
Base64
const data = {
apiKey: "free",
mode: "development",
images: {
logo: "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",
background: "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
}
};
Local File (NodeJS only)
var fs = require("fs");
const data = {
apiKey: "free",
mode: "development",
images: {
logo: fs.readFileSync('logo.png', 'base64'),
background: fs.readFileSync('images/background.png', 'base64')
}
};
Click here for an online tool to convert an image to base64
Async/await support
var easyinvoice = require('easyinvoice');
var data = {
apiKey: "free",
mode: "development",
};
const result = await easyinvoice.createInvoice(data);
console.log('PDF base64 string: ', result.pdf);
To store the file locally (NodeJS)
var fs = require('fs');
var data = {
apiKey: "free",
mode: "development",
};
const result = await easyinvoice.createInvoice(data);
await fs.writeFileSync("invoice.pdf", result.pdf, 'base64');
Print your invoice (browser only)
var data = {
apiKey: "free",
mode: "development",
};
const result = await easyinvoice.createInvoice(data);
easyinvoice.print(result.pdf);
Download your invoice (browser only)
var data = {
apiKey: "free",
mode: "development",
};
const result = await easyinvoice.createInvoice(data);
easyinvoice.download('myInvoice.pdf', result.pdf);
Render(view) your invoice (browser only)
html
<script src="https://unpkg.com/pdfjs-dist@3.11.174/build/pdf.min.js"></script>
<script src="https://unpkg.com/pdfjs-dist@3.11.174/build/pdf.worker.min.js"></script>
<div id="pdf"></div>
css (optional)
#pdf {
text-align: center;
}
#pdf canvas {
border: 1px solid black;
width: 95%;
}
js
var data = {
apiKey: "free",
mode: "development",
};
const elementId = 'pdf';
const result = await easyinvoice.createInvoice(data);
await easyinvoice.render(elementId, result.pdf);
Template customization
Download our default template (
invoice-v2) here to have an
example which you can customize.
Supported file types:
var html = '<p>Hello world! This is invoice number %number%</p>';
const data = {
apiKey: "free",
mode: "development",
customize: {
template: btoa(html)
},
information: {
number: '2022.0001'
}
};
Variable placeholders
The following placeholders can be put into your template. They will be replaced by their corresponding value upon
creation.
Placeholder | Will be replaced by |
%document-title% | translate.invoice |
%logo% | images.logo |
%company-from% | sender.company |
%address-from% | sender.address |
%zip-from% | sender.zip |
%city-from% | sender.city |
%country-from% | sender.country |
%sender-custom-1% | sender.custom1 |
%sender-custom-2% | sender.custom2 |
%sender-custom-3% | sender.custom3 |
%company-to% | client.company |
%address-to% | client.address |
%zip-to% | client.zip |
%city-to% | client.city |
%country-to% | client.country |
%client-custom-1% | client.custom1 |
%client-custom-2% | client.custom2 |
%client-custom-3% | client.custom3 |
%number-title% | translate.number |
%number% | settings.number |
%date-title% | translate.date |
%date% | settings.date |
%due-date-title% | translate.dueDate |
%due-date% | settings.dueDate |
%products-header-products% | translate.products |
%products-header-quantity% | translate.quantity |
%products-header-price% | translate.price |
%products-header-total% | translate.productTotal |
A custom product row must be enclosed in products tags like:
<products>
</products>
Don't leave out the product tags or your custom product row won't be iterable by the template parser and you will end up
with a single product row. Customize the html as you wish.
| products |
Within:
<products></products>
%description%
| products[].description |
Within:
<products></products>
%quantity%
| products[].quantity |
Within:
<products></products>
%price%
| products[].price |
Within:
<products></products>
%row-total%
| products[].quantity * products[].price (rounded) |
%subtotal-title% | translate.subtotal |
%subtotal% | Auto inserted:
Calculated total price excluding tax |
A custom tax row must be enclosed in tax tags like:
<tax>
</tax>
Don't leave out the tax tags or your custom tax row won't be iterable by the template parser and you will end up with a
single tax row. Customize the html as you wish.
| tax |
Within:
<tax></tax>
%tax-notation%
| translate.vat |
Within:
<tax></tax>
%tax-rate%
| Auto inserted:
Distinct tax rate used in products |
Within:
<tax></tax>
%tax%
| Auto inserted:
Calculated total tax for rate |
%total% | Auto inserted:
Calculated total price including tax |