# Create or update site bank account

`PUT /api/configuration/{siteId}/bank-accounts/{eftSystemId}`

- **Success:** `201 Created`
- **Products:** Operator (`FOH`)
- **Features:** Front of House Generic Access (`FOHGENERIC`)

HTML version: [Create or update site bank account](https://support.gladstonesoftware.cloud/reference/configuration/create-or-update-site-bank-account)

## Overview

Records the bank account a site collects money into for one Electronic Funds Transfer (EFT) scheme — the account whose sort code, account number and originator references end up on the direct debit or credit files that scheme generates. An account is identified by the pair `siteId` plus `eftSystemId`, which is unique within your tenant, so a site holds at most one account per scheme.

**Whether the call creates or updates is not yours to choose — it depends on whether an account already exists, and the status code tells you which happened.** No account for that site and scheme yet: the account is created and you get `201` with the `eftSystemId` echoed back as a bare integer. An account already exists: it is overwritten and you get `204` with no body. There is no way to force a create, and no way to make the call fail because the account already exists. Repeating an identical request is therefore safe — the second attempt is an update and changes nothing.

**An update replaces the whole account, so every field you leave out is wiped.** There is no per-field "only if present" handling: an omitted or null string clears the stored value, and `originatorPlusInd` and `processInAuddisRun` are not nullable, so leaving them out writes `0` rather than preserving what was there. Read the current account with [Get site bank account by EFT system id](get-site-bank-accounts-by-eft-system-id.md) and send every value back, including the ones you are not changing.

Checks run in a fixed order and stop at the first failure: the site must exist, then the EFT scheme must exist, then the scheme's own required fields are validated, and only then is the create-or-update decision made. That means a `404` for an unknown site or scheme reaches you before any complaint about the body. After a successful call, subsequent reads of the site's bank accounts show the new values straight away.

Sensitive values are sent in the clear in this request. The account also has encrypted counterparts of the account number, sort code, BIC and IBAN, and this endpoint does not populate them.

## Endpoint

`PUT {base_url}/api/configuration/{siteId}/bank-accounts/{eftSystemId}`

`{base_url}` is the environment URL issued to your integration. See [Authenticating with Gladstone APIs](../../guides/authenticating-with-gladstone-apis.md).

## Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `siteId` | string | Yes | The site whose banking details you are configuring — one half of the pair that identifies the account. Take it from [Get all sites](get-all-sites-with-optional-filtering.md); site codes are at most 15 characters. The site must already exist or the call fails with `404` before the body is looked at. |
| `eftSystemId` | integer (int32) | Yes | The EFT collection scheme this account is used for, and the other half of the pair that identifies the account. Take it from [Get all EFT systems](../payments/get-all-eft-systems.md) — do not hard-code it, since which schemes an operator has is configuration. The value also decides which body fields are compulsory (see Request body below) and, through the scheme's `isBicMandatory` and `showBicIbanForSite` flags, whether `bic` and `iban` are compulsory. An id the operator does not have returns `404`. |

## Request body

Every field is optional as far as request validation is concerned, but the endpoint then applies a required-field rule chosen by `eftSystemId`. A field in that rule fails only if it is **null** — an empty string passes, so you can satisfy the rule with a blank value if you genuinely have nothing to record. The rules, by scheme id:

- `1` BACS direct debit, `10` Swiss bank, `18` Swedish — `name`, `number`, `sortCode`
- `2` AIB, `3` Ulster Bank, `4` National Irish Bank, `5` Bank of Ireland — `name`, `number`, `sortCode`, `userNumber`
- `6` Australian direct debit — `name`, `number`, `sortCode`, `userNumber`, `financialInstitution`
- `7` Dutch guilders, `16` Austrian, `17` Dutch euro — `name`, `number`
- `8` French, `12` Italian — `name`, `number`, `sortCode`, `bankCode`, `userNumber`
- `9` Spanish, `21` Smart Debit, `22` third-party collections — `name`
- `11` German — `name`, `number`, `bankCode`
- `13` BACS credit — `name`, `number`, `sortCode`, `bankCode`, `userNumber`, `merchantNumber`
- `14` Australian credit card — `name`, `number`, `cdtfid`, `merchantNumber`
- `15` Swiss post office — `name`, `number`, `userNumber`
- `19` Belgian francs, `20` Belgian euro — `name`, `number`, `sortCode`, `bankCode`, `userNumber`, `financialInstitution`
- any other id — `name`, `number`

A breach returns `400` with the plain-text message `Property {PropertyName} cannot be null`, using the property name in PascalCase (`SortCode`, `UserNumber`, `BankCode`, `MerchantNumber`, `FinancialInstitution`, `Cdtfid`, `Name`, `Number`) rather than the JSON name.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `bankCode` | string | No | The bank identifier the scheme uses to route the file, distinct from the sort code — required by the French, Italian, German, BACS credit and Belgian schemes, and ignored by the rest. Maximum 5 characters. Omitting it on an update clears the stored value. |
| `cdtfid` | string | No | The CDTF identifier, required only by the Australian credit card scheme (`eftSystemId` `14`) and unused by every other scheme. Maximum 3 characters. |
| `financialInstitution` | string | No | The financial institution code carried on the collection file, required by the Australian direct debit and Belgian schemes. Maximum 3 characters. |
| `merchantNumber` | string | No | The merchant or vendor number the acquiring bank has given the operator for this account. Required by the BACS credit (`13`) and Australian credit card (`14`) schemes. Maximum 10 characters. |
| `name` | string | No | The account name as it should appear on the collection file and in staff-facing configuration. Required by every scheme — it is the one field in all of the rules above, including the fallback for unrecognised scheme ids. Maximum 25 characters. |
| `number` | string | No | The bank account number for the site, sent unencrypted and stored as given. Required by every scheme except Spanish (`9`), Smart Debit (`21`) and third-party collections (`22`). Maximum 8 characters, so an account number longer than 8 characters cannot be recorded through this endpoint. |
| `originatorPlusInd` | integer (int32) | No | Whether this account is an Originator Plus arrangement: `0` no, `1` yes. It applies only to the Bank of Ireland scheme (`eftSystemId` `5`); other schemes ignore it. It must be an integer between 0 and 255 — anything else is rejected with `400`. It is not nullable, so omitting it writes `0`, which on an update overwrites whatever was set before. |
| `processInAuddisRun` | integer (int32) | No | Whether this account is included when the AUDDIS run is processed — the automated lodgement of direct debit instructions with the banks: `0` no, `1` yes. Not nullable, so omitting it writes `0` and, on an update, turns the flag off. |
| `sortCode` | string | No | The sort code (or the local equivalent branch identifier) of the site's account, sent unencrypted. Required by most schemes — see the list above; the German, Australian credit card, Dutch, Austrian, Swiss post office, Spanish, Smart Debit and third-party collection schemes do not ask for it. Maximum 6 characters, so a longer international branch code will not fit. |
| `userNumber` | string | No | The originator or service user number the scheme has issued to the operator, identifying who is collecting the money. Required by the Irish, Australian direct debit, French, Italian, BACS credit, Swiss post office and Belgian schemes. Maximum 6 characters. |
| `bic` | string | No | The BIC (SWIFT code) of the site's bank. Independent of the per-scheme list above: it is compulsory whenever the EFT scheme has `isBicMandatory` set to `true` in [Get all EFT systems](../payments/get-all-eft-systems.md), and sending null in that case fails with `400` and `Property Bic cannot be null`. Maximum 25 characters. Where the scheme does not mandate it, omit it — but remember that omitting it on an update clears the stored value. |
| `iban` | string | No | The IBAN of the site's account. Compulsory only when the scheme has both `showBicIbanForSite` and `isBicMandatory` set to `true`; sending null then fails with `400` and `Property Iban cannot be null`. Maximum 50 characters. As with `bic`, an omitted value on an update blanks the stored value rather than leaving it alone. |

## Sample request

```bash title="cURL"
curl -X PUT '{base_url}/api/configuration/{siteId}/bank-accounts/{eftSystemId}' \
  -H 'Authorization: Bearer {accessToken}' \
  -H 'X-Use-SSO: true' \
  -H 'Content-Type: application/json' \
  -d '{
  "bankCode": "string",
  "cdtfid": "string",
  "financialInstitution": "string",
  "merchantNumber": "string",
  "name": "string",
  "number": "string",
  "originatorPlusInd": 1,
  "processInAuddisRun": 1,
  "sortCode": "string",
  "userNumber": "string",
  "bic": "string",
  "iban": "string"
}'
```

## Sample response

A create returns `201` whose body is the `eftSystemId` from the path repeated back as a bare integer — it tells you nothing you did not already send, so use the status code, not the body, to work out whether the account was created. An update returns `204` with no body at all.

```json title="201 Created"
1
```

## Errors

| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad request | A field required by the scheme in the path was sent as null — the body is the plain-text message `Property {PropertyName} cannot be null`. Note that this is a null check only, so an empty string is accepted. |
| `400` | Bad request | The scheme has `isBicMandatory` set and `bic` was null (`Property Bic cannot be null`), or it also has `showBicIbanForSite` set and `iban` was null (`Property Iban cannot be null`). |
| `400` | Bad request | Request validation rejected the body before any other check: a string longer than its limit (`bankCode` 5, `cdtfid` 3, `financialInstitution` 3, `merchantNumber` 10, `name` 25, `number` 8, `sortCode` 6, `userNumber` 6, `bic` 25, `iban` 50), or a value for `originatorPlusInd` or `processInAuddisRun` that is not a valid integer — `originatorPlusInd` accepts 0 to 255 only. The body is a validation problem document (`application/problem+json`) with an `errors` map keyed by field name, not the plain-text form above. |
| `404` | Not found | The site does not exist — `Site with id {siteId} was not found`. Checked first, before the scheme and before the body. |
| `404` | Not found | The EFT scheme does not exist for this operator — `Eft System with id {eftSystemId} was not found`. Note there is no `404` for a missing bank account: if none exists, one is created. |
| `500` | Internal server error | An unexpected server-side failure while reading or saving the account, including a value the platform cannot store. The response body is empty, so you will need Gladstone support to find out what happened. |
