---
title: "Idempotencia — API v3 de AllSign"
type: explanation
canonical_url: "https://allsign.io/developers/docs/idempotency"
api_version: "2026-07-11"
agent_rules: [idempotency-key]
---

# Idempotencia

El header `Idempotency-Key` hace que reintentar un `POST` mutante sea **seguro**: si tu red se cae después de mandar la petición pero antes de recibir la respuesta, reintentas con la misma key y AllSign te devuelve el resultado original en vez de crear un segundo documento (o cobrar dos veces). Usa un **UUID v4** nuevo por cada operación lógica.

## Para agentes y asistentes de IA

-   **Todo `POST` que crea, cobra o envía algo lleva `Idempotency-Key` con un UUID v4 nuevo por operación.** Sin ella la API responde `400 IDEMPOTENCY_KEY_REQUIRED`; al reintentar la *misma* operación reutiliza la *misma* key y recibes la primera respuesta, sin doble cobro ni doble invitación.

```
Idempotency-Key: $(uuidgen)
```

## Qué POST la requieren

La `Idempotency-Key` es **requerida** en los `POST` que crean, cobran o mandan algo a una persona. Sin ella la respuesta es `400 IDEMPOTENCY_KEY_REQUIRED`:

| Operación | Idempotency-Key |
| --- | --- |
| `POST /v3/documents` | **Requerida** |
| `POST /v3/documents/{id}/send` | **Requerida** |
| `POST /v3/documents/{id}/void` | **Requerida** |
| `POST /v3/documents/{id}/annexes` | **Requerida** |
| `POST /v3/documents/{id}/signers/{signerId}/remind` | **Requerida** |
| `POST /v3/documents/{id}/signers/remind-all` | **Requerida** |
| `POST /v3/documents/{id}/signers/{signerId}/reassign` | **Requerida** |
| `POST /v3/documents/bulk-sends` | **Requerida** |
| `POST /v3/templates/{id}/documents` | **Requerida** |
| `POST /v3/signing-sessions` | **Requerida** |
| `POST /v3/constancias` | **Requerida** |
| `POST /v3/webhooks` y `POST /v3/webhooks/{id}/rotate-secret` | Opcional |
| Altas de plantillas, campos y *signer sets* (`POST /v3/templates`, `…/fields`, `…:duplicate`, `…:from-document`, `POST /v3/signer-sets`…) | Opcional |

**Opcional** quiere decir que si la mandas se honra igual (un reintento devuelve la primera respuesta), y si no la mandas la petición se procesa sin protección contra duplicados.

Los recordatorios (`remind` y `remind-all`) la exigen aunque además tienen su propio freno de **un recordatorio cada 4 horas** por firmante: la llave evita que un reintento de red mande dos correos; el freno evita que tu código insista de más.

No la usan:

-   `GET` — ya son idempotentes por naturaleza.
-   `PATCH` y `DELETE` — idempotentes por definición (el estado final es el mismo).
-   Los `POST` que no la declaran: `POST /v3/folders`, `POST /v3/documents/{id}/fields:assign-role`, `POST /v3/templates/{id}/validate-values`, `POST /v3/constancias/verify`, `POST /v3/devices/enroll` y el `init` de una sesión de firma.

## Cómo funciona

La primera vez que llega una key, AllSign procesa la petición normalmente y **guarda la respuesta** asociada a esa key. Si vuelve a llegar la *misma* key con el *mismo* cuerpo, no reprocesa: te devuelve la respuesta guardada **íntegra** (mismo status, mismo body), con el header `Idempotency-Replayed: true` para que sepas que fue un replay.

```
HTTP/1.1 201 Created
Idempotency-Replayed: true
Content-Type: application/json

{ "id": "doc_...", "status": "draft" }
```

Para decidir si dos peticiones son "la misma", AllSign calcula un **fingerprint sobre los bytes crudos** del cuerpo (no sobre el JSON normalizado). Reintenta con exactamente el mismo payload que enviaste la primera vez — un cambio de espacios o de orden de campos cuenta como cuerpo distinto.

## Respuestas de conflicto

| Código | Cuándo | Qué hacer |
| --- | --- | --- |
| `409 IDEMPOTENCY_KEY_REUSED` | Reusaste una key con una **petición distinta** (cuerpo o query string) en el mismo endpoint. | Usa una key nueva para la petición nueva; no mezcles operaciones bajo una misma key. |
| `409 IDEMPOTENCY_KEY_IN_PROGRESS` | La petición original **sigue procesándose**. | Espera y reintenta; trae `retryAfter` (segundos) para saber cuánto. |
| `400 IDEMPOTENCY_KEY_REQUIRED` | El endpoint la exige y **no la mandaste**. | Agrega el header `Idempotency-Key` con un UUID v4. |
| `400 IDEMPOTENCY_KEY_INVALID` | La key no tiene el **formato** esperado (UUID v4). | Genera un UUID v4 válido. |

```
HTTP/1.1 409 Conflict
Content-Type: application/problem+json

{
  "type": "https://allsign.io/developers/docs/errors#IDEMPOTENCY_KEY_IN_PROGRESS",
  "title": "Conflict",
  "status": 409,
  "code": "IDEMPOTENCY_KEY_IN_PROGRESS",
  "detail": "A request with this Idempotency-Key is still in progress.",
  "retryAfter": 2,
  "requestId": "req_..."
}
```

## Qué se cachea y por cuánto

No todas las respuestas se guardan para replay. Solo se cachean los resultados **determinísticos**: si reintentar puede dar un resultado distinto, no tiene sentido guardar el anterior.

| Respuesta | ¿Se cachea? | Por qué |
| --- | --- | --- |
| `2xx` (éxito) | **Sí** | El resultado es final; reintentar debe devolver lo mismo. |
| `4xx` de validación determinista (p.ej. `422`) | **Sí** | El mismo cuerpo fallará igual; se replica el error. |
| `402` (pago requerido) | No | Transitorio: reintentar tras arreglar el pago debe poder tener éxito. |
| `429` (rate limited) | No | Transitorio: reintentar más tarde debe funcionar. |
| `5xx` (error del servidor) | No | Transitorio: reintentar puede tener éxito. |

Las keys se **retienen 24 horas**. Dentro de esa ventana, reintentar con la misma key te devuelve la respuesta guardada; después, esa key se libera y una petición nueva se procesa desde cero. Genera una key por operación lógica y no la reutilices para operaciones diferentes.
