Liquidations
Liquidate Loan
Seize collateral from a loan that is undercollateralized or past its term
POST
/
lending-external-securities-v2
/
api
/
liquidations
/
{marketId}
/
liquidate
/
{loanId}
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/liquidations/{marketId}/liquidate/7" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{}'
const res = await fetch(
`https://api.trusset.org/lending-external-securities-v2/api/liquidations/${marketId}/liquidate/7`,
{
method: 'POST',
headers: {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({ signerAddress: wallet.address })
}
);
const { data, error } = await res.json();
if (error) throw new Error(`${error.code}: ${error.message}`);
const tx = await wallet.sendTransaction(data.transaction);
await tx.wait();
const confirmed = await fetch(
`https://api.trusset.org/lending-external-securities-v2/api/liquidations/${marketId}/liquidate/7`,
{
method: 'POST',
headers: {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({ txHash: tx.hash })
}
);
const { data: liquidation } = await confirmed.json();
{
"success": true,
"data": {
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x70a0e25c7b768b87e658348b3b577678a173e038",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "liquidate",
"readiness": {
"routerAddress": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"routerAuthorized": true,
"routerTokenEligible": true,
"routerTokenRequirement": "adapter_must_be_verified_holder",
"operatorRoleReady": true,
"operatorAddress": "0x1234f9a07c6b53d81e2a4f70c9b385d6014a7e52",
"operatorDeclared": true,
"liquidatorRoleReady": true,
"liquidatorViaBot": false,
"liquidatorBotAddress": null,
"signerAddress": "0x1234f9a07c6b53d81e2a4f70c9b385d6014a7e52",
"collateralTransferChecked": true,
"collateralTransferAllowed": true,
"collateralTransferCode": 0,
"collateralTransferReason": null,
"collateralTransferAmount": "1500000000000000000000",
"saleRecipient": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"saleRecipientFixed": true,
"saleRecipientRotatable": true,
"configuredSaleVenue": null,
"saleVenue": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"saleDeliveryChecked": true,
"saleDeliveryAllowed": true,
"saleDeliveryCode": 0,
"saleDeliveryAmount": "1500000000000000000000",
"auctionVenue": null,
"auctionVenueAdmitted": null,
"auctionVenueRequirement": null,
"dutchAuctionEnabled": false,
"declaredRealization": "EXCHANGE_SALE",
"auctionPathMissing": false,
"priceStale": false,
"priceAge": 184,
"seizureConfigured": true,
"isConfigured": true,
"readFailed": false,
"blockedConfirmed": false,
"seizureBlockedConfirmed": false,
"unverifiedReason": null,
"unverifiedSections": null,
"errors": null,
"canSeizeNow": true,
"canRealizeNow": true,
"blockedReason": null,
"atomic": {
"routerAddress": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"available": true,
"mode": 0,
"modeName": "TWO_STEP",
"effective": false,
"saleRecipient": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"buyerAvailable": false,
"code": null,
"reasonCode": "NO_BID",
"saleBasis": {
"available": true,
"priceSource": "MARKET",
"realizationMode": "EXCHANGE_SALE",
"reasonCode": null,
"reason": null
}
}
}
}
}
{
"success": true,
"data": {
"loanId": "7",
"liquidationId": "14",
"auctionId": null,
"txHash": "0x9f2c41d8b7e05a3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b",
"collateralSeized": "220.0",
"debtRepaid": "21159.2",
"borrower": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"status": "PENDING",
"realization": "ROUTER",
"buyer": null,
"proceeds": null,
"usdcProceeds": null,
"surplus": null,
"reserve": null
}
}
{
"success": true,
"data": {
"loanId": "7",
"liquidationId": "15",
"auctionId": null,
"txHash": "0x7e2a4c9f1b3d50e86a2c4f1b7d9e03c58a1f6b2d4e8c7a09f5b3d1e6a2c8f4b7",
"collateralSeized": "220.0",
"debtRepaid": "21159.2",
"borrower": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"status": "SETTLED",
"realization": "ATOMIC",
"buyer": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"proceeds": "21560.0",
"usdcProceeds": "21560.0",
"surplus": { "returned": "0.0", "escrowed": "0.0" },
"reserve": { "seizureCovered": "0.0", "settlementCovered": "0.0", "reimbursed": "0.0" },
"settlement": {
"marketLiquidationId": "9",
"routerLiquidationId": "15",
"proceedsReceived": "21560.0",
"routerProceeds": "21560.0",
"shortfall": null,
"debtApplied": "21159.2",
"writeOffRecovered": null,
"reserve": null,
"reserveReimbursed": null
},
"sale": {
"collateralAmount": "220.0",
"collateralAmountRaw": "220000000000000000000",
"payment": "21560.0",
"paymentRaw": "21560000000",
"price": "100.0",
"priceRaw": "100000000",
"priceFactor": "0.98",
"priceFactorBps": 9800
},
"settledTxHash": "0x7e2a4c9f1b3d50e86a2c4f1b7d9e03c58a1f6b2d4e8c7a09f5b3d1e6a2c8f4b7",
"settledAt": "2026-10-09T13:41:07.000Z"
}
}
{
"success": true,
"data": {
"loanId": "7",
"liquidationId": "5",
"auctionId": "3",
"txHash": "0x9f2c41d8b7e05a3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b",
"collateralSeized": "250.0",
"debtRepaid": "21159.2",
"borrower": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"status": "PENDING",
"realization": "VENUE",
"buyer": null,
"proceeds": null,
"usdcProceeds": null,
"surplus": null,
"reserve": null
}
}
{
"success": false,
"error": {
"code": "LOAN_NOT_LIQUIDATABLE",
"message": "Loan 7 is healthy (health factor 1.204813 is at or above the 1.0 threshold) and carries no term, so liquidate reverts. A loan becomes realizable when its health drops below 1.0 or when its term passes its effective due date plus the grace period.",
"loan": {
"loanId": "7",
"active": true,
"healthFactor": "1.204813",
"healthFactorThreshold": "1.0",
"borrower": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3"
},
"readiness": {
"routerAddress": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"canSeizeNow": true,
"canRealizeNow": true,
"blockedReason": null
}
}
}
{
"success": false,
"error": {
"code": "LIQUIDATION_NOT_READY",
"message": "The liquidation router 0x067a3feea46649adad8e31c33b3a4d8774b8d8cf is not a verified holder in the collateral token's identity registry, so it cannot receive seized collateral.",
"readiness": {
"routerAddress": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"routerTokenEligible": false,
"routerTokenRequirement": "adapter_must_be_verified_holder",
"seizureConfigured": false,
"canSeizeNow": false,
"blockedReason": "The liquidation router 0x067a3feea46649adad8e31c33b3a4d8774b8d8cf is not a verified holder in the collateral token's identity registry, so it cannot receive seized collateral."
}
}
}
Liquidates a loan on either of two triggers. A loan qualifies when its health factor is below
Confirming with
1.0, and it qualifies when its term has run past its effective due date plus grace, whatever its health. A market that makes open-ended loans has only the first trigger.
Where the seized collateral goes depends on the market’s useDutchAuction setting.
With Dutch auctions disabled, collateral is seized and transferred to the market’s liquidation router, and a pending liquidation is created on the market and on the router. The response carries the router’s liquidationId, collateralSeized and debtRepaid, and settlement becomes a manual operator workflow.
On a market whose router runs the atomic sale, the seized collateral is sold to the sale recipient at its standing bid in the same transaction, and the record settles at once. See Atomic sale.
With Dutch auctions enabled, the collateral goes to the market’s auction venue and a Dutch auction opens. The market records its pending liquidation at the seizure, but the router holds nothing. The response carries auctionId, and liquidationId is the market’s own record ID rather than a router ID. The router takes part only if the auction expires with collateral unsold and Settle Expired Auction hands the remainder to it. A market priced from a live market price cannot enable Dutch auctions, and none can run before an auction venue is wired.
A market whose lender of record declared AUCTION as its realization path is refused with 409 AUCTION_PATH_NOT_ENABLED while Dutch auctions are off, because the seizure would go to the router for a direct sale instead. Wire the venue with Wire Auction Module and turn on useDutchAuction with Update Market Config first. readiness.auctionPathMissing reports this state.
The signing wallet must hold
LIQUIDATOR_ROLE on the market. Role state is reported in readiness but never blocks the calldata. You sign in your own environment, so the wallet this API knows about is not necessarily the one that will call. A wallet without the role has its transaction reverted on-chain rather than rejected here. Pass signerAddress to have readiness answer for the wallet you intend to use.Path Parameters
string
required
The market’s record ID, as
id on List Markets, not its contract address. See Market IDs. At most 100 characters.integer
required
On-chain loan ID. Must be a positive integer.
Body Parameters
object
EIP-712 signed price built with Sign Price and signed by the oracle’s authorized signer. The contract applies it atomically with the liquidation, before it reads the price. Omit it to price against the stored oracle value. Before building, the API checks the quote against the oracle: it must verify against an authorized signer, be dated after the stored price, and stay inside the oracle’s deviation band. Otherwise the call is refused with
INVALID_SIGNED_PRICE, SIGNED_PRICE_OUTDATED or PRICE_DEVIATION_TOO_LARGE. An accepted quote lifts the PRICE_STALE refusal, since the liquidation then runs on the quoted price. Without one, push a fresh price with Sync Oracle Price first. A market that prices from an external feed refuses a signed price with EXTERNAL_FEED_ACTIVE, and a market with a fixed price with FIXED_PRICE_ACTIVE.string
Wallet you intend to liquidate with. Used to resolve
readiness against that address rather than against your instance’s primary verified wallet. It does not appear in the transaction. On a collateral token whose ERC-1400 granularity() is above one base unit it is required: the exact liquidation is simulated from it before the calldata is returned, and without it the call is refused with COLLATERAL_GRANULARITY_UNCHECKED. When the granularity or the simulation cannot be read, the calldata is returned and the contract decides. Anything that is not a valid address is ignored.string
Hash of the transaction you broadcast for this operation. Send it to confirm the transaction and record the result. Omit it to receive the calldata. A value that is not
0x followed by 64 hex characters is refused with 400 VALIDATION_ERROR and nothing is built or recorded. null or an empty string counts as omitted.Response Fields
WithouttxHash the response is the unsigned liquidate call, alongside a readiness object describing every gate the contract passes through.
object
Show child attributes
Show child attributes
string
SIGN_TRANSACTION. Returned when txHash is omitted.object
Unsigned transaction,
{ to, data, value, chainId }, targeting the market contract. Returned when txHash is omitted.string
liquidate. Returned when txHash is omitted.object
Realization readiness for this market, or
null when it could not be read. Returned when txHash is omitted, and also attached to the errors below. It carries the same fields as Get Liquidation Config, without marketId, marketAddress, liquidationRouterAddress and stats. The decisive ones:Show child attributes
Show child attributes
string
Liquidation router for this market.
boolean
Every seizure gate is satisfied and the price is fresh.
boolean
canSeizeNow, plus the router’s operator role and onward delivery to the sale recipient.boolean
Whether
signerAddress, or a connected liquidation bot, holds LIQUIDATOR_ROLE. null when it could not be read.boolean
Whether this liquidation would open an auction instead of seizing to the router.
boolean
true when declaredRealization is AUCTION and Dutch auctions are off. The liquidation is then refused with AUCTION_PATH_NOT_ENABLED.boolean
Whether the oracle price is outside its window.
boolean
true when at least one gate could not be read. unverifiedReason says which.string
The first gate that fails, in words.
null when nothing blocks.object
The atomic sale state, as on Get Atomic Sale, with
saleBasis when it was read and without saleRecipientLenderSide. Its available, reasonCode and reason describe the router, the market and the sale recipient; the sale basis is reported in saleBasis alone. null when the router could not be resolved.string
Loan ID, read from the mined transaction. Returned when confirming with
txHash.string
On the router path, the liquidation’s ID on the market’s router: pass it to every settlement endpoint. In Dutch auction mode, the market’s own record ID, which is not a router ID, so do not pass it to a router endpoint. While the auction runs, Get Pending Liquidations lists the record as
venue-{id}, and the router endpoints refuse that ID with LIQUIDATION_ON_VENUE. Returned when confirming with txHash.string
Dutch auction ID on the market’s auction venue.
null on the router path. Returned when confirming with txHash.string
Transaction hash. Returned when confirming with
txHash.string
Collateral moved to the router, or put up for auction in Dutch auction mode, in collateral token units. Returned when confirming with
txHash.string
Debt the seizure discharged on the router path, or the debt the auction must cover, in borrow asset units. Returned when confirming with
txHash.string
Borrower address, or
null when it could not be resolved. Returned when confirming with txHash.string
SETTLED when the liquidation sold the collateral atomically, PENDING otherwise. Returned when confirming with txHash.string
ATOMIC, ROUTER or VENUE: how the seized collateral is realized. Returned when confirming with txHash.string
The sale recipient that bought, on an atomic sale.
null otherwise.string
What the market received from the atomic sale, in borrow asset units.
null otherwise. usdcProceeds repeats it.object
On an atomic sale,
{ returned, escrowed }: surplus paid to the borrower, or escrowed for it. null otherwise.object
On an atomic sale,
{ seizureCovered, settlementCovered, reimbursed }: what the insurance fund paid in and was paid back. null otherwise.object
On an atomic sale only: the market’s settlement of the record, as on Sell Pending Liquidation. Present with
sale, settledTxHash and settledAt. sale carries collateralAmount, payment, price and priceFactor, each also in base units, and priceFactorBps.Atomic sale
A market priced from a live market price (MARKET) whose lender of record declared EXCHANGE_SALE can run its router in atomic mode, switched on with Set Atomic Mode. A liquidation there sells the seized collateral to the sale recipient at its standing bid inside the liquidation transaction, and the record settles in the same block: status: SETTLED, realization: ATOMIC. If the sale recipient cannot buy, the whole liquidation reverts and the loan stays liquidatable.
The calldata is refused before anything is signed:
409 ATOMIC_SALE_UNAVAILABLEwhen the router runs atomic mode on a market where the atomic sale is not offered: notMARKET-priced, or not declaredEXCHANGE_SALE.detailscarriesloanId,priceSource,realizationModeandreasonCode. The router administrator switches the router back to two-step first, then the loan is liquidated the two-step way.409 ATOMIC_BUYER_UNAVAILABLEwhen the sale recipient cannot buy. On the market’s state,detailscarriesreasonCode,saleRecipientandrouterAddress. Without asignedPrice, the loan itself is checked too. For this loan,detailsaddsloanId,expectedPayment({ amount, raw }) andcollateralAmount(in base units), andreasonCodecan also beINTAKE_CLOSED: the market reports that the router would not take this sale although every buyer fact readable here passes. The sale recipient can post or renew its bid with Set Sale Bid, or the router administrator can switch to two-step.409 LIQUIDATION_NOT_READYwhen, on that same loan check, the collateral token refuses delivery of the loan’s seized collateral to the router.
503 ROUTER_UNREADABLE and records nothing, so the liquidation is never booked as two-step by mistake. Retry the confirm.
What One Call Realizes
On the health trigger a liquidation does not close the whole loan. The debt one call can discharge is capped bycloseFactor, and the collateral seized for it is marked up by liquidationPenalty at the current price. A deeply underwater loan therefore needs several liquidations to clear. When the collateral runs out before the debt does, all of it is seized. The remaining debt is then written off at once, against the insurance fund first and the pool second.
On the term trigger the whole debt is realized in one call, marked up by the loan’s term penalty instead of the liquidation penalty. The seizure takes only the collateral that requires, and the rest goes back to the borrower in the same transaction. Collateral that falls short is taken whole and the remaining debt is written off the same way.
On the auction path the venue takes closeFactor of the collateral against the same share of the debt, or all of it when the collateral is worth less than that debt. A term realization routed to an auction sizes its slice at the auction’s floor price rather than at the oracle price.
There is no auto-sell for external securities. Once collateral reaches the router in two-step mode it stays there until an operator sells it and settles the proceeds. See Settle Liquidation. The atomic sale above sells to the sale recipient’s standing bid inside the liquidation, and only where the router administrator switched it on. An auction sells only to verified bidders who take the price the venue quotes through Bid on Auction.
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/liquidations/{marketId}/liquidate/7" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{}'
const res = await fetch(
`https://api.trusset.org/lending-external-securities-v2/api/liquidations/${marketId}/liquidate/7`,
{
method: 'POST',
headers: {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({ signerAddress: wallet.address })
}
);
const { data, error } = await res.json();
if (error) throw new Error(`${error.code}: ${error.message}`);
const tx = await wallet.sendTransaction(data.transaction);
await tx.wait();
const confirmed = await fetch(
`https://api.trusset.org/lending-external-securities-v2/api/liquidations/${marketId}/liquidate/7`,
{
method: 'POST',
headers: {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({ txHash: tx.hash })
}
);
const { data: liquidation } = await confirmed.json();
{
"success": true,
"data": {
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x70a0e25c7b768b87e658348b3b577678a173e038",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "liquidate",
"readiness": {
"routerAddress": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"routerAuthorized": true,
"routerTokenEligible": true,
"routerTokenRequirement": "adapter_must_be_verified_holder",
"operatorRoleReady": true,
"operatorAddress": "0x1234f9a07c6b53d81e2a4f70c9b385d6014a7e52",
"operatorDeclared": true,
"liquidatorRoleReady": true,
"liquidatorViaBot": false,
"liquidatorBotAddress": null,
"signerAddress": "0x1234f9a07c6b53d81e2a4f70c9b385d6014a7e52",
"collateralTransferChecked": true,
"collateralTransferAllowed": true,
"collateralTransferCode": 0,
"collateralTransferReason": null,
"collateralTransferAmount": "1500000000000000000000",
"saleRecipient": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"saleRecipientFixed": true,
"saleRecipientRotatable": true,
"configuredSaleVenue": null,
"saleVenue": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"saleDeliveryChecked": true,
"saleDeliveryAllowed": true,
"saleDeliveryCode": 0,
"saleDeliveryAmount": "1500000000000000000000",
"auctionVenue": null,
"auctionVenueAdmitted": null,
"auctionVenueRequirement": null,
"dutchAuctionEnabled": false,
"declaredRealization": "EXCHANGE_SALE",
"auctionPathMissing": false,
"priceStale": false,
"priceAge": 184,
"seizureConfigured": true,
"isConfigured": true,
"readFailed": false,
"blockedConfirmed": false,
"seizureBlockedConfirmed": false,
"unverifiedReason": null,
"unverifiedSections": null,
"errors": null,
"canSeizeNow": true,
"canRealizeNow": true,
"blockedReason": null,
"atomic": {
"routerAddress": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"available": true,
"mode": 0,
"modeName": "TWO_STEP",
"effective": false,
"saleRecipient": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"buyerAvailable": false,
"code": null,
"reasonCode": "NO_BID",
"saleBasis": {
"available": true,
"priceSource": "MARKET",
"realizationMode": "EXCHANGE_SALE",
"reasonCode": null,
"reason": null
}
}
}
}
}
{
"success": true,
"data": {
"loanId": "7",
"liquidationId": "14",
"auctionId": null,
"txHash": "0x9f2c41d8b7e05a3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b",
"collateralSeized": "220.0",
"debtRepaid": "21159.2",
"borrower": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"status": "PENDING",
"realization": "ROUTER",
"buyer": null,
"proceeds": null,
"usdcProceeds": null,
"surplus": null,
"reserve": null
}
}
{
"success": true,
"data": {
"loanId": "7",
"liquidationId": "15",
"auctionId": null,
"txHash": "0x7e2a4c9f1b3d50e86a2c4f1b7d9e03c58a1f6b2d4e8c7a09f5b3d1e6a2c8f4b7",
"collateralSeized": "220.0",
"debtRepaid": "21159.2",
"borrower": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"status": "SETTLED",
"realization": "ATOMIC",
"buyer": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"proceeds": "21560.0",
"usdcProceeds": "21560.0",
"surplus": { "returned": "0.0", "escrowed": "0.0" },
"reserve": { "seizureCovered": "0.0", "settlementCovered": "0.0", "reimbursed": "0.0" },
"settlement": {
"marketLiquidationId": "9",
"routerLiquidationId": "15",
"proceedsReceived": "21560.0",
"routerProceeds": "21560.0",
"shortfall": null,
"debtApplied": "21159.2",
"writeOffRecovered": null,
"reserve": null,
"reserveReimbursed": null
},
"sale": {
"collateralAmount": "220.0",
"collateralAmountRaw": "220000000000000000000",
"payment": "21560.0",
"paymentRaw": "21560000000",
"price": "100.0",
"priceRaw": "100000000",
"priceFactor": "0.98",
"priceFactorBps": 9800
},
"settledTxHash": "0x7e2a4c9f1b3d50e86a2c4f1b7d9e03c58a1f6b2d4e8c7a09f5b3d1e6a2c8f4b7",
"settledAt": "2026-10-09T13:41:07.000Z"
}
}
{
"success": true,
"data": {
"loanId": "7",
"liquidationId": "5",
"auctionId": "3",
"txHash": "0x9f2c41d8b7e05a3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b",
"collateralSeized": "250.0",
"debtRepaid": "21159.2",
"borrower": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"status": "PENDING",
"realization": "VENUE",
"buyer": null,
"proceeds": null,
"usdcProceeds": null,
"surplus": null,
"reserve": null
}
}
{
"success": false,
"error": {
"code": "LOAN_NOT_LIQUIDATABLE",
"message": "Loan 7 is healthy (health factor 1.204813 is at or above the 1.0 threshold) and carries no term, so liquidate reverts. A loan becomes realizable when its health drops below 1.0 or when its term passes its effective due date plus the grace period.",
"loan": {
"loanId": "7",
"active": true,
"healthFactor": "1.204813",
"healthFactorThreshold": "1.0",
"borrower": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3"
},
"readiness": {
"routerAddress": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"canSeizeNow": true,
"canRealizeNow": true,
"blockedReason": null
}
}
}
{
"success": false,
"error": {
"code": "LIQUIDATION_NOT_READY",
"message": "The liquidation router 0x067a3feea46649adad8e31c33b3a4d8774b8d8cf is not a verified holder in the collateral token's identity registry, so it cannot receive seized collateral.",
"readiness": {
"routerAddress": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"routerTokenEligible": false,
"routerTokenRequirement": "adapter_must_be_verified_holder",
"seizureConfigured": false,
"canSeizeNow": false,
"blockedReason": "The liquidation router 0x067a3feea46649adad8e31c33b3a4d8774b8d8cf is not a verified holder in the collateral token's identity registry, so it cannot receive seized collateral."
}
}
}
Error Codes
Refusals from the readiness, loan, atomic and granularity checks carry the fullreadiness object alongside code and message, so the failing gate can be inspected without a second call. The examples above shorten it, and the calldata example shortens readiness.atomic. The loan-level refusals also carry loan. When the loan itself cannot be read, the calldata is returned and the contract decides.
| Code | HTTP | Cause |
|---|---|---|
MISSING_MARKET_ID | 400 | marketId is longer than 100 characters |
MARKET_NOT_CONFIGURED | 400 | The market has no address or no oracle recorded |
INVALID_LOAN_ID | 400 | loanId is not a positive integer |
VALIDATION_ERROR | 400 | A signedPrice field has the wrong type, or txHash is present but malformed |
INVALID_SIGNED_PRICE | 400 | The signedPrice is malformed, expired, or not signed by an authorized signer of the market’s oracle |
PRICE_DEVIATION_TOO_LARGE, PRICE_WINDOW_DEVIATION_TOO_LARGE | 400 | The signedPrice moves further from the stored price than the oracle accepts, in one step or within its current hour. details carries the band |
LIQUIDATION_NOT_READY | 400 | The router is not authorized on the market, or the collateral token will not let the router hold the seized tokens. 409 when the router runs atomic mode and the token refuses delivery of this loan’s seizure. See Atomic sale |
COLLATERAL_TRANSFER_RESTRICTED | 400 | The collateral token’s compliance rules block the seizure transfer to the router |
PRICE_STALE | 400 | The oracle price is stale, so liquidate reverts. Push a fresh price first, or carry an accepted signedPrice |
AUCTION_VENUE_NOT_ADMITTED | 400 | Dutch auctions are on, but the collateral token does not admit the auction venue as a holder |
AUCTION_PATH_NOT_ENABLED | 409 | The lender of record declared AUCTION as the realization path and Dutch auctions are off. details carries declaredRealization and auctionVenue, null when no venue is wired |
COLLATERAL_GRANULARITY_UNCHECKED | 409 | The collateral token’s ERC-1400 granularity is above one base unit and no signerAddress was sent, so the seizure could not be simulated. details.granularity carries it in base units |
COLLATERAL_GRANULARITY_UNSUPPORTED | 409 | Simulated from signerAddress, the seizure is not a whole multiple of the token’s granularity and the token refuses it. details carries granularity, status and reason. The position can be realized only by a seizure that takes the whole position |
LIQUIDATION_SIMULATION_FAILED | 409 | On a token with a granularity above one base unit, the liquidation simulated from signerAddress reverts for a reason other than the token’s transfer refusal. The message quotes the reason. details carries granularity and revertData |
EXTERNAL_FEED_ACTIVE | 409 | A signedPrice was sent to a market that prices from an external feed. Retry without it |
FIXED_PRICE_ACTIVE | 409 | A signedPrice was sent to a market with a fixed price. Retry without it |
SIGNED_PRICE_OUTDATED | 409 | The signedPrice is not dated after the price the oracle holds. Sign a fresh quote |
ATOMIC_SALE_UNAVAILABLE | 409 | The router runs atomic mode, but the market is not MARKET-priced or not declared EXCHANGE_SALE. Switch the router to two-step first. See Atomic sale |
ATOMIC_BUYER_UNAVAILABLE | 409 | The router runs atomic mode and the sale recipient cannot buy, so the liquidation would revert. details.reasonCode names the gap. See Atomic sale |
LOAN_IN_AUCTION | 400 | An auction is already realizing this loan. The error carries loan.auction |
LOAN_NOT_ACTIVE | 400 | The loan is closed, so there is nothing to realize. The error carries loan |
LOAN_NOT_LIQUIDATABLE | 400 | The loan’s health factor is at or above 1.0 and it carries no enforceable term. The error carries loan, including its term when it has one |
TX_NOT_VERIFIED | 400 | The confirmed transaction liquidates a different loan |
LIQUIDATION_FAILED | 400 | Confirming failed for a reason no more specific code covers, such as a chain read that did not answer |
MARKET_NOT_FOUND | 404 | No market with this ID on your instance |
PRICE_STATE_UNAVAILABLE | 503 | The oracle could not be read to check the signedPrice. Nothing was built. Retry shortly |
ROUTER_UNREADABLE | 503 | Confirming: the transaction carries an atomic sale that could not be read back, so nothing was recorded. Retry |
txHash can also return any transaction verification error.
A missing
LIQUIDATOR_ROLE shows as liquidatorRoleReady: false in readiness rather than as an error. Resolve it through Set Liquidator Role when the market admin drives the grant, or let a connected liquidation bot hold it.⌘I
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/liquidations/{marketId}/liquidate/7" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{}'
const res = await fetch(
`https://api.trusset.org/lending-external-securities-v2/api/liquidations/${marketId}/liquidate/7`,
{
method: 'POST',
headers: {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({ signerAddress: wallet.address })
}
);
const { data, error } = await res.json();
if (error) throw new Error(`${error.code}: ${error.message}`);
const tx = await wallet.sendTransaction(data.transaction);
await tx.wait();
const confirmed = await fetch(
`https://api.trusset.org/lending-external-securities-v2/api/liquidations/${marketId}/liquidate/7`,
{
method: 'POST',
headers: {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({ txHash: tx.hash })
}
);
const { data: liquidation } = await confirmed.json();
{
"success": true,
"data": {
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x70a0e25c7b768b87e658348b3b577678a173e038",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "liquidate",
"readiness": {
"routerAddress": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"routerAuthorized": true,
"routerTokenEligible": true,
"routerTokenRequirement": "adapter_must_be_verified_holder",
"operatorRoleReady": true,
"operatorAddress": "0x1234f9a07c6b53d81e2a4f70c9b385d6014a7e52",
"operatorDeclared": true,
"liquidatorRoleReady": true,
"liquidatorViaBot": false,
"liquidatorBotAddress": null,
"signerAddress": "0x1234f9a07c6b53d81e2a4f70c9b385d6014a7e52",
"collateralTransferChecked": true,
"collateralTransferAllowed": true,
"collateralTransferCode": 0,
"collateralTransferReason": null,
"collateralTransferAmount": "1500000000000000000000",
"saleRecipient": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"saleRecipientFixed": true,
"saleRecipientRotatable": true,
"configuredSaleVenue": null,
"saleVenue": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"saleDeliveryChecked": true,
"saleDeliveryAllowed": true,
"saleDeliveryCode": 0,
"saleDeliveryAmount": "1500000000000000000000",
"auctionVenue": null,
"auctionVenueAdmitted": null,
"auctionVenueRequirement": null,
"dutchAuctionEnabled": false,
"declaredRealization": "EXCHANGE_SALE",
"auctionPathMissing": false,
"priceStale": false,
"priceAge": 184,
"seizureConfigured": true,
"isConfigured": true,
"readFailed": false,
"blockedConfirmed": false,
"seizureBlockedConfirmed": false,
"unverifiedReason": null,
"unverifiedSections": null,
"errors": null,
"canSeizeNow": true,
"canRealizeNow": true,
"blockedReason": null,
"atomic": {
"routerAddress": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"available": true,
"mode": 0,
"modeName": "TWO_STEP",
"effective": false,
"saleRecipient": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"buyerAvailable": false,
"code": null,
"reasonCode": "NO_BID",
"saleBasis": {
"available": true,
"priceSource": "MARKET",
"realizationMode": "EXCHANGE_SALE",
"reasonCode": null,
"reason": null
}
}
}
}
}
{
"success": true,
"data": {
"loanId": "7",
"liquidationId": "14",
"auctionId": null,
"txHash": "0x9f2c41d8b7e05a3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b",
"collateralSeized": "220.0",
"debtRepaid": "21159.2",
"borrower": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"status": "PENDING",
"realization": "ROUTER",
"buyer": null,
"proceeds": null,
"usdcProceeds": null,
"surplus": null,
"reserve": null
}
}
{
"success": true,
"data": {
"loanId": "7",
"liquidationId": "15",
"auctionId": null,
"txHash": "0x7e2a4c9f1b3d50e86a2c4f1b7d9e03c58a1f6b2d4e8c7a09f5b3d1e6a2c8f4b7",
"collateralSeized": "220.0",
"debtRepaid": "21159.2",
"borrower": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"status": "SETTLED",
"realization": "ATOMIC",
"buyer": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"proceeds": "21560.0",
"usdcProceeds": "21560.0",
"surplus": { "returned": "0.0", "escrowed": "0.0" },
"reserve": { "seizureCovered": "0.0", "settlementCovered": "0.0", "reimbursed": "0.0" },
"settlement": {
"marketLiquidationId": "9",
"routerLiquidationId": "15",
"proceedsReceived": "21560.0",
"routerProceeds": "21560.0",
"shortfall": null,
"debtApplied": "21159.2",
"writeOffRecovered": null,
"reserve": null,
"reserveReimbursed": null
},
"sale": {
"collateralAmount": "220.0",
"collateralAmountRaw": "220000000000000000000",
"payment": "21560.0",
"paymentRaw": "21560000000",
"price": "100.0",
"priceRaw": "100000000",
"priceFactor": "0.98",
"priceFactorBps": 9800
},
"settledTxHash": "0x7e2a4c9f1b3d50e86a2c4f1b7d9e03c58a1f6b2d4e8c7a09f5b3d1e6a2c8f4b7",
"settledAt": "2026-10-09T13:41:07.000Z"
}
}
{
"success": true,
"data": {
"loanId": "7",
"liquidationId": "5",
"auctionId": "3",
"txHash": "0x9f2c41d8b7e05a3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b",
"collateralSeized": "250.0",
"debtRepaid": "21159.2",
"borrower": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"status": "PENDING",
"realization": "VENUE",
"buyer": null,
"proceeds": null,
"usdcProceeds": null,
"surplus": null,
"reserve": null
}
}
{
"success": false,
"error": {
"code": "LOAN_NOT_LIQUIDATABLE",
"message": "Loan 7 is healthy (health factor 1.204813 is at or above the 1.0 threshold) and carries no term, so liquidate reverts. A loan becomes realizable when its health drops below 1.0 or when its term passes its effective due date plus the grace period.",
"loan": {
"loanId": "7",
"active": true,
"healthFactor": "1.204813",
"healthFactorThreshold": "1.0",
"borrower": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3"
},
"readiness": {
"routerAddress": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"canSeizeNow": true,
"canRealizeNow": true,
"blockedReason": null
}
}
}
{
"success": false,
"error": {
"code": "LIQUIDATION_NOT_READY",
"message": "The liquidation router 0x067a3feea46649adad8e31c33b3a4d8774b8d8cf is not a verified holder in the collateral token's identity registry, so it cannot receive seized collateral.",
"readiness": {
"routerAddress": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"routerTokenEligible": false,
"routerTokenRequirement": "adapter_must_be_verified_holder",
"seizureConfigured": false,
"canSeizeNow": false,
"blockedReason": "The liquidation router 0x067a3feea46649adad8e31c33b3a4d8774b8d8cf is not a verified holder in the collateral token's identity registry, so it cannot receive seized collateral."
}
}
}
