Saltar al contenido principal

🔌 Introducción y Autenticación

📖 Referencia Completa de Endpoints

Los endpoints son las URL que se utilizan para acceder a los recursos de la API. Cada endpoint es un punto de acceso que devuelve datos o realiza operaciones en el servidor.

📮 Ver Colección Oficial de Postman

🟢
Públicos
Sin autenticación
🔐
Privados
Requieren token
📄
Documentos
CRUD y consultas
🔔
Webhooks
v3.0.0

🎯 Flujo Completo de una Factura Electrónica​

1. AUTENTICACIÓN 2. CONSULTA 3. ENVÍO 4. ESTADO
/auth/login /document-type /invoice /status
↓ ↓ ↓ ↓
[Token] [Tabla DIAN] [Factura JSON] [Validado]
↓ ↓ ↓ ↓
Públicos Públicos Privados Privados

🏷️ Tipos de Endpoints​

TipoAutenticaciónUsoHeaders
🟢 Públicos❌ NoTablas DIAN, autenticaciónNinguno
🔐 Privados✅ SíDocumentos, estado, eventosAuthorization: Bearer {token}
Importante

Los endpoints privados requieren el header Authorization: Bearer {token} en todas las solicitudes.


🔑 Autenticación​

Verifica el correo antes del primer login

Las cuentas principales creadas con POST /register quedan con el correo sin verificar. Hasta abrir el enlace del correo de verificación, POST /auth/login responde HTTP 404 con el mensaje El correo electrónico no ha sido verificado. Comuníquese con el administrador. Si el correo no llegó o el enlace venció, pide uno nuevo con POST /email/verification-notification. Las sub-cuentas que una Casa de Software crea con POST /company/{uuid}/customer ya quedan verificadas.

POST /auth/login — Iniciar Sesión
POST {{url}}/auth/login
Content-Type: application/json
Accept: application/json

Parámetros del Body:

CampoTipoRequeridoDescripción
emailstring✅ SíCorreo electrónico registrado (formato de correo válido)
passwordstring✅ SíContraseña de la cuenta
remember_mebooleanNoOpcional. Se acepta por compatibilidad, pero no cambia la vigencia del token
curl -X POST "{{url}}/auth/login" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"email": "usuario@miempresa.com",
"password": "MiPassword123!"
}'
✅ Respuesta Exitosa (HTTP 200)
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImYyZTFlYjgyZDUyMjEz...",
"token_id": "f2e1eb82d52213a6b1c0d3e4f5a60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f9",
"user": {
"id": 1,
"type_id": 2,
"first_name": "JUAN",
"last_name": "PEREZ",
"email": "usuario@miempresa.com",
"avatar": null,
"active": 1,
"name": "JUAN PEREZ",
"avatarUrl": null,
"user_type": {
"id": 2,
"user_type_name": "DESARROLLADOR",
"type": 2,
"active": 1
}
},
"expires_at": "2026-05-15 20:00:00",
"message": "Bienvenido. Su sesión ha sido iniciada con éxito.",
"success": true
}
  • access_token: el token que se envía en Authorization: Bearer {token}.
  • token_id: identificador del token (el mismo id que aparece en GET /tokens).
  • expires_at: fecha de vencimiento (YYYY-MM-DD HH:MM:SS). Por defecto, 90 días después del login.
  • La respuesta no incluye token_type ni roles: el tipo de usuario está en user.type_id y user.user_type (ver GET /profile/types).
❌ Inicio de Sesión Rechazado (HTTP 404)

Todos los rechazos del login responden HTTP 404 (no 401) con el mismo formato. Se comprueban en el orden de la tabla:

{
"message": "Credenciales inválidas.",
"success": false
}
messageCausa
Credenciales inválidas.El correo o la contraseña no coinciden.
El usuario se encuentra inactivo. Comuníquese con el administrador.El usuario está inactivo.
El correo electrónico no ha sido verificado. Comuníquese con el administrador.Cuenta de POST /register sin verificar, o correo cambiado con PUT /profile/update-email y aún sin verificar. Ver verificación de correo.
No se ha encontrado el perfil de usuario.El usuario no está asociado a ninguna empresa.
No se ha encontrado la empresa asociada al usuario.La empresa del usuario no existe.
La empresa se encuentra inactiva. Comuníquese con el administrador.La empresa está inactiva.
❌ Error de Validación (HTTP 422)

Falta email o password, o el correo no tiene un formato válido. Envía Accept: application/json para recibir el error en JSON (sin esa cabecera, la respuesta es una redirección HTTP 302).

{
"message": "El campo email es obligatorio.",
"errors": {
"email": [
"El campo email es obligatorio."
]
}
}
GET /auth/user — Obtener Usuario Actual
GET {{url}}/auth/user
Authorization: Bearer {token}
Accept: application/json

Devuelve el usuario dueño del token. Es equivalente a GET /profile.

✅ Respuesta Exitosa (HTTP 200)
{
"dataRecords": {
"data": [
{
"id": 1,
"type_id": 2,
"first_name": "JUAN",
"last_name": "PEREZ",
"email": "usuario@miempresa.com",
"avatar": null,
"active": 1,
"name": "JUAN PEREZ",
"avatarUrl": null,
"user_type": {
"id": 2,
"user_type_name": "DESARROLLADOR",
"type": 2,
"active": 1
}
}
]
},
"success": true
}
❌ No Autenticado (HTTP 401)

Sin token, o con un token inválido, vencido o revocado. Este formato solo se recibe si la petición envía Accept: application/json; sin esa cabecera, la respuesta es una redirección (HTTP 302).

{
"message": "Unauthenticated."
}
GET /auth/logout — Cerrar Sesión
GET {{url}}/auth/logout
Authorization: Bearer {token}
Accept: application/json

Revoca el token con el que se hace la petición y cierra la sesión asociada. Los demás tokens del usuario siguen vigentes (para revocarlos, usa POST /tokens/revoke-all).

✅ Respuesta Exitosa (HTTP 200)
{
"message": "Successfully logged out",
"success": true
}
❌ No Autenticado (HTTP 401)

Sin token, o con un token inválido o ya revocado. Requiere Accept: application/json; sin esa cabecera, la respuesta es una redirección (HTTP 302).

{
"message": "Unauthenticated."
}

📧 Verificación de Correo​

🆕 Paso obligatorio para cuentas nuevas

Al registrarse con POST /register, la API envía un correo con un enlace de verificación firmado y con vencimiento. Hay que abrirlo antes de iniciar sesión. Estos endpoints son públicos: no llevan token.

POST /email/verification-notification — Reenviar Correo de Verificación
POST {{url}}/email/verification-notification
Content-Type: application/json
Accept: application/json

Envía de nuevo el correo de verificación. Úsalo cuando el correo no llegó o cuando el enlace venció.

Parámetros del Body:

CampoTipoRequeridoDescripción
emailstring✅ SíCorreo de la cuenta pendiente de verificar
curl -X POST "{{url}}/email/verification-notification" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"email": "usuario@miempresa.com"}'
✅ Correo Enviado (HTTP 200)
{
"message": "Se ha enviado un correo electrónico de verificación"
}
❌ Correo no Registrado (HTTP 404)

También se recibe si no se envía email.

{
"message": "El usuario no existe.",
"success": false
}
❌ Correo ya Verificado (HTTP 400)
{
"message": "El correo electrónico ya fue verificado.",
"success": false
}
GET Enlace de verificación — Confirmar el Correo

El correo contiene un enlace con esta forma. Lo genera la API: no se construye a mano.

GET {{url}}/verify-email/{id}/{hash}?expires={timestamp}&signature={firma}
ResultadoComportamiento
Enlace válidoMarca el correo como verificado, activa el usuario y redirige al portal web, a la pantalla de inicio de sesión. Si el correo ya estaba verificado, también redirige al login.
Enlace vencido o alteradoHTTP 403 (Invalid signature.). Pide un enlace nuevo con POST /email/verification-notification.
Usuario inexistenteHTTP 404.

Se admiten hasta 6 intentos por minuto sobre este enlace.


🔁 Recuperar Contraseña​

Endpoints públicos (sin token) para restablecer la contraseña por correo.

POST /forgot-password — Solicitar Enlace de Restablecimiento
POST {{url}}/forgot-password
Content-Type: application/json
Accept: application/json

Parámetros del Body:

CampoTipoRequeridoDescripción
emailstring✅ SíCorreo de la cuenta (formato válido)

Envía al correo un enlace con el token de restablecimiento. El enlace vence a los 60 minutos.

curl -X POST "{{url}}/forgot-password" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"email": "usuario@miempresa.com"}'
✅ Enlace Enviado (HTTP 200)
{
"success": true,
"message": "¡Recordatorio de contraseña enviado!"
}

El correo contiene el enlace con el token que se usa en POST /reset-password.

❌ No se Pudo Enviar (HTTP 422)

El correo no está registrado o ya se pidió un enlace hace muy poco (en ese caso, Por favor espere antes de volver a intentarlo.). Si falta email o no tiene formato válido, el error es el de validación (El campo email es obligatorio.).

{
"message": "No se ha encontrado un usuario con esa dirección de correo.",
"errors": {
"email": [
"No se ha encontrado un usuario con esa dirección de correo."
]
}
}
POST /reset-password — Restablecer Contraseña
POST {{url}}/reset-password
Content-Type: application/json
Accept: application/json

Parámetros del Body:

CampoTipoRequeridoDescripción
tokenstring✅ SíToken recibido en el enlace del correo
emailstring✅ SíCorreo de la cuenta
passwordstring✅ SíNueva contraseña (mínimo 8 caracteres)
password_confirmationstring✅ SíDebe coincidir con password
curl -X POST "{{url}}/reset-password" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"token": "token-recibido-en-el-correo",
"email": "usuario@miempresa.com",
"password": "NuevaPassword123!",
"password_confirmation": "NuevaPassword123!"
}'
✅ Contraseña Restablecida (HTTP 200)
{
"success": true,
"message": "¡Su contraseña ha sido restablecida!"
}
❌ Token Inválido o Vencido (HTTP 422)

El token no corresponde al correo enviado o ya venció (60 minutos). Si el correo no está registrado, el mensaje es No se ha encontrado un usuario con esa dirección de correo. Los errores de la contraseña (longitud, confirmación) llegan en errors.password.

{
"message": "Este token de restablecimiento de contraseña es inválido.",
"errors": {
"email": [
"Este token de restablecimiento de contraseña es inválido."
]
}
}

🔐 Gestión de Tokens (Personal Access Tokens)​

PAT vs OAuth2 — ¿Cuándo usar cada uno?
PATOAuth2 (login)
Caso de usoIntegraciones servidor-a-servidor, scripts automatizados, ERPApps web con usuarios que inician sesión
CreaciónSelf-service desde la APILogin con email/contraseña
ExpiraciónConfigurable: 1–365 días (por defecto, 90)90 días
RevocaciónSelectiva por IDLogout del token usado
Recomendado para✅ Integraciones B2B✅ Portales web
Parámetro Multi-Tenant: client_uuid

Todos los endpoints de /tokens aceptan ?client_uuid={{client_uuid}}. Una Casa de Software lo usa para gestionar los tokens del usuario de una de sus sub-cuentas (con relación activa). Sin el parámetro, se gestionan los tokens del propio usuario.

GET /tokens — Listar Tokens
GET {{url}}/tokens?client_uuid={{client_uuid}}
Authorization: Bearer {token}
Accept: application/json

Obtiene la lista de los tokens vigentes del usuario (no incluye los revocados ni los vencidos), del más reciente al más antiguo. También aparecen los tokens de las sesiones abiertas con POST /auth/login, con name igual a Login - {correo}.

✅ Respuesta Exitosa (HTTP 200)
{
"dataRecords": {
"data": [
{
"id": "cb6282ed9f5cb116416928518f9dd93b53aafc2c0273722bbe5eb7eb96d7ccfac10178f43b8fe617",
"name": "Token ERP",
"description": "Token de integración para facturación",
"ip_address": "203.0.113.10",
"user_agent": "curl/8.4.0",
"scopes": [],
"revoked": false,
"expires_at": "2026-05-02 12:00:00",
"created_at": "2026-02-01 12:00:00",
"last_used_at": "2026-02-10 08:30:00",
"is_expired": false
}
],
"total": 1
},
"success": true
}
GET /tokens/{token_id} — Obtener Token por ID
GET {{url}}/tokens/{token_id}?client_uuid={{client_uuid}}
Authorization: Bearer {token}
Accept: application/json
ParámetroUbicaciónDescripción
token_idpathID del token (id en GET /tokens, token_id al crearlo)
client_uuidqueryOpcional. UUID de la sub-cuenta (Casa de Software)
✅ Respuesta Exitosa (HTTP 200)
{
"dataRecords": {
"data": {
"id": "cb6282ed9f5cb116416928518f9dd93b53aafc2c0273722bbe5eb7eb96d7ccfac10178f43b8fe617",
"name": "Token ERP",
"description": "Token de integración para facturación",
"ip_address": "203.0.113.10",
"user_agent": "curl/8.4.0",
"scopes": [],
"revoked": false,
"expires_at": "2026-05-02 12:00:00",
"created_at": "2026-02-01 12:00:00",
"last_used_at": "2026-02-10 08:30:00",
"is_expired": false
}
},
"success": true
}
❌ Token no Encontrado (HTTP 404)

El token no existe o ya fue revocado.

{
"success": false,
"message": "Token not found."
}
❌ Token de Otro Usuario (HTTP 403)
{
"success": false,
"message": "Token does not belong to the authenticated user"
}
POST /tokens — Crear Nuevo Token
POST {{url}}/tokens?client_uuid={{client_uuid}}
Authorization: Bearer {token}
Content-Type: application/json
Accept: application/json

Parámetros del Body:

CampoTipoRequeridoDescripción
namestring✅ SíNombre descriptivo (máx. 100). Solo letras sin tilde, números, espacios, guiones (-), guiones bajos (_) y puntos
descriptionstringNoDescripción del uso del token (máx. 500)
expires_in_daysintegerNoDías de vigencia, de 1 a 365. Por defecto, 90
Límite diario

Cada usuario puede crear hasta 10 tokens por día. Al superarlo, la API responde HTTP 429.

curl -X POST "{{url}}/tokens" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"name": "Token Produccion",
"description": "Token para integración ERP",
"expires_in_days": 60
}'
✅ Respuesta Exitosa (HTTP 201)
{
"dataRecords": {
"data": {
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI...",
"token_id": "cb6282ed9f5cb116416928518f9dd93b53aafc2c0273722bbe5eb7eb96d7ccfac10178f43b8fe617",
"name": "Token Produccion",
"description": "Token para integración ERP",
"expires_at": "2026-05-02 12:00:00",
"created_at": "2026-03-03 12:00:00"
}
},
"message": "Token creado exitosamente. Asegúrese de guardar el token, ya que no podrá verlo nuevamente.",
"success": true
}
Guarda el token ahora

El valor dataRecords.data.token solo se muestra una vez al crearlo. No se puede recuperar después.

❌ Límite Diario Alcanzado (HTTP 429)
{
"success": false,
"message": "Límite de creación de tokens alcanzado. Máximo 10 por día.",
"error": "Rate limit exceeded",
"retry_after": 3600
}

retry_after indica los segundos que faltan para poder crear otro token.

❌ Error de Validación (HTTP 422)
{
"message": "The token name may only contain letters, numbers, spaces, hyphens, underscores, and periods.",
"errors": {
"name": [
"The token name may only contain letters, numbers, spaces, hyphens, underscores, and periods."
]
}
}
DELETE /tokens/{token_id} — Revocar Token
DELETE {{url}}/tokens/{token_id}?client_uuid={{client_uuid}}
Authorization: Bearer {token}
Accept: application/json
ParámetroUbicaciónDescripción
token_idpathID del token a revocar
client_uuidqueryOpcional. UUID de la sub-cuenta (Casa de Software)
reasonbodyOpcional. Motivo de la revocación
✅ Respuesta Exitosa (HTTP 200)
{
"message": "Token revoked successfully",
"success": true
}

Revocar un token que ya estaba revocado también responde 200.

❌ Token no Encontrado o de Otro Usuario (HTTP 404 / 403)
{
"success": false,
"message": "Token not found: cb6282ed9f5cb116416928518f9dd93b53aafc2c0273722bbe5eb7eb96d7ccfac10178f43b8fe617"
}

Si el token pertenece a otro usuario, la respuesta es HTTP 403 con Token does not belong to user.

POST /tokens/revoke-all — Revocar Todos los Tokens
POST {{url}}/tokens/revoke-all?client_uuid={{client_uuid}}
Authorization: Bearer {token}
Accept: application/json

Revoca todos tus tokens excepto el que estás usando actualmente.

✅ Respuesta Exitosa (HTTP 200)
{
"dataRecords": {
"data": {
"revoked_count": 0
}
},
"message": "Tokens revoked successfully",
"success": true
}