> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trusset.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Repay Loan

> Repay loan debt, interest first then principal

Repays part or all of a loan's outstanding debt. Accrued interest is settled before principal. Anyone can repay any loan, so a third party can rescue a position approaching liquidation.

At least two transactions are required: an approval on the borrow asset, then the repayment. They come back as ordered steps.

## Path Parameters

<ParamField path="marketId" type="string" required>Market ID.</ParamField>

## Body Parameters

<ParamField body="loanId" type="integer" required>
  On-chain loan ID. A positive integer. Accepted as a JSON number or as a numeric string, so the value [Get Loan](/endpoints/lending/get-loan) returns passes straight back.
</ParamField>

<ParamField body="amount" type="string">
  Amount to repay as a decimal string in borrow asset units. The contract caps repayment at the total debt, so overpaying does not transfer more than owed. Required unless `all` is `true` or you are confirming with `txHash`.
</ParamField>

<ParamField body="all" type="boolean">
  Repay the loan in full. The API reads the current debt and sizes the approval with a small overshoot, so interest accruing between the quote and the mine cannot leave dust behind. Use this instead of computing a payoff yourself.
</ParamField>

<ParamField body="signedPrice" type="object">
  EIP-712 signed price from [Sign Price](/endpoints/lending/sign-price), carried on-chain by the repayment. A repayment is the most frequent transaction a market sees, so carrying a price here keeps the oracle fresh without a separate write. Omit it and the repayment stays on the entry point that no price can block, which is the path a borrower must always have.

  <Expandable>
    <ParamField body="price" type="string">Price in base units.</ParamField>
    <ParamField body="timestamp" type="integer">Signing timestamp.</ParamField>
    <ParamField body="validUntil" type="integer">Signature expiry.</ParamField>
    <ParamField body="signature" type="string">EIP-712 signature.</ParamField>
  </Expandable>
</ParamField>

<ParamField body="permit" type="object">
  An EIP-2612 permit over the settlement asset, which collapses approve-then-repay into one signed transaction. Offered only where the settlement asset provably implements EIP-2612. `permitSupported` on the standard response says whether this market's asset does.

  <Expandable>
    <ParamField body="deadline" type="integer" required>Future unix timestamp in seconds. A deadline at or before now is rejected.</ParamField>
    <ParamField body="v" type="integer" required>Signature recovery id, `27` or `28`.</ParamField>
    <ParamField body="r" type="string" required>32 bytes, hex.</ParamField>
    <ParamField body="s" type="string" required>32 bytes, hex.</ParamField>
    <ParamField body="value" type="string">Amount the permit covers, as a decimal string. Defaults to the repayment amount. It must be at least that amount, or the request is refused rather than left to revert.</ParamField>
  </Expandable>

  The spender in the signature must be the market address.
</ParamField>

<ParamField body="txHash" type="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.
</ParamField>

## Transaction Shape

A partial repayment returns two steps: `approve` on the borrow asset, then `repay`.

A full repayment (`all: true`) returns three. The third resets the allowance to zero. `repay` caps the pull at the true debt, so without it the unused approval would stay live against the payer's funds after the loan closed.

With a `permit`, the approval disappears. A partial repayment is one step, `repayWithPermit`. A full repayment is two: `repayWithPermit`, then the same allowance reset, because the permit installs the overshoot as an allowance the repayment does not spend.

<Warning>
  The confirmable step is not always the last one, and it is not always at the same index. Read `confirmStepIndex` from the response rather than assuming a position. It is `1` on the approve-then-repay path and `0` on the permit path, and in both cases it names the step whose `functionName` starts with `repay`. Confirming with the allowance-reset hash returns `TX_WRONG_TARGET`.
</Warning>

## Response Fields

<ResponseField name="data" type="object">
  <Expandable>
    <ResponseField name="action" type="string">`SIGN_TRANSACTIONS`. Returned when `txHash` is omitted.</ResponseField>
    <ResponseField name="steps" type="array">Ordered transactions to broadcast. Returned when `txHash` is omitted.</ResponseField>
    <ResponseField name="fullRepayment" type="boolean">Whether the payload settles the loan in full.</ResponseField>
    <ResponseField name="confirmStepIndex" type="integer">Index of the step to confirm with. `1` on the approve-then-repay path, `0` on the permit path. Read it rather than assuming.</ResponseField>
    <ResponseField name="confirmWith" type="string">`repay`, on both paths.</ResponseField>
    <ResponseField name="permitSupported" type="boolean">Whether the settlement asset implements EIP-2612, so a `permit` could have been sent instead. Probed once and stored on the market, not per request. Present on the approve-then-repay path.</ResponseField>
    <ResponseField name="permitUsed" type="boolean">`true` on the permit path. Absent otherwise.</ResponseField>
    <ResponseField name="outstandingDebt" type="string">Principal plus accrued interest at the time the payload was built.</ResponseField>
    <ResponseField name="repayAmount" type="string">Amount the `repay` step is sized for, including the overshoot on a full repayment.</ResponseField>
    <ResponseField name="collateralRelease" type="object">Present on a full repayment when releasing the collateral is restricted. Describes what the collateral token would do.</ResponseField>
    <ResponseField name="warning" type="string">Human-readable form of `collateralRelease`, present alongside it.</ResponseField>
    <ResponseField name="success" type="boolean">Nested inside `data` on the calldata response.</ResponseField>
    <ResponseField name="txHash" type="string">Transaction hash. Returned when confirming.</ResponseField>
    <ResponseField name="loanId" type="integer">Loan ID, echoed back. Returned when confirming.</ResponseField>
    <ResponseField name="repaidAmount" type="string">Amount that actually moved, read from the `LoanRepaid` event rather than from the calldata. On a full repayment this is lower than `repayAmount`, because the contract pulls only the true debt. Returned when confirming.</ResponseField>
    <ResponseField name="collateralReturned" type="string">Collateral the repayment released back to the borrower, when the receipt carries a return. Returned when confirming.</ResponseField>
    <ResponseField name="collateralReturnEscrowed" type="boolean">`true` when that return was blocked on compliance and escrowed on the adapter instead of delivered. Claim it with [Claim Escrowed Collateral](/endpoints/lending/claim-escrowed-collateral).</ResponseField>
  </Expandable>
</ResponseField>

<Note>
  Repaying the full debt does not release collateral on its own. Follow with [Close Loan](/endpoints/lending/close-loan) to unlock the pledged tokens and mark the position repaid.
</Note>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://api.trusset.org/lending-external-securities/api/positions/{marketId}/repay" \
    -H "X-API-Key: trusset_your_key_here" \
    -H "Content-Type: application/json" \
    -d '{"loanId": 5, "amount": "10000"}'
  ```

  ```typescript TypeScript theme={null}
  const res = await fetch(
    `https://api.trusset.org/lending-external-securities/api/positions/${marketId}/repay`,
    {
      method: 'POST',
      headers: {
        'X-API-Key': 'trusset_your_key_here',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ loanId: 5, all: true })
    }
  );
  const { data } = await res.json();

  const hashes = [];
  for (const step of data.steps) {
    const tx = await wallet.sendTransaction(step.transaction);
    await tx.wait();
    hashes.push(tx.hash);
  }

  await fetch(
    `https://api.trusset.org/lending-external-securities/api/positions/${marketId}/repay`,
    {
      method: 'POST',
      headers: {
        'X-API-Key': 'trusset_your_key_here',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ loanId: 5, txHash: hashes[data.confirmStepIndex] })
    }
  );
  ```
</RequestExample>

<ResponseExample>
  ```json Calldata Response - Full Repayment theme={null}
  {
    "success": true,
    "data": {
      "action": "SIGN_TRANSACTIONS",
      "steps": [
        {
          "action": "SIGN_TRANSACTION",
          "transaction": {
            "to": "0x98ad0ca091552e23c564b41c74282e5343d03e8a",
            "data": "0x...",
            "value": "0",
            "chainId": 11155111
          },
          "functionName": "approve",
          "description": "Approve the market to pull USDC"
        },
        {
          "action": "SIGN_TRANSACTION",
          "transaction": {
            "to": "0x70a0e25c7b768b87e658348b3b577678a173e038",
            "data": "0x...",
            "value": "0",
            "chainId": 11155111
          },
          "functionName": "repay"
        },
        {
          "action": "SIGN_TRANSACTION",
          "transaction": {
            "to": "0x98ad0ca091552e23c564b41c74282e5343d03e8a",
            "data": "0x...",
            "value": "0",
            "chainId": 11155111
          },
          "functionName": "approve",
          "description": "Clear the leftover USDC allowance granted for this repayment"
        }
      ],
      "fullRepayment": true,
      "confirmStepIndex": 1,
      "confirmWith": "repay",
      "permitSupported": true,
      "outstandingDebt": "50412.881000",
      "repayAmount": "50513.706763"
    }
  }
  ```

  ```json Calldata Response - With Permit theme={null}
  {
    "success": true,
    "data": {
      "action": "SIGN_TRANSACTIONS",
      "steps": [
        {
          "action": "SIGN_TRANSACTION",
          "transaction": {
            "to": "0x70a0e25c7b768b87e658348b3b577678a173e038",
            "data": "0x...",
            "value": "0",
            "chainId": 11155111
          },
          "functionName": "repayWithPermit",
          "description": "Repay in a single transaction: the embedded permit installs the allowance and the market pulls at most the true debt"
        }
      ],
      "fullRepayment": false,
      "confirmStepIndex": 0,
      "confirmWith": "repay",
      "permitUsed": true,
      "outstandingDebt": "50412.881000",
      "repayAmount": "10000.000000"
    }
  }
  ```

  ```json Confirmed Response theme={null}
  {
    "success": true,
    "data": {
      "txHash": "0x9f2c41d8b7e05a3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b",
      "loanId": 5,
      "repaidAmount": "50412.913422"
    }
  }
  ```

  ```json Error - Wrong Step Confirmed theme={null}
  {
    "success": false,
    "error": {
      "code": "TX_WRONG_TARGET",
      "message": "This transaction does not target the market. A full repayment is signed as several steps and only the repay step can be confirmed. Use the hash of the step whose functionName is \"repay\" (index 1 of the steps returned for this repayment), not the last one."
    }
  }
  ```
</ResponseExample>

## Error Codes

| Code                     | HTTP  | Cause                                                                                                                                                 |
| ------------------------ | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `NO_MARKET_ADDRESS`      | `400` | The market has no on-chain address recorded                                                                                                           |
| `VALIDATION_ERROR`       | `400` | `loanId` is not a positive integer, or neither `amount` nor `all` was supplied                                                                        |
| `INVALID_AMOUNT`         | `400` | `amount` carries more decimal places than the borrow asset supports                                                                                   |
| `NO_OUTSTANDING_DEBT`    | `400` | `all` was set on a loan that owes nothing                                                                                                             |
| `LOAN_NOT_ACTIVE`        | `400` | The loan is closed and can no longer be modified                                                                                                      |
| `INVALID_PERMIT`         | `400` | `permit.deadline` is not in the future, `v`, `r` or `s` is malformed, or `permit.value` covers less than the repayment offers                         |
| `TX_WRONG_TARGET`        | `400` | The confirmed transaction does not target the market. On a full repayment, confirm the `repay` step                                                   |
| `TX_NOT_VERIFIED`        | `400` | The confirmed transaction repays a different loan                                                                                                     |
| `REPAY_FAILED`           | `400` | The repayment could not be prepared and no more specific code applied                                                                                 |
| `LOAN_NOT_FOUND`         | `404` | No such loan on this market                                                                                                                           |
| `PERMIT_UNSUPPORTED`     | `409` | A `permit` was sent for a settlement asset that does not implement EIP-2612, or whose support could not be verified. Use the approve-then-repay steps |
| `LOAN_STATE_UNAVAILABLE` | `503` | The loan could not be read from the network right now. Retry shortly                                                                                  |
