Ir al contenido

Autenticación y scopes ​

La API pública (/api/v1/*) acepta API keys y tokens OAuth2 en la cabecera Authorization: Bearer. Usa una API key para una integración propia entre servidores; usa OAuth2 cuando otra aplicación necesite que un usuario autorice el acceso a su empresa. La BFF (/app/*) se accede con la sesión del navegador por cookie sobre HTTPS: los tokens OAuth2 no autentican la BFF.

API key ​

La API pública se autentica con una API key del tenant, enviada como Bearer token:

Authorization: Bearer bk_live_xxxxxxxxxxxxxxxx
  • bk_live_… → tenant de producción.
  • bk_test_… → tenant de pruebas (remite a los servicios de test de la AEAT). Ver Entorno de pruebas.

Una clave inválida o ausente devuelve 401; una clave sin el scope requerido para la operación devuelve 403.

OAuth2 para aplicaciones externas ​

Las aplicaciones externas pueden conectar mediante authorization code con PKCE S256. Un administrador de Bilteo registra la aplicación en el admin con su nombre, las URL de retorno exactas y los scopes máximos. El client_id es público; no hay client secret. El usuario que autoriza necesita el permiso api_keys.admin en el tenant elegido.

Genera un code_verifier aleatorio (43–128 caracteres), el code_challenge = base64url(SHA256(code_verifier)) sin padding y un state aleatorio de al menos 16 caracteres. Redirige el navegador a la página de la aplicación https://<host-app>/oauth/authorize con response_type=code, client_id, redirect_uri, scope (separados por espacios), state, code_challenge y code_challenge_method=S256. Bilteo muestra el selector de empresa y los permisos para que el usuario acepte o cancele. Puedes enviar tenant_id si ya conoces la empresa; el token siempre queda ligado a una sola empresa. Si el usuario cancela, Bilteo vuelve a redirect_uri con error=access_denied y el state original.

Ejemplo de URL de autorización (codifica cada parámetro de consulta; en scope, los espacios se codifican como %20):

text
https://<host-app>/oauth/authorize?response_type=code&client_id=<uuid>&redirect_uri=https%3A%2F%2Fapp.ejemplo.com%2Fcallback&scope=invoices%3Aread%20partners%3Aread&state=<valor-aleatorio>&code_challenge=<desafio-base64url>&code_challenge_method=S256

Tras aceptar, verifica el state recibido y canjea el code una sola vez antes de cinco minutos:

bash
curl -X POST https://api.test.bilteo.com/oauth/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=authorization_code' \
  --data-urlencode 'client_id=<uuid>' \
  --data-urlencode 'code=<codigo-recibido>' \
  --data-urlencode 'redirect_uri=https://app.ejemplo.com/callback' \
  --data-urlencode 'code_verifier=<verifier-original>'

La respuesta incluye access_token, token_type (Bearer), expires_in (900 segundos), refresh_token y scope.

Usa Authorization: Bearer bo_at_... en /api/v1/*. El access token dura 15 minutos. Renuévalo con POST /oauth/token y los campos grant_type=refresh_token, client_id y refresh_token=bo_rt_.... Guarda el nuevo refresh token: cada uso lo rota y reutilizar uno anterior revoca toda la conexión. El refresh token vence a los 30 días. Para desconectar, envía client_id y token (access o refresh) a POST /oauth/revoke como formulario. La metadata está en /.well-known/oauth-authorization-server.

bash
curl -X POST https://api.test.bilteo.com/oauth/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=refresh_token' \
  --data-urlencode 'client_id=<uuid>' \
  --data-urlencode 'refresh_token=bo_rt_...'

curl -X POST https://api.test.bilteo.com/oauth/revoke \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'client_id=<uuid>' \
  --data-urlencode 'token=bo_rt_...'

OAuth2 y API keys usan exactamente los mismos scopes y endpoints. El token OAuth queda ligado al tenant autorizado: no envíes X-Tenant para cambiarlo. Una petición sin autenticación o con un token vencido devuelve 401; si faltan scopes, 403. Consulta los errores de autenticación.

Identidad de la credencial ​

GET /api/v1/me dice a qué empresa está ligada la credencial. Funciona con API key y con token OAuth y no necesita ningún scope.

json
{
  "tenant": {
    "id": "…",
    "name": "Peluquería Ejemplo SL",
    "issuer_name": "Peluquería Ejemplo SL",
    "issuer_id_num": "B12345678",
    "livemode": true
  },
  "plan_code": "pro",
  "auth": { "type": "oauth", "scopes": ["invoices:read", "invoices:write"] }
}

livemode vale false en el tenant de pruebas. Con OAuth, llámalo justo después de obtener el token. El usuario elige la empresa en Bilteo y la respuesta del token no la incluye.

Scopes ​

Cada API key o conexión OAuth lleva un conjunto de scopes que delimitan qué puede hacer. Concede solo los necesarios (mínimo privilegio). Siguen el patrón recurso:acción; los catálogos de solo lectura únicamente exponen :read.

Esta es la lista completa (21 scopes):

ScopePermite
invoices:readLeer facturas y sus líneas
invoices:writeCrear/editar borradores y sus líneas, y crear rectificativas
invoices:issueEmitir facturas (numerar + remitir a la AEAT)
invoices:cancelAnular facturas emitidas
invoices:replace_simplifiedFlujo de sustitutivas (F2 → F3): crear/emitir la F3 y gestionar sus relaciones replace
invoices:fixSubsanar el registro Veri*Factu de una factura emitida: la reabre (needs_fix) si nunca fue aceptado, o encola la subsanación directamente si lo fue. Se usa junto con invoices:issue
verifactu:readConsultar los registros Veri*Factu y las facturas externas (Verifactu Direct API)
verifactu:writeVerifactu Direct API: registrar / anular / subsanar en Veri*Factu facturas ya emitidas en otro programa (/external-invoices)
partners:readLeer clientes
partners:writeCrear, editar y borrar clientes (incluido por by-external-id)
products:readLeer productos
products:writeCrear, editar y borrar productos (incluido por by-external-id)
series:readLeer series de numeración
series:writeCrear, editar y borrar series
economic_activities:readLeer actividades económicas
economic_activities:writeCrear, editar y borrar actividades económicas
taxes:readLeer el catálogo de impuestos (solo lectura)
fiscal_positions:readLeer el catálogo de posiciones fiscales (solo lectura)
payment_terms:readLeer las condiciones de pago (solo lectura)
usage:readConsultar el plan efectivo, sus límites y el consumo actual (GET /usage)
webhooks:readListar y consultar la configuración de endpoints de webhook (sin el secret)
webhooks:writeCrear, editar y borrar endpoints; regenerar su secret

La fuente de verdad son las rutas

Cada operación de la Referencia de la API declara el scope que exige. Si alguna vez esta tabla y la Referencia no coinciden, manda la Referencia (se genera desde el propio servicio).

Subsanar requiere también emitir

POST /invoices/{id}/actions/request-fix exige invoices:fix y invoices:issue: reabrir solo tiene sentido si la clave también puede re-emitir la subsanación. Ver Subsanación.

Bilteo · Documentación