{
  "openapi": "3.1.0",
  "info": {
    "title": "Mortgage Calculator — Agent Integration API",
    "version": "1.0.0",
    "description": "API for AI agents to build mortgage calculator share URLs. The agent sends normalized loan parameters; the API validates, enriches with reference context, encodes into the internal URL state format, and returns a ready-to-use canonical link that opens a pre-filled mortgage calculator.\n\n## Workflow\n1. Extract loan parameters from the user's request (price, down payment, term, rate).\n2. POST to `/api/agent/mortgage` with a JSON body.\n3. Receive a `url` in the response — give it to the user.\n\n## Reference Data\nThe `reference` object is OPTIONAL. When omitted, the server automatically uses current NBRB rates from its internal cache (updated once per day after midnight Minsk time). You can still provide `reference` to override with your own values if needed.\n\n## Defaults\n- `propertyCurrency`: BYN\n- `downPaymentCurrency`: same as `propertyCurrency`\n- `reference`: auto-injected from server cache when omitted\n- `editing.repaymentMethod`: annuity\n- `editing.downPaymentMode`: amount",
    "contact": {
      "name": "Mini-Tools Hub"
    }
  },
  "servers": [
    {
      "url": "https://minitools.by",
      "description": "Mini-Tools Hub"
    }
  ],
  "paths": {
    "/api/agent/mortgage": {
      "post": {
        "operationId": "buildMortgageUrl",
        "summary": "Build a mortgage calculator share URL",
        "description": "Accepts structured loan parameters, validates them, enriches with reference data (refinancing rate, FX rates), encodes into the internal URL state format, and returns a canonical link. The user opens the link and sees a pre-filled mortgage calculator with all parameters.\n\nThe endpoint is stateless and idempotent. No server-side persistence occurs. The generated URL is self-contained and permanent.",
        "tags": [
          "Mortgage"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentMortgageRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Minimal required fields",
                  "value": {
                    "propertyPrice": 250000,
                    "downPayment": 50000,
                    "termMonths": 240,
                    "interestRatePct": 9.5,
                    "reference": {
                      "refinancingRatePct": 9.5,
                      "usdToByn": 3.27,
                      "eurToByn": 3.56
                    }
                  }
                },
                "withCurrency": {
                  "summary": "USD property with explicit currencies",
                  "value": {
                    "propertyPrice": 85000,
                    "downPayment": 17000,
                    "termMonths": 180,
                    "interestRatePct": 11.2,
                    "propertyCurrency": "USD",
                    "downPaymentCurrency": "USD",
                    "startDate": "2025-06-01",
                    "label": "Family apartment — agent scenario",
                    "reference": {
                      "refinancingRatePct": 9.5,
                      "usdToByn": 3.27,
                      "eurToByn": 3.56
                    }
                  }
                },
                "full": {
                  "summary": "All fields including reference and editing options",
                  "value": {
                    "propertyPrice": 300000,
                    "downPayment": 60000,
                    "termMonths": 300,
                    "interestRatePct": 8,
                    "propertyCurrency": "BYN",
                    "downPaymentCurrency": "BYN",
                    "startDate": "2025-09-01",
                    "label": "Premium apartment — two periods",
                    "reference": {
                      "refinancingRatePct": 10,
                      "usdToByn": 3.4,
                      "eurToByn": 3.7
                    },
                    "editing": {
                      "downPaymentMode": "amount",
                      "repaymentMethod": "differentiated",
                      "twoPeriodsEnabled": true,
                      "period1Mode": "manual",
                      "period2": {
                        "period1LengthMonths": 60,
                        "mode": "formula",
                        "marginPct": 3.5
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "URL successfully generated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentMortgageResponse"
                },
                "example": {
                  "url": "https://minitools.by/mortgage?state=v.1.a1b2c3d4.eJy...",
                  "params": {
                    "propertyPrice": 250000,
                    "downPayment": 50000,
                    "termMonths": 240,
                    "interestRatePct": 9.5,
                    "propertyCurrency": "BYN",
                    "downPaymentCurrency": "BYN",
                    "repaymentMethod": "annuity"
                  },
                  "meta": {
                    "version": 1,
                    "permanent": true,
                    "generatedAt": "2025-05-13T12:00:00.000Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Request body is not valid JSON",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentErrorResponse"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed (use POST)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation failed — field-level errors in `details`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentErrorResponse"
                },
                "example": {
                  "error": {
                    "code": "VALIDATION_ERROR",
                    "message": "Request validation failed. Check details for field-level errors.",
                    "details": [
                      {
                        "path": "propertyPrice",
                        "message": "Number must be greater than 0"
                      },
                      {
                        "path": "termMonths",
                        "message": "Expected integer, received float"
                      }
                    ]
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AgentMortgageRequest": {
        "type": "object",
        "required": [
          "propertyPrice",
          "downPayment",
          "termMonths",
          "interestRatePct"
        ],
        "properties": {
          "propertyPrice": {
            "type": "number",
            "exclusiveMinimum": 0,
            "description": "Sale price of the property in the specified currency."
          },
          "downPayment": {
            "type": "number",
            "minimum": 0,
            "description": "Down payment amount (or percent of price if editing.downPaymentMode = \"percent\")."
          },
          "termMonths": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Loan term in months. Example: 240 = 20 years."
          },
          "interestRatePct": {
            "type": "number",
            "minimum": 0,
            "description": "Annual nominal interest rate in percent. Example: 9.5 means 9.5%."
          },
          "propertyCurrency": {
            "type": "string",
            "enum": [
              "BYN",
              "USD",
              "EUR"
            ],
            "default": "BYN",
            "description": "Currency of the property price. Default: BYN."
          },
          "downPaymentCurrency": {
            "type": "string",
            "enum": [
              "BYN",
              "USD",
              "EUR"
            ],
            "description": "Currency of the down payment. Default: same as propertyCurrency."
          },
          "startDate": {
            "type": "string",
            "format": "date",
            "description": "Loan start date in ISO format (YYYY-MM-DD, first of month). If omitted, current month is used.",
            "example": "2025-06-01"
          },
          "label": {
            "type": "string",
            "maxLength": 200,
            "description": "Optional human-readable label for the scenario."
          },
          "reference": {
            "$ref": "#/components/schemas/AgentReferenceInput"
          },
          "editing": {
            "$ref": "#/components/schemas/AgentEditingOptions"
          }
        }
      },
      "AgentReferenceInput": {
        "type": "object",
        "description": "Optional reference rates. When omitted, the server automatically uses current NBRB rates from its internal cache (refreshed once per day after midnight Minsk time). You may provide individual values to override the cache.",
        "properties": {
          "refinancingRatePct": {
            "type": "number",
            "minimum": 0,
            "description": "Central bank refinancing rate, percent annual (e.g. 9.5). Optional — auto-filled from server cache."
          },
          "usdToByn": {
            "type": "number",
            "exclusiveMinimum": 0,
            "description": "USD → BYN exchange rate (BYN per 1 USD). Optional — auto-filled from server cache."
          },
          "eurToByn": {
            "type": "number",
            "exclusiveMinimum": 0,
            "description": "EUR → BYN exchange rate (BYN per 1 EUR). Optional — auto-filled from server cache."
          }
        }
      },
      "AgentEditingOptions": {
        "type": "object",
        "description": "Optional advanced editing preferences for fine-grained UI control.",
        "properties": {
          "downPaymentMode": {
            "type": "string",
            "enum": [
              "amount",
              "percent"
            ],
            "default": "amount",
            "description": "How to interpret the downPayment field."
          },
          "repaymentMethod": {
            "type": "string",
            "enum": [
              "annuity",
              "differentiated"
            ],
            "default": "annuity",
            "description": "Loan repayment method."
          },
          "twoPeriodsEnabled": {
            "type": "boolean",
            "default": false,
            "description": "Whether to use a two-period rate structure."
          },
          "period1Mode": {
            "type": "string",
            "enum": [
              "manual",
              "formula"
            ],
            "default": "manual",
            "description": "How the period 1 rate is determined."
          },
          "period1MarginPct": {
            "type": "number",
            "minimum": 0,
            "description": "Bank margin in percent for period 1 (only used when period1Mode = \"formula\")."
          },
          "period2": {
            "$ref": "#/components/schemas/AgentPeriod2Options"
          }
        }
      },
      "AgentPeriod2Options": {
        "type": "object",
        "description": "Period 2 settings (only relevant when twoPeriodsEnabled = true).",
        "properties": {
          "period1LengthMonths": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Length of period 1 in months. Period 2 covers the remainder."
          },
          "mode": {
            "type": "string",
            "enum": [
              "manual",
              "formula"
            ],
            "default": "manual",
            "description": "How the period 2 rate is determined."
          },
          "ratePct": {
            "type": "number",
            "minimum": 0,
            "description": "Period 2 manual interest rate in percent (when mode = \"manual\")."
          },
          "marginPct": {
            "type": "number",
            "minimum": 0,
            "description": "Period 2 bank margin in percent (when mode = \"formula\")."
          }
        }
      },
      "AgentMortgageResponse": {
        "type": "object",
        "required": [
          "url",
          "params",
          "meta"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Ready-to-use canonical URL. The user opens it and sees the filled mortgage calculator."
          },
          "params": {
            "type": "object",
            "description": "Echo of the validated/normalized inputs used to build the URL.",
            "properties": {
              "propertyPrice": {
                "type": "number"
              },
              "downPayment": {
                "type": "number"
              },
              "termMonths": {
                "type": "integer"
              },
              "interestRatePct": {
                "type": "number"
              },
              "propertyCurrency": {
                "type": "string"
              },
              "downPaymentCurrency": {
                "type": "string"
              },
              "startDate": {
                "type": "string",
                "format": "date"
              },
              "repaymentMethod": {
                "type": "string"
              },
              "label": {
                "type": "string"
              }
            }
          },
          "meta": {
            "type": "object",
            "description": "Metadata about the generated link.",
            "properties": {
              "version": {
                "type": "integer",
                "description": "URL state encoding version."
              },
              "permanent": {
                "type": "boolean",
                "description": "Whether the link is permanent (no expiry). Always true."
              },
              "generatedAt": {
                "type": "string",
                "format": "date-time",
                "description": "ISO timestamp of generation."
              }
            }
          }
        }
      },
      "AgentErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "VALIDATION_ERROR",
                  "METHOD_NOT_ALLOWED",
                  "INTERNAL_ERROR"
                ],
                "description": "Machine-readable error code."
              },
              "message": {
                "type": "string",
                "description": "Human-readable error description."
              },
              "details": {
                "type": "array",
                "description": "Field-level validation errors (only for VALIDATION_ERROR).",
                "items": {
                  "type": "object",
                  "required": [
                    "path",
                    "message"
                  ],
                  "properties": {
                    "path": {
                      "type": "string",
                      "description": "Dot-notation path to the invalid field."
                    },
                    "message": {
                      "type": "string",
                      "description": "Validation error message for this field."
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}