API reference¶
The spec is the authority¶
https://sandbox.api.goclix.ai/v1/api/integrations/docs Swagger UI, with Authorize for a clix_ key
https://sandbox.api.goclix.ai/v1/api/integrations/openapi.json the OpenAPI 3 document
Both are public — no key needed to read them — and both are generated from the running code, so they cannot drift from what the API actually does. Point your client generator at the JSON; use Swagger UI to try any call with your own key. These are the sandbox addresses. In production, use the host that comes with your production key.
Sandbox only: TLS ends outside the Kingdom
sandbox.api.goclix.ai terminates TLS on a server outside Saudi Arabia before passing the request to Clix. Send only test data to it. Production Clix keeps your data in the Kingdom.
Every request and response body of a complete run, captured on the sandbox, is on Worked example, key to cleared invoice; each endpoint below links to its step there.
This page lists the same surface in prose. Where the two disagree, the spec is right.
What a key can call¶
24 paths, 30 operations. The Role column is the least privilege that works.
Invoices¶
| Method | Path | Role | Live example |
|---|---|---|---|
GET |
/api/invoices/ |
ViewInvoice | |
POST |
/api/invoices/ |
CreateInvoice | example |
POST |
/api/invoices/preview/ |
ViewInvoice | example |
GET |
/api/invoices/{invoice_id}/ |
ViewInvoice | example |
PATCH |
/api/invoices/{invoice_id}/clearance-reporting/ |
CreateInvoice | |
GET |
/api/invoices/{invoice_id}/pdf-a3/ |
ViewInvoice | example |
POST |
/api/invoices/{invoice_id}/pdf-a3/ |
ViewInvoice |
PATCH …/clearance-reporting/ retries the ZATCA submission of an invoice that has no ZATCA answer yet, for example after POST /api/invoices/ replied that the submission to ZATCA failed. It returns 202 and a location to poll. An invoice ZATCA has already answered, or one whose retry is still in flight, gets 409. It does not change the invoice: to correct an issued invoice, issue a credit or debit note.
Notes on an invoice¶
| Method | Path | Role | Live example |
|---|---|---|---|
GET |
/api/invoices/{invoice_id}/notes/ |
ViewInvoice | |
POST |
/api/invoices/{invoice_id}/notes/ |
CreateInvoice |
These are annotations, not credit or debit notes
The body is {"title": "…", "details": "…"} — free text kept against the invoice for your own audit trail. It has no VAT effect, is never sent to ZATCA, and does not correct anything.
To issue a credit or debit note, post a document to /api/invoices/ with the right type_code — 381 for a credit note, 383 for a debit note — and the original invoice's id in original_invoice_reference (a list of invoice UUIDs). Send a reason_id too: the uuid of an active reason from GET /api/sellers/reasons/. The schema marks it optional, but its description is the reason ZATCA reads (rule BR-KSA-17), and Clix refuses a note without one before it reaches ZATCA, on preview too: 400 {"message": "Reason for issuance of credit / debit note as per the VAT Implementing Regulation is missing"}. Every note line carries the original line's invoice_line_id. On a credit note, item_net_price must be above 0 and at most the original line's price: at the original price the line is a return, below it a price correction that credits invoiced_quantity × that price. Send the original line's vat_category_code and vat_rate; a different VAT, or a price above the original, is refused with 400. Returns and corrections on a line together may not exceed the line's value. A debit note keeps the price you send. See A credit note. The codes come from /api/invoices/invoice-type-codes/. See Credit and debit notes for what the reasons are and who sets them up.
Clients¶
| Method | Path | Role | Live example |
|---|---|---|---|
GET |
/api/buyers/ |
ViewInvoice | example |
GET |
/api/buyers/{buyer_id}/ |
ViewInvoice | |
PATCH |
/api/buyers/{buyer_id}/ |
CreateInvoice | |
POST |
/api/onboarding/organizations/clients/ |
CreateInvoice |
Creating a client uses the onboarding path, not POST /api/buyers/. The body is multipart/form-data, not JSON: a client_data field holding the client as a JSON string, and an optional file field for a logo. street, province_state, buyer_name, business_type and industry are required; the last two are UUIDs from GET /api/business-types/ and GET /api/industries/ (see Reference data). Other fields are required depending on the client, and the spec lists them all.
curl -X POST "$CLIX_API/api/onboarding/organizations/clients/" \
-H "Authorization: Bearer $CLIX_KEY" \
-F 'client_data={"buyer_name": "Al Noor Trading", "business_type": "<business-type-uuid>", "industry": "<industry-uuid>",
"is_from_saudi_arabia": true, "is_vat_registered": true, "vat_registration_number": "300000000000003",
"additional_buyer_id": [{"type_id": "CRN", "id_number": "1010101010"}],
"street": "King Fahd Road", "building_number": "1234", "district": "Al Olaya",
"city": "Riyadh", "postal_code": "12211", "province_state": "Riyadh", "country": "SA"}'
This is a Saudi, VAT-registered client: the kind a standard tax invoice needs. Its VAT number has 15 digits and starts and ends with 3; building_number has 4 digits and postal_code 5. Without is_vat_registered and vat_registration_number the API answers 400 "Buyer VAT Registration or VAT Group Registration must not exist for Non VAT Registered Buyer"; without an additional_buyer_id entry it answers 400 "Type ID and ID number are required". A VAT number already on file answers 409.
Success is 201 with location: /api/buyers/{buyer_id}/. Client creation has its own limit of 50 a minute per key; beyond it you get 429.
Items¶
| Method | Path | Role | Live example |
|---|---|---|---|
GET |
/api/items/ |
ViewInvoice | example |
POST |
/api/items/ |
CreateInvoice | |
GET |
/api/items/{item_id}/ |
ViewInvoice | |
PATCH |
/api/items/{item_id}/ |
CreateInvoice |
POST /api/items/ is multipart/form-data too: an item_data field holding the item as a JSON string, and optional files for images. PATCH /api/items/{item_id}/ takes plain JSON.
Devices and usage¶
| Method | Path | Role | Live example |
|---|---|---|---|
GET |
/api/devices/ |
ViewInvoice | example |
GET |
/api/usage/current/ |
any | example |
Reference data¶
Eight GET endpoints for the codes on an invoice, any authenticated key — see Reference data.
Three more list the ids that a client or a note needs:
| Method | Path | Role | Live example |
|---|---|---|---|
GET |
/api/business-types/ |
any key | |
GET |
/api/industries/ |
any key | |
GET |
/api/sellers/reasons/ |
ViewInvoice |
The first two need no role: any valid key reads them. The spec marks them security: [], but the gateway still asks for a key and answers 401 without one. Their response shapes are on Reference data.
What a key deliberately cannot do¶
No deletes. DELETE on items and clients is Admin-only and off the key surface. Invoices cannot be deleted by anyone: DELETE /api/invoices/{invoice_id}/ answers 403 {"message": "Invoice deletion is not allowed."} even for an Admin. A leaked key cannot destroy records.
No administration. Users, roles, branches, devices, billing and API keys themselves are all Admin-only. A key cannot create another key.
No webhooks. There is no callback registration. Poll — see Quickstart.
Conventions¶
- Base URL — the gateway host including the version segment. Sandbox:
https://sandbox.api.goclix.ai/v1. Production: the host that comes with your production key, plus/v1. Every path on this page goes after it. - Auth —
Authorization: Bearer clix_…on every request. - Ids — UUIDs in paths.
-
Lists — a list endpoint returns an object with a named list inside, never a bare array. Read the list by its name, not
[0]. The top-level keys, as the sandbox returned them on 2026-10-04:Endpoint Top-level keys GET /api/devices/devices,total,num_pages,current_page,total_active_devices,total_ccsid_expired,total_pcsid_expired,total_active,total_expiring_soon,total_expired,total_unknownGET /api/buyers/buyers,total,num_pages,current_pageGET /api/items/items,total,page,page_size,num_pagesGET /api/invoices/message,invoices,total,num_pages,current_page,payment_status_options,invoice_status_options,max_invoice_amount,summaryGET /api/sellers/reasons/reasons,total,num_pages,current_pageItems name the page
page; the others name itcurrent_page. Reference data is different again: an object keyed by enum name, see Reference data. - Async creation —POST /api/invoices/returns202and alocationto poll. Thelocationis a path,/api/invoices/{invoice_id}/; put the base URL in front of it. - Errors —400for validation, never422; a validation400carries an array of"field.path: message"strings inmessage. Other errors carrymessageordetail; see Errors.
One key, one organisation¶
A key is bound to one organisation when it is issued, and every call acts in that organisation. There is no organisation switch: an X-Active-Org header is ignored for a key.