Loan Webhook Payloads
Payload reference for loan.created and loan.updated, and how they differ from drawdown transactions.
Loan webhooks notify you about the lifecycle of a loan account held by a merchant's customer — its creation, its status, and its balances. They are distinct from loan transactions: drawing funds against a loan produces a drawdown transaction and emits a transaction event instead. See Transaction Webhook Payloads.
| Event | Fires when |
|---|---|
loan.created | A loan account is first recorded against a merchant. |
loan.updated | An existing loan account's details, status, or balances change. |
Both events share the same data shape.
Payload
data is an envelope carrying the loan account object plus the merchant it belongs to.
{
"id": "what_test_6knw5fhtys9egrxtd6bt0txjhj",
"webhookId": "wh_test_57vn6accfv9hrb5kqehv3k47tx",
"eventType": "loan.updated",
"data": {
"type": "loan",
"merchantId": "mid_test_wsqgngrn99gptndb1h2s70dzj",
"createdOn": "2026-03-04T14:22:10Z",
"modifiedOn": "2026-07-18T09:41:55Z",
"loan": {
"id": "tkn_test_4hb2n8xq5m81wcvfd7k3prz9ta",
"brand": "Greensky",
"type": "CREDIT",
"status": "ACTIVE",
"merchantName": "Documentation Corp",
"externalLoanId": "1234567890",
"creditLimit": 1500000,
"availableCredit": 1250000,
"currentBalance": 250000,
"applicationDate": "2026-03-01",
"originationDate": "2026-03-04",
"expirationDate": "2031-03-04"
}
}
}Envelope fields
| Field | Description |
|---|---|
type | Always loan. Identifies the payload kind. |
merchantId | The merchant the loan belongs to, prefixed mid_. |
createdOn | When the loan record was created, ISO 8601 UTC. |
modifiedOn | When the loan record last changed, ISO 8601 UTC. Use this to discard stale notifications. |
loan | The loan account object. |
loan fields
loan fields| Field | Description |
|---|---|
id | Preczn's identifier for the loan record. |
externalLoanId | The lender's own identifier for the loan. Use this when reconciling directly with the lender. |
brand | The lender, such as Greensky or NelNet. |
type | The instrument type of the loan. |
status | The loan's status, normalized by Preczn. The values you can receive depend on the lender — see below. |
merchantName | The merchant's name. |
creditLimit | Total credit extended, in minor units. |
availableCredit | Currently available credit, in minor units. |
currentBalance | Outstanding balance, in minor units. |
applicationDate | When the customer applied. |
originationDate | When the loan was originated. |
expirationDate | When the loan or credit line expires. |
tokenId | The payment token representing this loan, when one exists. |
merchantDrawdownPercentageFee | The merchant's drawdown fee percentage, where the lender supplies it. |
customerFirst, customerLast | The borrower's name, where the lender supplies it. |
Whichloanfields are present depends on the lenderLoan notifications originate from several different lender integrations, and each supplies a different subset of these fields. Fields with no value are omitted from the payload rather than sent as
nullor"", so the set of keys you receive varies by lender and by event.Treat every field inside
loanexceptidas optional, read them with null-safe accessors, and ignore keys you do not recognize. Do not build logic that requires a field to exist unless you have confirmed the specific lender you are integrating with always sends it.
Amounts are in minor units
creditLimit,availableCredit, andcurrentBalancefollow the same convention as transaction amounts —1500000is $15,000.00, not $1,500,000.00.
FAQ
Should I use loan.updated or the drawdown transaction event to track spending?
Use transaction events for the movement of money and loan events for the state of the account. A customer drawing funds produces a drawdown transaction, which is what tells you a charge occurred, its amount, and whether it was approved.
loan.updated tells you the resulting account state — the new currentBalance and availableCredit. Because ordering between the two is not guaranteed, do not derive a balance by applying transaction amounts yourself; take the balance from the loan payload and treat it as authoritative as of its modifiedOn.
What status values can loan.status take?
status is normalized by Preczn, not passed through raw from the lender — so you work against Preczn's vocabulary rather than each lender's own codes.
There is no single list that applies everywhere, though. Each lender maps its own statuses onto Preczn's, and different lenders map onto different subsets, so the values you can actually receive depend on which lender the loan is with. Check the guide for your lender under Supported Connections — for example Greensky, Jaris, or Nelnet — for the statuses that connection can produce.
Whichever lender you use, do not hardcode an exhaustive list or fail on an unrecognized value. Log unknown statuses and treat them as "no change" rather than as an error, so a lender adding a status does not break your handler.
Is loan.created guaranteed to arrive before loan.updated for the same loan?
No — ordering is not guaranteed for any webhook. Your handler should be able to accept a loan.updated for a loan it has not seen before and treat it as an upsert rather than erroring on a missing record.
Do I need to subscribe to both loan events?
Subscribe to both if you track loan state, and list them both explicitly in the events array — ["loan.created", "loan.updated"]. Since both carry the same payload shape, one handler can process either, branching on eventType only if you need to distinguish a new account from a change to an existing one.
Are loan webhooks available for every processor?
No. They apply only to lending connections, so a platform with no lending processors configured will never receive them. Subscribing is harmless if you are not yet live with a lender — the subscription simply stays quiet.
Updated about 1 hour ago
