---
title: "Partially update account interest [Beta]"
method: PATCH
path: "/v1/interest/account/{accountId}"
tags: ["Account interest"]
---

# Partially update account interest \[Beta\]

`PATCH /v1/interest/account/{accountId}`

## Request

- Base URL: `https://sandbox.pismolabs.io/interest-engine`
- URL: `https://sandbox.pismolabs.io/interest-engine/v1/interest/account/{accountId}`
- Auth: HTTP bearer

Record an effective-dated change to the interest configuration of an account. Send only the interest parameters you want to change, together with the date on which the change takes effect. The change is appended to the account's history of configuration changes, which you can retrieve with [Get account interest](ref:get-v1-interest-account).

Key features:
- Updates only the provided parameters. A parameter that is omitted is left untouched, and a parameter sent as `null` clears the account-level value so the interest plan value applies.
- Applies from `effective_date` and, optionally, up to `end_date`. After `end_date`, the configuration that applied before the change takes effect again.
- Allows overlapping changes. For each parameter, the most recently created change that covers a date determines the value that applies on that date.
- Validates the resulting configuration for every date from today onward and rejects the request with `400` when it is invalid.
- Rejects requests that contain no interest parameter, only dates and `metadata`.

Once an account has a configuration change, `PUT /v1/interest/account/{accountId}` is rejected for that account with `409`.

**Account identification.** The token identifies the account. Exactly one of `x-account-id` or `x-external-account-id` must be passed and must match the `{accountId}` path parameter. Otherwise the request is rejected (`403` on a mismatch or when neither header is passed, `400` when both are).

**Stored identifiers.** Which identifiers are stored follows the header used:

- `x-account-id`: An Accounts API call confirms the account ID exists, then `account_id` is stored with the change.
- `x-external-account-id`: A Corporate API call resolves the external account ID to a Pismo `account_id`, and both IDs are stored with the change.

If the Accounts or Corporate API cannot resolve the identifier the request fails with `400` and nothing is persisted. Any other failure of those APIs fails with `500`.

**Idempotency.** If a change was already recorded with the same `x-cid` for the organization, the request succeeds without recording a second change.

When a new change is recorded, the endpoint publishes an `interest_account_update_success` event.

## Path parameters

- `accountId` string, required

## Request body

- InterestAccountPatchRequest: Request body for `PATCH /v1/interest/account/{accountId}`. The endpoint records an effective-dated change to the interest configuration of the account. Changes are appended to the account's history, and earlier changes are never modified or deleted. Send only the interest parameters you want to change. At least one is required: - A parameter that is omitted is left untouched by this change. - A parameter sent as `null` clears the account-level value, so the value from the associated interest plan applies. - `tax_withholding` and `interest_by_tiers` are replaced as a whole. Their fields are not merged with the values of earlier changes. `effective_date` is required. A request that contains only `effective_date`, `end_date`, and `metadata`, or an empty `tax_withholding` object, is rejected with `400 Bad Request`. Changes can overlap. For each interest parameter, the most recently created change that covers a given date determines the value that applies on that date. The configuration that results from the change is validated for every date from today onward, using the same rules as `PUT /v1/interest/account/{accountId}`: - **Interest type**: With `benchmark` and `margin_rate`, `margin` is optional and `fixed_interest_rate` must be omitted. With `fixed_interest_rate`, `benchmark`, `margin_rate`, and `margin` must be omitted. When `fixed_interest_rate` is sent without `benchmark`, the change is stored with `benchmark` set to `FIXED`. - **Tax withholding**: With `withholding_moment` set to `ACCRUAL`, `fee_processing_code` is required and `tax_rules` must be omitted. With `CAPITALIZATION`, `tax_rules` is required and `fee_processing_code` must be omitted. - **Tax exemption**: When `taxes_exemption` is `true`, `tax_withholding` must be null. `fixed_interest_rate`, `margin_rate`, and `margin` must be positive, and are stored and returned with 8 decimal places.
  - `benchmark` 'BOE' | 'DI' | 'FED' | 'RBA' | 'RBI' | 'TO': Market index used to measure interest value over time. For fixed interest, this field must be null. - `BOE`: Bank of England, UK - `DI`: Interbank Deposit Contract, Brazil - `FED`: Federal Reserve System, USA - `RBA`: Reserve Bank of Australia - `RBI`: Reserve Bank of India - `TO`: Overnight Interbank Target Rate (Tasa Objetivo), Mexico
  - `fixed_interest_rate` number, float, nullable: Nominal annual interest rate, expressed as a decimal fraction. 0.10 = 10% per year. 1.00 = 100% per year. Do not send 10 for 10%. Maximum precision: 8 decimal places. The platform converts this annual rate to the accrual period using `accrual_basis` and `interest_type`. If you pass a value for `benchmark`, this field must be null. Otherwise, it's required.
  - `margin_rate` number, double, nullable: Multiplier applied to the benchmark rate, expressed as a decimal fraction of 100%. 1.00 = 100% of the benchmark. 1.10 = 110% of the benchmark. 0.95 = 95% of the benchmark. This is not added to the benchmark—use `margin` for an additive spread. If you don't pass a value for `benchmark`, this field must be null. Otherwise, it's required.
  - `margin` number, double: Additive spread, in the same unit and period as the benchmark rate: nominal annual, decimal fraction. If `benchmark` is 0.025 and `margin` is 0.0225, the resulting annual rate is 0.0475. If you pass a value for `benchmark`, this field is optional. If `benchmark` is null, this field must be null also.
  - `taxes_exemption` boolean: Is the account exempt from taxes?
  - `tax_withholding` TaxWithholding: Tax withholding configuration. Replaces the standalone `fee_processing_code` field. Conditional rules enforced at creation/update time: - `ACCRUAL`: `fee_processing_code` is required; `tax_rules` must be omitted. - `CAPITALIZATION`: `tax_rules` is required; `fee_processing_code` must be omitted. - Omitted `withholding_moment`: both `fee_processing_code` and `tax_rules` must be omitted. In GET responses, legacy plans that predate this field may return `fee_processing_code` with a null `withholding_moment`.
    - `withholding_moment` 'ACCRUAL' | 'CAPITALIZATION', required: Moment at which tax is withheld. When omitted, no withholding applies.
    - `fee_processing_code` string: Processing code configured in the [fee model](doc:fee-model) for charging a tax, penalty, or fee.
    - `tax_rules` TaxRule[]
      - `description` string, required: Description of the tax rule.
      - `fixed_percentage` number, required: Fixed percentage applied by the tax rule.
      - `threshold_amount` number, double, nullable: Optional monetary threshold amount associated with the tax rule. Use null when the rule does not depend on a threshold.
  - `interest_by_tiers` InterestByTiers: Interest by tiers configuration
    - `type` 'TERM' | 'AMOUNT', required: Interest type - `TERM`: Interest rate varies according to the period of time since the deposit was made. - `AMOUNT`: Interest rate varies according to the current balance.
    - `tier_calculation` 'RETROACTIVE' | 'NON-RETROACTIVE', required: Tier calculation method - `RETROACTIVE`: Interest is recalculated from the beginning based on the new applicable rate. - `NON-RETROACTIVE`: Interest is calculated progressively based on each layer rate.
    - `tiers` InterestByTiersArrayObject[], required
      - `days` integer, nullable: Number of days in `interest_by_tier`
      - `amount` number, double, nullable: Amount in the `interest_by_tier`
      - `margin_rate` number, double, nullable: Multiplier applied to the benchmark rate, expressed as a decimal fraction of 100%. 1.00 = 100% of the benchmark. 1.10 = 110% of the benchmark. 0.95 = 95% of the benchmark. This is not added to the benchmark—use `margin` for an additive spread. If you don't pass a value for `benchmark`, this field must be null. Otherwise, it's required.
      - `fixed_interest_rate` number, float, nullable: Nominal annual interest rate, expressed as a decimal fraction. 0.10 = 10% per year. 1.00 = 100% per year. Do not send 10 for 10%. Maximum precision: 8 decimal places. The platform converts this annual rate to the accrual period using `accrual_basis` and `interest_type`. If you pass a value for `benchmark`, this field must be null. Otherwise, it's required.
  - `capitalization_frequency` 'DAILY' | 'MONTHLY' | 'QUARTERLY' | 'HALF_YEARLY' | 'YEARLY' | 'MATURITY': Interest payout frequency
  - `effective_date` string, date, required: First day on which the change applies. Format = YYYY-MM-DD.
  - `end_date` string, date, nullable: Last day on which the change applies, inclusive. After this day, the configuration that applied before the change takes effect again. When omitted or `null`, the change has no end date. Must be equal to or greater than `effective_date`. Format = YYYY-MM-DD.
  - `metadata` Metadata: Free-form key-value data to store with the change. The serialized JSON can be at most 4096 bytes. When omitted, an empty object is stored and returned.

## Response `200`

OK

- ConfigurationChange: A single effective-dated change recorded for the interest configuration of an account.
  - `interest_parameters` InterestParameters, required: Interest parameters recorded by a configuration change, as sent in the `PATCH` request. Only the parameters that were present in the request are included. A parameter that was sent as `null` is returned as `null`, meaning the change cleared the account-level value and the value from the associated interest plan applies. `fixed_interest_rate`, `margin_rate`, and `margin` are returned with 8 decimal places.
    - `benchmark` 'BOE' | 'DI' | 'FED' | 'FIXED' | 'RBA' | 'RBI' | 'TO': Market index returned in responses. - `BOE`: Bank of England, UK - `DI`: Interbank Deposit Contract, Brazil - `FED`: Federal Reserve System, USA - `FIXED`: Fixed interest rate, no market index - `RBA`: Reserve Bank of Australia - `RBI`: Reserve Bank of India - `TO`: Overnight Interbank Target Rate (Tasa Objetivo), Mexico
    - `fixed_interest_rate` number, float, nullable: Nominal annual interest rate, expressed as a decimal fraction. 0.10 = 10% per year. 1.00 = 100% per year. Do not send 10 for 10%. Maximum precision: 8 decimal places. The platform converts this annual rate to the accrual period using `accrual_basis` and `interest_type`. If you pass a value for `benchmark`, this field must be null. Otherwise, it's required.
    - `margin_rate` number, double, nullable: Multiplier applied to the benchmark rate, expressed as a decimal fraction of 100%. 1.00 = 100% of the benchmark. 1.10 = 110% of the benchmark. 0.95 = 95% of the benchmark. This is not added to the benchmark—use `margin` for an additive spread. If you don't pass a value for `benchmark`, this field must be null. Otherwise, it's required.
    - `margin` number, double: Additive spread, in the same unit and period as the benchmark rate: nominal annual, decimal fraction. If `benchmark` is 0.025 and `margin` is 0.0225, the resulting annual rate is 0.0475. If you pass a value for `benchmark`, this field is optional. If `benchmark` is null, this field must be null also.
    - `taxes_exemption` boolean: Is the account exempt from taxes?
    - `tax_withholding` TaxWithholding: Tax withholding configuration. Replaces the standalone `fee_processing_code` field. Conditional rules enforced at creation/update time: - `ACCRUAL`: `fee_processing_code` is required; `tax_rules` must be omitted. - `CAPITALIZATION`: `tax_rules` is required; `fee_processing_code` must be omitted. - Omitted `withholding_moment`: both `fee_processing_code` and `tax_rules` must be omitted. In GET responses, legacy plans that predate this field may return `fee_processing_code` with a null `withholding_moment`.
      - `withholding_moment` 'ACCRUAL' | 'CAPITALIZATION', required: Moment at which tax is withheld. When omitted, no withholding applies.
      - `fee_processing_code` string: Processing code configured in the [fee model](doc:fee-model) for charging a tax, penalty, or fee.
      - `tax_rules` TaxRule[]
        - `description` string, required: Description of the tax rule.
        - `fixed_percentage` number, required: Fixed percentage applied by the tax rule.
        - `threshold_amount` number, double, nullable: Optional monetary threshold amount associated with the tax rule. Use null when the rule does not depend on a threshold.
    - `interest_by_tiers` InterestByTiers: Interest by tiers configuration
      - `type` 'TERM' | 'AMOUNT', required: Interest type - `TERM`: Interest rate varies according to the period of time since the deposit was made. - `AMOUNT`: Interest rate varies according to the current balance.
      - `tier_calculation` 'RETROACTIVE' | 'NON-RETROACTIVE', required: Tier calculation method - `RETROACTIVE`: Interest is recalculated from the beginning based on the new applicable rate. - `NON-RETROACTIVE`: Interest is calculated progressively based on each layer rate.
      - `tiers` InterestByTiersArrayObject[], required
        - `days` integer, nullable: Number of days in `interest_by_tier`
        - `amount` number, double, nullable: Amount in the `interest_by_tier`
        - `margin_rate` number, double, nullable: Multiplier applied to the benchmark rate, expressed as a decimal fraction of 100%. 1.00 = 100% of the benchmark. 1.10 = 110% of the benchmark. 0.95 = 95% of the benchmark. This is not added to the benchmark—use `margin` for an additive spread. If you don't pass a value for `benchmark`, this field must be null. Otherwise, it's required.
        - `fixed_interest_rate` number, float, nullable: Nominal annual interest rate, expressed as a decimal fraction. 0.10 = 10% per year. 1.00 = 100% per year. Do not send 10 for 10%. Maximum precision: 8 decimal places. The platform converts this annual rate to the accrual period using `accrual_basis` and `interest_type`. If you pass a value for `benchmark`, this field must be null. Otherwise, it's required.
    - `capitalization_frequency` 'DAILY' | 'MONTHLY' | 'QUARTERLY' | 'HALF_YEARLY' | 'YEARLY' | 'MATURITY': Interest payout frequency
  - `effective_date` string, date, required: First day on which the change applies. Format = YYYY-MM-DD.
  - `end_date` string, date, nullable: Last day on which the change applies, inclusive. After this day, the configuration that applied before the change takes effect again. When omitted or `null`, the change has no end date. Must be equal to or greater than `effective_date`. Format = YYYY-MM-DD.
  - `created_at` string: Date and time when the change was recorded, in ISO 8601 format without a time zone offset
  - `metadata` Metadata, required: Free-form key-value data to store with the change. The serialized JSON can be at most 4096 bytes. When omitted, an empty object is stored and returned.

## Other responses

- `400`: Bad request
- `401`: Unauthorized. The response body is produced by the upstream authentication gateway and is not defined by this service.
- `403`: Forbidden
- `500`: Internal server error

---

[API](https://skmtc.dev/pismo/apis/banking-interest-engine.md) - [All operations](https://skmtc.dev/pismo/apis/banking-interest-engine/llms.txt) - [OpenAPI document](https://skmtc.dev/pismo/apis/banking-interest-engine/revisions/50c20b2cac0c?raw)
