> ## Documentation Index
> Fetch the complete documentation index at: https://turnkey-0e7c1f5b-iframe-stamper-docs-update.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Track Swap Status

> Poll a swap from execute acceptance to settlement with get_swap_status. Same-chain and cross-chain swaps normalize to a single PENDING / COMPLETED / FAILED model.

`ACTIVITY_TYPE_EXECUTE_SWAP_V2` returns a `swapRequestId`. Query `get_swap_status` with it to observe the full lifecycle — including failures that occur before broadcast, such as pre-flight simulation failures. Same-chain and cross-chain swaps share the same query and the same response shape; provider-specific state machines are normalized to three states: `PENDING`, `COMPLETED`, `FAILED`.

<Note>
  Swaps is currently an Early Access Product. [Contact us](https://www.turnkey.com/contact-us) to enable it for your organization.
</Note>

## Lifecycle model

Turnkey normalizes swap lifecycle to three states across same-chain and cross-chain routes:

* **PENDING**: still in flight. Broadcast pending, origin transaction not yet included, or (cross-chain) destination-side execution not yet settled.
* **COMPLETED**: the user received the destination asset. Terminal, happy path.
* **FAILED**: the swap will not fill as intended. Reported only when Turnkey knows what the user holds. Terminal.

Intermediate provider states (`bridge_pending`, `delayed`, `submitted`, and so on) collapse into `PENDING` on purpose. Every state maps to exactly one customer action: `PENDING` means wait, `COMPLETED` means you got the output, `FAILED` means look at what you hold and consider re-swapping.

## Query get\_swap\_status

Query [`get_swap_status`](/api-reference/queries/get-swap-status) with:

<ParamField body="organizationId" type="string" required>
  The organization that executed the swap: the same organization the execute activity was submitted against, parent or sub-organization.
</ParamField>

<ParamField body="swapRequestId" type="string" required>
  The handle returned by [`ACTIVITY_TYPE_EXECUTE_SWAP_V2`](/features/transaction-management/swap/execute-swap), e.g. `sha256:9a80031c2def...`.
</ParamField>

cURL:

```bash title="cURL" theme={null}
curl --request POST \
  --url https://api.turnkey.com/public/v1/query/get_swap_status \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header "X-Stamp: <string> (see Stamps)" \
  --data '{
    "organizationId": "<ORGANIZATION_ID>",
    "swapRequestId": "<SWAP_REQUEST_ID>"
  }'
```

JavaScript:

```javascript title="JavaScript" theme={null}
const status = await client.request("/public/v1/query/get_swap_status", {
  organizationId: "<ORGANIZATION_ID>",
  swapRequestId: "<SWAP_REQUEST_ID>",
});
```

Response:

```json theme={null}
{
  "status": "PENDING | COMPLETED | FAILED",
  "swapKind": "SAME_CHAIN | CROSS_CHAIN",
  "provider": "<PROVIDER>",
  "inputToken": "<CAIP-19>",
  "outputToken": "<CAIP-19>",
  "inputAmount": "<RAW_AMOUNT>",
  "originTxHash": "<ORIGIN_TX_HASH>",
  "destinationTxHashes": ["<TX_HASH_ON_COMPLETED_CROSS_CHAIN_ONLY>"],
  "outputAmount": "<ACTUAL_OUTPUT_ON_COMPLETED>",
  "refund": {
    "asset": "<CAIP-19_ON_FAILED>",
    "amount": "<RAW_AMOUNT_ON_FAILED>",
    "txHash": "<TX_HASH_ON_FAILED>"
  },
  "error": {
    "reason": "<ORIGIN_TRANSACTION_FAILED | PROVIDER_FILL_FAILED>",
    "message": "<HUMAN_READABLE_DETAIL>",
    "originTxError": {
      "message": "<REVERT_MESSAGE>",
      "revertChain": [],
      "eth": {},
      "solana": {}
    },
    "providerReason": "<PROVIDER_SPECIFIC_REASON>"
  },
  "updatedAt": "<UNIX_MS_TIMESTAMP>"
}
```

### Response fields

* `status`: normalized state. `PENDING`, `COMPLETED`, or `FAILED`.
* `swapKind`: `SAME_CHAIN` or `CROSS_CHAIN`. Set at execute time; does not change.
* `provider`: the provider that executed the swap. Present when known.
* `inputToken`, `outputToken`, `inputAmount`: echoed from the execute intent.
* `originTxHash`: origin-chain transaction hash. Present once the swap is broadcast, for both same-chain and cross-chain routes.
* `destinationTxHashes`: array of destination-chain transaction hashes on `COMPLETED`. Cross-chain only.
* `outputAmount`: actual amount received, on `COMPLETED`. May lag the `status` transition by seconds while the monitor fetches the final settled amount.
* `refund`: present on `FAILED` when funds moved and came back. Contains `asset` (CAIP-19), `amount` (raw onchain units), and `txHash`. See [What FAILED means](#what-failed-means).
* `error`: present on `FAILED`. Contains `reason` (`ORIGIN_TRANSACTION_FAILED` or `PROVIDER_FILL_FAILED`), `message` (human-readable detail), `originTxError` (decoded revert detail, origin failures only), and `providerReason` (provider-specific detail, fill failures only). See [What FAILED means](#what-failed-means).
* `updatedAt`: last observed state change, as a Unix timestamp in milliseconds (stringified).

## Same-chain vs. cross-chain differences

The response shape is identical. Two behaviors differ in practice:

* **Timing.** Same-chain swaps reach a terminal state within roughly one block time of the origin chain. Cross-chain swaps can take tens of seconds to several minutes depending on the route. Each quote's `estimatedTimeSeconds` is the per-swap estimate.
* **Field population.** `destinationTxHashes` is populated only for cross-chain `COMPLETED` swaps. Same-chain outcomes are fully described by `originTxHash`: on `COMPLETED`, that transaction delivered the output; on `FAILED`, either the transaction reverted or — if `originTxHash` is absent — the swap failed before broadcast and nothing moved onchain.

`swapKind` (`SAME_CHAIN` or `CROSS_CHAIN`) tells you which model applies. Branch on it client-side only where the difference matters — for example, showing a bridge-progress state for cross-chain `PENDING` — and otherwise treat both kinds uniformly through the three-state model.

## What FAILED means

`FAILED` is set as soon as Relay reports a failure. Refund details (`asset`, `amount`, `txHash`) are populated in a subsequent enrichment pass and may be absent when `FAILED` first appears. Keep polling if you need the refund details. `PENDING` means the destination leg may still fill — it does not indicate a refund is in flight.

On `FAILED`, two fields together describe the outcome:

* `error.reason` — why it failed: `ORIGIN_TRANSACTION_FAILED` (the origin transaction failed pre-flight simulation or reverted onchain) or `PROVIDER_FILL_FAILED` (the origin transaction succeeded but the provider could not fill). `error.message` and, for origin failures, `error.originTxError` carry the decoded detail, including the full revert chain.
* `refund` — present when funds moved and came back: `refund.asset` (CAIP-19), `refund.amount` (raw onchain units), and `refund.txHash`. The refunded asset can differ from the original input if the route included an origin-side swap, and it lands on the origin chain.

Reading the user's position from the response:

| `error.reason`              | `originTxHash` | `refund` | The user holds                                                                                              |
| :-------------------------- | :------------- | :------- | :---------------------------------------------------------------------------------------------------------- |
| `ORIGIN_TRANSACTION_FAILED` | absent         | absent   | The full input — the swap failed simulation and never broadcast.                                            |
| `ORIGIN_TRANSACTION_FAILED` | present        | absent   | The full input — the transaction reverted onchain. Gas was spent (yours, if sponsored).                     |
| `PROVIDER_FILL_FAILED`      | present        | present  | `refund.amount` of `refund.asset`, on the origin chain.                                                     |
| `PROVIDER_FILL_FAILED`      | present        | absent   | Unknown — refund is still being enriched, or Relay reported failure with no automated return. Keep polling. |

If the user still wants the swap, re-quote — with the refunded asset as the new input where a refund occurred. Caveats worth surfacing to end users:

* A refund is reduced by refund gas and any origin-side swap losses; it will not equal the original input.
* A re-swap is a new swap: new quote, new fees, new slippage.
* If the original destination was another chain, the re-swap is again cross-chain.

<Warning>
  `FAILED` with error reason `PROVIDER_FILL_FAILED` and no `refund` object means Turnkey could not recover funds through the provider's automated flows. Contact support if you encounter this state.
</Warning>

## Polling cadence

* **Same-chain**: poll every \~1 second while `PENDING`. Typically settles within one block time.
* **Cross-chain**: poll every 5 to 10 seconds while `PENDING`. Settlement can take from tens of seconds to several minutes depending on route.

Websocket and event-driven updates are on the roadmap and will replace polling for cross-chain lifecycles.

## Next steps

* [End-to-end example](/features/transaction-management/swap/end-to-end-example): full flow from enable to confirmation.
* [Execute a swap](/features/transaction-management/swap/execute-swap): request semantics that generate the poll handle.
