> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Events and ledger integration

> Integrating with Lerian SPB: STR operation event families, ledger integration, and API conventions.

Lerian SPB is event-driven. Event emission is not guaranteed for every operation or lifecycle change: some emitters are optional or best effort, and `EMISSION_REQUIRED` defaults to `false`. Set `EMISSION_REQUIRED=true` in a deployment whose downstream systems depend on these events. Bootstrap then fails closed unless event emission is fully wired.

Lerian SPB publishes every event family on the streaming backbone. Downstream systems read settlement state from the `settlement.*` and `spb.ldl.*` streaming events and do not poll.

## Event families

***

| Family | Emitted on |
| - | - |
| `str.operation.*` | Operation lifecycle: `accepted`, `received`, `returnRequested`, `cancelRequested` |
| `str.readiness.changed` | The rail's readiness state changes |
| `str.certificate.*` | Certificate lifecycle: `rotated`, `expiring`, `counterpartyChanged`, `activationRequested` |
| `str.approval.*` | A queued approval emits `signed` or `denied`; when it reaches quorum and changes from `PENDING_APPROVAL` to `SUBMITTED`, it emits `quorumReached` once |
| `str.reconciliation.*` | A reconciliation case is `opened` or `resolved` |
| `str.schedule.changed` | The operating-window grades change |
| `str.message.*` | Message-level `received`, `submitted`, `rejected` |
| `str.emoney.transferAdvised` | A new third-party electronic-money advice (`SME0001R2`, `SME0002R2`, or `SME0004R2`) is recorded |
| `spb.ldl.*` | SILOC deposit-advisory and deposit-command facts, including `deposit-commanded`, `deposit-confirmed`, and `deposit-failed`. LDL and LTR settlement facts: `settlement-confirmed`, `settlement-failed`, and `third-party-settlement-received` |
| `settlement.*` | The final settlement position: `settled` once the inbound R-leg confirms the transfer, `failed` on a rejection or on the cancellation of a never-settled original |

Inbound BACEN notices also publish dedicated events. See [Inbound messaging from BACEN](https://docs.lerian.studio/en/rails/spb/spb-inbound-messaging.md).

## Ledger integration

***

Your ledger consumer must receive the `str.operation.*`, `settlement.*`, and `spb.ldl.*` families on the streaming backbone. The `str.operation.accepted` event signals dispatch acceptance, not BACEN settlement, so use it to record a pending posting.

Record the final position from the `settlement.*` facts on the streaming backbone. The business transition behind `settlement.settled` occurs when the inbound R-leg moves the transfer's STR message to `CONFIRMED`. Broker delivery is at-least-once and can redeliver the fact. The `ce-id` is deterministic, so deduplicate on the `(ce-source, ce-id)` pair.

LDL settlements, LDL0022 deposits, the LTR0004 payment, and the unsolicited LDL and LTR0005R2 notices have no `settlement.*` fact. Record them from the `spb.ldl.*` facts:

* The R1 answer to your command: `deposit-confirmed` or `deposit-failed` for an OT deposit, and `settlement-confirmed` or `settlement-failed` for every other command.
* An LDL0020R2 credit that matches an expected OT credit: `credit-received`.
* Every other notice: `third-party-settlement-received`.

An incoming credit that answers no operation of yours arrives as `str.operation.received`, so record that credit from this event. A return of a TED you sent arrives the same way. Its `numCtrlSTROr` field holds the control number of your original TED.

A return gives back a TED credit that you received, as a transfer of its own. `str.operation.returnRequested` signals the return's dispatch acceptance, and the return's own `settlement.settled` or `settlement.failed` gives its final position. Lerian SPB holds no accounting position. The rail carries the message and its settlement state, and your ledger records the money.

## API conventions

***

* **Auth** is a bearer token.
* **Writes are idempotent** through the `X-Idempotency` header. A retried submit does not double-dispatch.
* **Message-log reads do not expose the signed on-wire frame.** You read a single message by its NUOp for structured data. When the rail retained a frame, read its reconstructed XML through the dedicated, separately authorized frame route. It does not separately retain the literal sent bytes.
* **Unknown ids return a uniform not-found.** The response never reveals whether an operation exists that your institution does not own.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.