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.

Copy this page into your AI coding assistant (Cursor, Copilot, Claude, etc.) for accurate Amplify REST calldata API completions — the path that returns ready-to-sign EVM transactions without requiring the TypeScript SDK.
This page is a condensed, single-file reference for the REST calldata API. For full documentation with per-language tabs and step-by-step walkthroughs, see the API Calldata Integration guide.
Using a skill-aware tool? The same content is exposed as the amplify-earn-api-calldata Agent Skill and is auto-discovered at /.well-known/agent-skills/index.json. Prefer the skill in agents that support them — it loads progressively. Use this page when you need to paste a single reference into a general-purpose AI chat.

When to Use

  • Backend transaction builders in any language (Python, Go, Rust, Java, Node)
  • Custodial wallets, HSMs, multisig services — fetch calldata, sign elsewhere
  • Non-JS stacks that can’t consume @paxoslabs/amplify-sdk
  • Prototyping with curl before application code
For the TypeScript SDK with built-in wallet hooks, see the SDK AI Reference. For calling contracts directly without the API, see the Contract AI Reference.

Base URL & Authentication

Base URL:   https://api.paxoslabs.com
API prefix: /v2
Auth:       x-api-key: pxl_<public_id>_<secret>
  • Obtain a key at https://app.paxoslabs.com.
  • Send the key as a header — never as a query param (it ends up in access logs).

OpenAPI Spec

Endpoint Map

Transaction preparation

EndpointPurpose
GET /v2/core/permitDetect authorization method (permit / approval / already_approved)
GET /v2/amplify/depositBuild deposit calldata
GET /v2/amplify/withdrawBuild withdrawal order calldata
GET /v2/amplify/withdraw/cancelBuild cancel-order calldata

Discovery

EndpointPurpose
GET /v2/amplify/vaultsAccounts grouped by name with per-chain deployments[]; each deployment carries contract addresses, per-asset flags, fees, supply caps, min order size, SLAs

Order status

EndpointPurpose
GET /v2/amplify/withdrawalRequestsWithdrawal orders with orderIndex and status

Analytics

EndpointPurpose
GET /v2/amplify/vaultApysHistorical APY time series per vault
GET /v2/amplify/vaultTvlsHistorical TVL time series (+ current on-chain TVL on the final page)
GET /v2/amplify/vaultAssetsPer-asset depositable/withdrawable flags (paginated, flat)
GET /v2/amplify/vaultCompositionsCurrent portfolio composition from the rate provider
GET /v2/amplify/withdrawalVolumesHistorical withdrawal volumes (requires vaultAddress, startTime, endTime)
GET /v2/amplify/liquidityShortfallsPending withdrawal demand in excess of current vault balance

Display helpers

EndpointPurpose
GET /v2/amplify/calculateWithdrawalFeePreview fee for a specific offerAmount + wantAsset redemption
GET /v2/amplify/supplyCapsUp-to-the-block totalSupplyInBase, supplyCap, and percentageFilled per chain deployment
GET /v2/amplify/userPositionsUser shareBalance, positionValueInBase, baseAssetAddress, and exchangeRateToBase per chain deployment
On-/v2/amplify/vaults (no dedicated endpoint needed): depositSupplyCap, minimumWithdrawalOrderSize, assets[].depositFees, assets[].withdrawFees, assets[].withdrawalSLAs.

Response Format (calldata endpoints only)

/v2/amplify/deposit, /v2/amplify/withdraw, and /v2/amplify/withdraw/cancel accept a responseFormat query parameter:
responseFormatdata (hex)abi / functionName / argsUse when
encoded (default)Signer consumes raw data (eth_sendTransaction, HSM)
fullDebugging; need raw + decoded views
structuredEncode locally (viem encodeFunctionData, ethers Interface.encodeFunctionData)

Filter Syntax (filter query parameter)

filter=field%3Dvalue                          # equality
filter=field1%3Dvalue1%20AND%20field2%3Dvalue2 # conjunction
  • URL-encode once: %3D = =, %20 = space.
  • Separate query params (chainId=1&inDeprecation=false) are ignored.

Discovery — GET /v2/amplify/vaults

Single aggregated endpoint. Params (all optional): filter (flags: name, chainId, inDeprecation, requiresKyt), pageSize (1–100, default 25), pageToken.
curl "https://api.paxoslabs.com/v2/amplify/vaults?filter=chainId%3D1%20AND%20inDeprecation%3Dfalse" \
  -H "x-api-key: $AMPLIFY_API_KEY"
{
  "vaults": [{
    "name": "Amplify USDC Core",
    "deployments": [{
      "chainId": 1,
      "boringVaultAddress": "0xbbbb...",
      "depositorAddress": "0xcccc...",
      "withdrawQueueAddress": "0xdddd...",
      "requiresKyt": false,
      "baseTokenAddress": "0xA0b8...",
      "accountantAddress": "0xaaaa...",
      "tellerAddress": "0xeeee...",
      "depositFeeAddress": null,
      "withdrawFeeAddress": null,
      "inDeprecation": false,
      "depositSupplyCap": { "raw": "1000000000000", "formatted": "1000000.0", "decimals": 6, "hasCap": true },
      "minimumWithdrawalOrderSize": { "raw": "1000000000000000000", "formatted": "1.0", "decimals": 18 },
      "assets": [{
        "assetAddress": "0xA0b8...",
        "depositable": true,
        "withdrawable": true,
        "depositFees": { "bps": 0, "percentage": "0.0000" },
        "withdrawFees": { "bps": 25, "percentage": "0.2500" },
        "withdrawalSLAs": { "expectedDelay": "86400s", "expiryBuffer": "36000s", "internalWithdrawalQueueDelaySLA": "43200s", "externalWithdrawalQueueDelaySLA": "86400s", "internalAccountantRateUpdateDelaySLA": "43200s", "externalAccountantRateUpdateSLA": "86400s" }
      }]
    }]
  }],
  "nextPageToken": null
}

Field → Transaction Parameter Mapping

Discovery fieldUsed as
deployments[].boringVaultAddressvaultAddress in /v2/core/permit and all calldata endpoints; also the ERC-20 share token
deployments[].depositorAddresstransaction.to returned by the prepared deposit
deployments[].withdrawQueueAddressSpender for the share approval before withdrawal
deployments[].baseTokenAddressDefault depositAsset / wantAsset
deployments[].requiresKyt: trueKYT attestation is resolved server-side — no special client handling required
deployments[].depositSupplyCap{ raw, formatted, decimals, hasCap }; hasCap=false → uncapped
deployments[].minimumWithdrawalOrderSizeMinimum shareAmount accepted by /v2/amplify/withdraw

Deposit Flow

Three authorization branches handled by one API:
MethodMeaning
permitEIP-2612 off-chain signature — gas-efficient, single on-chain tx
approvalStandard ERC-20 approve required first, then the deposit
already_approvedSufficient allowance exists — deposit directly

Step 1 — Detect authorization

GET /v2/core/permit
ParamRequiredNotes
vaultAddressYesdeployments[].boringVaultAddress from /v2/amplify/vaults
tokenAddressYesERC-20 deposit token
amountYesDecimal string, token base units
userAddressYesDepositor wallet
chainIdYesEVM chain ID
Response variants:
// permit
{
  "method": "permit",
  "permitData": {
    "domain": { "name": "USD Coin", "version": "2", "chainId": 1, "verifyingContract": "0xA0b8..." },
    "types":  { "Permit": [ ... ] },
    "value":  { "owner": "0x1234...", "spender": "0xcccc...", "value": "1000000", "nonce": "0", "deadline": "9999999999" },
    "deadline": "9999999999"
  }
}

// approval
{ "method": "approval", "approvalTransaction": { "encoded": "0x095ea7b3..." } }

// already_approved
{ "method": "already_approved" }

Step 2 — Satisfy authorization

BranchAction
permitSign domain + types + value via eth_signTypedData_v4 (primaryType: "Permit"). Keep signature and permitData.deadline.
approvalSend tx with to = tokenAddress, data = approvalTransaction.encoded. Wait for receipt.
already_approvedSkip to step 3.

Step 3 — Prepare deposit calldata

GET /v2/amplify/deposit
ParamRequiredNotes
vaultAddressYesboringVaultAddress
depositAssetYesERC-20 to deposit
depositAmountYesDecimal string, token base units
userAddressYesWallet that signs and submits; also the default share recipient
chainIdYesEVM chain ID
toNoShare recipient override (maps to on-chain to arg). Defaults to userAddress.
permitSignatureConditionalRequired on permit path
permitDeadlineConditionalFrom permitData.deadline; required with permitSignature
responseFormatNoencoded (default), full, structured
Response (encoded):
{ "transaction": { "to": "0xcccc...", "data": "0x47e7ef24...", "value": "0" } }

Step 4 — Sign & broadcast

Send { to, data, value }. value is always "0" for ERC-20 deposits.

Reference implementation (Node / viem)

import { createWalletClient, createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'

const BASE = 'https://api.paxoslabs.com'
const HEADERS = { 'x-api-key': process.env.AMPLIFY_API_KEY! }

// 1. Detect authorization
const permitUrl = new URL(`${BASE}/v2/core/permit`)
permitUrl.searchParams.set('vaultAddress', VAULT_ADDRESS)
permitUrl.searchParams.set('tokenAddress', DEPOSIT_ASSET)
permitUrl.searchParams.set('amount', AMOUNT)
permitUrl.searchParams.set('userAddress', account.address)
permitUrl.searchParams.set('chainId', '1')
const permit = await fetch(permitUrl, { headers: HEADERS }).then((r) => r.json())

// 2. Build deposit params, branch on method
const depositUrl = new URL(`${BASE}/v2/amplify/deposit`)
depositUrl.searchParams.set('vaultAddress', VAULT_ADDRESS)
depositUrl.searchParams.set('depositAsset', DEPOSIT_ASSET)
depositUrl.searchParams.set('depositAmount', AMOUNT)
depositUrl.searchParams.set('userAddress', account.address)
depositUrl.searchParams.set('chainId', '1')

if (permit.method === 'permit') {
  const sig = await walletClient.signTypedData({
    account,
    domain: permit.permitData.domain,
    types: permit.permitData.types,
    primaryType: 'Permit',
    message: permit.permitData.value,
  })
  depositUrl.searchParams.set('permitSignature', sig)
  depositUrl.searchParams.set('permitDeadline', permit.permitData.deadline)
} else if (permit.method === 'approval') {
  const hash = await walletClient.sendTransaction({
    to: DEPOSIT_ASSET as `0x${string}`,
    data: permit.approvalTransaction.encoded as `0x${string}`,
    chain: mainnet,
    account,
  })
  await publicClient.waitForTransactionReceipt({ hash })
}

// 3. Fetch + submit deposit
const { transaction: tx } = await fetch(depositUrl, { headers: HEADERS }).then((r) => r.json())
await walletClient.sendTransaction({
  to: tx.to as `0x${string}`,
  data: tx.data as `0x${string}`,
  value: BigInt(tx.value),
  chain: mainnet,
  account,
})

Withdrawal Flow

Withdrawals are asynchronous. Submitting an order locks shares in the WithdrawQueue; the protocol processes the queue off-cycle and transfers the asset on completion.

Step 1 — Approve share spending

Standard ERC-20 approve(spender, amount):
  • Token contract (to): boringVaultAddress
  • spender: withdrawQueueAddress
  • amount: share amount to redeem (always 18 decimals)
Wait for a receipt before step 2.

Step 2 — Prepare withdrawal calldata

GET /v2/amplify/withdraw
ParamRequiredNotes
vaultAddressYesboringVaultAddress
wantAssetYesERC-20 to receive
shareAmountYesDecimal string, 18 decimals
userAddressYesSubmitter; also the default intendedDepositor/receiver/refundReceiver when those are omitted
chainIdYesEVM chain ID
intendedDepositorNoOn-chain SubmitOrderParams.intendedDepositor. Defaults to userAddress.
receiverNoAddress that receives wantAsset on settlement. Defaults to userAddress.
refundReceiverNoAddress that receives refunded shares if the order is cancelled. Defaults to userAddress.
responseFormatNoencoded / full / structured
The server picks submitOrder vs submitOrderAndProcessAll automatically based on the account’s on-chain RolesAuthority configuration — there is no client-side atomic flag. Response:
{ "transaction": { "to": "0xdddd...", "data": "0x1a2b3c4d...", "value": "0" } }

Step 3 — Sign & submit

Broadcast. On confirmation, shares are locked under a new orderIndex.

Step 4 — Poll order status

curl "https://api.paxoslabs.com/v2/amplify/withdrawalRequests?\
filter=userAddress%3D0x1234...%20AND%20vaultAddress%3D0xbbbb..." \
  -H "x-api-key: $AMPLIFY_API_KEY"
StatusMeaning
PENDINGIn queue
COMPLETEAsset transferred
PENDING_REFUNDBeing refunded
REFUNDEDShares returned
Do not filter on status=PENDING while polling — orders disappear the moment they reach a terminal state and you lose visibility into the outcome. Filter on userAddress + vaultAddress (and optionally chainId).

Reference implementation (Node / viem)

import { encodeFunctionData, erc20Abi } from 'viem'

// 1. Approve shares to the queue
const approveData = encodeFunctionData({
  abi: erc20Abi,
  functionName: 'approve',
  args: [WITHDRAW_QUEUE as `0x${string}`, BigInt(SHARE_AMOUNT)],
})
const approveHash = await walletClient.sendTransaction({
  to: VAULT_ADDRESS as `0x${string}`,
  data: approveData,
  chain: mainnet,
  account,
})
await publicClient.waitForTransactionReceipt({ hash: approveHash })

// 2. Fetch withdraw calldata
const url = new URL('https://api.paxoslabs.com/v2/amplify/withdraw')
url.searchParams.set('vaultAddress', VAULT_ADDRESS)
url.searchParams.set('wantAsset', WANT_ASSET)
url.searchParams.set('shareAmount', SHARE_AMOUNT)
url.searchParams.set('userAddress', account.address)
url.searchParams.set('chainId', '1')
const { transaction: tx } = await fetch(url, { headers: HEADERS }).then((r) => r.json())

// 3. Submit
await walletClient.sendTransaction({
  to: tx.to as `0x${string}`,
  data: tx.data as `0x${string}`,
  value: BigInt(tx.value),
  chain: mainnet,
  account,
})

Cancellation Flow

Only PENDING orders are cancellable. The wallet submitting the cancel tx must be the same address that submitted the original order (msg.sender enforced on-chain).

Step 1 — Find orderIndex

curl "https://api.paxoslabs.com/v2/amplify/withdrawalRequests?\
filter=userAddress%3D0x1234...%20AND%20vaultAddress%3D0xbbbb...%20AND%20status%3DPENDING" \
  -H "x-api-key: $AMPLIFY_API_KEY"
orderIndex is a decimal string — pass it verbatim; never coerce to a JS number.

Step 2 — Prepare cancel calldata

GET /v2/amplify/withdraw/cancel
ParamRequiredNotes
vaultAddressYesboringVaultAddress
orderIndexYesExact string from withdrawalRequests.orderIndex
chainIdYesEVM chain ID
responseFormatNoencoded / full / structured
Response:
{ "transaction": { "to": "0xdddd...", "data": "0x5c975abb...", "value": "0" } }

Step 3 — Sign & broadcast

Send from the same wallet that submitted the order. On confirmation, locked shares return to that wallet.

Display Helpers (read-only)

Most display data is returned inline on /v2/amplify/vaults (see Discovery above). Three dedicated helpers cover what isn’t on the discovery response: fee preview for a specific redemption, up-to-the-block supply-cap utilization, and a user’s current position.
EndpointRequired paramsReturns
GET /v2/amplify/calculateWithdrawalFeeofferAmount, wantAsset, vaultAddress, chainId{ feeAmount, offerFeePercentage: { bps, percentage }, flatFee } — all decimal strings / integers, scaled to human-readable units
GET /v2/amplify/supplyCapsoptional filter (flags: vaultAddress, chainId); optional pageSize, pageToken{ supplyCaps: [{ vaultAddress, chainId, totalSupplyInBase, supplyCap, percentageFilled }], nextPageToken }supplyCap / percentageFilled are null for uncapped vaults. With no filter, every live vault deployment is returned. Filter flags: vaultAddress (optional), chainId (optional).
GET /v2/amplify/userPositionsrequired userAddress (top-level, hex); optional filter (flags: vaultAddress, chainId); optional pageSize, pageToken{ userPositions: [{ vaultAddress, chainId, shareBalance, positionValueInBase, baseAssetAddress, exchangeRateToBase }], nextPageToken, tokenMetadata }baseAssetAddress is read from the DB (or via accountant.base() for stand-in vaults where the canonical base asset isn’t natively deployed). With no filter, the user position is returned for every live vault deployment. Filter flags: vaultAddress (optional), chainId (optional).
Fields already on /v2/amplify/vaults (no dedicated endpoint):
FieldShapeNotes
deployments[].depositSupplyCap{ raw, formatted, decimals, hasCap }hasCap: false → uncapped (maxUint256)
deployments[].minimumWithdrawalOrderSize{ raw, formatted, decimals }Minimum shareAmount accepted by /v2/amplify/withdraw
deployments[].assets[].depositFees / withdrawFees{ bps, percentage }Per-asset fees
deployments[].assets[].withdrawalSLAsProtobuf duration strings (e.g. "86400s")Queue + rate-update SLAs
Client caching of 10–30s is safe; invalidate after any of the caller’s own deposits, withdrawals, or cancellations.

Error Envelope

{
  "error": {
    "code": 400,
    "message": "vaultAddress is not a valid hex address",
    "status": "INVALID_ARGUMENT",
    "details": [{
      "@type": "type.paxoslabs.dev/errors/BadRequest",
      "fieldViolations": [{ "field": "vaultAddress", "description": "..." }]
    }]
  }
}
HTTPerror.statusAction
400INVALID_ARGUMENTFix request; inspect fieldViolations
401UNAUTHENTICATEDVerify x-api-key header
403PERMISSION_DENIEDRotate the key
404NOT_FOUNDRe-discover via /v2/amplify/vaults
429RESOURCE_EXHAUSTEDBack off (respect Retry-After if present)
503INTERNALRetry with exponential backoff
Retries: 429 and 503 are safe. 400, 401, 403, 404 are deterministic — do not retry without changing inputs.

Common Gotchas

GotchaConsequenceFix
Filter passed as separate query paramsPredicates silently ignoredUse single filter=field%3Dvalue%20AND%20...
permitSignature without permitDeadline400 INVALID_ARGUMENTSend both from the permit response
Expired permit deadlineOn-chain revertRe-fetch /v2/core/permit
Approval tx not mined before depositRevert (insufficient allowance)Wait for receipt before preparing deposit
Passing a client-side atomic flag to /v2/amplify/withdrawIgnoredThe server chooses submitOrder vs submitOrderAndProcessAll based on on-chain roles
Deposit amount uses wrong decimalsRevert / roundingUSDC/USDT = 6 decimals; shares always 18
shareAmount uses token decimalsToo-small withdrawal or 400Share tokens are always 18 decimals
Polling with status=PENDINGOrder “vanishes” at completionDrop the status predicate from the poll query
orderIndex coerced to numberOff-by-one for large indicesKeep as string end-to-end
Cancel from a different walletOn-chain revertSign from the original submitter
Stale address cacheCalls hit deprecated contractsRespect inDeprecation; refresh on startup

Supported Chains

ChainID
Ethereum1
Sepolia11155111
Base8453
HyperEVM999
Stable Testnet2201

Canonical Docs