# GET /route/outcome

> GET /route/outcome of the Intear DEX Aggregator: what a route's transactions spent and received, why a swap failed, and what's left to move.

This page is part of the DEX Aggregator docs. The aggregator is at `https://router.intear.tech`, with live quotes at `wss://router.intear.tech/route/subscribe`, on NEAR mainnet only. https://docs.intear.tech/dex-aggregator/llms-full.txt has all of its pages in one file, and https://docs.intear.tech/llms.txt lists every page of the Intear docs.

```
GET https://router.intear.tech/route/outcome
```

Once the trader has sent a route's transactions, this tells you what they did: how much of the input they spent, how much of the output they received, and why the swap failed if it did. It waits for the transactions to execute, so you can call it right after sending them. With `wait_until=swap`, it [answers as soon as the swap executed](#answering-at-the-swap), before the output reaches the trader.

It also returns `next_steps`: transactions that move tokens which ended up somewhere other than `token_in` or `token_out` to where they belong. Examples are the wNEAR left over when a swap from NEAR fails, or the output of a route whose [`token_output`](https://docs.intear.tech/dex-aggregator/guides/tokens.md#when-token_output-differs) isn't the `token_out` you asked for.

See [Checking the outcome](https://docs.intear.tech/dex-aggregator/guides/executing-routes.md#checking-the-outcome) for how it fits in a swap.

## Example

```
https://router.intear.tech/route/outcome?token_in=near&token_out=nep141:usdt.tether-token.near&trader_account_id=alice.near&tx_hashes=9FtHUFBQsZ2MG77K3x3MJ9wjX3UT8zE1TczCrhZEcG8U,4mSbD8V5E3kCdNghTnzVh7fhCwuC2wB6K9a5xbdZvR3P
```

## Query parameters

### Required

| Parameter | Type | Description |
| --- | --- | --- |
| `token_in` | [token ID](https://docs.intear.tech/dex-aggregator/guides/tokens.md#token-id-format) | The `token_in` of the route request |
| `token_out` | [token ID](https://docs.intear.tech/dex-aggregator/guides/tokens.md#token-id-format) | The `token_out` of the route request. Must be different from `token_in` |
| `trader_account_id` | account ID | The account that signed the transactions |
| `tx_hashes` | comma-separated list | Hashes of the route's transactions, without its [fee transactions](https://docs.intear.tech/dex-aggregator/guides/executing-routes.md#fee-transactions). 1 to 20 of them, each once, all signed by `trader_account_id` |

### Optional

| Parameter | Type | Description |
| --- | --- | --- |
| `fee_amount` | integer string | The quote's [`fee_amount`](https://docs.intear.tech/dex-aggregator/reference/quote.md), so that `next_steps` leave it in the wallet for the fee transactions. Defaults to `0` |
| `wait_until` | string | When to answer: `executed`, the default, once every transaction and receipt executed, with the balances compared; or `swap`, [as soon as the swap executed](#answering-at-the-swap) |
| `key` | string | API key, to lift the [rate limit](https://docs.intear.tech/dex-aggregator/reference/errors.md#rate-limits) |

## Response

`200 OK` with `Content-Type: application/json`:

```json
{
  "charge_fee": true,
  "amount_in": "1000000000000000000000000",
  "amount_out": "4880007",
  "balance_changes": [
    { "token": "near", "change": "-1000000000000000000000000" },
    { "token": "nep141:usdt.tether-token.near", "change": "4880007" }
  ],
  "next_steps": [],
  "error": null,
  "settled": true
}
```

| Field | Type | Description |
| --- | --- | --- |
| `charge_fee` | boolean | Whether the swap went through: `true` if the trader received any of the output. Send the route's fee transactions only if it's `true` |
| `amount_in` | string | How much of the input the transactions spent, wherever it was held. For NEAR, gas and storage deposits don't count. What the fee transactions pay isn't included, since they haven't been sent yet. Fees paid in the swap's own transaction are: Plach's referral fees, which Intear DEX takes in the swap, and the fees of a Rhea swap between Rhea balances (`rhea-nep141:`) |
| `amount_out` | string | How much of the output the transactions gave, wherever it ended up |
| `balance_changes` | array | Each balance of the input and output tokens that changed, as `{ "token", "change" }`: the [token ID](https://docs.intear.tech/dex-aggregator/guides/tokens.md#token-id-format) of the place it's held, and the change, a signed integer string, negative if the balance went down |
| `next_steps` | array | [Execution instructions](https://docs.intear.tech/dex-aggregator/reference/quote.md#execution-instruction) that move what ended up somewhere else to `token_in` or `token_out`. Execute them like a route's, after its fee transactions. Usually empty |
| `error` | string or `null` | Why the swap failed, written to show to the trader. Present when `charge_fee` is `false`, `null` otherwise. See [error messages](#error-messages) |
| `settled` | boolean | Whether every transaction and receipt executed and the balances were compared. `false` only for an [answer at the swap](#answering-at-the-swap), whose `balance_changes` and `next_steps` are empty |

All amounts are strings in the token's smallest unit. Parse them as big integers.

A failed swap from NEAR on Rhea DCL, where `near_deposit` succeeded and the swap refunded the wNEAR, gets a `next_steps` that unwraps it:

```json
{
  "charge_fee": false,
  "amount_in": "0",
  "amount_out": "0",
  "balance_changes": [
    { "token": "near", "change": "-1000000000000000000000000" },
    { "token": "nep141:wrap.near", "change": "1000000000000000000000000" }
  ],
  "next_steps": [
    {
      "NearTransaction": {
        "receiver_id": "wrap.near",
        "actions": [
          {
            "FunctionCall": {
              "method_name": "near_withdraw",
              "args": "eyJhbW91bnQiOiIxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwIn0=",
              "gas": 30000000000000,
              "deposit": "1"
            }
          }
        ],
        "is_fee_transaction": false
      }
    }
  ],
  "error": "The price moved more than your slippage allows while the transaction was on its way. Try again, or increase the slippage.",
  "settled": true
}
```

## How balances are compared

The aggregator waits until every transaction and its receipts have executed, at least optimistically, for up to 60 seconds in total. Then it compares the trader's balances before the block of the first transaction with the balances after the block of the last receipt, in every place a token can be held:

- NEAR: native NEAR, wNEAR in the wallet, on Rhea and on Intear DEX, and NEAR on Intear DEX
- Other tokens: the wallet, the Rhea inner balance (`rhea-nep141:`) and the Intear DEX inner balance (`intear-dex:`)

Native NEAR is added up from the transactions themselves, so gas and storage deposits don't count. The other balances are read at those two blocks, so anything else that changes them in between, like another transaction of the trader, counts too.

`amount_in` and `amount_out` add up the changes of all the places, so moving a token from one place to another, like wrapping NEAR, isn't spending it. For a Wrap route between two places of the same token, they're the changes of `token_in` and `token_out` themselves.

## Answering at the swap

With `wait_until=swap`, the aggregator asks how far the transactions got every 100 ms, and answers as soon as their swaps executed, at least optimistically. It doesn't wait for the output to reach the trader, for callbacks or for gas refunds. A Plach swap that withdraws to the wallet, for example, is answered at the block it swapped in, a block before the tokens arrive and two before the callback.

It reads the trader's swaps from what the DEXes log of them:

- Intear DEX's `swap` events, for Plach
- Rhea DCL's `swap` events
- Rhea's `Swapped <amount> <token> for <amount> <token>` logs

It answers once each transaction has either executed or logged a swap, nothing has failed so far, and the swaps gave some of the output. `amount_in` and `amount_out` are then what the swaps logged, of the tokens in any of their places, and `settled` is `false`. For Plach, the aggregator adds the [referral fees](https://docs.intear.tech/dex-aggregator/guides/referral-fees.md) of Intear DEX's `swap` event to its input, so `amount_in` is the same as with `wait_until=executed`. Rhea logs only what it swapped, so with `fees`, a Rhea swap between Rhea balances has an `amount_in` less than the one of `wait_until=executed` by the fees. `balance_changes` and `next_steps` are empty, since what ends up somewhere else isn't known until everything executed: to move it, ask again with `wait_until=executed` after sending the fee transactions, and execute its `next_steps`.

A swap that failed, a route without a swap, like a Wrap route, and transactions that all executed before their swaps were seen, are answered as with `wait_until=executed`, with `settled: true`.

## Errors

Errors are plain text (`text/plain`), as for [`/route`](https://docs.intear.tech/dex-aggregator/reference/errors.md):

| Status | Message | Cause |
| --- | --- | --- |
| `400` | `tx_hashes must have 1 to 20 transaction hashes` | `tx_hashes` is missing, empty, or has more than 20 hashes |
| `400` | `tx_hashes must not repeat a transaction` | A hash is in `tx_hashes` twice |
| `400` | `Token in and token out must be different` | `token_in` equals `token_out` |
| `400` | `fee_amount is too large` | `fee_amount` doesn't fit a signed 128-bit integer |
| `400` | `Transaction <hash> is signed by <signer>, not <trader>` | A transaction isn't signed by `trader_account_id` |
| `400` | `Failed to deserialize query string: ...` | A parameter is missing or has the wrong format |
| `502` | `Failed to get block <hash>: ...` and others | Reading a transaction, block or balance from the chain failed |
| `504` | `Transaction <hash> didn't execute in 60s: <reason>` | A transaction wasn't found, or didn't finish executing, within 60 seconds. For example, it was never sent |
| `504` | `The transactions didn't execute in 60s: <reason>` | With `wait_until=swap`: a transaction wasn't found, or its swap didn't execute, within 60 seconds |
| `504` | `Reading the balances took more than 20s` | |

A request over the [rate limit](https://docs.intear.tech/dex-aggregator/reference/errors.md#rate-limits) gets `429 Too Many Requests`, and a wrong `key` `401 Unauthorized`, as for `/route`.

### Error messages

When the swap failed, `error` describes the first failure of the transactions that it recognizes:

| `error` | Cause |
| --- | --- |
| `The price moved more than your slippage allows while the transaction was on its way. Try again, or increase the slippage.` | The output was less than the minimum, or the input more than the maximum, on Rhea, Rhea DCL or Plach |
| `The pool doesn't have enough liquidity for this trade. Try a smaller amount.` | A Plach pool doesn't have enough of the output |
| `You don't have enough tokens for this trade.` | The balance of the input is too low |
| `Your account isn't registered for one of the tokens. Try again.` | The trader isn't registered with a token or DEX |
| `Your account doesn't have enough NEAR for storage. Try again.` | The trader's storage deposit on a DEX is too low |
| `The quote expired before the transaction executed. Request a new route and try again.` | The route's [fee discount](https://docs.intear.tech/dex-aggregator/guides/amounts.md#fee-discounts) expired |
| `The transaction ran out of gas. Try again with a smaller amount.` | A receipt ran out of gas |
| `Your account doesn't have enough NEAR left for gas and storage. Deposit some NEAR and try again.` | The trader's NEAR balance is too low for the account's storage |

Other failures are `The swap failed: ` followed by what the contract panicked with, and a swap that gave nothing without failing is `The swap didn't give any tokens`.
