Skip to content

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_unknown
    GET /api/buyers/ buyers, total, num_pages, current_page
    GET /api/items/ items, total, page, page_size, num_pages
    GET /api/invoices/ message, invoices, total, num_pages, current_page, payment_status_options, invoice_status_options, max_invoice_amount, summary
    GET /api/sellers/reasons/ reasons, total, num_pages, current_page

    Items name the page page; the others name it current_page. Reference data is different again: an object keyed by enum name, see Reference data. - Async creation — POST /api/invoices/ returns 202 and a location to poll. The location is a path, /api/invoices/{invoice_id}/; put the base URL in front of it. - Errors — 400 for validation, never 422; a validation 400 carries an array of "field.path: message" strings in message. Other errors carry message or detail; 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.