# Quickstart

Every trade is three requests:

1. `POST /quote` prices the trade and returns a quote `id`. A quote can be turned into an order for ten minutes, until its `expires_at`.
2. `POST /order` binds the quote to your recipient address and returns a fresh `deposit_address`.
3. `GET /order/{id}` tracks the order once you send the deposit.

You don't need an API key or a wallet connection. You send `from_amount` of the `from` asset to the order's `deposit_address`, and Rift delivers the output to your `to_address`.

Assets are named `<chain>.<asset>`, for example `ethereum.eth`, `bitcoin.btc` or `base.steakhouseUSDC`. The chain is always spelled out (`ethereum`, not `eth`). The [token list](/docs/integration/token-list) has every registered name.

> Replace the example addresses with your own before you run anything. Rift delivers to exactly the `to_address` you set, and transfers can't be reversed.

## Set up

The examples are JavaScript modules for Node.js 22 or later. They call the Rift API, `https://api.rift.trade`, through two helpers. Save them as `rift.mjs` next to the examples:

```js
const RIFT_API = "https://api.rift.trade";

// POSTs `body` as JSON, or GETs without one, and returns the parsed response.
export async function rift(path, body) {
  const response = await fetch(`${RIFT_API}${path}`, {
    method: body ? "POST" : "GET",
    headers: { "content-type": "application/json" },
    body: body ? JSON.stringify(body) : undefined,
  });
  const text = await response.text();
  if (!response.ok) throw new Error(`${path} failed (${response.status}): ${text}`);
  return JSON.parse(text);
}

// Checks the order every 10 seconds until it settles, logging each new status.
export async function waitForOrder(id) {
  const settled = ["delivered", "refunded", "expired", "frozen"];
  let status;
  while (true) {
    const order = await rift(`/order/${id}`);
    if (order.status !== status) console.log(`Order ${order.status}`);
    if (settled.includes(order.status)) return order;
    status = order.status;
    await new Promise((resolve) => setTimeout(resolve, 10_000));
  }
}
```

The deposits are sent with [viem](https://viem.sh) on EVM chains and Hyperliquid, and with [@scure/btc-signer](https://github.com/paulmillr/scure-btc-signer) on Bitcoin. Install both with `npm install viem @scure/btc-signer`. The paying wallet's key goes in `PRIVATE_KEY` (`0x`-prefixed hex) or, for Bitcoin, `BITCOIN_WIF`. Keep them in a `.env` file and run each script with `node --env-file=.env <script>.mjs`.

The Bitcoin examples pay their deposit with one more helper. It pays from the native SegWit (`bc1q`) wallet in `BITCOIN_WIF`, using the mempool.space API to find the wallet's coins, pick a fee rate and broadcast the transaction. Save it as `bitcoin.mjs`:

```js
import * as btc from "@scure/btc-signer";
import { pubECDSA } from "@scure/btc-signer/utils.js";

// Pays `amount` BTC to `address` in one transaction from the wallet in BITCOIN_WIF.
export async function sendBitcoin(address, amount) {
  const mempool = "https://mempool.space/api";
  const getJson = (path) => fetch(mempool + path).then((res) => res.json());
  const key = btc.WIF().decode(process.env.BITCOIN_WIF);
  const wallet = btc.p2wpkh(pubECDSA(key));
  const coins = await getJson(`/address/${wallet.address}/utxo`);
  const { halfHourFee } = await getJson("/v1/fees/recommended");

  const inputs = coins.map((coin) => ({
    ...wallet,
    txid: coin.txid,
    index: coin.vout,
    witnessUtxo: { script: wallet.script, amount: BigInt(coin.value) },
  }));
  const outputs = [{ address, amount: btc.Decimal.decode(amount) }];
  const payment = btc.selectUTXO(inputs, outputs, "default", {
    changeAddress: wallet.address,
    feePerByte: BigInt(halfHourFee),
    createTx: true,
  });
  if (!payment) throw new Error(`Not enough BTC in ${wallet.address}`);

  payment.tx.sign(key);
  payment.tx.finalize();
  const res = await fetch(`${mempool}/tx`, { method: "POST", body: payment.tx.hex });
  if (!res.ok) throw new Error(`Broadcast failed: ${await res.text()}`);
  return res.text();
}
```

Every example below takes the same four steps, marked `// 1.` to `// 4.` in its code.

### 1. Get a quote

`POST /quote` prices the trade. For 0.5 ETH on Ethereum into Apple stock tokens on Robinhood Chain:

```js
const quote = await rift("/quote", {
  from: "ethereum.eth",
  to: "robinhood.aapl",
  from_amount: "0.5",
  return_full_route: true,
});
```

`quote` holds the response, shown here with its main fields:

```json
{
  "id": "01a0e938-82cb-72c2-9e28-109d455c5267",
  "estimated_amount_out": "3.961555150436755734",
  "expires_at": "2026-09-28T18:23:09.963523Z",
  "route": [
    { "venue": "across", "from": "ethereum.eth", "to": "robinhood.eth" },
    { "venue": "nordstern", "from": "robinhood.eth", "to": "robinhood.aapl" }
  ]
}
```

`estimated_amount_out` is what reaches the recipient after every venue and delivery cost. `route` lists the venue steps, here a bridge to Robinhood Chain followed by a swap into the stock token.

### 2. Create the order

`POST /order` binds the quote to the address that receives the output:

```js
const order = await rift("/order", {
  quote_id: quote.id,
  to_address: "0xYourRobinhoodChainAddress", // receives the AAPL tokens
});
```

```json
{
  "id": "01a0e938-96a9-7d92-a5cb-bab585c2fc47",
  "status": "awaiting_deposit",
  "from_amount": "0.5",
  "deposit_address": "0x5adfc66c5e7158cbfb3b0129a8433c5da6f6382c",
  "deposit_deadline": "2026-10-05T18:13:14.984542Z"
}
```

`to_address` is an address on the `to` asset's chain: a Bitcoin address for `bitcoin.btc`, your Hyperliquid account for a `hyperliquid` asset. An optional `refund_address` on the `from` chain gets the deposit back if the trade fails. Without one, a refund goes back to the address the deposit came from.

### 3. Send the deposit

Send `from_amount` to `deposit_address` in one transfer before `deposit_deadline`, seven days after the order was created. The examples send it from the wallet in `PRIVATE_KEY` or `BITCOIN_WIF`, but any wallet or exchange withdrawal works.

Only the `from` asset on the `from` chain counts toward the order: for `ethereum.usdt`, send USDT on Ethereum, not ETH or USDT on another chain. A token transfer also needs a little of that chain's gas coin in the paying wallet.

### 4. Track the order

`waitForOrder` checks `GET /order/{id}` until the order settles. The status moves from `awaiting_deposit` to `funded`, `executing` and then `delivered`, when `amount_out` holds what reached the recipient. An order that can't complete is `refunded`. If far below `from_amount` arrives at the deposit address and the order can't be filled, it is `underfunded`.

## Buy a stock token with ETH

This example sells 0.5 ETH on Ethereum for Apple stock tokens (`robinhood.aapl`) on Robinhood Chain. Save it as `buy-aapl.mjs`.

```js
import { createWalletClient, http, parseEther } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { mainnet } from "viem/chains";
import { rift, waitForOrder } from "./rift.mjs";

// 1. Get a quote
const quote = await rift("/quote", {
  from: "ethereum.eth",
  to: "robinhood.aapl",
  from_amount: "0.5",
  return_full_route: true,
});
console.log(`0.5 ETH -> ~${quote.estimated_amount_out} AAPL`);

// 2. Create the order
const order = await rift("/order", {
  quote_id: quote.id,
  to_address: "0xYourRobinhoodChainAddress", // receives the AAPL tokens
});

// 3. Send the deposit, 0.5 ETH on Ethereum
const wallet = createWalletClient({
  account: privateKeyToAccount(process.env.PRIVATE_KEY),
  chain: mainnet,
  transport: http(),
});
const hash = await wallet.sendTransaction({
  to: order.deposit_address,
  value: parseEther(order.from_amount),
});
console.log(`Deposit sent: https://etherscan.io/tx/${hash}`);

// 4. Track the order
const { status, amount_out } = await waitForOrder(order.id);
if (status === "delivered") console.log(`Delivered ${amount_out} AAPL`);
```

## Sell a stock token for USDC

The way back out: this script sells 5 NVIDIA stock tokens (`robinhood.nvda`) on Robinhood Chain for USDC on Base. The deposit is a token transfer on Robinhood Chain, so the wallet also needs a little ETH there for gas.

```js
import { createWalletClient, erc20Abi, http, parseUnits } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { robinhood } from "viem/chains";
import { rift, waitForOrder } from "./rift.mjs";

// NVDA on Robinhood Chain, which has 18 decimals
const NVDA = "0xd0601CE157Db5bdC3162BbaC2a2C8aF5320D9EEC";

// 1. Get a quote
const quote = await rift("/quote", {
  from: "robinhood.nvda",
  to: "base.usdc",
  from_amount: "5",
  return_full_route: true,
});
console.log(`5 NVDA -> ~${quote.estimated_amount_out} USDC`);

// 2. Create the order
const order = await rift("/order", {
  quote_id: quote.id,
  to_address: "0xYourBaseAddress", // receives the USDC
});

// 3. Send the deposit, an NVDA transfer on Robinhood Chain
const wallet = createWalletClient({
  account: privateKeyToAccount(process.env.PRIVATE_KEY),
  chain: robinhood,
  transport: http(),
});
const hash = await wallet.writeContract({
  address: NVDA,
  abi: erc20Abi,
  functionName: "transfer",
  args: [order.deposit_address, parseUnits(order.from_amount, 18)],
});
console.log(`Deposit sent: https://robinhoodchain.blockscout.com/tx/${hash}`);

// 4. Track the order
const { status, amount_out } = await waitForOrder(order.id);
if (status === "delivered") console.log(`Delivered ${amount_out} USDC`);
```

## Buy a stock token with Bitcoin

This script sells 0.01 BTC for NVIDIA stock tokens on Robinhood Chain, paying with `sendBitcoin` from `bitcoin.mjs`. The route passes through Hyperliquid, and the order starts once the Bitcoin deposit confirms, so expect it to take 30 to 60 minutes.

```js
import { sendBitcoin } from "./bitcoin.mjs";
import { rift, waitForOrder } from "./rift.mjs";

// 1. Get a quote
const quote = await rift("/quote", {
  from: "bitcoin.btc",
  to: "robinhood.nvda",
  from_amount: "0.01",
  return_full_route: true,
});
const venues = quote.route.map((step) => step.venue).join(" -> ");
console.log(`0.01 BTC -> ~${quote.estimated_amount_out} NVDA via ${venues}`);

// 2. Create the order
const order = await rift("/order", {
  quote_id: quote.id,
  to_address: "0xYourRobinhoodChainAddress", // receives the NVDA tokens
  refund_address: "bc1qYourBitcoinAddress", // gets the BTC back if the trade fails
});

// 3. Send the deposit
const txid = await sendBitcoin(order.deposit_address, order.from_amount);
console.log(`Deposit sent: https://mempool.space/tx/${txid}`);

// 4. Track the order
const { status, amount_out } = await waitForOrder(order.id);
if (status === "delivered") console.log(`Delivered ${amount_out} NVDA`);
```

## Swap Bitcoin for USDC

This script quotes 0.05 BTC into USDC on Ethereum and creates the order with a Bitcoin refund address. It pays the deposit with `sendBitcoin` from `bitcoin.mjs`, then waits for the order to settle.

```js
import { sendBitcoin } from "./bitcoin.mjs";
import { rift, waitForOrder } from "./rift.mjs";

// 1. Get a quote
const quote = await rift("/quote", {
  from: "bitcoin.btc",
  to: "ethereum.usdc",
  from_amount: "0.05",
  return_full_route: true,
});
console.log(`0.05 BTC -> ~${quote.estimated_amount_out} USDC`);

// 2. Create the order
const order = await rift("/order", {
  quote_id: quote.id,
  to_address: "0xYourEthereumAddress", // receives the USDC
  refund_address: "bc1qYourBitcoinAddress", // gets the BTC back if the trade fails
});

// 3. Send the deposit
const txid = await sendBitcoin(order.deposit_address, order.from_amount);
console.log(`Deposit sent: https://mempool.space/tx/${txid}`);

// 4. Track the order
const { status, amount_out } = await waitForOrder(order.id);
if (status === "delivered") console.log(`Delivered ${amount_out} USDC`);
```

The deposit address is a regular Bitcoin address. To let someone pay from their own wallet instead, show them the payment URI `bitcoin:<deposit_address>?amount=<from_amount>` as a link or QR code. Without a `refund_address`, a refund goes back to the address the deposit came from. That address may not belong to you when the BTC comes from an exchange.

## Buy Bitcoin with USDC

This script sells 1,000 USDC on Ethereum for native BTC, delivered to a Bitcoin address. The deposit is a USDC transfer, so the wallet in `PRIVATE_KEY` also needs a little ETH for gas.

```js
import { createWalletClient, erc20Abi, http, parseUnits } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { mainnet } from "viem/chains";
import { rift, waitForOrder } from "./rift.mjs";

// USDC on Ethereum, which has 6 decimals
const USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";

// 1. Get a quote
const quote = await rift("/quote", {
  from: "ethereum.usdc",
  to: "bitcoin.btc",
  from_amount: "1000",
  return_full_route: true,
});
console.log(`1000 USDC -> ~${quote.estimated_amount_out} BTC`);

// 2. Create the order
const order = await rift("/order", {
  quote_id: quote.id,
  to_address: "bc1qYourBitcoinAddress", // receives the BTC
});

// 3. Send the deposit, a USDC transfer on Ethereum
const wallet = createWalletClient({
  account: privateKeyToAccount(process.env.PRIVATE_KEY),
  chain: mainnet,
  transport: http(),
});
const hash = await wallet.writeContract({
  address: USDC,
  abi: erc20Abi,
  functionName: "transfer",
  args: [order.deposit_address, parseUnits(order.from_amount, 6)],
});
console.log(`Deposit sent: https://etherscan.io/tx/${hash}`);

// 4. Track the order
const { status, amount_out } = await waitForOrder(order.id);
if (status === "delivered") console.log(`Delivered ${amount_out} BTC`);
```

## Move USDC between chains

This script moves 1,000 USDC from Base to Ethereum. Any token works the same way: change `from` and `to`, and the token address and decimals of the deposit.

```js
import { createWalletClient, erc20Abi, http, parseUnits } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";
import { rift, waitForOrder } from "./rift.mjs";

// USDC on Base, which has 6 decimals
const USDC = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";

// 1. Get a quote
const quote = await rift("/quote", {
  from: "base.usdc",
  to: "ethereum.usdc",
  from_amount: "1000",
  return_full_route: true,
});
console.log(`1000 USDC on Base -> ~${quote.estimated_amount_out} USDC on Ethereum`);

// 2. Create the order
const order = await rift("/order", {
  quote_id: quote.id,
  to_address: "0xYourEthereumAddress", // receives the USDC
});

// 3. Send the deposit, a USDC transfer on Base
const wallet = createWalletClient({
  account: privateKeyToAccount(process.env.PRIVATE_KEY),
  chain: base,
  transport: http(),
});
const hash = await wallet.writeContract({
  address: USDC,
  abi: erc20Abi,
  functionName: "transfer",
  args: [order.deposit_address, parseUnits(order.from_amount, 6)],
});
console.log(`Deposit sent: https://basescan.org/tx/${hash}`);

// 4. Track the order
const { status, amount_out } = await waitForOrder(order.id);
if (status === "delivered") console.log(`Delivered ${amount_out} USDC on Ethereum`);
```

## Get gas on another chain

This script turns 20 USDC on Base into ETH on Arbitrum, to pay for transactions there. Any chain's gas coin works as the target, such as `ethereum.eth`, `ink.eth` or `robinhood.eth`.

```js
import { createWalletClient, erc20Abi, http, parseUnits } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";
import { rift, waitForOrder } from "./rift.mjs";

// USDC on Base, which has 6 decimals
const USDC = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";

// 1. Get a quote
const quote = await rift("/quote", {
  from: "base.usdc",
  to: "arbitrum.eth",
  from_amount: "20",
  return_full_route: true,
});
console.log(`20 USDC -> ~${quote.estimated_amount_out} ETH on Arbitrum`);

// 2. Create the order
const order = await rift("/order", {
  quote_id: quote.id,
  to_address: "0xYourArbitrumAddress", // receives the ETH
});

// 3. Send the deposit, a USDC transfer on Base
const wallet = createWalletClient({
  account: privateKeyToAccount(process.env.PRIVATE_KEY),
  chain: base,
  transport: http(),
});
const hash = await wallet.writeContract({
  address: USDC,
  abi: erc20Abi,
  functionName: "transfer",
  args: [order.deposit_address, parseUnits(order.from_amount, 6)],
});
console.log(`Deposit sent: https://basescan.org/tx/${hash}`);

// 4. Track the order
const { status, amount_out } = await waitForOrder(order.id);
if (status === "delivered") console.log(`Delivered ${amount_out} ETH on Arbitrum`);
```

## Buy HYPE on Hyperliquid with ETH

This script sells 0.5 ETH on Ethereum for HYPE, delivered to the spot balance of a Hyperliquid account. `to_address` is the account's address.

```js
import { createWalletClient, http, parseEther } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { mainnet } from "viem/chains";
import { rift, waitForOrder } from "./rift.mjs";

// 1. Get a quote
const quote = await rift("/quote", {
  from: "ethereum.eth",
  to: "hyperliquid.hype",
  from_amount: "0.5",
  return_full_route: true,
});
console.log(`0.5 ETH -> ~${quote.estimated_amount_out} HYPE`);

// 2. Create the order
const order = await rift("/order", {
  quote_id: quote.id,
  to_address: "0xYourHyperliquidAddress", // receives the HYPE
});

// 3. Send the deposit, 0.5 ETH on Ethereum
const wallet = createWalletClient({
  account: privateKeyToAccount(process.env.PRIVATE_KEY),
  chain: mainnet,
  transport: http(),
});
const hash = await wallet.sendTransaction({
  to: order.deposit_address,
  value: parseEther(order.from_amount),
});
console.log(`Deposit sent: https://etherscan.io/tx/${hash}`);

// 4. Track the order
const { status, amount_out } = await waitForOrder(order.id);
if (status === "delivered") console.log(`Delivered ${amount_out} HYPE`);
```

## Withdraw USDC from Hyperliquid

This script moves 1,000 USDC from a Hyperliquid spot balance to USDC on Base. On Hyperliquid the deposit isn't a transaction: it's a spot transfer that the account signs with the key in `PRIVATE_KEY` and sends to Hyperliquid's API. Hyperliquid charges the sender 1 USDC for a transfer to a new address, and every deposit address is new, so keep at least 1 USDC more than `from_amount` in the account.

```js
import { parseSignature } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { rift, waitForOrder } from "./rift.mjs";

// 1. Get a quote
const quote = await rift("/quote", {
  from: "hyperliquid.usdc",
  to: "base.usdc",
  from_amount: "1000",
  return_full_route: true,
});
console.log(`1000 USDC on Hyperliquid -> ~${quote.estimated_amount_out} USDC on Base`);

// 2. Create the order
const order = await rift("/order", {
  quote_id: quote.id,
  to_address: "0xYourBaseAddress", // receives the USDC
});

// 3. Send the deposit, a USDC spot transfer on Hyperliquid
const account = privateKeyToAccount(process.env.PRIVATE_KEY);
const time = Date.now();
const transfer = {
  hyperliquidChain: "Mainnet",
  destination: order.deposit_address.toLowerCase(),
  token: "USDC:0x6d1e7cde53ba9467b783cb7c530ce054",
  amount: order.from_amount,
  time: BigInt(time),
};
const signature = await account.signTypedData({
  domain: {
    name: "HyperliquidSignTransaction",
    version: "1",
    chainId: 42161,
    verifyingContract: "0x0000000000000000000000000000000000000000",
  },
  types: {
    "HyperliquidTransaction:SpotSend": [
      { name: "hyperliquidChain", type: "string" },
      { name: "destination", type: "string" },
      { name: "token", type: "string" },
      { name: "amount", type: "string" },
      { name: "time", type: "uint64" },
    ],
  },
  primaryType: "HyperliquidTransaction:SpotSend",
  message: transfer,
});
const { r, s, v } = parseSignature(signature);
const response = await fetch("https://api.hyperliquid.xyz/exchange", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({
    action: { type: "spotSend", signatureChainId: "0xa4b1", ...transfer, time },
    nonce: time,
    signature: { r, s, v: Number(v) },
  }),
});
const result = await response.json();
if (result.status !== "ok") throw new Error(`Hyperliquid refused the transfer: ${JSON.stringify(result)}`);
console.log("Deposit sent");

// 4. Track the order
const { status, amount_out } = await waitForOrder(order.id);
if (status === "delivered") console.log(`Delivered ${amount_out} USDC on Base`);
```

## Deposit into a Morpho vault

This script sells 5,000 USDT on Ethereum for shares of the Steakhouse USDC Morpho vault on Base (`base.steakhouseUSDC`). Vault shares are just another asset to the API. The router finds the path to USDC on Base, deposits into the vault, and delivers the shares to the recipient. The deposit is a USDT transfer, so the wallet in `PRIVATE_KEY` also needs a little ETH for gas.

```js
import { createWalletClient, erc20Abi, http, parseUnits } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { mainnet } from "viem/chains";
import { rift, waitForOrder } from "./rift.mjs";

// USDT on Ethereum, which has 6 decimals
const USDT = "0xdAC17F958D2ee523a2206206994597C13D831ec7";

// 1. Get a quote
const quote = await rift("/quote", {
  from: "ethereum.usdt",
  to: "base.steakhouseUSDC",
  from_amount: "5000",
  return_full_route: true,
});
const venues = quote.route.map((step) => step.venue).join(" -> ");
console.log(`5000 USDT -> ~${quote.estimated_amount_out} steakUSDC via ${venues}`);

// 2. Create the order
const order = await rift("/order", {
  quote_id: quote.id,
  to_address: "0xYourBaseAddress", // receives the vault shares
});

// 3. Send the deposit, a USDT transfer on Ethereum
const wallet = createWalletClient({
  account: privateKeyToAccount(process.env.PRIVATE_KEY),
  chain: mainnet,
  transport: http(),
});
const hash = await wallet.writeContract({
  address: USDT,
  abi: erc20Abi,
  functionName: "transfer",
  args: [order.deposit_address, parseUnits(order.from_amount, 6)],
});
console.log(`Deposit sent: https://etherscan.io/tx/${hash}`);

// 4. Track the order
const { status, amount_out } = await waitForOrder(order.id);
if (status === "delivered") console.log(`Delivered ${amount_out} steakUSDC`);
```

## Move between vaults on different chains

This script moves 1,000 shares of the Steakhouse USDC High Yield vault on Ethereum (`ethereum.steakhouseUSDCHighYield`) into the Gauntlet USDC Prime vault on Base (`base.gauntletUSDCPrimeV2`) in one order. The router redeems the shares, bridges the USDC to Base and deposits it into the new vault. The deposit is a transfer of the vault shares, so the wallet also needs a little ETH for gas.

```js
import { createWalletClient, erc20Abi, http, parseUnits } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { mainnet } from "viem/chains";
import { rift, waitForOrder } from "./rift.mjs";

// Steakhouse USDC High Yield vault shares (bbqUSDC) on Ethereum, which have 18 decimals
const BBQ_USDC = "0xbeeff2C5bF38f90e3482a8b19F12E5a6D2FCa757";

// 1. Get a quote
const quote = await rift("/quote", {
  from: "ethereum.steakhouseUSDCHighYield",
  to: "base.gauntletUSDCPrimeV2",
  from_amount: "1000",
  return_full_route: true,
});
const venues = quote.route.map((step) => step.venue).join(" -> ");
console.log(`1000 bbqUSDC -> ~${quote.estimated_amount_out} gtUSDCp via ${venues}`);

// 2. Create the order
const order = await rift("/order", {
  quote_id: quote.id,
  to_address: "0xYourBaseAddress", // receives the Gauntlet vault shares
});

// 3. Send the deposit, a transfer of the vault shares on Ethereum
const wallet = createWalletClient({
  account: privateKeyToAccount(process.env.PRIVATE_KEY),
  chain: mainnet,
  transport: http(),
});
const hash = await wallet.writeContract({
  address: BBQ_USDC,
  abi: erc20Abi,
  functionName: "transfer",
  args: [order.deposit_address, parseUnits(order.from_amount, 18)],
});
console.log(`Deposit sent: https://etherscan.io/tx/${hash}`);

// 4. Track the order
const { status, amount_out } = await waitForOrder(order.id);
if (status === "delivered") console.log(`Delivered ${amount_out} gtUSDCp`);
```

## Things to know

- **Quotes expire.** Create the order before `expires_at`, ten minutes after quoting. An expired quote returns `410`, so quote again.
- **A quote binds to one order.** Repeating `POST /order` with the same quote and addresses returns the same order. Other addresses return `409`.
- **Deposit amount.** You can send more or less than `from_amount`, and Rift uses everything you send to complete the order. The rate may differ from the quote when the amount is significantly different from what was quoted.
- **`return_full_route` is required.** A quote request without it returns `422`. Set it to `false` to leave `route` out of the response.
- **Quote speed.** The default `optimal` mode gives every venue up to ten seconds. Set `"quote_mode": "fast"` for a 1.5-second cutoff.
- **Rate limits.** The default rate limit is 1 request per second. If you need a key with a higher limit, contact the Rift team using **Support**.
- **No route.** When no venue can quote the pair and amount, `POST /quote` returns `422` with an `error` explaining why.
- **Stock token hours.** Certain tokenized stocks are only liquid 24/5. Most venues don't quote them during off hours.
- **Attribution.** Add `"integrator_id": "your-app"` to the quote request. The ID is echoed in the quote and carried onto the order.
- **Polling.** Check the order every few seconds and back off on errors. Stop at `delivered`, `refunded`, `expired` or `frozen`. See [get order status](/docs/api/get-order-status) for every status.
