> ## Documentation Index
> Fetch the complete documentation index at: https://docs.swaps.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Track Transactions

> Monitor the status of transactions and trigger indexing for alt VM transactions.

export const Callout = ({type = 'info', children}) => {
  const borderColor = ({
    info: '#007acc',
    warning: '#FFC263',
    danger: '#d9534f',
    success: '#00C256'
  })[type] || '#ccc';
  const bgColor = ({
    info: '#f3f9ff',
    warning: '#FFF2DE',
    danger: '#f7f2f1',
    note: '#f8f8f8',
    tip: '#f1f1f8',
    success: '#E0FFEE'
  })[type] || '#f3f9ff';
  return <div style={{
    borderLeft: `4px solid ${borderColor}`,
    backgroundColor: bgColor,
    padding: '0.5rem',
    borderRadius: '12px',
    margin: '1rem 0',
    fontSize: '14px'
  }}>
      {children}
    </div>;
};

Swaps provides a status endpoint you can use to track your transactions. The endpoint provides status updates and key transaction data for any transaction type. Key transaction data includes the USD value of the transaction, transaction fees, execution path, and other useful on-chain information.

For transactions originating on alt VMs (e.g., Bitcoin, Ripple), you will need to register your transaction by submitting a `POST` request containing the transaction's `txHash`.

## Get status

**API Reference:** [Get Status](/swap-api-reference/get-status)

The status endpoint supports three query parameters:

| Parameter | Description                                                         |
| :-------- | :------------------------------------------------------------------ |
| `chainId` | Source chain ID of the transaction                                  |
| `txHash`  | Source or destination transaction hash                              |
| `txId`    | Unique identifier applied to each transaction by the Swaps protocol |

We recommend using the source chain ID and the transaction hash. The example below assumes this approach.

The status endpoint will return a [`TxDetails` object](/swap-api-reference/get-status#response-status-message).

```typescript theme={null}
async function getStatus(
  srcChainId: ChainId,
  srcTxHash: string
): Promise<TxDetails> {
  const url = `https://ghost.swaps.xyz/api/v2/getStatus?chainId=${srcChainId}&txHash=${srcTxHash}`;
  const options = {
    method: "GET",
    headers: { "x-api-key": SWAPS_API_KEY },
  };

  const response = await fetch(url, options);
  const txDetails = await response.json();
}
```

<Callout type="info">
  **If you would prefer to use webhooks, please reference the [webhook
  documentation](/guides/track-transactions#webhooks) below.**
</Callout>

## Register transaction

**API Reference:** [Register Transaction](/swap-api-reference/register-transaction)

Registering a transaction triggers indexing after it is broadcasted on the source chain.

This is required for any transactions that return an `alt-vm-*` bridge ID in the [Action Response](/swap-api-reference/get-action). The Action Response also includes a `requiresRegisterTx` flag. This is covered in the [alt VM broadcast guide](/guides/swap#broadcast-on-altvm). Swaps will automatically register any transaction submitted to a named VM. If you believe we have missed a transaction, calling the register transaction endpoint will trigger indexing.

This endpoint does support registering multiple transactions in a single call.

| Parameter | Description                                      |
| :-------- | :----------------------------------------------- |
| `txId`    | The **transaction ID** from the action response. |
| `txHash`  | The **transaction hash** from the source chain.  |

```typescript theme={null}
async function registerTx(
  txId: string,
  srcTxHash: string
): Promise<{ success: true; error: string | null }> {
  const url = "https://api-v2.swaps.xyz/api/registerTxs";
  const options = {
    method: "POST",
    headers: {
      "x-api-key": SWAPS_API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      txId,
      txHash: srcTxHash
    }),
  };

  const response = await fetch(url, options);
  const data = await response.json();
}
```

## Webhooks

Swaps can emit webhooks on transaction creation and completion (success or failure) events. To use webhooks, please register a webhook URL in the developer console. Webhook URLs should correspond to a certain API key -- each API key represents a unique `appId`. Each `appId` can have its own webhook URL.

<Callout type="warning">
  🚧 The Console does not yet support webhook URL registration. 🚧 Please
  contact the Swaps team to register a URL.
</Callout>

Swaps' webhooks are sent with a `x-signature-256` header that hashes the raw request body and delivery timestamp. This signature ensures that neither the request body nor the timestamp were modified and can be trusted as sent from Swaps.

The webhook body mirrors the [`TxDetails` object](/swap-api-reference/get-status#response-status-message) returned from the `/getStatus` endpoint. The schema is:

```typescript theme={null}
type WebhookBody = {
  event: "created" | "updated"; // "updated" is emitted on tx completion
  txStatus: StatusDetails;
  timestamp: number;
};
```

To verify the webhook signature, hash the payload with your webhook secret using SHA256 and confirm that the timestamp is within an expected buffer. Please see a reference implementation below:

```typescript theme={null}
function verifyWebhook(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac("sha256", secret)
    .update(payload)
    .digest("hex");

  const receivedSignature = signature.replace("sha256=", "");

  // Use constant-time comparison
  const sigBuffer = Buffer.from(receivedSignature, "hex");
  const expectedBuffer = Buffer.from(expectedSignature, "hex");

  if (sigBuffer.length !== expectedBuffer.length) {
    return false;
  }

  return crypto.timingSafeEqual(sigBuffer, expectedBuffer);
}

// Sample usage in Express handler
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  const signature = req.headers["x-signature-256"];
  const payload = req.body.toString();

  if (!verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send("Invalid signature");
  }

  // Process webhook...
  res.status(200).send("OK");
});
```
