Versioning and changelog
Versions
The major version is in every path: https://secondappraisal.com/api/gap/v1. Within it, the OpenAPI document gives its own version as info.version; the document this API serves is version 1.4.0. The reference is generated from the same document.
What may change within a version
- New operations, new response fields and new webhook event types. Ignore fields and event types you don't recognise.
- New values in an enum a response carries. Each such enum says in the reference what to do with a value you don't recognise.
- What a label or a description says, and when the API sends a value. The document doesn't show these, so the changelog below lists each.
Requests are strict: send only the fields a request's schema names. Any other is refused with 400 validation_failed, its field_errors naming the field with the code unknown_field.
Deprecations
A deprecated parameter or field is marked deprecated in the document and the reference, and is still accepted until it is withdrawn; its description says what it does now. A deprecated operation's responses carry:
Deprecation: RFC 9745: when the operation was deprecated, as@<unix seconds>.Sunset: RFC 8594: when the operation stops answering (an HTTP date).Link:rel="deprecation": where the migration is described.
Deprecated now
- The
external_refparameter ofGET /api/gap/v1/referrals - The
vinparameter ofGET /api/gap/v1/plans/enrollments - The
liability.deductible_centsfield ofReferral - The
deductible_centsfield ofReferralBulkRow - The
deductible_centsfield ofReferralCreateInput - The
financial.deductible_centsfield ofReferralDetail - The
deductible_centsfield ofReferralUpdateInput - The
outreach.contact_stopped_atfield ofReviewRecordBundle - The
liability.deductible_centsfield ofWebhookReferral
Changelog
The changes each version shipped that its document doesn't show, newest first. A new or changed field, type, operation or event shows in the document itself.
Version 1.4.0
In production from November 8, 2026
financial.savings_statementreads "Estimated exposure reduced (loan payoff minus the insurer's figure) from $8,400 to $2,100 — $6,300 saved.", settled or not. Before Release F it named the reduction as the GAP amount itself, starting with "Projected" until the referral settled.On:GET /api/gap/v1/referrals/{id},PATCH /api/gap/v1/referrals/{id},POST /api/gap/v1/referrals/{id}/simulate
Version 1.3.0
In production from October 19, 2026
GET /api/gap/v1/referrals/{id}no longer gives a membership referral's "Invitation sent" step, since a borrower who activated without an invitation was never sent the co-branded link, and the current step moves on to the next one not done. Invitation referrals and warm handoffs read as before.On:GET /api/gap/v1/referrals/{id},PATCH /api/gap/v1/referrals/{id},POST /api/gap/v1/referrals/{id}/simulate
Version 1.2.0
In production from October 15, 2026
timeline: whileborrower_invitedis the current milestone (you haven't sent the borrower's invitation yet), itswaiting_onandwaiting_labelarenull, since sending the invitation is your step. Before Release D they read"borrower"and "Waiting on borrower".On:GET /api/gap/v1/referrals/{id},PATCH /api/gap/v1/referrals/{id},POST /api/gap/v1/referrals/{id}/simulatetimeline: whileborrower_invitedis current, until the borrower activates, itsdetailreads "The institution hasn't sent the borrower's invitation yet." Before Release D it read "SecondAppraisal sent the borrower a co-branded activation link.", which it still reads once the invitation is sent. Once itsdelayedis true, more than 10 days after the referral, itsnotereads "Not sent yet, more than 10 days after the referral."On:GET /api/gap/v1/referrals/{id},PATCH /api/gap/v1/referrals/{id},POST /api/gap/v1/referrals/{id}/simulatetimeline: whiledisclosure_attestedis current on a warm handoff, until the borrower activates, itsdetailreads "The institution hasn't confirmed the program disclosure yet." Once you attest, it reads "The institution confirmed the program disclosure was delivered to the borrower." Before Release D it read "The provider confirmed the program disclosure was delivered to the borrower." in both states.On:GET /api/gap/v1/referrals/{id},PATCH /api/gap/v1/referrals/{id},POST /api/gap/v1/referrals/{id}/simulate,POST /api/gap/v1/referrals/{id}/attesttimeline: on a referral that activated without an invitation (a membership referral, or one our staff activated on a call),borrower_invited'sdelayedis alwaysfalse.On:GET /api/gap/v1/referrals/{id},PATCH /api/gap/v1/referrals/{id},POST /api/gap/v1/referrals/{id}/simulatetimeline:referral_submitted'sdetailnames the institution: "The institution referred this borrower for an independent appraisal." Before Release D it read "The provider submitted this borrower for an independent appraisal."On:GET /api/gap/v1/referrals/{id},PATCH /api/gap/v1/referrals/{id},POST /api/gap/v1/referrals/{id}/simulate,POST /api/gap/v1/referrals/{id}/attesttimeline: a cancelled referral'sterminal.detailreads "The institution cancelled this referral before activation." Before Release D it read "The provider cancelled this referral before activation."On:GET /api/gap/v1/referrals/{id},PATCH /api/gap/v1/referrals/{id},POST /api/gap/v1/referrals/{id}/simulatetimeline: the fourth phase, betweenresearchandsettlement, is labelled "Appraisal award" from Release D on. Its key is unchanged.On:GET /api/gap/v1/referrals/{id},PATCH /api/gap/v1/referrals/{id},POST /api/gap/v1/referrals/{id}/simulate,POST /api/gap/v1/referrals/{id}/attesttimeline: theappraisals_exchangedmilestone'slabelreads "Appraisals exchanged — working toward an award", and itsdetailreads "Both appraisals are in; the two appraisers are working to agree on the vehicle's value." Both changed in Release D, with the phase label. A FULL_V1consultation.status_changedbody that namesappraisals_exchangedcarries itslabelanddetailtoo, so it reads the new wording.On:GET /api/gap/v1/referrals/{id},PATCH /api/gap/v1/referrals/{id},POST /api/gap/v1/referrals/{id}/simulate,POST /api/gap/v1/referrals/{id}/atteststatus_label: ahandoff_pendingreferral reads "Awaiting the institution's disclosure", and acancelledone reads "Cancelled by the institution". Before Release D they read "Awaiting provider disclosure" and "Cancelled by provider". A FULL_V1 webhook body'sreferral.status_labelreads the same.On:POST /api/gap/v1/referrals,GET /api/gap/v1/referrals,POST /api/gap/v1/referrals/bulk,GET /api/gap/v1/referrals/{id},PATCH /api/gap/v1/referrals/{id},POST /api/gap/v1/referrals/{id}/simulate,POST /api/gap/v1/referrals/{id}/attest- A warm-handoff delivery day sent with no time is stored as noon UTC on that day, such as
2026-10-12T12:00:00.000Z, which falls on the day sent in every US time zone. It was midnight UTC, the evening before across the US. The day is thedelivered_onyou send inline on a create or a bulk row, or on an attest (YYYY-MM-DD, as before), or thedisclosure_delivered_oncolumn of the portal's Bulk upload, which also takes the day as a spreadsheet saves it (10/12/2026). The referral'sconsent.disclosure_confirmed_atand the review record'soutreach.disclosure_confirmed_at(staged, with review records) return it. Attestations recorded before the change keep their stored instant. The checks that a day is at most a day ahead and no more than 90 days old measure from that noon: a day ahead is accepted from noon UTC the day before (it was from midnight), and a day 90 days back is accepted 12 hours longer. A value with a time is read as sent, as before.On:POST /api/gap/v1/referrals,GET /api/gap/v1/referrals,POST /api/gap/v1/referrals/bulk,GET /api/gap/v1/referrals/{id},PATCH /api/gap/v1/referrals/{id},POST /api/gap/v1/referrals/{id}/simulate,POST /api/gap/v1/referrals/{id}/attest,GET /api/gap/v1/referrals/{id}/review-record