Hooks
Execute Hook
Run a hook now and return its outcome
POST
/
lending-external-securities-v2
/
api
/
hooks
/
{marketId}
/
{hookId}
/
execute
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/hooks/{marketId}/{hookId}/execute" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{}'
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/hooks/{marketId}/{hookId}/execute" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{"loanData": {"loanId": "5", "healthFactor": "0.92", "debtValue": "4272.50"}}'
const res = await fetch(
`https://api.trusset.org/lending-external-securities-v2/api/hooks/${marketId}/${hookId}/execute`,
{
method: 'POST',
headers: {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({ liquidationData: { loanId: '5', auctionId: '3' } })
}
);
const { data } = await res.json();
if (data.requiresUserAction) {
for (const step of data.steps) {
const tx = await wallet.sendTransaction(step.transaction);
await tx.wait();
}
}
{
"success": true,
"data": {
"success": true,
"result": true,
"fields": [
{ "path": "ageHours", "operator": "<", "threshold": 36, "value": 12, "pass": true }
]
}
}
{
"success": true,
"data": {
"success": true,
"result": true,
"checkResults": [
{ "parameter": "healthFactor", "value": "0.92", "pass": true }
]
}
}
{
"success": true,
"data": {
"success": true,
"result": null,
"queued": true,
"deliveryId": "86c63be2-bb94-4109-af7d-c3bc3b420d23",
"status": "PENDING"
}
}
{
"success": true,
"data": {
"success": true,
"result": false,
"reason": "requires_wallet_signature",
"requiresUserAction": true,
"action": "SIGN_TRANSACTIONS",
"steps": [
{
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x98ad0ca091552e23c564b41c74282e5343d03e8a",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "approve",
"description": "Approve the auction venue to pull USDC"
},
{
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x5c1e8f2a9b7d34c06e4f8a1b29d7c3e5f0a6b84d",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "bidOnAuction"
}
],
"currentPrice": "97.412"
}
}
{
"success": true,
"data": {
"success": true,
"result": false,
"reason": "Price exceeds max buy price"
}
}
{
"success": true,
"data": {
"success": false,
"result": false,
"error": "Auction not active"
}
}
{
"success": false,
"data": null,
"error": {
"code": "MISSING_LOAN_DATA",
"message": "Loan data required"
}
}
Runs one hook immediately and returns the outcome synchronously, except that an
What the body must carry depends on the hook type:
inform action returns the delivery it queued. It runs whether or not the hook is active, which makes it the way to test a new hook. The response is HTTP 200 whenever the hook ran, including when the hook itself failed: read the outcome from data.success and data.result.
A
buy hook never bids. It returns an approval and a bidOnAuction step for a wallet to sign, priced when they were built. The auction module charges its price at the moment the bid lands. It reverts if the auction has ended, the market is paused, the price is stale, or the signer is the loan’s borrower. Delivery is a compliance-gated token transfer, so a wallet the collateral token does not admit reverts too. The balance check before the steps reads only the instance’s registered wallet, whichever wallet signs.hookType | Required body | What the run does |
|---|---|---|
monitorRisk | None | Fetches riskUri and evaluates riskFields |
beforeLiquidation | loanData | Evaluates parameterChecks against loanData |
afterLiquidation | liquidationData | Checks its triggers, then runs its buy or inform action |
Path Parameters
string
required
string
required
Hook ID.
Body Parameters
object
Required for
beforeLiquidation hooks. Carries the values the hook’s parameterChecks name, such as healthFactor, collateralValue, debtValue, collateralRatio or interestAccrued, as numbers or decimal strings. An optional loanId is written to the execution log. Nothing is read from chain.object
Required for
afterLiquidation hooks. An inform body carries the fields a liquidation’s delivery carries, listed under Signed deliveries, and a field left out reads null. marketLiquidationId, txHash and marketAddress are forwarded as sent, like the fields below. realization, buyer, proceeds, surplus, reserve and payee are forwarded only when valid: ATOMIC, ROUTER or VENUE, a non-zero address, or a non-negative decimal amount. Anything else reads null.Show child attributes
Show child attributes
string
On-chain loan ID, written to the log and to an
inform body.string
Auction ID on the market’s auction module. Required for a
buy action to have anything to price.string
Collateral seized, forwarded in an
inform body.string
Debt outstanding at liquidation, forwarded in an
inform body.string
Borrower address, forwarded in an
inform body.string
Makes an
inform call idempotent. A second call with the same eventKey for this hook queues nothing and returns duplicate: true. Without it, every call queues its own delivery.What each type does
monitorRisk sends a GET to riskUri with Accept: application/json, a 10-second timeout and a 5 MB cap on the body. A non-2xx status, a body that is not JSON, a refused host or a timeout returns success: false with the reason in error, and sets the hook’s lastResult to null. A completed evaluation lists each field in fields, up to the first that fails. When it evaluates to false, every active afterLiquidation hook that lists this monitor in triggerHookIds acts on the breach. Their outcomes go to their own logs, not into this response.
beforeLiquidation evaluates every check, and result is true only when all pass. checkResults lists { parameter, value, pass } per check, with value as sent. A hook with no parameterChecks returns result: true without logging a run.
afterLiquidation first checks triggerHookIds. If it lists any, it acts only when every listed hook is active and its last counted run returned false. Otherwise it returns result: false with reason: "Trigger condition not met".
An inform action queues a signed delivery to webhookUrl and returns at once, before anything is sent: result: null, queued: true, the deliveryId and status: "PENDING". A worker sends and retries it as Signed deliveries describes, and List Hook Deliveries shows how it went. A repeated eventKey returns queued: false and duplicate: true instead. The delivery is signed like any other but reports liquidationData as sent, so a receiver checks a reported liquidation against the chain before acting on it.
A buy action reads liquidationData.auctionId on the market’s auction module. Without an auctionId it returns result: false with reason: "This liquidation opened no auction, so there is nothing to buy". It returns success: false when the market has no auction module wired or the auction is not active. Above maxBuyPrice it returns result: false with reason: "Price exceeds max buy price". When the registered wallet holds less of the borrow asset than the bid needs, it returns success: false and an error naming the asset. Otherwise it returns two steps. The first approves the auction module to pull the borrow asset for the remaining collateral at the current price. The second is bidOnAuction for all remaining collateral. The run records result: false with reason: "requires_wallet_signature", because nothing has been bought. The hook does not record the bid; confirm the mined bid with Bid on Auction.
A monitor’s breach takes neither path above and skips the trigger check. An inform hook queues a riskBreach delivery that carries the monitor and its failing fields instead of loan data. A buy hook only logs that a breach carries no auction to act on.
Counted runs, unmet triggers, skipped bids, a buy run without an auction, a short wallet balance and runs that raised an error are written to Get Hook Executions. An inform run is logged when its delivery is delivered or fails for good, not when it is queued. A refusal before anything is evaluated is returned but not logged. That covers a missing risk config, no parameter checks, no webhook URL, no auction module and an inactive auction.
Response Fields
object
Show child attributes
Show child attributes
boolean
Whether the hook ran without an error.
boolean | null
Outcome of the evaluation or action.
null for a queued inform delivery, whose outcome is not known yet.array
monitorRisk. One { path, operator, threshold, value, pass } per field evaluated.array
beforeLiquidation. One { parameter, value, pass } per check.boolean
inform. true when a delivery was queued, false for a duplicate.string
string
inform. PENDING, the delivery’s status when queued.boolean
inform. true when liquidationData.eventKey was already queued for this hook.string
Why a run that did not error returned
result: false: Trigger condition not met, This liquidation opened no auction, so there is nothing to buy, Price exceeds max buy price or requires_wallet_signature. On a duplicate inform, This liquidation was already announced to the hook.string
Why the run failed, when
success is false.boolean
buy. true when steps are returned.string
buy. SIGN_TRANSACTIONS.array
buy. The approve step, then bidOnAuction. Each carries action, transaction (to, data, value, chainId) and functionName.string
buy. Auction price per whole collateral token, in the borrow asset, when the steps were built.curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/hooks/{marketId}/{hookId}/execute" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{}'
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/hooks/{marketId}/{hookId}/execute" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{"loanData": {"loanId": "5", "healthFactor": "0.92", "debtValue": "4272.50"}}'
const res = await fetch(
`https://api.trusset.org/lending-external-securities-v2/api/hooks/${marketId}/${hookId}/execute`,
{
method: 'POST',
headers: {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({ liquidationData: { loanId: '5', auctionId: '3' } })
}
);
const { data } = await res.json();
if (data.requiresUserAction) {
for (const step of data.steps) {
const tx = await wallet.sendTransaction(step.transaction);
await tx.wait();
}
}
{
"success": true,
"data": {
"success": true,
"result": true,
"fields": [
{ "path": "ageHours", "operator": "<", "threshold": 36, "value": 12, "pass": true }
]
}
}
{
"success": true,
"data": {
"success": true,
"result": true,
"checkResults": [
{ "parameter": "healthFactor", "value": "0.92", "pass": true }
]
}
}
{
"success": true,
"data": {
"success": true,
"result": null,
"queued": true,
"deliveryId": "86c63be2-bb94-4109-af7d-c3bc3b420d23",
"status": "PENDING"
}
}
{
"success": true,
"data": {
"success": true,
"result": false,
"reason": "requires_wallet_signature",
"requiresUserAction": true,
"action": "SIGN_TRANSACTIONS",
"steps": [
{
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x98ad0ca091552e23c564b41c74282e5343d03e8a",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "approve",
"description": "Approve the auction venue to pull USDC"
},
{
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x5c1e8f2a9b7d34c06e4f8a1b29d7c3e5f0a6b84d",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "bidOnAuction"
}
],
"currentPrice": "97.412"
}
}
{
"success": true,
"data": {
"success": true,
"result": false,
"reason": "Price exceeds max buy price"
}
}
{
"success": true,
"data": {
"success": false,
"result": false,
"error": "Auction not active"
}
}
{
"success": false,
"data": null,
"error": {
"code": "MISSING_LOAN_DATA",
"message": "Loan data required"
}
}
Error Codes
These refuse the call before the hook runs. A hook that runs and fails answers200 with data.success: false.
| Code | HTTP | Cause |
|---|---|---|
MISSING_LOAN_DATA | 400 | The hook is beforeLiquidation and loanData is missing |
MISSING_LIQUIDATION_DATA | 400 | The hook is afterLiquidation and liquidationData is missing |
KEY_MATERIAL_REJECTED | 400 | A key in the body is named for key material |
MISSING_MARKET_ID | 400 | marketId is longer than 100 characters |
MISSING_HOOK_ID | 400 | hookId is longer than 100 characters |
MARKET_NOT_FOUND | 404 | No market with this ID belongs to your instance |
HOOK_NOT_FOUND | 404 | No hook with this ID exists on this market |
⌘I
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/hooks/{marketId}/{hookId}/execute" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{}'
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/hooks/{marketId}/{hookId}/execute" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{"loanData": {"loanId": "5", "healthFactor": "0.92", "debtValue": "4272.50"}}'
const res = await fetch(
`https://api.trusset.org/lending-external-securities-v2/api/hooks/${marketId}/${hookId}/execute`,
{
method: 'POST',
headers: {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({ liquidationData: { loanId: '5', auctionId: '3' } })
}
);
const { data } = await res.json();
if (data.requiresUserAction) {
for (const step of data.steps) {
const tx = await wallet.sendTransaction(step.transaction);
await tx.wait();
}
}
{
"success": true,
"data": {
"success": true,
"result": true,
"fields": [
{ "path": "ageHours", "operator": "<", "threshold": 36, "value": 12, "pass": true }
]
}
}
{
"success": true,
"data": {
"success": true,
"result": true,
"checkResults": [
{ "parameter": "healthFactor", "value": "0.92", "pass": true }
]
}
}
{
"success": true,
"data": {
"success": true,
"result": null,
"queued": true,
"deliveryId": "86c63be2-bb94-4109-af7d-c3bc3b420d23",
"status": "PENDING"
}
}
{
"success": true,
"data": {
"success": true,
"result": false,
"reason": "requires_wallet_signature",
"requiresUserAction": true,
"action": "SIGN_TRANSACTIONS",
"steps": [
{
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x98ad0ca091552e23c564b41c74282e5343d03e8a",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "approve",
"description": "Approve the auction venue to pull USDC"
},
{
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x5c1e8f2a9b7d34c06e4f8a1b29d7c3e5f0a6b84d",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "bidOnAuction"
}
],
"currentPrice": "97.412"
}
}
{
"success": true,
"data": {
"success": true,
"result": false,
"reason": "Price exceeds max buy price"
}
}
{
"success": true,
"data": {
"success": false,
"result": false,
"error": "Auction not active"
}
}
{
"success": false,
"data": null,
"error": {
"code": "MISSING_LOAN_DATA",
"message": "Loan data required"
}
}
