Factuarea APIDevelopers

Automatitzacions

El model quan, si i fes del motor de regles — versions, l'assaig que no materialitza res, l'historial d'execucions i els seus passos, el rellançament, els límits del motor i les regles de cartera d'un compte.

El motor d'automatitzacions converteix un esdeveniment en feina. Una regla escolta un tipus d'esdeveniment, una condició decideix si aquell esdeveniment concret és el seu cas, i s'executa una llista ordenada d'accions. Tot penja de https://api.factuarea.com/v1/companies/{company}/automations, requereix el mòdul automations del pla i fa servir quatre scopes fins: automations:read, automations:write, automations:delete i automation_runs:read. Consulta Scopes i permisos.

Quan, si i fes

Una regla té exactament tres peces mòbils:

PeçaCampQuè decideix
Quantrigger_typeL'esdeveniment que escolta la regla, en forma resource.action (invoice.paid)
SiconditionsUn arbre de condicions sobre els camps d'aquell esdeveniment. Un {} buit vol dir sense condició: la regla actua sempre
FesactionsLes accions que s'executen quan un esdeveniment coincideix, en l'ordre en què les declaris

Pregunta al catàleg en comptes d'endevinar. GET /v1/companies/{company}/automations/catalog retorna els activadors als quals la teva empresa es pot subscriure —ja filtrats pels mòduls que inclou el teu pla, de manera que un activador governat per un mòdul que no has contractat ni s'ofereix—, més el conjunt tancat d'operadors i combinadors que admet una condició i les accions amb adaptador registrat en aquest desplegament. És determinista: dues crides seguides sense canvis de configuració retornen el mateix cos, així que desa'l a la memòria cau i compara'l.

Els camps avaluables d'un activador són una segona crida. Són fora del catàleg expressament: al voltant d'un centenar d'activadors visibles amb desenes de propietats cadascun donarien un document de centenars de kilobytes per acabar fent servir els camps d'un. Demana GET /v1/companies/{company}/automations/catalog/triggers/{trigger}/fields per a l'activador que hagis triat, i construeix la condició contra els camps que enumeri.

Avui existeixen dotze tipus d'acció: notify_in_app, notify_channel, emit_webhook, create_calendar_event, send_document_email, send_payment_reminder, change_status, tag_entity i, per a tasques, create_task, change_task_status, assign_task i add_task_comment: consulta Tasques i projectes. El catàleg anuncia només els que tenen adaptador cablejat, mai la llista de tipus declarats — triar un tipus sense adaptador produiria una regla el pas de la qual s'omet en executar-se. create_calendar_event està retirada: el calendari al qual alimentava ja no existeix, així que el nom es queda al vocabulari —una versió segellada abans continua llegint-se—, però cap adaptador no l'executa i el seu pas no produeix cap efecte. Fes servir create_task en el seu lloc.

L'enumerat type d'una acció ha crescut. Si la teva integració valida actions[].type contra una llista tancada, afegeix create_task, change_task_status, assign_task i add_task_comment, i continua reconeixent create_calendar_event perquè les versions antigues de les regles continuïn llegint-se.

Una regla neix inactiva. Crear-la segella la versió 1 i la deixa en draft: no escolta res fins que l'actives amb POST /v1/companies/{company}/automations/rules/{rule}/activate. L'activació comprova el límit d'automatitzacions actives del pla. No comprova per endavant el pressupost mensual d'execucions: es comprova en admetre una execució. Llegeix l'endpoint de consum per consultar tots dos comptadors abans d'activar.

curl -X POST https://api.factuarea.com/v1/companies/{company}/automations/rules \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Content-Type: application/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"
        }
      }
    ]
  }'

Tasques i projectes

Les automatitzacions arriben al mòdul de tasques en els dos sentits: els seus esdeveniments posen en marxa regles, i quatre accions creen i canvien tasques. Tots dos necessiten el mòdul tasks.

Activadors

Els 21 esdeveniments de tasques i projectes —task.*, task_comment.*, task_time_entry.* i project.*— són activadors vàlids. Com tot activador governat per un mòdul, existeixen només per a una empresa amb el mòdul tasks: si no, el catàleg no els ofereix i desar una regla que en faci servir un retorna 422. Les condicions llegeixen els camps que publica cada esdeveniment —en una tasca, entre d'altres, el seu estat, columna, prioritat, projecte, persona assignada, data de venciment i data de completat; consulta'ls amb GET /v1/companies/{company}/automations/catalog/triggers/{trigger}/fields— i l'execució congela com a payload el data.object de l'esdeveniment.

Accions

AccióQuè faParàmetres
create_taskCrea una tascaproject_id (obligatori: un projecte actiu de la teva empresa), title (obligatori, fins a 500 caràcters), description (Markdown), priority, assignee_mode (user, role o trigger_actor) amb assignee_user_id o assignee_role (owner, admin o member), label_ids, la data de venciment i link_to_trigger
change_task_statusMou la tasca de l'activadortarget: l'id d'una columna del projecte de la tasca, o planned o archived
assign_taskAssigna la tasca de l'activadorassignee_user_id: un membre de la teva empresa
add_task_commentComenta la tasca de l'activadorbody: Markdown, d'1 a 10.000 caràcters
{
  "name": "Follow up approved quotes",
  "scope": "empresa",
  "trigger_type": "quote.approved",
  "conditions": {},
  "actions": [
    {
      "type": "create_task",
      "order": 0,
      "parameters": {
        "project_id": "0193a4f2-7c20-7a11-8b52-4d6e8f0a2c01",
        "title": "Prepare the delivery of the approved quote",
        "priority": "high",
        "assignee_mode": "role",
        "assignee_role": "admin",
        "link_to_trigger": true
      }
    }
  ]
}
  • La tasca de l'activador. Les tres últimes accions hi actuen: la pròpia tasca als esdeveniments task.*, i la tasca a la qual pertany un comentari o una imputació de temps als esdeveniments task_comment.* i task_time_entry.*. Amb qualsevol altre activador, o si la tasca ja no existeix, el pas es descarta amb task_target_not_found.
  • Data de venciment de create_task. Envia due_on (una data explícita) o due_from_payload_path amb due_offset_days (un camp de data del payload congelat més un nombre de dies), mai les dues. Un camp que falta o que no és una data fa fallar el pas amb un missatge que el nomena: no s'inventa cap data. Sense cap de les dues, la tasca no té data de venciment.
  • link_to_trigger vincula la tasca nova amb l'entitat que ha disparat la regla —una factura, un pressupost, un contacte…—, de manera que apareix entre les tasques vinculades d'aquesta entitat. Si l'activador no té una entitat vinculable, la tasca es crea sense vincle i la traça del pas ho indica.
  • Persona assignada. assignee_mode: "trigger_actor" assigna l'usuari que ha causat l'esdeveniment, i deixa la tasca sense assignar quan l'esdeveniment no identifica cap membre. role tria el primer usuari de l'empresa amb aquest rol, en un ordre determinista. Un usuari que no és membre de l'empresa fa fallar el pas i no crea res.
  • Els comentaris d'una automatització no tenen un usuari com a autoria (el seu author.type és automation); ningú els pot editar i un admin els pot esborrar.
  • Les referències es comproven contra la teva empresa —el projecte, la persona assignada, les etiquetes i un target que sigui una columna— en desar la regla (422, amb el mateix missatge tant si la referència és d'una altra empresa com si no existeix) i de nou en executar-la.
  • Passos descartats. Un create_task el projecte del qual es va arxivar després de desar la regla es descarta amb task_project_not_found i es pot rellançar quan el desarxivis; una empresa que ha perdut el mòdul tasks rep module_not_accessible, rellançable quan el mòdul torni.
  • Els bucles es tallen. Una regla task.created → create_task arriba al límit de profunditat de cadena com qualsevol altra cadena.
  • L'assaig valida paràmetres, referències, subjecte i mòdul exactament igual que una execució real, i no crea cap tasca ni cap comentari.

Cada edició segella una versió

Editar una regla mai reescriu la seva definició anterior. Segella una versió nova i puja current_version, i cada execució conserva un punter a la versió exacta que va executar, així que una execució de fa setmanes es continua llegint després que la regla hagi avançat.

  • PATCH /v1/companies/{company}/automations/rules/{rule} actualitza de manera parcial: els camps que ometis conserven el seu valor, i "" a description el buida. L'estat queda intacte — editar una regla activa la deixa activa, executant la versió nova des del seu esdeveniment següent.
  • Pausar i activar no toquen la definició, així que no segellen cap versió.
  • GET /v1/companies/{company}/automations/rules/{rule}/versions llista les versions segellades i .../versions/{version} en retorna una, amb l'arbre de condicions i les accions congelats tal com eren.

El rule_version d'una execució apunta exactament a aquell número. Pot quedar per darrere de current_version, i aquesta és la gràcia.

L'assaig no materialitza res

POST /v1/companies/{company}/automations/rules/{rule}/dry-run respon què faria una regla davant d'un esdeveniment d'exemple. No executa res: no surt cap correu, no es crea cap entrega de webhook, no es muta cap entitat, no s'escriu cap fila d'execució ni de pas, i no consumeix ni el pressupost mensual ni el límit de freqüència del motor. Per això demana l'scope de lectura tot i ser un POST — l'esdeveniment d'exemple ha de viatjar al cos.

La resposta porta matched, una entrada de condition_trace per cada fulla avaluada en ordre d'avaluació, i una entrada de steps per acció amb allò que resoldria. Una condició que no es pot avaluar torna com a condition_error amb un 200, no com una fallada HTTP: veure per què una regla no es pot avaluar abans d'activar-la és justament per a això que serveix l'assaig.

Si la regla actua sobre documents — enviar un document per correu, enviar un recordatori de cobrament, canviar un estat, etiquetar una entitat — passa event_aggregate_id amb l'id d'un document real teu. Sense ell, l'assaig informa que no s'executaria cap pas, i una regla perfectament correcta sembla trencada.

curl -X POST https://api.factuarea.com/v1/companies/{company}/automations/rules/{rule}/dry-run \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "invoice.paid",
    "event_payload": { "total": 1200, "status": "paid" }
  }'

Execucions i els seus passos

Cada esdeveniment admès produeix una execució, i cada acció de la definició congelada produeix un pas. Una execució porta la definició que va executar (rule_version + rule_snapshot) i el payload de l'esdeveniment que la va disparar (event_payload), tots dos congelats en el moment d'executar.

Estat de l'execucióQuè vol dir
pendingEn cua, sense començar
runningEn curs
completedTots els passos van aplicar el seu efecte
failedVa acabar sense produir el seu efecte, i no es pot reprocessar
dead_letteredAparcada, a l'espera d'un rellançament manual
blockedAturada per un límit del motor abans d'executar-se

Els passos tornen sempre en ordre d'execució, perquè step_index —començant per zero— és la identitat del pas: és allò que es rellança i allò que l'esdeveniment automation_run.step_dead_lettered publica com a data.step_index. Cada pas porta el seu action_type, els seus parameters congelats, el result que va tornar el seu adaptador i una marca replayable.

Dos eixos ortogonals expliquen un desenllaç. discard_reason és el motiu de descart classificat, d'un catàleg tancat —condition_not_matched, chain_depth_exceeded, rate_limit_exceeded, monthly_budget_exhausted, step_attempts_exhausted…—, així que ramifica segons ell. last_error és el missatge tècnic cru, pensat per depurar. discard_reason_label és l'etiqueta humana del motiu i va sempre en castellà: pertany al vocabulari del motor i no segueix Accept-Language.

Llegeix l'historial amb GET /v1/companies/{company}/automations/runs —filtra per automation_rule_id, status o una finestra created[…]—, GET /v1/companies/{company}/automations/runs/{run} i GET /v1/companies/{company}/automations/runs/{run}/steps. Tots tres paginen per cursor; consulta Paginació.

Rellançar torna a executar la feina de debò

Dues operacions rearmen feina aparcada: POST /v1/companies/{company}/automations/runs/{run}/replay rearma tots els passos aparcats d'una execució, i POST /v1/companies/{company}/automations/runs/{run}/steps/{step_index}/replay en rearma un de sol, deixant els seus germans amb el seu estat, el seu motiu i les seves marques de temps intactes.

Els passos rearmats s'executen de debò: envien correu, entreguen webhooks i criden tercers. Això no és un reintent inert — confirma-ho amb el titular del compte abans de cridar-ho.

  • Només es rearmen els passos aparcats amb un motiu rellançable. Una execució encara en curs, o una que va acabar netament, es rebutja amb un 422 automation_replay_not_allowed.
  • La resposta és un 202 —acceptat i encuat, no acabat— i el seu cos porta només identificadors, deliberadament sense status, perquè «encuat» no és cap dels estats de l'execució. Comprova el desenllaç amb l'execució, o més barat amb els seus passos.
  • Cridar-ho dues vegades no duplica l'efecte: el motor revisa de nou l'estat de cada pas dins del seu propi bloqueig.
  • step_index és l'índex que publica l'endpoint de passos, no la posició de l'acció a la definició de la regla. Un índex fora de rang retorna un 404, igual que una execució que no és teva.

Els límits del motor

El pla acota quantes regles pots activar. Per separat, quatre límits acoten les execucions: una execució aturada per un d'ells queda registrada com a blocked amb el seu motiu tipat — bloquejada no és fallida, i llegir el motiu les distingeix. El rebuig pel límit d'actives no crea una execució.

LímitQuè acotaMotiu i codi d'error
Automatitzacions activesRegles actives i no eliminades de la teva empresa; es comprova en activar o reprendreActivació rebutjada · 402 automation_active_rules_limit_exceeded
Profunditat d'encadenamentSalts «acció → esdeveniment → regla», tres per defectechain_depth_exceeded · 422 automation_chain_depth_exceeded
Límit de freqüènciaExecucions admeses per minut i empresa. Un fre de pic, no de volumrate_limit_exceeded · 429 automation_rate_limit_exceeded
Pressupost mensualExecucions que permet el pla per períodemonthly_budget_exhausted · 402 automation_monthly_budget_exhausted
Fallades consecutivesUna ratxa d'execucions fallides pausa la regla solaEsdeveniment automation_rule.auto_paused amb consecutive_failures

Un esdeveniment que produeix una persona o una integració entra amb profunditat zero, així que només consumeix el pressupost d'encadenament allò que va provocar una automatització. Una regla que reacciona a automation_run.failed i torna a fallar no pot, per tant, repetir-se sense fi.

GET /v1/companies/{company}/automations/usage és on veus com vas davant del pressupost mensual: consumed, limit (null vol dir sense sostre automàtic, mai «desconegut» — tracta'l com que no hi ha barra de progrés, no com a zero), reset_at ja resolt, el period en format YYYY-MM i el threshold_percent a partir del qual la plataforma avisa el titular del compte. Aquell percentatge viatja perquè el teu avís i el nostre no es desalineïn.

La mateixa resposta també inclou active_rules: {count, limit}: count és el nombre de regles actives i no eliminades de l'empresa; els esborranys i les pausades no compten. limit és el límit del pla, inclòs zero quan no es permet activar, o null quan no hi ha un sostre automàtic. La capacitat d'Enterprise s'acorda segons contracte. La resposta pública v1 i MCP get_automation_usage exposen el mateix parell, sense limit_mode.

Fragment de la resposta:

{
  "data": {
    "active_rules": { "count": 7, "limit": 7 }
  }
}

Quan count >= limit amb un límit fix, activar o reprendre una regla es rebutja amb automation_active_rules_limit_exceeded: v1 retorna 402 amb error.type: payment_required_error i error.details: {active_rules, limit}. Pausa una regla activa amb POST /v1/companies/{company}/automations/rules/{rule}/pause o amplia el pla abans de tornar-ho a intentar. MCP activate_automation_rule retorna JSON-RPC -32008, amb el mateix codi a data.code, data.http_status: 402 i el mateix parell a data.details; l'app respon HTTP 422 amb el mateix codi.

Les regles ja actives per sobre del límit es continuen executant i es poden editar o pausar. Aquest límit no les pausa automàticament; només impedeix noves activacions. Pausar allibera una plaça d'actives, i reprendre torna a comprovar el límit. El pressupost mensual d'execucions continua separat i es comprova en executar.

Un pas concret també té límit d'intents. Quan s'exhaureix, el pas queda aparcat com a dead_lettered amb step_attempts_exhausted i espera un rellançament — és l'únic estat que admet reentrada.

Regles de cartera

Una regla declara quins NIF vigila al seu camp opcional scope: empresa —el valor que pren si l'omets— vigila els esdeveniments de l'empresa que la posseeix, i cartera vigila els esdeveniments de la cartera del compte que la posseeix, i n'entrega l'avís a aquella empresa, el NIF titular del compte. Es van dissenyar per a les gestories, que són comptes com qualsevol altre.

L'abast és immutable. El tries en crear la regla, i per canviar-lo crees una altra regla. Una edició que enviï un valor diferent es rebutja amb automation_rule_scope_immutable: envia l'abast que la regla ja té, o omet el camp.

Què vigila una regla de cartera. Els altres NIF reals del compte, més els NIF que un altre compte posa al seu abast per una relació vigent amb nivell operate, un accés cedit o un compte gestionat. Una relació amb nivell view, o una que es va revocar o ha acabat, no aporta res. La regla mai no vigila l'empresa que la posseeix: si vols la mateixa automatització per a aquella empresa, crea-la amb abast empresa.

L'univers no és una llista desada. Es calcula a partir de cada esdeveniment i es torna a comprovar a cada pas: en triar les regles candidates d'un esdeveniment, abans d'escriure l'execució, dins de cada pas abans que s'executi la seva acció, i quan rellances una execució o un pas. Un NIF que s'ha arxivat, desactivat o traspassat a un altre compte, o la relació del qual es va revocar, va acabar o va baixar a view, no passa la comprovació: no s'escriu cap execució per a ell o, si l'execució ja existeix, el pas s'atura com a blocked amb el motiu tenant_mismatch i la seva acció no s'executa mai. Rellançar no l'esquiva.

Qui pot crear una regla de cartera. Només l'empresa titular d'un compte que tingui concedit el mòdul gestoria, per pla (empresario i enterprise) o per un override d'empresa. El primer que es pregunta és si l'empresa és la titular del seu compte: un NIF addicional —un que el compte va comprar, va rebre per traspàs o va donar d'alta— mai no té cartera pròpia, encara que se li hagi concedit el mòdul, perquè la cartera és del compte i la representa el seu titular. No necessites un segon NIF per escriure la regla; mentre el compte no en tingui, simplement no es dispara.

El catàleg retorna sempre els dos abasts, cadascun amb available i, quan no ho està, un unavailable_reason: module_not_granted (ampliar el pla el concedeix) o company_is_managed_child (l'empresa no és la titular del seu compte, així que cap pla ho desbloqueja; el nom és heretat i es conserva perquè forma part del contracte). Així distingeixes «no contractat» de «no existeix». Crear una regla de cartera sense aquell dret retorna un 403 automation_portfolio_scope_not_available.

En cartera només s'admeten cinc dels dotze tipus d'acció. notify_in_app, notify_channel i emit_webhook avisen l'empresa titular o no toquen cap entitat, i create_task crea la tasca en un projecte de la pròpia empresa titular —link_to_trigger es rebutja a cartera, perquè l'entitat que ha disparat la regla és d'un altre NIF—. La retirada create_calendar_event conserva el seu lloc en aquest grup però no fa res. Els altres set —send_document_email, send_payment_reminder, change_status, tag_entity, change_task_status, assign_task i add_task_comment— tindrien per subjecte un document o una tasca d'un altre NIF, cosa que la frontera multiempresa no permet. Es rebutgen en crear o editar la regla, mai en executar-la, amb un 422 automation_portfolio_scope_forbids_action. Cada acció del catàleg porta supports_portfolio_scope perquè filtris abans d'escriure la regla.

De qui és l'execució i quin és el seu subjecte. Una execució de cartera es desa sota l'empresa titular del compte: és la seva regla, els seus avisos arriben a la seva bústia i les seves execucions consumeixen el seu pressupost mensual i el seu límit de freqüència, així que el pressupost es gasta en proporció a la cartera. Un esdeveniment pot iniciar més d'una execució quan el seu NIF és a la cartera de més d'un titular, per exemple un NIF cedit a un altre compte amb nivell operate: cada titular amb una regla que coincideixi té la seva pròpia execució, contra el seu propi pressupost. Cada execució anomena a subject_company el NIF sobre el qual va actuar, que és null a les execucions d'abast empresa. El bloc viatja fins i tot quan aquell NIF ja no es pot llegir: id i name tornen a null en comptes de desaparèixer el bloc. El propi NIF no veu les execucions de cartera del seu titular: són del titular i porten la definició congelada de la seva regla.

Filtra execucions amb GET /v1/companies/{company}/automations/runs?subject_company_id=… i regles amb GET /v1/companies/{company}/automations/rules?scope=cartera. Filtrar per un NIF fora de la cartera retorna una pàgina buida, mai un error, així que el filtre no serveix per esbrinar quins NIF existeixen.

En mode de prova res no surt del sandbox

Una clau fact_test_ opera contra una empresa sandbox aïllada, i allà el motor es comporta igual fins a l'últim instant: l'activador coincideix, l'execució s'admet i es registra, i cada pas queda neutralitzat just abans de produir el seu efecte. El pas tanca amb sandbox_neutralized i l'execució acaba completed — un efecte neutralitzat és el desenllaç buscat, no una fallada. No s'envia cap correu, no s'entrega cap webhook i cap document no canvia. Consulta Mode de prova i sandbox.

Passos següents

En aquesta pàgina

Et donem un cop de mà?Contactar amb suport