Skip to main content
Origination is the journey from “a borrower wants credit” to “a loan account exists and the disbursement is recorded”. Lender models it as an explicit application lifecycle. The lifecycle keeps a record of every decision, and it makes every disbursement traceable.

The application lifecycle


An application moves through named states. Each transition is a distinct operation, and each keeps a decision or disbursement record:

Steps


1

Preview the schedule (optional)

POST /api/v1/loan-applications/preview-schedule computes the amortisation schedule for prospective terms without originating anything. When it records the quote as an offer, it returns the offer’s scheduleOfferSnapshotId, which the application can cite. Use it to show installments and disclosures before anyone commits.
2

Submit the application

POST /api/v1/loan-applications creates the application against the product’s current version. It declares the borrower kind, and the requested rate must fall inside the version’s rate band.
3

Decide

Resolve the application with exactly one of:
  • POST /api/v1/loan-applications/{id}/approve: accept it, with a decision record.
  • POST /api/v1/loan-applications/{id}/reject: decline it, with a decision record.
  • POST /api/v1/loan-applications/{id}/withdraw: retract it while pending approval or, after approval, before disbursement.
4

Disburse

POST /api/v1/loan-applications/{id}/disburse records the funds delivered. It takes the X-Idempotency key every write on this page takes. A retry under the same key therefore replays the first response and records no second disbursement.One database transaction commits the disbursement event, the origination schedule, and a balanced posting intent. When the call returns, the loan is an active loan account you service from here on.The ledger booking is not in that transaction. With the ledger relay configured, an outbox dispatcher relays the intent to Midaz shortly after the response, through the product’s accounting profile. Otherwise, the intent remains in the outbox. See the posting path.

Every write takes an idempotency key


Creating an application and moving it (approve, reject, withdraw, disburse) all require the X-Idempotency header. Lender reads the key from that spelling and no other. It refuses Idempotency-Key and X-Idempotency-Key by name, so a client is never silently unprotected because it guessed the header. Sending one of those alongside the contract header is fine. The refusal fires only when X-Idempotency is absent. The guard fails closed. When the idempotency store cannot answer, Lender refuses the request with 503 instead of waving it through unprotected. Creation costs a key deliberately: without one, a client that times out on create and calls again books a second application for the same borrower. That is the cheapest duplicate in the service to produce and the most expensive to unpick. It is expensive because both copies look legitimate and only a person can say which one is real.
On the four lifecycle writes, you can reconcile a request that ends unresolved and resubmit it under a new key. Read the application by id and ask whether it already holds the state you wanted. Disbursement is the exception, where a new key is not a safe recovery at all. A genuine second release declares its tranche instead.

The product has to be active


Origination reads the loan product’s activation status and refuses a product that is not active, with LENDER-0225 and a 422. The refusal sits on the three steps that decide new credit: creating the application, approving it, and releasing the money over the API. A product switched off after an application was filed therefore stops that application before the money leaves. Creating an application must also name the product’s current version, or Lender refuses it with LENDER-0226 and a 422. That check runs at creation and nowhere else, because an application keeps the version it was born on for life. Promoting a new version therefore never kills the applications standing against the old one, and each of them still books on the version it named. See Define a loan product. Two paths sit outside this gate on purpose:
  • The consignado rail, which records a contract the client’s own systems already registered with the payroll rail. Refusing a fact that already happened would leave the book denying a contract the borrower holds.
  • A substantial renegotiation, whose replacement contract inherits the product version of the contract it replaces. The replacement contract inherits that version whether or not that product is still active and whether or not that version is still current. Renegotiating services credit already written. Only a new application is new credit.
Lender gates nothing after origination. Reject, withdraw, servicing, and accounting keep working against a product retired years later.

What you get


Disbursement produces a loan account, the servicing view of the live contract, carrying its schedule, transactions, charges, and audit history. Continue in Service a loan.

What happens downstream


The lifecycle emits loan_application.submitted, loan_application.approved, loan_application.rejected, loan_application.withdrawn, and loan_application.disbursed, each at schema version 2.0.0. Disbursement records a durable posting intent and relays it to the ledger only when you configure the ledger relay. Read the posting path.
Brazilian origination adds regulated steps (CET disclosure and capitalization consent) covered in the Brazil regulatory pack. The payroll-deducted consignado flow forms its own Brazilian bounded context. See Consignado privado.

Next steps


Service a loan

Record repayments, prepay, reschedule, and correct an active loan account.