Skip to main content

Case lifecycle & statuses

Your system sees a deliberately simple four-state model — internal operational sub-states are mapped onto it so we can evolve them without breaking you.

External statusMeaningTerminal?
pendingAccepted, live in the network, awaiting a field partnerno
in_progressA partner is assigned / visiting / a payment is in flight. Also the state between a partial payment and re-assignment.no
collectedFully collected (payments reached ≥ 99 % of the outstanding — 1 % tolerance)yes
closed_unrecoveredClosed without full recovery — recall, borrower not available / refused, write-off, legal handoveryes

Visits and partial payments do not change the external status — the case stays in_progress (each one arrives as its own visit.completed / payment.collected event) until it fully clears or closes.

Which event fires when​

MomentEventStatus after
Your row is accepted (POST /cases, not a dry-run)case.receivedpending
A field partner accepts the casecase.assigned (opt-in)in_progress
A visit is recorded, any outcomevisit.completed (opt-in)in_progress
Money booked — Mode A after our ops verifies the proof, Mode B when you call payments/confirmpayment.collectedin_progress (partial) — a full clear is followed by case.closed
Payments reach full clearancepayment.collected then case.closed status: collected, reason: full_settlementcollected
You call POST /cases/{loan}/recall on a non-terminal casecase.closed status: closed_unrecovered, reason: recalledclosed_unrecovered
Field outcome ends the case (borrower not found / refuses)case.closed reason: not_available or refusedclosed_unrecovered
Fieldproof admin writes the case offcase.closed reason: written_offclosed_unrecovered
Fieldproof admin hands the case over for legal actioncase.closed reason: legal_handoverclosed_unrecovered

Default webhook subscription is case.received, payment.collected, case.closed; case.assigned and visit.completed are opt-in (event reference). The poll API always returns all types.

Details worth knowing:

  • Recall is idempotent. On an already-terminal case it returns alreadyClosed: true with the existing status and emits nothing new. The assigned partner is told to stop.
  • Partial payment in Mode B (org_gateway): the case detaches from the partner and re-enters the marketplace after a cool-down (default 48 h) — externally still in_progress.
  • Re-pushing an active case (pending / in_progress) updates it in place — outstanding, DPD, address… — with no new case. Use this to correct an address after wrong_address / shifted.
  • Re-pushing a closed loan (collected / closed_unrecovered) opens a fresh case: new caseId, case.received again, and sequence restarts at 1. Watermark on (sourceLoanNumber, caseId) — see ordering.
  • One case per loan is active at a time; cases of the same loan never overlap.

Visit outcomes​

Delivered in visit.completed events (opt-in) and in the visits[] array of GET /cases/{loan}:

OutcomeMeaning
delivered_acknowledgedPayment notice delivered and acknowledged by the borrower
collected / partialMoney collected (full / part) — the partner's claim; the booking arrives as payment.collected
ptpPromise to pay with a committed date (ptpDate)
rtpRefuse to pay — the borrower declined to pay
refused / not_availableBorrower refused / not found this visit (also case.closed reasons when the case ends that way)
wrong_address / shiftedAddress problem — your cue to push a corrected address (just re-send the row)

Reading state correctly​

  • The event stream is the narrative; GET /api/v1/partner/cases/{sourceLoanNumber} is the authoritative snapshot — when in doubt (e.g. a sequence gap), fetch it. It returns the loan's active case if there is one, otherwise the most recent: { sourceLoanNumber, caseId, status, isActive, assignedAt, totalCollected, outstandingAmount, visits[] (last 20), createdAt, updatedAt }. A 404 CASE_NOT_FOUND means we hold no case for that loan number under your org.
  • visits[].amountCollected is the partner's unverified claim until a payment.collected confirms it (Mode A: after ops verification, and the operator-confirmed amount may differ). Book money from events, not from visits.
  • Payment events carry absolute values (totalCollected, outstandingAfter) — never accumulate deltas yourself. Amounts are whole INR rupees.
  • Never skip a payment.collected because it arrived out of order — book it and gate only your case-state fields on sequence (Updating your LMS).