# Market trades

Use `POST /v1/trades/execute` for the normal one-request flow. It creates a fresh market quote and immediately submits it for asynchronous execution. Use the separate quote and submit endpoints when your service must inspect the route before committing.

## Execute a trade

Use the selected wallet, network key, side, token address, and raw input amount. Buy amounts are denominated in the network settlement token. Sell amounts are denominated in the selected asset. Read decimals from [Chains and tokens](/docs/chains-and-tokens). The example spends 25 units of Base's six-decimal settlement token.

`slippagePercentage: "1"` means one percent. Omit `recipient` to keep the output in the selected StarSwap wallet. An explicit recipient changes where the trade sends its output.

~~~typescript POST /v1/trades/execute
const tradeResponse = await fetch(
  "https://starswap.cc/api/v1/trades/execute",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.STARSWAP_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify({
      walletId: "wlt_example",
      side: "buy",
      chain: "base",
      token: "0xTokenAddress",
      amountRaw: "25000000",
      slippagePercentage: "1",
    }),
  },
);

const trade = await tradeResponse.json();
~~~

The same `Idempotency-Key` identifies the internal quote and trade, so retry the request with that key when the response is interrupted. Persist the key and body before sending them. The API returns HTTP `202` with the accepted trade record without waiting for onchain confirmation. Check `tradeResponse.ok` before treating its JSON body as a trade.

Poll `GET /v1/trades/:tradeId` until `state` becomes `confirmed` or `failed`. A submitted trade includes `broadcastAt` once signed-transaction dispatch is recorded. It may enter `awaiting_ticket_refund` while unused settlement value is returned.

For Solana, use `chain: "solana"` and preserve mint address casing. The API accepts routable SPL and Token-2022 mints. Use `solana:native` for SOL. Solana buys fund custody and execute the route atomically. Solana sells execute into custody USDC and deposit the guaranteed minimum into the vault in the same transaction.

## Inspect a quote before trading

Request a short-lived quote first when your service needs to check the assets, minimum output, recipient, fees, or expiry before submission.

~~~typescript POST /v1/trade-quotes
const quoteResponse = await fetch(
  "https://starswap.cc/api/v1/trade-quotes",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.STARSWAP_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify({
      walletId: "wlt_example",
      side: "buy",
      chain: "base",
      token: "0xTokenAddress",
      amountRaw: "25000000",
      slippagePercentage: "1",
    }),
  },
);

const quote = await quoteResponse.json();
~~~

Quotes remain valid for up to 30 seconds. Check `tokenIn`, `tokenOut`, `amountInRaw`, `minimumAmountOutRaw`, `recipient`, `routeFeePercentage`, `vaultFeeMicros`, `gasReserveMicros`, and `expiresAt` before submission. These fields distinguish route fees, platform fees, and the gas reservation. A reservation is not the final gas charge.

The public quote is a summary for review. StarSwap stores and validates the execution instructions internally. Submit the returned quote ID; clients do not construct or sign the trade transaction.

### Submit the inspected quote

~~~typescript POST /v1/trades
const tradeResponse = await fetch(
  "https://starswap.cc/api/v1/trades",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.STARSWAP_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify({ quoteId: quote.id }),
  },
);

const trade = await tradeResponse.json();
~~~

Submit the quote before its `expiresAt` value. Quote creation and submission are separate mutations, so give each request its own `Idempotency-Key` and preserve that key when retrying the same mutation.

Submission also returns HTTP `202`. If submission is unresolved, recover that operation before creating another quote or using a new submission key. Expiry alone does not prove that an earlier submission failed.

## Trade multiple wallets

`POST /v1/trades/execute-batch` accepts a `trades` array with 1 to 30 entries. Each entry uses the same fields as one-request execution, with an optional pre-created `quoteId`. A wallet may appear only once. The response is HTTP `202` with an `outcomes` array. Each outcome has a `walletId` and either a `trade` or an `error`.

Admission can succeed for some wallets and fail for others. Follow every accepted trade independently. For a retry of an interrupted batch, preserve the entire array, its order, and the original idempotency key. Do not submit accepted entries again with new keys.

`POST /v1/trades/execute-clip` is a separate coordinated EVM sell flow for 1 to 30 wallets holding one token on one network. Its `trades` entries omit `side`; they are sells. It returns HTTP `202` with a `trades` array. This is distinct from sniper execution, where each wallet uses its own transaction.

`POST /v1/trade-routes/preview` returns a buy-route estimate without an executable quote ID. Use a fresh quote or one-request execution to trade. See [OpenAPI](/openapi.json) for all three request shapes.

## Read execution results

Use `settledAmountOutRaw` and `netProceedsRaw` when present on confirmed trades, rather than quoted output. Confirmed sell `pnlUSD` includes fees and gas. `gasReservedMicros` is the reservation; `gasChargedMicros` is the actual charge.

`marketCapUSD` can describe a quote, attempt, entry, or exit. Inspect `marketCapMoment` before presenting it as an execution value, and use `marketCapTimestamp` for its observation time. A quote-time market cap is not a verified exit market cap.

## List wallet activity

Pass a wallet ID to list only that wallet's trades. Results are returned newest first and support cursor pagination.

~~~typescript GET /v1/trades?walletId=wlt_example&limit=20
const activityResponse = await fetch(
  "https://starswap.cc/api/v1/trades?walletId=wlt_example&limit=20",
  {
    headers: {
      Authorization: `Bearer ${process.env.STARSWAP_API_KEY}`,
    },
  },
);

const activity = await activityResponse.json();
~~~

## Trade states

| State | Meaning |
| --- | --- |
| `queued` | Execution is waiting for the relayer |
| `submitted` | The transaction is signed; `broadcastAt` records when broadcast dispatch began |
| `confirmed` | The transaction settled successfully |
| `failed` | Validation or onchain execution failed |
| `awaiting_ticket_refund` | Remaining settlement value is being returned |
