Factuarea API

Empresas gestionadas

Da de alta, aprovisiona y opera empresas hijas bajo tu tenant maestro — el modelo de gestoría desde la API v1, con cobro per-seat y un ciclo de vida activa/desactivada.

Una empresa gestionada es una subcuenta hija que creas y operas bajo tu propio tenant maestro. Es el modelo de gestoría: una asesoría (la maestra) mantiene un único juego de credenciales y, mediante ellas, da de alta y gestiona muchas empresas clientes, cada una aislada de las demás.

Aprovisionas cada empresa hija y luego la manejas de dos formas: emites una API key hija acotada a ella, o mantienes tu master key y cambias de empresa objetivo por petición con el header X-Active-Profile. Esta página cubre las empresas en sí — crearlas, aprovisionarlas, su ciclo de vida activa/desactivada, el cobro de asientos y el archivado.

Once endpoints bajo /v1/companies gestionan las empresas.

OperaciónEndpointScope
Listar empresasGET /v1/companiescompanies:read
Crear una empresaPOST /v1/companiescompanies:write
Recuperar una empresaGET /v1/companies/{id}companies:read
Actualizar una empresaPATCH /v1/companies/{id}companies:write
Archivar una empresaDELETE /v1/companies/{id}companies:delete
Consultar el estado de creaciónGET /v1/companies/{id}/creation-statuscompanies:read
Verificar (reconciliar) la creaciónPOST /v1/companies/{id}/verify-creationcompanies:write
Desactivar una empresaPOST /v1/companies/{id}/deactivatecompanies:write
Reactivar una empresaPOST /v1/companies/{id}/activatecompanies:write
Activar empresas en bloquePOST /v1/companies/activatecompanies:write
Previsualizar el cobro del asientoGET /v1/companies/seat-charge-previewcompanies:read

{id} es el id de la empresa — un UUID v7 opaco, no su tax_id. Mira los esquemas completos en la Referencia de la API.

Crea una empresa gestionada

POST /v1/companies da de alta una nueva empresa hija bajo tu tenant maestro. name y tax_id son los únicos campos obligatorios; el resto del perfil (razón social, dirección fiscal, datos de contacto) es opcional y se puede enviar en la misma petición. El tax_id (NIF / CIF / NIE) debe ser único entre las empresas que ya gestionas; un duplicado devuelve 409. Requiere el scope companies:write.

curl -X POST https://api.factuarea.com/v1/companies \
  -H "Authorization: Bearer fact_live_8KqW3pXnR2VbY7TcA9eFmN5z" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "name": "Talleres García SL",
    "tax_id": "B12345678"
  }'

Respuesta (201):

{
  "data": {
    "object": "company",
    "id": "01931b3e-7c4a-7f2e-9a8b-4d6e7f8a9b0c",
    "name": "Talleres García SL",
    "business_name": "Talleres García, Sociedad Limitada",
    "tax_id": "B12345678",
    "status": "active",
    "address": "Calle Mayor 1",
    "city": "Madrid",
    "postal_code": "28013",
    "province": "Madrid",
    "country_aeat_zone": "peninsula",
    "email": "contacto@talleresgarcia.es",
    "phone": null,
    "logo_url": null,
    "created_at": "2026-01-15T09:30:00+00:00",
    "updated_at": null
  }
}

Cuerpo de la petición

CampoObligatorioNotas
nameNombre comercial (1–255 caracteres).
tax_idIdentificador fiscal español (NIF / CIF / NIE). Inmutable tras el alta.
business_namenoRazón social, hasta 100 caracteres.
addressnoDirección fiscal.
citynoCiudad de la sede fiscal.
postal_codenoCódigo postal — de él se deriva la zona AEAT (country_aeat_zone en las respuestas).
provincenoProvincia.
countrynoPaís.
emailnoEmail de contacto.
phonenoTeléfono de contacto.

El campo status de la respuesta es el ciclo de vida activa/desactivada de la empresa, un eje distinto del provisioning_status que sigue el aprovisionamiento asíncrono. No hay campo de entrada country_aeat_zone — envías un country de texto libre, y la zona AEAT se deriva del postal_code.

En el alta solo se aplica validación a nivel de formulario. La comprobación censal con la AEAT es un paso de aprovisionamiento aparte — dar de alta una empresa aquí no la verifica contra el censo en la misma petición.

Identificador fiscal duplicado

Reutilizar un tax_id que ya gestionas devuelve 409 con resource_already_exists, y existing_resource_id apunta a la empresa que ya lo tiene:

{
  "error": {
    "type": "invalid_request_error",
    "code": "resource_already_exists",
    "message": "Ya gestionas una empresa con este NIF.",
    "param": "tax_id",
    "existing_resource_id": "01931b3e-7c4a-7f2e-9a8b-4d6e7f8a9b0c"
  }
}

El tax_id es único por tenant maestro, no a nivel global: dos gestorías distintas pueden gestionar cada una una empresa con el mismo identificador fiscal.

Ciclo de vida del aprovisionamiento

Dar de alta una empresa de facturación real no es instantáneo. POST /v1/companies responde al momento, pero detrás la empresa hija se aprovisiona de forma asíncrona: se crean una serie de documentos por defecto y la config fiscal mínima y — en live — se cobra a la gestoría el nuevo asiento. Hasta que eso termina, la hija aún no es operativa. Dos endpoints exponen el ciclo: uno para consultarlo y otro para reconciliarlo.

OperaciónEndpointScope
Consultar el estado de creaciónGET /v1/companies/{id}/creation-statuscompanies:read
Verificar (reconciliar) la creaciónPOST /v1/companies/{id}/verify-creationcompanies:write

Estados de aprovisionamiento

provisioning_status recorre un ciclo de vida pequeño y de un solo sentido:

EstadoSignificado
pendingLa hija se dio de alta; el aprovisionamiento aún no ha empezado.
awaiting_paymentLa gestoría no tiene un método de pago registrado, así que el asiento todavía no se puede cobrar. payment_setup_url apunta a donde el tenant maestro añade uno.
provisioningEl asiento se cobró (o la hija está en modo de prueba) y el tenant se está configurando.
activeEl aprovisionamiento terminó. La hija es plenamente operativa.
failedEl aprovisionamiento no pudo completarse — failed_reason indica el motivo. Vuelve a crear la empresa para reintentarlo.

Con una clave de prueba (fact_test_) no hay llamada a Stripe: la hija pasa directamente a active, de forma determinista. El camino de awaiting_payment y el cobro per-seat solo aplican a las claves live.

Cobro per-seat

En live, cada empresa hija activa es un asiento que se cobra dentro de la suscripción ya existente del tenant maestro — una sola factura recurrente que se lee como "plan + N clientes". Añadir una hija añade un asiento y cobra el prorrateo de inmediato por lo que queda del periodo de facturación; archivar una hija quita el asiento y abona el tiempo no usado en la siguiente factura. La hija no llega a active hasta que ese cobro inmediato tiene éxito; si falla, la hija acaba en failed. Previsualiza el importe de antemano con el preview del asiento.

Como el asiento vive en la propia suscripción del tenant maestro, la hija hereda el plan y los add-ons del maestro, y un impago de la suscripción del maestro suspende la cuenta entera de la gestoría — sus hijas incluidas. No hay una factura separada por hija.

Consulta el estado de creación

GET /v1/companies/{id}/creation-status devuelve el provisioning_status actual y las marcas de tiempo. Consúltalo tras crear una empresa hasta que llegue a active (o failed). Requiere el scope companies:read.

curl https://api.factuarea.com/v1/companies/01931b3e-7c4a-7f2e-9a8b-4d6e7f8a9b0c/creation-status \
  -H "Authorization: Bearer fact_live_8KqW3pXnR2VbY7TcA9eFmN5z"

Respuesta (200):

{
  "data": {
    "object": "company_creation_status",
    "id": "01931b3e-7c4a-7f2e-9a8b-4d6e7f8a9b0c",
    "provisioning_status": "active",
    "payment_setup_url": null,
    "failed_reason": null,
    "started_at": "2026-01-15T09:30:00+00:00",
    "completed_at": "2026-01-15T09:31:00+00:00"
  }
}

payment_setup_url está presente solo mientras awaiting_payment, y failed_reason solo cuando failed; ambos son null en los demás casos.

Verifica la creación

POST /v1/companies/{id}/verify-creation reconcilia una hija contra la suscripción del tenant maestro y la hace avanzar cuando puede. No lleva cuerpo de petición y es idempotente. Requiere el scope companies:write.

curl -X POST \
  https://api.factuarea.com/v1/companies/01931b3e-7c4a-7f2e-9a8b-4d6e7f8a9b0c/verify-creation \
  -H "Authorization: Bearer fact_live_8KqW3pXnR2VbY7TcA9eFmN5z"

Llámalo una vez el tenant maestro haya añadido un método de pago, o cuando quieras sacar a una hija de awaiting_payment:

  • Una hija que ya está active es una operación sin efecto — la llamada se puede repetir sin riesgo.
  • Mientras awaiting_payment, si el maestro ya tiene un método de pago, se cobra el asiento prorrateado y la hija pasa a active.
  • Si el maestro aún no tiene método de pago, la llamada no tiene efecto ni error — la hija permanece en awaiting_payment.

Devuelve el mismo recurso de creation-status que el endpoint de consulta, así que puedes leer el provisioning_status resultante directamente de la respuesta.

El ciclo de vida activa/desactivada

Aparte del aprovisionamiento, cada hija lleva un status — su ciclo de vida del vínculo dentro de la gestoría. Es el campo status del recurso de empresa, y recorre tres estados:

EstadoSignificado
activeLa hija está vinculada y operativa.
inactiveLa hija está desactivada — inaccesible hasta que la reactives (pagando de nuevo su asiento), pero con sus datos intactos y de forma reversible.
archivedLa hija ha sido desvinculada. Es un estado terminal.

Las transiciones son active ↔ inactive (desactivar / reactivar) y active → archived o inactive → archived (archivar). archived es terminal.

Desactivar libera el asiento; reactivar lo cobra de nuevo. Esto permite a una gestoría aparcar un cliente entre encargos sin perder su historial, y recuperarlo más tarde.

Desactiva una empresa

POST /v1/companies/{id}/deactivate pasa una hija active a inactive. La empresa queda inaccesible pero conserva todos sus datos, de forma reversible. No cobra: el abono prorrateado del asiento liberado se aplica best-effort en la siguiente factura. Requiere el scope companies:write.

curl -X POST \
  https://api.factuarea.com/v1/companies/01931b3e-7c4a-7f2e-9a8b-4d6e7f8a9b0c/deactivate \
  -H "Authorization: Bearer fact_live_8KqW3pXnR2VbY7TcA9eFmN5z"

Devuelve el recurso de empresa actualizado con status: "inactive".

Reactiva una empresa

POST /v1/companies/{id}/activate devuelve una hija inactive a active. La reactivación está gateada por un cobro atómico del asiento: primero se cobra el prorrateo, y solo si el cobro tiene éxito la hija pasa a active. Si el maestro no tiene método de pago, o el cobro falla, la empresa sigue inactive. Requiere el scope companies:write.

curl -X POST \
  https://api.factuarea.com/v1/companies/01931b3e-7c4a-7f2e-9a8b-4d6e7f8a9b0c/activate \
  -H "Authorization: Bearer fact_live_8KqW3pXnR2VbY7TcA9eFmN5z"

Devuelve el recurso de empresa actualizado con status: "active".

Activa empresas en bloque

POST /v1/companies/activate reactiva varias hijas en una sola llamada, con un único cobro conjunto — una factura para todo el lote en vez de una por empresa. El cuerpo lleva company_ids, una lista de valores id de empresa hija (1–1000). Requiere el scope companies:write.

curl -X POST https://api.factuarea.com/v1/companies/activate \
  -H "Authorization: Bearer fact_live_8KqW3pXnR2VbY7TcA9eFmN5z" \
  -H "Content-Type: application/json" \
  -d '{
    "company_ids": [
      "01931b3e-7c4a-7f2e-9a8b-4d6e7f8a9b0c",
      "01931b3e-8d5b-7a1f-9c2d-5e6f7a8b9c0d"
    ]
  }'

El cobro es atómico a nivel de lote — o todas o ninguna. La propiedad (404 para una empresa fuera de tu árbol) y la precondición inactive (422) se validan para cada empresa antes de que corra ningún cobro. La respuesta es la lista de empresas reactivadas ({ "data": [ … ] }).

Previsualiza el cobro del asiento

GET /v1/companies/seat-charge-preview devuelve lo que costaría añadir o reactivar empresas hijas, sin cobrar nada. Úsalo para mostrar el prorrateo antes de un POST /v1/companies o de una activación, y para detectar de antemano el caso "sin método de pago". Requiere el scope companies:read.

Tiene dos modos:

  • count (≥1, default 1) — previsualiza el prorrateo conjunto de activar ese número de hijas en un lote.
  • company_ids — una lista de valores id de hijas concretas, para un preview consciente de la cobertura: el importe es 0 con already_covered: true cuando todas siguen cubiertas este periodo, y en caso contrario prorratea solo las no cubiertas. Cuando se envía, manda sobre count.
curl "https://api.factuarea.com/v1/companies/seat-charge-preview?count=1" \
  -H "Authorization: Bearer fact_live_8KqW3pXnR2VbY7TcA9eFmN5z"

Respuesta (200):

{
  "data": {
    "object": "seat_charge_preview",
    "amount": 1240,
    "tax_amount": 260,
    "total": 1500,
    "tax_rate": 21,
    "currency": "EUR",
    "next_invoice_date": "2026-02-01",
    "requires_payment_method": false,
    "requires_active_plan": false,
    "included_in_trial": false,
    "already_covered": false,
    "is_first_seat": false,
    "recurring_quantity": 4,
    "recurring_base_cents": 4000,
    "recurring_total_cents": 4840
  }
}

amount es la base imponible del prorrateo en unidades mínimas de la moneda (céntimos), tax_amount el IVA, y total (amount + tax_amount) lo que se cobra realmente. tax_rate es el porcentaje de IVA derivado (p. ej. 21) o null si Stripe Tax no lo calculó. Los campos recurring_* proyectan la cuota mensual conjunta tras la activación: número total de asientos, base sin IVA y total con IVA (recurring_total_cents es null cuando el IVA no es calculable).

Cuatro flags mutuamente excluyentes explican un importe 0, por orden de prioridad:

FlagEl amount es 0 porque…
already_coveredLas empresas que activarías ya están incluidas en la suscripción de este periodo — reactivarlas es gratis.
requires_active_planLa gestoría no tiene plan vigente y debe contratar uno antes de gestionar empresas.
included_in_trialLa gestoría está en su periodo de prueba — la empresa se crea gratis (los asientos empiezan a cobrarse cuando el trial se convierte en plan de pago).
requires_payment_methodLa gestoría tiene un plan de pago pero ningún método de pago registrado, y debe añadir uno (Billing Portal) primero.

is_first_seat es true cuando la activación crea la primera suscripción de asientos del maestro: el cargo es un mes completo y hoy ancla el día de cobro mensual del ciclo conjunto.

Lista y recupera empresas

GET /v1/companies devuelve tus empresas gestionadas con paginación por cursor; GET /v1/companies/{id} devuelve una. Ambas están acotadas a tu tenant maestro.

curl https://api.factuarea.com/v1/companies?limit=25 \
  -H "Authorization: Bearer fact_live_8KqW3pXnR2VbY7TcA9eFmN5z"

Una empresa gestionada por un tenant maestro distinto devuelve 404, nunca 403 — la API no revela jamás que existe una empresa que no puedes gestionar.

Actualiza una empresa

PATCH /v1/companies/{id} es una actualización parcial. El único campo editable es name — el perfil (razón social, dirección fiscal, contacto, zona AEAT) no es editable aquí, y el tax_id es inmutable y se rechaza si lo incluyes en el cuerpo. Una empresa debe estar active para editarse. Requiere el scope companies:write.

curl -X PATCH \
  https://api.factuarea.com/v1/companies/01931b3e-7c4a-7f2e-9a8b-4d6e7f8a9b0c \
  -H "Authorization: Bearer fact_live_8KqW3pXnR2VbY7TcA9eFmN5z" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Talleres García e Hijos SL" }'

Archiva una empresa

DELETE /v1/companies/{id} archiva la empresa en lugar de borrarla: su status pasa a archived y deja de aceptar operaciones. Una empresa active o inactive se puede archivar; archived es terminal. Requiere el scope companies:delete.

curl -X DELETE \
  https://api.factuarea.com/v1/companies/01931b3e-7c4a-7f2e-9a8b-4d6e7f8a9b0c \
  -H "Authorization: Bearer fact_live_8KqW3pXnR2VbY7TcA9eFmN5z"

El archivado puede quedar bloqueado: si la empresa todavía tiene estado que lo impide (por ejemplo documentos pendientes), la petición devuelve 422 y la empresa conserva su estado actual. Resuelve antes la condición que lo bloquea y luego archívala.

Scopes y aislamiento

Las empresas se protegen con sus propios scopes:

  • companies:read — listar y recuperar empresas gestionadas, consultar el estado de creación y previsualizar el cobro del asiento.
  • companies:write — crear, actualizar, activar y desactivar empresas gestionadas, y verificar su creación.
  • companies:delete — archivar empresas gestionadas.

Toda operación está acotada a tu tenant maestro. Un id de empresa que pertenece a otro maestro devuelve 404 — nunca 403. Este aislamiento entre maestros es la garantía central del modelo de gestoría: un maestro solo ve y actúa sobre sus propias empresas. La misma garantía rige actuar en nombre de una hija y sus API keys.

En esta página