Liquidation Settlement
Handle Liquidation Timeout
Write off a liquidation that could not be settled within 7 days
POST
/
lending-external-securities-v2
/
api
/
liquidations
/
handle-timeout
/
{liquidationId}
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/liquidations/handle-timeout/14" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{"marketId": "clx_secmarket_001"}'
const url = `https://api.trusset.org/lending-external-securities-v2/api/liquidations/handle-timeout/${liquidationId}`;
const headers = {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json'
};
const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify({ marketId }) });
const { data, error } = await res.json();
if (error?.code === 'LIQUIDATION_NOT_TIMED_OUT') {
console.log(`Retry after ${error.eligibleAt}`);
} else if (data) {
const tx = await wallet.sendTransaction(data.transaction);
await tx.wait();
await fetch(url, { method: 'POST', headers, body: JSON.stringify({ marketId, txHash: tx.hash }) });
}
{
"success": true,
"data": {
"success": true,
"marketLiquidationId": "14",
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x70a0e25c7b768b87e658348b3b577678a173e038",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "handleLiquidationTimeout"
}
}
{
"success": true,
"data": {
"liquidationId": "14",
"marketLiquidationId": "14",
"txHash": "0x6e3a9b27d140c85f2e71b9d04a3c68f5e2b17d90c4a86e3f51b02d7c9e48a1f5",
"reserve": {
"requested": "21159.2",
"covered": "15000.0",
"uncovered": "6159.2"
}
}
}
{
"success": false,
"error": {
"code": "LIQUIDATION_NOT_TIMED_OUT",
"message": "A liquidation can only be written off after the 7-day timeout. Liquidation 14 becomes eligible at 2026-06-21T09:12:00.000Z, in 38 hours. Settle it with the sale proceeds instead, or retry after that time.",
"txHash": null,
"eligibleAt": "2026-06-21T09:12:00.000Z"
}
}
{
"success": false,
"error": {
"code": "ALREADY_SETTLED",
"message": "Already settled or written off"
}
}
Writes off a liquidation the operator was unable to settle. The market clears the outstanding debt, draws on the insurance fund to cover it, and reconciles the pool’s liquidity. The record moves to
On-chain the router’s record remains settleable by its operator, so late proceeds can still reach the market directly. The market applies them to the pool’s loss first and then to what the insurance fund advanced.
Confirming with
WRITTEN_OFF.
This is a loss-recognition step, not a recovery step. Use it when collateral proved unsellable within the window, or when a sale realised nothing.
Write-off does not touch the liquidation router. The router’s record stays open and whatever collateral it still holds stays there. This API then refuses every further action on the record, because
WRITTEN_OFF is terminal here. Withdraw it first with Withdraw Collateral for Sale. Otherwise it is stranded as far as this API is concerned.Path Parameters
string
required
Liquidation ID on the market’s router. The market-local ID needed on-chain is resolved automatically.
Body Parameters
string
Names the market whose liquidation you mean. Every market runs its own liquidation router and IDs restart at
1 on each of them, so the same liquidationId can exist on several markets in one instance. Supply this when it does, otherwise the call is refused with AMBIGUOUS_LIQUIDATION_ID and the response lists the candidates. Also accepted as a query parameter.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
object
Show child attributes
Show child attributes
string
Router liquidation ID, echoed back. Returned when confirming with
txHash.string
Market-local ID the contract call uses.
boolean
Nested inside
data on the calldata response.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
handleLiquidationTimeout. Returned when txHash is omitted.string
Transaction hash. Returned when confirming with
txHash.object
What the write-off asked the insurance fund for:
requested, covered and uncovered. null when the fund was not asked. Returned when confirming with txHash.The 7 Day Window
The clock starts at the seizure, when the market opened its pending liquidation record. For a liquidation seized straight to the router, that is when the router received the collateral:onChainData.timestamp on Get Pending Liquidations. For the remainder of an expired auction the clock started earlier, at the seizure into the auction.
The write-off is possible only once the window has fully elapsed. Calling before then is refused with LIQUIDATION_NOT_TIMED_OUT, and the error carries eligibleAt, the moment after which a retry succeeds.
What the Write-Off Does
1
Close the pending liquidation
The market marks its pending liquidation settled so the debt stops counting against
pendingLiquidationDebt.2
Draw on the insurance fund
The market asks its insurance fund for the record’s whole claim. The fund covers as much as its balance allows, and nothing when it is empty or no longer authorizes the market. What it pays is booked against the record, so later recoveries repay it.
3
Reconcile the pool
Any shortfall between the covered amount and the principal is deducted from pool liquidity. Liquidity providers absorb what the insurance fund could not.
4
Apply held auction cash
Cash the auction venue forwarded for the record, which the market was still holding, counts as late proceeds on the written-off record.
This call requires the signing wallet to hold
DEFAULT_ADMIN_ROLE on the market contract, which is a higher privilege than the LIQUIDATOR_ROLE and router OPERATOR_ROLE the other liquidation endpoints need. The role is checked in advance against your instance’s primary verified wallet. A missing role is refused with MARKET_ADMIN_ROLE_MISSING, which carries no grant calldata.curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/liquidations/handle-timeout/14" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{"marketId": "clx_secmarket_001"}'
const url = `https://api.trusset.org/lending-external-securities-v2/api/liquidations/handle-timeout/${liquidationId}`;
const headers = {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json'
};
const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify({ marketId }) });
const { data, error } = await res.json();
if (error?.code === 'LIQUIDATION_NOT_TIMED_OUT') {
console.log(`Retry after ${error.eligibleAt}`);
} else if (data) {
const tx = await wallet.sendTransaction(data.transaction);
await tx.wait();
await fetch(url, { method: 'POST', headers, body: JSON.stringify({ marketId, txHash: tx.hash }) });
}
{
"success": true,
"data": {
"success": true,
"marketLiquidationId": "14",
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x70a0e25c7b768b87e658348b3b577678a173e038",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "handleLiquidationTimeout"
}
}
{
"success": true,
"data": {
"liquidationId": "14",
"marketLiquidationId": "14",
"txHash": "0x6e3a9b27d140c85f2e71b9d04a3c68f5e2b17d90c4a86e3f51b02d7c9e48a1f5",
"reserve": {
"requested": "21159.2",
"covered": "15000.0",
"uncovered": "6159.2"
}
}
}
{
"success": false,
"error": {
"code": "LIQUIDATION_NOT_TIMED_OUT",
"message": "A liquidation can only be written off after the 7-day timeout. Liquidation 14 becomes eligible at 2026-06-21T09:12:00.000Z, in 38 hours. Settle it with the sale proceeds instead, or retry after that time.",
"txHash": null,
"eligibleAt": "2026-06-21T09:12:00.000Z"
}
}
{
"success": false,
"error": {
"code": "ALREADY_SETTLED",
"message": "Already settled or written off"
}
}
Error Codes
| Code | HTTP | Cause |
|---|---|---|
VALIDATION_ERROR | 400 | txHash is present but malformed. Nothing was built or recorded |
AMBIGUOUS_LIQUIDATION_ID | 400 | This ID exists on more than one market in your instance. The error carries candidates; resend with marketId |
ALREADY_SETTLED | 400 | The liquidation is already settled or written off, here or on the market |
LIQUIDATION_NOT_FOUND | 400 | The market holds no pending liquidation under the resolved market-local ID |
LIQUIDATION_NOT_TIMED_OUT | 400 | The window has not elapsed. The error carries eligibleAt |
WALLET_NOT_CONFIGURED | 400 | No verified wallet is registered on this instance to resolve the signer against |
MARKET_ADMIN_ROLE_MISSING | 400 | Your instance’s primary verified wallet lacks DEFAULT_ADMIN_ROLE on the market |
TX_NOT_VERIFIED | 400 | The confirmed transaction targets a different liquidation |
TIMEOUT_TX_REVERTED | 400 | The write-off could not be prepared or recorded, for example because a chain read failed. error.txHash carries the hash when one exists |
ROLE_UNVERIFIABLE | 400 | The role check could not read the market. Nothing was built. Retry shortly |
LIQUIDATION_NOT_FOUND | 404 | No liquidation with that ID on your instance, and none could be adopted from chain |
MARKET_NOT_FOUND | 404 | marketId was supplied but names no market on your instance |
txHash can also return any transaction verification error. A write-off that reverted on-chain is refused there with TX_REVERTED.⌘I
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/liquidations/handle-timeout/14" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{"marketId": "clx_secmarket_001"}'
const url = `https://api.trusset.org/lending-external-securities-v2/api/liquidations/handle-timeout/${liquidationId}`;
const headers = {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json'
};
const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify({ marketId }) });
const { data, error } = await res.json();
if (error?.code === 'LIQUIDATION_NOT_TIMED_OUT') {
console.log(`Retry after ${error.eligibleAt}`);
} else if (data) {
const tx = await wallet.sendTransaction(data.transaction);
await tx.wait();
await fetch(url, { method: 'POST', headers, body: JSON.stringify({ marketId, txHash: tx.hash }) });
}
{
"success": true,
"data": {
"success": true,
"marketLiquidationId": "14",
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x70a0e25c7b768b87e658348b3b577678a173e038",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "handleLiquidationTimeout"
}
}
{
"success": true,
"data": {
"liquidationId": "14",
"marketLiquidationId": "14",
"txHash": "0x6e3a9b27d140c85f2e71b9d04a3c68f5e2b17d90c4a86e3f51b02d7c9e48a1f5",
"reserve": {
"requested": "21159.2",
"covered": "15000.0",
"uncovered": "6159.2"
}
}
}
{
"success": false,
"error": {
"code": "LIQUIDATION_NOT_TIMED_OUT",
"message": "A liquidation can only be written off after the 7-day timeout. Liquidation 14 becomes eligible at 2026-06-21T09:12:00.000Z, in 38 hours. Settle it with the sale proceeds instead, or retry after that time.",
"txHash": null,
"eligibleAt": "2026-06-21T09:12:00.000Z"
}
}
{
"success": false,
"error": {
"code": "ALREADY_SETTLED",
"message": "Already settled or written off"
}
}
