---
title: "Autenticación — API v3 de AllSign"
type: explanation
canonical_url: "https://allsign.io/developers/docs/authentication"
api_version: "2026-07-11"
---

# Autenticación

La API v3 se autentica con una **API key** enviada como *bearer token*. Cada key trae un conjunto de **scopes** que definen qué recursos y qué acciones puede tocar. Sin key válida obtienes `401`; con key válida pero sin el scope necesario, `403`. Todo error es un documento `application/problem+json`.

## Bearer token

Manda tu key en el header `Authorization` con el esquema `Bearer` en cada petición. Nunca la pongas en la URL ni en el cuerpo, y nunca la expongas en código de cliente.

```
Authorization: Bearer allsign_{env}_sk_...
```

```
curl https://api.allsign.io/v3/documents \
  -H "Authorization: Bearer allsign_test_sk_..."
```

## Prefijos de key

El prefijo de la key te dice, a simple vista, en qué entorno estás operando. El segmento `{env}` es `live` (producción), `test` o `dev` (ambos sandbox — cuál te toca depende de tu panel):

| Prefijo | Entorno | Efecto |
| --- | --- | --- |
| `allsign_test_sk_…` | Sandbox | Cero cobros, cero correos reales. Ideal para desarrollo y CI. |
| `allsign_dev_sk_…` | Sandbox | Igual que `test`: cero cobros, cero correos reales. `AllSign-Environment` reporta `dev`. |
| `allsign_live_sk_…` | Producción | Documentos, cobros y notificaciones reales. |

`sk` = *secret key*: es un secreto de servidor. Trátala como una contraseña, rótala si se filtra, y no la subas al repositorio.

## Scopes por recurso

Los scopes tienen la forma `recurso:acción`. Una key solo puede hacer lo que sus scopes permiten. La taxonomía está **congelada y es append-only**: nunca renombramos ni quitamos un scope; solo agregamos nuevos. Así, un cliente que programa contra un scope no se rompe.

| Scope | Permite |
| --- | --- |
| `document:read` | Listar y leer documentos, firmantes, eventos y evidencia. También gobierna la lectura de **plantillas**, **carpetas** y *signer sets*. |
| `document:write` | Crear, actualizar, enviar y anular (*void*) documentos. También crear, cambiar y borrar plantillas, carpetas y *signer sets*. |
| `document:delete` | Eliminar documentos en lote (*bulk delete*). |
| `signature:read` | Está en la taxonomía, pero hoy ninguna ruta de v3 lo exige: el estado de firma se lee con `document:read`. |
| `analytics:read` | Leer KPIs, embudos y métricas. |
| `user:read` | Leer los miembros del equipo (`GET /v3/users/me` no lo necesita). |
| `embedded:write` | Crear y consultar sesiones de firma embebida (embedded signing). |
| `constancia:read` | Listar y leer constancias NOM-151 independientes. |
| `constancia:write` | Emitir constancias NOM-151 independientes (cobra créditos). |
| `webhook:read` | Listar y leer webhooks. |
| `webhook:write` | Crear y actualizar webhooks (incluye rotar el secreto). |
| `webhook:delete` | Eliminar webhooks. |

Existen **wildcards** para conveniencia:

-   `recurso:*` — todas las acciones sobre un recurso (p.ej. `document:*` = read + write + delete).
-   `*` — acceso total (úsalo con extremo cuidado; prefiere el mínimo privilegio).

## Sin key: 401

Si no mandas key, o la key es inválida o revocada, la API responde `401 AUTHENTICATION_REQUIRED` y agrega el header estándar `WWW-Authenticate: Bearer`. Esto significa "autentícate", no "no tienes permiso".

```
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer
Content-Type: application/problem+json

{
  "type": "https://allsign.io/developers/docs/errors#AUTHENTICATION_REQUIRED",
  "title": "Authentication required",
  "status": 401,
  "code": "AUTHENTICATION_REQUIRED",
  "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_…",
  "requestId": "req_..."
}
```

## Sin scope: 403 con requiredScope

Si tu key es válida pero le falta el scope que el endpoint exige, obtienes `403 PERMISSION_DENIED`. El error te dice **exactamente** qué scope necesitas (`requiredScope`) y cuáles tiene tu key (`yourScopes`), para que corrijas sin adivinar.

```
HTTP/1.1 403 Forbidden
Content-Type: application/problem+json

{
  "type": "https://allsign.io/developers/docs/errors#PERMISSION_DENIED",
  "title": "Permission denied",
  "status": 403,
  "code": "PERMISSION_DENIED",
  "detail": "This API key is missing the 'document:write' scope.",
  "requiredScope": "document:write",
  "yourScopes": ["document:read", "user:read"],
  "requestId": "req_..."
}
```

`GET /v3/users/me` es la excepción: **nunca** responde `403`. Cualquier key autenticada puede leer su propio usuario, sin importar sus scopes — úsalo como *health check* de autenticación.

## OAuth 2.1 (próximamente)

Hoy la única forma de autenticarse es la API key (bearer). **OAuth 2.1** (para apps de terceros que actúan en nombre de un usuario) está en el roadmap pero no está habilitado en producción. Si presentas un token OAuth (con forma de JWT) como bearer en `https://api.allsign.io/v3`, la API responde `501 OAUTH_NOT_IMPLEMENTED`, para que tu integración distinga "todavía no existe" de "salió mal".

El spec declara un esquema `oauth2` con URLs de autorización y de token en `auth.allsign.io`. Ese host todavía no existe: no conectes un cliente generado a esas URLs. Cuando OAuth se habilite, esta sección dirá cómo obtener un token.

```
HTTP/1.1 501 Not Implemented
Content-Type: application/problem+json

{
  "type": "https://allsign.io/developers/docs/errors#OAUTH_NOT_IMPLEMENTED",
  "title": "Not Implemented",
  "status": 501,
  "code": "OAUTH_NOT_IMPLEMENTED",
  "detail": "This credential looks like an OAuth token. AllSign v3 currently accepts API keys only (Authorization: Bearer allsign_live_sk_…). OAuth (Ory Hydra) is a fast-follow; see https://allsign.io/developers/docs/authentication.",
  "requestId": "req_..."
}
```

## Formato de error (problem+json)

Todo error de autenticación (y todo error de la API) es un documento **RFC 9457 `application/problem+json`**. Ramifica tu lógica por el campo `code` (estable, append-only), **nunca** por `detail` (texto en inglés que puede cambiar) ni por el `title`.

| Campo | Qué es |
| --- | --- |
| `type` | URI que ancla al código en la página de [Errores](https://allsign.io/developers/docs/errors). |
| `title` | Resumen humano corto (inglés). |
| `status` | El código HTTP, repetido en el cuerpo. |
| `detail` | Explicación específica de esta instancia (inglés; puede cambiar). |
| `instance` | La ruta que causó el error. |
| `code` | **Tu punto de ramificación**: identificador estable (p.ej. `PERMISSION_DENIED`). |
| `requestId` | El `req_…` para correlacionar con nuestros logs. |
| `errors` | Arreglo de errores a nivel de campo (poblado en validación `422`). |

## Headers en cada respuesta

`AllSign-Request-Id` viaja en **toda** respuesta. Los headers de entorno y *rate limiting* viajan en toda respuesta **autenticada** (incluidos `403` y `429`) — un `401` sin credenciales no los trae:

| Header | Qué te dice |
| --- | --- |
| `AllSign-Request-Id` | El `req_…` de esta petición (igual a `requestId`). Cítalo al reportar problemas. |
| `AllSign-Environment` | `live`, `test` o `dev`: confirma en qué entorno respondió. |
| `RateLimit-Limit` | El tope de tu ventana actual. |
| `RateLimit-Remaining` | Cuántas peticiones te quedan en la ventana. |
| `RateLimit-Reset` | Segundos (delta, no epoch) que faltan para tener cupo seguro. |
| `Retry-After` | Presente en `429`: cuántos segundos esperar antes de reintentar. Solo el `429` del recordatorio a firmante no lo trae (ver [Rate limits](https://allsign.io/developers/docs/rate-limits#el-429)). |
