Saltearse al contenido

Autenticación y contexto

La API usa HTTP Bearer con la API_KEY de tu ApiAccess.

Authorization: Bearer <API_KEY>
  1. Ingresá al panel de Host Factura con tu usuario administrador.
  2. En Configuración → API, creá un nuevo Access. Ahí mismo elegís los alcances de la credencial (ver más abajo) y, opcionalmente, la asociás a una sucursal específica para que las emisiones queden atribuidas a esa sucursal sin necesidad de header.
  3. Al crearlo se muestra una sola vez la API_KEY. Guardala en un lugar seguro (por ejemplo, un gestor de secretos como 1Password o AWS Secrets Manager).
  4. Si la perdés o sospechás filtración, rotala desde el panel: la anterior se invalida en el acto.
HeaderTipoCuándo
Authorization: Bearer <API_KEY>obligatorioSiempre
x-cuenta-id: <uuid>opcionalSólo credenciales de revendedor: operar sobre una subcuenta de la cartera
x-branch-id: <uuid>opcionalOperar contra una sucursal específica cuando el ApiAccess es global
x-point-id: <uuid>opcionalCuando la sucursal tiene 2+ puntos de emisión activos
Idempotency-Key: <clave>opcionalEn los POST de /v1/pagos (obligatoria en /v1/pagos/cobrar)
X-Request-ID: <uuid>opcionalSi lo enviás se respeta; si no, lo genera el servidor

Cada credencial lleva una lista de alcances y cada operación exige uno o varios. La semántica es OR: alcanza con tener alguno de los que la operación declara.

AlcanceQué habilita
cfe:emitirEmitir y validar CFE, mandar la representación impresa por correo y emitir el comprobante de un cobro (al cobrar o después). Consume numeración
cfe:leerListar CFE emitidos, consultar su estado en DGI y descargar el PDF. No emite nada
recibidos:leerListar y consultar los CFE que la empresa recibió de sus proveedores y descargar su PDF y su XML firmado. Ver CFE recibidos
consultasConsultar un RUT, el padrón de emisores, las cotizaciones del BCU y el echo
clientes:leerListar, buscar y consultar los clientes de la empresa. Sólo lectura
clientes:escribirCrear o actualizar un cliente (upsert). Incluye leerlos
pagos:leerListar y consultar links y cobros, el resumen y el comprobante de pago. Sólo lectura
pagos:cobrarCrear links, cobrar con tarjeta registrada, anular. Mueve plata real. Pedir el comprobante del cobro exige además cfe:emitir
pagos:tarjetasAlta, listado y baja de tarjetas del cliente
pagos:suscripcionesPlanes y suscripciones. Una suscripción activa cobra sola
webhooks:gestionarListar, probar y dar de baja suscripciones de webhook

En la Referencia OpenAPI, cada operación declara los suyos en la extensión x-alcance. El panel muestra, debajo de cada permiso, las operaciones que habilita.

Además de estar en la credencial, el alcance tiene que estar disponible para la empresa dueña de la credencial. El panel sólo ofrece los disponibles:

AlcancesDisponibles si…
cfe:*La empresa emite comprobantes electrónicos
pagos:*La empresa tiene habilitados los cobros con tarjeta
webhooks:gestionarLa cuenta es proveedora (revendedor)
consultas, clientes:*, recibidos:leerSiempre (aunque la empresa no emita)

Una cuenta proveedora admite todos; lo que puede hacer en cada empresa de su cartera lo sigue decidiendo lo que esa empresa tenga habilitado. Si una credencial tiene un alcance que su empresa no admite (por ejemplo, una credencial con acceso total en una empresa que no es proveedora, contra /v1/webhooks), la respuesta es 403 API_ALCANCE_NO_DISPONIBLE, con error.details.alcances y error.details.motivo (PAGOS_NO_HABILITADO, FACTURACION_NO_HABILITADA o SOLO_REVENDEDOR).

Credenciales anteriores al modelo de alcances

Sección titulada «Credenciales anteriores al modelo de alcances»

Una credencial creada antes de que existieran los alcances tiene acceso total y sigue funcionando igual. La restricción es opt-in: hay que editar la credencial en el panel para acotarla, y el panel la muestra como “acceso total (credencial anterior)”.

Una credencial nueva creada sin elegir alcances nace con el preset Solo facturación (cfe:emitir, cfe:leer, consultas): no puede cobrar ni tocar tarjetas hasta que se lo habilites. Tampoco trae recibidos:leer: para leer los comprobantes recibidos hay que marcarlo.

{
"error": {
"code": "API_ALCANCE_INSUFICIENTE",
"message": "La credencial de API no tiene ninguno de los alcances necesarios para esta operación (pagos:cobrar)",
"requerido": ["pagos:cobrar"]
},
"requestId": "3f6b1c2e-9a4d-4f80-bc11-7e2d5a8f0c31"
}

requerido va dentro de error, al lado de code y message. No reintentes: un 403 de alcance no se arregla con el tiempo, hay que editar la credencial.

  • Si tu ApiAccess está fijado a una sucursal, todas las emisiones se atribuyen a esa sucursal. Enviar x-branch-id con otro valor devuelve 403 API_ACCESS_BRANCH_MISMATCH.
  • Si tu ApiAccess es global, podés enviar x-branch-id para apuntar a una sucursal; sin el header se asume la casa central.
  • Si la sucursal resuelta tiene 2 o más puntos de emisión activos, x-point-id es obligatorio. Con uno solo, se selecciona automáticamente.

La sucursal nunca sale del cuerpo: sucursalId y puntoEmisionId en el JSON no tienen efecto.

Si tu cuenta es proveedora (revendedor de facturación electrónica), tu credencial puede operar sobre cualquier subcuenta de tu cartera mandando:

x-cuenta-id: <uuid de la subcuenta>

La cuenta efectiva del request pasa a ser esa: se emite con sus CAE y su certificado, se cobra con su configuración, y el request queda registrado en su log. Sin la cabecera, operás sobre tu propia cuenta.

  • Una subcuenta que no está en tu cartera devuelve 403 API_CUENTA_FUERA_DE_CARTERA — el mismo código exista o no la cuenta.
  • Tu credencial tiene que ser de cuenta (sin sucursal fijada) para poder delegar.
  • Es la única forma de cambiar de cuenta: no hay ningún parámetro ni campo de cuerpo que la elija. Para empresas que no son de tu cartera, usá una API_KEY por empresa.

Todos los POST de /v1/pagos aceptan Idempotency-Key con el mismo contrato. Es opcional en todos salvo POST /v1/pagos/cobrar, que la exige.

SituaciónRespuesta
Sin cabeceraLa operación se ejecuta normalmente; cada llamada es nueva
Misma clave + mismo cuerpoSe replica la respuesta original con meta.reusada: true, sin re-ejecutar
Misma clave + otro cuerpo, u otro endpoint409 PAGOS_IDEMPOTENCY_KEY_CONFLICTO
Misma clave con la operación en curso409 PAGOS_IDEMPOTENCY_EN_CURSO
  • Forma de la clave: 8 a 128 caracteres de A-Za-z0-9._:~-.
  • Ventana: 24 horas.
  • Sólo se cachean las respuestas 2xx. Un 4xx/5xx libera la clave: podés corregir el cuerpo y reintentar con la misma clave sin perder la protección.

Dos interruptores comerciales que habilita administración y que la API no puede cambiar:

GateQué cortaError
Módulo de cobrosTodo /v1/pagos/**, incluida la configuración403 PAGOS_NO_HABILITADO
Facturación electrónicaLa emisión de CFE403 FACTURACION_NO_HABILITADA

Una cuenta sin facturación electrónica puede cobrar pero no emitir: la única política fiscal posible es solo_registrar y el papel que se le entrega al comprador es el comprobante de pago no fiscal.

Éxito:

{ "data": {}, "meta": { "paginacion": { "pagina": 1, "porPagina": 20, "totalFilas": 87, "totalPaginas": 5 } } }

Error:

{
"error": { "code": "CODIGO_ESTABLE", "message": "Mensaje legible en español", "details": {} },
"requestId": "uuid-de-correlación"
}

Usá el campo code (SCREAMING_SNAKE_CASE, estable) para lógica condicional; el message puede cambiar entre versiones. Incluí el requestId en tickets de soporte. La paginación y los filtros van en español: pagina, porPagina, ordenarPor, orden, busqueda.

  • Cuentas estándar: 60 requests/minuto por ApiAccess.
  • Cuentas proveedor: 600 requests/minuto.

Cada respuesta incluye RateLimit-Limit, RateLimit-Remaining y RateLimit-Reset. Al excederlo recibís 429 API_RATE_LIMITED con header Retry-After.

El detalle de todos los códigos de error globales está en la Referencia OpenAPI.