Endpoints
POST /login

POST /login

Intercambia credenciales de larga duración por un access token JWT de corta duración.

POST /api/v1/fe/login
Content-Type: application/json

Este es el único endpoint que no requiere Authorization header. El body ES la credencial.

Request body

CampoTipoRequeridoDescripción
apiKeyIdstringIdentificador público de la key. Formato fak_ + 12 hex.
apiSecretstringSecret asociado. Bcrypt-verificado en el servidor.
{
  "apiKeyId": "fak_a1b2c3d4e5f6",
  "apiSecret": "abcd1234ef56789012345678..."
}

Response — 200 OK

{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "tokenType": "Bearer",
  "expiresIn": 3600,
  "environment": "ecf",
  "scopes": [
    "invoices:write",
    "invoices:read",
    "usage:read",
    "billing:read"
  ]
}
CampoDescripción
accessTokenEl JWT. Pásalo en Authorization: Bearer <token>.
tokenTypeSiempre "Bearer".
expiresInSegundos hasta que el JWT expire. Default: 3600.
environmentAmbiente DGII de la key (ecf, certecf, testecf).
scopesScopes permitidos por esta key.

Response — 401 Unauthorized

{
  "message": "Invalid credentials",
  "statusCode": 401
}
⚠️

El mensaje es idéntico para todas las causas de fallo (key no existe, secret incorrecto, key revocada, key expirada). Esto es intencional — evita timing oracles. Revisa el panel de Digimart para diagnosticar.

Notas de seguridad

  • El servidor ejecuta una comparación bcrypt incluso cuando la key no existe, usando un hash dummy. Esto mantiene constante el tiempo de respuesta (~200ms) y previene enumeración de keys vía análisis de timing.
  • El apiSecret se guarda en la DB como bcrypt hash (rounds=12). Nunca se almacena en texto plano. Si lo pierdes, no podemos recuperarlo — debes crear una key nueva.
  • El apiKeyId es público y puede aparecer en logs sin riesgo.

Tiempo de respuesta esperado

PercentilLatencia
p50~50ms
p95~250ms (dominado por bcrypt)
p99~500ms

Si ves latencias > 1 segundo de forma consistente, contáctanos.

Rate limit

Throttle de dos capas para frenar brute-force de secrets:

LayerTriggerLockout
Por IP30 intentos / 60s15 min
Por apiKeyId5 intentos / 60s15 min

El JWT dura 1 hora — una llamada por hora por servicio backend es lo normal y queda muy por debajo del threshold. Si recibes 429 Too Many Requests, respeta el header Retry-After y haz backoff exponencial.

🧪

En el panel de la derecha tienes un playground interactivo para probar este endpoint con tus credenciales reales. La llamada se hace desde nuestro Next.js server-side al FE API real — exactamente como haría tu backend.