Rates and Loan Terms
Set Term Config
Set the maximum duration, terminal date, grace period and term penalty for new loans
POST
/
lending-external-securities-v2
/
api
/
markets
/
{marketId}
/
term-config
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/markets/{marketId}/term-config" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"maxLoanDurationDays": 180,
"termGracePeriodDays": 3,
"termPenaltyBps": 200
}'
const url = `https://api.trusset.org/lending-external-securities-v2/api/markets/${marketId}/term-config`;
const headers = { 'X-API-Key': 'trusset_your_key_here', 'Content-Type': 'application/json' };
const build = await fetch(url, {
method: 'POST',
headers,
body: JSON.stringify({ maxLoanDurationDays: 180, termGracePeriodDays: 3, termPenaltyBps: 200 })
});
const { data: calldata } = await build.json();
for (const warning of calldata.warnings ?? []) console.warn(warning.kind, warning.message);
const tx = await issuerWallet.sendTransaction({
to: calldata.to,
data: calldata.data,
value: calldata.value,
chainId: calldata.chainId
});
await tx.wait();
await fetch(url, { method: 'POST', headers, body: JSON.stringify({ txHash: tx.hash }) });
{
"success": true,
"data": {
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x70a0e25c7b768b87e658348b3b577678a173e038",
"data": "0x..."
},
"to": "0x70a0e25c7b768b87e658348b3b577678a173e038",
"data": "0x...",
"functionName": "setTermConfig",
"requiredRole": "ISSUER_ROLE",
"termStamping": "PER_LOAN",
"stampedOnNewLoansOnly": ["maxLoanDuration", "terminalDueDate", "termGracePeriod", "termPenalty"],
"appliesToOpenLoans": [],
"openLoansFollowingConfig": 0,
"requiredSigner": null,
"heldByThisInstance": true,
"signerAddress": "0x5ad87a0621175206b72d10e4b8577b192e7f40ab",
"note": null,
"confirmWith": {
"endpoint": "POST /lending-external-securities-v2/api/markets/clx_secmarket_001/term-config",
"field": "txHash"
},
"chainId": 11155111,
"value": "0"
}
}
{
"success": false,
"error": {
"code": "TERMS_REQUIRED_BY_FIXED_RATE",
"message": "Terms cannot be disabled while the model stamps a fixed rate: the term clock is the compensating force for the missing curve. Move the rate mode off FIXED first."
}
}
{
"success": false,
"error": {
"code": "INVALID_TERM_OFFERING",
"message": "The term penalty cannot exceed the liquidation penalty of 500 bps: a borrower who was never undercollateralized owes no larger charge than one who was."
}
}
Builds the
Confirming with
setTermConfig transaction that sets the market’s loan terms. Requires ISSUER_ROLE on the market, held by the wallet the lender of record named at adoption. Before adoption only the deploying factory could call it, so the API refuses a market that has no lender of record yet.
Read the current terms first with Get Term Config. The market brings its interest accrual up to date before the new terms apply.
Every call writes the whole term configuration. An omitted
terminalDueDate clears the terminal date, and an omitted termPenaltyBps sets the term penalty to zero. Only an omitted termGracePeriodDays keeps the value the market already runs. Send every term you want to keep.Which Loans a Change Reaches
A new maturity reaches new loans only, and nothing here moves an open loan’s maturity earlier. Whether the grace period and the penalty also stay with new loans depends on the market’s implementation, which the calldata response names astermStamping.
On PER_LOAN, the current implementation, each loan carries the grace period and term penalty it was signed under, so the whole change reaches new loans only. Loans signed before the market stamped terms still follow the live configuration, and openLoansFollowingConfig counts them. On MARKET_CONFIG, the earlier implementation, the grace period and the penalty are read at realization, so a change reaches every open termed loan.
When a change shortens the grace period or raises the penalty for loans that follow the live configuration, the response carries an OPEN_TERMED_LOANS_AFFECTED warning. Such a borrower can be realized sooner, or at a higher charge, than the terms in force when it borrowed.
Path Parameters
string
required
Body Parameters
integer
required
How long a new loan may run before it falls due. Integer number of days, 0 to 3650.
0 sets no duration, and with no terminalDueDate either it switches terms off for new loans.integer | string
A date every new loan falls due by, whatever its duration. A unix timestamp in seconds, or an ISO date. Must be in the future. With
maxLoanDurationDays at 0, every new loan matures on this date. Omitting it clears any terminal date the market has.integer
Days between a loan’s maturity and the moment it becomes realizable. Integer, 1 to 30. Omit it to keep the market’s current grace period, or 3 days on a market that has none yet. Refused when terms are being switched off.
integer
default:"0"
Charge on the whole claim when a loan is realized for its term, in basis points. The schema accepts 0 to 50000, but it cannot exceed the market’s liquidation penalty. A penalty above zero needs terms.
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. When
txHash is present, every other field is ignored.Switch Terms Off
SendmaxLoanDurationDays: 0 with no terminalDueDate, no grace period and no penalty. New loans then open without a maturity, and loans already open keep the maturity they were signed with.
Terms cannot be switched off while the interest model stamps a fixed rate, because the term clock is what pulls a fixed-rate loan toward repayment. Move the rate mode off FIXED with Set Rate Mode first.
A terminal date that has passed closes the market to new loans. Set a future terminal date, or a duration without one, to reopen it.
Confirm the Change
Send the mined hash back to this path as{ "txHash": "0x..." }. The API checks that the transaction called setTermConfig on the market. It then reads the offering back from the chain and updates the market record.
Response Fields
The calldata response carries the transaction twice.transaction holds to and data. The same to and data also sit directly on data, and that is where the chainId and value binding lands, so sign from those four fields.
object
Show child attributes
Show child attributes
string
SIGN_TRANSACTION. Returned when txHash is omitted.object
{ to, data } for the setTermConfig call on the market. Returned when txHash is omitted.string
The market address. Returned when
txHash is omitted.string
The encoded
setTermConfig call. Returned when txHash is omitted.string
Always
"0". Returned when txHash is omitted.integer
The chain your instance resolves to. Returned when
txHash is omitted.string
setTermConfig, or the verified function when confirming.string
ISSUER_ROLE. Returned when txHash is omitted.string
PER_LOAN, MARKET_CONFIG or UNKNOWN, as described above. Returned when txHash is omitted.array
The term fields this change reaches on new loans only. Returned when
txHash is omitted.array
The term fields this change also reaches on open loans. Empty on
PER_LOAN. Returned when txHash is omitted.integer
Open termed loans signed before the market stamped terms, which this change still reaches. Counted over at most 200 recorded positions. Present only on
PER_LOAN markets.array
Present only when there is something to say. Each entry carries
kind and message.Show child attributes
Show child attributes
string
OPEN_TERMED_LOANS_AFFECTED when the change shortens the grace period or raises the penalty for open loans that follow the live configuration. Carries openTermedLoans. TERM_FLOOR_EXPOSURE when Dutch auctions are on, the market is not known to run the current implementation, and a term realization sold at the auction floor could leave the pool short. Carries termPenaltyBps, auctionMinPremiumBps and uncoveredBps.string
What the warning means for borrowers or liquidity providers. The floor warning also names the remedies.
string
Plain-language summary of the change, including which loans it reaches. Returned when
txHash is omitted.string
Always
null here: the signer is whoever holds ISSUER_ROLE, not one fixed address. Returned when txHash is omitted.boolean
true when a verified wallet of your instance holds ISSUER_ROLE, false when none does, null when the check could not be completed. The build is never refused on it. Returned when txHash is omitted.string
The wallet of your instance that holds
ISSUER_ROLE, or null. Returned when txHash is omitted.string
What to do when your instance cannot sign: the wallet the lender of record placed the role with must sign, because any other wallet reverts
NotAuthorized. null when your instance can sign. Returned when txHash is omitted.object
{ endpoint, field }: the call that confirms this transaction, and the body field that carries the hash. Returned when txHash is omitted.string
Transaction hash. Returned when confirming.
string
The wallet that sent the transaction. Returned when confirming.
integer
Block the transaction was mined in. Returned when confirming.
object
The market’s rate and term offering, read back from the chain after the transaction, including
maxLoanDuration, termGracePeriod, terminalDueDate, termPenalty and marketDueFloor. The same object Set Rate Mode returns. Returned when confirming.array
Names of the stored market fields this confirmation changed. Returned when confirming.
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/markets/{marketId}/term-config" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"maxLoanDurationDays": 180,
"termGracePeriodDays": 3,
"termPenaltyBps": 200
}'
const url = `https://api.trusset.org/lending-external-securities-v2/api/markets/${marketId}/term-config`;
const headers = { 'X-API-Key': 'trusset_your_key_here', 'Content-Type': 'application/json' };
const build = await fetch(url, {
method: 'POST',
headers,
body: JSON.stringify({ maxLoanDurationDays: 180, termGracePeriodDays: 3, termPenaltyBps: 200 })
});
const { data: calldata } = await build.json();
for (const warning of calldata.warnings ?? []) console.warn(warning.kind, warning.message);
const tx = await issuerWallet.sendTransaction({
to: calldata.to,
data: calldata.data,
value: calldata.value,
chainId: calldata.chainId
});
await tx.wait();
await fetch(url, { method: 'POST', headers, body: JSON.stringify({ txHash: tx.hash }) });
{
"success": true,
"data": {
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x70a0e25c7b768b87e658348b3b577678a173e038",
"data": "0x..."
},
"to": "0x70a0e25c7b768b87e658348b3b577678a173e038",
"data": "0x...",
"functionName": "setTermConfig",
"requiredRole": "ISSUER_ROLE",
"termStamping": "PER_LOAN",
"stampedOnNewLoansOnly": ["maxLoanDuration", "terminalDueDate", "termGracePeriod", "termPenalty"],
"appliesToOpenLoans": [],
"openLoansFollowingConfig": 0,
"requiredSigner": null,
"heldByThisInstance": true,
"signerAddress": "0x5ad87a0621175206b72d10e4b8577b192e7f40ab",
"note": null,
"confirmWith": {
"endpoint": "POST /lending-external-securities-v2/api/markets/clx_secmarket_001/term-config",
"field": "txHash"
},
"chainId": 11155111,
"value": "0"
}
}
{
"success": false,
"error": {
"code": "TERMS_REQUIRED_BY_FIXED_RATE",
"message": "Terms cannot be disabled while the model stamps a fixed rate: the term clock is the compensating force for the missing curve. Move the rate mode off FIXED first."
}
}
{
"success": false,
"error": {
"code": "INVALID_TERM_OFFERING",
"message": "The term penalty cannot exceed the liquidation penalty of 500 bps: a borrower who was never undercollateralized owes no larger charge than one who was."
}
}
Error Codes
| Code | HTTP | Cause |
|---|---|---|
MISSING_MARKET_ID | 400 | The marketId path segment is longer than 100 characters |
VALIDATION_ERROR | 400 | A field is missing, has the wrong type or is outside its range, or txHash is malformed |
INVALID_TERM_OFFERING | 400 | terminalDueDate is unreadable or not in the future, a grace period or penalty was sent without terms, or the penalty exceeds the liquidation penalty |
INVALID_CONFIRMATION | 400 | The market has no on-chain address, so there is nothing to confirm against |
MARKET_NOT_FOUND | 404 | No market with this ID on your instance |
MARKET_PENDING_CURATOR | 409 | The market has no lender of record yet, so nobody holds ISSUER_ROLE. Skipped when confirming with txHash |
TERMS_REQUIRED_BY_FIXED_RATE | 409 | Terms were being switched off while the interest model stamps a fixed rate |
INTERNAL_ERROR | 500 | The chain could not be read while confirming. Retry shortly |
TERM_GRACE_UNRESOLVED | 503 | termGracePeriodDays was omitted and the market’s current grace period could not be read. Send it explicitly, or retry |
txHash can also return any transaction verification error.⌘I
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/markets/{marketId}/term-config" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"maxLoanDurationDays": 180,
"termGracePeriodDays": 3,
"termPenaltyBps": 200
}'
const url = `https://api.trusset.org/lending-external-securities-v2/api/markets/${marketId}/term-config`;
const headers = { 'X-API-Key': 'trusset_your_key_here', 'Content-Type': 'application/json' };
const build = await fetch(url, {
method: 'POST',
headers,
body: JSON.stringify({ maxLoanDurationDays: 180, termGracePeriodDays: 3, termPenaltyBps: 200 })
});
const { data: calldata } = await build.json();
for (const warning of calldata.warnings ?? []) console.warn(warning.kind, warning.message);
const tx = await issuerWallet.sendTransaction({
to: calldata.to,
data: calldata.data,
value: calldata.value,
chainId: calldata.chainId
});
await tx.wait();
await fetch(url, { method: 'POST', headers, body: JSON.stringify({ txHash: tx.hash }) });
{
"success": true,
"data": {
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x70a0e25c7b768b87e658348b3b577678a173e038",
"data": "0x..."
},
"to": "0x70a0e25c7b768b87e658348b3b577678a173e038",
"data": "0x...",
"functionName": "setTermConfig",
"requiredRole": "ISSUER_ROLE",
"termStamping": "PER_LOAN",
"stampedOnNewLoansOnly": ["maxLoanDuration", "terminalDueDate", "termGracePeriod", "termPenalty"],
"appliesToOpenLoans": [],
"openLoansFollowingConfig": 0,
"requiredSigner": null,
"heldByThisInstance": true,
"signerAddress": "0x5ad87a0621175206b72d10e4b8577b192e7f40ab",
"note": null,
"confirmWith": {
"endpoint": "POST /lending-external-securities-v2/api/markets/clx_secmarket_001/term-config",
"field": "txHash"
},
"chainId": 11155111,
"value": "0"
}
}
{
"success": false,
"error": {
"code": "TERMS_REQUIRED_BY_FIXED_RATE",
"message": "Terms cannot be disabled while the model stamps a fixed rate: the term clock is the compensating force for the missing curve. Move the rate mode off FIXED first."
}
}
{
"success": false,
"error": {
"code": "INVALID_TERM_OFFERING",
"message": "The term penalty cannot exceed the liquidation penalty of 500 bps: a borrower who was never undercollateralized owes no larger charge than one who was."
}
}
