# Accounts API

Base URL: `https://interact-uat.hsbc.com/accounts-service`

### POST /v1/account-balances

**List account balances**

Same behaviour as `GET /v1/account-balances`, except the entitled-account list is supplied in the JSON body instead of the `X-HSBC-Entitled-Accounts` header (avoids header size limits), plus an optional `requestedAccountIds` selection.

###### Headers
* Auth: exactly one of `Authorization: Bearer`, `neosession` cookie or `X-Neo-Session`.
* `x-hsbc-channel-id: nio-api` **and** `x-hsbc-custid` are **mandatory** for B2B (Bearer-token) callers; cookie-authenticated (C2B) callers may omit both.
* `hsbc-correlation-id` — optional, numeric only.
* The header `X-HSBC-Entitled-Accounts` is **ignored** by this operation — use the body instead.

###### Body
The body is technically optional (`{}` or no body → empty entitled list), but omitting `entitledAccounts` (or supplying only unusable entries) will return no bank-account balances, so it should be treated as **mandatory** for a meaningful response. Parsing rules :
* Malformed JSON → `400 Invalid request payload`.
* `entitledAccounts` — recommended/mandatory array; entries without `unFmtdAccNo` are skipped, other properties default to `""`.
* `requestedAccountIds` — optional; must be an **array of strings**, each trimmed, upper-cased and stripped of spaces/`-`/`/`, then matched against `[A-Z0-9]{1,128}`. The list must be non-empty, ≤ 100 entries and unique, otherwise `400`.

Requires authentication: **bearerAuth** (header) or **neosessionCookie** (cookie) or **neoSessionHeader** (header)


#### Parameters

| Name | In | Type | Description |
|---|---|---|---|
| `filter` | query | string | Optional. all (or omitted) returns every account. Any other value returns only accounts that have a non-empty interimAvailableAmount. The value is compared case-insensitively. |
| `fields` | query | string | Optional. Comma-separated list of additional field names to include. Prefix with ~ for derived fields (e.g. ~soloDisplayBalanceAmountFXAdjusted). Unsupported derived fields are ignored. Unknown names return 400. All identity fields allowed on /v1/accounts are also supported here. Additional balance-specific fields: currentAvailableBalance, currentAvailableBalanceDate, currentAvailableBalanceWithCF, currentAvailableBalanceWithCFDate, currentBookedBalance, currentBookedBalanceDate, currentBookedBalanceWithCF, currentBookedBalanceWithCFDate, projectedAvailableBalance, projectedAvailableBalanceDate, projectedAvailableBalanceWithCF, projectedAvailableBalanceWithCFDate, projectedBookedBalance, projectedBookedBalanceDate, projectedBookedBalanceWithCF, openingAvailableBalance, openingAvailableBalanceDate, openingAvailableBalanceWithCF, openingBookedBalance, openingBookedBalanceDate, openingBookedBalanceWithCF, balanceAsAt Derived fields: ~soloDisplayBalanceAmountFXAdjusted |
| `fx_target_currency` | query | string | Optional (conditionally required). ISO 4217 target currency for FX conversion; only used when the ~soloDisplayBalanceAmountFXAdjusted derived field is requested. |
| `hsbc-correlation-id` | header | string | Optional. Correlation ID for end-to-end tracing. Honoured only when non-blank and fully numeric; anything else is replaced by a generated timestamp-based ID. Forwarded upstream as x-hsbc-request-correlation-id. |
| `x-hsbc-channel-id` | header | string *(required)* | Mandatory for B2B (nio-api) callers. Must be nio-api and be accompanied by a non-blank x-hsbc-custid for the B2B customer override to apply. When it applies, the service forces the nio-api TPID and forwards x-hsbc-channel-id: NEO upstream. Only cookie-based (C2B, neosession) callers may omit this header — the inbound value is otherwise forwarded upstream as-is. |
| `x-hsbc-custid` | header | string *(required)* | Mandatory for B2B (nio-api) callers. Customer ID to query, used instead of the session subject when x-hsbc-channel-id is nio-api. Header names are case-insensitive, so X-HSBC-CustId is equivalent. Without it a B2B Bearer call falls back to the token subject (a profile ID) and will typically return no accounts. Only cookie-based (C2B, neosession) callers may omit this header. |


#### Request body

Content type: `application/json`

| Field | Type | Description |
|---|---|---|
| `entitledAccounts` | array *(required)* | Mandatory for a non-empty response. Entitled accounts to query. An empty or omitted array returns no bank-account balances. Entries without unFmtdAccNo are silently skipped. |
| `requestedAccountIds` | array | Optional. Narrows the returned accounts. Values are trimmed, upper-cased and have spaces, - and / removed before validation against [A-Z0-9]{1,128}. Must be a non-empty array of 1-100 unique strings, otherwise 400. |


#### Responses

- **200** — Account balances retrieved successfully
- **400** — Invalid request. Returned as JSON for unknown fields values, an invalid JSON body or invalid requestedAccountIds. Exception: when both a neosession token and an Authorization header are supplied, the session security check aborts with text/plain Ambiguous authentication credentials.
- **401** — Missing or invalid credentials. * Rejected by the session security check → text/plain body 401 Unauthorized with WWW-Authenticate: Bearer. * Upstream 401 while fetching accounts/cards → JSON envelope with message UnAuthorized Access.
- **429** — Too many requests. The caller has exceeded the rate limit for this endpoint.
- **500** — Unexpected server error. The upstream/exception message and a generated errorId are returned in the envelope.
- **403** — Forbidden — insufficient permissions for this resource


#### Examples

```bash
curl -X POST "https://interact-uat.hsbc.com/accounts-service/v1/account-balances?filter=all&fields=bic,currentAvailableBalance,projectedAvailableBalance,balanceAsAt,~soloDisplayBalanceAmountFXAdjusted&fx_target_currency=USD" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "hsbc-correlation-id: 1234567890" \
  -H "x-hsbc-channel-id: nio-api" \
  -H "x-hsbc-custid: GBHBEUNEOTEST" \
  -H "Content-Type: application/json" \
  -d '{ ... }'
```

```javascript
const response = await fetch("https://interact-uat.hsbc.com/accounts-service/v1/account-balances?filter=all&fields=bic,currentAvailableBalance,projectedAvailableBalance,balanceAsAt,~soloDisplayBalanceAmountFXAdjusted&fx_target_currency=USD", {
  method: "POST",
  headers: {
      "Authorization": "Bearer YOUR_TOKEN",
      "hsbc-correlation-id": "1234567890",
      "x-hsbc-channel-id": "nio-api",
      "x-hsbc-custid": "GBHBEUNEOTEST"
  },
  body: JSON.stringify({ /* ... */ }),
});

const data = await response.json();
```

```python
import requests

url = "https://interact-uat.hsbc.com/accounts-service/v1/account-balances?filter=all&fields=bic,currentAvailableBalance,projectedAvailableBalance,balanceAsAt,~soloDisplayBalanceAmountFXAdjusted&fx_target_currency=USD"
headers = {
    "Authorization": "Bearer YOUR_TOKEN",
    "hsbc-correlation-id": "1234567890",
    "x-hsbc-channel-id": "nio-api",
    "x-hsbc-custid": "GBHBEUNEOTEST",
}

response = requests.post(url, headers=headers, json={
    # ...
})
print(response.json())
```

```java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://interact-uat.hsbc.com/accounts-service/v1/account-balances?filter=all&fields=bic,currentAvailableBalance,projectedAvailableBalance,balanceAsAt,~soloDisplayBalanceAmountFXAdjusted&fx_target_currency=USD"))
    .header("Authorization", "Bearer YOUR_TOKEN")
    .header("hsbc-correlation-id", "1234567890")
    .header("x-hsbc-channel-id", "nio-api")
    .header("x-hsbc-custid", "GBHBEUNEOTEST")
    .POST(HttpRequest.BodyPublishers.ofString("{ ... }"))
    .build();

HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
```

#### Example response

```json
{
  "data": {
    "accountBalances": [
      {
        "institutionCode": "HBUK",
        "unformattedAccountNumber": "12345678",
        "countryCode": "GB",
        "accountType": "CA",
        "accountName": "HSBC CURRENT ACCOUNT",
        "currencyCode": "GBP",
        "availableAmount": "+10000.00",
        "interimAvailableAmount": "+10000.00",
        "interimBookedAmount": "+9500.00",
        "soloDisplayBalanceAmount": "+10000.00",
        "combinedCashBalanceAmount": "+10000.00",
        "formattedAccountNumber": "40-22-20 12345678",
        "accountId": "GBP-001234",
        "soloDisplayFXBalanceAmount": "+12750.00",
        "fxCurrencyCode": "USD"
      }
    ]
  },
  "meta": {
    "success": true,
    "message": "Accounts retrieved successfully",
    "status": 200,
    "timestamp": "2026-08-27T09:00:00.123Z"
  }
}
```

