Transport contract
| Field | Value |
|---|---|
ce-source | plugin-br-bank-transfer |
| Topic | lerian.streaming.plugin-br-bank-transfer |
ce-type | studio.lerian.plugin-br-bank-transfer.<event-key> |
| Schema version | Per event, in the catalog below |
| Content type | application/json |
ce-subject | The transfer id. payment_initiation.created carries the initiation id, and transfer_incoming.undeliverable carries its jdIncomingMessageId |
ce-tenantid | Your tenant, in multi-tenant mode |
| Delivery | Through the PostgreSQL outbox. The outbox relay is the only broker publisher |
| Runtime manifest | GET /streaming/manifest |
STREAMING_ENABLED=true and the streaming variables. While streaming is off, the plugin discards events. If you set STREAMING_CLOUDEVENTS_SOURCE, its value must be exactly plugin-br-bank-transfer. In production, the plugin serves the manifest only when authentication is on.
Some events are best effort: when their outbox write fails, the plugin keeps the change that they announce and does not publish the event. If an expected event does not arrive, read the transfer with Get Transfer.
Event catalog
Initiation and transfer lifecycle
| Event key | Schema | Fires when |
|---|---|---|
payment_initiation.created | 1.0.0 | Initiate Transfer created an initiation, before its confirmation. |
transfer.initiated | 1.0.0 | The plugin created a TED OUT or cross-core TED transfer from a confirmed initiation. |
transfer.processing_started | 1.0.0 | A TED OUT entered processing (CREATED to PENDING to PROCESSING). |
transfer.completed | 1.2.0 | A TED OUT, P2P, or cross-core TED completed. For a TED OUT, the STR settled it, or an operator settled it by hand. For a cross-core TED, the other core credited the recipient. |
transfer.rejected | 1.1.0 | A TED OUT or cross-core TED was rejected, and its hold was cancelled. For a TED OUT, JD refused it at dispatch, or the STR refused the settlement. For a cross-core TED, the other core refused the credit, or the JD Courier reached no recipient. |
Reconciliation
| Event key | Schema | Fires when |
|---|---|---|
transfer.reconciliation_required | 1.0.0 | A TED OUT with an unknown outcome moved to reconciliation. |
transfer.reconciliation_resolved | 1.5.0 | The reconciliation worker or an operator resolved a transfer. |
transfer.reconciliation_exhausted | 1.1.0 | The reconciliation worker stopped after the maximum number of attempts and moved the transfer to manual review. |
transfer.reconciliation_failed | 1.0.0 | The reconciliation worker failed a TED OUT on a deterministic error. |
transfer.reconciliation_manual_retry_requested | 1.0.0 | An operator returned a TED OUT from manual review to the reconciliation queue. |
transfer.scope_repaired | 1.0.0 | An operator corrected the ledger that a transfer is filed under. No money moved. |
Incoming transfers
| Event key | Schema | Fires when |
|---|---|---|
transfer_incoming.completed | 1.0.0 | The plugin credited a TED IN or a customer credit, or booked a cross-core credit or return from the other core (transferType CROSS_CORE_IN). |
transfer_incoming.chargeback | 1.1.0 | A completed TED IN failed on an STR0010R2 chargeback. The TED IN worker sends it, and so does an operator who closes a parked chargeback by hand. |
transfer_incoming.undeliverable | 1.0.0 | The plugin recorded an incoming credit that it could not deliver. |
transfer_incoming.return_requested | 1.0.0 | The return of a TED IN entered processing: the hold is placed, and the STR0010 is about to be sent. |
transfer_incoming.returned | 1.0.0 | The STR settled the return of a TED IN, and the original credit was reverted. |
transfer_incoming.return_rejected | 1.0.0 | The return of a TED IN was refused, and its hold was cancelled. |
transfer_incoming.return_manual_review | 1.0.0 | The return of a TED IN waits for an operator. |
Devolutions and P2P returns
| Event key | Schema | Fires when |
|---|---|---|
transfer_outgoing.devolution_notified | 1.1.0 | The plugin recorded a devolution (STR0010R2) of a TED OUT on the original transfer. |
transfer_internal.returned | 1.0.0 | The return of a P2P completed, and the ledger reverted the original transaction. |
transfer_internal.return_failed | 1.0.0 | The ledger refused the return of a P2P. Nothing moved, and the P2P can be returned again. |
Deduplication
Deduplicate on(ce-source, ce-id), and keep consumers idempotent. Two events also need a business key:
transfer_incoming.chargeback: the TED IN worker and an operator can each announce one chargeback, under two ids. Deduplicate ontenantId,transferId, andstatus.transfer.reconciliation_resolved: an operator resolution can arrive twice.convergedOntoExistingResolutionmarks the copy that found the resolution already written. Deduplicate ontenantId,transferId,status, andreconciliationStatus, not on that marker.
Payload contracts
Amounts are decimal strings, for example"1500.00". Timestamps are UTC RFC 3339 strings. Fields marked with ? are optional. tenantId is empty in single-tenant mode.
// payment_initiation.created
interface PaymentInitiationCreated {
paymentInitiationId: string
tenantId: string
organizationId?: string
ledgerId: string
senderAccountId: string
recipientAccountId?: string
recipientIspb: string
amount: string
feeAmount: string
totalAmount: string
transferType: string
status: string
purpose?: string
expiresAt: string
createdAt: string
}
// transfer.initiated
interface TransferInitiated {
transferId: string
paymentInitiationId: string
tenantId: string
organizationId?: string
ledgerId: string
senderAccountId: string
recipientAccountId?: string
amount: string
feeAmount: string
totalAmount: string
transferType: string
status: string
confirmationNumber: string
controlNumber: string
midazTransactionId?: string
signingArtifactId?: string
createdAt: string
}
// transfer.processing_started
interface TransferProcessingStarted {
transferId: string
tenantId: string
transferType: string
status: string
controlNumber: string
statusPath: string
processingStartedAt: string
}
// transfer.completed
interface TransferCompleted {
transferId: string
initiationId: string
tenantId: string
organizationId?: string
ledgerId: string // on a P2P between ledgers, the payer's ledger
senderAccountId: string
recipientAccountId?: string
midazTransactionId: string
confirmationNumber: string
status: string
transferType: string // TED_OUT, P2P, or CROSS_CORE
amount: string
feeAmount: string
totalAmount: string
packageAppliedId?: string
completedAt: string
// TED OUT only
source?: "str0008r1" | "reconciliation" | "manual"
controlNumber?: string
clearingControlNumber?: string
messageSequence?: string
settledAt?: string
// P2P between ledgers only
recipientLedgerId?: string
ledgerGroupId?: string
}
// transfer.rejected
interface TransferRejected {
transferId: string
tenantId: string
transferType: string // TED_OUT or CROSS_CORE
status: string
failureCode: string // BTF-4005 on a cross-core TED
failureMessage: string
errorCategory: string
midazCancelled: boolean
midazTransactionId?: string
rejectedAt: string
// TED OUT only
source?: "dispatch" | "str0008r1" | "reconciliation"
rejectedBy?: "jd" | "bacen"
settlementRejectionCode?: string
controlNumber?: string
clearingControlNumber?: string
messageSequence?: string
}
// transfer.reconciliation_required
interface TransferReconciliationRequired {
transferId: string
tenantId: string
transferType: string
status: string
reconciliationStatus: string
controlNumber?: string
counterpartySystem: string
failureClass: string
failureCode: string
errorCategory: string
reason: string
reconciliationEnqueuedAt: string
}
// transfer.reconciliation_resolved
interface TransferReconciliationResolved {
transferId: string
tenantId: string
status: string
transferType: string
reconciliationStatus: string
resolution: string
reasonCategory: string
attempts: number
jdResponseCode?: string
controlNumber?: string
jdSequenceNumber?: string
clearingControlNumber?: string
// operator resolution only
actor?: string
operatorReason?: string
evidenceReference?: string
convergedOntoExistingResolution?: boolean
resolutionAuthorizedBy?: string
// resolution manual_repost only
previousCompensationTransactionId?: string
compensationTransactionId?: string
}
// transfer.reconciliation_exhausted
interface TransferReconciliationExhausted {
transferId: string
tenantId: string
status: string
transferType: string
reconciliationStatus: string
resolution: string
reasonCategory: string
attempts: number
maxAttempts: number
holdPreserved: boolean
jdResponseCode?: string
controlNumber?: string
jdSequenceNumber?: string
}
// transfer.reconciliation_failed
interface TransferReconciliationFailed {
transferId: string
tenantId: string
status: string
reconciliationStatus: string
resolution: string
reasonCategory: string
attempts: number
errorCategory: string
jdResponseCode?: string
controlNumber?: string
jdSequenceNumber?: string
}
// transfer.reconciliation_manual_retry_requested
interface TransferReconciliationManualRetryRequested {
transferId: string
tenantId: string
status: string
transferType: string
reconciliationStatus: string
operatorReason: string
previousAttempts: number
requestId?: string
requeuedAt: string
}
// transfer.scope_repaired
interface TransferScopeRepaired {
transferId: string
tenantId: string
ledgerId: string
status: string
transferType: string
actor: string
operatorReason: string
evidenceReference?: string
requestId?: string
repairedAt: string
}
// transfer_incoming.completed
interface TransferIncomingCompleted {
transferId: string
tenantId: string
status: string
transferType: string // TED_IN, TED_IN_STR0005 to TED_IN_STR0051, or CROSS_CORE_IN
amount: string
feeAmount: string
grossAmount: string
controlNumber: string // empty on CROSS_CORE_IN
messageSequence: string // empty on CROSS_CORE_IN
repairedBy: string
}
// transfer_incoming.chargeback
interface TransferIncomingChargeback {
transferId: string
tenantId: string
status: string
transferType: string
// absent when an operator closes the chargeback
chargebackCode?: string
messageSequence?: string
controlNumber?: string
}
// transfer_incoming.undeliverable
interface TransferIncomingUndeliverable {
undeliverableId: string
tenantId: string
jdIncomingMessageId: string
rejectionReason: string
rejectionCategory: string
controlNumber: string
messageSequence: string
grossAmount: string
senderISPB: string
}
// transfer_incoming.return_requested, returned, return_rejected, return_manual_review
interface TransferIncomingReturn {
transferId: string // the return, a TED_OUT
originalTransferId: string // the TED IN that it returns
tenantId: string
organizationId?: string
transferType: string
status: string
controlNumber: string
amount: string // the gross amount that leaves your institution
returnReasonCode: string
requestedVia: string
externalReference?: string
clearingControlNumber?: string
reversalTransactionId?: string
reconciliationReasonCode?: string
reconciliationReasonClass?: string
revertFailureClass?: string
failureCode?: string
rejectionCause?: "not_found" | "str_refused" | "jd_refused" | "local_verdict" | "operator"
occurredAt: string
}
// transfer_outgoing.devolution_notified
interface TransferOutgoingDevolutionNotified {
transferId: string
tenantId: string
codDevTransf: string
chargebackCode: string
senderISPB: string
recipientISPB: string
amount: string
controlNumber: string
transferStatus: string
transferType: string
feeRetained: boolean
feeRefunded: boolean
feeRefundedAmount?: string
via: string
}
// transfer_internal.returned, return_failed
interface TransferInternalReturn {
transferId: string // the return, a P2P
originalTransferId: string
tenantId: string
organizationId: string
ledgerId: string // the ledger of the debited account
recipientLedgerId?: string // between ledgers only: the ledger of the credited account
amount: string
reversalTransactionId?: string
requestedVia: string
revertFailureClass?: string
failureCode?: string
occurredAt: string
}

