# Quickstart

From sign-in to a first swap on Base. Allow a few minutes, plus the time until your app is approved.

Your own fee per trade: add `swapFeeRecipient` and `swapFeeBps` to price and quote (see [Swap](swap.md)). Not in v1: exact-out (`buyAmount`) and the `/swap/permit2/*` endpoints.

## 1. Sign in and create an app

1. Open [dashboard.qiguard.com](https://dashboard.qiguard.com) and choose **Continue with MetaMask**. Complete the human check, then sign the sign-in message in MetaMask. Signing sends no transaction and costs no gas.
2. Enter your team name and project type (wallet, DEX, bot, platform or other). A contact email is optional.
3. Create an app: give it a name, pick the products (`swap`, `gasless`) and the chains.
4. The app starts as `pending`. Keys of a pending app answer `403 APP_NOT_APPROVED`; they work as soon as the app is approved. Adding a product or a chain to an approved app later sends it back for review.

## 2. Create a key

Open the app, tab **Keys**, and choose **Create key**. The key (`qg_sk_...`) is shown once: copy it into your server's secret store. Qiguard keeps only a keyed hash of it.

Secret keys are for servers. A secret key sent by a browser (an `Origin` header together with `Sec-Fetch-Mode: cors`) is refused with `403 ORIGIN_NOT_ALLOWED`.

## 3. First calls

Keyless calls need no header:

```sh
curl -s https://api.qiguard.com/swap/chains
curl -s "https://api.qiguard.com/tokens?chainId=8453"
```

A price for 25 USDC to WETH on Base:

```sh
curl -s "https://api.qiguard.com/swap/allowance-holder/price?chainId=8453&sellToken=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&buyToken=0x4200000000000000000000000000000000000006&sellAmount=25000000" \
  -H "qg-api-key: $QG_API_KEY" -H "qg-version: v1"
```

`buyAmount` and `minBuyAmount` are net amounts, after the on-chain fee in `fees.qiguardFee`.

## 4. Install the SDK

The JavaScript SDK is one file with no dependencies (Node 18+, Workers, browsers for keyless calls). Download it, with its type declarations, next to your code:

```sh
curl -sO https://docs.qiguard.com/sdk/qiguard-sdk.mjs
curl -sO https://docs.qiguard.com/sdk/qiguard-sdk.d.ts
```

| File | SHA-256 |
|---|---|
| [qiguard-sdk.mjs](sdk/qiguard-sdk.mjs) | `a444094cbd4d19133b9e3e801a75b284f68aead5b825fb72cfdc8de744583459` |
| [qiguard-sdk.d.ts](sdk/qiguard-sdk.d.ts) | `b5b6b75341b9e514e4e3b14673b6e4f4881e2a2ad95554a3fb2477aeebd1e963` |

Then import it by path: `import { QiguardClient } from './qiguard-sdk.mjs';`.

## 5. Quote, approve, send

1. Call `GET /swap/allowance-holder/quote` with the same parameters plus `taker` (the wallet that sends the trade).
2. If `issues.allowance` is set, the taker approves `issues.allowance.spender` (the settlement contract) for exactly `sellAmount`, and waits for the approval receipt.
3. Quote again: the transaction carries a deadline (`expiresAt`, 120 seconds by default).
4. Check that `transaction.to` is the settlement contract of the chain ([Contracts and fees](contracts.md)), then send `transaction` as returned: `to`, `data`, `value`, and `gas` as the gas limit.

With the SDK and [viem](https://viem.sh) (`npm install viem`; `TAKER_KEY` is the private key of the trading wallet, kept in your own secret store):

```js
import { createWalletClient, createPublicClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { base } from 'viem/chains';
import { QiguardClient, approvalsForQuote, assertSwapQuote } from './qiguard-sdk.mjs';

const account = privateKeyToAccount(process.env.TAKER_KEY); // your wallet
const wallet = createWalletClient({ account, chain: base, transport: http() });
const reader = createPublicClient({ chain: base, transport: http() });
const sendAndWait = async (tx) => {
  const hash = await wallet.sendTransaction({ to: tx.to, data: tx.data, value: BigInt(tx.value), gas: tx.gas ? BigInt(tx.gas) : undefined });
  return reader.waitForTransactionReceipt({ hash });
};

const qg = new QiguardClient({ apiKey: process.env.QG_API_KEY });
const taker = account.address;
const params = {
  chainId: 8453,
  sellToken: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC
  buyToken: '0x4200000000000000000000000000000000000006',  // WETH
  sellAmount: '25000000',
  taker,
};

let quote = await qg.getQuote(params);
// exact-amount approvals, only ever for the settlement contract pinned in the SDK
for (const tx of approvalsForQuote(quote, { chainId: params.chainId })) await sendAndWait(tx);
quote = await qg.getQuote(params);
assertSwapQuote(quote, { chainId: params.chainId, sellToken: params.sellToken, buyToken: params.buyToken, sellAmount: params.sellAmount });
const receipt = await sendAndWait(quote.transaction);
console.log(receipt.status, receipt.transactionHash);
```

Complete scripts: [swap-viem.mjs](sdk/examples/swap-viem.mjs) (this flow) and [gasless-viem.mjs](sdk/examples/gasless-viem.mjs) (gasless, with the checks before signing). They import `./qiguard-sdk.mjs` from the same folder.

## 6. Check the dashboard

The **Usage** tab of the app shows requests per hour, errors and latency per endpoint. The **Audit log** lists sign-ins, key changes and app decisions.

## Next

- [Swap](swap.md) for every parameter and response field.
- [Gasless](gasless.md) to let takers trade without holding gas.
- [Errors](errors.md) for every error name.
