Skip to content

Public tools

A small set of endpoints under /api/public/ that need no API key and no account. They are utilities, not a way into your data — nothing here reads or writes an organisation's records.

What is there

Path What it does
POST /api/public/scan-qr-code/ Decode a ZATCA invoice QR code
POST /api/public/validate-zatca/ Check an invoice against ZATCA rules
POST /api/public/calculate-vat/ Work out VAT on an amount
POST /api/public/parse-invoice/ Parse an invoice document
POST /api/public/export/ Export a processed result
GET /api/public/health/ Liveness

Example: calculate VAT

The body is a list of invoice lines in the same vocabulary as the authenticated invoice endpoints. Verified against the sandbox 2026-09-27.

curl -s -X POST "$CLIX_API/api/public/calculate-vat/" \
  -H "Content-Type: application/json" \
  -d '{
    "lines": [
      { "item_name": "Consulting", "invoiced_quantity": "1",
        "item_net_price": "1000.00", "vat_rate": "15", "vat_category_code": "S" }
    ],
    "document_level_allowances": []
  }'
{
  "invoice_total_line_net_amount": "1000.00",
  "invoice_total_document_level_allowance_amount": "0.00",
  "invoice_total_amount_without_vat": "1000.00",
  "invoice_total_vat_amount": "150.00",
  "invoice_gross_total": "1150.00",
  "vat_breakdown": [
    { "vat_category_code": "S", "vat_rate": "15",
      "vat_category_taxable_amount": "1000.00", "vat_category_tax_amount": "150.00",
      "vat_exemption_reason_code": null, "vat_exemption_reason_text": null }
  ],
  "branding": "Powered by Clix"
}

A missing or unknown field returns 400 with the field named: {"message": ["lines: Field required"]}. The QR decoder takes {"qr_base64": "…"} and answers the same way when it is absent.

Limits

Separate from your API key's limits, and stricter:

Caller Allowance
Anonymous 10 a day, per IP address
Free-tier organisation 100 a month
Paid plans Not metered

Exceeding one returns 429:

{ "detail": "…", "window": "daily", "limit": 10, "current": 10 }

window is daily, monthly or hourly. A 503 with a service_unavailable window means the limiter itself could not answer — retry shortly.

Uploads are capped at 5 MiB.

The same router serves the public view of a shared invoice: GET /api/public/shared/{token}/. Links expire after 30 days and views are limited to 60 an hour per link.

Anyone with the link can view that one invoice. Treat a share link as a bearer credential for a single document — do not put it somewhere indexable.

When to use these

Use the public tools for one-off checks and for features you offer your own users — scanning a supplier QR code in your app, validating a file before you submit it.

Do not build your integration on them. They are rate-limited for anonymous use, carry no organisation context, and cannot create anything. Issuing invoices goes through the authenticated API — see Quickstart.