{
  "openapi": "3.1.0",
  "info": {
    "title": "Settle API",
    "version": "1.0.0",
    "summary": "A P2P market for ETH on Robinhood Chain, from your server.",
    "description": "Settle is a P2P market for ETH on Robinhood Chain (chain id 4663). Sellers lock ETH in an on-chain escrow vault; buyers pay them off-chain (PayPal, X Money, Revolut, bank transfers, gift cards...); the seller confirms and the vault releases the ETH to the buyer. The API lets your own servers do what you do on the site: read the market, post and manage ads, open and run trades, get notified.\n\n**Server to server only.** `Authorization: Bearer settle_sk_<id>_<secret>` (`<id>`: 12 `[a-z0-9]`, `<secret>`: 43 base64url characters). A key acts as the Settle account that created it on the Developers page; at most 5 active keys per account. A request that carries a browser `Origin` or `Sec-Fetch-Site` header with a key is refused (403 `browser_not_allowed`). Public routes (`/config`, `/methods`, `/market`, `/ads/{id}`) work without a key.\n\n**Scopes.** Every key has `read`, plus any of `trade` and `release` (each operation's `x-settle-scope`). `release` is opt-in: a leaked key with `release` can give your ETH away. Missing scope: 403 `insufficient_scope`.\n\n**A key can't change where money goes.** No route changes your wallet or your payees: trades use the ones saved on the site, withdrawals go to your saved wallet only. Deposits are calldata you sign from your own wallet: check `to` against GET /config `vault`.\n\n**Errors** are `{\"error\": \"<code>\", \"message\": \"<human text>\"}` with the status: 400 `bad_request`; 401 `missing_api_key`, `invalid_api_key`, `revoked_api_key`; 403 `insufficient_scope`, `browser_not_allowed`, `forbidden`; 404 `not_found`; 405 `method_not_allowed`; 409 `idempotency_conflict`, `conflict`; 413 `body_too_large` (16 KB); 415 `unsupported_media_type`; 429 `rate_limited` (`Retry-After`); 500 `internal_error`; 503 `unavailable` (retry).\n\n**Idempotency.** Every POST and PATCH accepts `Idempotency-Key` (1 to 100 `[A-Za-z0-9_.:-]`): the same key, method, path and body within 24 h replay the first answer with `Idempotent-Replayed: true`.\n\n**Units.** ETH in wei as decimal strings; dollars in integer US cents; prices per ETH as USD numbers; times ISO 8601 (UTC); ids UUIDs, except event ids (increasing decimal strings).\n\n**Limits.** 60 requests a minute per key (best effort), 300 per IP.\n\n**Webhooks.** One HTTPS endpoint per account (Developers page). Each event is POSTed with `Settle-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256>` over `<t>.<raw body>`, keyed with the full `whsec_...` secret. At least once, not ordered: dedupe on the event id and read the trade before acting.\n\nSDK: https://usesettle.cash/sdk/settle.mjs (one file, zero dependencies; Node, Deno, Bun)."
  },
  "externalDocs": {
    "description": "Settle API guide",
    "url": "https://usesettle.cash/docs/api"
  },
  "servers": [
    {
      "url": "https://usesettle.cash/api/v1"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "Market",
      "description": "Public reads: no key needed."
    },
    {
      "name": "Account",
      "description": "Your account."
    },
    {
      "name": "Ads",
      "description": "Your ads and their escrow."
    },
    {
      "name": "Trades",
      "description": "Open and run trades."
    },
    {
      "name": "Events",
      "description": "What happened on your account, in order."
    }
  ],
  "paths": {
    "/config": {
      "get": {
        "tags": [
          "Market"
        ],
        "operationId": "getConfig",
        "summary": "Chain, vault, fees and limits",
        "description": "Public: works without an API key.\n\nCheck every deposit you sign against `vault` and `chainId`.",
        "security": [],
        "responses": {
          "200": {
            "description": "The configuration.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Config"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/methods": {
      "get": {
        "tags": [
          "Market"
        ],
        "operationId": "listMethods",
        "summary": "Payment methods",
        "description": "Public: works without an API key.",
        "security": [],
        "responses": {
          "200": {
            "description": "Every payment method.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "methods"
                  ],
                  "properties": {
                    "methods": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Method"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/market": {
      "get": {
        "tags": [
          "Market"
        ],
        "operationId": "getMarket",
        "summary": "Listed ads, best price first",
        "description": "Public: works without an API key.\n\nOnly listed ads. `side=sell`: people selling, where you buy; `side=buy`: people buying, where you sell. `asset` picks the market (ETH by default). Public market reads may be cached briefly.",
        "security": [],
        "parameters": [
          {
            "name": "side",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "sell",
                "buy"
              ],
              "default": "sell"
            },
            "description": "Which side of the market."
          },
          {
            "name": "asset",
            "in": "query",
            "required": false,
            "schema": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/Asset"
                }
              ],
              "default": "ETH"
            },
            "description": "Which asset's market."
          },
          {
            "name": "method",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "A payment method id: only ads that take it."
          },
          {
            "name": "amountCents",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100000000
            },
            "description": "A trade size in cents: only ads whose limits allow it."
          }
        ],
        "responses": {
          "200": {
            "description": "The market.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "asset",
                    "marketUsd",
                    "ethUsd",
                    "ads"
                  ],
                  "properties": {
                    "asset": {
                      "$ref": "#/components/schemas/Asset"
                    },
                    "marketUsd": {
                      "type": [
                        "number",
                        "null"
                      ],
                      "description": "Price of one unit of the asset in USD (1 for USDG; null while the ETH feed is down)."
                    },
                    "ethUsd": {
                      "type": [
                        "number",
                        "null"
                      ],
                      "description": "Deprecated: same as marketUsd on the ETH market, null on others."
                    },
                    "ads": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Ad"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/ads": {
      "post": {
        "tags": [
          "Ads"
        ],
        "operationId": "createAd",
        "summary": "Create an ad",
        "description": "Scope: `trade`.\n\nSell ads need a payee saved for each method; buy ads need a saved wallet (both set on the site: no API changes them). A sell ad shows on the market once its escrow covers the minimum trade: GET /ads/{id}/deposit.",
        "security": [
          {
            "apiKey": [
              "trade"
            ]
          }
        ],
        "x-settle-scope": "trade",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAd"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ad"
                  ],
                  "properties": {
                    "ad": {
                      "$ref": "#/components/schemas/MyAd"
                    }
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/ads/{id}": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "getAd",
        "summary": "One ad",
        "description": "Public: works without an API key.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/AdId"
          }
        ],
        "responses": {
          "200": {
            "description": "The ad.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ad",
                    "marketUsd",
                    "ethUsd"
                  ],
                  "properties": {
                    "ad": {
                      "$ref": "#/components/schemas/Ad"
                    },
                    "marketUsd": {
                      "type": [
                        "number",
                        "null"
                      ],
                      "description": "Price of one unit of the ad's asset in USD."
                    },
                    "ethUsd": {
                      "type": [
                        "number",
                        "null"
                      ],
                      "description": "Deprecated: same as marketUsd on ETH ads, null on others."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      },
      "patch": {
        "tags": [
          "Ads"
        ],
        "operationId": "updateAdStatus",
        "summary": "Pause, resume or close an ad",
        "description": "Scope: `trade`.",
        "security": [
          {
            "apiKey": [
              "trade"
            ]
          }
        ],
        "x-settle-scope": "trade",
        "parameters": [
          {
            "$ref": "#/components/parameters/AdId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "status"
                ],
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "paused",
                      "closed"
                    ]
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The ad.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ad"
                  ],
                  "properties": {
                    "ad": {
                      "$ref": "#/components/schemas/MyAd"
                    }
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/ads/{id}/deposit": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "getAdDeposit",
        "summary": "Calldata to fund a sell ad's escrow",
        "description": "Scope: `read`.\n\nYour sell ad. Sign and send the returned transaction from your own wallet, after checking `to` against GET /config (`vault` for ETH, `tokenVault` for USDG) and `chainId` (4663). USDG: send `approve` first. SOL ads get a `SolDeposit`: send the amount to the ad's escrow address from any wallet.",
        "security": [
          {
            "apiKey": [
              "read"
            ]
          }
        ],
        "x-settle-scope": "read",
        "parameters": [
          {
            "$ref": "#/components/parameters/AdId"
          },
          {
            "name": "amountWei",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Wei",
              "description": "More than 0."
            },
            "description": "The amount to lock, in the ad's asset base units (wei for ETH, 1e-6 for USDG, lamports for SOL)."
          }
        ],
        "responses": {
          "200": {
            "description": "The transaction to sign.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "deposit"
                  ],
                  "properties": {
                    "deposit": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/Deposit"
                        },
                        {
                          "$ref": "#/components/schemas/SolDeposit"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/ads/{id}/withdraw": {
      "post": {
        "tags": [
          "Ads"
        ],
        "operationId": "withdrawAd",
        "summary": "Withdraw an ad's free escrow",
        "description": "Scope: `trade`.\n\nEscrow not committed to open trades, to your saved wallet only.",
        "security": [
          {
            "apiKey": [
              "trade"
            ]
          }
        ],
        "x-settle-scope": "trade",
        "parameters": [
          {
            "$ref": "#/components/parameters/AdId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "maxProperties": 0,
                "description": "An empty JSON object."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The payout, or null when nothing was free to withdraw.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "payout"
                  ],
                  "properties": {
                    "payout": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "required": [
                        "id",
                        "amountWei",
                        "to"
                      ],
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "amountWei": {
                          "$ref": "#/components/schemas/Wei"
                        },
                        "to": {
                          "type": "string",
                          "pattern": "^0x[0-9a-fA-F]{40}$",
                          "description": "Your saved wallet."
                        }
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/me": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getMe",
        "summary": "Your account",
        "description": "Scope: `read`.",
        "security": [
          {
            "apiKey": [
              "read"
            ]
          }
        ],
        "x-settle-scope": "read",
        "responses": {
          "200": {
            "description": "Your account, wallet, payees and this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Me"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/me/ads": {
      "get": {
        "tags": [
          "Ads"
        ],
        "operationId": "listMyAds",
        "summary": "Your ads",
        "description": "Scope: `read`.",
        "security": [
          {
            "apiKey": [
              "read"
            ]
          }
        ],
        "x-settle-scope": "read",
        "responses": {
          "200": {
            "description": "Your ads.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ads"
                  ],
                  "properties": {
                    "ads": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MyAd"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/trades": {
      "get": {
        "tags": [
          "Trades"
        ],
        "operationId": "listTrades",
        "summary": "Your trades",
        "description": "Scope: `read`.\n\n`open`: awaiting_escrow, escrowed, paid, releasing, disputed. `closed`: completed, cancelled.",
        "security": [
          {
            "apiKey": [
              "read"
            ]
          }
        ],
        "x-settle-scope": "read",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "closed",
                "all"
              ],
              "default": "all"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "`nextCursor` of the previous page."
          }
        ],
        "responses": {
          "200": {
            "description": "A page.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "trades",
                    "nextCursor"
                  ],
                  "properties": {
                    "trades": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TradeSummary"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      },
      "post": {
        "tags": [
          "Trades"
        ],
        "operationId": "openTrade",
        "summary": "Open a trade on an ad",
        "description": "Scope: `trade`.\n\nOn a sell ad you buy (the ETH goes to your saved wallet); on a buy ad you sell (then lock the ETH: `trade.deposit`).",
        "security": [
          {
            "apiKey": [
              "trade"
            ]
          }
        ],
        "x-settle-scope": "trade",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "adId",
                  "fiatCents",
                  "method"
                ],
                "properties": {
                  "adId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "fiatCents": {
                    "$ref": "#/components/schemas/Cents",
                    "minimum": 1
                  },
                  "method": {
                    "type": "string",
                    "description": "One of the ad's methods."
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opened.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "trade"
                  ],
                  "properties": {
                    "trade": {
                      "$ref": "#/components/schemas/Trade"
                    }
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/trades/{id}": {
      "get": {
        "tags": [
          "Trades"
        ],
        "operationId": "getTrade",
        "summary": "One trade",
        "description": "Scope: `read`.",
        "security": [
          {
            "apiKey": [
              "read"
            ]
          }
        ],
        "x-settle-scope": "read",
        "parameters": [
          {
            "$ref": "#/components/parameters/TradeId"
          }
        ],
        "responses": {
          "200": {
            "description": "The trade.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "trade"
                  ],
                  "properties": {
                    "trade": {
                      "$ref": "#/components/schemas/Trade"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/trades/{id}/messages": {
      "get": {
        "tags": [
          "Trades"
        ],
        "operationId": "listTradeMessages",
        "summary": "Trade chat",
        "description": "Scope: `read`.\n\nOldest first, at most 500.",
        "security": [
          {
            "apiKey": [
              "read"
            ]
          }
        ],
        "x-settle-scope": "read",
        "parameters": [
          {
            "$ref": "#/components/parameters/TradeId"
          },
          {
            "name": "after",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "A message id: only newer messages."
          }
        ],
        "responses": {
          "200": {
            "description": "Messages.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "messages"
                  ],
                  "properties": {
                    "messages": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Message"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      },
      "post": {
        "tags": [
          "Trades"
        ],
        "operationId": "sendTradeMessage",
        "summary": "Send a chat message",
        "description": "Scope: `trade`.",
        "security": [
          {
            "apiKey": [
              "trade"
            ]
          }
        ],
        "x-settle-scope": "trade",
        "parameters": [
          {
            "$ref": "#/components/parameters/TradeId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "body"
                ],
                "properties": {
                  "body": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 1000
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Sent.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "message"
                  ],
                  "properties": {
                    "message": {
                      "$ref": "#/components/schemas/Message"
                    }
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/trades/{id}/paid": {
      "post": {
        "tags": [
          "Trades"
        ],
        "operationId": "markTradePaid",
        "summary": "Mark the payment as sent",
        "description": "Scope: `trade`.\n\nBuyer.",
        "security": [
          {
            "apiKey": [
              "trade"
            ]
          }
        ],
        "x-settle-scope": "trade",
        "parameters": [
          {
            "$ref": "#/components/parameters/TradeId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "note": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "A reference for the seller."
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The trade.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "trade"
                  ],
                  "properties": {
                    "trade": {
                      "$ref": "#/components/schemas/Trade"
                    }
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/trades/{id}/cancel": {
      "post": {
        "tags": [
          "Trades"
        ],
        "operationId": "cancelTrade",
        "summary": "Cancel a trade",
        "description": "Scope: `trade`.",
        "security": [
          {
            "apiKey": [
              "trade"
            ]
          }
        ],
        "x-settle-scope": "trade",
        "parameters": [
          {
            "$ref": "#/components/parameters/TradeId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "maxProperties": 0,
                "description": "An empty JSON object."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The trade.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "trade"
                  ],
                  "properties": {
                    "trade": {
                      "$ref": "#/components/schemas/Trade"
                    }
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/trades/{id}/dispute": {
      "post": {
        "tags": [
          "Trades"
        ],
        "operationId": "disputeTrade",
        "summary": "Open a dispute",
        "description": "Scope: `trade`.",
        "security": [
          {
            "apiKey": [
              "trade"
            ]
          }
        ],
        "x-settle-scope": "trade",
        "parameters": [
          {
            "$ref": "#/components/parameters/TradeId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "reason"
                ],
                "properties": {
                  "reason": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 500
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The trade.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "trade"
                  ],
                  "properties": {
                    "trade": {
                      "$ref": "#/components/schemas/Trade"
                    }
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/trades/{id}/release": {
      "post": {
        "tags": [
          "Trades"
        ],
        "operationId": "releaseTrade",
        "summary": "Release the ETH to the buyer",
        "description": "Scope: `release` (opt-in: a leaked key with `release` can give your ETH away).\n\nSeller; the trade is `escrowed` or `paid`. Irreversible: release only once the money is in your account.",
        "security": [
          {
            "apiKey": [
              "release"
            ]
          }
        ],
        "x-settle-scope": "release",
        "parameters": [
          {
            "$ref": "#/components/parameters/TradeId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "maxProperties": 0,
                "description": "An empty JSON object."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The trade (status `releasing`).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "trade"
                  ],
                  "properties": {
                    "trade": {
                      "$ref": "#/components/schemas/Trade"
                    }
                  }
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/events": {
      "get": {
        "tags": [
          "Events"
        ],
        "operationId": "listEvents",
        "summary": "Your events, in order",
        "description": "Scope: `read`.\n\nPoll with `after` = the last id you processed (`next`). Without `after`: the latest `limit` events. Events are kept 30 days.",
        "security": [
          {
            "apiKey": [
              "read"
            ]
          }
        ],
        "x-settle-scope": "read",
        "parameters": [
          {
            "name": "after",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{1,18}$"
            },
            "description": "An event id."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Events.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "events",
                    "next"
                  ],
                  "properties": {
                    "events": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Event"
                      }
                    },
                    "next": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "pattern": "^[0-9]+$",
                      "description": "Pass as `after` on the next poll: the last event id, or `after` itself when nothing is new (null without `after` and without events)."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    }
  },
  "webhooks": {
    "event": {
      "post": {
        "operationId": "settleEvent",
        "summary": "An event on your account",
        "description": "Settle POSTs each Event as JSON (`Content-Type: application/json`) to your endpoint. Verify `Settle-Signature` on the raw body before parsing (SDK: `verifyWebhook`): `v1` is the hex HMAC-SHA256, keyed with the full `whsec_...` secret as UTF-8 bytes, of `<t>.<raw request body>`; compare in constant time and refuse a `t` more than 300 s from now. Answer 2xx within 10 s; otherwise Settle retries after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h and 24 h (8 attempts), then marks the delivery failed (it can be resent from the Developers page). At least once and not ordered: dedupe on the event id, and read the trade (GET /trades/{id}) before acting. Redirects are not followed; private, loopback and link-local addresses are refused.",
        "security": [],
        "parameters": [
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "const": "Settle-Webhooks/1"
            }
          },
          {
            "name": "Settle-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^([0-9]+|ping_[0-9]+)$"
            },
            "description": "The event id (same as the body's `id`; unsigned: trust the verified body)."
          },
          {
            "name": "Settle-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/EventType"
            }
          },
          {
            "name": "Settle-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^t=[0-9]+(,v1=[0-9a-f]{64})+$"
            },
            "description": "t=<unix seconds>,v1=<hex HMAC-SHA256(secret, `${t}.${rawBody}`)>"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Event"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Delivered. Anything else, or no answer within 10 s, is retried."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "settle_sk_<id>_<secret>",
        "description": "An API key from the Developers page: `settle_sk_` + 12 `[a-z0-9]` + `_` + 43 base64url characters. Server side only. Scopes: `read` (always), `trade`, `release` (opt-in)."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error",
          "message"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Stable error code.",
            "example": "insufficient_scope"
          },
          "message": {
            "type": "string",
            "description": "Human text. For `bad_request`, it says which rule failed."
          }
        }
      },
      "Wei": {
        "type": "string",
        "pattern": "^[0-9]+$",
        "description": "An amount in the asset's base units, as a decimal string: wei for ETH (18 decimals), 1e-6 for USDG (6 decimals), lamports for SOL (9 decimals).",
        "example": "5587000000000000"
      },
      "Cents": {
        "type": "integer",
        "minimum": 0,
        "description": "US cents (5000 = $50.00).",
        "example": 5000
      },
      "Trader": {
        "type": "object",
        "required": [
          "handle",
          "name",
          "avatarUrl",
          "verified",
          "trades",
          "completion",
          "online",
          "releaseMinutes"
        ],
        "properties": {
          "handle": {
            "type": "string",
            "description": "X handle, without @."
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "avatarUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "verified": {
            "type": "boolean"
          },
          "trades": {
            "type": "integer",
            "minimum": 0,
            "description": "Trades completed."
          },
          "completion": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 1,
            "description": "Share of trades that didn't fail on their side."
          },
          "online": {
            "type": "boolean",
            "description": "On Settle (site or API) in the last 5 minutes."
          },
          "releaseMinutes": {
            "type": [
              "number",
              "null"
            ],
            "description": "Median minutes from the buyer's \"paid\" to the release, over their recent sales (null: no sales yet)."
          }
        }
      },
      "Ad": {
        "type": "object",
        "required": [
          "id",
          "side",
          "asset",
          "status",
          "priceUsd",
          "priceType",
          "marginBps",
          "fixedPriceUsd",
          "minCents",
          "maxCents",
          "methods",
          "paymentWindowMin",
          "terms",
          "availableWei",
          "listed",
          "toListWei",
          "advertiser",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "side": {
            "type": "string",
            "enum": [
              "sell",
              "buy"
            ],
            "description": "`sell`: the advertiser sells the asset (you buy). `buy`: the advertiser buys it (you sell)."
          },
          "asset": {
            "$ref": "#/components/schemas/Asset"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused",
              "closed"
            ]
          },
          "priceUsd": {
            "type": [
              "number",
              "null"
            ],
            "description": "Price per whole unit of the asset in USD, now (null while the price feed is down).",
            "example": 2711.64
          },
          "priceType": {
            "type": "string",
            "enum": [
              "market",
              "fixed"
            ]
          },
          "marginBps": {
            "type": "integer",
            "description": "Market ads: basis points over (or under, negative) the market price."
          },
          "fixedPriceUsd": {
            "type": [
              "number",
              "null"
            ],
            "description": "Fixed ads: the price per ETH in USD."
          },
          "minCents": {
            "type": "integer",
            "minimum": 1,
            "description": "Smallest trade, in cents."
          },
          "maxCents": {
            "type": "integer",
            "minimum": 1,
            "description": "Largest trade, in cents; capped by what a sell ad's escrow covers."
          },
          "methods": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Payment method ids (GET /methods)."
          },
          "paymentWindowMin": {
            "type": "integer",
            "enum": [
              15,
              30,
              45,
              60
            ],
            "description": "Minutes the buyer has to pay once the ETH is locked."
          },
          "terms": {
            "type": [
              "string",
              "null"
            ]
          },
          "availableWei": {
            "description": "Sell ads: escrow not committed to open trades.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Wei"
              },
              {
                "type": "null"
              }
            ]
          },
          "listed": {
            "type": "boolean",
            "description": "Shown on the market (priced, and enough escrow for the minimum trade)."
          },
          "toListWei": {
            "description": "Sell ads not listed: ETH still to lock to cover the minimum trade and the fee.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Wei"
              },
              {
                "type": "null"
              }
            ]
          },
          "advertiser": {
            "$ref": "#/components/schemas/Trader"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "MyAd": {
        "description": "One of your ads, with its escrow.",
        "allOf": [
          {
            "$ref": "#/components/schemas/Ad"
          },
          {
            "type": "object",
            "required": [
              "escrowRouteId",
              "escrowOnchainWei"
            ],
            "properties": {
              "escrowRouteId": {
                "type": [
                  "string",
                  "null"
                ],
                "pattern": "^0x[0-9a-fA-F]{64}$",
                "description": "The ad's escrow route in the vault (sell ads)."
              },
              "escrowOnchainWei": {
                "description": "What the route holds on chain.",
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/Wei"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          }
        ]
      },
      "Deposit": {
        "type": "object",
        "required": [
          "chainId",
          "to",
          "value",
          "data",
          "routeId"
        ],
        "properties": {
          "chainId": {
            "type": "integer",
            "const": 4663
          },
          "to": {
            "type": "string",
            "pattern": "^0x[0-9a-fA-F]{40}$",
            "description": "The Settle vault for ETH, the token vault for USDG. Check it against GET /config (`vault` or `tokenVault`) before signing."
          },
          "value": {
            "$ref": "#/components/schemas/Wei"
          },
          "data": {
            "type": "string",
            "pattern": "^0x[0-9a-fA-F]*$",
            "description": "ETH: `depositFees(bytes32 routeId, address source = 0x0, uint16 platformBps = 0)` on the vault, with the ETH as `value`. USDG: `deposit(address token, bytes32 routeId, uint256 amount)` on the token vault, `value` 0."
          },
          "routeId": {
            "type": "string",
            "pattern": "^0x[0-9a-fA-F]{64}$"
          },
          "token": {
            "type": "string",
            "pattern": "^0x[0-9a-fA-F]{40}$",
            "description": "USDG only: the token contract."
          },
          "amount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Wei"
              }
            ],
            "description": "USDG only: the amount deposited, in base units."
          },
          "approve": {
            "type": "object",
            "required": [
              "to",
              "data"
            ],
            "description": "USDG only: send this first (`approve(tokenVault, amount)` on the token), so the token vault can pull the USDG.",
            "properties": {
              "to": {
                "type": "string",
                "pattern": "^0x[0-9a-fA-F]{40}$"
              },
              "data": {
                "type": "string",
                "pattern": "^0x[0-9a-fA-F]*$"
              }
            }
          }
        },
        "description": "A transaction to sign and send from your own wallet on Robinhood Chain. Settle never holds your keys."
      },
      "TradeStatus": {
        "type": "string",
        "enum": [
          "awaiting_escrow",
          "escrowed",
          "paid",
          "releasing",
          "completed",
          "disputed",
          "cancelled"
        ]
      },
      "Leg": {
        "type": "object",
        "required": [
          "purpose",
          "status",
          "amountWei",
          "txHash"
        ],
        "properties": {
          "purpose": {
            "type": "string",
            "enum": [
              "release",
              "fee",
              "refund"
            ]
          },
          "status": {
            "type": "string"
          },
          "amountWei": {
            "$ref": "#/components/schemas/Wei"
          },
          "txHash": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^0x[0-9a-fA-F]{64}$"
          }
        }
      },
      "Trade": {
        "type": "object",
        "required": [
          "id",
          "adId",
          "role",
          "status",
          "method",
          "asset",
          "fiatCents",
          "amountWei",
          "feeWei",
          "priceUsd",
          "buyerWallet",
          "sellerWallet",
          "payee",
          "giftCard",
          "escrowRouteId",
          "escrowSource",
          "escrowDeadline",
          "payDeadline",
          "paidAt",
          "paymentNote",
          "outcome",
          "disputeReason",
          "buyer",
          "seller",
          "legs",
          "escrowFundedWei",
          "deposit",
          "createdAt",
          "updatedAt",
          "completedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "adId": {
            "type": "string",
            "format": "uuid"
          },
          "role": {
            "type": "string",
            "enum": [
              "buyer",
              "seller"
            ],
            "description": "Your side of the trade."
          },
          "status": {
            "$ref": "#/components/schemas/TradeStatus"
          },
          "method": {
            "type": "string",
            "description": "Payment method id."
          },
          "asset": {
            "$ref": "#/components/schemas/Asset"
          },
          "fiatCents": {
            "$ref": "#/components/schemas/Cents"
          },
          "amountWei": {
            "$ref": "#/components/schemas/Wei",
            "description": "What the buyer receives, in the asset's base units."
          },
          "feeWei": {
            "$ref": "#/components/schemas/Wei"
          },
          "priceUsd": {
            "type": "number",
            "description": "Price per ETH in USD."
          },
          "buyerWallet": {
            "type": "string"
          },
          "sellerWallet": {
            "type": [
              "string",
              "null"
            ]
          },
          "payee": {
            "type": [
              "string",
              "null"
            ],
            "description": "Where the buyer sends the money; null for the buyer until the ETH is locked."
          },
          "giftCard": {
            "type": "boolean",
            "description": "Gift-card methods: the code goes in the trade chat."
          },
          "escrowRouteId": {
            "type": "string",
            "pattern": "^0x[0-9a-fA-F]{64}$"
          },
          "escrowSource": {
            "type": "string",
            "enum": [
              "ad",
              "trade"
            ],
            "description": "`ad`: locked from a sell ad's escrow. `trade`: the seller locks it for this trade (trades on buy ads)."
          },
          "escrowDeadline": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "payDeadline": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "paidAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "paymentNote": {
            "type": [
              "string",
              "null"
            ]
          },
          "outcome": {
            "type": [
              "string",
              "null"
            ]
          },
          "disputeReason": {
            "type": [
              "string",
              "null"
            ]
          },
          "buyer": {
            "$ref": "#/components/schemas/Trader"
          },
          "seller": {
            "$ref": "#/components/schemas/Trader"
          },
          "legs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Leg"
            },
            "description": "On-chain payouts: the release to the buyer, the fee, or a refund."
          },
          "escrowFundedWei": {
            "description": "awaiting_escrow: what the trade's route holds so far.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Wei"
              },
              {
                "type": "null"
              }
            ]
          },
          "deposit": {
            "description": "What the seller sends to lock the asset (buy-ad trades, while awaiting escrow).",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Deposit"
              },
              {
                "$ref": "#/components/schemas/SolDeposit"
              },
              {
                "type": "null"
              }
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "completedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "TradeSummary": {
        "type": "object",
        "required": [
          "id",
          "adId",
          "role",
          "status",
          "method",
          "asset",
          "fiatCents",
          "amountWei",
          "counterparty",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "adId": {
            "type": "string",
            "format": "uuid"
          },
          "role": {
            "type": "string",
            "enum": [
              "buyer",
              "seller"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/TradeStatus"
          },
          "method": {
            "type": "string"
          },
          "asset": {
            "$ref": "#/components/schemas/Asset"
          },
          "fiatCents": {
            "$ref": "#/components/schemas/Cents"
          },
          "amountWei": {
            "$ref": "#/components/schemas/Wei"
          },
          "counterparty": {
            "type": "object",
            "required": [
              "handle",
              "avatarUrl"
            ],
            "properties": {
              "handle": {
                "type": "string"
              },
              "avatarUrl": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uri"
              }
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Message": {
        "type": "object",
        "required": [
          "id",
          "from",
          "mine",
          "body",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "from": {
            "type": "string",
            "enum": [
              "buyer",
              "seller",
              "settle"
            ],
            "description": "`settle`: system messages and the Settle team."
          },
          "mine": {
            "type": "boolean"
          },
          "body": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "EventType": {
        "type": "string",
        "enum": [
          "trade.opened",
          "trade.escrowed",
          "trade.paid",
          "trade.releasing",
          "trade.completed",
          "trade.disputed",
          "trade.cancelled",
          "trade.message",
          "ping"
        ],
        "description": "`trade.opened`: a trade was opened on your ad, or by you. `trade.escrowed`: the ETH is locked: the buyer can pay. `trade.paid`: the buyer marked the payment as sent (seller: check it). `trade.releasing`, `trade.completed` (the ETH reached the buyer), `trade.disputed`, `trade.cancelled`. `trade.message`: a new chat message, yours included (check `message.mine`). `ping`: webhook test only."
      },
      "Event": {
        "type": "object",
        "required": [
          "id",
          "type",
          "createdAt",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^([0-9]+|ping_[0-9]+)$",
            "description": "Increasing decimal id (the `after` cursor of GET /events); `ping_<ms>` for a webhook test.",
            "example": "1042"
          },
          "type": {
            "$ref": "#/components/schemas/EventType"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "type": "object",
            "properties": {
              "trade": {
                "$ref": "#/components/schemas/TradeSummary",
                "description": "Every trade.* event: the trade as it was when the event was recorded (`status` included). Absent on `ping`."
              },
              "message": {
                "$ref": "#/components/schemas/Message",
                "description": "`trade.message` only."
              },
              "handle": {
                "type": "string",
                "description": "`ping` only: your handle."
              }
            }
          }
        }
      },
      "Config": {
        "type": "object",
        "required": [
          "chainId",
          "vault",
          "explorerUrl",
          "feeBps",
          "minTradeCents",
          "maxTradeCents",
          "paymentWindows",
          "escrowWindowMin",
          "tokenVault",
          "assets",
          "solanaProgram"
        ],
        "properties": {
          "chainId": {
            "type": "integer",
            "const": 4663
          },
          "vault": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^0x[0-9a-fA-F]{40}$",
            "description": "The escrow vault: the only `to` a deposit may have (null if this deployment has none)."
          },
          "explorerUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Block explorer root: `<explorerUrl>/tx/<hash>`."
          },
          "feeBps": {
            "type": "integer",
            "minimum": 0
          },
          "minTradeCents": {
            "type": "integer",
            "minimum": 1
          },
          "maxTradeCents": {
            "type": "integer",
            "minimum": 1
          },
          "paymentWindows": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "example": [
              15,
              30,
              45,
              60
            ]
          },
          "escrowWindowMin": {
            "type": "integer",
            "minimum": 1,
            "description": "Minutes a seller has to lock the asset of a trade on a buy ad."
          },
          "tokenVault": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^0x[0-9a-fA-F]{40}$",
            "description": "The token vault holding USDG escrow: the only `to` a USDG deposit may have (null until deployed)."
          },
          "assets": {
            "type": "array",
            "description": "Assets live on this deployment.",
            "items": {
              "type": "object",
              "required": [
                "id",
                "symbol",
                "decimals",
                "stable",
                "native",
                "token"
              ],
              "properties": {
                "id": {
                  "$ref": "#/components/schemas/Asset"
                },
                "symbol": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "decimals": {
                  "type": "integer"
                },
                "stable": {
                  "type": "boolean",
                  "description": "Pegged to the dollar: priced at $1."
                },
                "native": {
                  "type": "boolean",
                  "description": "The chain's coin (no token contract, no approval)."
                },
                "token": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "pattern": "^0x[0-9a-fA-F]{40}$"
                },
                "chain": {
                  "type": "string",
                  "enum": [
                    "robinhood",
                    "solana"
                  ]
                }
              }
            }
          },
          "solanaProgram": {
            "type": [
              "string",
              "null"
            ],
            "description": "Settle's escrow program on Solana (null until SOL is live)."
          }
        }
      },
      "Method": {
        "type": "object",
        "required": [
          "id",
          "label",
          "category",
          "region",
          "payee"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "paypal"
          },
          "label": {
            "type": "string",
            "example": "PayPal"
          },
          "category": {
            "type": "string",
            "enum": [
              "apps",
              "banks",
              "giftcards"
            ]
          },
          "region": {
            "type": "string",
            "example": "Global"
          },
          "payee": {
            "type": [
              "object",
              "null"
            ],
            "required": [
              "label",
              "placeholder"
            ],
            "properties": {
              "label": {
                "type": "string"
              },
              "placeholder": {
                "type": "string"
              }
            },
            "description": "What a seller saves to get paid by this method."
          }
        }
      },
      "Me": {
        "type": "object",
        "required": [
          "user",
          "wallet",
          "paymentAccounts",
          "key"
        ],
        "properties": {
          "user": {
            "type": "object",
            "required": [
              "id",
              "handle",
              "name",
              "verified"
            ],
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "handle": {
                "type": "string"
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "verified": {
                "type": "boolean"
              }
            }
          },
          "wallet": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your saved wallet: where bought ETH and withdrawals go. Set on the site only."
          },
          "paymentAccounts": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "method",
                "details"
              ],
              "properties": {
                "method": {
                  "type": "string"
                },
                "details": {
                  "type": "string",
                  "description": "The payee saved for this method."
                }
              }
            },
            "description": "Your saved payees. Set on the site only."
          },
          "key": {
            "type": "object",
            "required": [
              "id",
              "name",
              "scopes"
            ],
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^[a-z0-9]{12}$"
              },
              "name": {
                "type": "string"
              },
              "scopes": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "read",
                    "trade",
                    "release"
                  ]
                }
              }
            }
          }
        }
      },
      "CreateAd": {
        "type": "object",
        "required": [
          "side",
          "priceType",
          "minCents",
          "maxCents",
          "methods",
          "paymentWindowMin"
        ],
        "additionalProperties": false,
        "properties": {
          "side": {
            "type": "string",
            "enum": [
              "sell",
              "buy"
            ]
          },
          "asset": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Asset"
              }
            ],
            "default": "ETH"
          },
          "priceType": {
            "type": "string",
            "enum": [
              "market",
              "fixed"
            ]
          },
          "marginBps": {
            "type": "integer",
            "minimum": -2000,
            "maximum": 2000,
            "default": 0,
            "description": "Market ads."
          },
          "fixedPriceUsd": {
            "type": "number",
            "exclusiveMinimum": 0,
            "description": "Fixed ads: price per whole unit of the asset in USD."
          },
          "minCents": {
            "type": "integer",
            "minimum": 1
          },
          "maxCents": {
            "type": "integer",
            "minimum": 1
          },
          "methods": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string"
            },
            "description": "Payment method ids. Sell ads need a payee saved for each."
          },
          "paymentWindowMin": {
            "type": "integer",
            "enum": [
              15,
              30,
              45,
              60
            ]
          },
          "terms": {
            "type": "string",
            "maxLength": 1000
          }
        }
      },
      "Asset": {
        "type": "string",
        "enum": [
          "ETH",
          "USDG",
          "SOL"
        ],
        "description": "What is traded: ETH or USDG (6 decimals, priced at $1) on Robinhood Chain, or SOL (9 decimals) on Solana."
      },
      "SolDeposit": {
        "type": "object",
        "required": [
          "chain",
          "to",
          "amount",
          "routeId",
          "uri"
        ],
        "description": "SOL: a plain transfer of `amount` lamports to `to`, the route's own escrow address on Solana, from any wallet or exchange. An empty address's first deposit includes the 0.00089088 SOL reserve Solana requires it to keep (it comes back when the escrow is emptied).",
        "properties": {
          "chain": {
            "type": "string",
            "const": "solana"
          },
          "to": {
            "type": "string",
            "description": "The escrow address (a PDA of Settle's program, seeds [\"route\", routeId])."
          },
          "amount": {
            "$ref": "#/components/schemas/Wei"
          },
          "routeId": {
            "type": "string",
            "pattern": "^0x[0-9a-fA-F]{64}$"
          },
          "uri": {
            "type": "string",
            "description": "A Solana Pay link with the address and amount filled in."
          }
        }
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Same key (per API key) and same method, path and body within 24 h: the first answer is replayed (same status and body) with `Idempotent-Replayed: true`. Same key with another request: 409 `idempotency_conflict`. A request still running under that key: 409 `conflict` (retry later). The SDK always sends one.",
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_.:-]{1,100}$"
        },
        "example": "order_1042"
      },
      "AdId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Ad id.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "TradeId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Trade id.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      }
    },
    "headers": {
      "RetryAfter": {
        "description": "Seconds to wait.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      },
      "IdempotentReplayed": {
        "description": "`true` when this is the replay of an earlier answer to the same Idempotency-Key.",
        "schema": {
          "type": "string",
          "const": "true"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "`bad_request`: validation or a business rule (the message says which).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "`missing_api_key`, `invalid_api_key`, `revoked_api_key`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "`insufficient_scope` (the key lacks the scope), `browser_not_allowed` (a key with a browser `Origin` or `Sec-Fetch-Site` header), `forbidden`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "`not_found` (or not yours).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Conflict": {
        "description": "`idempotency_conflict` (same Idempotency-Key, another request), or `conflict` (a request under that key is still running, or the state changed: retry later).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "PayloadTooLarge": {
        "description": "`body_too_large`: bodies are capped at 16 KB.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "UnsupportedMediaType": {
        "description": "`unsupported_media_type`: send `Content-Type: application/json`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "`rate_limited`: 60 requests a minute per key (best effort), 300 per IP.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        }
      },
      "InternalError": {
        "description": "`internal_error`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unavailable": {
        "description": "`unavailable`: the price feed or the chain RPC is down. Retry.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}
