docs.vin

Repossession end to end

Default → right to cure → assignment → recovery → NOI → redemption or deficiency — every step a catalog capability, runnable against the sandbox world.

A repossession is a loan told through its worst month. The note goes delinquent, the borrower gets the cure notice the law requires, the agent is assigned and recovers the unit, the notice of intent to sell goes out — and the story ends one of two ways: the borrower redeems, or the sale settles the ledger and bills the shortfall. Under the journey-ownership ruling (2026-08-17), every door on this walk answers from its shared-world owner: the delinquency read from the note desk, the assignment / recovery / NOI / redemption-window arc from the repo yard that adjudicates the RepoServicingFSM itself, and the compliance and money doors from the legal-adverse rails. The journey consumes those answers — it never mints a second story.

The cast

This journey rides the curated world — deterministic, replayable, every payload provenance-labeled. One fleet exemplar stands at each position of the RepoServicingFSM arc. The full trigger register is at sandbox test triggers.

World keyRole in this journey
1FL0ANLATE0000000The defaulted note: LoanServicingFSM Delinquent, the pipeline open.
1FL0ANDEFERRED000The deferred note: the pipeline stands Cured.
1FL0ANREC0VERY000The assigned case: the agent is out.
1FLANESCHED000000The recovered unit: consigned inbound to the lane.
1FLANE0PEN0000000The open redemption window: the borrower's clock runs.
1FLANED1SBURSED00The billed deficiency: sold short, NOI on record.
1FKEEPM0N1T0R0000The current note: nothing to repossess.
1FDEALFRESH000000No loan story on the row.

1 — Read the default

capabilityloanServicing.delinquencyPOST /loan-servicings/delinquency

The note desk consults the machines: the defaulted note reads Delinquent with the repo pipeline alongside, the deferred note reads its Cured pipeline, a current note is simply not delinquent — and iron with no note answers no-open-loan. The desk never invents a borrower.

runnable — sandbox · deterministic1FL0ANLATE0000000
run it — POST /loan-servicings/delinquency
curl -X POST 'https://apis.vin/loan-servicings/delinquency' \
  -H 'content-type: application/json' \
  -d '{"vin":"1FL0ANLATE0000000"}'
the world answers — LoanServicingDelinquency@1
{
  "vin": "1FL0ANLATE0000000",
  "noun": "loanServicing",
  "asOf": "2026-08-10",
  "delinquency": {
    "status": "run",
    "delinquent": true,
    "loanId": "LN-840f59ff",
    "servicingId": "SVC-c543660d",
    "position": "Delinquent",
    "repoPipeline": "Delinquent"
  }
}

2 — The right to cure

capabilityrepossession.rightToCureNoticePOST /repossessions/right-to-cure-notice

The legal-adverse rail posts the compliance record: a RTC- notice, the documented 20-day cure period, certified-mail delivery. The rail does not read the note's standing before it answers — that gap is filed and attested below.

runnable — sandbox · deterministic1FL0ANLATE0000000
run it — POST /repossessions/right-to-cure-notice
curl -X POST 'https://apis.vin/repossessions/right-to-cure-notice' \
  -H 'content-type: application/json' \
  -d '{"vin":"1FL0ANLATE0000000"}'
the world answers — RepossessionRightToCureNotice@1
{
  "vin": "1FL0ANLATE0000000",
  "noticeRef": "RTC-001L",
  "cureAmount": { "amount": "1840.50", "currency": "USD" },
  "cureDeadline": "2026-08-30",
  "curePeriodDays": 20,
  "deliveryMethod": "certified-mail",
  "compliant": true,
  "asOf": "2026-08-10"
}

3 — Authorize and assign

capabilityrepossession.triggerrepossession.assignPOST /repossessions/assign

The trigger posts the rail's authorization record (REPO- case, breach-of- peace check, cure expiry). The assignment is the yard's: it adjudicates the RepoServicingFSM at the observation — the delinquent case is assignable under its RCV- id, the out-for-recovery case answers already-assigned, a recovered unit answers past-assignment, and a current note has no-repo-on-file. The yard's loanId IS the note desk's — one note, both clusters.

runnable — sandbox · deterministic1FL0ANLATE0000000
run it — POST /repossessions/assign
curl -X POST 'https://apis.vin/repossessions/assign' \
  -H 'content-type: application/json' \
  -d '{"vin":"1FL0ANLATE0000000","account":"acc_demo"}'
the world answers — RepossessionAssign@1
{
  "vin": "1FL0ANLATE0000000",
  "noun": "repossession",
  "asOf": "2026-08-10",
  "id": "RCV-2bfeda78",
  "loanId": "LN-840f59ff",
  "status": "Delinquent",
  "assignment": { "status": "assignable", "caseId": "RCV-2bfeda78" }
}

4 — Recover

capabilityrepossession.recoverPOST /repossessions/recover

The arc never runs out of order: the assigned case is recoverable, the merely-delinquent one answers not-yet-assigned, and the recovered exemplar answers already-recovered — same RCV- case, every door.

runnable — sandbox · deterministic1FL0ANREC0VERY000
run it — POST /repossessions/recover
curl -X POST 'https://apis.vin/repossessions/recover' \
  -H 'content-type: application/json' \
  -d '{"vin":"1FL0ANREC0VERY000"}'
the world answers — RepossessionRecover@1
{
  "vin": "1FL0ANREC0VERY000",
  "noun": "repossession",
  "asOf": "2026-08-10",
  "id": "RCV-2d158182",
  "loanId": "LN-627eea15",
  "status": "Assigned",
  "recovery": { "status": "recoverable", "caseId": "RCV-2d158182" }
}

5 — The notice of intent to sell

capabilityrepossession.noticeCompliancePOST /repossessions/notice-compliance

The NOI answers only post-recovery (noi-issuable, its own NOI- id), an assigned-but-unrecovered case answers not-yet-recovered, and after the sale the notice stands noi-on-record with the position that closed it.

runnable — sandbox · deterministic1FLANESCHED000000
run it — POST /repossessions/notice-compliance
curl -X POST 'https://apis.vin/repossessions/notice-compliance' \
  -H 'content-type: application/json' \
  -d '{"vin":"1FLANESCHED000000"}'
the world answers — RepossessionNoticeCompliance@1
{
  "vin": "1FLANESCHED000000",
  "noun": "repossession",
  "asOf": "2026-08-10",
  "id": "RCV-37cb689c",
  "loanId": "LN-29304a23",
  "status": "Recovered",
  "notice": { "status": "noi-issuable", "id": "NOI-23a71736" }
}

6 — Redeem: the window and the quote

capabilityrepossession.redemptionrepossession.redeemPOST /repossessions/redeem

Two doors, two owners. The yard's redeem adjudicates the window — open on the window exemplar, window-closed after the sale — with its money HONESTLY not-posted (the yard's declared no-world-money-law block). The rail's redemption posts a quote whose arithmetic is internally whole: payoff + recovery costs = the redemption amount, to the cent.

runnable — sandbox · deterministic1FLANE0PEN0000000
run it — POST /repossessions/redeem
curl -X POST 'https://apis.vin/repossessions/redeem' \
  -H 'content-type: application/json' \
  -d '{"vin":"1FLANE0PEN0000000","assignment":"rpa_demo"}'
the world answers — RepossessionRedeem@1
{
  "vin": "1FLANE0PEN0000000",
  "noun": "repossession",
  "asOf": "2026-08-10",
  "id": "RCV-732b99c2",
  "loanId": "LN-d0889f55",
  "status": "RedemptionWindow",
  "redemption": {
    "status": "window-open",
    "caseId": "RCV-732b99c2",
    "amount": { "status": "not-posted", "basis": "no-world-money-law" }
  }
}

7 — Or: the sale settles the ledger

capabilityrepossession.deficiencyGET /repossessions/deficiency

The rail's deficiency record reconciles internally, to the cent: payoff + recovery fees − remarketing proceeds = the billed balance, with the commercially-reasonable-sale and post-sale-notice attestations on the wire.

runnable — sandbox · deterministic1FLANED1SBURSED00
run it — GET /repossessions/deficiency
curl 'https://apis.vin/repossessions/deficiency?vin=1FLANED1SBURSED00'
the world answers — RepossessionDeficiency@1
{
  "vin": "1FLANED1SBURSED00",
  "deficiencyRef": "RDF-0031",
  "fsmState": "DeficiencyBilled",
  "payoffBalance": { "amount": "24604.00", "currency": "USD" },
  "remarketingProceeds": { "amount": "18604.00", "currency": "USD" },
  "recoveryFeesAndCosts": { "amount": "1104.00", "currency": "USD" },
  "deficiencyBalance": { "amount": "7104.00", "currency": "USD" },
  "commerciallyReasonableSale": true,
  "postSaleNoticeSent": true,
  "asOf": "2026-08-10"
}

Where the world refuses

capabilityrepossession.assignrepossession.recoverPOST /repossessions/assign

The yard's refusals are typed, never a wall: no-repo-on-file for a current note, not-yet-assigned for a premature recovery, past-assignment and already-recovered where the arc has moved on, window-closed after the sale.

runnable — sandbox · deterministic1FKEEPM0N1T0R0000
run it — POST /repossessions/assign
curl -X POST 'https://apis.vin/repossessions/assign' \
  -H 'content-type: application/json' \
  -d '{"vin":"1FKEEPM0N1T0R0000","account":"acc_demo"}'
the world answers — RepossessionAssign@1 (no pipeline)
{
  "vin": "1FKEEPM0N1T0R0000",
  "noun": "repossession",
  "asOf": "2026-08-10",
  "repo": { "status": "no-repo-on-file" }
}

What the record now holds — and what it does not

The walk posts one pipeline story on the desk and the yard: a machine-read delinquency (no-open-loan where there is no note), a position-adjudicated assignment → recovery → NOI → redemption-window arc under one RCV- case per VIN, the yard's loanId in byte parity with the note desk's, and internally-whole money records on the legal-adverse rails.

Thin ground, attested (each filed as a bd model-gap, per the honest-grade law — the journey suite pins today's bytes as the tripwire): the legal-adverse rails never adjudicate standing — a current note gets a cure notice and an authorized trigger, every VIN carries a redemption window and a billed deficiency, the Cured exemplar included (vin-xnmw); and the repo money never crosses clusters — no arrears rides the delinquency read, the rail's payoffBalance is not the payoff rail's own payoff.quote figure, and the yard and the rail tell two redemption stories for one window (vin-nytj). Compose the facts on the record face, GET /{vin}, at the record.

Next