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

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_statement reads "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: while borrower_invited is the current milestone (you haven't sent the borrower's invitation yet), its waiting_on and waiting_label are null, 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}/simulate
  • timeline: while borrower_invited is current, until the borrower activates, its detail reads "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 its delayed is true, more than 10 days after the referral, its note reads "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}/simulate
  • timeline: while disclosure_attested is current on a warm handoff, until the borrower activates, its detail reads "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}/attest
  • timeline: on a referral that activated without an invitation (a membership referral, or one our staff activated on a call), borrower_invited's delayed is always false.On: GET /api/gap/v1/referrals/{id}, PATCH /api/gap/v1/referrals/{id}, POST /api/gap/v1/referrals/{id}/simulate
  • timeline: referral_submitted's detail names 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}/attest
  • timeline: a cancelled referral's terminal.detail reads "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}/simulate
  • timeline: the fourth phase, between research and settlement, 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}/attest
  • timeline: the appraisals_exchanged milestone's label reads "Appraisals exchanged — working toward an award", and its detail reads "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_V1 consultation.status_changed body that names appraisals_exchanged carries its label and detail too, 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}/attest
  • status_label: a handoff_pending referral reads "Awaiting the institution's disclosure", and a cancelled one reads "Cancelled by the institution". Before Release D they read "Awaiting provider disclosure" and "Cancelled by provider". A FULL_V1 webhook body's referral.status_label reads 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 the delivered_on you send inline on a create or a bulk row, or on an attest (YYYY-MM-DD, as before), or the disclosure_delivered_on column of the portal's Bulk upload, which also takes the day as a spreadsheet saves it (10/12/2026). The referral's consent.disclosure_confirmed_at and the review record's outreach.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