Saltar a contenido

🔁 Reintentar peticiones sin duplicar cambios

Cuando una petición de escritura se corta por un timeout o un fallo de red, no sabes si Zinkee llegó a aplicarla. Si la repites, puedes crear dos veces el mismo registro; si no la repites, puedes perder el cambio.

La cabecera Idempotency-Key resuelve esa duda. Envías una clave con la petición y, si la repites con la misma clave, Zinkee reconoce el reintento: si la primera petición ya terminó, devuelve la misma respuesta sin volver a ejecutarla. Es especialmente útil en integraciones, scripts y agentes que reintentan las peticiones de forma automática.

Antes de empezar

  • Necesitas una clave API del workspace. En los ejemplos se lee de la variable de entorno ZINKEE_API_KEY.
  • La cabecera es opcional y solo afecta a las peticiones de escritura (POST, PATCH, PUT y DELETE) de la API V2, las rutas que empiezan por /api/v2. Si no la envías, la API funciona igual que siempre.

1. Generar una clave para cada operación

La clave identifica una operación concreta, por ejemplo, «crear el contacto Ada Lovelace». Genera una clave nueva para cada operación y reutilízala solo para reintentar esa misma operación.

  • Usa un UUID v4, como 3f1c2b7e-8d4a-4c55-9a61-2f0e7b9c1d44. En Bash puedes generarlo con uuidgen.
  • La clave admite de 1 a 128 caracteres: letras sin tilde (A-Z, a-z), números y los signos ., _, : y -.

Guarda la clave antes de enviar la petición

Guarda la clave junto a la operación pendiente. Si tu proceso se reinicia después de un fallo, necesitarás la misma clave para reintentar: con una clave nueva, Zinkee trataría el reintento como otra operación y podría aplicarla dos veces.

2. Enviar la petición con la cabecera

Añade la cabecera Idempotency-Key a la petición. En este ejemplo se crea un registro con POST /api/v2/schemas/{schemaId}/records:

IDEMPOTENCY_KEY=$(uuidgen)

curl https://api-z2.zinkee.com/api/v2/schemas/$SCHEMA_ID/records   
  --request POST   
  --header "Authorization: Bearer $ZINKEE_API_KEY"   
  --header "Content-Type: application/json"   
  --header "Idempotency-Key: $IDEMPOTENCY_KEY"   
  --data '{
    "records": [
      {
        "contact-name": "Ada Lovelace",
        "contact-email": "ada@example.com"
      }
    ]
  }'

La primera vez, la petición se ejecuta con normalidad.

3. Reintentar con la misma clave

Si no recibes respuesta, repite la misma petición con la misma clave. Zinkee compara el método, la ruta, los parámetros de consulta y el cuerpo, así que reenvía la petición tal como la enviaste, sin volver a generar el cuerpo: si cambia un valor, por ejemplo una fecha calculada en el momento, la API la considera otra petición.

Si la primera petición ya terminó, la API no la vuelve a ejecutar: devuelve el mismo código y el mismo cuerpo, y añade la cabecera de respuesta Idempotent-Replayed: true. Con curl --include puedes ver las cabeceras:

HTTP/1.1 200 OK
Content-Type: application/json
Idempotent-Replayed: true

{
  "created": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "errors": []
}

Registros rechazados al crear varios a la vez

POST /api/v2/schemas/{schemaId}/records valida cada registro por separado. Si un registro no supera la validación, también cuando el valor por defecto de un campo no es válido para él, aparece en errors de una respuesta 200, junto con los registros creados. Así, una petición que ya ha empezado a crear registros nunca responde con un error 4xx, y un reintento con la misma clave devuelve ese mismo resultado parcial sin crear nada más. Para crear los registros rechazados, corrígelos y envíalos en una petición nueva, con una clave nueva.


Qué responde la API

Situación Respuesta Qué hacer
Es la primera petición con esa clave. La petición se ejecuta con normalidad. Nada especial.
La primera petición ya terminó y repites la misma petición con la misma clave. El mismo código y el mismo cuerpo que la primera vez, con la cabecera Idempotent-Replayed: true. Trata la respuesta como la de la primera petición.
Usas la misma clave con una petición distinta. 422, motivo idempotency_key_reused. Usa una clave nueva para cada operación.
La primera petición todavía se está ejecutando. 409, motivo idempotency_request_in_progress, con la cabecera Retry-After: 2. Espera los segundos que indica Retry-After y reintenta con la misma clave.
La primera petición terminó, pero su respuesta no se guardó porque no era JSON u ocupaba más de 256 KB. 409, motivo idempotency_response_not_stored. La operación no se repite. Consulta los recursos afectados para ver el resultado.
La primera petición falló con un error del servidor (5xx) después de empezar. Los reintentos devuelven el mismo código, con el motivo idempotent_request_failed. Los cambios pueden haberse aplicado en parte. Revisa los recursos afectados y, si hace falta, repite la operación con una clave nueva.
La primera petición se rechazó con un error 4xx: validación, recurso no encontrado, conflicto… No se guarda nada. Un reintento con la misma clave se ejecuta de nuevo. Si corriges la petición, envíala con una clave nueva.
La petición supera el límite de peticiones del workspace. 429, motivo rate_limit, con la cabecera Retry-After. La petición no se ejecuta y la clave no se guarda. Espera los segundos que indica Retry-After y reintenta con la misma clave.
El servicio que guarda las claves no responde. 503, motivo idempotency_unavailable, con la cabecera Retry-After: 5. La petición no se ejecuta. Si el almacenamiento de la plataforma está caído por completo, la petición puede fallar antes con otro error del servidor, por ejemplo 500, también sin ejecutarse. Espera unos segundos, los que indique Retry-After si viene, y reintenta con la misma clave.
La clave no tiene un formato válido o envías la cabecera más de una vez. 400, motivo idempotency_key_invalid. Envía la cabecera una sola vez, con 1 a 128 caracteres permitidos.
Envías la cabecera al subir un fichero. 400, motivo idempotency_key_not_supported. Envía la subida sin la cabecera.
El cuerpo de la petición ocupa más de 256 KB. 413, motivo idempotency_request_too_large. La petición no se ejecuta. Divide la operación en peticiones más pequeñas, cada una con su clave, o envíala sin la cabecera.

Si recibes un error del servidor (5xx)

Si la respuesta no trae el motivo idempotent_request_failed, reintenta con la misma clave: si la primera petición no llegó a ejecutarse, el reintento la ejecuta, y si falló después de empezar, el reintento recibe idempotent_request_failed en lugar de repetirla. Solo ese motivo exige revisar los recursos afectados y, si hace falta, repetir la operación con una clave nueva. Ten en cuenta la excepción que se describe en Limitaciones.

Los errores tienen el formato habitual de la API. Usa el campo reason para decidir qué hacer; message y action describen el error en inglés:

{
  "status": 409,
  "error": "CONFLICT",
  "reason": "idempotency_request_in_progress",
  "message": "A request with this Idempotency-Key is still in progress.",
  "action": "Retry with the same Idempotency-Key after the Retry-After delay.",
  "retryable": true,
  "path": "/api/v2/schemas/2eb8bdcf-6d9c-4fbb-9018-7fa8180f4c5e/records",
  "requestId": "6f1d9c2a-0b7e-4f4c-8a3d-5e2b1c9f7a10",
  "timestamp": "2026-10-22T10:15:00Z"
}

Alcance de la clave

  • La clave pertenece al workspace: todas las claves API del mismo workspace comparten el mismo espacio de claves. Si cada operación usa un UUID v4 nuevo, dos integraciones no coincidirán por accidente.
  • Zinkee guarda el resultado durante 24 horas. Pasado ese plazo, una petición con la misma clave se ejecutaría como nueva, así que no la uses para reintentos tan tardíos.

Peticiones que admiten la cabecera

  • Todas las peticiones POST, PATCH, PUT y DELETE de la API V2, salvo las indicadas a continuación.
  • Las consultas que se envían con POST, cuyas rutas terminan en :query o :aggregate, como POST /api/v2/schemas/{schemaId}/records:query y POST /api/v2/schemas/{schemaId}/records:aggregate, ignoran la cabecera: solo leen datos y puedes repetirlas sin riesgo.
  • Las subidas de ficheros, POST /api/v2/files y POST /api/v2/document-templates/{templateId}/assets, no la admiten. Si una subida falla, súbela de nuevo: cada subida genera un identificador distinto. Para borrar los ficheros que no llegues a usar, sigue Subir ficheros y adjuntarlos a un registro.

Con la CLI de Zinkee

La CLI de Zinkee acepta la opción global --idempotency-key. Con ella, envía la cabecera y repite la misma petición si hay un error de red, se agota el tiempo de espera o la API responde idempotency_request_in_progress. Hace como máximo 3 intentos y respeta la cabecera Retry-After.

zinkee records create contacts --records-file ./registros.json   
  --idempotency-key 3f1c2b7e-8d4a-4c55-9a61-2f0e7b9c1d44

Si vuelves a ejecutar el mismo comando con la misma clave, recibirás la misma respuesta sin crear los registros otra vez.

En las consultas, como zinkee records query y zinkee records aggregate, la CLI no envía la cabecera aunque indiques --idempotency-key y no repite la petición si falla: solo leen datos, así que puedes volver a ejecutarlas.

Limitaciones

  • Con la cabecera, el cuerpo de la petición no puede ocupar más de 256 KB. Si necesitas enviar más datos, por ejemplo muchos registros a la vez, divídelos en varias peticiones y usa una clave distinta en cada una.
  • Si el servidor se detiene en mitad de una petición o no consigue guardar cómo terminó, durante unos 60 segundos los reintentos con la misma clave reciben idempotency_request_in_progress. Después, un reintento con la misma clave vuelve a ejecutar la operación. Si la operación crea registros, comprueba antes si ya existen.
  • Las rutas que no pertenecen a la API V2 no admiten la cabecera.

Consulta todos los parámetros y respuestas en la referencia de la API.