The Dolibarr REST API, from the key to a paid invoice

Enable the Dolibarr REST API, create an API key for a dedicated user, then create a customer, an invoice, its PDF and its payment with curl. Including the trap of invoice lines that change order.

Versions concerned
Dolibarr 24.0.1 (tested); the line order flaw is also in the code of 24.0.2 and of the development branch on 13/10/2026
What was checked
Every call on this page run on 13/10/2026 against a fresh Dolibarr 24.0.1 instance (official Docker image), with a dedicated user limited to the permissions listed: responses and HTTP codes recorded, invoice checked in the database and on the generated PDF. API code (api_invoices, api_access) and Facture::create and Facture::addline read in 24.0.1, 24.0.2 and develop.

Dolibarr ships a REST API: everything you do on screen (third parties, invoices, orders, products…) can be done from another program, a website or a script. This page starts from scratch and goes all the way to a validated invoice, with its PDF and its payment. Every command was run on 13 October 2026 against a fresh Dolibarr 24.0.1 instance.

Along the way, three behaviours worth knowing that the documentation does not mention:

  • lines sent together with the invoice change order on the invoice and on the PDF;
  • an invoice validated through the API has no PDF until you ask for one;
  • when the module is disabled, the API still answers “200 OK”.

1. Enable the module

Setup › Modules/Applications, module API / Web services (REST server). Its setup page gives the explorer address and lets you restrict access to some IP addresses.

While the module is disabled, every API address answers with code 200 and this text:

Module <b>Api</b> must be enabled.<br><br>To activate modules, go on setup Area (Home->Setup->Modules).

A script that only checks the HTTP code will think all is well: also check that the response is JSON.

Enable the modules whose data you want as well. For this page: Third Parties, Invoices and, for payments, Banks & Cash. The APIs of a disabled module do not show up.

2. Create a dedicated user and its key

The API key carries exactly the permissions of the user it belongs to. Do not create it on your administrator account: create a user reserved for the API.

  1. Users & Groups › New user: a name, a login (for example api-invoicing).
  2. On the Token for API line, click Generate: a 32-character key appears. Copy it, then Create user.
  3. Permissions tab: grant only what is needed. For everything below, this was enough:
Module Permissions
Third Parties Read third parties linked to user; Create/modify third parties linked to user
Invoices Read customer invoices (and payments); Create/modify customer invoices; Create payments for customer invoices

The user record then shows the key as “Hidden”: it is stored encrypted in the database. To see it again, open the record with Modify.

3. The first call

Every address starts with https://your-dolibarr/api/index.php/. The key goes in the DOLAPIKEY header:

DOLI=https://your-dolibarr/api/index.php
KEY=paste_your_key_here
curl -s -H "DOLAPIKEY: $KEY" "$DOLI/status"
{
    "success": {
        "code": 200,
        "dolibarr_version": "24.0.1",
        "access_locked": "0"
    }
}

The Authorization: Bearer <key> header works too. Dolibarr also accepts the key in the address (?DOLAPIKEY=…), but it then ends up in server and proxy logs: prefer the header.

The errors you will meet

Response Cause
401 “Neither parameter ‘HTTP_DOLAPIKEY’ nor ‘Authentication: Bearer’ found” No key sent
401 “Error user not valid (not found with api key or bad status…)” Wrong key, or user disabled or outside its validity dates
403 “Forbidden” Right key, but the user lacks the required permission
200 with “Module Api must be enabled” API module disabled
400 “Invalid value specified for accountid” Payment without a bank account (see step 8)

4. Create a customer

curl -s -X POST -H "DOLAPIKEY: $KEY" -H "Content-Type: application/json" \
  -d '{"name": "Martin Bakery", "client": 1}' \
  "$DOLI/thirdparties"

The response is simply the id of the new third party, for example 1. "client": 1 makes it a customer. To find a third party by name:

curl -s -G -H "DOLAPIKEY: $KEY" \
  --data-urlencode "sqlfilters=(t.nom:like:'Martin%')" \
  "$DOLI/thirdparties"

5. Create the invoice, then its lines one by one

The API accepts an invoice with its lines in a single call (a lines array). Don’t. In our tests the lines changed order: sent as 1, 2, 3, they showed on the invoice and on the PDF as 2, 1, 3, and as 3, 1, 2 when each line’s rank was given. During creation, Dolibarr believes it is inserting each line between the others and shifts ranks wrongly. The same code is in 24.0.2 and in the development branch.

Create the invoice on its own first:

curl -s -X POST -H "DOLAPIKEY: $KEY" -H "Content-Type: application/json" \
  -d '{"socid": 1, "type": 0, "date": "2026-10-13"}' \
  "$DOLI/invoices"

The response is the invoice id (here 4). socid is the customer id and "type": 0 means a standard invoice. A YYYY-MM-DD date is accepted. Then add each line, in the order you want:

curl -s -X POST -H "DOLAPIKEY: $KEY" -H "Content-Type: application/json" \
  -d '{"desc": "Dolibarr installation", "qty": 1, "subprice": 690, "tva_tx": 20, "product_type": 1}' \
  "$DOLI/invoices/4/lines"

subprice is the unit price excluding tax, tva_tx the VAT rate, and product_type is 1 for a service, 0 for a product. The invoice stays a draft, with a temporary reference such as (PROV4).

6. Validate the invoice

curl -s -X POST -H "DOLAPIKEY: $KEY" "$DOLI/invoices/4/validate"

The response holds the full invoice, with its final reference ("ref": "FA2610-0001").

7. Generate and fetch the PDF

On screen, validation produces the PDF. Through the API it does not: after validation, the invoice folder holds no PDF. Ask for it explicitly, with the reference you got:

curl -s -X PUT -H "DOLAPIKEY: $KEY" -H "Content-Type: application/json" \
  -d '{"modulepart": "invoice", "original_file": "FA2610-0001/FA2610-0001.pdf", "langcode": "en_US"}' \
  "$DOLI/documents/builddoc" > /dev/null

The file is then stored in Dolibarr, as if you had generated it on screen. To download it, the API returns its content base64-encoded (decoded here with jq):

curl -s -H "DOLAPIKEY: $KEY" \
  "$DOLI/documents/download?modulepart=invoice&original_file=FA2610-0001/FA2610-0001.pdf" \
  | jq -r .content | base64 -d > FA2610-0001.pdf

8. Record the payment

A payment must belong to an account of the Banks module: without accountid, the API answers “Invalid value specified for accountid”. The account id can be read in the address of its record (…/compta/bank/card.php?id=1). The payment method id can be found through the API:

curl -s -H "DOLAPIKEY: $KEY" "$DOLI/setup/dictionary/payment_types"

On a fresh install: 2 transfer, 4 cash, 6 card, 7 cheque. Then:

curl -s -X POST -H "DOLAPIKEY: $KEY" -H "Content-Type: application/json" \
  -d '{"datepaye": "2026-10-13", "paymentid": 2, "closepaidinvoices": "yes", "accountid": 1, "num_payment": "TRF-001"}' \
  "$DOLI/invoices/4/payments"

With "closepaidinvoices": "yes", a fully paid invoice moves to the paid status.

The explorer, for everything else

At https://your-dolibarr/api/index.php/explorer/, Dolibarr lists all its APIs. Paste the key in the field at the top right and click Explore: without a key, only the login API shows. Every call is documented there and can be tried; the list depends on the enabled modules. The same description, in Swagger format, is at /api/index.php/explorer/swagger.json.

Good practice

  • One user per use (website, invoicing tool, script…), each with its own permissions only: you can cut one off without touching the others.
  • Always over HTTPS: the key travels with every request.
  • If the API only serves a known server, restrict access to its IP address in the module setup.

To connect Dolibarr to another program without writing the code yourself, the Custom module package starts from a precise quote.

DolibarrAPIRESTAPI keyDOLAPIKEYcurlinvoiceexplorer