Cairos
Facturación
Programa de facturaciónOrzamentosFacturas recorrentesGastos e provedoresCobros e tesouraría
Contabilidade e impostos
ContabilidadeModelos de FacendaLibros rexistroInmobilizadoIGIC e Canarias
Operacións
Inventario e almacénsCRMControl horarioProxectosSubvencións e axudas
Cumprimento
VeriFactuTicketBAIFactura electrónicaToda a normativaSeguridade e datos
Por tipo de negocio
AutónomosPemesAsesorías e xestoríasEstranxeiros en EspañaStartupsComercios e tendas
Por sector
Hostalaría e restaurantesConstrución e reformasServizos profesionaisComercio electrónicoTodos os sectores
Por forma xurídica
AsociaciónsFundaciónsCooperativasClubs deportivosTodas as formas xurídicas
Cambiar de programa
ComparativasAlternativa a HoldedMigrar os teus datos
Ferramentas gratis
Modelo de facturaCalculadora de IVECalculadora de IRPFTodas as ferramentas
Aprender
GuíasGlosarioCalendario fiscalBlog
Desenvolvedores
API e documentaciónComezar en cinco minutosReferencia de recursosWebhooks
Axuda
Centro de axudaContacto
Prezos
Comeza gratis Iniciar sesión
EspañolGalego
Idempotencia

Unha cabeceira que evita dúas facturas polo mesmo pedido

Se a rede se corta antes da resposta, quen chama non sabe se a factura se creou. Reintentar sen chave produce dous números correlativos por un pedido, e iso nunha serie de facturación non se arranxa borrando.

Unha cabeceiraVinte e catro horas de memoriaEn todo o que cree algo

A API está en marcha. Isto é o que hai hoxe e o que non

Funciona. As rutas desta documentación están despregadas e respondendo en https://erp.cairos.es/api/v1/. Os exemplos destas páxinas pódense copiar e executar. A especificación completa está en openapi.json, que é o que importan Make e n8n.

As claves créalas ti, desde Desenvolvedores na túa conta de Cairos. Comeza cunha cai_test_: traballa contra os teus datos de verdade pero non rexistra en VeriFactu nin envía correos, así que podes montar a túa integración sen enlixar unha serie de facturación.

E o que aínda NON hai, dito sen adornos: ningún conector oficial. Nin app de Shopify, nin plugin de WooCommerce, nin módulo publicado en Make ou n8n. Coa API e a súa especificación pódense construír —para iso están as guías desta sección— pero construílos é traballo, e ese traballo non está feito.

Se montas algo con isto, escríbenos a hola@cairos.es. Interésanos especialmente o que che falte do contrato: é o que decide que se amplía primeiro.

O problema, contado como pasa de verdade

A túa tenda recibe o pedido 1042. O teu código chama a Cairos para crear a factura e emitila. E entón cae a rede.

Fíxate no que sabes e no que non. Sabes que mandaches a petición. Non sabes se chegou. Non sabes se se procesou. O único que tes é un tempo de espera esgotado, que é exactamente a mesma resposta tanto se a factura se creou coma se non.

E aquí é onde empeza o problema de verdade, porque a reacción natural é reintentar. Se a primeira chamada si chegara, agora tes dúas facturas, con dous números correlativos, polo mesmo pedido.

Diagrama de secuencia en dous carrís: á esquerda «o teu sistema», á dereita «Cairos». Frecha de ida POST /facturas que chega; Cairos crea a factura F27/0042; a frecha de volta 201 córtase a metade cunha marca de erro. Debaixo, o reintento sen chave crea F27/0043 duplicada, e con chave devolve a mesma F27/0042. Estilo de liña, cores do sistema, radio 0.

developers-idempotencia.svg · 1200×560 px

O corte prodúcese na volta, non na ida. Por iso quen chama non pode distinguir «non se fixo» de «fíxose e non me enterei».

Por que iso non se arranxa borrando

En case calquera outra API, dous rexistros duplicados bórranse e non pasou nada. Nunha serie de facturación, non.

Os números dunha serie son correlativos e sen ocos: é o que esixe o regulamento de facturación e o que comproba calquera que mire os teus libros. Se emitiches a F27/0042 e a F27/0043 polo mesmo pedido e borras a segunda, non che queda unha serie limpa: quédache unha serie cun oco, e un oco nunha numeración correlativa é exactamente o sinal que busca unha inspección.

O que hai que facer entón é o correcto, e é traballo: emitir unha factura rectificativa que anule a duplicada, deixando constancia de por que. Con VeriFactu hai ademais un rexistro de anulación encadeado, porque a norma non permite que unha factura desapareza sen deixar rastro.

Reintentar sen chave

  • Dúas facturas con dous números por un pedido.
  • O teu cliente recibe dúas facturas e chama.
  • Non se arranxa borrando: hai que rectificar e xustificar.
  • O IVE repercutido do trimestre sae de máis ata que o corrixas.
  • E se o reintento foi automático, pode ter pasado cen veces.

Reintentar con chave

  • A segunda chamada devolve a mesma factura, co seu mesmo número.
  • O teu código non ten que distinguir «creado» de «xa estaba creado».
  • Un tempo de espera esgotado deixa de ser un problema: repites e xa.
  • Vale igual para o 500 e para o proceso que se reinicia a medias.
  • E non custa nada: é unha cabeceira.

Como se usa: unha cabeceira e nada máis

En calquera chamada que cree algo, engade Idempotency-Key cun valor teu:

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",
    "lineas": [ { "descripcion": "Pedido 1042",
                  "cantidad": 1, "precio": 360.00,
                  "tipo_iva": 21 } ]
  }'

O que fai o servidor con iso:

  • Se é a primeira vez que ve esa chave, fai o traballo e garda a resposta.
  • Se xa a vira co mesmo corpo, non repite nada: devolve a resposta gardada, co mesmo identificador e o mesmo número de factura.
  • Se xa a vira cun corpo distinto, devolve 409 conflicto. Iso non é unha molestia: é a API avisándote de que estás reutilizando unha chave para dúas cousas diferentes, que é un fallo do teu lado.

Que chave poñer, que é o único que hai que pensar

A regra é unha soa e todo o demais dedúcese dela: a chave ten que ser a mesma no intento e no reintento, e distinta para dúas operacións distintas.

ChaveServe?Por que
pedido-1042SiSae do identificador do pedido no teu sistema. Ao reintentar sae a mesma sen ter que gardala en ningunha parte.
emitir-pedido-1042SiCrear a factura e emitila son dúas operacións: dúas chaves. Coa mesma para as dúas, a segunda chamada daría 409.
wc-1042-2027SiSe tes dúas tendas que numeran pedidos pola súa conta, mete de onde vén: dous pedidos 1042 distintos non poden compartir chave.
Un UUID aleatorio por intentoNonÉ o erro clásico. Se o reintento xera outra chave, a API non pode saber que é o mesmo traballo, e duplicas igual ca sen cabeceira.
A marca de tempoNonCambia entre o intento e o reintento. Mesmo caso ca o anterior.
facturaNonDemasiado xenérica: a segunda factura do día chocaría coa primeira e sairía un 409 que non significa nada.

Se tes que gardar a chave nalgún sitio para poder reintentar, escolle outra: a boa é a que se calcula a partir de algo que xa tes.

Un UUID aleatorio si vale, pero só se o xeras unha vez e o gardas xunto ao pedido antes de chamar, e o reutilizas nos reintentos. Que é máis traballo ca usar o identificador do pedido e non dá nada a cambio.

Canto dura unha chave

As chaves lémbranse durante vinte e catro horas. Pasado ese prazo, a mesma chave volve considerarse nova e crearía outra factura.

É tempo de sobra para o que a cabeceira resolve —un corte de rede, un reintento automático, un proceso que se reinicia—, e non é un mecanismo para non duplicar nunca. Se o que necesitas é garantir que un pedido de hai tres semanas non se volva facturar, iso non o arranxa a idempotencia: arránxao gardar no teu sistema o identificador da factura que creaches e miralo antes de chamar. As dúas cousas compleméntanse e fan falta as dúas.

O patrón completo, en tres liñas

Un: antes de chamar, mira se xa gardaches o identificador de factura dese pedido. Se o tes, non chames. Dous: se non o tes, chama con Idempotency-Key derivada do pedido. Tres: garda o identificador que che devolve antes de facer nada máis. Con iso, nin un corte de rede nin un reproceso a man duplican nada.

Onde vale e onde non fai falta

Mándaa en todo o que cree algo: POST /contactos, POST /productos, POST /facturas, POST /facturas/{id}/emitir, POST /gastos e POST /cobros. Emitir e rexistrar un cobro son as dúas onde máis doe o duplicado.

Non fai falta nas lecturas. Un GET pódese repetir cen veces sen consecuencias; esa é a definición de idempotente e por iso non leva cabeceira.

E nun PATCH tampouco é necesaria, porque mandar dúas veces o mesmo cambio deixa o recurso igual. Podes mandala se che simplifica o código, e non estorba.

A forma curta de se lembrar: se a operación consome un número de serie ou move diñeiro, leva chave.

Preguntas sobre idempotencia

Un identificador que ti escolles e que lle di á API «esta chamada e o seu reintento son o mesmo traballo». Se a petición se repite coa mesma chave, non se volve facer nada: devólvese a resposta da primeira.
Tecnicamente non, e na práctica si para calquera integración automática. Sen ela, o primeiro corte de rede entre o teu servidor e o noso pode acabar en dúas facturas polo mesmo pedido.
Porque os números dunha serie de facturación son correlativos e sen ocos. Borrar a duplicada deixa un oco, que é xusto o que non pode haber. O correcto é emitir unha rectificativa, e con VeriFactu queda ademais un rexistro de anulación encadeado.
Unha que se poida calcular a partir de algo que xa tes, como o identificador do pedido: pedido-1042. O que non vale é un aleatorio novo en cada intento, porque entón o reintento parece outra operación e duplica igual.
Vinte e catro horas. É de sobra para cubrir cortes e reintentos. Para non volver facturar un pedido antigo, o que fai falta é gardar no teu sistema o identificador da factura e comprobalo antes de chamar.
Que esa chave xa se usou cun corpo distinto. É un fallo do teu lado: estás reutilizando a mesma chave para dúas operacións diferentes. Cambia a chave, non o corpo.

É unha cabeceira. Ponna desde o primeiro día

Engadila cando a integración xa está en marcha é fácil. Explicarlle a un cliente por que ten dúas facturas do mesmo pedido, non.

Idempotency-Key · En POST · Derivada do pedido

Soporte