---
title: "Lleva tu primer documento a firma — Receta de la API v3 de AllSign"
type: how-to
canonical_url: "https://allsign.io/developers/docs/recetas/primer-documento-a-firma"
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:19:39.845Z"
---

Receta

# Lleva tu primer documento a firma

**Objetivo:** Un documento firmado de punta a punta en sandbox, con el aviso de cada firma y el de cierre llegando a tu servidor.

Para: integrador · nivel inicial · 10 min · Necesitas: API key de sandbox (allsign\_test\_sk\_…) · Un PDF: contrato.pdf · Un endpoint HTTPS para webhooks

## 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:19 (hora CDMX) · test `docs-checks-v3/tests/recetas/primer-documento-a-firma.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 Registra tu endpoint de webhooks

POST `/webhooks` [ver en la referencia](https://allsign.io/developers/docs/webhooks#create-endpoint)

### Qué haces

Primero tu endpoint: así te enteras de cada firma y del cierre sin consultar en bucle. Guarda el secreto whsec\_…, que solo se muestra aquí; con él verificas cada entrega.

### Qué mirar

-   `id` = `"whe_faed666bbdc5444693acfac1655160a6"`
-   `secret` = `"whsec_…"`

**cURL**

```
curl -X POST 'https://api.allsign.io/v3/webhooks' \
  -H "Authorization: Bearer $ALLSIGN_API_KEY" \
  -H "AllSign-Version: 2026-07-11" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://ejemplo.com/webhooks/allsign",
  "events": [
    "signer.signed",
    "document.completed"
  ],
  "description": "Mi primer contrato"
}'
```

**Node**

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

const respuesta = await fetch('https://api.allsign.io/v3/webhooks', {
    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({
        url: 'https://ejemplo.com/webhooks/allsign',
        events: [
            'signer.signed',
            'document.completed',
        ],
        description: 'Mi primer contrato',
    }),
});
console.log(respuesta.status, await respuesta.json());
```

**Python**

```
import os
import uuid

import requests

respuesta = requests.post(
    "https://api.allsign.io/v3/webhooks",
    headers={
        "Authorization": f"Bearer {os.environ['ALLSIGN_API_KEY']}",
        "AllSign-Version": "2026-07-11",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "url": "https://ejemplo.com/webhooks/allsign",
        "events": [
            "signer.signed",
            "document.completed",
        ],
        "description": "Mi primer contrato",
    },
)
print(respuesta.status_code, respuesta.json())
```

**Respuesta · 201**

```
{
  "livemode": false,
  "id": "whe_faed666bbdc5444693acfac1655160a6",
  "object": "webhook_endpoint",
  "url": "https://ejemplo.com/webhooks/allsign",
  "events": [
    "signer.signed",
    "document.completed"
  ],
  "description": "Mi primer contrato",
  "status": "enabled",
  "apiVersion": "2026-07-11",
  "environment": "test",
  "secretLast4": "S5w=",
  "createdAt": "2026-07-11T18:00:00.000000Z",
  "secret": "whsec_…"
}
```

## 2 Crea el documento con su firmante

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

### Qué haces

Crear no envía nada: el documento nace en draft y todavía lo puedes cambiar. signer-pending@sandbox.allsign.io es un firmante de prueba que no recibe correo y nunca firma solo: espera a que tú firmes por él.

### Qué mirar en sandbox

-   `id` = `"doc_fdde14eeff0b4444acec4d6b10736068"`
-   `status` = `"draft"`
-   `signerCount` = `1`

**cURL**

```
curl -X POST 'https://api.allsign.io/v3/documents' \
  -H "Authorization: Bearer $ALLSIGN_API_KEY" \
  -H "AllSign-Version: 2026-07-11" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "file": {
    "content": "'"$(base64 < contrato.pdf | tr -d '\n')"'",
    "fileType": "pdf",
    "name": "contrato.pdf"
  },
  "name": "Mi primer contrato (sandbox)",
  "signers": [
    {
      "email": "signer-pending@sandbox.allsign.io",
      "name": "Ana Torres"
    }
  ]
}'
```

**Node**

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

const respuesta = await fetch('https://api.allsign.io/v3/documents', {
    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({
        file: {
            content: readFileSync('contrato.pdf').toString('base64'),
            fileType: 'pdf',
            name: 'contrato.pdf',
        },
        name: 'Mi primer contrato (sandbox)',
        signers: [
            {
                email: 'signer-pending@sandbox.allsign.io',
                name: 'Ana Torres',
            },
        ],
    }),
});
console.log(respuesta.status, await respuesta.json());
```

**Python**

```
import base64
import os
import uuid
from pathlib import Path

import requests

respuesta = requests.post(
    "https://api.allsign.io/v3/documents",
    headers={
        "Authorization": f"Bearer {os.environ['ALLSIGN_API_KEY']}",
        "AllSign-Version": "2026-07-11",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "file": {
            "content": base64.b64encode(Path("contrato.pdf").read_bytes()).decode(),
            "fileType": "pdf",
            "name": "contrato.pdf",
        },
        "name": "Mi primer contrato (sandbox)",
        "signers": [
            {
                "email": "signer-pending@sandbox.allsign.io",
                "name": "Ana Torres",
            },
        ],
    },
)
print(respuesta.status_code, respuesta.json())
```

**Respuesta · 201**

```
{
  "livemode": false,
  "id": "doc_fdde14eeff0b4444acec4d6b10736068",
  "object": "document",
  "name": "Mi primer contrato (sandbox)",
  "status": "draft",
  "documentType": "EDITABLE",
  "signerCount": 1,
  "signedCount": 0,
  "ownerId": "usr_08f394a003014001b429ca03db05b7f7",
  "orgId": "f4d8bad5-5bb0-451c-a917-2ae6b489d38f",
  "folderId": null,
  "expiresAt": null,
  "signingOrder": "parallel",
  "currentStage": null,
  "expirationReminders": null,
  "templateId": null,
  "templateVersionId": null,
  "parentDocumentId": null,
  "createdAt": "2026-07-11T18:01:02.144000Z",
  "updatedAt": "2026-07-11T18:01:02.144000Z"
}
```

## 3 Envíalo a firma

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

### Qué haces

Ahora el documento espera firmas. Desde aquí ya no se edita: si algo estaba mal, lo anulas y creas otro.

### Qué mirar

-   `status` = `"awaiting_signatures"`

### En producción

Aquí AllSign le manda la invitación a tu firmante por correo o WhatsApp, y con una key live el envío consume créditos de tu saldo; en sandbox no se cobra nada.

**cURL**

```
curl -X POST 'https://api.allsign.io/v3/documents/doc_fdde14eeff0b4444acec4d6b10736068/send' \
  -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_fdde14eeff0b4444acec4d6b10736068/send', {
    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_fdde14eeff0b4444acec4d6b10736068/send",
    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**

```
{
  "livemode": false,
  "id": "doc_fdde14eeff0b4444acec4d6b10736068",
  "object": "document",
  "name": "Mi primer contrato (sandbox)",
  "status": "awaiting_signatures",
  "documentType": "EDITABLE",
  "signerCount": 1,
  "signedCount": 0,
  "ownerId": "usr_08f394a003014001b429ca03db05b7f7",
  "orgId": "f4d8bad5-5bb0-451c-a917-2ae6b489d38f",
  "folderId": null,
  "expiresAt": null,
  "signingOrder": "parallel",
  "currentStage": null,
  "expirationReminders": null,
  "templateId": null,
  "templateVersionId": null,
  "parentDocumentId": null,
  "createdAt": "2026-07-11T18:01:02.144000Z",
  "updatedAt": "2026-07-11T18:01:05.421000Z"
}
```

## 4 Consulta a tu firmante

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

### Qué haces

Cada firmante tiene su id sgr\_… y su propio status. Con ese id le recuerdas, lo reasignas o, en sandbox, firmas por él.

### Qué mirar

-   `data.0.id` = `"sgr_d64e1ca6bcf64eebac2d35da21d23c88"`
-   `data.0.status` = `"sent"`

**cURL**

```
curl 'https://api.allsign.io/v3/documents/doc_fdde14eeff0b4444acec4d6b10736068/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_fdde14eeff0b4444acec4d6b10736068/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_fdde14eeff0b4444acec4d6b10736068/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_d64e1ca6bcf64eebac2d35da21d23c88",
      "object": "signer",
      "documentId": "doc_fdde14eeff0b4444acec4d6b10736068",
      "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
}
```

## 5 Firma por tu firmante (solo en sandbox)

POST `/sandbox/signers/{signer_id}/sign` [ver en la referencia](https://allsign.io/developers/docs/endpoints/documents#sign-as-a-signer-sandbox-only)

### Qué haces

En sandbox no hay nadie del otro lado: esta operación firma como si tu firmante hubiera abierto su liga, y dispara los mismos eventos que una firma real.

### Qué mirar

-   `status` = `"signed"`
-   `signedAt` = `"2026-07-11T18:01:06.969000Z"`

### En producción

Aquí firma tu cliente: abre la liga del correo o del WhatsApp, revisa el documento y firma. Esta operación solo funciona en sandbox.

**cURL**

```
curl -X POST 'https://api.allsign.io/v3/sandbox/signers/sgr_d64e1ca6bcf64eebac2d35da21d23c88/sign' \
  -H "Authorization: Bearer $ALLSIGN_API_KEY" \
  -H "AllSign-Version: 2026-07-11" \
  -H "Idempotency-Key: $(uuidgen)"
```

**Node**

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

const respuesta = await fetch('https://api.allsign.io/v3/sandbox/signers/sgr_d64e1ca6bcf64eebac2d35da21d23c88/sign', {
    method: 'POST',
    headers: {
        Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,
        'AllSign-Version': '2026-07-11',
        'Idempotency-Key': randomUUID(),
    },
});
console.log(respuesta.status, await respuesta.json());
```

**Python**

```
import os
import uuid

import requests

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

**Respuesta · 200**

```
{
  "livemode": false,
  "id": "sgr_d64e1ca6bcf64eebac2d35da21d23c88",
  "object": "signer",
  "documentId": "doc_fdde14eeff0b4444acec4d6b10736068",
  "email": "signer-pending@sandbox.allsign.io",
  "phone": null,
  "name": "Ana Torres",
  "status": "signed",
  "signedAt": "2026-07-11T18:01:06.969000Z",
  "routingOrder": null,
  "delivery": null
}
```

## 6 Espera el webhook signer.signed

POST `tu endpoint` · evento `signer.signed`

### Qué haces

Llega en cuanto firma cada persona. Verifica la firma de la entrega antes de confiar en su contenido.

AllSign le hace `POST` a la URL que registraste, con el evento `signer.signed`. Responde `2xx` rápido y, antes de confiar en el cuerpo, verifica la firma: `webhook-signature` es un HMAC-SHA256 de `webhook-id.webhook-timestamp.cuerpo` con el secreto del webhook ([Webhooks](https://allsign.io/developers/docs/webhooks)).

Esta entrega llegó de verdad al receptor del test y su firma se verificó con el secreto del webhook.

### Qué mirar

-   `eventType` = `"signer.signed"`
-   `data.documentId` = `"doc_fdde14eeff0b4444acec4d6b10736068"`

**Entrega recibida · Cuerpo**

```
{
  "data": {
    "name": "Mi primer contrato (sandbox)",
    "signer": {
      "name": "Ana Torres",
      "email": "signer-pending@sandbox.allsign.io",
      "phone": null,
      "signedAt": "2026-07-11T18:01:06.969000Z",
      "signerId": "sgr_d64e1ca6bcf64eebac2d35da21d23c88",
      "authMethod": "POR_DEFINIR"
    },
    "documentId": "doc_fdde14eeff0b4444acec4d6b10736068",
    "signedCount": 1,
    "totalSigners": 1
  },
  "eventId": "evt_b65f702e300448f9906987d0e9aa0ec0",
  "livemode": false,
  "tenantId": "d521e797-924d-41c6-be8b-a3dcd62f5b6f",
  "eventType": "signer.signed",
  "apiVersion": "2026-07-11",
  "occurredAt": "2026-07-11T18:01:07.025Z"
}
```

**Entrega recibida · Cabeceras**

```
{
  "content-type": "application/json",
  "allsign-event": "signer.signed",
  "allsign-livemode": "false",
  "webhook-id": "b65f702e-3004-48f9-9069-87d0e9aa0ec0",
  "webhook-timestamp": "1783792867",
  "webhook-signature": "v1,<firma>",
  "allsign-delivery-id": "7553835d-3b51-4c47-a79b-a036813e0d92"
}
```

**Verifica la firma · Node**

```
import { createHmac, timingSafeEqual } from 'node:crypto';

export function verificarWebhook(cuerpoCrudo, headers, secreto) {
    const id = headers['webhook-id'];
    const timestamp = headers['webhook-timestamp'];
    if (!id || !/^\d+$/.test(timestamp ?? '') || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
    const llave = Buffer.from(secreto.replace(/^whsec_/, ''), 'base64');
    const esperada = Buffer.from(createHmac('sha256', llave).update(`${id}.${timestamp}.${cuerpoCrudo}`).digest('base64'));
    return (headers['webhook-signature'] ?? '').split(' ').some((token) => {
        const [version, firma = ''] = token.split(',');
        const candidata = Buffer.from(firma);
        return version === 'v1' && candidata.length === esperada.length && timingSafeEqual(candidata, esperada);
    });
}
```

**Verifica la firma · Python**

```
import base64
import hashlib
import hmac
import time


def verificar_webhook(cuerpo_crudo: bytes, headers: dict, secreto: str) -> bool:
    id_ = headers.get("webhook-id")
    timestamp = headers.get("webhook-timestamp", "")
    if not id_ or not (timestamp.isascii() and timestamp.isdigit()) or abs(time.time() - int(timestamp)) > 300:
        return False
    llave = base64.b64decode(secreto.removeprefix("whsec_"))
    contenido = f"{id_}.{timestamp}.".encode() + cuerpo_crudo
    esperada = base64.b64encode(hmac.new(llave, contenido, hashlib.sha256).digest())
    return any(
        version == "v1" and hmac.compare_digest(firma.encode(), esperada)
        for version, _, firma in (token.partition(",") for token in headers.get("webhook-signature", "").split())
    )
```

## 7 Espera el webhook document.completed

POST `tu endpoint` · evento `document.completed`

### Qué haces

Llega cuando firmó la última persona y la evidencia ya está lista para descargar. Es la señal para guardar el PDF firmado.

AllSign le hace `POST` a la URL que registraste, con el evento `document.completed`. Responde `2xx` rápido y, antes de confiar en el cuerpo, verifica la firma: `webhook-signature` es un HMAC-SHA256 de `webhook-id.webhook-timestamp.cuerpo` con el secreto del webhook ([Webhooks](https://allsign.io/developers/docs/webhooks)).

Esta entrega llegó de verdad al receptor del test y su firma se verificó con el secreto del webhook.

### Qué mirar

-   `eventType` = `"document.completed"`
-   `data.status` = `"completed"`

**Entrega recibida · Cuerpo**

```
{
  "data": {
    "name": "Mi primer contrato (sandbox)",
    "nom151": null,
    "status": "completed",
    "signers": [
      {
        "name": "Ana Torres",
        "email": "signer-pending@sandbox.allsign.io",
        "signedAt": "2026-07-11T18:01:06.969000Z",
        "signerId": "sgr_d64e1ca6bcf64eebac2d35da21d23c88",
        "authMethod": "POR_DEFINIR"
      }
    ],
    "documentId": "doc_fdde14eeff0b4444acec4d6b10736068",
    "completedAt": "2026-07-11T18:01:08.816000Z",
    "evidencePdf": {
      "url": "https://api.allsign.io/v3/documents/doc_fdde14eeff0b4444acec4d6b10736068/evidence",
      "sha256": "ed345419cea24ebbee27d9226b383468c70176e89b2391c5dec89bd4b7df4682",
      "mimeType": "application/pdf",
      "sizeBytes": 81606
    }
  },
  "eventId": "evt_118e25115c1c4b0b859b732e5ca40301",
  "livemode": false,
  "tenantId": "d521e797-924d-41c6-be8b-a3dcd62f5b6f",
  "eventType": "document.completed",
  "apiVersion": "2026-07-11",
  "occurredAt": "2026-07-11T18:01:08.818Z"
}
```

**Entrega recibida · Cabeceras**

```
{
  "content-type": "application/json",
  "allsign-event": "document.completed",
  "allsign-livemode": "false",
  "webhook-id": "118e2511-5c1c-4b0b-859b-732e5ca40301",
  "webhook-timestamp": "1783792869",
  "webhook-signature": "v1,<firma>",
  "allsign-delivery-id": "8510c66d-8d0a-417a-b767-f1d78612b3ec"
}
```

**Verifica la firma · Node**

```
import { createHmac, timingSafeEqual } from 'node:crypto';

export function verificarWebhook(cuerpoCrudo, headers, secreto) {
    const id = headers['webhook-id'];
    const timestamp = headers['webhook-timestamp'];
    if (!id || !/^\d+$/.test(timestamp ?? '') || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
    const llave = Buffer.from(secreto.replace(/^whsec_/, ''), 'base64');
    const esperada = Buffer.from(createHmac('sha256', llave).update(`${id}.${timestamp}.${cuerpoCrudo}`).digest('base64'));
    return (headers['webhook-signature'] ?? '').split(' ').some((token) => {
        const [version, firma = ''] = token.split(',');
        const candidata = Buffer.from(firma);
        return version === 'v1' && candidata.length === esperada.length && timingSafeEqual(candidata, esperada);
    });
}
```

**Verifica la firma · Python**

```
import base64
import hashlib
import hmac
import time


def verificar_webhook(cuerpo_crudo: bytes, headers: dict, secreto: str) -> bool:
    id_ = headers.get("webhook-id")
    timestamp = headers.get("webhook-timestamp", "")
    if not id_ or not (timestamp.isascii() and timestamp.isdigit()) or abs(time.time() - int(timestamp)) > 300:
        return False
    llave = base64.b64decode(secreto.removeprefix("whsec_"))
    contenido = f"{id_}.{timestamp}.".encode() + cuerpo_crudo
    esperada = base64.b64encode(hmac.new(llave, contenido, hashlib.sha256).digest())
    return any(
        version == "v1" and hmac.compare_digest(firma.encode(), esperada)
        for version, _, firma in (token.partition(",") for token in headers.get("webhook-signature", "").split())
    )
```

## 8 Confirma el estado final

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

### Qué haces

Una sola consulta, después del webhook y nunca en un bucle: el documento está completed y todas las firmas cuentan.

### Qué mirar

-   `status` = `"completed"`
-   `signedCount` = `1`

**cURL**

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

**Node**

```
const respuesta = await fetch('https://api.allsign.io/v3/documents/doc_fdde14eeff0b4444acec4d6b10736068', {
    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_fdde14eeff0b4444acec4d6b10736068",
    headers={
        "Authorization": f"Bearer {os.environ['ALLSIGN_API_KEY']}",
        "AllSign-Version": "2026-07-11",
    },
)
print(respuesta.status_code, respuesta.json())
```

**Respuesta · 200**

```
{
  "livemode": false,
  "id": "doc_fdde14eeff0b4444acec4d6b10736068",
  "object": "document",
  "name": "Mi primer contrato (sandbox)",
  "status": "completed",
  "documentType": "EDITABLE",
  "signerCount": 1,
  "signedCount": 1,
  "ownerId": "usr_08f394a003014001b429ca03db05b7f7",
  "orgId": "f4d8bad5-5bb0-451c-a917-2ae6b489d38f",
  "folderId": null,
  "expiresAt": null,
  "signingOrder": "parallel",
  "currentStage": null,
  "expirationReminders": null,
  "templateId": null,
  "templateVersionId": null,
  "parentDocumentId": null,
  "createdAt": "2026-07-11T18:01:02.144000Z",
  "updatedAt": "2026-07-11T18:01:05.421000Z"
}
```

## 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).

`IDEMPOTENCY_KEY_REQUIRED` · 400 · en el paso 2 (Crea el documento con su firmante)

Crear sin Idempotency-Key. [Qué significa y qué hacer](https://allsign.io/developers/docs/errors#IDEMPOTENCY_KEY_REQUIRED)

**Respuesta · 400 · IDEMPOTENCY_KEY_REQUIRED**

```
{
  "type": "https://allsign.io/developers/docs/errors#IDEMPOTENCY_KEY_REQUIRED",
  "title": "Bad Request",
  "status": 400,
  "detail": "POST requests that create or charge require a unique Idempotency-Key (UUID v4).",
  "instance": "/v3/documents",
  "code": "IDEMPOTENCY_KEY_REQUIRED",
  "requestId": "req_48ab6b50c363414c8d0e41850d05d5f5"
}
```

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

`IDEMPOTENCY_KEY_INVALID` · 400 · en el paso 2 (Crea el documento con su firmante)

Crear con una Idempotency-Key que no es UUID v4. [Qué significa y qué hacer](https://allsign.io/developers/docs/errors#IDEMPOTENCY_KEY_INVALID)

**Respuesta · 400 · IDEMPOTENCY_KEY_INVALID**

```
{
  "type": "https://allsign.io/developers/docs/errors#IDEMPOTENCY_KEY_INVALID",
  "title": "Bad Request",
  "status": 400,
  "detail": "Idempotency-Key must be a UUID v4.",
  "instance": "/v3/documents",
  "code": "IDEMPOTENCY_KEY_INVALID",
  "requestId": "req_e289ae908d284f7bbbdfc6abc2178d32"
}
```

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

`DOCUMENT_NOT_FOUND` · 404 · en el paso 8 (Confirma el estado final)

Consultar un documento que no existe o es de otra cuenta. [Qué significa y qué hacer](https://allsign.io/developers/docs/errors#DOCUMENT_NOT_FOUND)

**Respuesta · 404 · DOCUMENT_NOT_FOUND**

```
{
  "type": "https://allsign.io/developers/docs/errors#DOCUMENT_NOT_FOUND",
  "title": "Document not found",
  "status": 404,
  "detail": "No document was found with that id.",
  "instance": "/v3/documents/doc_dd56d81575b84eb790373c6dff92cb95",
  "code": "DOCUMENT_NOT_FOUND",
  "requestId": "req_c72bfc8e0f1f4fc69bcc8111e77dc52d"
}
```

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

`INVALID_STATE_TRANSITION` · 409 · en el paso 5 (Firma por tu firmante (solo en sandbox))

Firmar en sandbox un documento que todavía no envías. [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": "The document has not been sent yet. Send it first with POST /v3/documents/{documentId}/send.",
  "instance": "/v3/sandbox/signers/sgr_592c7816786d4e70bb676a8be0648b5b/sign",
  "code": "INVALID_STATE_TRANSITION",
  "requestId": "req_c1f762446ffa48c2a620e3c8297daa1f",
  "reason": "never_invited"
}
```

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

## Siguiente

-   [Descarga el PDF firmado y su evidencia](https://allsign.io/developers/docs/recetas/descarga-el-pdf-firmado-y-la-evidencia) — El PDF firmado y el PDF de evidencia de un documento completado, con su huella sha256 para archivarlos.
-   [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.
-   [Varios firmantes, uno después de otro](https://allsign.io/developers/docs/recetas/varios-firmantes-en-orden) — Un contrato que firma primero la vendedora y después el comprador, con el comprador sin poder firmar antes de su turno.
