---
updatedAt: 2026-06-17T17:50:44.000Z
agentTools:
  siteIndex: https://developers.pismo.io/llms.txt
  projectIndex: https://developers.pismo.io/pismo-docs/llms.txt
---

# Create interest plan version

Create a new version of an existing interest plan. This endpoint allows you to update specific fields while preserving others from the previous version.

Key features:
- Creates a new version with the specified `start_date`.
- Updates only the provided fields—any field not specified inherits the value from the previous version.
- Validates that the new `start_date` is after the `start_date` of the previous version.
- Maintains immutable fields like `interest_type` and `tier_calculation`.
- Preserves existing tiers when updating `interest_by_tiers`—only specified tiers are updated.

This endpoint generates an [Interest plan created](https://developers.pismo.io/events/docs/interest-engine-interest-plan-creation-success-1) event.


# OpenAPI definition

```json
{
  "openapi": "3.1.0",
  "info": {
    "title": "Banking - Interest engine",
    "version": "1.0.0",
    "description": "API to handle interest-bearing account operations",
    "termsOfService": "https://developers.pismo.io/terms/",
    "contact": {
      "name": "API Support",
      "url": "https://developers.pismolabs.io/pismo-docs/docs/support"
    },
    "license": {
      "name": "Copyright Pismo"
    }
  },
  "servers": [
    {
      "url": "https://sandbox.pismolabs.io/interest-engine",
      "description": "Sandbox API server for testing"
    },
    {
      "url": "https://sandbox.pismolabs.io/passport/v2/s2s/access-token",
      "description": "Sandbox API for oauth2"
    }
  ],
  "tags": [
    {
      "name": "Interest engine",
      "description": "Manage interest plans"
    }
  ],
  "components": {
    "parameters": {
      "InterestPlanIdPath": {
        "name": "interestPlanId",
        "in": "path",
        "description": "Interest plan ID generated during the plan's creation. Must be an alphanumeric UUID with the alphabetical characters in lowercase.",
        "required": true,
        "example": "d9b2c9e1-4633-4a10-841b-270f7f1493cd",
        "schema": {
          "type": "string"
        }
      }
    },
    "schemas": {
      "Amount": {
        "type": [
          "number",
          "null"
        ],
        "format": "double",
        "description": "Amount in the `interest_by_tier`",
        "example": 1000
      },
      "CapEffectiveRate": {
        "type": "number",
        "format": "double",
        "description": "Cap effective rate. If you pass a value for `cap_effective_rate`, you must also pass a value for `cap_threshold`.",
        "example": 1.2
      },
      "CapThreshold": {
        "type": "number",
        "format": "double",
        "description": "Cap threshold value. If you pass a value for `cap_threshold`, you must also pass a value for `cap_effective_rate`.",
        "example": 1.1
      },
      "Days": {
        "type": "integer",
        "format": "int32",
        "description": "Number of days in `interest_by_tier`",
        "example": 30
      },
      "Description": {
        "type": "string",
        "description": "Interest plan name",
        "example": "Banking plan"
      },
      "FixedInterestRate": {
        "type": "number",
        "format": "float",
        "description": "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`.\n\nIf you pass a value for `benchmark`, this field must be null. Otherwise, it's required.\n",
        "example": 0.1
      },
      "FloorEffectiveRate": {
        "type": "number",
        "format": "double",
        "description": "Floor effective rate",
        "example": 2.2
      },
      "FloorThreshold": {
        "type": "number",
        "format": "double",
        "description": "Floor threshold value",
        "example": 2.1
      },
      "InterestByTiers": {
        "type": "object",
        "properties": {
          "type": {
            "$ref": "#/components/schemas/InterestByTiersType"
          },
          "tier_calculation": {
            "$ref": "#/components/schemas/TierCalculation"
          },
          "tiers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InterestByTiersArrayObject"
            }
          }
        },
        "required": [
          "type",
          "tier_calculation",
          "tiers"
        ],
        "description": "Interest by tiers configuration",
        "example": {
          "type": "TERM",
          "tier_calculation": "RETROACTIVE",
          "tiers": [
            {
              "days": 30,
              "amount": 1000,
              "margin_rate": 1,
              "fixed_interest_rate": 1.2
            },
            {
              "days": 60,
              "amount": 2000,
              "margin_rate": 1,
              "fixed_interest_rate": 1.3
            }
          ]
        }
      },
      "InterestByTiersArrayObject": {
        "type": "object",
        "properties": {
          "days": {
            "$ref": "#/components/schemas/Days"
          },
          "amount": {
            "$ref": "#/components/schemas/Amount"
          },
          "margin_rate": {
            "$ref": "#/components/schemas/MarginRate"
          },
          "fixed_interest_rate": {
            "$ref": "#/components/schemas/FixedInterestRate"
          }
        },
        "description": "Tier details for interest calculation"
      },
      "InterestByTiersType": {
        "type": "string",
        "description": "Interest type\n- `TERM`: Interest rate varies according to the period of time since the deposit was made.\n- `AMOUNT`: Interest rate varies according to the current balance.\n",
        "enum": [
          "TERM",
          "AMOUNT"
        ],
        "example": "TERM"
      },
      "InterestPlanId": {
        "type": "string",
        "format": "UUID",
        "description": "Interest plan ID generated during the plan's creation. Must be an alphanumeric UUID with the alphabetical characters in lowercase.",
        "example": "07d84f79-3027-47bd-b628-65528ccc8fb2"
      },
      "InterestPlanVersionRequest": {
        "title": "Interest plan version request",
        "type": "object",
        "properties": {
          "start_date": {
            "$ref": "#/components/schemas/StartDateForNewVersion"
          },
          "description": {
            "$ref": "#/components/schemas/Description"
          },
          "fixed_interest_rate": {
            "$ref": "#/components/schemas/FixedInterestRate"
          },
          "margin": {
            "$ref": "#/components/schemas/Margin"
          },
          "margin_rate": {
            "$ref": "#/components/schemas/MarginRate"
          },
          "interest_by_tiers": {
            "$ref": "#/components/schemas/InterestByTiers"
          },
          "interest_thresholds": {
            "$ref": "#/components/schemas/InterestThresholds"
          }
        },
        "required": [
          "start_date"
        ],
        "example": {
          "start_date": "2025-06-17",
          "description": "BANKING PLAN v2",
          "margin": 0.05,
          "margin_rate": 1.2
        }
      },
      "InterestPlanVersionResponse": {
        "title": "Interest plan version response",
        "type": "object",
        "properties": {
          "interest_plan_id": {
            "$ref": "#/components/schemas/InterestPlanId"
          },
          "version": {
            "type": "string",
            "description": "ID for the new interest plan version",
            "example": "2025-06-17"
          }
        }
      },
      "InterestThresholds": {
        "type": "object",
        "properties": {
          "cap_threshold": {
            "$ref": "#/components/schemas/CapThreshold"
          },
          "cap_effective_rate": {
            "$ref": "#/components/schemas/CapEffectiveRate"
          },
          "floor_threshold": {
            "$ref": "#/components/schemas/FloorThreshold"
          },
          "floor_effective_rate": {
            "$ref": "#/components/schemas/FloorEffectiveRate"
          }
        },
        "description": "Cap and floor thresholds for the interest plan",
        "example": {
          "cap_threshold": 1.1,
          "cap_effective_rate": 1.2,
          "floor_threshold": 2.2,
          "floor_effective_rate": 2.1
        }
      },
      "Margin": {
        "type": "number",
        "format": "double",
        "description": "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.\n\nIf you pass a value for `benchmark`, this field is optional. If `benchmark` is null, this field must be null also.\n",
        "example": 0.02
      },
      "MarginRate": {
        "type": [
          "number",
          "null"
        ],
        "format": "double",
        "description": "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.\n\nIf you don't pass a value for `benchmark`, this field must be null. Otherwise, it's required.\n",
        "example": 1.1
      },
      "StartDateForNewVersion": {
        "type": "string",
        "format": "date",
        "description": "Date to start applying the new interest plan version. Format = YYYY-MM-DD. Must be greater than or equal to current date.",
        "example": "2025-06-17"
      },
      "TierCalculation": {
        "type": "string",
        "description": "Tier calculation method\n- `RETROACTIVE`: Interest is recalculated from the beginning based on the new applicable rate.\n- `NON-RETROACTIVE`: Interest is calculated progressively based on each layer rate.\n",
        "enum": [
          "RETROACTIVE",
          "NON-RETROACTIVE"
        ],
        "example": "RETROACTIVE"
      },
      "ErrorResponse": {
        "type": "object",
        "description": "Standard error payload generated by the global exception handler.\n`message` is a single string for most errors and an array of strings\nwhen multiple bean-validation or request-binding errors occur in the same request.\n",
        "additionalProperties": false,
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          }
        },
        "example": {
          "message": "interest account not found"
        }
      },
      "ErrorResponseDeserialization": {
        "type": "object",
        "description": "Error payload generated only when the request body fails JSON deserialization\n(unknown field or invalid JSON structure). Returned with HTTP 400.\n",
        "additionalProperties": false,
        "required": [
          "error",
          "status"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Short error category."
          },
          "message": {
            "type": "string",
            "description": "Details about the field or structure that causes the error."
          },
          "field": {
            "type": "string",
            "description": "Name of the invalid field. Present only for unknown-field errors."
          },
          "status": {
            "type": "integer",
            "description": "HTTP status code, always 400 for this shape."
          }
        },
        "example": {
          "error": "Invalid field in request",
          "message": "Field 'foo' is not allowed. Only the following fields can be updated: start_date, description, fixed_interest_rate, margin_rate, margin, interest_by_tiers, interest_thresholds",
          "field": "foo",
          "status": 400
        }
      }
    },
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    },
    "responses": {
      "400BadRequest": {
        "description": "Bad request",
        "content": {
          "application/json": {
            "schema": {
              "anyOf": [
                {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                {
                  "$ref": "#/components/schemas/ErrorResponseDeserialization"
                }
              ]
            },
            "examples": {
              "validation": {
                "summary": "Bean validation or binding errors",
                "value": {
                  "message": [
                    "fixed_interest_rate must be informed",
                    "margin_rate must be positive"
                  ]
                }
              },
              "requestBody": {
                "summary": "invalid or missing request value",
                "value": {
                  "message": "Failed to process your request. Validate the fields in your request."
                }
              },
              "tenantHeader": {
                "summary": "Tenant header missing or malformed",
                "value": {
                  "message": "x-tenant header is missing or malformed"
                }
              },
              "unknownField": {
                "summary": "Unknown field in request body",
                "value": {
                  "error": "Invalid field in request",
                  "message": "Field 'foo' is not allowed. Only the following fields can be updated: start_date, description, fixed_interest_rate, margin_rate, margin, interest_by_tiers, interest_thresholds",
                  "field": "foo",
                  "status": 400
                }
              },
              "invalidJson": {
                "summary": "Invalid JSON body",
                "value": {
                  "error": "Invalid JSON format",
                  "message": "Request contains invalid JSON structure or field types",
                  "status": 400
                }
              },
              "taxWithholdingAccrualFeeRequired": {
                "summary": "ACCRUAL withholding without fee_processing_code",
                "value": {
                  "message": [
                    "fee_processing_code is required when tax_withholding.withholding_moment is ACCRUAL."
                  ]
                }
              },
              "taxWithholdingAccrualTaxRulesNotAllowed": {
                "summary": "ACCRUAL withholding with tax_rules present",
                "value": {
                  "message": [
                    "tax_rules must be null when tax_withholding.withholding_moment is ACCRUAL."
                  ]
                }
              },
              "taxWithholdingCapitalizationFeeNotAllowed": {
                "summary": "CAPITALIZATION withholding with fee_processing_code present",
                "value": {
                  "message": [
                    "fee_processing_code must be null when tax_withholding.withholding_moment is CAPITALIZATION."
                  ]
                }
              },
              "taxWithholdingCapitalizationTaxRulesRequired": {
                "summary": "CAPITALIZATION withholding without tax_rules",
                "value": {
                  "message": [
                    "tax_rules is required when tax_withholding.withholding_moment is CAPITALIZATION."
                  ]
                }
              },
              "taxWithholdingNoneFieldsNotAllowed": {
                "summary": "NULL withholding_moment with fee_processing_code or tax_rules present",
                "value": {
                  "message": [
                    "fee_processing_code and tax_rules must be null when tax_withholding.withholding_moment is NULL."
                  ]
                }
              },
              "taxWithholdingNotAllowedWhenTaxesExemption": {
                "summary": "taxes_exemption is true with tax_withholding present",
                "value": {
                  "message": [
                    "tax_withholding must be null when taxes_exemption is true."
                  ]
                }
              }
            }
          }
        }
      },
      "401Unauthorized": {
        "description": "Unauthorized. The response body is produced by the upstream authentication gateway and is not defined by this service."
      },
      "404NotFound": {
        "description": "Not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "interestAccountNotFound": {
                "summary": "Interest account not found",
                "value": {
                  "message": "interest account not found"
                }
              },
              "interestPlanNotFound": {
                "summary": "Interest plan not found",
                "value": {
                  "message": "interest plan not found"
                }
              },
              "benchmarkNotFound": {
                "summary": "Benchmark not found",
                "value": {
                  "message": "benchmark not found"
                }
              }
            }
          }
        }
      },
      "409Conflict": {
        "description": "Conflict: A version with this start date already exists",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "Conflict: Version with this start date already exists"
            }
          }
        }
      },
      "500InternalServerError": {
        "description": "Internal server error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "Failed to process your request"
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "paths": {
    "/v1/interest/plan/{interestPlanId}": {
      "patch": {
        "summary": "Create interest plan version",
        "description": "Create a new version of an existing interest plan. This endpoint allows you to update specific fields while preserving others from the previous version.\n\nKey features:\n- Creates a new version with the specified `start_date`.\n- Updates only the provided fields—any field not specified inherits the value from the previous version.\n- Validates that the new `start_date` is after the `start_date` of the previous version.\n- Maintains immutable fields like `interest_type` and `tier_calculation`.\n- Preserves existing tiers when updating `interest_by_tiers`—only specified tiers are updated.\n\nThis endpoint generates an [Interest plan created](https://developers.pismo.io/events/docs/interest-engine-interest-plan-creation-success-1) event.\n",
        "tags": [
          "Interest engine"
        ],
        "operationId": "patch-v1-interest-plan",
        "parameters": [
          {
            "$ref": "#/components/parameters/InterestPlanIdPath"
          }
        ],
        "requestBody": {
          "description": "Request body",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InterestPlanVersionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InterestPlanVersionResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/400BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/401Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/404NotFound"
          },
          "409": {
            "$ref": "#/components/responses/409Conflict"
          },
          "500": {
            "$ref": "#/components/responses/500InternalServerError"
          }
        }
      }
    }
  }
}
```