---
title: "Update account interest"
method: PUT
path: "/v1/interest/account/{accountId}"
tags: ["Account interest"]
---

# Update account interest

`PUT /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

Apply specific interest accrual options to an account by replacing its full interest
configuration.

This operation has full-replacement semantics: every request must redeclare the complete
configuration. Partial updates (sending only the fields you want to change) are not
supported and cause the validation to fail.

Although every property in the request body is independently optional, the body as a
whole must satisfy several conditional rules. See the request body schema description
for the full set of `benchmark`/`fixed_interest_rate`,
`tax_withholding`, and `taxes_exemption` rules.

**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 and `external_account_id` is stored as `null` - **any external account ID
  previously stored for this account is cleared**.
- `x-external-account-id`: A Corporate API call resolves the external account ID to a
  Pismo `account_id`, and both IDs are stored.

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`. In both
cases, the interest account is left unchanged and no update event is emitted.

## Path parameters

- `accountId` string, required

## Request body

- InterestAccountRequest: Request body for `PUT /v1/interest/account/{accountId}`. The endpoint replaces the full interest configuration of the account, partial updates are not supported. Every request must redeclare a complete configuration that satisfies the rules below. Interest type. Exactly one of the two paths must be chosen: - **Benchmark-indexed rate:** If you pass `benchmark` and `margin_rate`., then `margin` is optional. `fixed_interest_rate` must be omitted. - **Fixed rate:** If you pass `fixed_interest_rate`, then `benchmark`, `margin_rate`, and `margin` must all be omitted. Passing neither `benchmark` nor `fixed_interest_rate` returns `400 Bad Request` with `fixed_interest_rate must be provided`. Passing both returns `400 Bad Request` with `fixed_interest_rate is not allowed when benchmark is passed`. **Tax-withholding rule**: Driven by `tax_withholding.withholding_moment`: - When `withholding_moment` is `ACCRUAL`, `fee_processing_code` is required and `tax_rules` must be omitted. - When `withholding_moment` is `CAPITALIZATION`, `tax_rules` is required and `fee_processing_code` must be omitted. - When `tax_withholding` is omitted, no withholding is configured. **Tax-exemption rule**: When `taxes_exemption` is `true`, `tax_withholding` must be null. When `taxes_exemption` is `false` or omitted, `tax_withholding` follows the rule above. Numeric fields (`fixed_interest_rate`, `margin_rate`) must have a positive value. `tax_withholding.fee_processing_code` is limited to 128 characters.
  - `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: When true, the account is exempt from tax withholding and `tax_withholding` must be null.
  - `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

## Response `200`

OK

- InterestAccountResponse
  - `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.
  - `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.
  - `taxes_exemption` boolean: Is the account exempt from taxes?
  - `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
  - `external_account_id` string: External account ID, at most 60 characters, provided by the client system that owns the account. It cannot be passed directly in a request body—it's parsed from an external account ID token, and it's included in responses and events for accounts that have it stored.
  - `account_id` string: Pismo account ID. Returned only when the request was authenticated with a Pismo account ID token. Omitted otherwise.

## 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
- `404`: Not found
- `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)
