Rate Lock v1 to v2 Migration Guide

This guide helps partner developers migrate a LOCK integration from the v1 result format (application/vnd.productpricing-lock-1.0.0.json or application/vnd.productpricing-lock-1.1.0.json) to the v2 result format (application/vnd.productpricing-lock-2.0.0.json). For the complete field reference, see Rate Lock (v2) and Rate Lock (v2).

What changed at a glance

Areav1v2Notes
Lock request valuesTop level of detailsrequestSide objectMoved and renamed
Required fieldsbaseRate, plus two of lockDate, lockNumberOfDays, and lockExpirationDateAt least one side objectNew anyOf rule
DatesMM/DD/YYYYYYYY-MM-DDISO 8601
Rate and price fieldsbaseRate, basePrice, baseMarginRaterate, priceRate, marginRateRenamed
Lock period fieldslockNumberOfDays, lockExpirationDate, lastRateSetDatenumberOfDays, lockExpires, currentRateSetDateRenamed
AdjustmentsOne adjustments[] arrayTyped adjustment arraysSee Restructured adjustments
additionalFields itemsstringValue, numericValue, or dateValuevalueSingle untyped value
New in v2buySide, sellSide, comparisonSide, pricingInformationOptional

Updating the format and entitlements

Change $.result.format from the v1 format string to the v2 format string in every transaction response that uses v2:

{
  "result": {
    "format": "application/vnd.productpricing-lock-1.1.0.json",
    "action": "LOCK"
  }
}
{
  "result": {
    "format": "application/vnd.productpricing-lock-2.0.0.json",
    "action": "LOCK"
  }
}

Then add the v2 format to the formats array for the LOCK action in your product entitlements ($.entitlements.data.transaction, response.results). During the transition you can declare both format strings to support both versions:

{
  "action": "LOCK",
  "formats": [
    "application/vnd.productpricing-lock-1.0.0.json",
    "application/vnd.productpricing-lock-1.1.0.json",
    "application/vnd.productpricing-lock-2.0.0.json"
  ]
}

Request side and additional fields

In v1, the lock request values are sent at the top level of details. In v2, they are sent in the requestSide object, using the same field renames as the other side objects. At least one of requestSide, buySide, sellSide, or comparisonSide is required, and each side object that you send must contain at least one property.

{
  "baseRate": 6.375,
  "lockDate": "10/05/2026",
  "lockNumberOfDays": 30,
  "rateSheetId": "RS9110"
}
{
  "requestSide": {
    "rate": 6.375,
    "lockDate": "2026-10-05",
    "numberOfDays": 30,
    "rateSheetId": "RS9110"
  }
}

v1 additionalFields items carry the value in exactly one of stringValue, numericValue, or dateValue. v2 items carry it in a single value property, which has no defined type or format.

{
  "additionalFields": [
    {
      "fieldName": "CX.PPE.PRICINGTIER",
      "stringValue": "Gold"
    }
  ]
}
{
  "additionalFields": [
    {
      "fieldName": "CX.PPE.PRICINGTIER",
      "value": "Gold"
    }
  ]
}

Migrating from 1.0.0 to 1.1.0

If you only need the 1.1.0 fields, you can move from 1.0.0 to 1.1.0 without restructuring your payload. Version 1.1.0 adds investor, impoundWaived, and impoundType, and allows an empty penaltyTerm; every valid 1.0.0 payload is also valid against 1.1.0. Update $.result.format and your entitlements to the 1.1.0 format string.

Date format

Every date field in the side objects changes from MM/DD/YYYY to ISO 8601 (YYYY-MM-DD). This includes lockDate, lockExpires (formerly lockExpirationDate), currentRateSetDate (formerly lastRateSetDate), commitmentDate, and the date fields in investor and concession objects.

{
  "lockDate": "01/15/2026",
  "lockExpirationDate": "02/14/2026",
  "lastRateSetDate": "01/15/2026"
}
{
  "lockDate": "2026-01-15",
  "lockExpires": "2026-02-14",
  "currentRateSetDate": "2026-01-15"
}

Action required: Format all date values as YYYY-MM-DD before you submit v2 responses.

Restructured adjustments

v1 uses a single adjustments[] array on each object. Each item declares its category in adjustmentType and its sub-type in priceAdjustmentType, and carries the value in adjustment. adjustmentType, description, and priceAdjustmentType are required on every item, and each adjustments[] array must contain at least one item.

v2 replaces each adjustments[] array with separate typed arrays. Each item has priceAdjustmentTypeIndex (integer), description, and rate (decimal). None of the item fields are required, and the arrays can be empty or omitted.

{
  "buySide": {
    "adjustments": [
      {
        "adjustmentType": "Adjustment",
        "priceAdjustmentType": "BaseRate",
        "description": "FICO score",
        "adjustment": -0.125
      },
      {
        "adjustmentType": "LockExtensionAdjustment",
        "priceAdjustmentType": "BasePrice",
        "description": "15-day extension",
        "adjustment": -0.25
      }
    ]
  }
}
{
  "buySide": {
    "baseRateAdjustments": [
      {
        "priceAdjustmentTypeIndex": 2,
        "description": "FICO score",
        "rate": -0.125
      }
    ],
    "lockExtensionAdjustments": [
      {
        "priceAdjustmentTypeIndex": 0,
        "description": "15-day extension",
        "rate": -0.25
      }
    ]
  }
}
v2 arrayReplaces v1 items with
baseRateAdjustmentsadjustmentType Adjustment and priceAdjustmentType BaseRate
basePriceAdjustmentsadjustmentType Adjustment and priceAdjustmentType BasePrice
baseMarginAdjustmentsadjustmentType Adjustment and priceAdjustmentType BaseMargin
profitMarginAdjustmentsadjustmentType Adjustment and priceAdjustmentType ProfitMargin (buySide only)
lockExtensionAdjustmentsadjustmentType LockExtensionAdjustment
reLockFeeAdjustmentsadjustmentType ReLockFeeAdjustment
customPriceAdjustmentsadjustmentType CustomPriceAdjustment

Field renames

Apply these renames inside each listed object:

v1 fieldv2 fieldApplies to
lockExpirationDatelockExpiresrequestSide
lockNumberOfDaysnumberOfDaysrequestSide
startingAdjustRatestartingAdjustmentRaterequestSide
startingAdjustPricestartingAdjustmentPointrequestSide
lastRateSetDatecurrentRateSetDaterequestSide
baseRateraterequestSide
basePricepriceRaterequestSide
baseMarginRatemarginRaterequestSide

Fields not in v2

The following v1 fields have no field of the same name in the v2 schema. Remove them from your v2 payloads, and review any logic that depends on them.

v1 locationv1 fieldNotes
Top level of detailsextensionIndicatorNot in the v2 schema
Top level of detailspriceConcessionNot in the v2 schema
Top level of detailsborrLenderPaidNot in the v2 schema
Top level of detailsonrpDateNot in the v2 schema
Top level of detailsonrpTimeNot in the v2 schema
Top level of detailsonrpLockNot in the v2 schema
Top level of detailsonrpEligibleNot in the v2 schema
Top level of detailsteaserRateNot in the v2 schema
Top level of detailsdisclosureTypeNot in the v2 schema
Top level of detailsindexCurrentValuePercentNot in the v2 schema
Top level of detailsbuydownTypeNot in the v2 schema
Top level of detailspudIndicatorNot in the v2 schema
Top level of detailsnotInProjectIndicatorNot in the v2 schema
Top level of detailsinvestorNot in the v2 schema
Top level of detailsplanCodeNot in the v2 schema
Top level of detailsgpmRateNot in the v2 schema
Top level of detailsgpmYearsNot in the v2 schema
Top level of detailscorrespondentCommitmentTypeNot in the v2 schema
Top level of detailscorrespondentDeliveryTypeNot in the v2 schema
Top level of detailsisDeliveryTypeNot in the v2 schema
Top level of detailshedgingNot in the v2 schema
Top level of detailspenaltyTermNot in the v2 schema
Top level of detailscurrentAcquisitionNot in the v2 schema
Top level of detailscurrentConstructionRefiNot in the v2 schema
Top level of detailsprepayPenaltyNot in the v2 schema
Top level of detailsrequestImpoundWaivedNot in the v2 schema
Top level of detailsrequestImpoundTypeNot in the v2 schema
Top level of detailsimpoundWaivedNot in the v2 schema
Top level of detailsimpoundTypeNot in the v2 schema
Top level of detailslenderFeeWaiverOptionNot in the v2 schema
Top level of detailssellerPaidMiPremiumNot in the v2 schema
Top level of detailsfhaUpfrontMiPremiumPercentNot in the v2 schema
Top level of detailsroundToNearest50Not in the v2 schema

New fields in v2

v2 objectNew field
requestSidecommitmentType
requestSidesrpPaidOut
requestSideonrpLockDate
requestSideonrpLockTime

Complete example

The example below shows a v1 details object and the same values converted to v2 by applying the changes on this page.

{
  "comments": "Lock requested at borrower request",
  "programNotes": "30 year fixed conforming program",
  "planCode": "99999",
  "lockDate": "07/24/2020",
  "lockExpirationDate": "08/30/2020",
  "lastRateSetDate": "05/19/2020",
  "hedging": true,
  "penaltyTerm": "1 Year",
  "prepayPenalty": true,
  "baseRate": 5.2,
  "basePrice": 4.5,
  "baseMarginRate": 1.5,
  "rateSheetId": "Sheet-ID-4555",
  "currentAcquisition": true,
  "currentConstructionRefi": false,
  "gpmRate": 5.5,
  "gpmYears": 10,
  "requestImpoundWaived": "Waived",
  "requestImpoundType": "No Impounds",
  "lenderFeeWaiverOption": true,
  "sellerPaidMiPremium": 1555,
  "fhaUpfrontMiPremiumPercent": 2,
  "roundToNearest50": true,
  "adjustments": [
    {
      "adjustmentType": "Adjustment",
      "description": "No FICO",
      "priceAdjustmentType": "BasePrice",
      "adjustment": 0.02
    },
    {
      "adjustmentType": "Adjustment",
      "description": "1 Year Payment Option",
      "priceAdjustmentType": "BaseMargin",
      "adjustment": 0.25
    },
    {
      "adjustmentType": "Adjustment",
      "description": "15 Day Lock Period",
      "priceAdjustmentType": "BaseRate",
      "adjustment": 0.002
    },
    {
      "adjustmentType": "Adjustment",
      "description": "Extended Payment Option",
      "priceAdjustmentType": "BaseRate",
      "adjustment": 0.001
    },
    {
      "adjustmentType": "LockExtensionAdjustment",
      "description": "Lock extension, 15 days",
      "priceAdjustmentType": "BasePrice",
      "adjustment": 0.125
    },
    {
      "adjustmentType": "ReLockFeeAdjustment",
      "description": "Relock fee",
      "priceAdjustmentType": "BasePrice",
      "adjustment": 0.25
    },
    {
      "adjustmentType": "CustomPriceAdjustment",
      "description": "Custom price adjustment",
      "priceAdjustmentType": "BasePrice",
      "adjustment": 0.05
    }
  ],
  "investor": "ABC Mortgage Investors",
  "impoundWaived": "Waived",
  "impoundType": "Taxes and Insurance",
  "additionalFields": [
    {
      "fieldName": "CX.PPE.PRICINGTIER",
      "stringValue": "Gold"
    }
  ]
}
{
  "requestSide": {
    "comments": "Lock requested at borrower request",
    "programNotes": "30 year fixed conforming program",
    "lockDate": "2020-07-24",
    "lockExpires": "2020-08-30",
    "currentRateSetDate": "2020-05-19",
    "rate": 5.2,
    "priceRate": 4.5,
    "marginRate": 1.5,
    "rateSheetId": "Sheet-ID-4555",
    "basePriceAdjustments": [
      {
        "priceAdjustmentTypeIndex": 0,
        "description": "No FICO",
        "rate": 0.02
      }
    ],
    "baseMarginAdjustments": [
      {
        "priceAdjustmentTypeIndex": 1,
        "description": "1 Year Payment Option",
        "rate": 0.25
      }
    ],
    "baseRateAdjustments": [
      {
        "priceAdjustmentTypeIndex": 2,
        "description": "15 Day Lock Period",
        "rate": 0.002
      },
      {
        "priceAdjustmentTypeIndex": 2,
        "description": "Extended Payment Option",
        "rate": 0.001
      }
    ],
    "lockExtensionAdjustments": [
      {
        "priceAdjustmentTypeIndex": 0,
        "description": "Lock extension, 15 days",
        "rate": 0.125
      }
    ],
    "reLockFeeAdjustments": [
      {
        "priceAdjustmentTypeIndex": 0,
        "description": "Relock fee",
        "rate": 0.25
      }
    ],
    "customPriceAdjustments": [
      {
        "priceAdjustmentTypeIndex": 0,
        "description": "Custom price adjustment",
        "rate": 0.05
      }
    ]
  },
  "additionalFields": [
    {
      "fieldName": "CX.PPE.PRICINGTIER",
      "value": "Gold"
    }
  ]
}

Migration checklist

  • Update $.result.format to application/vnd.productpricing-lock-2.0.0.json in all transaction responses that use v2.
  • Add application/vnd.productpricing-lock-2.0.0.json to the formats registered for LOCK in your product entitlements.
  • Move the top-level lock request fields into requestSide.
  • Convert additionalFields items to fieldName and value.
  • Convert all dates from MM/DD/YYYY to YYYY-MM-DD.
  • Apply the field renames in each object.
  • Split each adjustments[] array into the typed adjustment arrays, using priceAdjustmentTypeIndex, description, and rate.
  • Remove the fields that are not in v2.
  • Validate your v2 payloads against the JSON schema before deploying to production.

Support

If you have questions about this migration or encounter v2 validation issues, post them on our Discussion board or contact the EPC team at [email protected]. We recommend validating your v2 payloads against the JSON schema, and testing them in your EPC sandbox, before deploying to production.


Did this page help you?