docs.vin

Refinance end to end

Payoff quote → refi application → funding → GL reconcile — every step a catalog capability, runnable against the sandbox world.

A refinance moves no metal — it is a walk over the note. The borrower's agent quotes what the current lienholder will take, applies for a new note at a better rate, funds the payoff to the old lender, and posts the balanced general-ledger batch that proves the money moved. Every number below is ONE number: the net payoff the quote answers is the principal the origination sizes, the amount the remit moves, and the totals the GL batch balances to.

The cast

This journey rides the curated world — deterministic, replayable, every payload provenance-labeled. The full trigger register is at sandbox test triggers.

World keyRole in this journey
1FKEEPM0N1T0R0000The monitored keep-arc car: LoanServicingFSM stands at Current — an open, refinance-able note.
Ava Good, 94103The super-prime anchor: her tier prices the offer at the posted 4.49% / 72mo band.
F3TC22The lienholder of record in the payoff registry (VIN-serviceable, no account number needed).
1FL0ANLATE0000000The delinquent-loan exemplar: the world refuses to refinance past-due paper.

1 — Quote the payoff

capabilitypayoff.quoteGET /payoffs/quote

The number every refi turns on: what the current lienholder says it will take, as of a date, to release the title. The financing rail answers the ratified door wire flat — gross, net, per-diem, allowance, good-through.

runnable — sandbox · deterministic1FKEEPM0N1T0R0000
run it — GET /payoffs/quote
curl 'https://apis.vin/payoffs/quote?vin=1FKEEPM0N1T0R0000&financeSourceId=F3TC22'
the world answers — PayoffQuote@1
{
  "vin": "1FKEEPM0N1T0R0000",
  "lienholder": "Huntington National Bank",
  "grossPayOffAmount": { "currency": "USD", "minorUnits": 2038411 },
  "netPayOffAmount": { "currency": "USD", "minorUnits": 2032829 },
  "perDiem": { "currency": "USD", "minorUnits": 274 },
  "allowance": { "currency": "USD", "minorUnits": 5582 },
  "goodThrough": "2026-08-20T00:00:00.000Z",
  "freshQuote": true
}

2 — Check the standing

capabilityrefinance.eligibilityGET /refinances/eligibility

The application gate. The world adjudicates off the note's LoanServicingFSM position at the observation: an open current note stands eligible; delinquent, in-recovery, or paid-off paper refuses; branded iron refuses on collateral.

runnable — sandbox · deterministic1FKEEPM0N1T0R0000
run it — GET /refinances/eligibility
curl 'https://apis.vin/refinances/eligibility?vin=1FKEEPM0N1T0R0000'
the world answers — RefinanceEligibility@1
{
  "vin": "1FKEEPM0N1T0R0000",
  "asOf": "2026-08-10",
  "eligible": true,
  "standing": "eligible",
  "loanStatus": "Current",
  "lienholder": { "fsId": "F3TC22", "name": "Huntington National Bank" },
  "collateral": { "titleBranded": false, "disposition": "retail", "mileage": 32400 }
}

3 — Price the new note

capabilityrefinance.rateOfferrefinance.savingsGET /refinances/rate-offer

The applicant resolves through the persona cast, and the offer prices at her credit tier's posted band — the same tier, the same APR, the credit rail answers for the same identity. refinance.savings derives the delta over the same principal; it is a derivation, never a second number.

runnable — sandbox · deterministicAva Good, 94103
run it — GET /refinances/rate-offer
curl 'https://apis.vin/refinances/rate-offer?vin=1FKEEPM0N1T0R0000&firstName=Ava&lastName=Good&zip=94103'
the world answers — RefinanceRateOffer@1
{
  "vin": "1FKEEPM0N1T0R0000",
  "applicant": { "name": "Ava Good", "castRow": "super-prime", "creditTier": "super-prime" },
  "offered": true,
  "offerId": "off_010fa04f",
  "apr": "4.49",
  "termMonths": 72,
  "rateBand": "best",
  "decision": "approved",
  "stipulations": []
}

4 — Originate

capabilityrefinance.originatePOST /refinances/originate

The new note, sized by the world: the principal IS the net payoff the quote answered, the rate IS the offer, and the payoff reference points back at the quote the funding will retire.

runnable — sandbox · deterministic1FKEEPM0N1T0R0000
run it — POST /refinances/originate
curl -X POST 'https://apis.vin/refinances/originate' \
  -H 'content-type: application/json' \
  -d '{"vin":"1FKEEPM0N1T0R0000","firstName":"Ava","lastName":"Good","zip":"94103"}'
the world answers — RefinanceOriginate@1
{
  "vin": "1FKEEPM0N1T0R0000",
  "refiId": "refi_6fd1dcd1",
  "payoffReference": "poq_a2a1e93f",
  "principal": { "currency": "USD", "minorUnits": 2032829 },
  "apr": "4.49",
  "termMonths": 72,
  "monthlyPayment": { "currency": "USD", "minorUnits": 32260 },
  "status": "Originated"
}

5 — Fund: remit the payoff

capabilityrefinance.payoffRemitPOST /refinances/payoff-remit

The funding leg: the net figure — the same minorUnits the quote answered — moves to the old lienholder inside the quote's good-through window.

runnable — sandbox · deterministic1FKEEPM0N1T0R0000
run it — POST /refinances/payoff-remit
curl -X POST 'https://apis.vin/refinances/payoff-remit' \
  -H 'content-type: application/json' \
  -d '{"vin":"1FKEEPM0N1T0R0000"}'
the world answers — RefinancePayoffRemit@1
{
  "vin": "1FKEEPM0N1T0R0000",
  "remitId": "rmt_d137a8e6",
  "lienholder": "Huntington National Bank",
  "payoffReference": "poq_a2a1e93f",
  "amount": { "currency": "USD", "minorUnits": 2032829 },
  "method": "ach",
  "goodThrough": "2026-08-20T00:00:00.000Z",
  "status": "Remitted"
}

6 — GL reconcile

capabilityledger.postPOST /ledgers/post

The proof the money moved: a balanced double-entry batch off the same net figure — debit the new loan receivable, credit the payoff clearing account. Totals equal by construction; the basis names the payoff reference the remit carried.

runnable — sandbox · deterministic1FKEEPM0N1T0R0000
run it — POST /ledgers/post
curl -X POST 'https://apis.vin/ledgers/post' \
  -H 'content-type: application/json' \
  -d '{"vin":"1FKEEPM0N1T0R0000"}'
the world answers — LedgerPost@1
{
  "vin": "1FKEEPM0N1T0R0000",
  "batchId": "glb_88949fea",
  "entries": [
    { "account": "loan-receivable:new-note", "side": "debit", "amount": { "currency": "USD", "minorUnits": 2032829 } },
    { "account": "payoff-clearing:lienholder", "side": "credit", "amount": { "currency": "USD", "minorUnits": 2032829 } }
  ],
  "totals": {
    "debits": { "currency": "USD", "minorUnits": 2032829 },
    "credits": { "currency": "USD", "minorUnits": 2032829 }
  },
  "balanced": true,
  "basis": { "payoffReference": "poq_a2a1e93f", "lienholder": "Huntington National Bank" },
  "status": "Posted"
}

Where the world refuses

capabilityrefinance.originatePOST /refinances/originate

The refusal is typed, never a wall. Delinquent paper refuses with the loan's own position — the same position the repossession journey picks up from — and a declined credit tier refuses with the adverse-action notice.

runnable — sandbox · deterministic1FL0ANLATE0000000
run it — POST /refinances/originate
curl -X POST 'https://apis.vin/refinances/originate' \
  -H 'content-type: application/json' \
  -d '{"vin":"1FL0ANLATE0000000"}'
the world answers — RefinanceOriginate@1 (refused)
{
  "vin": "1FL0ANLATE0000000",
  "status": "refused",
  "reason": "loan-delinquent",
  "loanStatus": "Delinquent"
}

What the record now holds

The journey posted one coherent money story: a payoff quote (poq_a2a1e93f), a new note originated against it, a remit of exactly its net figure, and a balanced GL batch whose basis points back at the same reference. The origination emits Refinance.originated@1 and the remit Refinance.payoffRemitted@1 — see the event registry. Compose the facts on the record face, GET /{vin}, at the record.

Next