Skip to main content
ApiClient is the server-side interface to the CoinVoyage API. Import it from @coin-voyage/paykit/server and use it in your API routes, server actions, or backend services to create pay orders, retrieve quotes, manage KYC links, bank accounts, withdrawals, webhooks, and more. Every method returns an APIResponse<T> wrapper that provides consistent, type-safe error handling without throwing exceptions.

Initialization

import { ApiClient } from "@coin-voyage/paykit/server";

const apiClient = new ApiClient({
  apiKey: process.env.COIN_VOYAGE_API_KEY!,
  environment: "production",
  sessionId: "optional-session-id",
  version: "1.0.0",
});
apiKey
string
required
Your organization’s API key from the CoinVoyage dashboard.
environment
string
default:"production"
Environment to connect to: "production" or "development".
sessionId
string
Optional session identifier attached to every request for tracking purposes.
version
string
Optional client version string sent as the X-Client-Version request header.

APIResponse<T>

Every ApiClient method returns a Promise<APIResponse<T>>. The response is always an object with either a data field (on success) or an error field (on failure) — never both.
interface APIResponse<T> {
  data?: T
  error?: {
    path: string
    statusCode: number
    status: string
    message: string
  }
}

Handling responses

const { data, error } = await apiClient.someMethod();

if (error) {
  console.error("Operation failed:", error.message);
  return;
}

// TypeScript narrows `data` to T here
console.log("Success:", data);
data
T
The typed response payload. Present when the request succeeds.
error
object
Error details. Present when the request fails.

Methods

createDepositPayOrder

Creates a pay order with mode DEPOSIT for a direct on-chain deposit to a specified address.
import { ApiClient, ChainId } from "@coin-voyage/paykit/server";

const { data, error } = await apiClient.createDepositPayOrder({
  intent: {
    asset: {
      chain_id: ChainId.SUI,
      address: null, // null = native token (SUI)
    },
    amount: {
      token_amount: 10, // 10 SUI
    },
    receiving_address: "0xYourReceivingAddressHere",
  },
  metadata: {
    items: [{ name: "Deposit to SUI wallet" }],
  },
});
Provide either token_amount or fiat in intent.amount, never both. The amount must be greater than zero. Invalid input is caught by built-in Zod validation and returns an error without making a network request.
Parameters: params (PayOrderParams), opts? (Opts) Returns: Promise<APIResponse<PayOrder>>

createSalePayOrder

Creates a pay order with mode SALE for a merchant sale. Requires your API secret for authorization. If you omit intent.asset, CoinVoyage settles the payment to the settlement currency configured in your dashboard. If you provide intent.asset, the pay order settles to that specific asset and chain.
The authorization signature is generated internally. You only need to pass the raw apiSecret string.
const apiSecret = process.env.COIN_VOYAGE_API_SECRET!;

const { data, error } = await apiClient.createSalePayOrder(
  {
    intent: {
      amount: {
        fiat: {
          amount: 200,
          unit: "USD",
        },
      },
    },
    metadata: {
      items: [
        {
          name: "t-shirt",
          description: "A nice t-shirt",
          image: "https://example.com/tshirt.jpg",
          quantity: 1,
          unit_price: 200,
          currency: "USD",
        },
      ],
    },
  },
  apiSecret
);
intent.assetSettlement behavior
OmittedSettles to your dashboard settlement currency (must be configured)
ProvidedSettles to the specified asset and chain for this pay order
Parameters: params (PayOrderParams), apiSecret (string), opts? (Opts) Returns: Promise<APIResponse<PayOrder>>

createRefundPayOrder

Creates a pay order with mode REFUND against an existing pay order. Supports full and partial refunds.
const apiSecret = process.env.COIN_VOYAGE_API_SECRET!;

const { data: refundPayOrder, error } = await apiClient.createRefundPayOrder(
  "original-payorder-id",
  {
    intent: {
      asset: {
        chain_id: 1,
        address: null,
      },
      receiving_address: "0x5678...efgh",
      amount: {
        fiat: {
          amount: 100,
          unit: "USD",
        },
      },
    },
    metadata: {
      items: [
        {
          name: "refund",
          description: "Refund for t-shirt purchase",
          unit_price: 100,
          currency: "USD",
        },
      ],
    },
  },
  apiSecret
);
Parameters: payOrderId (string), params (PayOrderParams), apiSecret (string), opts? (Opts) Returns: Promise<APIResponse<PayOrder>>

getPayOrder

Fetches a pay order by its ID.
const { data: payOrder, error } = await apiClient.getPayOrder(
  "pay-order-id-123"
);
Parameters: payOrderId (string), opts? (Opts) Returns: Promise<APIResponse<PayOrder>>

listPayOrders

Lists PayOrders for your organization with pagination. This is a signed server-side method and requires your API secret.
const apiSecret = process.env.COIN_VOYAGE_API_SECRET!;

const { data, error } = await apiClient.listPayOrders(
  {
    limit: 50,
    offset: 0,
  },
  apiSecret
);

if (!error) {
  console.log(data.data, data.pagination);
}
Parameters: params? (ListPayOrdersParams), apiSecret (string), opts? (Opts) Returns: Promise<APIResponse<PayOrdersWithPagination>>

currencySearch

Searches supported currencies for token pickers and back-office tools.
const { data, error } = await apiClient.currencySearch({
  q: "usdc",
  chain_ids: [ChainId.SUI, ChainId.SOL],
  limit: 10,
});
Parameters: params (CurrencySearchParams), opts? (Opts) Returns: Promise<APIResponse<CurrencySearchResponse>>

portfolio

Retrieves wallet token balances and USD values for a wallet address.
const { data, error } = await apiClient.portfolio({
  wallet_address: "0x1234...abcd",
  chain_type: ChainType.EVM,
  chain_ids: [1, 10, 137],
  min_balance_usd: 1,
});
Parameters: params (WalletPortfolioRequest), opts? (Opts) Returns: Promise<APIResponse<WalletPortfolioResponse>>

payOrderQuote

Generates a quote for a pay order given a user’s wallet and chain information. Returns available payment tokens with balances.
const { data: quote, error } = await apiClient.payOrderQuote("pay-order-id", {
  wallet_address: "0x1234...abcd",
  chain_type: ChainType.EVM,
  chain_ids: [1, 10, 137],
});
Parameters: payOrderId (string), params (PayOrderQuoteParams), opts? (Opts) Returns: Promise<APIResponse<RouteQuote[]>>

payOrderPaymentDetails

Retrieves the information needed to complete a payment — destination address, amount, and per-step payment instructions.
const { data: paymentDetails, error } = await apiClient.payOrderPaymentDetails({
  payorder_id: "12345",
  source_currency: {
    chain_id: ChainId.ETH,
    address: "0x1234567890abcdef1234567890abcdef12345678",
  },
  refund_address: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
});
Parameters:
params.payorder_id
string
required
The unique identifier of the pay order.
params.payment_rail
string
default:"CRYPTO"
Payment rail to use. Defaults to CRYPTO.
params.source_currency
object
Source currency to use for the payment details request, with chain_id and address.
params.quote_id
string
Quote identifier from a previously selected route quote.
params.refund_address
string
Address to which funds are returned if the payment fails.
Returns: Promise<APIResponse<PaymentDetails>>

getPayOrderPaymentMethods

Fetches the available payment methods (rails, tokens, availability) for a pay order.
const { data: paymentMethods, error } =
  await apiClient.getPayOrderPaymentMethods("pay-order-id-123");
Parameters: payOrderId (string), opts? (Opts) Returns: Promise<APIResponse<PaymentMethodsResponse>>

KYC methods

Use these methods from server code to create verification links and check identity-verification status for your organization.
Retrieves the current KYC and terms-of-service status. Requires your API secret.
const { data, error } = await apiClient.getKYCStatus(apiSecret);
Parameters: apiSecret (string), opts? (Opts)Returns: Promise<APIResponse<KYCLinkResponse>>

Bank account methods

Use these signed server-side methods for fiat payout destination management.
Lists bank accounts linked to the authenticated organization.
const { data, error } = await apiClient.listBankAccounts(apiSecret);
Parameters: apiSecret (string), opts? (Opts)Returns: Promise<APIResponse<BankAccountsResponse>>
Retrieves one linked bank account.
const { data, error } = await apiClient.getBankAccount(
  "bank_account_id",
  apiSecret
);
Parameters: bankAccountId (string), apiSecret (string), opts? (Opts)Returns: Promise<APIResponse<BankAccountDetails>>
Adds a new linked bank account. The request shape depends on the account type and payout currency.
const { data, error } = await apiClient.addBankAccount(
  {
    account_owner_type: "business",
    account_owner_name: "Example Inc",
    business_name: "Example Inc",
    bank_name: "Example Bank",
    account_name: "Operating account",
    address: {
      street_line_1: "123 Market St",
      city: "San Francisco",
      state: "CA",
      postal_code: "94105",
      country: "US",
    },
    currency: "usd",
    account_type: "us",
    account: {
      account_number: "000123456789",
      routing_number: "110000000",
      checking_or_savings: "checking",
    },
  },
  apiSecret
);
Parameters: params (AddBankAccountRequest), apiSecret (string), opts? (Opts)Returns: Promise<APIResponse<BankAccountDetails>>

Withdrawal methods

Use these signed server-side methods to list and create off-ramp withdrawals.
Lists organization withdrawals. Requires your API secret.
const { data, error } = await apiClient.listWithdrawals(apiSecret);
Parameters: apiSecret (string), opts? (Opts)Returns: Promise<APIResponse<WithdrawalsResponse>>
Creates an off-ramp withdrawal and returns wallet execution data when a source-chain transaction is required.
const { data: bankAccount, error: bankAccountError } =
  await apiClient.getBankAccount("bank_account_id", apiSecret);

if (bankAccountError || !bankAccount) {
  throw new Error(bankAccountError?.message ?? "Bank account not found");
}

const { data, error } = await apiClient.createWithdrawal(
  {
    data: {
      src: {
        id: "currency_id",
        name: "USD Coin",
        ticker: "USDC",
        decimals: 6,
        chain_id: ChainId.BASE,
        address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
        currency_amount: {
          token: {
            raw_amount: "100000000",
            ui_amount: 100,
          },
        },
      },
      dst: {
        bank_account_details: bankAccount,
        currency_amount: {
          unit: "usd",
        },
      },
      payment_rail: "ach",
    },
    sender_address: "0xSenderWallet",
  },
  apiSecret
);
Parameters: params (CreateWithdrawalRequest), apiSecret (string), opts? (Opts)Returns: Promise<APIResponse<WithdrawalResponse>>

generateAuthorizationSignature

Generates an HMAC-SHA256 authorization signature for signed server-side API requests. Most ApiClient methods that require signing generate this value internally when you pass apiSecret.
const apiSecret = process.env.COIN_VOYAGE_API_SECRET!;
const signature = apiClient.generateAuthorizationSignature(
  apiSecret,
  "POST",
  "/pay-orders"
);
The result is formatted as:
APIKey=<apiKey>,signature=<signature>,timestamp=<timestamp>
This method uses your API secret. Call it only in server-side code. Never expose your API secret in client-side bundles.
Parameters: apiSecret (string), method (string), path (string) Returns: string

subscribeOrderStatus

Opens a WebSocket connection for real-time pay order status events. Order-scoped subscriptions authenticate with your API key. Organization-wide subscriptions require a server-generated authorization signature for GET /ws.
const socket = apiClient.subscribeOrderStatus();

socket.onOpen(() => {
  socket.subscribe(orderId);
});

socket.onMessage((msg) => {
  if (msg.type === "event") {
    console.log(msg.data);
  }
});
For server-side dashboards and reconciliation workers, pass an authorization signature to subscribe to all organization PayOrder events:
const authorizationSignature = apiClient.generateAuthorizationSignature(
  apiSecret,
  "GET",
  "/ws"
);

const socket = apiClient.subscribeOrderStatus({ authorizationSignature });

socket.onOpen(() => {
  socket.subscribeOrg();
});
Returns: OrderStatusSocket The OrderStatusSocket exposes the following methods:
subscribe(orderId)
function
Subscribe to status events for a specific pay order.
subscribeOrg()
function
Subscribe to all pay order events for your organization. Available only when subscribeOrderStatus() is called with an authorization signature.
unsubscribe(orderId)
function
Unsubscribe from a specific pay order.
unsubscribeOrg()
function
Unsubscribe from organization-wide events. Available only when subscribeOrderStatus() is called with an authorization signature.
onMessage(callback)
function
Attach a listener for parsed server messages.
onOpen(callback)
function
Attach a listener for the WebSocket open event.
onClose(callback)
function
Attach a listener for the WebSocket close event.
onError(callback)
function
Attach a listener for WebSocket errors.
close()
function
Close the WebSocket connection.

Webhook methods

Lists all webhooks configured for your organization.
const { data: webhooks, error } = await apiClient.listWebhooks(apiSecret);
Parameters: apiSecret (string), opts? (Opts)Returns: Promise<APIResponse<WebhookResponse[]>>
Creates a new webhook subscription for your organization.
const { data: webhook, error } = await apiClient.createWebhook(
  params,
  apiSecret
);
Parameters: params (CreateWebhookRequest), apiSecret (string), opts? (Opts)Returns: Promise<APIResponse<WebhookResponse>>
Updates an existing webhook subscription.
const { data: webhook, error } = await apiClient.updateWebhook(
  "webhook-id",
  params,
  apiSecret
);
Parameters: webhookId (string), params (UpdateWebhookRequest), apiSecret (string), opts? (Opts)Returns: Promise<APIResponse<WebhookResponse>>
Deletes a webhook subscription.
const { error } = await apiClient.deleteWebhook("webhook-id", apiSecret);
Parameters: webhookId (string), apiSecret (string), opts? (Opts)Returns: Promise<APIResponse<void>>

Fee methods

Retrieves claimable fee balances for your organization.
const { data: balances, error } = await apiClient.getFeeBalances(apiSecret);
Parameters: apiSecret (string), opts? (Opts)Returns: Promise<APIResponse<GetFeeBalancesResponse>>
Claims accrued fees for your organization.
const { data: claimResult, error } = await apiClient.claimFees(
  claimFeesParams,
  apiSecret
);
Parameters: params (ClaimFeesRequest), apiSecret (string), opts? (Opts)Returns: Promise<APIResponse<ClaimFeesResponse>>

Swap methods

Gets a quote for swapping between two currencies.
const { data: quote, error } = await apiClient.swapQuote(params);
Parameters: params (SwapQuoteRequest), opts? (Opts)Returns: Promise<APIResponse<SwapQuoteResponse>>
Gets the transaction data needed to execute a swap.
const { data: swapTx, error } = await apiClient.swapData(params);
Parameters: params (SwapDataRequest), opts? (Opts)Returns: Promise<APIResponse<SwapDataResponse>>

createPayOrder (low-level)

A lower-level helper that creates a DEPOSIT or SALE pay order with an explicit mode. In most integrations you should use the mode-specific helpers above (createDepositPayOrder, createSalePayOrder, createRefundPayOrder). Use createPayOrder only when you need direct control over the mode and authorization signature.
const signature = apiClient.generateAuthorizationSignature(
  apiSecret,
  "POST",
  "/pay-orders"
);

const { data, error } = await apiClient.createPayOrder(
  params,
  PayOrderMode.SALE,
  signature
);
Parameters: params (PayOrderParams), mode (CreatePayOrderMode), signature? (string), opts? (Opts) Returns: Promise<APIResponse<PayOrder>>
ApiClient does not expose a processPayOrder() method. PayOrder processing begins automatically once funds are detected on-chain.

TypeScript types

The SDK exports the following TypeScript types for use in your application.

PayOrder

The main pay order object returned by API methods.
type PayOrder = {
  id: string
  mode: PayOrderMode
  status: PayOrderStatus
  metadata?: PayOrderMetadata
  settings?: PayOrderSettings
  fulfillment: FulfillmentData
  payment?: PaymentData
}

PayOrderMode

enum PayOrderMode {
  SALE = "SALE",
  DEPOSIT = "DEPOSIT",
  REFUND = "REFUND",
}
ValueDescription
SALEMerchant sale. Settles to the dashboard settlement currency unless intent.asset is provided.
DEPOSITDirect deposit to a specified address on a target chain.
REFUNDFull or partial refund of a previous pay order.

PayOrderStatus

enum PayOrderStatus {
  PENDING = "PENDING",
  FAILED = "FAILED",
  AWAITING_PAYMENT = "AWAITING_PAYMENT",
  AWAITING_CONFIRMATION = "AWAITING_CONFIRMATION",
  OPTIMISTIC_CONFIRMED = "OPTIMISTIC_CONFIRMED",
  EXECUTING_ORDER = "EXECUTING_ORDER",
  COMPLETED = "COMPLETED",
  EXPIRED = "EXPIRED",
  REFUNDED = "REFUNDED",
  PARTIAL_PAYMENT = "PARTIAL_PAYMENT",
}
StatusDescription
PENDINGCreated but not yet ready for payment.
AWAITING_PAYMENTReady and waiting for the user to send payment.
AWAITING_CONFIRMATIONPayment transaction detected; waiting for blockchain confirmation.
OPTIMISTIC_CONFIRMEDOptimistically confirmed; execution can begin.
EXECUTING_ORDERPayment is being routed to the destination.
COMPLETEDCompleted successfully.
FAILEDFailed during processing.
EXPIREDExpired before payment was received.
REFUNDEDRefunded to the configured refund address.
PARTIAL_PAYMENTReceived an insufficient amount; reached a terminal partial-payment state.

PayOrderMetadata

type PayOrderMetadata = {
  items?: Array<{
    name: string
    description?: string
    image?: string
    quantity?: number
    unit_price?: number
    currency?: string
  }>
  refund?: {
    name?: string
    reason?: string
    additional_info?: string
    refund_amount?: number
    currency?: string
  }
  // Up to 20 custom string fields
  [key: string]: any
}
You can attach up to 20 additional custom fields to the metadata object. Each custom field value must be a string with a maximum of 500 characters.

PayOrderParams

type PayOrderParams = {
  intent: PayOrderIntent
  metadata?: PayOrderMetadata
}

PayOrderIntent

type PayOrderIntent = {
  asset?: CurrencyBase
  amount: IntentAmount
  receiving_address?: string
}

IntentAmount

Provide either token_amount or fiat — not both.
type IntentAmount = {
  token_amount?: number
  fiat?: {
    amount: number
    unit: FiatCurrency
  }
}

FulfillmentData

type FulfillmentData = {
  asset?: Currency
  fiat?: FiatCurrency
  amount: CurrencyAmount
  rate_usd?: number
  receiving_address?: string
  custom_fee_bps?: number
}

PaymentData

type PaymentData = {
  src: QuoteWithCurrency
  dst: CurrencyWithAmount

  // Legacy fields — prefer steps
  deposit_address: string
  receiving_address: string
  refund_address: string

  source_tx_hash?: string
  destination_tx_hash?: string
  refund_tx_hash?: string
  fee_tx_hash?: string

  steps: PaymentStep[]

  expires_at: Date
}
deposit_address, receiving_address, and refund_address are legacy compatibility fields. Use the steps array for rail-specific payment instructions and provider data instead.

CurrencyAmount

interface CurrencyAmount {
  ui_amount_display: string
  raw_amount: string
  value_usd: number
}
ui_amount_display
string
Formatted display string suitable for rendering in UI.
raw_amount
string
Raw amount as a string to prevent BigInt precision loss.
value_usd
number
USD equivalent value of the amount.

WebhookEventType

enum WebhookEventType {
  ORDER_CREATED = "ORDER_CREATED",
  ORDER_AWAITING_PAYMENT = "ORDER_AWAITING_PAYMENT",
  ORDER_CONFIRMING = "ORDER_CONFIRMING",
  ORDER_EXECUTING = "ORDER_EXECUTING",
  ORDER_COMPLETED = "ORDER_COMPLETED",
  ORDER_ERROR = "ORDER_ERROR",
  ORDER_REFUNDED = "ORDER_REFUNDED",
  ORDER_EXPIRED = "ORDER_EXPIRED",
}
EventPayload typeDescription
ORDER_CREATEDpayorder_createdA new pay order was created.
ORDER_AWAITING_PAYMENTpayorder_startedThe pay order is ready for payment.
ORDER_CONFIRMINGpayorder_confirmingPayment detected and confirming on-chain.
ORDER_EXECUTINGpayorder_executingPayment execution has begun.
ORDER_COMPLETEDpayorder_completedThe pay order completed successfully.
ORDER_ERRORpayorder_errorAn error occurred during processing.
ORDER_REFUNDEDpayorder_refundedA refund was processed.
ORDER_EXPIREDpayorder_expiredThe pay order expired before payment was received.