Cairos
Facturació
Programa de facturacióPressupostosFactures recurrentsDespeses i proveïdorsCobraments i tresoreria
Comptabilitat i impostos
ComptabilitatModels d'HisendaLlibres registreImmobilitzatIGIC i Canàries
Operacions
Inventari i magatzemsCRMControl horariProjectesSubvencions i ajuts
Compliment
VeriFactuTicketBAIFactura electrònicaTota la normativaSeguretat i dades
Per tipus de negoci
AutònomsPimesAssessories i gestoriesEstrangers a EspanyaStartupsComerços i botigues
Per sector
Hostaleria i restaurantsConstrucció i reformesServeis professionalsComerç electrònicTots els sectors
Per forma jurídica
AssociacionsFundacionsCooperativesClubs esportiusTotes les formes jurídiques
Canviar de programa
ComparativesAlternativa a HoldedMigrar les teves dades
Eines gratis
Plantilla de facturaCalculadora d'IVACalculadora d'IRPFTotes les eines
Aprendre
GuiesGlossariCalendari fiscalBlog
Desenvolupadors
API i documentacióComença en cinc minutsReferència de recursosWebhooks
Ajuda
Centre d'ajudaContacte
Preus
Comença gratis Inicia la sessió
Primeres passes

De zero a una factura emesa, en sis crides

Sense SDK, sense instal·lar res i sense llegir-se la referència sencera. Sis crides que pots copiar, enganxar i executar ara mateix: l'API està desplegada i la clau te la crees tu des del teu compte. Comença amb una de proves i no embrutaràs cap sèrie de facturació.

curl, JavaScript i PHPSense dependènciesCopiar i enganxar

L'API està en marxa. Això és el que hi ha avui i el que no

Funciona. Les rutes d'aquesta documentació estan desplegades i responent a https://erp.cairos.es/api/v1/. Els exemples d'aquestes pàgines es poden copiar i executar. L'especificació completa és a openapi.json, que és el que importen Make i n8n.

Les claus te les crees tu, des de Desenvolupadors al teu compte de Cairos. Comença amb una cai_test_: treballa contra les teves dades de veritat però no registra a VeriFactu ni envia correus, així que pots muntar la teva integració sense embrutar una sèrie de facturació.

I el que encara NO hi ha, dit sense adorns: cap connector oficial. Ni app de Shopify, ni plugin de WooCommerce, ni mòdul publicat a Make o n8n. Amb l'API i la seva especificació es poden construir —per això hi ha les guies d'aquesta secció— però construir-los és feina, i aquesta feina no està feta.

Si muntes alguna cosa amb això, escriu-nos a hola@cairos.es. Ens interessa especialment el que et falti del contracte: és el que decideix què s'amplia primer.

El recorregut

El que faràs

Tres blocs. El primer es fa al teu compte, en un minut; els altres dos són codi.

1

Crear la clau

A Desenvolupadors, dins del teu compte. Comença per una de proves, i apunta-te-la: s'ensenya una sola vegada.

2

Comprovar que arriba

Una crida a /organizacion, que no demana cap permís. Si respon, la resta és costa avall.

3

Facturar

Contacte, factura en esborrany, emissió i PDF. Quatre crides més i ja està fet.

1 · Crea la clau

Al teu compte de Cairos, a Desenvolupadors. No cal demanar-la per correu ni esperar que ningú contesti: tries el mode, marques els permisos un a un i es genera a l'instant. Comença amb una de proves, que comença per cai_test_.

Marca els permisos que faràs servir en aquesta pàgina i cap més: contacts:write per al pas 3, i invoices:read i invoices:write per als passos 4, 5 i 6. Si te'n falta un, l'error ho diu pel seu nom i s'arregla creant una altra clau.

La clau s'ensenya una sola vegada. No la guardem: guardem la seva empremta, que serveix per reconèixer-la però no per reconstruir-la. Si la perds no te la podem recuperar; s'ha de revocar i crear-ne una altra. Guarda-la on guardis les contrasenyes del teu servidor —una variable d'entorn, un gestor de secrets— i no al codi.

Què fa diferent la clau de proves

Treballa contra les mateixes dades que la de producció: el que creïs amb ella apareix al teu compte. El que no fa és registrar a VeriFactu ni enviar correus. Això és exactament el que et permet desenvolupar sense embrutar una sèrie de facturació de debò. No és una còpia de la teva empresa en un servidor a part, i convé tenir-ho clar abans de llançar un bucle de proves.

2 · La primera crida, que confirma que tot està bé

GET /organizacion retorna les dades fiscals de la teva empresa. És la crida més barata que hi ha i no demana cap scope: si la teva clau val, respon.

export CAIROS_CLAVE=cai_test_TU_CLAVE

curl https://erp.cairos.es/api/v1/organizacion \
  -H "Authorization: Bearer $CAIROS_CLAVE"

Quan surti un 200 amb el nom de la teva empresa a dins, hauràs acabat la part difícil.

200 OK
{
  "id": "clx3k2p9y0000qz8h1a2b3c4d",
  "nombre": "Talleres Miralles SL",
  "razon_social": "Talleres Miralles, S.L.",
  "nif": "B12345674",
  "ciudad": "Girona",
  "provincia": "Girona",
  "moneda": "EUR",
  "region_fiscal": "peninsula",
  "tipo_iva_defecto": 21,
  "recargo_equivalencia": false,
  "plan_contable": "pgc"
}

Els identificadors són així de lletjos a propòsit: són cuid, opacs i sense prefix. No els interpretis ni intentis deduir de quin recurs són —guarda'ls tal qual i envia'ls on toqui—, perquè el dia que deixin de tenir aquesta forma el teu codi no se n'hauria d'assabentar.

I si surt un 401, la clau no ha arribat bé. Els dos motius són gairebé sempre el mateix: falta la paraula Bearer al davant, o la variable d'entorn és buida i estàs enviant la capçalera sense res al darrere.

3 · Crea un contacte

Una factura necessita a qui la fas. Amb contacts:write:

curl -X POST https://erp.cairos.es/api/v1/contactos \
  -H "Authorization: Bearer $CAIROS_CLAVE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: alta-cliente-1042" \
  -d '{
    "nombre": "Grupo Bonaire SL",
    "nif": "B17654321",
    "email": "admin@bonaire.example",
    "tipo": "customer"
  }'

Torna un 201 amb el contacte creat i el seu id. Guarda-te'l: és el que demanarà la factura.

Fixa't en la capçalera Idempotency-Key. Aquí encara no fa mal —un contacte duplicat s'esborra— però és el mateix hàbit que d'aquí a dos passos evita que emetis dues factures de la mateixa comanda. Està explicat sencer a idempotència.

4 · Crea la factura, que neix en esborrany

Amb invoices:write. La factura es crea sense número i en estat borrador:

curl -X POST https://erp.cairos.es/api/v1/facturas \
  -H "Authorization: Bearer $CAIROS_CLAVE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: pedido-1042" \
  -d '{
    "contacto_id": "clx3k2p9y0000qz8h1a2b3c4d",
    "serie": "F27",
    "fecha_emision": "2027-03-02",
    "lineas": [
      {
        "descripcion": "Revision anual",
        "cantidad": 2,
        "precio": 180.00,
        "tipo_iva": 21
      }
    ]
  }'
201 Created
{
  "id": "clx3k2p9y0001qz8h5e6f7g8h",
  "serie": "F27",
  "numero": null,
  "referencia": null,
  "tipo_documento": "invoice",
  "estado": "draft",
  "fecha_emision": "2027-03-02",
  "fecha_vencimiento": null,
  "base_imponible": 360.00,
  "cuota_iva": 75.60,
  "cuota_irpf": 0.00,
  "total": 435.60,
  "cobrado": 0.00,
  "pendiente": 435.60
}

numero i referencia vénen a null, i això és correcte: el número no existeix fins que s'emet. Els totals, en canvi, ja vénen calculats, així que aquí és on es comprova que el que has enviat quadra amb el que esperaves cobrar.

Fixa't en estado: val draft, en anglès. Els recursos i els camps d'aquesta API són en castellà, però uns quants valors d'enumerat es van quedar en anglès —draft, sent, paid, overdue— i aquí es queden, perquè traduir-los trencaria qualsevol integració escrita fins avui.

5 · Emet-la, que és el pas que no es desfà

Ara sí. En emetre, la factura pren el següent número de la seva sèrie i es genera el registre de VeriFactu encadenat amb l'anterior.

curl -X POST \
  https://erp.cairos.es/api/v1/facturas/clx3k2p9y0001qz8h5e6f7g8h/emitir \
  -H "Authorization: Bearer $CAIROS_CLAVE" \
  -H "Idempotency-Key: emitir-pedido-1042"
201 Created
{
  "id": "clx3k2p9y0001qz8h5e6f7g8h",
  "serie": "F27",
  "numero": 42,
  "referencia": "F27-0042",
  "estado": "sent",
  "total": 435.60,
  "pendiente": 435.60,
  "verifactu": {
    "registrada": true,
    "huella": "7f3c1a…d904",
    "registrada_en": "2027-03-02T10:41:08.517Z",
    "aeat": null
  }
}

Dues coses d'aquesta resposta que convé mirar bé. numero és un enter, no un text: el «F27-0042» que s'ensenya imprès és referencia, que ajunta sèrie i número. I l'estat passa a sent, que és el mateix en què la deixa el botó «Marca enviada» de la pantalla.

Si tornes a cridar /emitir sobre una factura ja emesa, no surt un error: surt la mateixa factura amb el seu mateix número, i un 200 en comptes del 201. És a propòsit, i és el que permet reintentar sense arriscar un salt en la numeració quan no saps si la primera crida va arribar.

Amb una clau de proves, «verifactu» ve amb registrada: false

El bloc arriba igual —no desapareix—, però diu la veritat: una clau cai_test_ no registra a VeriFactu ni envia correus, així que huella i registrada_en vénen a null. Tota la resta —el número de la sèrie, els totals, el PDF— funciona igual. I aquest camp és just el que s'ha de mirar el dia que passis a producció, per comprovar que ara sí que es registra.

6 · I descarrega't el PDF

GET /facturas/{id}/pdf no retorna JSON: retorna el fitxer, amb el seu codi QR i la seva llegenda ja impresos.

curl
curl https://erp.cairos.es/api/v1/facturas/clx3k2p9y0001qz8h5e6f7g8h/pdf \
  -H "Authorization: Bearer $CAIROS_CLAVE" \
  -o factura.pdf

I ja està: sis crides, i al final una factura emesa, numerada i en PDF. La resta de la documentació és detall sobre això.

El que falla en els dos primers minuts

Gairebé sempre és una d'aquestes cinc coses, i cap no és interessant. Per això val la pena tenir-les juntes:

El que veusEl que passa de debò
401 no_autenticadoFalta la paraula Bearer davant de la clau, o la variable d'entorn és buida i envies la capçalera amb res a dins. Comprova això segon abans de donar la clau per perduda.
403 sin_permisoLa clau és vàlida però li falta el scope d'aquella crida. I compte amb el parany: tenir invoices:write no et deixa llegir factures. Són dos permisos diferents.
422 datos_invalidosEl JSON va arribar, però alguna cosa de dins no val. error.detalles et diu quin camp i per què; mira-ho abans de tocar res.
409 conflictoEstàs intentant una cosa que l'estat del document no permet: emetre una factura ja emesa, o reutilitzar una Idempotency-Key amb un cos diferent.
El servidor no respon JSONSol ser el Content-Type. Si envies cos, ha d'anar application/json: sense ell, el cos arriba i no es llegeix.

Els set codis d'error, amb el que s'ha de fer amb cadascun, són a errors i límits.

I ara, per on continuo?

Depèn del que estiguis muntant, i sincerament només hi ha tres camins:

  • Crearàs factures des d'un altre sistema. Llegeix idempotència abans que res. És la pàgina més avorrida d'aquesta secció i la que evita l'únic error d'aquesta API que no s'arregla esborrant.
  • Necessites assabentar-te del que passa a Cairos. Llavors el teu són els webhooks, no consultar l'API cada cinc minuts.
  • Llegiràs dades i poca cosa més. Mira la paginació per cursor, perquè una llista de factures d'un any no cap en una resposta.

I si el que tens al davant és una botiga o una eina d'automatització, hi ha pàgina pròpia: WooCommerce, Shopify, Make i n8n.

Dubtes del primer dia

No. La clau s'emet contra una organització, així que cal un compte —el pla gratuït serveix—. La clau te la crees tu des de Desenvolupadors; no cal demanar-la ni esperar que ningú contesti.
Perquè emetre és irreversible: assigna el número correlatiu de la sèrie i genera el registre de VeriFactu. Separar-ho en dues crides et deixa comprovar els totals abans que passi el que ja no es pot desfer. Si vols les dues coses seguides, encadena les dues crides; el que no fem és treure't l'oportunitat de mirar.
Una factura emesa no s'esborra: es rectifica, amb una factura rectificativa que en deixa constància. És el que exigeix el reglament de facturació, i per això no hi ha un DELETE que ho arregli. Està explicat a VeriFactu.
Per defecte no: precio és el preu unitari sense impostos i tipo_iva és el tipus en percentatge. La resposta porta base_imponible, cuota_iva i total ja calculats, que és el que convé comparar amb el que esperaves. Si véns d'una botiga al públic, on el preu que existeix és el de l'etiqueta, envia precios_con_iva: true i Cairos desglossa la base cap enrere en cèntims sencers, amb el mateix motor que fa servir el connector de botigues.
No ho facis. Posar una clau d'API al JavaScript d'una pàgina és publicar-la: qualsevol que obri les eines del navegador la veu. Les crides es fan des del teu servidor, i el navegador parla amb el teu servidor, no amb Cairos.

Sis crides, quinze minuts amb calma

Crea la clau de proves, enganxa el primer curl i continua fins al PDF. I si muntes alguna cosa amb això, explica-nos-ho: el que li falta a la gent del contracte és el que decideix què s'amplia primer.

Clau de proves · Les mateixes dades, sense VeriFactu ni correus

Suport