Uso
El árbol de comandos de factuarea — list, show, create, acciones de dominio, plantillas PDF, escrituras condicionales, descargas binarias, subidas multipart, el escape hatch genérico api y el manifiesto commands --json.
El árbol de comandos cubre todos los recursos de la API
(factuarea <recurso> [<sub-recurso>] <acción>), generado desde la
especificación OpenAPI para que nunca se desincronice de la superficie real.
Leer datos
# Listar (con paginación automática por cursor)
factuarea invoices list --json
factuarea contacts list --paginate --json
# Obtener uno
factuarea invoices show <uuid> --json--json emite el cuerpo crudo de la API por stdout. --paginate recorre
todas las páginas por ti, siguiendo next_cursor hasta que has_more sea
falso. Consulta Paginación para la semántica del cursor
subyacente.
Escribir datos
Pasa el cuerpo JSON con -d (en línea) o --data-file (una ruta). La API
calcula los totales — no los redondees por adelantado.
factuarea invoices create -d '{"client_id":"…","series_id":"…","lines":[…]}'Cada mutación recibe un Idempotency-Key automático para que una petición
reintentada nunca cree el recurso dos veces. Consulta
Idempotencia.
La clave se genera una vez por invocación y se reutiliza en los reintentos que
hace el propio CLI ante respuestas 429 y 5xx, que esperan lo que indica
Retry-After. Para repetir una operación desde una invocación posterior, por
ejemplo cuando tu script vuelve a ejecutarse tras un timeout, fija la clave con
--idempotency-key <clave> y envía el mismo cuerpo. El envío y la cancelación
en FACe (invoices face-submissions submit y face-submissions cancel) hacen
una sola llamada y nunca se reintentan: si uno falla, consulta el envío antes de
volver a enviar.
Acciones de dominio
Los cambios de estado son acciones discretas, no un flag de estado genérico — reflejando el propio diseño de la API:
factuarea invoices send <uuid>
factuarea invoices mark-paid <uuid>Algunas acciones son irreversibles (borrados, void, conversiones,
emisión fiscal). El CLI te pide confirmarlas antes de la llamada — consulta
Operaciones irreversibles y la
guía de scopes e irreversibilidad.
Ejes de empresa y de cuenta
Un recurso cuelga de uno de dos ejes, y el CLI rellena el de su ruta a partir de un flag para que no tengas que escribirlo en cada comando:
| Eje | Ruta | Flag | Comandos |
|---|---|---|---|
| Empresa | /v1/companies/{company}/… | --company | invoices, contacts, time-entries, … |
| Cuenta | /v1/accounts/{account}/… | --account | account (members, invitations, api-keys, nif-transfers, owner, webhooks, request-logs, usage, provisioning-usage), companies, employee-seats, gestoria workforce-summary |
--company rellena el eje de empresa: pasa la empresa como primer argumento
posicional o con el flag, o no la escribas cuando tu credencial alcance una sola
empresa (factuarea invoices list --company acme_co --json). Nunca rellena el
hueco de la cuenta, y --account nunca rellena el de la empresa.
--account rellena el eje de cuenta, con estas reglas:
- Una lectura (
GET) sin cuenta usa la cuenta propia de tu credencial: la queGET /v1/mepublica endata.account.id. Se consulta una vez por invocación y nunca se escribe en disco.whoamino muestra ese id;factuarea account show --jsonsí. - Una escritura nunca deduce la cuenta: nómbrala como argumento posicional o
con
--account. Sin ninguna de las dos, el CLI termina con un error de uso (código2) y no envía nada; el mensaje nombra la cuenta propia de tu credencial y las dos formas de pasarla. Darla como posicional y con el flag también es un error de uso. - Una operación irreversible cuyo último parámetro de ruta es la cuenta
(
account nif-transfers create,account nif-transfers acceptyaccount owner transfer) la toma solo como argumento posicional: ahí el flag no vale. - En
managed-accountsla cuenta es la gestionada: un recurso obligatorio que escribes siempre como argumento posicional y que el flag nunca rellena. - Las rutas raíz de provisión e importación (
GETyPOST /v1/accounts,POST /v1/accounts/imports,POST /v1/accounts/imports/previewyGET /v1/accounts/imports/template) no llevan cuenta, aunque pases--account.
# 1) Una lectura resuelve la cuenta sola
# (GET /v1/me, luego GET /v1/accounts/<tu cuenta>/members)
factuarea account members list --json
# 2) Una escritura debe nombrarla. Sin la cuenta falla con código 2 y no envía
# nada; con --account la petición va a POST /v1/accounts/<account>/webhooks
factuarea account webhooks create --url https://example.com/hooks --enabled-events account.member_added
factuarea account webhooks create --account <account> --url https://example.com/hooks --enabled-events account.member_added
# 3) Una cuenta gestionada es el recurso: siempre el argumento posicional
# (GET /v1/accounts/<managed_account>); --account no la rellena
factuarea managed-accounts show <managed_account> --json
# 4) Una ruta raíz de provisión no lleva cuenta (POST /v1/accounts)
factuarea managed-accounts create --external-ref cliente-0042 --plan emprendedor \
--tax-id B12345674 --legal-name "Talleres García SL" --confirm createfactuarea commands --json publica el argumento omitible en optional_args
({"account": "--account"}, o {"company": "--company"} en el eje de empresa)
en cada comando donde un flag lo rellena; consulta
Agentes y scripting. Los comandos de managed-accounts y los
irreversibles con la cuenta como último parámetro no lo publican.
Cuentas gestionadas
Para quien provisiona cuentas para sus propios clientes. El token de --confirm
es el literal create en las operaciones raíz y el id del recurso en el resto:
factuarea managed-accounts list --json
factuarea managed-accounts show <managed_account>
factuarea managed-accounts plan preview <managed_account> --plan empresario
factuarea managed-accounts plan update <managed_account> --plan empresario --confirm <managed_account>
factuarea managed-accounts access-level update <managed_account> --level view
factuarea managed-accounts claim-tokens create <managed_account> --send-email --confirm <managed_account>
factuarea managed-accounts management end <managed_account> --confirm <managed_account>managed-accounts claim-tokens create reemite el vale de reclamación de una
cuenta gestionada. La cuenta propia ya no tiene vale de reclamación: lo
sustituyó el traspaso de NIF (factuarea account nif-transfers create,
accept, list y revoke).
Webhooks y registros de peticiones de la cuenta
Los endpoints de webhook de la cuenta (account webhooks, con sus entregas en
account webhooks deliveries) y sus registros de peticiones
(account request-logs) usan el eje de cuenta de arriba: una lectura deduce la
cuenta, una escritura la pide. Consulta Webhooks de cuenta
para saber qué recibe un endpoint de cuenta.
factuarea account webhooks list --json
factuarea account webhooks create --account <account> --url https://example.com/hooks \
--enabled-events account.member_added --account-relationship own
factuarea account webhooks deliveries list <webhook> --status failed --json
factuarea account webhooks deliveries retry --account <account> <webhook> <delivery>
factuarea account request-logs list --only_errors true --json
factuarea account request-logs show <request_id> --jsonControl horario (fichajes y ausencias)
El add-on de control horario añade los recursos de jornada — empleados, horarios,
fichajes, ausencias, presencia, festivos, cierres mensuales y el resumen consolidado de
personal de la cuenta (gestoria workforce-summary). Cada comando se genera desde la spec y queda protegido por su scope
fino (employees:*, time_entries:*, absences:*, work_schedules:*,
presence:read, holidays:read, payroll_exports:*).
# Fichar entrada y salida (cada asiento encadena su huella — RD-ley 8/2019)
factuarea time-entries clock-in -d '{"employee_id":"…","source":"web"}'
factuarea time-entries clock-out -d '{"employee_id":"…","source":"web"}'
# Solicitar una ausencia y aprobarla
factuarea absence-requests create \
-d '{"employee_id":"…","absence_type_id":"…","start_date":"2026-08-01","end_date":"2026-08-05"}'
factuarea absence-requests approve <uuid>
# Presencia del equipo en vivo
factuarea presence live --json
# Cerrar el registro mensual inalterable y exportarlo (ITSS RD-ley 8/2019)
factuarea monthly-time-record-closes create -d '{"year":2026,"month":7}'
factuarea monthly-time-record-closes export <uuid> --format rdley_8_2019 --jsonAutomatizaciones
El add-on de automations expone el motor de reglas: una regla escucha un
evento, una condición decide si actuar, y se ejecuta una lista ordenada de
acciones. El módulo protege todo el grupo, y cada comando lleva su scope fino —
automations:read (8 comandos), automations:write (6),
automation_runs:read (3) y automations:delete (1). Cuatro subgrupos espejan
la API: catalog, rules (con rules versions), runs (con runs steps) y
usage. Consulta la guía de automatizaciones para el
modelo.
Empieza por el catálogo. Los campos evaluables de un disparador son una segunda llamada, una por disparador — no viajan dentro del catálogo:
# Qué se puede automatizar: disparadores, operadores y acciones registradas.
factuarea automations catalog show --json
# Los campos evaluables de un disparador concreto.
factuarea automations catalog trigger-fields invoice.paid --jsonEl alta de una regla va por el cuerpo JSON completo. actions es una lista
de objetos, así que no se genera ninguna opción tipada para ella, y el binario se
niega a mezclar opciones de campo con -d/--data-file — elige una. --skeleton
imprime la plantilla del cuerpo sin llamar a la API:
factuarea automations rules create --skeleton{
"actions": [],
"conditions": {
"<key>": "<string>"
},
"description": "<string>",
"name": "<string>",
"scope": "<empresa|cartera>",
"trigger_type": "<string>"
}# Rellénala y mándala entera. El `scope` se elige aquí y luego no se puede cambiar.
factuarea automations rules create --json -d '{
"name": "Warn me on a large payment",
"scope": "empresa",
"trigger_type": "invoice.paid",
"conditions": {"field": "total", "operator": "gte", "value": 1000},
"actions": [
{"type": "notify_in_app", "order": 0, "parameters": {
"recipient_type": "role", "role": "admin", "category": "invoice",
"title": "Large payment", "message": "An invoice over 1000 EUR has been paid"
}}
]
}'
# Ensáyala contra un evento de ejemplo: devuelve la traza por paso y no materializa nada.
factuarea automations rules dry-run <rule_id> --json \
-d '{"event_type":"invoice.paid","event_payload":{"total":1200,"status":"paid"}}'
# Una regla nace en draft y no dispara nada hasta que la actives.
factuarea automations rules activate <rule_id>
factuarea automations rules pause <rule_id>
# Léela y edítala — cada edición sella una versión nueva.
factuarea automations rules show <rule_id> --json
factuarea automations rules update <rule_id> --json -d '{"name":"Warn me on a payment over 2000"}'
# Lístalas con filtros, recorriendo el cursor por ti.
factuarea automations rules list --paginate --json
factuarea automations rules list --status active --trigger_type invoice.paid --json
# Solo las reglas de cartera: las que vigilan los demás NIF de la cuenta.
factuarea automations rules list --scope cartera --json
# Las versiones selladas de la definición.
factuarea automations rules versions list <rule_id> --json
factuarea automations rules versions show <rule_id> 2 --json
# Qué ha disparado, y qué hizo cada paso.
factuarea automations runs list --paginate --json
factuarea automations runs list --automation_rule_id <rule_id> --status failed --json
# Qué hizo una regla de cartera sobre uno de los NIF que vigila.
factuarea automations runs list --subject_company_id <company_id> --json
factuarea automations runs show <run_id> --json
factuarea automations runs steps list <run_id> --json
# Consumo frente al presupuesto del plan para el periodo.
factuarea automations usage show --jsonUna regla de cartera solo la crea la titular de la cuenta, y solo cuando la
cuenta tiene concedido el módulo gestoria. Vigila los demás NIF de la cuenta
(uno adicional, uno traspasado a la cuenta) y los que otra cuenta le cede con el
nivel de acceso operate, nunca el NIF propio de la titular. En ese alcance una
regla solo avisa: notify_in_app, notify_channel, emit_webhook y
create_calendar_event. Se guarda a nombre de la titular, que recibe sus avisos,
y cada ejecución lleva el NIF sujeto sobre el que actuó.
Cuatro listados paginan por cursor —rules list, rules versions list,
runs list y runs steps list— y --paginate recorre todas las páginas por ti.
El historial de versiones es el único cuyo cursor es una cadena numérica
opaca en vez de un UUID, porque pagina por posición; devuelve el next_cursor
que te dieron y no construyas uno a mano.
Tres comandos de este grupo son irreversibles y se niegan a adivinar:
# Relanzar vuelve a ejecutar DE VERDAD el trabajo aparcado: envía correo y entrega webhooks.
factuarea automations runs replay <run_id> --confirm <run_id>
factuarea automations runs steps replay <run_id> 0 --confirm 0
# Borrar una regla la deja sin disparar para siempre; sus versiones y ejecuciones siguen auditables.
factuarea automations rules delete <rule_id> --confirm <rule_id>--confirm toma el último argumento posicional del comando: el id de la
regla en rules delete, el id de la ejecución en runs replay y el índice
del paso en runs steps replay. Sin terminal interactiva (o con
--no-input) y sin --confirm, el comando sale con 2 en vez de adivinar.
Además, toda mutación hecha con una clave fact_live_ necesita el flag
explícito --live — consulta Modo de prueba y
Operaciones irreversibles.
Tareas
El módulo tasks —incluido en todos los planes— añade al árbol 80 comandos en
siete grupos, cada uno protegido por su propio scope fino (projects:read|write|delete,
tasks:read|write|delete, users:read y notifications:read|write), y
projects time-invoices create necesita además invoices:write, porque crea una
factura. Los grupos salen de los operationId del spec:
| Grupo | Qué cubre |
|---|---|
projects | Proyectos, sus columnas (projects columns), campos personalizados, exportación e importación de tareas (projects tasks), el resumen de tiempo y la factura de las horas imputadas |
tasks | Tareas y sus subrecursos: comentarios, adjuntos, imputaciones de tiempo (tasks time-entries), temporizador, etiquetas, relaciones, vínculos con documentos y contactos, actividad |
task-labels | El catálogo de etiquetas de tarea de la empresa |
task-timers | El temporizador en marcha de quien tiene la key |
users | Los miembros de la empresa a los que se puede asignar una tarea |
notifications | Las notificaciones de quien tiene la key |
agenda | La agenda combinada: tareas con vencimiento, vencimientos de documentos, plazos fiscales y ausencias |
# Un proyecto: su clave (una letra más hasta nueve letras o dígitos) prefija las claves de sus tareas (WEB-1, WEB-2…)
factuarea projects list --json
factuarea projects create --name "Web redesign" --key WEB --json
factuarea projects columns list <project_id> --json
# Crear una tarea. Con el cuerpo completo también puedes vincularla a un documento o a un
# contacto en la misma llamada con `entity_link` (invoice, quote, contact, product…).
factuarea tasks create --json -d '{
"project_id": "<project_id>",
"title": "Prepare the quote",
"priority": "high",
"due_on": "2026-10-15",
"entity_link": {"type": "quote", "id": "<quote_id>"}
}'
# Con flags, cada campo personalizado es `<id del campo>=<valor>` y todos los valores viajan como texto.
factuarea tasks create --project-id <project_id> --title "Call the customer" \
--custom-fields <field_id>=42 --custom-fields <other_field_id>=high
# Los comandos piden el UUID; resuelve antes una clave como WEB-1.
factuarea tasks find-by-key WEB-1 --json
# Cambiar su estado: a una columna del proyecto o a un estado virtual (`planned` es el backlog).
factuarea tasks status <task_id> --column-id <column_id>
factuarea tasks status <task_id> --status planned
# Buscar, recorriendo el cursor por ti.
factuarea tasks search --project_id <project_id> --status active --paginate --json
# Las etiquetas de tarea de la empresa.
factuarea task-labels list --json
# Imputar tiempo: un periodo cerrado (ISO 8601 con zona horaria)…
factuarea tasks time-entries list <task_id> --paginate --json
factuarea tasks time-entries create <task_id> \
--started-at 2026-09-28T09:00:00+02:00 --ended-at 2026-09-28T10:30:00+02:00 \
--description "Quote review"
# …o con el temporizador de quien tiene la key, que solo puede tener uno en marcha.
factuarea tasks timer start <task_id>
factuarea task-timers current --json # `{"data": null}` si no hay ninguno en marcha
factuarea task-timers stop --json
# Previsualizar y después crear el borrador de factura de las horas facturables de un mes.
factuarea projects time-invoices preview <project_id> \
-d '{"period":{"from":"2026-09-01","to":"2026-09-30"},"grouping":"per_task"}' --json
# Borrar una columna con tareas exige un destino para ellas. Es irreversible: sin terminal
# interactiva hay que confirmar con --confirm, y lo que se confirma es el ÚLTIMO argumento
# posicional (aquí, la columna borrada).
factuarea projects columns delete <project_id> <column_id> \
--move_to_column_id <other_column_id> --confirm <column_id>Borrar proyectos, columnas, campos personalizados, etiquetas, tareas (también
tasks bulk-delete), comentarios, adjuntos e imputaciones de tiempo es
irreversible y pide confirmación. Consulta la guía de proyectos y tareas
para el modelo.
task-timers no es el fichaje de jornada. El temporizador y los comandos
tasks time-entries registran el tiempo dedicado a una tarea, para medirlo y
facturarlo. No son el registro del módulo de control horario
(factuarea time-entries clock-in, más arriba), que tiene su propio scope y su
propio registro inalterable. Consulta Tiempo imputado a tareas.
Plantillas PDF y presentación de documentos
La biblioteca de plantillas PDF y la presentación de cada documento tienen sus propios comandos, generados desde el spec como el resto del árbol:
| Grupo | Comandos |
|---|---|
pdf-templates | list, create, find, update, duplicate, archive, restore, impact, publish-revision, revision, defaults-get, defaults-set, contact-default-get, contact-default-set, asset-upload, asset-get |
pdf-commercial-identities | list, create, find, update, archive, restore, impact, publish-revision, revision |
pdf-template-previews | create |
pdf-artifacts | prepare, render, show, download |
invoices, quotes, proformas, delivery-notes | get-presentation, assign-presentation, list-presentations, revise-presentation |
series | get-pdf-template, assign-pdf-template |
Todos cuelgan del eje de empresa (/v1/companies/{company}/pdf-templates,
/v1/companies/{company}/pdf-artifacts,
/v1/companies/{company}/invoices/{invoice}/presentation…), así que reciben la
empresa como cualquier otro comando de empresa: como primer argumento
posicional, con --company o sin indicarla cuando tu credencial alcanza una sola
empresa. Consulta Ejes de empresa y de cuenta y
el segmento de empresa. Los binarios anteriores no
tienen estos comandos: comprueba que factuarea commands --json los incluye.
# Create a template in the company library: only --name is required.
factuarea pdf-templates create --company "$COMPANY_ID" \
--name "Factura clásica" --base-preset classic --json
# Template lists paginate by page: one request per call, without --paginate.
factuarea pdf-templates list --company "$COMPANY_ID" --page 1 --per_page 20 --json
# Rename it, with the ETag of the last read as the If-Match precondition.
ETAG=$(factuarea pdf-templates find --company "$COMPANY_ID" "$TEMPLATE_ID" \
--show-etag --json 2>&1 >/dev/null | sed -n 's/^etag: //p')
factuarea pdf-templates update --company "$COMPANY_ID" "$TEMPLATE_ID" \
--name "Factura clásica 2026" --if-match "$ETAG" --json
# Pin that template on an invoice: expected_version is the selection_version
# of get-presentation…
factuarea invoices get-presentation --company "$COMPANY_ID" "$INVOICE_ID" --json
factuarea invoices assign-presentation --company "$COMPANY_ID" "$INVOICE_ID" \
--template-id "$TEMPLATE_ID" --expected-version 1 --json
# …or hand the choice back to the defaults: template_id is required and accepts null.
factuarea invoices assign-presentation --company "$COMPANY_ID" "$INVOICE_ID" \
--null-template-id --expected-version 2 --json
# Exact PDF of the invoice: prepare it from the id of its presentation, render it
# and download it.
factuarea pdf-artifacts prepare --company "$COMPANY_ID" --document-type invoice \
--document-id "$INVOICE_ID" --presentation-id "$PRESENTATION_ID" \
--purpose complete --format a4 --variant official --json
factuarea pdf-artifacts render --company "$COMPANY_ID" "$ARTIFACT_ID" --mode async --json
factuarea pdf-artifacts download --company "$COMPANY_ID" "$ARTIFACT_ID" -o invoice.pdf --show-etagConsulta la biblioteca de plantillas PDF, Presentación de documentos y Vistas previas y artefactos PDF para el modelo.
Escrituras condicionales y null explícito
Cuando el spec declara una cabecera condicional en una operación, su comando
recibe un flag con el mismo nombre: --if-match en las escrituras que la aceptan
(pdf-templates update, defaults-set y contact-default-set,
pdf-commercial-identities update, series assign-pdf-template y
assign-presentation de cada documento) y --if-none-match en las lecturas que
pueden responder 304, como las descargas de PDF. El valor viaja tal cual,
comillas incluidas; un valor vacío es un error de uso (salida 2).
--show-etag, en los comandos cuya respuesta lleva un ETag, escribe
etag: <valor> en stderr y deja stdout intacto, así que puedes capturarlo
junto a --json, como en el ejemplo anterior. El CLI nunca rellena un ETag ni
una versión por ti:
| Envías | Cuando ya no se cumple |
|---|---|
--if-match con un ETag antiguo | 412 |
--expected-version con una versión antigua | 409 |
| Ninguna de las dos, en una escritura que exige precondición | 428 |
Consulta Concurrencia para los códigos de error y cómo recuperarte.
Null explícito. El cuerpo distingue un campo omitido de null, de un valor
vacío, de 0 y de false. Un flag de campo que no pasas no se envía, y un valor
que pasas viaja tal cual, incluso --description "". Para enviar null, usa
--null-<campo>, que solo existe en los campos que admiten null, o escribe null
en -d/--data-file. Pasar --<campo> y --null-<campo> a la vez es un error
de uso.
# Clear the description (null). --name is not passed, so the name is kept.
factuarea pdf-templates update --company "$COMPANY_ID" "$TEMPLATE_ID" \
--null-description --if-match "$ETAG" --jsonUn campo requerido que admite null, como template_id de assign-presentation,
se satisface con su flag --null-<campo> (--null-template-id).
Descargas binarias y subidas
Los endpoints de PDF, ZIP y XML transmiten un binario que guardas con -o. Las
subidas multipart toman el archivo con un flag --file-<campo>:
# Descargar un PDF
factuarea invoices pdf <uuid> -o invoice.pdf
# Subir un certificado (multipart)
factuarea verifactu certificates upload \
-d '{"certificate_password":"…"}' --file-certificate_file cert.p12
# Importar cuentas gestionadas en bloque (multipart). Cada fichero va con --file-<campo>:
# `accounts_file` es obligatorio, `customers_file` opcional. Las opciones viajan en -d
# como un objeto JSON plano cuyas claves son los nombres de campo del formulario: solo
# se aceptan `options[send_email]`, `options[apply_customers_to_own_company]` y
# `options[confirm_plan_changes]` (booleanas, `false` por defecto).
factuarea managed-accounts imports template -o plantilla.csv
factuarea managed-accounts imports preview \
--file-accounts_file cuentas.csv --file-customers_file clientes.csv # no escribe
factuarea managed-accounts imports create \
--file-accounts_file cuentas.csv --file-customers_file clientes.csv \
-d '{"options[send_email]":true}' --confirm create # irreversibleCuando un PDF no está listo o no ha cambiado
Un comando binario escribe los bytes exactos en -o, o en stdout cuando stdout
no es un terminal. Las demás respuestas de una descarga de PDF nunca dejan un
fichero a medias:
| Estado | Qué hace el CLI |
|---|---|
200 | Escribe los bytes. |
202 | El PDF del documento (invoices pdf, quotes pdf, proformas pdf, delivery-notes pdf) aún se está generando. Imprime el JSON de estado en stdout y retry-after: <segundos> en stderr, no crea ningún fichero y sale con 0. Vuelve a lanzar el mismo comando pasado ese tiempo. |
304 | Pasaste --if-none-match con el ETag vigente. Sale con 0 sin nada en stdout y deja tu fichero como estaba. |
503 | pdf-artifacts download de un artefacto que aún no está listo (pdf_artifact_not_ready). El CLI lo reintenta, esperando lo que indica Retry-After; si sigue sin estar listo, el error en stderr incluye el valor de Retry-After. |
# Keep the ETag of the copy you download…
factuarea invoices pdf --company "$COMPANY_ID" "$INVOICE_ID" -o invoice.pdf --show-etag
# …and download it again only if it changed: a 304 leaves invoice.pdf untouched.
factuarea invoices pdf --company "$COMPANY_ID" "$INVOICE_ID" -o invoice.pdf \
--if-none-match "$PDF_ETAG"Un código de salida 0 por sí solo no demuestra que se haya escrito un fichero:
busca la línea retry-after: en stderr, o el propio fichero. Consulta
Cómo responden las descargas.
El escape hatch api
Cualquier endpoint es accesible directamente con factuarea api <método> <ruta>,
incluso los que aún no tienen un comando dedicado:
factuarea api get /v1/me --json
factuarea api post /v1/companies/acme_co/invoices -d '{…}'El manifiesto de comandos
factuarea commands --json vuelca el manifiesto completo de comandos en una
sola llamada — path, args, flags, si cada uno muta, si es binario o paginado, su
scope requerido, si es irreversible, y un ejemplo. Un agente descubre toda la
superficie en una sola llamada:
factuarea commands --jsonConsulta Agentes y scripting para los campos del manifiesto y el contrato JSON.
Referencia de la API embebida
Una referencia rápida de la API viaja con el binario — las búsquedas no salen de tu máquina:
factuarea docs search invoicedocs search consulta la especificación OpenAPI embebida en el binario y
responde a «¿qué comando llamo?». Devuelve operaciones — comando, resumen,
método y ruta — y nunca toca la red.
Buscar en la documentación publicada
docs list, docs grep y docs get consultan la documentación publicada
—el corpus llms-full de docs.factuarea.com— y
responden a «¿qué dice la documentación sobre esto?». Devuelven páginas y
secciones, de las guías, la referencia de la API y el catálogo de errores:
factuarea docs list # todas las páginas: <ruta> — <título>
factuarea docs list /guides # solo las que cuelgan de ese prefijo
factuarea docs grep "idempotency-key" # secciones de documentación que coinciden
factuarea docs get /guides/idempotency # la página entera, en MarkdownEl corpus se descarga entero y una sola vez, se guarda en el directorio de
caché del sistema (~/Library/Caches/factuarea/docs/ en macOS,
~/.cache/factuarea/docs/ en Linux) y se filtra en local. Mientras la copia
tenga menos de 15 minutos, no hay ninguna petición de red, así que una sesión
que encadene list, grep y get descarga una vez.
Tu término de búsqueda nunca sale de la máquina. La URL que se pide es fija
y no depende de lo que teclees — no hay ningún servidor de búsqueda al otro
lado. Ninguno de los cuatro subcomandos de docs lee ni envía una API key.
| Opción | Qué hace |
|---|---|
--refresh | Vuelve a descargar, ignorando una copia todavía vigente |
--lang | Idioma de las guías: en, es o ca (por defecto en, el idioma fuente). La referencia de la API no se traduce y sale siempre |
--json | Salida estable por stdout: path/title en list, path/title/section/snippet en grep, path/title/markdown en get |
Si la descarga falla y hay una copia en caché —aunque esté caducada—, se usa esa
copia, el aviso va a stderr para que el JSON de stdout siga siendo parseable,
y el exit code es 0. Sin ninguna copia, el exit code es 10 (red). Apunta
FACTUAREA_DOCS_URL a otro origen para descargar el corpus desde ahí.
Alternativa REST
El catálogo de comandos del CLI procede de su spec integrado. En la referencia de septiembre de 2026 está disponible la versión v0.2.0 y el spec de la rama principal contiene 414 entradas; faltan 38 endpoints REST en los comandos generados. Consulta factuarea commands --json para tu versión instalada. Usa el comando HTTP genérico para un endpoint REST disponible que falte en ese catálogo:
factuarea api get /v1/companies/acme_co/stores