Quickstart
API key to your first signed, VAT-compliant document in 5 minutes.
By the end of this guide you'll have:
- ✅ Created a sandbox API key with the right scopes
- ✅ Created a client
- ✅ Created and finalized a
tax_invoice_receiptdocument - ✅ Previewed the generated PDF
Total reading time: 5 minutes. The whole walkthrough runs against the sandbox
(https://sandbox-api.vuz.co.il) — a real, isolated environment with its own database, so
nothing you do here creates a real document, sends a real message, or charges anyone.
Going live at the end is a two-line change.
מעדיפ/ה עברית? יש מדריך זהה בעברית — קוד ותשובות ה-API נשארים באנגלית בכל השפות.
Step 1 — Create a sandbox API key
API keys are created from the VUZ dashboard, not the API itself (creating a key
requires a logged-in dashboard session — you can't mint a key with a key). Go to
Settings → Integrations → API Keys → "Sandbox key" — this mirrors your business into
the isolated sandbox database and mints a key that works only on
https://sandbox-api.vuz.co.il. It's the same endpoint your browser calls:
POST https://api.vuz.co.il/api/v1/api-keys/sandbox
Authorization: Bearer <your dashboard JWT>
X-Business-Id: <your business id>The response includes the raw key once:
{
"businessId": "b6b0b8b0-...",
"rawKey": "vuz_ab12cdef3456789012345678901234567890abcdef12",
"keyPrefix": "vuz_ab12",
"environment": "sandbox",
"created": true
}The sandbox key is minted with the full canonical scope set, so every walkthrough call
below just works. Store rawKey securely — it is never shown again. Every request from
here on sends it as X-Api-Key. Note the key's string looks the same in both
environments (vuz_...) — isolation comes from the completely separate sandbox database,
not the prefix (see Auth → API keys).
When you later create a production key (Settings → Integrations → API Keys →
Generate), you choose its scopes yourself — use the canonical scope strings, not the
short legacy names shown on some older screens (read, write, documents). The routes
below check for an exact string match against documents:write,
documents:finalize, clients:write, etc. — see Auth → Scopes for the
full list of canonical scopes.
Step 2 — Create a client
curl -X POST https://sandbox-api.vuz.co.il/api/v1/clients \
-H "X-Api-Key: vuz_ab12cdef3456789012345678901234567890abcdef12" \
-H "Content-Type: application/json" \
-d '{
"name": "Dana Cohen",
"email": "dana@example.com"
}'const res = await fetch('https://sandbox-api.vuz.co.il/api/v1/clients', {
method: 'POST',
headers: {
'X-Api-Key': process.env.VUZ_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({ name: 'Dana Cohen', email: 'dana@example.com' }),
});
const client = await res.json();
console.log('Client ID:', client.id);import os, requests
res = requests.post(
'https://sandbox-api.vuz.co.il/api/v1/clients',
headers={'X-Api-Key': os.environ['VUZ_API_KEY']},
json={'name': 'Dana Cohen', 'email': 'dana@example.com'},
)
client = res.json()
print('Client ID:', client['id'])<?php
$ch = curl_init('https://sandbox-api.vuz.co.il/api/v1/clients');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['X-Api-Key: ' . getenv('VUZ_API_KEY'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(['name' => 'Dana Cohen', 'email' => 'dana@example.com']),
]);
$client = json_decode(curl_exec($ch), true);
echo 'Client ID: ' . $client['id'];No X-Business-Id header — the API key itself is bound to your business (see
Concepts → Business).
Response (trimmed):
{
"id": "9b2f6b2e-2e1e-4b7e-9f1e-1e2e3e4e5e6e",
"name": "Dana Cohen",
"email": "dana@example.com",
"type": "private"
}Step 3 — Issue a document
The VAT rate below (17%) is illustrative. Your business's real rate lives on GET /businesses/current (vatRate field) — read it before computing lineVatTotal for real
traffic. The server re-computes and rejects the request (±0.01 tolerance) if your
totals don't match.
curl -X POST https://sandbox-api.vuz.co.il/api/v1/documents \
-H "X-Api-Key: vuz_ab12cdef3456789012345678901234567890abcdef12" \
-H "Content-Type: application/json" \
-d '{
"clientId": "9b2f6b2e-2e1e-4b7e-9f1e-1e2e3e4e5e6e",
"docType": "tax_invoice_receipt",
"issueDate": "2026-07-01",
"vatMode": "exclusive",
"items": [
{
"description": "Consulting - 2 hours",
"quantity": 2,
"unitPrice": 150,
"vatApplicable": true,
"vatRate": 17,
"lineSubTotal": 300,
"lineVatTotal": 51,
"lineGrandTotal": 351
}
],
"subTotal": 300,
"vatTotal": 51,
"grandTotal": 351
}'Response — a DRAFT document (no document number yet; VUZ assigns one on finalize):
{
"id": "205bd0d9-0c71-419f-989e-d5b2b790fe85",
"docType": "tax_invoice_receipt",
"status": "draft",
"issueDate": "2026-07-01",
"clientId": "9b2f6b2e-2e1e-4b7e-9f1e-1e2e3e4e5e6e",
"subTotal": "300.00",
"vatTotal": "51.00",
"grandTotal": "351.00",
"currency": "ILS"
}Step 4 — Finalize it
POST /documents creates a DRAFT. Finalizing is a separate call (and a separate
scope, documents:finalize) — it assigns the sequential document number, generates the
signed PDF, and — where required — requests an allocation number from the Tax Authority:
curl -X POST https://sandbox-api.vuz.co.il/api/v1/documents/205bd0d9-0c71-419f-989e-d5b2b790fe85/finalize \
-H "X-Api-Key: vuz_ab12cdef3456789012345678901234567890abcdef12"The document comes back as ISSUED, numbered, and immutable. See
Concepts → Documents for the full DRAFT → ISSUED lifecycle and
which document types apply per business type.
In the sandbox nothing legally binding happens: Tax Authority calls go to the Authority's own test environment, and the PDF is watermarked "SANDBOX — NOT A LEGAL DOCUMENT". In production this same call produces a real, signed, legally final document — that's the point.
Step 5 — Preview the PDF
curl "https://sandbox-api.vuz.co.il/api/v1/documents/205bd0d9-0c71-419f-989e-d5b2b790fe85/pdf/preview" \
-H "X-Api-Key: vuz_ab12cdef3456789012345678901234567890abcdef12" \
-o preview.pdfReturns Content-Type: application/pdf. Draft documents render with a DRAFT
watermark; pass ?draft=false once the document is finalized. ?language=he|en controls
the PDF language (defaults to he).
Going live
Two changes:
- Create a production key: Settings → Integrations → API Keys → Generate, granting only the scopes you actually use.
- Swap the base URL to
https://api.vuz.co.il/api/v1.
A sandbox key never works on production (and vice versa) — the environments have fully
separate databases, and every response tells you who answered via the
X-Vuz-Environment: live|sandbox header.
You did it 🎉
Handle errors
Every error code, what it means, and how to recover.
Set up webhooks
Get notified the moment a document is finalized.
OAuth instead of an API key
Building a store plugin? Connect via OAuth instead.
Full API Reference
Every endpoint, every parameter, with live testing.

