LendEasy/DocsLMS + Servicing·v1
Start integrating
Guides›Servicing Workspace›Execution-time checks

Execution-time checks

Volatile controls are re-evaluated at send, dial, submit, or post time, so neither immediate nor queued work can act on a permission that has gone stale.

Every permission in servicing has a shelf life. Between deciding to call somebody and dialling them, a borrower can revoke consent, file for bankruptcy, or pay in full. So execution asks “may this exact action run now?” and answers it at the moment of acting: the owning operation puts the question itself, and scheduled voice work adds a dispatch gate and a dispatch-bound dial authorization, because a queued call waits exactly where the facts move.

An allowed operation runs on its owning route rather than being turned into a request first, so the decision and the act happen in one place. The generalized preview and preparation lifecycle is described at the end of this page. See API availability.

Placing a call: the dial API

curl -X POST "$BASE/v1/servicing/calls/outbound" \
  -H "Authorization: Bearer $TOKEN" \
  -H "LendEasy-Tenant: demo-lender" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: hbr-call-attempt-2027-05-01-1" \
  -d '{
    "caseId": 1001,
    "customerRef": "412",
    "loanRef": "7204",
    "contactPointRef": "cp_MAYA_MOBILE_1",
    "reasonCode": "COLLECTIONS_FOLLOW_UP"
  }'

The dial API does not accept or trust a caller-provided allowed flag. It creates the interaction evidence first, resolves the latest contact facts, makes the execution decision, and only then invokes the telephony gateway — the response is always 201 with the persisted attempt, whose status is DIALING, BLOCKED, or FAILED with the compliance decisionId. A future-dated contact is booked as a scheduled callback on the case, and its start-call command runs this same gate again at dial time; there is deliberately no scheduled email or SMS send to drift stale.

Nothing commits on a version that moved

Checking and then acting leaves a gap, and a gap wide enough to read a fact in is wide enough for that fact to change. So the executor binds what it decided on:

  • normalized action payload hash;
  • customer, loan, case, instrument, schedule, and restriction versions used;
  • policy bundle and rule versions;
  • decision ID and expiry;
  • idempotency key and attempt number;
  • provider request or authoritative action reference.

If a bound version changes before commit, execution fails with a conflict or new decision—not a stale side effect.

Blocked attempts are evidence

A blocked attempt is not a sent interaction and should not count as provider delivery. It still records the intended action, pre-check, current blocking fact, rules, time, actor, and safe next step. Without that record, a control that fired and a control that never ran look identical from the outside — silence proves nothing, and the whole value of a gate is being able to show it held.

A mass action is many small decisions

A mass action fans out into individually checked actions, and each customer receives a fresh evaluation at their own execution time. One can be allowed, one blocked, one missing facts, and one already resolved; the customer record result preserves every branch. A population evaluated once at the top would carry one borrower’s permission to nine thousand others.

Retry only after the blocking condition has a documented resolution or current facts support a new evaluation. Re-enqueuing around a block with a new idempotency key is not remediation — it is the same action, asked again in the hope of a different answer.
Unified search across guides, recipes & the API referenceEsc