IBExWalletAPI
Admin

WebSockets

Real-time balance, transaction, KYC and IBAN updates via WebSocket.

Connect to the IBEx WebSocket endpoint to receive real-time push notifications for balance changes, new transactions, KYC/IBAN status updates, and more — without polling.

Endpoint

wss://<your-domain>/ws

Append ?blockchainId=<chainId> to target a specific chain (e.g. wss://api.ibex.fi/ws?blockchainId=421614). If omitted, the server uses the default chain.

Browsers cannot set custom headers on new WebSocket(). Use the query parameter for chain selection.

Authentication

WebSocket connections require JWT authentication. After opening the socket, send a single JSON message:

{
  "type": "auth",
  "token": "<your_jwt_access_token>",
  "clientName": "My App"
}
FieldTypeRequiredDescription
typestringYesMust be "auth"
tokenstringYesJWT obtained from POST /v1.2/auth/sign-in or /v1.2/auth/refresh
clientNamestringNoLabel for monitoring and debugging

The server verifies the JWT and resolves the user's Safe wallet on the target chain. On failure, an auth_error message is returned.

Quick start

const ws = new WebSocket('wss://api.ibex.fi/ws?blockchainId=100');
 
ws.onopen = () => {
  ws.send(JSON.stringify({
    type: 'auth',
    token: jwtToken,
    clientName: 'My App'
  }));
};
 
ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  switch (msg.type) {
    case 'auth_success':
      console.log('Connected, Safe:', msg.data.safeAddress);
      break;
    case 'balance_update':
      console.log('Balance changed:', msg.data);
      break;
    case 'new_transaction':
      console.log('New tx:', msg.data);
      break;
  }
};
 
ws.onclose = () => {
  // Reconnect with exponential backoff
};

Initial data sequence

After successful authentication, the server automatically sends the following messages in order:

#Message typeContent
1auth_successSafe address and confirmation
2balance_dataCurrent token balances
3transaction_dataRecent transaction history
4chainid_dataDefault and supported chain IDs
5recovery_dataSocial recovery status
6user_dataUser profile, signers, safes, IBAN info

No explicit request is needed — data is pushed automatically.

Server → client messages

All messages are JSON with type, data, and timestamp (ISO 8601).

auth_success

{
  "type": "auth_success",
  "data": {
    "safeAddress": "0x7CDb…D5a",
    "message": "Connected to real-time updates"
  },
  "timestamp": "2025-08-01T07:36:04.083Z"
}

auth_error

{
  "type": "auth_error",
  "data": {
    "message": "JWT token expired, please refresh your token",
    "context": "auth_process"
  },
  "timestamp": "2025-08-01T07:36:04.083Z"
}

balance_data

Sent after auth and in response to get_balance.

{
  "type": "balance_data",
  "data": {
    "safeAddress": "0x…",
    "balance": {
      "balances": [
        { "token": "0x…", "symbol": "EURe", "balance": "123.45", "decimals": 18 }
      ]
    }
  },
  "timestamp": "2025-08-01T07:36:04.083Z"
}

balance_update

Pushed when the wallet balance changes on-chain.

{
  "type": "balance_update",
  "data": {
    "address": "0x…",
    "balance": "1250000000000000000",
    "updated_at": "2025-08-01T07:36:04.083Z"
  },
  "timestamp": "2025-08-01T07:36:04.083Z"
}

new_transaction

Pushed when a new transaction is detected on-chain.

{
  "type": "new_transaction",
  "data": {
    "address": "0x…",
    "newTransaction": {
      "hash": "0x…",
      "blockNumber": 12345678,
      "timestamp": "2025-08-01T07:36:04.083Z",
      "from": "0x…",
      "to": "0x…",
      "tokenAddress": "0x…",
      "tokenType": "ERC20",
      "tokenSymbol": "EURe",
      "value": "100.0",
      "direction": "IN"
    },
    "recentTransactions": [],
    "transactionCount": 1,
    "historyLimit": 5
  },
  "timestamp": "2025-08-01T07:36:04.083Z"
}

transaction_data

Full transaction list, sent after auth or in response to get_transactions.

{
  "type": "transaction_data",
  "data": {
    "safeAddress": "0x…",
    "transactions": { "data": [ ] },
    "requestId": "optional-correlation-id"
  },
  "timestamp": "2025-08-01T07:36:04.083Z"
}

chainid_data

{
  "type": "chainid_data",
  "data": { "defaultChainId": 100, "supportedChainIds": [100, 421614] },
  "timestamp": "2025-08-01T07:36:04.083Z"
}

recovery_data

{
  "type": "recovery_data",
  "data": {
    "safeAddress": "0x…",
    "recoveryEnabled": false,
    "recoveryAddress": null,
    "delay": null,
    "pendingRecovery": false,
    "canExecute": false,
    "executeAfter": null
  },
  "timestamp": "2025-08-01T07:36:04.083Z"
}

user_data

{
  "type": "user_data",
  "data": {
    "id": "user-uuid",
    "ky": "verified",
    "signers": [
      {
        "id": "signer-id",
        "safes": [
          {
            "address": "0x…",
            "threshold": 1,
            "iban": { "chainId": 100, "iban": "FR76…", "bic": "CREDFRPP" }
          }
        ]
      }
    ]
  },
  "timestamp": "2025-08-01T07:36:04.083Z"
}

user.iban.updated

Pushed when an IBAN status changes.

{
  "type": "user.iban.updated",
  "data": {
    "safeAddress": "0x…",
    "iban": "FR76…",
    "previousState": "PENDING",
    "newState": "VERIFIED",
    "updatedAt": "2025-08-01T07:36:04.083Z"
  },
  "timestamp": "2025-08-01T07:36:04.083Z"
}

user.ky.updated

Pushed when the KYC status changes.

{
  "type": "user.ky.updated",
  "data": {
    "safeAddress": "0x…",
    "previousKyc": "PENDING",
    "newKyc": "VERIFIED",
    "updatedAt": "2025-08-01T07:36:04.083Z"
  },
  "timestamp": "2025-08-01T07:36:04.083Z"
}

error

Generic error for failed requests.

{
  "type": "error",
  "data": { "message": "Failed to retrieve balance", "context": "balance" },
  "timestamp": "2025-08-01T07:36:04.083Z"
}

Client → server messages

Once authenticated, you can request data on demand.

get_balance

{
  "type": "get_balance",
  "requestId": "optional-correlation-id"
}

Server responds with balance_data. If requestId is provided, it is echoed in data.requestId.

get_transactions

{
  "type": "get_transactions",
  "requestId": "optional-correlation-id",
  "params": {
    "limit": 50,
    "startDate": "2025-01-01",
    "endDate": "2025-12-31"
  }
}
FieldTypeRequiredDescription
typestringYesMust be "get_transactions"
requestIdstringNoEchoed in the response for correlation
params.limitnumberNoMax transactions to return
params.startDatestringNoFilter start date (ISO format)
params.endDatestringNoFilter end date (ISO format)

Server responds with transaction_data.

Keep-alive

The server sends a WebSocket ping every ~30 seconds. Standard clients reply with pong automatically — no action required.

Error handling & reconnection

Close codeMeaningAction
1006Abnormal closureReconnect with backoff
1008Policy violation / invalid JWTRefresh token, then reconnect
1011Server errorWait and reconnect

Recommended reconnection strategy:

let attempts = 0;
 
function reconnect() {
  if (attempts >= 10) {
    console.error('Max attempts reached — falling back to HTTP');
    return;
  }
  const delay = Math.min(1000 * Math.pow(2, attempts), 30000);
  attempts++;
  setTimeout(() => connect(), delay);
}

HTTP fallback

When WebSocket is unavailable, use these REST endpoints with Authorization: Bearer <token>:

PurposeMethodEndpoint
BalancesGET/v1.2/users/me/balances
TransactionsGET/v1.2/users/me/transactions
User dataGET/v1.2/users/me

Pass X-Blockchain-Id: <chainId> header to target a specific chain.

Best practices

  1. Authenticate immediately — send the auth message as soon as onopen fires.
  2. Use clientName — helps identify connections in monitoring and debugging.
  3. Use requestId — correlate on-demand requests with their responses.
  4. Exponential backoff — cap reconnection delay at 30 seconds with a max attempt count.
  5. Clean up — close the socket on logout or when the component unmounts.
  6. Secure connections — always use wss:// in production.