#What these endpoints solve
One family of endpoints, five document types. Send your parties (seller/buyer), optional items and shipping, and document-specific fields. You get a ready-to-send PDF URL plus an expiry time. All messages and validation feedback are in English.
- Pro-forma — a price quote / payment request before issuing a formal invoice.
- Invoice — a formal tax document for goods/services delivered.
- Debit Note — add charges to an issued invoice (e.g., extra billable hours).
- Credit Note — reduce or refund part/all of an invoice (e.g., returns, discounts).
- Receipt — acknowledge payment (with or without linking to an invoice).
#The practical field model
Each endpoint accepts a common core with some extras. Think in blocks:
| Block | Shape | Required | Notes that matter |
|---|---|---|---|
seller |
object { name, address?, email?, vat_number?, company_number?, logo?, phone? } |
Yes | At minimum, send name. Add VAT/registration for compliance; logo is a URL. |
buyer |
object { name, address?, email?, vat_number?, company_number?, phone? } |
Yes | name is required. Email is printed for delivery/records. |
items |
array<object> with when present, all required: { name, quantity, unit_price (net), vat_rate %, total_price (gross), description? } |
No* | If you include items, each line must be complete. Use when you want line-level detail in the PDF. |
shipping |
object { price (net), vat_rate % } |
No | If present, both price and vat_rate are required. Treated like a separate line. |
payment_methods |
array<object> { method, details?: object } |
No | For “how to pay” or “how refunded”. Keep labels short (method ≤ 20 chars). details is key/value (IBAN, BIC, email…). |
extras |
array<object> { label, value? } |
No | Small rows printed at the bottom (“Notes”, “PO #123”, etc.). |
unit_price is net, total_price is gross. vat_rate is a percent (0–100). shipping.price is net. If you don’t need line-level detail, skip items and use the document’s summary/amount fields (see below).
#When to use which endpoint
| Endpoint | When to use | Must-have fields (besides seller/buyer) | Shortcut (no items) |
|---|---|---|---|
POST https://api.yeb.to/v1/invoicing/proforma |
Quote or pay-first flow before tax invoice. | issue_date, valid_due_date |
Just set total_amount_due (optional for pro-forma if you show only lines; still recommended). |
POST https://api.yeb.to/v1/invoicing/invoice |
Formal tax invoice after delivery. | invoice_number, issue_date, tax_event_date, total_amount_due |
Provide total_amount_due; subtotal/vat_total are optional. |
POST https://api.yeb.to/v1/invoicing/debit-note |
Charge more against an invoice (extras, corrections). | debit_note_number, invoice_number, issue_date, reason |
Use debit_amount instead of items. |
POST https://api.yeb.to/v1/invoicing/credit-note |
Reduce/refund an existing invoice. | credit_note_number, invoice_number, issue_date, reason |
Use credit_amount instead of items. |
POST https://api.yeb.to/v1/invoicing/receipt |
Confirm a payment (optionally reference an invoice). | receipt_number, payment_date |
Use amount_paid (or send item lines if you need detail). |
#Dates we accept (and how we normalize)
The API accepts common formats and normalizes to YYYY-MM-DD internally:
Y-m-d(2025-01-09)d-m-Y(09-01-2025),d/m/Y(09/01/2025),d/m/y(09/01/25)m/d/Y(01/09/2025),m/d/y(01/09/25)
If a date can’t be parsed, you’ll get a clear validation error listing allowed formats.
#Minimal, production-ready payloads
#Pro-forma
curl -X POST "https://api.yeb.to/v1/invoicing/proforma" -H "Content-Type: application/json" -d '{
"api_key": "YOUR_KEY",
"seller": {"name":"My Company","address":"1 Seller St","email":"[email protected]"},
"buyer": {"name":"Client Inc.","address":"2 Buyer Rd","email":"[email protected]"},
"issue_date": "2025-07-23",
"valid_due_date": "2025-08-06",
"items": [{"name":"Consulting","quantity":2,"unit_price":100,"vat_rate":20,"total_price":240}],
"extras": [{"label":"Notes","value":"Valid for 14 days"}]
}'
#Invoice
curl -X POST "https://api.yeb.to/v1/invoicing/invoice" -H "Content-Type: application/json" -d '{
"api_key": "YOUR_KEY",
"seller": {"name":"My Company","address":"1 Seller St","email":"[email protected]"},
"buyer": {"name":"Client Inc.","address":"2 Buyer Rd","email":"[email protected]"},
"invoice_number": "INV-2025-002",
"issue_date": "2025-07-23",
"tax_event_date": "2025-07-23",
"items": [{"name":"Consulting","quantity":2,"unit_price":100,"vat_rate":20,"total_price":240}],
"shipping": {"price":25,"vat_rate":20},
"total_amount_due": 270
}'
#Debit Note
curl -X POST "https://api.yeb.to/v1/invoicing/debit-note" -H "Content-Type: application/json" -d '{
"api_key":"YOUR_KEY",
"seller":{"name":"My Co","address":"1 Seller St","email":"[email protected]"},
"buyer":{"name":"Client","address":"2 Buyer Rd","email":"[email protected]"},
"debit_note_number":"DN-2025-003",
"invoice_number":"INV-2025-002",
"issue_date":"2025-07-25",
"reason":"Additional billable hours (3h)",
"debit_amount":144
}'
#Credit Note
curl -X POST "https://api.yeb.to/v1/invoicing/credit-note" -H "Content-Type: application/json" -d '{
"api_key":"YOUR_KEY",
"seller":{"name":"My Co","address":"1 Seller St","email":"[email protected]"},
"buyer":{"name":"Client","address":"2 Buyer Rd","email":"[email protected]"},
"credit_note_number":"CN-2025-001",
"invoice_number":"INV-2025-002",
"issue_date":"2025-07-26",
"reason":"Refund for unused support hours",
"credit_amount":240,
"payment_methods":[{"method":"bank transfer","details":{"iban":"BG00...","bic":"BANKBGSF"}}]
}'
#Receipt
curl -X POST "https://api.yeb.to/v1/invoicing/receipt" -H "Content-Type: application/json" -d '{
"api_key":"YOUR_KEY",
"seller":{"name":"My Co","address":"1 Seller St","email":"[email protected]"},
"buyer":{"name":"Client","address":"2 Buyer Rd","email":"[email protected]"},
"receipt_number":"RCPT-2025-010",
"payment_date":"2025-07-25",
"amount_paid":200,
"payment_method":"card"
}'
#Presentation options that actually matter
- Design:
classic|modern|elegant|minimal. If a chosen design isn’t available, the API attempts to useclassic; if neither exists you’ll get400 "Design not found." - Language:
langis a 2-letter code for labels/text in the PDF (defaulten).Supported languages:- 🇬🇧 — English (
en) - 🇧🇬 — Bulgarian (
bg) - 🇫🇷 — French (
fr) - 🇩🇪 — German (
de) - 🇬🇷 — Greek (
el) - 🇮🇹 — Italian (
it) - 🇪🇸 — Spanish (
es) - 🇵🇹 — Portuguese (
pt) - 🇷🇺 — Russian (
ru) - 🇹🇷 — Turkish (
tr) - 🇵🇱 — Polish (
pl) - 🇨🇿 — Czech (
cs) - 🇷🇴 — Romanian (
ro) - 🇳🇱 — Dutch (
nl) - 🇸🇪 — Swedish (
sv) - 🇳🇴 — Norwegian (
no) - 🇫🇮 — Finnish (
fi) - 🇮🇸 — Icelandic (
is) - 🇺🇦 — Ukrainian (
uk) - 🇸🇦 — Arabic (
ar) - 🇩🇰 — Danish (
da) - 🇷🇸 — Serbian (Latin) (
sr)
- 🇬🇧 — English (
- Currency: Use
currency(symbol or code) andcurrency_side(beforeorafter, defaultafter).
#What you get back (and what to do next)
{
"result": {
"doc_type": "invoice|proforma|debit-note|credit-note|receipt",
"file_url": "https://cdn.../uuid.pdf",
"expires": "2025-08-01 10:05:00"
}
}
file_url— a direct PDF link. Best practice: download and store on your side; links expire after 7 days.doc_type— echoes the type you created. Use for auditing/notifications.expires— we recommend background jobs to archive PDFs before expiry.
#Common errors & quick fixes
{"error":"invoice_number is required for an invoice.","code":422}
{"error":"shipping.vat_rate is required when shipping is provided.","code":422}
{"error":"Design “elegant” not found.","code":400}
- 422 validation: Provide all must-have fields for your endpoint; if you send
items, each line must includename,quantity,unit_price,vat_rate,total_price. - Dates: If parsing fails you’ll get a helpful message listing accepted formats.
- Design 400: Switch to
classicor check your theme availability.
#Field recipes & integration tips
- No line items? For debit/credit notes and receipts, use the single amount fields (
debit_amount,credit_amount,amount_paid). - Totals: On invoices, you must send
total_amount_due.subtotalandvat_totalare optional (the PDF will still render correctly). - Payment instructions: Prefer
payment_methods[]to show bank transfer/PayPal/card with details. For receipts, you can also set a simplepayment_methodlabel. - Branding: Send
design,logo, andcurrency_sideto match your brand style and region conventions. - Compliance: Include VAT/registration IDs for both parties when applicable. Keep reason fields (
reason) clear for credit/debit notes.
#API Changelog
items[].vat_rate.
If omitted, the previous global VAT logic applies as before.
items[] fields:
tolerant to minor key order differences and documented a recommended field order for more predictable results.
classic, modern, elegant, minimal)
received visual/layout refinements and improved typography.
subtotal and vat_total became optional; total_amount_due remains required.
YYYY-MM-DD before validation, with clearer error messages on failure.
payment_method (short label) in addition to payment_methods[] for quick receipts without details.
currency_side (before|after) introduced; if a chosen design isn’t available we attempt classic (else 400).
PDFs render with Unicode-safe fonts by default.