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

# Project setup

> Install the Amplify SDK, get an API key, and instantiate the client.

Install `@paxoslabs/amplify-sdk@1.0.0`, instantiate `AmplifyClient` once, and call its subclient methods.

## Requirements

* Node.js `>= 24`
* An API key from Paxos Labs

The SDK has no required peer dependencies. Most consumers also install [`viem`](https://viem.sh) (and optionally [`wagmi`](https://wagmi.sh)) to sign and broadcast the transactions the SDK returns.

## Install

<Tabs>
  <Tab title="pnpm">
    ```bash theme={null}
    pnpm add @paxoslabs/amplify-sdk
    ```
  </Tab>

  <Tab title="npm">
    ```bash theme={null}
    npm install @paxoslabs/amplify-sdk
    ```
  </Tab>

  <Tab title="yarn">
    ```bash theme={null}
    yarn add @paxoslabs/amplify-sdk
    ```
  </Tab>

  <Tab title="bun">
    ```bash theme={null}
    bun add @paxoslabs/amplify-sdk
    ```
  </Tab>
</Tabs>

### Optional signing / wallet libraries

These are not pulled in by the SDK, but you'll typically install them in the consumer:

<Tabs>
  <Tab title="Viem only">
    ```bash theme={null}
    pnpm add viem
    ```
  </Tab>

  <Tab title="Wagmi (React)">
    ```bash theme={null}
    pnpm add wagmi viem @tanstack/react-query
    ```
  </Tab>
</Tabs>

## Get an API key

API keys are issued through the Paxos Labs onboarding process — contact your Paxos Labs representative if you don't have one yet. Store the secret in a server-side environment variable; never bundle it into a browser.

```env theme={null}
# .env.local (or your secrets manager of choice)
PAXOS_LABS_API_KEY=pxl_xxxxxxxxxxxxxxxxxxxxxxxxxx
```

## Instantiate the client

Construct an `AmplifyClient` once and reuse it across requests on a server.

```ts theme={null}
// lib/amplify.ts
import { AmplifyClient } from '@paxoslabs/amplify-sdk'

let client: AmplifyClient | undefined

export function getAmplifyClient(): AmplifyClient {
  if (client) return client
  const apiKey = process.env.PAXOS_LABS_API_KEY
  if (!apiKey) {
    throw new Error('PAXOS_LABS_API_KEY is not set')
  }
  client = new AmplifyClient({ apiKey })
  return client
}
```

The lazy-singleton pattern throws a clear error at first use instead of at module load, which is friendlier in build environments where the secret may be absent.

### Constructor options

```ts theme={null}
interface AmplifyClientOptions {
  /** API key (required). Sent as the `x-api-key` header on every request. */
  apiKey: string
  /** Optional environment override. Defaults to `AmplifyEnvironment.Production`. */
  environment?: AmplifyEnvironment | string
  /** Optional base URL override (takes precedence over `environment`). */
  baseUrl?: string
}
```

<Info>
  The SDK defaults to production (`AmplifyEnvironment.Production`). You only need to pass `environment` or `baseUrl` for non-production use cases.
</Info>

## Server-side vs. client-side usage

The API key authenticates every call and **must not** ship to the browser. The recommended pattern is:

1. Browser code calls your own backend (a Next.js Route Handler, a Server Action, an Express route, etc.).
2. Your backend constructs the `AmplifyClient`, calls the SDK, and returns the prepared `{ to, data, value }` payload.
3. Browser code signs and broadcasts the transaction with the user's wallet (wagmi / viem / Privy / Dynamic / etc.).

### Next.js Route Handler

```ts theme={null}
// app/api/amplify/deposit/prepare/route.ts
import { NextResponse } from 'next/server'
import { AmplifyError } from '@paxoslabs/amplify-sdk'
import { getAmplifyClient } from '@/lib/amplify'

export async function POST(request: Request) {
  const body = (await request.json()) as {
    vaultAddress: string
    depositAsset: string
    depositAmount: string
    userAddress: string
    chainId: number
  }

  try {
    const prepared = await getAmplifyClient().deposit.prepare(body)
    return NextResponse.json(prepared)
  } catch (err) {
    if (err instanceof AmplifyError) {
      return NextResponse.json(
        { error: err.message },
        { status: err.statusCode ?? 500 },
      )
    }
    return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 })
  }
}
```

### Browser-side submission

```tsx theme={null}
'use client'

import type { Address, Hex } from 'viem'
import { useSendTransaction } from 'wagmi'

interface PreparedTransaction {
  transaction: { to: Address; data: Hex; value: string }
}

export function DepositButton({
  vaultAddress,
  depositAsset,
  depositAmount,
  userAddress,
  chainId,
}: {
  vaultAddress: Address
  depositAsset: Address
  depositAmount: string
  userAddress: Address
  chainId: number
}) {
  const { sendTransactionAsync } = useSendTransaction()

  async function onClick() {
    const res = await fetch('/api/amplify/deposit/prepare', {
      method: 'POST',
      body: JSON.stringify({ vaultAddress, depositAsset, depositAmount, userAddress, chainId }),
    })
    if (!res.ok) throw new Error(await res.text())
    const prepared = (await res.json()) as PreparedTransaction

    await sendTransactionAsync({
      to: prepared.transaction.to,
      data: prepared.transaction.data,
      value: BigInt(prepared.transaction.value),
      chainId,
    })
  }

  return <button onClick={onClick}>Deposit</button>
}
```

## First call

A quick smoke test to confirm your key works:

```ts theme={null}
import { getAmplifyClient } from '@/lib/amplify'

const { vaults } = await getAmplifyClient().vaults.list({ filter: 'chainId=1' })
console.log(`Found ${vaults.length} vault(s) on mainnet`)
```

If the key is invalid or the request fails, the SDK throws `AmplifyError` (see [Errors](#errors)).

## Response format

By default, `prepare*` and `cancel` calls return ABI-encoded calldata only:

```ts theme={null}
const prepared = await client.amplify.deposit.prepare({ /* ... */ })
// prepared.transaction = { to, data, value, ... }
```

Pass `responseFormat: 'full'` if you want the ABI fragment, function name, and args alongside the encoded calldata — useful when you want to re-encode in your own ABI plumbing or render the call in a UI.

```ts theme={null}
const prepared = await client.amplify.deposit.prepare({
  vaultAddress,
  depositAsset,
  depositAmount,
  userAddress,
  chainId,
  responseFormat: 'full',
})
// prepared.transaction = { to, data, value, abi, functionName, args }
```

## Decimals

The SDK accepts and returns token amounts as **base-units decimal strings**. It never parses human-readable inputs. Convert before calling:

```ts theme={null}
import { parseUnits } from 'viem'

// User typed "10" intending 10 USDC (6 decimals)
const depositAmount = parseUnits('10', 6).toString() // '10000000'
```

Always read `decimals()` live from the token contract (e.g. via viem's `readContract` or wagmi's `useBalance`).

## Errors

Every method throws `AmplifyError` on non-2xx responses, network failures, and serialization errors. Timeouts throw `AmplifyTimeoutError`.

```ts theme={null}
import { AmplifyClient, AmplifyError, AmplifyTimeoutError } from '@paxoslabs/amplify-sdk'

try {
  await client.amplify.vaults.list()
} catch (err) {
  if (err instanceof AmplifyTimeoutError) {
    // Retry, surface a timeout UI, etc.
  } else if (err instanceof AmplifyError) {
    // err.statusCode  number  — HTTP status
    // err.body        unknown — parsed backend error body (when JSON)
    // err.message     string  — human-readable summary
    // err.rawResponse RawResponse — original Response object
  } else {
    throw err
  }
}
```

## Next steps

* [Deposits guide](./deposits) — full deposit flow with permit and approval branches
* [Withdrawals guide](./withdrawals) — `submitOrder`, fee estimation, listing, and cancel
* [AI Coding Reference](../sdk-ai-reference) — every subclient method, with params and response shapes
* [Migrating from 0.5.x](../migrating-from-0-5) — for upgrading an existing integration
