Skip to main content
This page takes you from an empty database to one disbursed loan in six calls. Every call sends application/json. Send every money and rate field as a decimal string, never as a JSON number. Complete the Prerequisites first. Send the same bearer token on all six calls. Lender takes the officer from the token subject. Under the generic profile, only that officer can approve and disburse the application.
Use jurisdiction XX for this walkthrough. XX is Lender’s generic profile, and it computes no withholdings — which keeps the amounts in step 6 simple. A Brazilian regulated loan carries CET disclosure and capitalization consent. Read the Brazil regulatory pack for that path. A payroll-deducted contract belongs to the consignado privado bounded context. Read Consignado privado for its vocabulary and its lifecycle topics.

The six calls


1. Create the product


POST /api/v1/loan-products
loanType takes personal, commercial, or card. jurisdictionCode takes a code the registry carries: XX or BR. Any other code returns 422. The response carries the new id. The product is in draft, which is all this walkthrough needs: an application binds to a version, so you do not activate the product to originate.

2. Create a version


POST /api/v1/loan-products/{productId}/versions
The version is the immutable snapshot of terms an application binds to.
  • currency has no default. Supply a valid ISO-4217 code in uppercase. The version is the currency source of truth from here to the ledger.
  • A fixed version carries no floating linkage. With rateMode: fixed, omit floatingRateTableId, floatingSpreadBps, and requiresFloatingRate. Lender rejects a fixed version that carries any of them.
  • jurisdictionCode is required, and it must match the product’s. A version cannot move a product to another jurisdiction.
The response carries the versionId.

3. Bind an accounting profile


POST /api/v1/loan-products/{productId}/accounting-profiles The profile maps each accounting event onto general-ledger accounts. Lender needs it at disbursement, so bind it now.
Send seven or eight rules, one per accounting event. Seven events need a rule: disbursement, repayment, prepayment, accrual, collection_unapplied, collection_reapply, and collection_refund. accrual_tax is the optional eighth. Fewer than seven rules is rejected before the handler runs. Each leg declares exactly one of role or component, and no account appears on both sides of the same rule. Four events also carry a fixed leg shape: collection_reapply takes unapplied_cash as its only debit. Each credit it carries must also appear as a credit on repayment or prepayment, with the same account and the same role. disbursement and repayment each need at least one debit and one credit. Keep the disbursement rule at two legs, as above. Lender fills the cash leg with the net amount and every other structural leg with the gross amount. A component leg takes a computed withholding, and the generic profile computes none, so the two-leg rule is the one that balances under XX. In multi-tenant mode the profile also needs midazOrganizationId and midazLedgerId. Read Define a loan product for the wider product surface.

4. Create the application


POST /api/v1/loan-applications
  • requestedInterestRate is the monthly rate as a decimal string at scale 8. It must be greater than 0 and no greater than 1. Lender builds the schedule from this rate: "0.01500000" a month is 1800 bps a year.
  • requestedInstallments is between 1 and 600.
  • previewScheduleSnapshotId is a UUID you generate to identify the quote you showed the borrower. Lender records it on the application. Compute the schedule you show with POST /api/v1/loan-applications/preview-schedule. That call persists nothing and returns no identifier. Mint the identifier on your side and keep it with your own quote record.
  • There is no assignedOfficerId field. Lender sets it from the token subject.
The application comes back in pending_approval, carrying the jurisdiction code and profile version Lender resolved from the product version.

5. Approve


POST /api/v1/loan-applications/{id}/approve
approvedAmount becomes the ceiling on everything you disburse. Under XX, only the officer who created the application may approve it. The application moves to approved and carries the decision record.

6. Disburse


POST /api/v1/loan-applications/{id}/disburse Send the header X-Idempotency. Lender requires it. A retry with the same value replays the first response, and records no second disbursement.
Under XX, netDeliveredAmount must equal grossRequestedAmount. The disbursement posting balances as net equals gross minus withholdings, and the generic profile computes no withholdings. Any lower net leaves the posting unbalanced and Lender rejects the disbursement.
loanAccountId is a UUID you supply — Lender does not mint it. It identifies the loan account this contract services under, and it is immutable across later tranches of the same application. Lender also checks that:
  • netDeliveredAmount does not exceed grossRequestedAmount.
  • grossRequestedAmount, and the running total across tranches, does not exceed approvedAmount.
  • disbursedAt is not before the approval decision.
  • The jurisdiction and profile version still match the pair Lender resolved at step 4.
originationFeeAmount is optional. It carries cost metadata that accrual reads. Lender does not treat it as a withholding, so it does not change the net-to-gross relationship.

Confirm the loan exists


The disburse response carries the application in disbursed with its disbursement event. Then read the loan account: The response also carries profileVersion — the jurisdiction profile version, not a product version. It carries no currency. The loan uses the currency you set on the loan product version in step 1. Keep that value with your own product record. If you configured Midaz, the disbursement posting reaches the ledger once the outbox dispatcher relays the intent. That happens shortly after the call, not inside it.

Next steps


Service a loan

Record repayments, prepay, reschedule, and correct a live loan account.

How accrual works

Interest recognition runs on its own schedule. Start an accrual run, or enable the heartbeat.