Skip to content
Automation

Automation

BigLedger has no workflow engine, and this page is the honest answer to what it has instead: four separate mechanisms, none of which is a visual designer or a rule language, and each of which is worth knowing about because between them they cover most of what integrators ask for.

There is no business rule engine, no workflow designer and no automation builder. Nothing in BigLedger lets you write a condition over a document and attach an action to it. The one package in the platform called a rule engine belongs to the contact centre and does exactly one thing: route an incoming task to a team or an agent. It has two rule types and twelve actions, all of them assignment, queueing, or handing the item to an OCR processor. It cannot see an invoice.

The Workflow Design applet is a catalogue of statuses and transitions — a status track a document applet can display — not an engine. It runs nothing.

If you need “when X happens, do Y”, Y runs in your system, triggered by a webhook and carried out through the API. The rest of this page is what BigLedger contributes to that.

The four mechanisms

You want to…UseWhere it runs
React to a change in a tenantWebhooksyour endpoint
Run something on a scheduleThe Scheduler — the tenant’s cron tableBigLedger
Run one of BigLedger’s own background jobsA job processor, put on the SchedulerBigLedger
Gate a purchase document on sign-offThe document approval engineBigLedger

Everything else — branching, retries, escalation, orchestration across steps — is yours to build.

React to a change: webhooks

Register a subscription (a URL, a topic, one optional header) and BigLedger POSTs the changed record to you. Webhooks documents the whole mechanism, including four absences that change how you must build:

  • no signature — the payload is not signed; the only credential is a static header you chose;
  • no retry — one attempt, ever, with no dead-letter queue and no replay;
  • no alerting — the notification fields on a subscription are loaded and never looked at again; no mail or SMS sender exists in the delivery path;
  • no readable delivery log — attempts are recorded, but the endpoint that lists them returns an empty list on every tenant.

The consequence is the single most important design rule on this page: treat a webhook as a hint that something changed, never as a delivery guarantee. Re-read the record through the Data API before you act on it, and pair every subscription with a periodic updated_date_from reconciliation pull. The webhook makes your integration fast; the pull is what makes it correct.

Run something on a schedule: the tenant cron table

Each tenant has a cron table. A row pairs the queue code of a background job processor with a UNIX cron expression and an optional JSON payload of properties for that job. On each platform tick, BigLedger reads the tenant’s active rows, works out which are due, and puts the matching job on the tenant queue.

The Scheduler applet is the screen for this and documents the behaviour in full. Over the API:

PurposeEndpoint
List schedulesGET /core2/tnt/dm/sch/crontabs
Filter schedulesGET /core2/tnt/dm/sch/crontabs/query
Read oneGET /core2/tnt/dm/sch/crontabs/{guid}
CreatePOST /core2/tnt/dm/sch/crontabs
UpdatePUT /core2/tnt/dm/sch/crontabs
DeleteDELETE /core2/tnt/dm/sch/crontabs/{guid}
Run one nowPOST /core2/tnt/dm/sch/crontabs/scheduler/execute/backoffice-ep/{guid}

These need API_TNT_DM_SCH_CRONTAB_READ, _CREATE, _UPDATE or _DELETE, or the broader _OWNER / _ADMIN grants. There is no documented etl-ep path for any of them, so a scheduled job is set up by a signed-in user rather than as part of a server-to-server integration.

A schedule row carries:

FieldNotes
codeThe job processor’s queue code. Stored upper-cased and trimmed.
nameA label.
cron_expressionParsed with the UNIX five-field definition. A six- or seven-field Quartz expression will not behave as written.
event_propertiesA JSON object handed to the job as its properties.
statusOnly ACTIVE rows are read.
execution_strategyINSERT_TO_QUEUE or RUN_NOW; the backend fills in INSERT_TO_QUEUE when it is absent.
last_run_timeMaintained by the platform. Defaults to the moment the row was created.
Three ways a schedule silently does nothing. A code that does not resolve to a job processor the platform knows is filtered out before the cron check — no error, no event, no change to the last-run time. A row that is not ACTIVE is never read. And because the next occurrence is computed forward from last_run_time, which starts at the moment of creation, a daily job created this afternoon does not back-fill this morning’s run.

What you can schedule: job processors

Everything BigLedger does in the background is a job processor — a named unit of work with a queue code, a description and a properties class. There are 597 of them registered in the platform. A processor has to be registered and enabled for your tenant before it can be selected; that is a platform-side step, visible in the Developer SysAdmin applet.

A few that show what the mechanism is for:

Queue codeWhat it does
RECURRING_GENERIC_DOCUMENT_PROCESSORCreates the next generic document when a recurring period comes round
STOCK_REPLENISHMENT_RUN_PROCESSORRuns every stock replenishment configuration against the current date and time
STOCK_LEVEL_MONITORING_RUN_PROCESSORChecks stock levels for a configured scope and records breaches
E_INVOICE_BATCH_PROCESSING_CYCLE_RUN_PROCESSORBuilds the to-IRB submission rows from the batch pool
BI_REPORT_QUERY_RUN_PROCESSORExecutes report query runs from an event and a template

That last one is how scheduled reporting works: a report is defined in the BI report surface (/core2/tnt/dm/bi-reports/…, backoffice-ep throughout — there is no documented etl-ep path into it), and BI_REPORT_QUERY_RUN_PROCESSOR on a cron row is what runs it. There is no “generate report of type X” API endpoint.

A registered processor is not a promise that it does something. At least one processor in the list is a stub whose processEvent returns immediately while its description claims real work (recorded as a product defect). A processor you have not seen produce an effect on a test tenant is a processor you should test before you schedule.

Chained jobs, and why you cannot define one

BigLedger can run a second job when a first one finishes: a platform-level applet trigger template links a publisher job processor to a subscriber job processor, and a tenant enables that link by holding a matching trigger-configuration row. The e-invoice pipeline is built this way.

The half that decides which job follows which lives in the platform registry, not in the tenant. A tenant can enable or disable a link that already exists; it cannot create one, and neither can you. If you need work chained, chain it in your own system.

The largest chain in the product starts when somebody finalises a document

Finalising a generic document — a sales invoice, a cash bill, a purchase order, a credit note — is not a save. It is its own endpoint, PUT /core2/tnt/dm/erp/generic-documents/{docType}/update-posting-status/{guid} with posting_status: FINAL in the body, and the last thing it does before returning is put one row on the tenant queue for the Generic Document Primary Processor. That processor exists to fan out: it reads the subscriber links for its own queue code and queues one job for each (GenericDocumentPrimaryProcessor.java L70–L101).

Dozens of processors subscribe to it in the platform registry — the journal posting, the inventory transaction line, the cashbook line, two e-invoice matching queues, the membership point update, four coupon processors, finance charges, budget register lines, historical aging for a back-dated document, intercompany, the open-queue (knock-off) processor, bundle and make-to-order unwrapping, sales commission, non-stock trade-in, and several integration-specific ones. None of that is on the screen, and the count is a property of the platform rather than of your tenant.

Three filters decide which of them actually run for one document, in this order:

  1. Your tenant’s subscription. Only links whose applet trigger template has an ACTIVE bl_applet_trigger_config_hdr row in your database are returned at all (JobProcessorService.java L538–L552, L592–L606). This is the switch that matters, and it is why two tenants pressing the same button get different amounts of work done. The stock chain is one template covering all three of its levels, so it is on or off as a unit.
  2. Your company’s override list. bl_fi_mst_comp.posting_final_json may carry includeJobProcessorCode and excludeJobProcessorCode arrays; an excluded code is skipped, and if the include list is non-empty everything not on it is skipped (GenericDocumentPrimaryProcessor.java L103–L115). It is an override on top of the subscription, not the thing that enables anything — and it is unset on almost every company in the estate, so in practice the subscription is the whole answer.
  3. The document type on the link. A link may carry serverDocTypes and clientDocTypes constraints; the job is queued only if this document matches (L117–L133). Most links carry none and therefore match every document type.

The chain is deeper than one hop

A subscriber may itself be a publisher. Stock is three levels below the button:

Finalise  →  BLG_ERP_GENERIC_DOCUMENT_PRIMARY_PROCESSOR
          →  INVENTORY_TRANSACTION_LINE_PROCESSOR                     (writes the stock ledger line)
          →  INVENTORY_TXN_LINE_TO_CURRENT_STOCK_BALANCE_PROCESSOR    (balances, moving average, write-back)
          →  INVENTORY_FIFO_LIFO_COSTING_PROCESSOR                    (FIFO baskets, FIFO write-back)

Each level re-runs the same lookup for its own queue code, so the depth is data, not code (InventoryTransactionLineProcessor.java L110–L132).

What the queue does with a job that fails

The queue row is deleted before the handler runsDELETE … RETURNING is how a worker claims it (TenantQueue.java L78–L88). So a handler that throws does not leave a row to retry: the failure is written to app_scheduler_std_error with the event code, the properties (which carry the document GUID) and the message (BaseQueue.java L172–L195), and nothing re-drives it.

The safety net covers the other failure: a row that was inserted and never attempted. The Main Tenant Processor’s tick reads up to ten distinct event codes from app_scheduler_queue and calls the job endpoint once for each, and that endpoint pulls a single event per call (MainTenantProcessor.java L170–L192). That is what makes asynchronous posting safe against a restart — and it is also why a tenant producing work faster than one job per code per tick accumulates a visible backlog in that table.

A subscriber whose queue code is not an enum constant breaks the whole fan-out. The fan-out resolves each subscriber with JobProcessorClassName.valueOf(code) and does not guard it (GenericDocumentPrimaryProcessor.java L89), while the scheduler path guards the identical call with a Try and skips the row (MainTenantProcessor.java L132). One subscriber link in the platform registry today names a queue code that no enum constant matches, so on a tenant that enables that template the exception aborts the loop and every subscriber after it in the list — journal, stock, e-invoice — is never queued, silently. Recorded as a product finding; if you are enabling trigger templates, enable them one at a time and check app_scheduler_std_error afterwards.

Approvals

There is no approval API to build custom chains on. BigLedger’s approval engine is a fixed, optional feature of three applets — Purchase Requisition, Purchase Order and Stock Requisition — and it is configured through their Settings → Approval Settings screens, not through code. It has no public rule engine, no SLA or timeout, no escalation, no delegation and no approval portal API. If you need approvals on any other document, the control is permissions, not a workflow you can register.

What the engine does expose over the API is the approval record for a document, so an integration can read where a purchase order stands and react to it:

PurposeEndpoint
Read approval headers for a documentGET /core2/tnt/dm/erp/generic-doc/approvals/backoffice-ep/query?generic_doc_hdr_guids=…
Read an approver’s outstanding requestsGET /core2/tnt/dm/erp/generic-doc/approvals/approval-requests/login-entity-ep
Record an approve or reject decisionPUT /core2/tnt/dm/erp/generic-doc/approvals/approval-requests/processors/login-entity-primary-ep
Read the approval historyGET /core2/tnt/dm/erp/generic-doc/approvals/approval-histories/backoffice-ep/query
Submit or resubmit a document for approvalPOST / PUT /core2/tnt/dm/erp/generic-doc/approvals/processors/submission/backoffice-ep
Withdraw a pending approvalPUT /core2/tnt/dm/erp/generic-doc/approvals/processors/withdrawals/backoffice-ep

The behaviour behind them — levels, quorum, the Min Approval Amount rule, the two notification e-mails, and the move to FINAL on the first approval — is described in Document Approvals. Anything beyond that (reminders, escalation, routing by supplier or category, a mobile approval app) has to be built in your own system.

The pattern that works

Automation that holds up on this platform looks the same every time:

  1. Subscribe to the topics you care about, one URL per subscription.
  2. Re-read the record through the Data API when a webhook arrives. Do not trust the body.
  3. Decide and act in your own system. Your conditions, your retries, your audit trail.
  4. Write back through the etl-ep endpoints in the API Reference.
  5. Reconcile on a schedule with an updated_date_from pull, because step 1 drops events silently.
  6. Schedule BigLedger’s own jobs for the work that has to happen inside BigLedger — recurring documents, replenishment runs, e-invoice sweeps, report runs.

Start at Integration: Getting Started, which takes you from no credential to moving real data.

What is not there

Stated plainly, because it changes what is worth designing:

Not availableWhat to do instead
A workflow engine or visual designerOrchestrate in your own system
A business rule engine over documentsEvaluate conditions in your own system
Webhook signatures, retries, replay or a readable delivery logRe-read every record; reconcile on a schedule
An API to create a job processorJob processors are platform code; only scheduling is tenant-side
An API to chain one job to anotherChain in your own system
An approval API for documents other than the three named aboveUse permissions
A “generate report” endpointDefine the report, then schedule BI_REPORT_QUERY_RUN_PROCESSOR
A BigLedger client SDK for JavaScript, Python, PHP, Java, .NET or GoCall the REST API directly. The published Angular libraries are for applet development, not for server-side integration

Related documentation

Last updated on