Cairos
Facturación
Programa de facturaciónPresupuestosFacturas recurrentesGastos y proveedoresCobros y tesorería
Contabilidad e impuestos
ContabilidadModelos de HaciendaLibros registroInmovilizadoIGIC y Canarias
Operaciones
Inventario y almacenesCRMControl horarioProyectosSubvenciones y ayudas
Cumplimiento
VeriFactuTicketBAIFactura electrónicaToda la normativaSeguridad y datos
Por tipo de negocio
AutónomosPymesAsesorías y gestoríasExtranjeros en EspañaStartupsComercios y tiendas
Por sector
Hostelería y restaurantesConstrucción y reformasServicios profesionalesComercio electrónicoTodos los sectores
Por forma jurídica
AsociacionesFundacionesCooperativasClubes deportivosTodas las formas jurídicas
Cambiar de programa
ComparativasAlternativa a HoldedMigrar tus datos
Herramientas gratis
Plantilla de facturaCalculadora de IVACalculadora de IRPFTodas las herramientas
Aprender
GuíasGlosarioCalendario fiscalBlog
Desarrolladores
API y documentaciónEmpezar en cinco minutosReferencia de recursosWebhooks
Ayuda
Centro de ayudaContacto
Precios
Empieza gratis Iniciar sesión
Primeros pasos

De cero a una factura emitida, en seis llamadas

Sin SDK, sin instalar nada y sin leerse la referencia entera. Seis llamadas que puedes tener escritas hoy y ejecutar el día que la API abra. Ojo: hoy las rutas devuelven todavía 404, y esta página lo dice en cada paso.

curl, JavaScript y PHPSin dependenciasCopiar y pegar

La API está en marcha. Esto es lo que hay hoy y lo que no

Funciona. Las rutas de esta documentación están desplegadas y respondiendo en https://erp.cairos.es/api/v1/. Los ejemplos de estas páginas se pueden copiar y ejecutar. La especificación completa está en openapi.json, que es lo que importan Make y n8n.

Las claves te las creas tú, desde Desarrolladores en tu cuenta de Cairos. Empieza con una cai_test_: trabaja contra tus datos de verdad pero no registra en VeriFactu ni envía correos, así que puedes montar tu integración sin ensuciar una serie de facturación.

Y lo que todavía NO hay, dicho sin adornos: ningún conector oficial. Ni app de Shopify, ni plugin de WooCommerce, ni módulo publicado en Make o n8n. Con la API y su especificación se pueden construir —para eso están las guías de esta sección— pero construirlos es trabajo, y ese trabajo no está hecho.

Si montas algo con esto, escríbenos a hola@cairos.es. Nos interesa especialmente lo que te falte del contrato: es lo que decide qué se amplía primero.

El recorrido

Lo que vas a hacer

Tres bloques. El primero es el único que necesita que alguien te conteste un correo.

1

Conseguir la clave

Se pide por correo mientras la API no está abierta. Llega una clave de pruebas y se enseña una sola vez.

2

Comprobar que llega

Una llamada a /organizacion, que no pide ningún permiso. Si responde, el resto es cuesta abajo.

3

Facturar

Contacto, factura en borrador, emisión y PDF. Cuatro llamadas más y ya está hecho.

1 · Consigue una clave

Escribe a hola@cairos.es diciendo qué quieres integrar. Cuando haya contra qué llamar, te llega una clave de pruebas, que empieza por cai_test_.

Hoy este paso todavía no se completa, y por eso está el primero: las rutas de los pasos siguientes devuelven 404 porque aún no están escritas. Lo que sí puedes hacer desde ya es dejar montado el código de los pasos 2 a 6, que está escrito contra el contrato definitivo.

La clave se enseña una sola vez. No la guardamos: guardamos su huella, que sirve para reconocerla pero no para reconstruirla. Si la pierdes no te la podemos recuperar; hay que revocarla y crear otra. Guárdala donde guardes las contraseñas de tu servidor —una variable de entorno, un gestor de secretos— y no en el código.

Qué hace distinta a la clave de pruebas

Trabaja contra los mismos datos que la de producción: lo que crees con ella aparece en tu cuenta. Lo que no hace es registrar en VeriFactu ni enviar correos. Eso es exactamente lo que te permite desarrollar sin ensuciar una serie de facturación de verdad. No es una copia de tu empresa en un servidor aparte, y conviene tenerlo claro antes de lanzar un bucle de pruebas.

2 · La primera llamada, que confirma que todo está bien

GET /organizacion devuelve los datos fiscales de tu empresa. Es la llamada más barata que hay y no pide ningún scope: si tu clave vale, responde.

export CAIROS_CLAVE=cai_test_TU_CLAVE

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

Cuando salga un 200 con el nombre de tu empresa dentro, habrás terminado la parte difícil. Hoy lo que sale es un 404, porque la ruta todavía no está escrita; eso no significa que la ruta sea otra.

200 OK
{
  "id": "org_3Kd8vR",
  "nombre": "Talleres Miralles SL",
  "nif": "B12345674",
  "regimen": "general",
  "moneda": "EUR",
  "series": ["F27"]
}

Y si sale un 401, la clave no ha llegado bien. Los dos motivos son casi siempre el mismo: falta la palabra Bearer delante, o la variable de entorno está vacía y estás mandando la cabecera sin nada detrás.

3 · Crea un contacto

Una factura necesita a quién se la haces. Con 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": "cliente"
  }'

Vuelve un 201 con el contacto creado y su id. Guárdatelo: es lo que va a pedir la factura.

Fíjate en la cabecera Idempotency-Key. Aquí todavía no duele —un contacto duplicado se borra— pero es el mismo hábito que dentro de dos pasos evita que emitas dos facturas del mismo pedido. Está contado entero en idempotencia.

4 · Crea la factura, que nace en borrador

Con invoices:write. La factura se crea sin número y en estado 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": "con_7Qb3xK",
    "serie": "F27",
    "fecha": "2027-03-02",
    "lineas": [
      {
        "concepto": "Revision anual",
        "cantidad": 2,
        "precio": 180.00,
        "iva": 21
      }
    ]
  }'
201 Created
{
  "id": "fac_5Np2wD",
  "numero": null,
  "estado": "borrador",
  "contacto_id": "con_7Qb3xK",
  "serie": "F27",
  "fecha": "2027-03-02",
  "base": 360.00,
  "cuota_iva": 75.60,
  "total": 435.60
}

numero viene a null, y eso es correcto: el número no existe hasta que se emite. Los totales, en cambio, ya vienen calculados, así que aquí es donde se comprueba que lo que has mandado cuadra con lo que esperabas cobrar.

5 · Emítela, que es el paso que no se deshace

Ahora sí. Al emitir, la factura toma el siguiente número de su serie y se genera el registro de VeriFactu encadenado con el anterior.

curl -X POST \
  https://erp.cairos.es/api/v1/facturas/fac_5Np2wD/emitir \
  -H "Authorization: Bearer $CAIROS_CLAVE" \
  -H "Idempotency-Key: emitir-pedido-1042"
200 OK
{
  "id": "fac_5Np2wD",
  "numero": "F27/0042",
  "estado": "emitida",
  "total": 435.60,
  "verifactu": {
    "estado": "remitida",
    "huella": "7f3c1a…d904"
  }
}

Con una clave de pruebas, el bloque «verifactu» no viene

Es la diferencia que importa entre cai_test_ y cai_live_: la de pruebas no registra en VeriFactu ni manda correos. Todo lo demás —el número de la serie, los totales, el PDF— funciona igual.

6 · Y descárgate el PDF

GET /facturas/{id}/pdf no devuelve JSON: devuelve el fichero, con su código QR y su leyenda ya impresos.

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

Y ya está: seis llamadas, y al final una factura emitida, numerada y en PDF. El resto de la documentación es detalle sobre esto.

Lo que falla en los dos primeros minutos

Casi siempre es una de estas cinco cosas, y ninguna es interesante. Por eso vale la pena tenerlas juntas:

Lo que vesLo que pasa de verdad
401 no_autenticadoFalta la palabra Bearer delante de la clave, o la variable de entorno está vacía y mandas la cabecera con nada dentro. Comprueba lo segundo antes de dar por perdida la clave.
403 sin_permisoLa clave es válida pero le falta el scope de esa llamada. Y ojo con la trampa: tener invoices:write no te deja leer facturas. Son dos permisos distintos.
422 datos_invalidosEl JSON llegó, pero algo dentro no vale. error.detalles te dice qué campo y por qué; míralo antes de tocar nada.
409 conflictoEstás intentando algo que el estado del documento no permite: emitir una factura ya emitida, o reutilizar una Idempotency-Key con un cuerpo distinto.
El servidor no responde JSONSuele ser el Content-Type. Si mandas cuerpo, tiene que ir application/json: sin él, el cuerpo llega y no se lee.

Los siete códigos de error, con lo que hay que hacer con cada uno, están en errores y límites.

Y ahora, ¿por dónde sigo?

Depende de lo que estés montando, y sinceramente sólo hay tres caminos:

  • Vas a crear facturas desde otro sistema. Lee idempotencia antes que nada. Es la página más aburrida de esta sección y la que evita el único error de esta API que no se arregla borrando.
  • Necesitas enterarte de lo que pasa en Cairos. Entonces lo tuyo son los webhooks, no consultar la API cada cinco minutos.
  • Vas a leer datos y poco más. Mira la paginación por cursor, porque una lista de facturas de un año no cabe en una respuesta.

Y si lo que tienes delante es una tienda o una herramienta de automatización, hay página propia: WooCommerce, Shopify, Make y n8n.

Dudas del primer día

No. La clave se emite contra una organización, así que hace falta una cuenta —el plan gratuito sirve— y pedir el acceso a hola@cairos.es.
Porque emitir es irreversible: asigna el número correlativo de la serie y genera el registro de VeriFactu. Separarlo en dos llamadas te deja comprobar los totales antes de que ocurra lo que ya no se puede deshacer. Si quieres las dos cosas seguidas, encadena las dos llamadas; lo que no hacemos es quitarte la oportunidad de mirar.
Una factura emitida no se borra: se rectifica, con una factura rectificativa que deja constancia. Es lo que exige el reglamento de facturación, y por eso no hay un DELETE que lo arregle. Está explicado en VeriFactu.
No. precio es el precio unitario sin impuestos e iva es el tipo en porcentaje. La respuesta trae base, cuota_iva y total ya calculados, que es lo que conviene comparar con lo que esperabas.
No lo hagas. Poner una clave de API en el JavaScript de una página es publicarla: cualquiera que abra las herramientas del navegador la ve. Las llamadas se hacen desde tu servidor, y el navegador habla con tu servidor, no con Cairos.

Déjalo escrito hoy y ejecútalo el día que abra

Seis llamadas, quince minutos con calma. Dinos qué estás montando y te avisamos en cuanto haya contra qué llamar.

Clave de pruebas · Mismos datos, sin VeriFactu ni correos

Soporte