Посібники
WebSocket-події
WebSocket stream BroSettlement повідомляє організацію про durable зміни рахунків, гаманців, депозитів і транзакцій, щоб клієнт міг оновлювати пов’язані REST-ресурси без постійного polling.
Підключення
Staging endpoint:
wss://brosettlement-staging-api.brolabel.io/v1/wsAPI key потребує scope websockets:read. Підпишіть handshake приватним Ed25519-ключем API key:
WS_CONNECT
/v1/ws
TIMESTAMP
NONCEВикористовуйте API key ID, Unix timestamp у секундах, nonce і стандартний padded Base64 signature відповідно до поточного integration environment. Шестирядковий REST canonical value не підходить для WebSocket connection.
Модель доставки
- Events належать лише організації API key.
- Durable business event має globally unique ID, який не змінюється під час redelivery.
- Delivery працює за моделлю at least once: клієнт має очікувати дублікати.
occurredAt— час durable state transition, а не доставки через WebSocket.correlationIdзв’язує REST requests, транзакції, blockchain activity і support logs.- Event schemas починаються з version
1і розвиваються additive-only. - Listener має ігнорувати невідомі поля.
- Приватні ключі, raw signatures, seed material, user secrets та internal MPC payloads не повинні потрапляти до event.
Event envelopes
MVP-compatible envelope використовує type, event і eventId:
{
"type": "EVENT",
"event": "transaction.updated",
"eventId": "evt_...",
"version": 1,
"orgId": "org-id",
"occurredAt": "2026-07-07T13:38:33.000Z",
"correlationId": "request-or-flow-id",
"data": {}
}Durable topic-stream envelope використовує op, subject, id і sequence:
{
"op": "event",
"subId": "s1",
"id": "evt_...",
"sequence": 987654,
"subject": "transaction.updated",
"occurredAt": "2026-07-07T13:38:33.000Z",
"orgId": "org-id",
"correlationId": "request-or-flow-id",
"version": 1,
"data": {}
}Під час міграції підтримуйте обидва envelopes, якщо ваше середовище може надсилати обидві форми. Нормалізуйте eventId/id та event/subject перед обробкою.
Обов’язкові event families
| Event | Значення |
|---|---|
system.connected | Автентифікація успішна, stream готовий |
system.error | Помилка автентифікації, policy, topic або payload |
account.created | Рахунок операційного журналу durable created |
wallet.created | Гаманець і адресу створено та можна прочитати через REST |
wallet.creation_failed | Асинхронно прийнятий wallet provisioning завершився помилкою |
wallet.status_changed | Гаманець перейшов між lifecycle states |
transaction.created | Створено durable transaction record або intent |
transaction.updated | Змінився client-visible стан або on-chain detail |
transaction.confirmed | Транзакція досягла успішної finality |
transaction.failed | Обробка завершилася помилкою до успішного on-chain completion |
transaction.failed_on_chain | Blockchain execution failed або reverted |
deposit.observed | Вхідний переказ виявлено |
deposit.confirmed | Депозит виконав confirmation policy |
deposit.credited | Підтверджений депозит зараховано до операційного журналу |
Read-only REST calls не створюють business event лише через факт виклику.
Account events
account.created надходить після успішного POST /api/v1/ledger/accounts.
{
"accountId": "account-id",
"orgId": "org-id",
"name": "Customer 123",
"externalId": "customer-123",
"createdAt": "2026-07-07T13:00:00.000Z",
"requestId": "http-request-id",
"idempotencyKey": null
}Synchronous validation або authentication rejection, який не створив рахунок, не призводить до account.created.
Wallet events
wallet.created ідентифікує durable wallet та адресу:
{
"walletId": "wallet-id",
"accountId": "account-id",
"orgId": "org-id",
"chain": "tron:nile",
"address": "T...",
"status": "ACTIVE",
"createdAt": "2026-07-07T13:00:00.000Z",
"requestId": "http-request-id",
"idempotencyKey": "client-operation-id"
}Якщо асинхронно прийняте створення гаманця згодом завершується помилкою, надсилається wallet.creation_failed з accountId, chain, status і machine-readable errorCode. wallet.status_changed використовується для переходів на кшталт PENDING → ACTIVE, DISABLED, ARCHIVED або FAILED.
Synchronous 4xx, який не створив durable wallet, не вимагає business event. Джерелом істини є REST error.
Transaction events
Використовуйте єдину family transaction.* для withdrawals та internal transfers. Не розділяйте lifecycle на withdrawal.*, transfer.* або internal_transfer.*.
Тип переміщення визначається в payload:
isInternalTransfer: falseіtransferKind: "EXTERNAL_WITHDRAWAL"для зовнішнього виведення;isInternalTransfer: trueіtransferKind: "INTERNAL_TRANSFER"для переміщення всередині організації.
Minimum lifecycle payload:
{
"transactionId": "transaction-id",
"transactionGroupId": null,
"sourceTransactionId": null,
"destinationTransactionId": null,
"orgId": "org-id",
"accountId": "account-id",
"walletId": "wallet-id",
"destinationAccountId": null,
"destinationWalletId": null,
"chain": "tron:nile",
"asset": "TRX",
"amountAtomic": "7000000",
"amountDirection": "DEBIT",
"isInternalTransfer": false,
"transferKind": "EXTERNAL_WITHDRAWAL",
"fromAddress": "T...",
"toAddress": "T...",
"txHash": null,
"status": "PENDING",
"sourceStatus": "PENDING",
"destinationStatus": null,
"failureCode": null,
"failureMessage": null
}transaction.updated покриває reservations, MPC signing progress, відправлення у блокчейн, confirmation progress, on-chain details і externally relevant failure information. Terminal events містять фінальний REST-visible status: CONFIRMED, FAILED або FAILED_ON_CHAIN.
Зберігайте amountAtomic як base-10 string. Не обробляйте його через floating-point types.
Депозити
Депозити виникають унаслідок blockchain observation, а не client REST POST:
deposit.observed— вхідний переказ виявлено.transaction.created— існує client-visible deposit transaction.deposit.confirmed— досягнуто необхідної кількості confirmations.transaction.confirmed— транзакція досягла terminal success.deposit.credited— кошти зараховано до операційного журналу.
Implementation може об’єднувати сумісні lifecycle signals, але підтверджений депозит повинен створити щонайменше одну deposit або transaction event. Клієнт не повинен виявляти durable confirmed deposit лише через polling.
Deposit data має містити transactionId, якщо він уже доступний, walletId, accountId, chain, asset, amountAtomic, txHash, block information і confirmation progress.
Synchronous rejection і durable failure
Ці випадки мають різну event behavior:
Результат POST /api/v1/transactions | Очікування WebSocket |
|---|---|
Synchronous 4xx, немає transaction ID, durable record або reservation | Немає transaction.* business event; обробіть REST error |
| Transaction ID або durable intent створено, а потім обробка завершилася помилкою | Надішліть transaction.created, потім terminal transaction.failed |
| Blockchain execution failed або reverted | Надішліть transaction.failed_on_chain |
Щойно транзакція стала видимою через list/detail REST endpoints, кожен наступний terminal failure має бути видимим і через WebSocket. Failed reservation має бути voided рівно один раз.
Для internal transfer із paired debit/credit rows додайте sourceTransactionId, destinationTransactionId і leg statuses. Failed source leg не повинен залишати destination leg у PENDING.
Звірка з REST
Сприймайте event як сигнал оновити authoritative state:
| Event family | REST resources для оновлення |
|---|---|
account.* | /api/v1/ledger/accounts/{accountId} |
wallet.* | /api/v1/wallets/{walletId} і wallets рахунку |
transaction.* | /api/v1/transactions/{id}, пов’язані balances і journal entries |
deposit.* | Transaction detail, wallet/account balances і ledger entries |
Transactions list і transaction detail мають збігатися за status. Не показуйте фінальний клієнтський баланс лише на основі неперевіреного event payload.
Вимоги до listener
- Записуйте отримані frames, але не API private keys або signing secrets.
- Парсьте JSON зі збереженням original payload для розслідування.
- Сприймайте
system.connectedяк transport state, а не business event. - Дедуплікуйте business events за стабільним
eventIdабоid. - Зберігайте
sequenceабо last event ID, коли доступний resume. - Виконуйте acknowledgement durable events, якщо server вимагає explicit ack.
- Повторно підключайтеся з bounded exponential backoff і jitter.
- Відновлюйте stream з останньої committed position, коли це підтримується.
- Оновлюйте пов’язані REST resources після
transaction.*,wallet.*і deposit events. - Commit resume position лише після успішної локальної обробки.
Сумісність поточного staging
Requirements document фіксує такі staging compatibility gaps:
- частина deployments може ще надсилати legacy
SYSTEM_CONNECTEDзамістьsystem.connected; - поточний
/v1/wstransport може ще не підтримувати topics, ack або resume; - event coverage для deposits і paired internal-transfer legs потрібно перевіряти в цільовому середовищі.
Під час міграції нормалізуйте legacy connection event, але не вигадуйте відсутні business events на стороні клієнта. Використовуйте REST-звірку для відновлення стану й підтвердьте ввімкнений WebSocket contract перед запуском у робочому режимі.
Безпека
- Відхиляйте або ігноруйте event, якщо
orgIdне відповідає автентифікованій організації. - Не записуйте credentials або MPC signing material у журнали.
- Сприймайте event data як untrusted input і валідуйте required fields.
- Зберігайте
correlationIdі RESTrequestIdдля підтримки. - Використовуйте окремий least-privilege API key зі scope
websockets:read.