---
title: "Quickstart — API v3 de AllSign"
type: tutorial
canonical_url: "https://allsign.io/developers/docs/quickstart"
api_version: "2026-07-11"
agent_rules: [una-base-url, webhook-no-polling, idempotency-key, error-por-code, reintento-429]
---

# Quickstart: de cero a firma en 5 pasos

Vas a crear tu primer documento, enviarlo a firma y firmarlo en el **sandbox**, sin cobros ni correos reales. Todo corre contra `https://api.allsign.io/v3` con una key de prueba (prefijo `allsign_test_sk_` o `allsign_dev_sk_`, según tu panel): los documentos se crean, los firmantes existen y los webhooks se disparan, pero nada sale al mundo real. La base URL es la **misma** en sandbox y en producción — la key decide el entorno (ver [Entornos](https://allsign.io/developers/docs/environments)). Cuando tu integración funcione aquí, solo cambias la key — el contrato es idéntico.

## Para agentes y asistentes de IA

-   **La base URL es siempre `https://api.allsign.io/v3`; no existe una URL de sandbox aparte.** El prefijo de la key decide el entorno: `allsign_test_sk_` / `allsign_dev_sk_` = sandbox, `allsign_live_sk_` = producción. Para pasar a producción solo cambias la key. → [Entornos](https://allsign.io/developers/docs/environments)
-   **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)
-   **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)

Las respuestas de esta página son las que dio la API en la última corrida de sus tests, en el entorno interno de AllSign con una key de sandbox. La receta [Lleva tu primer documento a firma](https://allsign.io/developers/docs/recetas/primer-documento-a-firma) hace este mismo recorrido paso a paso, en cURL, Node y Python.

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/ejemplos/usuarios.ejemplos.spec.ts`

## Paso 1 · Obtén tu API key de prueba

Entra a tu panel de AllSign, ve a **Developers → API Keys** y genera una key de **entorno de prueba**. Reconócela porque el prefijo **no** es `live`: `allsign_test_sk_` o `allsign_dev_sk_` (según tu panel) — ambas operan en sandbox. Guárdala como secreto (nunca la subas a tu repo ni la pegues en el front); se envía en cada petición como `Authorization: Bearer`.

```
# Guárdala en una variable de entorno, no en el código
export ALLSIGN_API_KEY="allsign_test_sk_tu_key_de_prueba"
```

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_…"`).

La key de sandbox y la de producción son distintas y no son intercambiables: una key de prueba jamás toca datos reales.

## Paso 2 · Verifica tu conexión y registra tu webhook

Antes de crear nada, confirma que tu key es válida con una llamada barata: `GET /v3/users/me`. Devuelve tu usuario y tu tenant. Este endpoint es tu *ping* de autenticación:

-   **200** — la key sirve; ya estás dentro.
-   **401 `AUTHENTICATION_REQUIRED`** — falta la key o está mal escrita.

`/v3/users/me` **nunca** responde `403`: cualquier key autenticada puede leer su propio usuario, sin importar sus scopes. Si ves 403 aquí, es un bug, no un problema de permisos.

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

```
{
  "livemode": false,
  "id": "usr_1fac1e055ae544ac9f9620b42b5ad98d",
  "email": "ana@ejemplo.com",
  "fullName": "Ana Torres",
  "tenantId": "ten_0831aa4e33224c3bbc71f396d736d34c",
  "orgId": "org_8f4afda0323e478985538d5ccee18821",
  "scopes": [
    "document:read",
    "document:write",
    "document:delete",
    "signature:read",
    "webhook:read",
    "webhook:write",
    "webhook:delete",
    "constancia:read",
    "constancia:write",
    "embedded:write",
    "analytics:read",
    "user:read"
  ],
  "environment": "test",
  "authMode": "api_key"
}
```

### Registra tu endpoint de webhooks

Para enterarte de cada firma y del cierre sin consultar en bucle, registra una URL HTTPS pública de tu servidor con `POST /v3/webhooks` y los eventos que quieres recibir. Hazlo antes de enviar el documento: el paso 5 espera los avisos en este endpoint.

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

```
{
  "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_…"
}
```

Guarda el `secret` (`whsec_…`): solo viene en esta respuesta y con él verificas cada entrega.

## Paso 3 · Crea un documento con sus firmantes

Un documento nace en estado `draft`: existe, pero todavía no se envía a nadie. Lo creas con `POST /v3/documents` y, **en la misma petición**, le dices quién firma con `signers[]`: cada firmante lleva `name` y un canal de contacto, `email` **o** `phone` (para invitación por WhatsApp). Los firmantes se adjuntan al crear: la API v3 no tiene una operación para agregarlos después, así que un documento creado sin `signers[]` no se puede enviar.

El documento sale de una de dos fuentes (`source`):

| `source` | Qué mandas | Notas |
| --- | --- | --- |
| `template` | `templateId` + `templateValues` (los valores de las variables) | El más rápido: reusas una plantilla ya diseñada. Si la plantilla define roles, agrega `roleName` a cada firmante para que herede los campos de su rol. |
| `file` | El PDF en `base64` (`content` + `name`) | El archivo pesa **≤ 10 MB**; si lo excedes → `413 DOCUMENT_TOO_LARGE`. |

Desde plantilla (rellenas `templateValues`):

```
curl https://api.allsign.io/v3/documents \
  -H "Authorization: Bearer $ALLSIGN_API_KEY" \
  -H "AllSign-Version: 2026-07-11" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "source": "template",
    "templateId": "tmpl_...",
    "name": "Mi primer contrato (sandbox)",
    "templateValues": { "arrendatario": "Ana Torres", "monto": "12000" },
    "signers": [
      { "name": "Ana Torres", "email": "signer-pending@sandbox.allsign.io" }
    ]
  }'
```

Desde archivo (este comando lee `contrato.pdf` de tu carpeta y lo manda en base64):

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

`signer-pending@sandbox.allsign.io` es un firmante de prueba: no recibe correo y nunca firma solo. En el paso 4 firmas tú por él.

La respuesta trae el documento en borrador:

```
{
  "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"
}
```

**¿Dónde firma cada quien?** Si el documento no trae cajas de firma propias (no mandas `fields[]` y la plantilla no las define), AllSign coloca una caja por firmante al pie de la página 1. En firma simple (sin firma autógrafa en `signatureValidation`) no se pone ninguna, porque no hace falta. Para ponerla en otro lugar, manda `fields[]` con el `email` del firmante y un `anchorString`: un texto que aparece en tu PDF y junto al que va la firma (detalle en [Create document](https://allsign.io/developers/docs/endpoints/documents#create-document)).

Mandar `Idempotency-Key` (un UUID v4) hace este POST seguro de reintentar sin crear duplicados. Es requerido en `POST /v3/documents`. Usa una llave nueva para cada documento: los ejemplos la generan con `$(uuidgen)` en cada corrida (en PowerShell, cámbiala por `$([guid]::NewGuid())`). Ver [Idempotencia](https://allsign.io/developers/docs/idempotency).

## Paso 4 · Envíalo a firma

Con el documento en `draft`, lo envías con `POST /v3/documents/{id}/send`. No hace falta cuerpo: se invita a los firmantes que adjuntaste al crearlo. El documento pasa a `awaiting_signatures` y cada firmante queda invitado.

```
curl -X POST https://api.allsign.io/v3/documents/doc_.../send \
  -H "Authorization: Bearer $ALLSIGN_API_KEY" \
  -H "AllSign-Version: 2026-07-11" \
  -H "Idempotency-Key: $(uuidgen)"
```

```
{
  "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"
}
```

`recipients[]` es opcional y solo sirve para invitar a **algunos** de los firmantes ya adjuntos (por su `email` o su `phone`). No agrega personas: si nombras a alguien que no es firmante del documento, la respuesta es `422 RECIPIENT_NOT_SIGNER` y no se cobra ni se invita a nadie. Repetir `send` en un documento ya enviado no vuelve a cobrar y solo invita a quien no tiene una invitación vigente; para insistirle a quien ya la tiene, usa [Remind signer](https://allsign.io/developers/docs/endpoints/documents#remind-signer).

**¿Por qué ese correo?** En sandbox los correos no salen al mundo real, así que un firmante normal **nunca firma** — y el paso 5 no llegaría jamás. Por eso usas `signer-pending@sandbox.allsign.io`: se queda pendiente, como un firmante real, hasta que firmas por él. El sandbox tiene tres **firmantes mágicos** (estilo Twilio; cuándo conviene cada uno, en [Entornos](https://allsign.io/developers/docs/environments#firmantes-magicos)):

| Dirección | Qué hace |
| --- | --- |
| `signer-pending@sandbox.allsign.io` | No firma solo: espera a que firmes por él. Es el que usa este Quickstart. |
| `signer-success@sandbox.allsign.io` | Firma automáticamente en cuanto recibe la invitación. |
| `signer-declined@sandbox.allsign.io` | Rechaza automáticamente. Dispara el webhook `signer.declined`. |

Solo funcionan en sandbox: en un documento `live` no firman ni rechazan solas. Además, ninguna dirección `@sandbox.allsign.io` recibe correo, en ningún entorno, así que no las uses como firmantes de un documento `live`: su invitación por correo nunca saldría.

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

En sandbox no hay nadie del otro lado, así que firmas tú por tu firmante. Primero consulta su id (`sgr_…`) con `GET /v3/documents/{id}/signers`; la respuesta de crear no lo trae.

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

```
{
  "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
}
```

Luego firma por él con [`POST /v3/sandbox/signers/{signerId}/sign`](https://allsign.io/developers/docs/endpoints/documents#sign-as-a-signer-sandbox-only). Responde en el momento con el firmante ya `signed` y, como es el único, el documento queda `completed` en la misma llamada.

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

```
{
  "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
}
```

Esta operación solo existe en sandbox: con una key live responde `409 ENVIRONMENT_MISMATCH`. En producción firma tu cliente, desde la liga de su invitación.

## Paso 5 · Recibe el webhook de completado

No hagas *polling*. Con la firma del paso 4, AllSign le envía a tu endpoint del paso 2 un `signer.signed` por esa firma y, como era el último firmante, un `document.completed`. El cuerpo es un **sobre (envelope) v3**: el tipo de evento viaja en `eventType` (no `event`), y el PDF de evidencia llega por **URL**, nunca embebido inline en el JSON.

Así llega `signer.signed`:

```
{
  "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"
}
```

Y así `document.completed`:

```
{
  "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"
}
```

Tu endpoint debe responder `2xx` rápido y, en segundo plano, pedir `data.evidencePdf.url` con tu API key. Es `GET /v3/documents/{id}/evidence`:

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

```
{
  "livemode": false,
  "documentId": "doc_c18e3aaf505d4e8aa839591f6d38f7b9",
  "available": true,
  "evidencePdf": {
    "url": "<url-firmada>",
    "sha256": "8a6bf4a711f5204bcce37981400b4a4030d969b33d24e7f2ad78748ca1e68725"
  },
  "nom151": null,
  "reason": null,
  "signedCount": 1,
  "totalSigners": 1
}
```

Responde `available: true` y, en `evidencePdf.url`, un enlace temporal para descargar el PDF con su `sha256`; mientras el documento no termina, `available` es `false` y `reason` dice por qué. Verifica la firma del webhook (Standard Webhooks) antes de confiar en el cuerpo (ver [Webhooks](https://allsign.io/developers/docs/webhooks)).

## Qué sigue

-   [Autenticación](https://allsign.io/developers/docs/authentication) — prefijos de key, scopes por recurso y el contrato de errores 401/403.
-   [Paginación](https://allsign.io/developers/docs/pagination) — cómo recorrer listas con cursores opacos.
-   [Idempotencia](https://allsign.io/developers/docs/idempotency) — qué POST la requieren y cómo reintentar sin duplicar.
-   [Errores](https://allsign.io/developers/docs/errors) — el contrato `problem+json` y el catálogo de códigos.
-   [Endpoints de Documents](https://allsign.io/developers/docs/endpoints/documents) — la referencia completa de cada operación.

Cuando tu flujo pase en sandbox, cambia tu key de prueba por la de producción. La base URL es la misma (`https://api.allsign.io/v3`): la key decide el entorno. El contrato no cambia.
