---
title: "Attach deposit product to program"
method: POST
path: "/v1/deposits/programs/{programId}/attach"
tags: ["Program attachment"]
---

# Attach deposit product to program

`POST /v1/deposits/programs/{programId}/attach`

Attach a time deposit product to a program.
This endpoint generates the [Program attached](https://developers.pismo.io/events/docs/deposit-product-program-attach-1) event.

At the program scope, `deposit_configs.overrides` only accepts `renewal_term`.
Sending `penalties` returns `400 EIBACC0317` and sending `maturity_instructions`
returns `400 EIBACC0318` — apply those per-account instead.

## Path parameters

- `programId` string, required

## Headers

- `AuthorizationToken` string, required

## Request body

- ProgramDepositAttachRequest — Request body for attaching a deposit product at the program scope. Same shape as the account-level request, with the exception that `deposit_configs.overrides` accepts only `renewal_term`. `penalties` and `maturity_instructions` are not allowed and produce `400 EIBACC0317` and `EIBACC0318`.
  - `product_id` string, required — Product identifier.
  - `deposit_configs` ProgramDepositConfigs
    - `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. 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`
      - `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. Example: `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.
    - `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' — Program‑level setting that defines how capitalized interest should be treated.<br> * `PAYOUT` is the default. In this mode, the capitalized amount is sent to the configured `payout_account`. * `REINVEST` instructs the Pismo platform to add the capitalized amount to the principal through the interest engine. All accounts attached to the program inherit this behavior unless an account‑level configuration overrides it. If the field is not provided, it is omitted from the attachment and the system applies `PAYOUT` at runtime.
    - `overrides` ProgramAttachmentOverridesRequest — Defines the per‑attachment overrides permitted at program scope. Only `renewal_term` is valid. `penalties` and `maturity_instructions` result in `400` responses (`EIBACC0317` and `EIBACC0318`) and must be provided at the account level.
      - `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`.
  - `metadata` object — The metadata object contains user-defined key-value pairs that provide additional context or custom information.<br> The platform has no control over its content, but rather controlled by the user.<br> **Note**: This field must not be used to send Personally Identifiable Information (PII), Payment Card Industry (PCI) data, or any sensitive/regulated information. Metadata fields are intended for operational, non-sensitive data only. For sensitive data, use the specific parameters designed for that purpose. For more information, refer to [Get started with Pismo APIs](https://developers.pismo.io/pismo-docs/reference/get-started-with-pismo-apis#metadata).

## Response `201`

Created

- DepositAttachProgramResponse — Response body returned when attaching a deposit product to a program.
  - `program_id` integer — Program identifier.
  - `product_id` string — Product identifier.
  - `deposit_configs` object
    - `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. 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`
      - `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. Example: `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.
    - `interest_capitalization_mode` 'PAYOUT' | 'REINVEST' — Present only when the request included `interest_capitalization_mode`. Reflects the value stored on the attachment.
    - `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` retains the structure provided by the client (calendar form or `unit`+`value`), 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. The platform preserves the client’s original format: `unit`+`value` appears when provided, and `renewal_calendar_maturity_date` is returned as a string when that form is used.
        - `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
          - `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

## Other responses

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

---

[API](https://skmtc.net/pismo/apis/platform-authentication.md) · [All operations](https://skmtc.net/pismo/apis/platform-authentication/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/pismo/platform-authentication/revisions/935b62e16de4/schema)
