---
title: "Update deposit program attachment overrides"
method: PATCH
path: "/v1/deposits/programs/{programId}/attachment"
tags: ["Program attachment"]
---

# Update deposit program attachment overrides

`PATCH /v1/deposits/programs/{programId}/attachment`

## Request

- Base URL: `https://sandbox.pismolabs.io/savings-products`
- URL: `https://sandbox.pismolabs.io/savings-products/v1/deposits/programs/{programId}/attachment`
- Auth: HTTP bearer

Partially updates `deposit_configs.overrides` and `deposit_configs.interest_capitalization_mode` on an active deposit program attachment. Each field follows three‑state `PATCH` rules, allowing values to be set, changed, or cleared. At the program level, the only supported override inside `overrides` is `renewal_term`.
  * **Omitted**: Keeps the current value
  * `null`: Removes the override; falls back through the cascade (product)
  * **Value**: Replaces the current value

**NOTES**:
* At least one of `deposit_configs.overrides` or `deposit_configs.interest_capitalization_mode` must be provided.
* Sending `penalties` inside `overrides` returns `400 EIBACC0317`
* Sending `maturity_instructions` inside `overrides` results in a `400 EIBACC0318` error. This field cannot be modified at the program level and must be configured on each account attachment instead.
* An empty `overrides` envelope returns `400 EIBACC0315`
* `renewal_term` still requires `ROLLOVER` configured in `maturity_instructions` somewhere in the fallback sequence (`400 EIBACC0310` otherwise)

This endpoint generates a [Program attachment updated](https://developers.pismo.io/events/docs/deposit-product-program-attachment-updated-1) event.

## Path parameters

- `programId` integer, required

## Request body

- UpdateProgramAttachmentRequest
  - `deposit_configs` object, required: At least one of `overrides` or `interest_capitalization_mode` must be provided.
    - `interest_capitalization_mode` 'PAYOUT' | 'REINVEST' | 'null', nullable: Updates the program-level default capitalization mode. Inherited by all accounts attached to this program unless overridden at account level. Send `null` to remove the program-level value and revert to the product default.
    - `overrides` ProgramAttachmentOverridesPatchRequest: PATCH envelope for program-level `deposit_configs.overrides`.<br> **NOTES**: * Only `renewal_term` is valid and uses three-state semantics: omit for no change, `null` to clear the override, or supply a value to replace it * `penalties` and `maturity_instructions` are not allowed and produce `400 EIBACC0317` and `EIBACC0318` * An empty `overrides` object is rejected with `400 EIBACC0315`
      - `renewal_term` RenewalTermOverrideRequest: Specifies the recurring rollover term, not to be confused with the initial `maturity_period`. You must provide either `unit` with `value` or `renewal_calendar_maturity_date`. A `ROLLOVER` configuration in principal or interest is required. When you pass `renewal_calendar_maturity_date`, the Pismo platform converts the interval from today into a day count and stores it at attach time in normalized form: `{unit: DAYS, value: <calculated>}`.
        - `unit` 'DAYS' | 'WEEKS' | 'MONTHS' | 'YEARS': Time unit of the renewal term. Required together with `value` when calendar form is not used.
        - `value` integer: Number of units. Required together with `unit` when calendar form is not used.
        - `renewal_calendar_maturity_date` string, date: Explicit calendar date (`YYYY-MM-DD`), the date must be a future date, and does not coincide with `unit`+`value`.

## Response `200`

OK

- ProgramAttachment
  - `product_type` 'deposit' | 'savings-account': Product type.
  - `product_id` string: Product identifier.
  - `interest_plan_id` string: Interest rate plan ID. This corresponds to the ID you created using the [Create interest plan version](ref:patch-v1-interest-plan)) endpoint.
  - `maturity_period` MaturityPeriod: Defines when the deposit matures. There are three usage modes: * **Relative period**: Sends `unit` + `value` (e.g. `MONTHS` + `6`). * **Explicit date**: Sends `calendar_maturity_date` (e.g. `2027-06-15`). * **Default**: Omits the field or sends `{}`. The product's configured default maturity term (`PRODUCT_DEFAULT_MATURITY_DATE_DAYS`, typically `10950` days ≈ 30 years) is applied. **NOTE**: `calendar_maturity_date` and `unit`/`value` are mutually exclusive, sending both in the same request returns a `400` validation error. In the **attach** endpoints, the response returns exactly what was sent in the request: * Send `unit` + `value` returns `unit` + `value` * Send `calendar_maturity_date` returns `calendar_maturity_date` * Send nothing (default fallback applied) returns `unit=DAYS` and `value` equal to the product's configured `PRODUCT_DEFAULT_MATURITY_DATE_DAYS` **NOTE**: this behavior applies only to attach. The `GET` attachment endpoints and `PATCH /v1/deposits/accounts/{accountId}/attachment` return the resolved term, with `unit`, `value`, and `calendar_maturity_date` populated together. A `PATCH` sent in explicit‑date form is returned normalized as `{unit: DAYS, value: <days>, calendar_maturity_date: <date>}`.
    - `unit` 'DAYS' | 'WEEKS' | 'MONTHS' | 'YEARS': Time unit for the relative maturity period. It's used together with `value` and cannot coincide with `calendar_maturity_date`. - `DAYS`: Uses `value` directly. Example: `value=90` → 90 days. - `WEEKS`: Multiplies `value` by 7. Example: `value=4` → 28 days. - `MONTHS`: Calculates calendar-month with end-of-month (EOM) clamping when the target day does not exist. The maturity date falls on the same day of the month as the start date. Example: `2026-09-22` + 3 months = `2026-12-22`; `2024-01-31` + 1 month = `2024-02-29` (leap year) or `2025-02-28` (non-leap year). - `YEARS`: Calculates calendar-year, for example: `2024-02-29` + 1 year = `2025-02-28`. Note that there is no Feb 29 in 2025. For `WEEKS`, `MONTHS`, and `YEARS`, the resulting calendar date is converted back to a day count to validate against the product's configured minimum or maximum term.
    - `value` integer: Number of time units until maturity. Must be greater than `0`. Mutually exclusive with `calendar_maturity_date`.
    - `calendar_maturity_date` string, date: Maturity date. Format is `YYYY-MM-DD`. The date must be a future date. This date cannot coincide with `unit`/`value`, sending both in the same request returns a `400` validation error.
  - `attachment_date` string, date-time: Timestamp that indicates when the attachment was created (when the attach API call was made). The datetime format follows the ISO 8601 standard `yyyy-mm-ddThh:mm:ss.sssZ`.
  - `effective_date` string, date: The effective date of the attachment in `YYYY-MM-DD` format This is the date when the attachment becomes valid. Maturity is calculated from this date. For attachments created in the past, the date defaults to the value of `attachment_date`.
  - `fee_model_id` string: Fee model identifier, if applicable.
  - `payout_account` PayoutAccount: The payout account defines where outbound payments are sent, and it is used in two operational contexts.<br> * **Capitalization flow**: When the capitalization mode is set to `PAYOUT`, the capitalized interest is directed to this account. If the mode is `REINVEST`, the payout account is not involved because the interest is added to the principal instead. * **Maturity instruction flow**: At maturity, this account receives principal or interest whenever the maturity instructions specify `PAY` for either `maturity_instructions.principal` or `maturity_instructions.interest`. This flow always relies on the payout account, regardless of how capitalization is configured. Both flows reference the same payout account settings. Choosing `REINVEST` for capitalization does not remove or disable the payout account, and it remains fully available for maturity‑related payments.
    - `label` string: Label to identify the account
    - `type` 'INTERNAL' | 'EXTERNAL': Payout account type, either `INTERNAL` or `EXTERNAL`
    - `internal_account_id` number: Internal account ID for the account that receives the payments. Required for type `INTERNAL` and not allowed for `EXTERNAL`.
    - `external_account` object: Contains user-defined key-value pairs that identify the external account receiving the payments. Note that external account information is client-provided. Required for type `EXTERNAL` and not allowed for `INTERNAL`.
  - `interest_capitalization_mode` 'PAYOUT' | 'REINVEST': Present only when this program attachment explicitly defines `interest_capitalization_mode`. If the field is missing, the Pismo platform applies `REINVEST` as the default behavior. All accounts linked to the program inherit this value unless an account‑level configuration provides its own setting.
  - `overrides` AttachmentOverridesSnapshot: Representation of the persisted overrides, present only when the request defined at least one override. Sub-fields are included only when set. The `renewal_term` always returns all three fields together (`unit`, `value` and `renewal_calendar_maturity_date`), mirroring the behavior of `maturity_period`.
    - `maturity_instructions` MaturityInstructionsOverrideRequest: Overrides the deposit’s behavior at maturity. If a field is omitted, the Pismo platform uses the value defined at the higher‑level configuration that governs this deposit.
      - `principal` 'ROLLOVER' | 'PAY': Specifies how the principal is handled once the deposit matures.
      - `interest` 'ROLLOVER' | 'PAY': Specifies how the interest is handled once the deposit matures.
      - `reason` string: Optional audit-trail reason.
    - `renewal_term` RenewalTermResponse: Renewal term applied on each rollover. Always returns all three fields together — `unit`, `value` and `renewal_calendar_maturity_date` — regardless of the form the client used to configure it, mirroring `maturity_period`. Legacy terms persisted before the calendar date was stored return only `unit`+`value`.
      - `unit` 'DAYS' | 'WEEKS' | 'MONTHS' | 'YEARS'
      - `value` integer
      - `renewal_calendar_maturity_date` string, date: Returned only when the request uses the calendar format. Format = `YYYY-MM-DD`.
    - `penalties` PenaltiesOverrideSnapshot: Persisted penalty overrides for each type. Types appear only when set. Each entry includes `waived`, the relevant type-specific fields, and an optional `valid_until` for scheduling the revert.
      - `reason` string
      - `grace_period` GracePeriodOverrideRequest: Grace period override. Type-specific fields are optional pointers, when omitted, the Pismo platform follows the normal fallback sequence, moving from the account level to the program and then to the product defaults.
        - `waived` boolean, required: `true` = fully exempt; `false` = penalty active (customize via the fields below).
        - `duration_days` integer
        - `penalty_interest_days` integer
        - `valid_until` string, date-time: Schedules the revert of this override via EventBridge. This value must be a future date and follows the ISO 8601 standard.
      - `early_withdrawal_after_opening` EarlyWithdrawalAfterOpeningOverrideRequest: Override for early withdrawal after account opening.
        - `waived` boolean, required
        - `applicable_within_days` integer
        - `penalty_interest_days` integer
        - `valid_until` string, date-time
      - `withdrawal_fee` WithdrawalFeeOverrideRequest: Withdrawal fee override.
        - `waived` boolean, required
        - `type` 'PERCENTAGE' | 'FIXED'
        - `value` number: Same format as the product's `withdrawal_fee.value`.
        - `valid_until` string, date-time
      - `tiered_interest_forfeiture` TieredInterestForfeitureOverrideRequest: Tiered interest forfeiture override. Tiers replace the product's tiers when provided.
        - `waived` boolean, required
        - `tiers` TieredInterestForfeitureTierRequest[]
          - `min_days_held` integer, required
          - `max_days_held` integer: Optional. Open-ended tier when omitted.
          - `forfeited_interest_days` integer, required
        - `valid_until` string, date-time
      - `subsequent_withdrawals` SubsequentWithdrawalsOverrideRequest: Subsequent withdrawals (Regulation D) override.
        - `waived` boolean, required
        - `applicable_within_days` integer
        - `penalty_interest_days` integer
        - `window_behavior` 'ROLLING' | 'FIXED'
        - `valid_until` string, date-time
  - `accrual_model` 'DEPOSIT_BASIS' | 'BALANCE_BASIS': Accrual model inherited from the attached product. `DEPOSIT_BASIS` or `BALANCE_BASIS`.
  - `balance_type` 'VALUE_DATED_BALANCE' | 'LEDGER_BALANCE': Balance type inherited from the attached product. Only meaningful when `accrual_model` is `BALANCE_BASIS`.

## Other responses

- `400`: Bad Request
- `404`: Not Found
- `409`: Conflict
- `500`: Internal Server Error

---

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