Skip to main content

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

Optional signing / wallet libraries

These are not pulled in by the SDK, but you’ll typically install them in the consumer:
pnpm add viem

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:
  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

// 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).

Response format

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