---
title: "Recuerda, reasigna o anula un documento que nadie firma — Receta de la API v3 de AllSign"
type: how-to
canonical_url: "https://allsign.io/developers/docs/recetas/anula-recuerda-reasigna"
api_version: "2026-07-11"
agent_rules: [webhook-no-polling, idempotency-key, una-base-url, error-por-code, reintento-429]
last_verified: "2026-10-08T12:16:37.879Z"
---

Receta

# Recuerda, reasigna o anula un documento que nadie firma

**Objetivo:** Destrabar un documento enviado: recordarle al firmante, pasarle su lugar a otra persona y, si ya no procede, anularlo dejando la razón.

Para: soporte · nivel intermedio · 10 min · Necesitas: API key de sandbox · Un documento enviado que sigue sin firmarse

## Para agentes y asistentes de IA

-   **Para saber que un documento quedó firmado, espera el webhook `document.completed`; no consultes `GET /v3/documents/{id}` en un bucle.** → [Webhooks](https://allsign.io/developers/docs/webhooks)
-   **Todo `POST` que crea, cobra o envía algo lleva `Idempotency-Key` con un UUID v4 nuevo por operación.** → [Idempotencia](https://allsign.io/developers/docs/idempotency)
-   **La base URL es siempre `https://api.allsign.io/v3`; no existe una URL de sandbox aparte.** → [Entornos](https://allsign.io/developers/docs/environments)
-   **Los errores son `application/problem+json` (RFC 9457) con un `code` estable y append-only; `detail` es texto técnico en inglés que puede cambiar.** → [Errores](https://allsign.io/developers/docs/errors)
-   **Ante un `429`, espera los segundos de `Retry-After` antes de reintentar; si el `429` no trae `Retry-After`, no lo reintentes.** → [Rate limits](https://allsign.io/developers/docs/rate-limits)

Grabado en el entorno interno de AllSign con una key de sandbox · backend `24c0469` · 8 oct 2026, 06:16 (hora CDMX) · test `docs-checks-v3/tests/recetas/anula-recuerda-reasigna.receta.spec.ts`

Los ejemplos usan `$ALLSIGN_API_KEY`. Defínela una vez con tu key de sandbox: `export ALLSIGN_API_KEY="allsign_test_sk_…"` (en PowerShell: `$env:ALLSIGN_API_KEY="allsign_test_sk_…"`).

## 1 Ubica al firmante que no ha firmado

GET `/documents/{document_id}/signers` [ver en la referencia](https://allsign.io/developers/docs/endpoints/documents#list-signers)

### Qué haces

Parte de un documento ya enviado. Cada firmante trae su id sgr\_…, su status y cómo le llegó su invitación.

### Qué mirar

-   `data.0.id` = `"sgr_80189c3a228a438cbb36757ed5f4738c"`
-   `data.0.status` = `"sent"`
-   `data.0.delivery` = `null`

**cURL**

```
curl 'https://api.allsign.io/v3/documents/doc_d0a1551c68d6457294e702fb25d07e4e/signers' \
  -H "Authorization: Bearer $ALLSIGN_API_KEY" \
  -H "AllSign-Version: 2026-07-11"
```

**Node**

```
const respuesta = await fetch('https://api.allsign.io/v3/documents/doc_d0a1551c68d6457294e702fb25d07e4e/signers', {
    headers: {
        Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,
        'AllSign-Version': '2026-07-11',
    },
});
console.log(respuesta.status, await respuesta.json());
```

**Python**

```
import os

import requests

respuesta = requests.get(
    "https://api.allsign.io/v3/documents/doc_d0a1551c68d6457294e702fb25d07e4e/signers",
    headers={
        "Authorization": f"Bearer {os.environ['ALLSIGN_API_KEY']}",
        "AllSign-Version": "2026-07-11",
    },
)
print(respuesta.status_code, respuesta.json())
```

**Respuesta · 200**

```
{
  "object": "list",
  "data": [
    {
      "livemode": false,
      "id": "sgr_80189c3a228a438cbb36757ed5f4738c",
      "object": "signer",
      "documentId": "doc_d0a1551c68d6457294e702fb25d07e4e",
      "email": "signer-pending@sandbox.allsign.io",
      "phone": null,
      "name": "Ana Torres",
      "status": "sent",
      "signedAt": null,
      "routingOrder": null,
      "delivery": null
    }
  ],
  "hasMore": false,
  "nextCursor": null,
  "previousCursor": null,
  "limit": null
}
```

## 2 Recuérdale que firme

POST `/documents/{document_id}/signers/{signer_id}/remind` [ver en la referencia](https://allsign.io/developers/docs/endpoints/documents#remind-signer)

### Qué haces

Le reenvía su invitación por el mismo canal. En sandbox ningún mensaje sale a @sandbox.allsign.io: delivered viene en false y nextAllowedAt es el mismo instante, así que no corre ninguna espera.

### Qué mirar

-   `channel` = `"email"`
-   `delivered` = `false`
-   `nextAllowedAt` = `"2026-07-11T18:00:00.000000Z"`

### En producción

Le llega de nuevo el correo o el WhatsApp y delivered viene en true. El siguiente recordatorio a esa persona queda bloqueado 4 horas: antes de nextAllowedAt la API responde 429, así que no lo reintentes en un bucle.

**cURL**

```
curl -X POST 'https://api.allsign.io/v3/documents/doc_d0a1551c68d6457294e702fb25d07e4e/signers/sgr_80189c3a228a438cbb36757ed5f4738c/remind' \
  -H "Authorization: Bearer $ALLSIGN_API_KEY" \
  -H "AllSign-Version: 2026-07-11" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'
```

**Node**

```
import { randomUUID } from 'node:crypto';

const respuesta = await fetch('https://api.allsign.io/v3/documents/doc_d0a1551c68d6457294e702fb25d07e4e/signers/sgr_80189c3a228a438cbb36757ed5f4738c/remind', {
    method: 'POST',
    headers: {
        Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,
        'AllSign-Version': '2026-07-11',
        'Idempotency-Key': randomUUID(),
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({}),
});
console.log(respuesta.status, await respuesta.json());
```

**Python**

```
import os
import uuid

import requests

respuesta = requests.post(
    "https://api.allsign.io/v3/documents/doc_d0a1551c68d6457294e702fb25d07e4e/signers/sgr_80189c3a228a438cbb36757ed5f4738c/remind",
    headers={
        "Authorization": f"Bearer {os.environ['ALLSIGN_API_KEY']}",
        "AllSign-Version": "2026-07-11",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={},
)
print(respuesta.status_code, respuesta.json())
```

**Respuesta · 200**

```
{
  "documentId": "doc_d0a1551c68d6457294e702fb25d07e4e",
  "signerId": "sgr_80189c3a228a438cbb36757ed5f4738c",
  "sentAt": "2026-07-11T18:00:00.000000Z",
  "nextAllowedAt": "2026-07-11T18:00:00.000000Z",
  "channel": "email",
  "delivered": false
}
```

## 3 Pásale su lugar a otra persona

POST `/documents/{document_id}/signers/{signer_id}/reassign` [ver en la referencia](https://allsign.io/developers/docs/endpoints/documents#reassign-signer)

### Qué haces

Conserva el lugar: mismo id sgr\_, mismo rol, mismas cajas y mismo turno; cambia la persona. La liga de la persona anterior deja de servir. Si ya había capturado algo, la API te pide confirm: true para descartarlo.

### Qué mirar en sandbox

-   `id` = `"sgr_80189c3a228a438cbb36757ed5f4738c"`
-   `email` = `"signer-pending+relevo@sandbox.allsign.io"`
-   `name` = `"Luis Ramírez"`
-   `status` = `"pending"`

### En producción

La persona nueva recibe su propia invitación.

**cURL**

```
curl -X POST 'https://api.allsign.io/v3/documents/doc_d0a1551c68d6457294e702fb25d07e4e/signers/sgr_80189c3a228a438cbb36757ed5f4738c/reassign' \
  -H "Authorization: Bearer $ALLSIGN_API_KEY" \
  -H "AllSign-Version: 2026-07-11" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "signer-pending+relevo@sandbox.allsign.io",
  "name": "Luis Ramírez",
  "reason": "Cambió el representante legal"
}'
```

**Node**

```
import { randomUUID } from 'node:crypto';

const respuesta = await fetch('https://api.allsign.io/v3/documents/doc_d0a1551c68d6457294e702fb25d07e4e/signers/sgr_80189c3a228a438cbb36757ed5f4738c/reassign', {
    method: 'POST',
    headers: {
        Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,
        'AllSign-Version': '2026-07-11',
        'Idempotency-Key': randomUUID(),
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        email: 'signer-pending+relevo@sandbox.allsign.io',
        name: 'Luis Ramírez',
        reason: 'Cambió el representante legal',
    }),
});
console.log(respuesta.status, await respuesta.json());
```

**Python**

```
import os
import uuid

import requests

respuesta = requests.post(
    "https://api.allsign.io/v3/documents/doc_d0a1551c68d6457294e702fb25d07e4e/signers/sgr_80189c3a228a438cbb36757ed5f4738c/reassign",
    headers={
        "Authorization": f"Bearer {os.environ['ALLSIGN_API_KEY']}",
        "AllSign-Version": "2026-07-11",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "email": "signer-pending+relevo@sandbox.allsign.io",
        "name": "Luis Ramírez",
        "reason": "Cambió el representante legal",
    },
)
print(respuesta.status_code, respuesta.json())
```

**Respuesta · 200**

```
{
  "livemode": false,
  "id": "sgr_80189c3a228a438cbb36757ed5f4738c",
  "object": "signer",
  "documentId": "doc_d0a1551c68d6457294e702fb25d07e4e",
  "email": "signer-pending+relevo@sandbox.allsign.io",
  "phone": null,
  "name": "Luis Ramírez",
  "status": "pending",
  "signedAt": null,
  "routingOrder": null,
  "delivery": null
}
```

## 4 Anula el documento

POST `/documents/{document_id}/void` [ver en la referencia](https://allsign.io/developers/docs/endpoints/documents#void-document)

### Qué haces

Anular es definitivo: el documento queda voided, nadie más puede firmarlo y la razón queda en su bitácora.

### Qué mirar

-   `status` = `"voided"`

**cURL**

```
curl -X POST 'https://api.allsign.io/v3/documents/doc_d0a1551c68d6457294e702fb25d07e4e/void' \
  -H "Authorization: Bearer $ALLSIGN_API_KEY" \
  -H "AllSign-Version: 2026-07-11" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "reason": "Se firmará otra versión con el monto corregido"
}'
```

**Node**

```
import { randomUUID } from 'node:crypto';

const respuesta = await fetch('https://api.allsign.io/v3/documents/doc_d0a1551c68d6457294e702fb25d07e4e/void', {
    method: 'POST',
    headers: {
        Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,
        'AllSign-Version': '2026-07-11',
        'Idempotency-Key': randomUUID(),
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        reason: 'Se firmará otra versión con el monto corregido',
    }),
});
console.log(respuesta.status, await respuesta.json());
```

**Python**

```
import os
import uuid

import requests

respuesta = requests.post(
    "https://api.allsign.io/v3/documents/doc_d0a1551c68d6457294e702fb25d07e4e/void",
    headers={
        "Authorization": f"Bearer {os.environ['ALLSIGN_API_KEY']}",
        "AllSign-Version": "2026-07-11",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "reason": "Se firmará otra versión con el monto corregido",
    },
)
print(respuesta.status_code, respuesta.json())
```

**Respuesta · 200**

```
{
  "livemode": false,
  "id": "doc_d0a1551c68d6457294e702fb25d07e4e",
  "object": "document",
  "name": "Contrato de arrendamiento — Ana Torres",
  "status": "voided",
  "documentType": "EDITABLE",
  "signerCount": 1,
  "signedCount": 0,
  "ownerId": "usr_024a2896938b4a6d81723e882bd556a9",
  "orgId": "f2cfe411-e1ac-4881-bf0c-a252d08e423a",
  "folderId": null,
  "expiresAt": null,
  "signingOrder": "parallel",
  "currentStage": null,
  "expirationReminders": null,
  "templateId": null,
  "templateVersionId": null,
  "parentDocumentId": null,
  "createdAt": "2026-07-11T17:59:57.129000Z",
  "updatedAt": "2026-07-11T18:00:17.507000Z"
}
```

## 5 Si lo anulas otra vez

POST `/documents/{document_id}/void` [ver en la referencia](https://allsign.io/developers/docs/endpoints/documents#void-document)

### Qué haces

Anular un documento ya anulado responde 200 con el mismo documento y no cambia nada: es así a propósito, para que un reintento no falle. No cuentes con un error para saber si ya estaba anulado: revisa status.

### Qué mirar

-   `status` = `"voided"`

**cURL**

```
curl -X POST 'https://api.allsign.io/v3/documents/doc_d0a1551c68d6457294e702fb25d07e4e/void' \
  -H "Authorization: Bearer $ALLSIGN_API_KEY" \
  -H "AllSign-Version: 2026-07-11" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "reason": "Se firmará otra versión con el monto corregido"
}'
```

**Node**

```
import { randomUUID } from 'node:crypto';

const respuesta = await fetch('https://api.allsign.io/v3/documents/doc_d0a1551c68d6457294e702fb25d07e4e/void', {
    method: 'POST',
    headers: {
        Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,
        'AllSign-Version': '2026-07-11',
        'Idempotency-Key': randomUUID(),
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        reason: 'Se firmará otra versión con el monto corregido',
    }),
});
console.log(respuesta.status, await respuesta.json());
```

**Python**

```
import os
import uuid

import requests

respuesta = requests.post(
    "https://api.allsign.io/v3/documents/doc_d0a1551c68d6457294e702fb25d07e4e/void",
    headers={
        "Authorization": f"Bearer {os.environ['ALLSIGN_API_KEY']}",
        "AllSign-Version": "2026-07-11",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "reason": "Se firmará otra versión con el monto corregido",
    },
)
print(respuesta.status_code, respuesta.json())
```

**Respuesta · 200**

```
{
  "livemode": false,
  "id": "doc_d0a1551c68d6457294e702fb25d07e4e",
  "object": "document",
  "name": "Contrato de arrendamiento — Ana Torres",
  "status": "voided",
  "documentType": "EDITABLE",
  "signerCount": 1,
  "signedCount": 0,
  "ownerId": "usr_024a2896938b4a6d81723e882bd556a9",
  "orgId": "f2cfe411-e1ac-4881-bf0c-a252d08e423a",
  "folderId": null,
  "expiresAt": null,
  "signingOrder": "parallel",
  "currentStage": null,
  "expirationReminders": null,
  "templateId": null,
  "templateVersionId": null,
  "parentDocumentId": null,
  "createdAt": "2026-07-11T17:59:57.129000Z",
  "updatedAt": "2026-07-11T18:00:17.507000Z"
}
```

## Errores comunes de esta receta

Errores reales que el test de esta receta provocó a propósito en sandbox, sobre sus mismos pasos. Cada uno enlaza a su explicación en [Errores](https://allsign.io/developers/docs/errors).

`SIGNER_NOT_FOUND` · 404 · en el paso 2 (Recuérdale que firme)

Recuérdale a un firmante que no es de ese documento. [Qué significa y qué hacer](https://allsign.io/developers/docs/errors#SIGNER_NOT_FOUND)

**Respuesta · 404 · SIGNER_NOT_FOUND**

```
{
  "type": "https://allsign.io/developers/docs/errors#SIGNER_NOT_FOUND",
  "title": "Not Found",
  "status": 404,
  "detail": "Signer '8bc0129e-c73d-4d49-b5d2-c0335a209b8d' not found in this document.",
  "instance": "/v3/documents/doc_ca783e90f0444172a7fbe75400ab5ebc/signers/sgr_8bc0129ec73d4d49b5d2c0335a209b8d/remind",
  "code": "SIGNER_NOT_FOUND",
  "requestId": "req_aa688e8a2b7e46ab88bb8e67a281ba61"
}
```

Grabado en el entorno interno de AllSign con una key de sandbox · backend `24c0469` · 8 oct 2026, 06:17 (hora CDMX) · test `docs-checks-v3/tests/recetas/anula-recuerda-reasigna.receta.spec.ts`

`INVALID_STATE_TRANSITION` · 409 · en el paso 2 (Recuérdale que firme)

Recuérdale a alguien de un documento anulado. [Qué significa y qué hacer](https://allsign.io/developers/docs/errors#INVALID_STATE_TRANSITION)

**Respuesta · 409 · INVALID_STATE_TRANSITION**

```
{
  "type": "https://allsign.io/developers/docs/errors#INVALID_STATE_TRANSITION",
  "title": "Conflict",
  "status": 409,
  "detail": "Document is in terminal state 'ANULADO' — cannot remind.",
  "instance": "/v3/documents/doc_ca783e90f0444172a7fbe75400ab5ebc/signers/sgr_f70f3376d8fc450a97111874e086f6b6/remind",
  "code": "INVALID_STATE_TRANSITION",
  "requestId": "req_18baf385999e4893975db73d70c38511",
  "reason": "document_terminal"
}
```

Grabado en el entorno interno de AllSign con una key de sandbox · backend `24c0469` · 8 oct 2026, 06:17 (hora CDMX) · test `docs-checks-v3/tests/recetas/anula-recuerda-reasigna.receta.spec.ts`

`INVALID_STATE_TRANSITION` · 409 · en el paso 3 (Pásale su lugar a otra persona)

Reasigna a alguien que ya firmó. [Qué significa y qué hacer](https://allsign.io/developers/docs/errors#INVALID_STATE_TRANSITION)

**Respuesta · 409 · INVALID_STATE_TRANSITION**

```
{
  "type": "https://allsign.io/developers/docs/errors#INVALID_STATE_TRANSITION",
  "title": "Conflict",
  "status": 409,
  "detail": "No se puede reasignar a un firmante que ya firmó.",
  "instance": "/v3/documents/doc_b7b43220a55940578a9feaef6c618cf5/signers/sgr_7d4f43e179d1487aab88d212de9def03/reassign",
  "code": "INVALID_STATE_TRANSITION",
  "requestId": "req_560c08b2d31f4128b8762eeec30fbf4e",
  "reason": "already_signed"
}
```

Grabado en el entorno interno de AllSign con una key de sandbox · backend `24c0469` · 8 oct 2026, 06:17 (hora CDMX) · test `docs-checks-v3/tests/recetas/anula-recuerda-reasigna.receta.spec.ts`

## Siguiente

-   [Lleva tu primer documento a firma](https://allsign.io/developers/docs/recetas/primer-documento-a-firma) — Un documento firmado de punta a punta en sandbox, con el aviso de cada firma y el de cierre llegando a tu servidor.
-   [Recibe y verifica los webhooks de AllSign](https://allsign.io/developers/docs/recetas/recibe-y-verifica-webhooks) — Un endpoint que recibe los eventos de AllSign, comprueba que de verdad los firmó AllSign y sobrevive a sus propias caídas y a la rotación del secreto.
