Cairos
Invoicing
Invoicing softwareQuotesRecurring invoicesExpenses and suppliersReceipts and cash flow
Accounting and tax
AccountingAEAT tax formsRecord booksFixed assetsIGIC and the Canary Islands
Operations
Inventory and warehousesCRMTime trackingProjectsGrants and funding
Compliance
VeriFactuTicketBAIElectronic invoicingAll the regulationsSecurity and data
By type of business
Self-employedSmall businessesAccountants and tax advisersForeigners in SpainStartupsRetail and shops
By sector
Hospitality and restaurantsConstruction and renovationProfessional servicesE-commerceAll sectors
By legal structure
AssociationsFoundationsCooperativesSports clubsAll legal structures
Switching software
ComparisonsAn alternative to HoldedMigrating your data
Free tools
Invoice templateVAT calculatorIRPF calculatorAll the tools
Learn
GuidesGlossaryTax calendarBlog
Developers
API and documentationGet started in five minutesResource referenceWebhooks
Help
Help centreContact
Pricing
Start for free Log in
Automation

Make: four HTTP modules and no app

There is no official Cairos app in Make, and for what has to be done there is no need for one either. With the HTTP module and a key connection you can build the whole route from an order to an issued invoice.

HTTP moduleThe key in the keychainWith error handling

The API is up and running. This is what there is today and what there is not

It works. The routes in this documentation are deployed and responding at https://erp.cairos.es/api/v1/. The examples on these pages can be copied and run. The full specification is at openapi.json, which is what Make and n8n import.

You create the keys yourself, from Developers in your Cairos account. Start with a cai_test_ key: it works against your real data but does not record to VeriFactu and does not send emails, so you can build your integration without dirtying an invoice series.

And what there still is NOT, said plainly: no official connector. No Shopify app, no WooCommerce plugin, no published Make or n8n module. They can be built with the API and its specification — that is what the guides in this section are for — but building them is work, and that work is not done.

If you build something with this, write to us at hola@cairos.es. We are particularly interested in whatever you find missing from the contract: that is what decides which parts get extended first.

There is no official Cairos app in Make

It is not published and there is no date. What there is is the API — with its list of events, its OpenAPI and its webhooks — and this page, which tells you exactly what to hook up and with what code. Inside Cairos there are also ready-made recipes and a downloadable n8n flow, under API and integrations → Get started.

If your shop runs on PrestaShop, this is your route

Cairos only connects to Shopify, WooCommerce and Odoo. Not to PrestaShop yet, and it is half-finished on purpose: the VAT rate for each line does not come with the line — it has to be resolved against two other resources in their API — coupons are a separate resource applied to the order and not to the lines, and every shop calls the status that means «sold» something different, because the merchant edits those statuses. Invoicing three orders out of four and making up the VAT on the fourth is worse than saying no: the «no» is visible on day one, and VAT put in wrong shows up on the 303.

In the meantime, its orders come in through here perfectly well: PrestaShop knows how to notify an address when an order arrives, and what sits underneath is exactly the same route this page describes.

The module you use

The usual one when there is no app: HTTP. And within HTTP, the one that makes the request with key authentication, which exists precisely so as not to leave the key written in plain sight in the scenario.

The difference between using that module and the generic HTTP one is not cosmetic. With the generic one, the Authorization header with your key inside it stays written in the scenario, and anyone on your team who opens it sees it and can take it away. With the key connection, the key lives in Make's keychain and the scenario only references it.

Connection fieldWhat to put
Key name (header)Authorization
ValueBearer cai_live_YOUR_KEY — with the word Bearer and the space
Where it goesIn the header, not in the query

The commonest mistake when setting this up is putting in only the key, without Bearer in front. You get a 401 no_autenticado and it looks as though the key is wrong when what is missing is a word.

A complete scenario: from an order to an invoice

Four modules. The first one changes depending on where the order comes from; the other three are always the same.

#ModuleWhat it does
1TriggerA custom webhook that your shop points at, or the watch module of whichever app you use. This is where the order comes in.
2HTTP · request with a keyPOST to /contactos. JSON body with the name, NIF and email from the order.
3HTTP · request with a keyPOST to /facturas with the lines and the contact id from step 2.
4HTTP · request with a keyPOST to /facturas/{id}/emitir, with the id from step 3.

The body for step 3, exactly as you paste it into the module's content field, replacing what is between braces with whatever your trigger brings:

The HTTP module's body
{
  "contacto_id": "el id que devolvió el paso 2",
  "serie": "WEB",
  "fecha_emision": "la fecha del pedido, en AAAA-MM-DD",
  "lineas": [
    {
      "descripcion": "el nombre del artículo",
      "cantidad": 1,
      "precio": 180.00,
      "tipo_iva": 21
    }
  ]
}

Copy those names exactly. The four that always get written wrong are fecha_emision (not “fecha”), descripcion (not “concepto”), tipo_iva (not “iva”) and, in step 2, tipo with the value customer (not “cliente”). The API does not ignore a field it does not know: it returns 422 naming it, so if a module goes red with that code, the first thing to look at is error.detalles.campos.

And in each module's headers, two of them, besides the one the connection adds:

Headers
Content-Type: application/json
Idempotency-Key: make-1042

The idempotency key, which in Make matters more than anywhere

Make retries scenarios, and that is the whole problem

A scenario that fails halfway can be run again, in full, from the incomplete executions queue. If the module that failed was the fourth, the first three run again, and the second creates another contact and the third another invoice. With the header in place, the second run returns the same invoice and nothing happens.

The key has to come from the order identifier in the trigger, not from a random function or the current date: if it changes between the run and the repeat, it is no use at all. And a different one per operation: make-1042 to create the invoice and make-1042-emitir to issue it.

Why this matters so much and what happens when it is missing is in idempotency.

Error handling

Without error handling, a module that returns 422 stops the scenario and sends it to the queue. With it, you can decide what to do, and the decision is not the same for every code:

What Cairos returnsWhat to put in the error handler
429 or 500Retry. They are the only two it makes sense to repeat, and with the key in place repeating costs nothing.
422 datos_invalidosIgnore it and post to a channel. The data is coming through wrong from the other system and repeating will give the same error. error.detalles says which field.
401 or 403Stop and raise the alarm. It is the connection or the scope: retrying only burns operations.

All seven codes, with which of them to retry, are in errors and limits.

And a tip that saves operations on your plan: do not build a scenario that polls Cairos every five minutes in case there is something new. Subscribe to a webhook and let the scenario start when something happens. It is cheaper, it is faster and it does not eat into the API limit.

If this is going to take you more than an afternoon, look at n8n

It is not a recommendation against Make: it is that n8n has a code node where you can check a webhook's signature, and in Make that is more awkward. If you are only going to call Cairos, Make works perfectly well; if you are also going to receive signed events, the other one will give you less trouble.

Questions about Make

No. You use the HTTP module, which calls any API that speaks JSON. Nothing more is needed for everything this documentation describes.
In a key-authentication connection on the HTTP module, with the name Authorization and the value Bearer plus the key. That way it sits in Make's keychain and is not written into the scenario, where anyone on your team would see it.
Almost always because the word Bearer and the space in front of the key are missing. It is the number one mistake when setting this up.
That the modules before the failure run again. Without Idempotency-Key that means a second invoice; with it, the second run returns the first invoice and nothing is duplicated.
Yes: create a custom webhook in Make and subscribe it with POST /webhooks. It is far better than polling every few minutes, which spends operations to find out that nothing has happened.
Yes, and today it is the way to do it. Cairos connects on its own to Shopify, WooCommerce and Odoo; not yet to PrestaShop, because its API does not let you safely work out the VAT rate on each line or the coupons, and we would rather not invoice at all than invoice with an invented VAT rate. With PrestaShop's order webhook and these four modules, the order ends up as an issued invoice just the same.
Yes, and that way you get every operation without typing a single route. But ask for it as openapi.json?version=3.0: Make still does not digest OpenAPI 3.1's type: ["string","null"] and it either gets stuck on import or leaves the fields that can come back empty badly typed. It is the same contract, translated.

Build the scenario and try it with a test key

The routes and the bodies are the ones the server accepts today. Create a cai_test_ key and run the scenario: it does not register with VeriFactu and it sends no emails.

HTTP module · Key connection · Idempotency-Key from the order

Support