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.
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 (and optionally wagmi) to sign and broadcast the transactions the SDK returns.
Install
pnpm add @paxoslabs/amplify-sdk
npm install @paxoslabs/amplify-sdk
yarn add @paxoslabs/amplify-sdk
bun add @paxoslabs/amplify-sdk
Optional signing / wallet libraries
These are not pulled in by the SDK, but you’ll typically install them in the consumer:
pnpm add wagmi viem @tanstack/react-query
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.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.
// 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
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
}
The SDK defaults to production (AmplifyEnvironment.Production). You only need to pass environment or baseUrl for non-production use cases.
Server-side vs. client-side usage
The API key authenticates every call and must not ship to the browser. The recommended pattern is:
- Browser code calls your own backend (a Next.js Route Handler, a Server Action, an Express route, etc.).
- Your backend constructs the
AmplifyClient, calls the SDK, and returns the prepared { to, data, value } payload.
- Browser code signs and broadcasts the transaction with the user’s wallet (wagmi / viem / Privy / Dynamic / etc.).
Next.js Route Handler
// 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.prepareDeposit(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
'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:
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).
By default, prepare* and cancel calls return ABI-encoded calldata only:
const prepared = await client.deposit.prepareDeposit({ /* ... */ })
// 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.
const prepared = await client.deposit.prepareDeposit({
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:
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.
import { AmplifyClient, AmplifyError, AmplifyTimeoutError } from '@paxoslabs/amplify-sdk'
try {
await client.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