3 minutes. No coding. Your invoices auto-save to a Google Sheet forever.
We've built a ready-to-use Google Sheet with 4 tabs, demo data, and the sync script pre-installed. You just need to make a copy.
Don't want the template? You can also download blank CSV files and create your own sheet.
For each tab in your copied sheet, publish it as CSV. This gives the tool read-only access to your products, customers, and profiles.
| Tab Name | Paste URL into Tool Field | |
|---|---|---|
| Products | https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/pub?gid=PRODUCTS_GID&output=csv |
|
| Customers | https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/pub?gid=CUSTOMERS_GID&output=csv |
|
| Profiles | https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/pub?gid=PROFILES_GID&output=csv |
Each tab gets its own URL. Paste all three into the Data Source panel of the Quote & Invoice tool.
The Apps Script is already in your sheet from the template. You just need to deploy it once:
Your Apps Script URL will look like:
URLhttps://script.google.com/macros/s/AKfycbxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/exec
Open the Data Source panel in the Quote & Invoice tool and paste:
| Field | Paste |
|---|---|
| Products Sheet URL | CSV publish URL from Products tab |
| Customers Sheet URL | CSV publish URL from Customers tab |
| Profiles Sheet URL | CSV publish URL from Profiles tab |
| Apps Script Web App URL | URL from Step 3's Deploy |
Click Save & Sync Now. From now on:
The template already has this script installed. This is here only if you're building your own sheet from scratch.
JavaScript// ═══════════════════════════════════════════════════
// Tender84 Quote & Invoice Tool — Sheet Sync Script
// ═══════════════════════════════════════════════════
var SHEETS = {
products: 'Products',
customers: 'Customers',
profiles: 'Profiles',
invoices: 'Invoices'
};
// GET: Return invoices as JSON
function doGet(e) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEETS.invoices);
var data = sheet.getDataRange().getValues();
if (data.length < 2) return json({ invoices: [] });
var headers = data[0];
var invoices = [];
for (var i = 1; i < data.length; i++) {
var row = {};
for (var j = 0; j < headers.length; j++) row[headers[j]] = data[i][j] || '';
if (row.Number) invoices.push(row);
}
return json({ invoices: invoices, count: invoices.length });
}
// POST: Append invoice row
function doPost(e) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEETS.invoices);
var payload = JSON.parse(e.postData.contents);
var invoices = Array.isArray(payload) ? payload : [payload];
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
invoices.forEach(function(inv) {
var row = [];
for (var j = 0; j < headers.length; j++) {
var key = headers[j];
row.push(inv[key] !== undefined ? inv[key] : '');
}
sheet.appendRow(row);
});
return json({ success: true, added: invoices.length });
}
function json(obj) {
return ContentService.createTextOutput(JSON.stringify(obj))
.setMimeType(ContentService.MimeType.JSON);
}
These are the exact CSV files pre-loaded in the template. Use them if you prefer to start from scratch with your own sheet.
Need help? WhatsApp Support