> ## 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.

# Unwind Sale

> Calldata that refunds the buyer of a paid sale whose asset was not delivered within 30 days

> [!NOTE]
>
> Seller Financing is in beta and runs on Ethereum Sepolia instances only for now (`DEVELOPMENT` instances on Ethereum). A `PRODUCTION` instance, or one on another network, answers `503 SELLER_FINANCING_UNAVAILABLE`. See [Seller Financing](https://docs.trusset.org/endpoints/seller-financing/introduction.md).

Builds the unwind of a `REPAID` sale on a market that runs delivery against payment. See [Market generations](https://docs.trusset.org/endpoints/seller-financing/introduction.md#market-generations). The market holds the downpayment and the principal of a paid sale until the asset is delivered. When it is not delivered within 30 days after the payoff, the sale can be unwound:

* **The buyer** can unwind it once the asset cannot be delivered.
* **A wallet that holds `OPERATOR_ROLE`** can unwind it in any case.

The unwind credits the held payment to the buyer, who withdraws it with [Withdraw](https://docs.trusset.org/endpoints/seller-financing/withdraw.md), and the listing reads `UNWOUND`. The interest the buyer paid stays with the seller. The lock is released: in freeze mode the freeze in the seller's wallet is lifted up to what the seller's other live sales on the market do not need, and nothing while the freeze adapter lacks the agent role on the token. In custody mode the adapter returns to the seller at most what it holds. An unwind stays open while the market is paused.

A sale paid off before the market moved to delivery against payment has no held payment: the seller was credited at that payoff, and the sale cannot be unwound. The answer is `409 TX_WOULD_REVERT` with `NoHeldPayment`.

Before building, the API checks, in order:

1. The market runs delivery against payment and has recounted its live sales. Otherwise the answer is `409 MARKET_UPGRADE_REQUIRED` or `409 MIGRATION_PENDING`.
2. The listing is `REPAID`.
3. The market holds a payment for the sale (`heldPayment(id)`). Otherwise `409 TX_WOULD_REVERT` with `NoHeldPayment`.
4. The delivery period has passed, measured against the time of the latest block. Before `unwindableAt` the answer is `409 DELIVERY_PERIOD_RUNNING` with `details.unwindableAt`.
5. Unless `from` holds `OPERATOR_ROLE`: `from` is the buyer, otherwise `409 TX_WOULD_REVERT` with `NotBuyer`, naming the buyer and the operators. And the asset cannot be delivered (`isDeliverable(id)` is false), otherwise `409 ASSET_DELIVERABLE`: the buyer claims the asset with [Claim Asset](https://docs.trusset.org/endpoints/seller-financing/claim-asset.md) instead.

A read that fails answers `503 CHAIN_UNAVAILABLE` and never a verdict. The unwind is then simulated from `from`.

## Path Parameters

**marketId** `string` *required*

The market's record ID, as `id` on [List Markets](https://docs.trusset.org/endpoints/seller-financing/list-markets.md).

**listingId** `string` *required*

The listing's ID on the market.

## Body Parameters

**from** `string` *required*

The wallet that signs: the buyer of the listing, or a wallet that holds `OPERATOR_ROLE` on the market. Without it the answer is `400 FROM_REQUIRED`.

## Response Fields

**data** `object`

**action** `string`

`SIGN_TRANSACTIONS`.

**chainId** `integer`

The chain the step is built for.

**steps** `array`

One step, `unwindSale` on the market, with `gasLimit`.

**confirmStepIndex** `integer`

`0`.

**preflight** `object`

`{ simulated: true, gasEstimate }`.

**heldPayment** `object`

The payment the market holds for this sale, as on [Get Listing](https://docs.trusset.org/endpoints/seller-financing/get-listing.md#response-fields), with `unwindable` measured against the latest block.

**refund** `object`

`{ to, amount, amountFormatted, note }`: the buyer and what the unwind credits it.

**assetReturn** `object`

Where the asset goes: `{ to, note }` with the seller. In custody mode, when the asset token refuses the return to the seller, `{ willEscrow: true, reason, message }` instead: the adapter keeps the asset in escrow for the seller, who reclaims it with [Claim Escrowed Collateral](https://docs.trusset.org/endpoints/seller-financing/claim-escrowed-collateral.md).

**signer** `object`

`{ role: "BUYER_OR_OPERATOR_ROLE", buyer, signingAs }`, where `signingAs` is `OPERATOR_ROLE` or `BUYER`.

**warning** `string`

Present with an escrowed custody return.

```bash cURL theme={null}
curl -X POST "https://api.trusset.org/seller-financing/api/markets/cmsg4x7k20003sf9q1d8v6b2e/listings/9/unwind" \
  -H "X-API-Key: trusset_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"from": "0x8cC237798b4E5eE7A07F20e8ad2db554404abF88"}'
```

```typescript TypeScript theme={null}
const res = await fetch(
  `https://api.trusset.org/seller-financing/api/markets/${marketId}/listings/${listingId}/unwind`,
  {
    method: 'POST',
    headers: { 'X-API-Key': 'trusset_your_key_here', 'Content-Type': 'application/json' },
    body: JSON.stringify({ from: await buyer.getAddress() })
  }
);
const { data } = await res.json();
const step = data.steps[0];
await (await buyer.sendTransaction({ to: step.to, data: step.data, value: 0, gasLimit: step.gasLimit })).wait();
```

```json Response theme={null}
{
  "success": true,
  "data": {
    "action": "SIGN_TRANSACTIONS",
    "chainId": 11155111,
    "steps": [
      {
        "to": "0xC0e7c00eFeE062188d596a5581638BE758F9D5d4",
        "data": "0xe45d7e7b...",
        "value": "0",
        "functionName": "unwindSale",
        "label": "Unwind the sale of listing 9 and refund 10.0 to the buyer",
        "description": "Unwind the sale of listing 9 and refund 10.0 to the buyer",
        "gasLimit": "143991"
      }
    ],
    "confirmStepIndex": 0,
    "preflight": { "simulated": true, "gasEstimate": "110762" },
    "heldPayment": {
      "readable": true,
      "amount": "10000000",
      "amountFormatted": "10.0",
      "repaidAt": 1792580111,
      "deliverBy": 1795172111,
      "unwindableAt": 1795172112,
      "unwindable": true,
      "note": "The market holds the downpayment and the principal until the asset is delivered. Delivered, they are credited to the seller. Not delivered by 2026-11-20T10:55:11.000Z, the buyer can unwind the sale when the asset cannot be delivered, and an operator can unwind it in any case."
    },
    "refund": {
      "to": "0x8cC237798b4E5eE7A07F20e8ad2db554404abF88",
      "amount": "10000000",
      "amountFormatted": "10.0",
      "note": "The unwind credits the downpayment and the principal to the buyer, who withdraws them with POST /seller-financing/api/markets/:marketId/withdraw. The interest paid stays with the seller."
    },
    "assetReturn": {
      "to": "0x23966303b7b8e6cE0223f6A1D34b5a0B1aD2417F",
      "note": "The lock is released in the seller's wallet up to what the seller's other live sales on this market do not need. While the freeze adapter lacks the agent role on the token, nothing is released."
    },
    "signer": { "role": "BUYER_OR_OPERATOR_ROLE", "buyer": "0x8cC237798b4E5eE7A07F20e8ad2db554404abF88", "signingAs": "BUYER" }
  },
  "error": null,
  "metadata": {
    "timestamp": "2026-11-21T11:02:40.000Z",
    "requestId": "3f7c2a91-6d84-4b0e-9a15-c2e8f4d7b603",
    "instanceId": "inst_abc123"
  }
}
```

```json Error - Delivery Period Running theme={null}
{
  "success": false,
  "data": null,
  "error": {
    "code": "DELIVERY_PERIOD_RUNNING",
    "message": "The seller has until 2026-11-20T10:55:11.000Z to deliver the asset of listing 8. The sale can be unwound from 2026-11-20T10:55:12.000Z (unix 1795172112). Nothing was built.",
    "details": {
      "action": "sale unwind",
      "error": "DeliveryPeriodRunning",
      "unwindableAt": 1795172112,
      "heldPayment": { "readable": true, "amount": "10000000", "amountFormatted": "10.0", "repaidAt": 1792580111, "deliverBy": 1795172111, "unwindableAt": 1795172112, "unwindable": false }
    }
  },
  "metadata": {
    "timestamp": "2026-10-21T10:55:20.000Z",
    "requestId": "3f7c2a91-6d84-4b0e-9a15-c2e8f4d7b603",
    "instanceId": "inst_abc123"
  }
}
```

```json Error - Asset Deliverable theme={null}
{
  "success": false,
  "data": null,
  "error": {
    "code": "ASSET_DELIVERABLE",
    "message": "The asset of listing 8 can still be delivered, so the buyer cannot unwind the sale: claim the asset with claim-asset instead. Only a wallet holding OPERATOR_ROLE (0xCeBE3CdF854629823D03892675f7FD4eA3A036a9) can unwind a sale whose asset can be delivered. Nothing was built.",
    "details": {
      "action": "sale unwind",
      "error": "AssetDeliverable",
      "requiredRole": "OPERATOR_ROLE",
      "roleHolders": ["0xCeBE3CdF854629823D03892675f7FD4eA3A036a9"],
      "heldPayment": { "readable": true, "amount": "10000000", "amountFormatted": "10.0", "repaidAt": 1792580111, "deliverBy": 1795172111, "unwindableAt": 1795172112, "unwindable": true }
    }
  },
  "metadata": {
    "timestamp": "2026-11-21T11:02:40.000Z",
    "requestId": "3f7c2a91-6d84-4b0e-9a15-c2e8f4d7b603",
    "instanceId": "inst_abc123"
  }
}
```

## Error Codes

| Code | HTTP | Cause |
| - | - | - |
| `INVALID_LISTING_ID` | `400` | `listingId` is not a positive integer of up to 19 digits |
| `VALIDATION_ERROR` | `400` | `from` is malformed, or the body carries another field. `error.details` names it |
| `FROM_REQUIRED` | `400` | `from` is missing. The message names who signs: the buyer, or a wallet that holds `OPERATOR_ROLE` |
| `MARKET_NOT_FOUND` | `404` | No market with this ID that your instance reaches on its network |
| `LISTING_NOT_FOUND` | `404` | No listing with this ID on the market |
| `MARKET_UPGRADE_REQUIRED` | `409` | The market runs the first implementation, where a payoff credits the seller at once and nothing is held |
| `MIGRATION_PENDING` | `409` | The market runs delivery against payment but has not recounted its live sales. [Upgrade Market](https://docs.trusset.org/endpoints/seller-financing/upgrade-market.md) builds the recount |
| `INVALID_STATUS` | `409` | The listing is not `REPAID`. `details.status` names its status |
| `DELIVERY_PERIOD_RUNNING` | `409` | The 30 days after the payoff have not passed. `details` carries `unwindableAt` and `heldPayment` |
| `ASSET_DELIVERABLE` | `409` | The buyer signs while the asset can still be delivered. `details.roleHolders` names the operators |
| `TX_WOULD_REVERT` | `409` | `NoHeldPayment` for a sale paid off before the market moved to delivery against payment, `NotBuyer` with `details.requiredRole: "BUYER_OR_OPERATOR_ROLE"`, `details.buyer` and `details.roleHolders`, or another refusal of the simulation |
| `CHAIN_UNAVAILABLE` | `503` | The held payment, the buyer, the role or the latest block could not be read. Nothing was built. Retry shortly |
| `SELLER_FINANCING_UNAVAILABLE` | `503` | The instance is a `PRODUCTION` instance or not on Ethereum |
| `UNWIND_BUILD_FAILED` | `500` | Unexpected failure. Nothing was built. Retry, or contact support with the request ID |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.