Autenticación
La API pública de FacturaDirecta soporta dos métodos de autenticación, OAuth2 y API key. Cada operación acepta ambos; tú eliges el que mejor encaje con tu integración. Ambos comparten los mismos scopes y operan sobre el mismo conjunto de endpoints.
Endpoint base
Todas las URLs de la API pública en producción tienen el prefijo:
https://app.facturadirecta.com/apiA partir de ahí, los paths que se documentan en cada recurso (por ejemplo
/{companyId}/contacts) se concatenan a esta base.
Recursos auxiliares:
- Referencia OpenAPI navegable (Swagger UI):
https://www.facturadirecta.com/api - Especificación OpenAPI cruda (
openapi.json):https://app.facturadirecta.com/openapi.json
OAuth2
Recomendado cuando un usuario conecta su propia empresa de FacturaDirecta a tu aplicación. Tú obtienes un token en su nombre y operas dentro de su empresa.
FacturaDirecta usa Keycloak como servicio de autorización, con realm
facturadirecta. El flujo es authorizationCode estándar:
- Rediriges al usuario a la URL de autorización con
client_id=facturadirecta-apiy los scopes que necesitas. - El usuario autentica y autoriza los scopes.
- Keycloak redirige a tu callback con un
code. - Intercambias
codeporaccess_token(y opcionalmenterefresh_token) en el endpoint de token. - Usas el
access_tokenen el headerAuthorization: Bearer <token>para cada llamada a la API.
URLs del servicio de autorización en producción:
| Endpoint | URL |
|---|---|
| Autorización | https://auth.facturadirecta.com/auth/realms/facturadirecta/protocol/openid-connect/auth |
| Token | https://auth.facturadirecta.com/auth/realms/facturadirecta/protocol/openid-connect/token |
| Refresh | https://auth.facturadirecta.com/auth/realms/facturadirecta/protocol/openid-connect/token |
La fuente autoritativa es el openapi.json público en
https://app.facturadirecta.com/openapi.json, sección
components.securitySchemes.oAuth.flows.authorizationCode.
client_id para integraciones externas es facturadirecta-api y
no requiere client_secret.
La API pública solo acepta tokens emitidos para clientes OAuth autorizados
por FacturaDirecta. Los clientes gestionados por FacturaDirecta para
integraciones propias, como conectores MCP autorizados y el CLI, pueden usar su
propio client_id. Un token válido del realm no basta si el cliente OAuth que
lo emitió no está autorizado para la API pública.
En esos clientes, el usuario elige además las empresas y los permisos de cada conexión. La autorización efectiva es la intersección entre lo que admite el token, lo concedido a la conexión, el rol actual del usuario y el plan de la empresa. Los cambios de Aplicaciones conectadas se aplican sin repetir el flujo OAuth.
offline_access como scope te permite obtener un refresh_token para
operar sin nueva intervención del usuario.
Cerrar la sesión de la web o de la aplicación móvil no revoca los tokens del MCP, del CLI ni de las integraciones OAuth que el usuario ya ha autorizado. Estas autorizaciones se retiran desde Aplicaciones conectadas o por el mecanismo de revocación de la integración. Los tokens de la propia sesión web o móvil sí dejan de aceptarse al cerrar esa sesión.
Ejemplo de cabecera
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIi...API key
Si tu integración solo necesita acceder a una empresa concreta que tú
administras, puedes generar una API key desde Ajustes > Integraciones
en la propia empresa de FacturaDirecta, o crearla por API desde
POST /apiKeys.
Al crear una API key le asignas los scopes que va a poder usar (los mismos
que están disponibles para OAuth2, salvo offline_access que para una API
key no tiene sentido).
Ejemplo de cabecera
facturadirecta-api-key: aB3cD9.xY7zN2qK4mP8rT5sJ1hF6gL0vW3uEFormato: <prefijo de 6 caracteres>.<sufijo de 32 caracteres>. Es lo que
devuelve POST /apiKeys en el campo apiKey de la respuesta (solo
visible en la creación; tras eso, FacturaDirecta solo conserva el hash).
La API key se envía como header propio, no como Authorization: Bearer.
Versión de la API
Todas las peticiones aceptan el header accept-version con el número de
versión de la API. Si no lo envías, se usa la versión vigente definida por el
servidor. Para producción se recomienda fijarlo explícitamente:
accept-version: 1.0.10El servidor solo aplica versiones que se hayan publicado. Si envías una
versión desconocida o con un formato no válido, aplica la versión vigente. La
cabecera X-Api-Version de la respuesta indica qué versión se ha aplicado.
Scopes
Cada operación de la API declara los scopes que requiere. Los scopes siguen
el patrón <recurso>:<acción>:
<recurso>:read— permite leer (GET).<recurso>:write— permite crear, modificar y borrar (POST,PUT,DELETE).
El conjunto exacto de scopes y su descripción está en el openapi público y en cada página de recurso de esta documentación. Pide siempre los scopes mínimos necesarios para la integración.
Dos scopes se salen del patrón y conviene conocerlos:
banks:readIban— scope adicional que añade el IBAN completo a las consultas de bancos y de métodos de pago. Ver Bancos.files:write— permite subir archivos para adjuntarlos a documentos. Ver Uploads.
Los documentos del Módulo Inventario tienen sus propios scopes:
clientOrders:read y clientOrders:write para
pedidos, y purchaseOrders:read y
purchaseOrders:write para órdenes de compra.
Tener el scope no basta: también se aplican el rol del usuario y el plan de la
empresa. En una aplicación conectada se comprueba además la empresa y el nivel
concedido para el recurso.
Si el plan no incluye los documentos del Módulo Inventario, las escrituras
responden 403. Las operaciones de stock de productos siguen usando
products:read y products:write, y también dependen de que el plan incluya el
control de stock.
Límite de peticiones
Cada empresa tiene un límite de peticiones por minuto que depende de su plan. El límite se cuenta por empresa (no por credencial) en ventanas de un minuto naturales, y solo se aplica al tráfico de integración: llamadas con API key y con clientes OAuth de integración.
| Plan | Peticiones por minuto |
|---|---|
| Gratis | 30 |
| Bronce | 60 |
| Plata | 120 |
| Oro | 300 |
| Diamante | 600 |
Esos son los valores de la familia de planes vigente. Algunas cuentas con planes anteriores o con condiciones particulares tienen otro límite: no lo supongas a partir del plan, léelo de la cabecera de la respuesta.
Cada respuesta incluye estas cabeceras:
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 118
X-RateLimit-Reset: 1789012860X-RateLimit-Limit— peticiones permitidas en la ventana actual.X-RateLimit-Remaining— peticiones que te quedan en esta ventana.X-RateLimit-Reset— timestamp Unix (segundos) en que empieza la ventana siguiente.
Cuando una petición supera el límite, la respuesta añade además
Retry-After con los segundos que faltan para la ventana siguiente. Hoy
esa petición se sigue atendiendo: el exceso queda registrado pero no se
rechaza. Aun así, diseña la integración para respetar el límite —lee
X-RateLimit-Remaining y espacia las llamadas— y para tratar un
429 Too Many Requests con reintento tras Retry-After.
Errores de autenticación
401 Unauthorized— token expirado, ausente, mal formado, emitido por un cliente OAuth no autorizado para la API pública, o API key inválida. Refresca el token (si tienesrefresh_token), revisa elclient_ido regenera la API key.403 Forbidden— la credencial es válida, pero falta un scope, el rol no permite la operación, el plan no incluye la API o la aplicación conectada no tiene concedida esa empresa o ese recurso.403 ForbiddenconmanageUrl— el usuario puede abrir esa página para ampliar la conexión y repetir la llamada sin volver a autorizar la aplicación.403 ForbiddenconcompanyIdajeno — el token no tiene acceso a la empresa indicada en el path. En OAuth, el usuario solo accede a empresas en las que tiene rol y, cuando hay una conexión, a las que haya autorizado. Una API key solo accede a la empresa en la que se creó.
Para el formato general de errores ver Errores y validaciones.
Recomendaciones
- No registres tokens ni API keys en logs, ni siquiera durante desarrollo.
- Limita los scopes al mínimo necesario. Si solo lees contactos, no
pidas
contacts:write. - Una API key por integración. Si una integración deja de usarse, rota la API key antes de borrarla.
- Para multi-tenant SaaS, OAuth2 con
offline_accesses el patrón correcto. API keys son por empresa y no escalan a “una clave para varias empresas”.