The flow at 2:05, 2:06 and 2:07 pm
- 2:05 pm, app. Marina disputes the August bill in your app. The message is tied to
invoice:erp:0823throughobject_refsand is in the live layer in under a second. - 2:06 pm, billing agent. It reads
context(object="invoice:erp:0823", view="task:billing", verification="no_customer"), receives the dispute throughlive, the technician visit that failed at 2:02 pm and the March credit from the history. It posts the $40 credit in the ERP and recordsaction("credit", closes=...). - 2:06 pm, ERP. The ERP emits
invoice.credited. The action and the event become one record, and the action goes fromdeclaredtoconfirmed. - 2:07 pm, call. The voice pack already says: “Done by another agent: $40 credit on the August bill, Billing, 2:06 pm, confirmed by the system”.
Niadra never executes an action in a system of record. Your agent acts, with its own credentials. Niadra keeps what it needs to remember and what it did.
Before you start: the source
An internal agent is a source like any other, with its own key, audience classinternal_agent and a purpose such as billing. Access to the ERP is not access to the memory: the billing agent reads invoices and disputes, not technical open items or health data. Two settings matter here:
- Scope
acton the key, andtrusted_action_opson the source (here["credit"]): the closed list of operations it may record, and the ones whose declared actions close open items before the system confirms them. Thetrackscope alone never records an action. - Verification
no_customer, the level for tasks with no customer present. It sits outside the V0 to V4 scale and is only accepted frominternal_agentsources. A pack built forno_customernever goes to the customer.
Steps
1. Open a task centered on the invoice
A task plays the role a conversation plays for service agents: it pins the pack, scopes the SDK cache, groups the events for billing and closes withtask.ended. Without it, the server closes the task after 10 minutes of inactivity.
The task:billing view is defined by your space as a template plus a policy. It favors objects of the task type, the open items tied to them and what was said about them in conversations; it leaves out what the billing purpose does not allow.
context(object=...) resolves the invoice to its owner and returns the pack centered on it: the timeline of the object plus the customer context the task needs. The same laws hold as for a conversation: precompiled, pinned by task, with ETag and a receipt of the read.
2. Act in the ERP, then record the action
Post the credit through your ERP integration. Then record the action withcloses, the open item it fulfils. Name it by id, or by the object and a canonical operation, which is what you usually know: the dispute on invoice 0823.
corrects_action_id pointing to the old one.
3. Let the system of record confirm it
The action staysdeclared until an event from the system of record confirms it. Send the ERP events through the generic webhook or as system events. When invoice.credited arrives for the same object and operation within the window, the two become a single record and the action is confirmed, so the credit is never counted twice.
A declared action only closes an open item if its operation is in the
trusted_action_ops of the source; a confirmed one always closes it.
4. Understand the retroactive close
The action can arrive before the open item exists. The dispute written in the app at 2:05 pm only becomes an open item when the app session closes and is extracted, say at 2:35 pm, and the billing agent acted at 2:06 pm. When the open item is created, Niadra looks for actions and events already applied to the same object and operation within the window. If one exists, the open item is bornresolved, pointing to the action that closed it.
5. Let other agents know
Every agent that reads this customer next sees the action in “Done by another agent”, with its source and time. If your CRM needs to show the outcome, subscribe to theaction.recorded and open_item.closed webhooks and write it there with your own integration. See Triggers and webhooks.
Delta for recurring work
Internal agents often revisit the same customers. Ask withdelta=True (delta: true) and the answer carries only what changed since this source last read the customer: “what changed since the last time YOU looked” costs tens of tokens.
Next steps
Systems, objects and actions
objects, derived state and actions in depth.
Webhooks from your systems
how
invoice.credited gets in.Voice agents
the call that knows about the credit.
Context use
how the action counts as use of the context.

