# Update a bank rule

Operation ID: `updateBankRule`

Group: Banking › Bank Rules

[Open in the interactive reference](https://docs.api.lensing.ai/lensing/v1/endpoints/updateBankRule)

`PATCH /banking/bank-rules/{id}`

Retry-safe: A write that accepts Idempotency-Key: repeating a request with the same key replays the stored answer instead of executing twice.

Updates a bank rule with the fields you send. `bankAccountIds` and `criteria` are the exception: each is replaced as a whole when sent, so send the complete list. A bank account or criterion left out is removed. In `actionObject`, only the fields you send are changed, and a field left out keeps its current value.

The checks that apply on create also apply to the new values. A new action must fit the rule's bank accounts, new bank accounts must fit the rule's action, and a new name must be unique.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `Api-Version` | header | string · v1 | yes | The API version this request targets, named by its public identifier. Required on every request; omitting it, or naming a version this company does not have, is answered with 400. This document describes version `v1`. |
| `Idempotency-Key` | header | string | no | An opaque caller-chosen string (1-255 characters) that makes this request safe to retry. Repeating the same key with an identical request body replays the original response instead of re-executing - but only once that original request succeeded; a failed attempt re-executes on retry. Repeating the key with a different body is answered with 422. A key still in flight is answered with 409 - as is a key whose original request was interrupted before it finished, for a few minutes afterwards, until that attempt is presumed dead. A completed response stays replayable for 24 hours. The key is scoped to the caller, not to the action: reusing it for a different action is answered with 409 or 422 rather than treated independently. On read actions this header is ignored. On write actions that cannot offer the guarantee it is answered with `400 IDEMPOTENCY_NOT_SUPPORTED` rather than silently ignored. |
| `id` | path | string | yes | The unique identifier of the bank rule you want to update. Example: `"9f2c6a10-7d34-4c8e-9b21-5a0f3e6d81b7"`. |

## Request body

Required, `application/json`: updateBankRuleInput.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `rule` | string | no | The name of the bank rule. Must be unique within the tenant. |
| `action` | any | no | New action. Only these three are implemented. Omit to leave unchanged. One of: `"createBankEntry"`, `"createCreditCardEntry"`, `"createFundTransfer"`. |
| `status` | any | no | The status of the rule. Accepted values: 'active' (the rule runs whenever bank rules run), 'inactive' (the rule is kept but does not run). Set to 'inactive' to stop a rule running without deleting it. One of: `"active"`, `"inactive"`. Example: `"inactive"`. |
| `priority` | number | no | The order in which this rule runs relative to other rules. Lower numbers run first. Example: `20`. |
| `description` | string | no | A description of the rule. |
| `bankAccountIds` | array<string> | no | The bank accounts or credit card accounts this rule applies to. Replaces the whole current list when sent. At least one is required. They must all belong to the same legal entity, and must be all bank accounts or all credit card accounts, not a mix. See id on GET banking/bank-accounts/:id. |
| `criteria` | array<object> | no | The conditions a bank transaction must meet. Replaces the whole current list when sent, so a criterion left out is deleted. At least one is required. |
| `criteria[].criteria` | any | yes | The bank transaction field this criterion tests. Accepted values: 'amount' (the signed transaction amount, negative for money out), 'description' (the description as the bank supplied it), 'payeePayor' (the name of the counterparty). One of: `"amount"`, `"description"`, `"payeePayor"`. |
| `criteria[].operator` | string | yes | How the field is compared with value. When criteria is 'amount', use 'equal', 'notEqual', 'greaterThan', 'greaterThanOrEqual', 'lessThan' or 'lessThanOrEqual'. When criteria is 'description' or 'payeePayor', use 'is', 'isNot', 'contains' or 'doesNotContain', which are case-sensitive, or 'isCaseInsensitive', 'isNotCaseInsensitive', 'containsCaseInsensitive' or 'doesNotContainCaseInsensitive'. |
| `criteria[].logicalOperator` | any | no | How this criterion combines with the next one. Accepted values: 'and', 'or'. Defaults to 'and'. Ignored on the last criterion. Consecutive criteria joined by the same operator form a group, and groups are always combined with 'and'. For example, A or B, and C matches (A or B) and C, while A and B, or C matches A and B and C. Ignored when criteriaGroups is sent. One of: `"and"`, `"or"`. |
| `criteria[].value` | string | yes | The value the field is compared with. Cannot be empty. When criteria is 'amount', send a number, for example '-250.00'. Otherwise, send text. |
| `criteria[].groupKey` | string | no | The key of the criteria group this criterion belongs to. See key on criteriaGroups. Required when criteriaGroups is sent, and left out otherwise. |
| `criteriaGroups` | array<object> | no | Optional nested AND/OR groups for the criteria. When sent, criteria must be sent too, and both replace the rule's current criteria and groups. When sent, exactly one group has no parentKey and is the root, every criterion names its group in groupKey, and each group combines its criteria and child groups with its own logicalOperator. For example, (A and B) or C is a root 'or' group holding C and a child 'and' group holding A and B. When left out, criteria are combined using logicalOperator on each criterion. |
| `criteriaGroups[].key` | string | yes | A key you choose for the group, unique within this request. Criteria refer to it in groupKey and child groups in parentKey. |
| `criteriaGroups[].parentKey` | string | no | The key of the parent group. Left out for the root group. |
| `criteriaGroups[].logicalOperator` | any | yes | How the group combines its criteria and child groups. Accepted values: 'and', 'or'. One of: `"and"`, `"or"`. |
| `actionObject` | object | no | The values for the bank entry or credit card entry the rule creates. Only the fields you send are changed. A field left out keeps its current value. |
| `actionObject.accountId` | string | no | The account each bank entry or credit card entry posts to. It must not be a grouping account. See id on GET accounting/accounts/:id. |
| `actionObject.name` | string | no | The name given to each bank entry or credit card entry. |
| `actionObject.description` | string | no | The description set on each bank entry or credit card entry and on its line. |
| `actionObject.billableExpense` | any | no | Marks the line of each credit card entry as a billable expense when 'yes'. Accepted values: 'yes', 'no'. Applies only to rules with the action 'createCreditCardEntry'. One of: `"yes"`, `"no"`. |
| `actionObject.businessUnitId` | string | no | The business unit set on each bank entry or credit card entry. |
| `actionObject.departmentId` | string | no | The department set on each bank entry or credit card entry. |
| `actionObject.customerId` | string | no | The customer set on each credit card entry. Use only when billableExpense is 'yes'. Not applied to bank entries. See id on GET accounting/customers/:id. |
| `actionObject.vendorId` | string | no | A vendor to save on the rule. It is not applied to bank entries or credit card entries. See id on GET accounting/vendors/:id. |
| `actionObject.intercompanyPartnerId` | string | no | The intercompany partner set on each bank entry or credit card entry. Applied only when accountId is an elimination account, and ignored otherwise. No endpoint returns intercompany partners. |
| `actionObject.valueAllocationTags` | array<string> | no | The value allocation tag codes set on each bank entry or credit card entry. A tag is applied only while value allocation tags are turned on and its dimension is enabled for that type of entry. |
| `actionObject.fromAccountId` | string | no | [fk: AccountApi.accounts.id] createFundTransfer only. Source cash account of the transfer, given as its id (a UUID). |
| `actionObject.toAccountId` | string | no | [fk: AccountApi.accounts.id] createFundTransfer only. Destination cash account of the transfer, given as its id (a UUID). Required for createFundTransfer. Must differ from fromAccountId. |
| `actionObject.fromLineDescription` | string | no | createFundTransfer only. Description stamped on the transfer's From line. |
| `actionObject.toLineDescription` | string | no | createFundTransfer only. Description stamped on the transfer's To line. |
| `actionObject.intercompanyProcessId` | string | no | [fk: IntercompanyProcessApi.intercompanyProcesses.id] createFundTransfer only, given as its id (a UUID). Required when the two accounts belong to different legal entities. |
| `actionObject.transferReason` | any | no | createFundTransfer only. Required when the two accounts belong to different legal entities. One of: `"funding"`, `"repayment"`. |
| `actionObject.intercompanyTransactionalCurrency` | string | no | createFundTransfer only. Currency the intercompany balance is carried in. Required when the two accounts belong to different legal entities. |
| `actionObject.fromFeeToleranceType` | any | no | createFundTransfer only. Whether the sending-side bank fee tolerance is read as a percentage or a fixed amount. One of: `"percentage"`, `"fixedAmount"`. |
| `actionObject.fromFeeToleranceValue` | decimal | no | createFundTransfer only. Sending-side tolerance; a shortfall up to this much is booked as a bank fee, beyond it the two transactions are not paired. Left unset, the amounts must match exactly. |
| `actionObject.toFeeToleranceType` | any | no | createFundTransfer only. Whether the receiving-side bank fee tolerance is read as a percentage or a fixed amount. One of: `"percentage"`, `"fixedAmount"`. |
| `actionObject.toFeeToleranceValue` | decimal | no | createFundTransfer only. Receiving-side tolerance; a shortfall up to this much is booked as a bank fee, beyond it the two transactions are not paired. Left unset, the amounts must match exactly. |

```json
{
  "rule": "<rule>",
  "action": "createBankEntry",
  "status": "inactive",
  "priority": 20,
  "description": "<description>",
  "bankAccountIds": [
    "<bankAccountIds>"
  ],
  "criteria": [
    {
      "criteria": "amount",
      "operator": "<operator>",
      "logicalOperator": "and",
      "value": "<value>",
      "groupKey": "<groupKey>"
    }
  ],
  "criteriaGroups": [
    {
      "key": "<key>",
      "parentKey": "<parentKey>",
      "logicalOperator": "and"
    }
  ],
  "actionObject": {
    "accountId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "name": "<name>",
    "description": "<description>",
    "billableExpense": "yes",
    "businessUnitId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "departmentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "vendorId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "intercompanyPartnerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "valueAllocationTags": [
      "<valueAllocationTags>"
    ],
    "fromAccountId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "toAccountId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "fromLineDescription": "<fromLineDescription>",
    "toLineDescription": "<toLineDescription>",
    "intercompanyProcessId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "transferReason": "funding",
    "intercompanyTransactionalCurrency": "<intercompanyTransactionalCurrency>",
    "fromFeeToleranceType": "percentage",
    "fromFeeToleranceValue": "19.99",
    "toFeeToleranceType": "percentage",
    "toFeeToleranceValue": "19.99"
  }
}
```

## Response

`200` Success

```json
{
  "data": {},
  "diagnostics": [
    {
      "code": "<code>",
      "message": "<message>",
      "severity": "error",
      "path": [
        "<path>"
      ],
      "details": "<details>"
    }
  ]
}
```

## Response headers

- `Idempotency-Replayed` — Present and `true` only when this response replays a previously stored one for the same Idempotency-Key, rather than reflecting a live execution. Absent on a live response - never sent as `false`.

## Errors

| Code | Status |
| --- | --- |
| `NOT_FOUND` | 400 |
| `REFERENCE_NOT_FOUND` | 400 |
| `ACCOUNTS_REQUIRED` | 400 |
| `CRITERIA_REQUIRED` | 400 |
| `ACCOUNTS_SPAN_ENTITIES` | 400 |
| `MIXED_ACCOUNT_TYPES` | 400 |
| `ACTION_ACCOUNT_TYPE_MISMATCH` | 400 |
| `RULE_ACTION_NOT_SUPPORTED` | 400 |
| `DUPLICATE_RULE_NAME` | 400 |
| `INVALID_FUND_TRANSFER` | 400 |
| `INVALID_CRITERIA` | 400 |
| `ACCOUNT_NOT_POSTABLE` | 400 |
| `IDEMPOTENCY_KEY_CONFLICT` | 409 |
| `IDEMPOTENCY_PAYLOAD_MISMATCH` | 422 |

## Statuses

- `400` — Invalid request or business failure. Codes: NOT_FOUND, REFERENCE_NOT_FOUND, ACCOUNTS_REQUIRED, CRITERIA_REQUIRED, ACCOUNTS_SPAN_ENTITIES, MIXED_ACCOUNT_TYPES, ACTION_ACCOUNT_TYPE_MISMATCH, RULE_ACTION_NOT_SUPPORTED, DUPLICATE_RULE_NAME, INVALID_FUND_TRANSFER, INVALID_CRITERIA, ACCOUNT_NOT_POSTABLE
- `401` — The request carries no valid access token.
- `403` — Not authorized
- `404` — Not found
- `409` — The Idempotency-Key is still being processed by another request.
- `422` — The Idempotency-Key was already used with a different request payload.
- `429` — Too many requests from this client address. The response has no body and no `Retry-After` header.
- `500` — Internal server error
