SDK reference

Production-ready SDK for CoinVoyage integration.

The @coin-voyage/paykit SDK offers client-side and server-side functionality that abstracts the integration of the API, while also exporting UI components. This SDK reduce the amount of boilerplate code you need and lets you easily integrate payment and deposit flow into your web application.


Install CoinVoyage PayKit

Use your preferred package manager to install CoinVoyage PayKit.

npm i @coin-voyage/paykit @tanstack/react-query@^5.80.2

PayKitProvider

The PayKitProvider is required if you want to utilize the PayButton and usePayStatus. It wraps the client application and tracks the state of the PayOrder flow.

"use client";

import { PayKitProvider, WalletProvider } from "@coin-voyage/paykit";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const queryClient = new QueryClient();

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <QueryClientProvider client={queryClient}>
      <WalletProvider>
        <PayKitProvider
          apiKey={process.env.NEXT_PUBLIC_COIN_VOYAGE_API_KEY!}
          debugMode={true}
          mode="light"
          onConnect={({ address, chainId, connectorId, type }) => {
            console.log(
              `Connected to ${chainId} with ${connectorId} (${type}) at ${address}`
            );
          }}
          environment="production"
        >
          {children}
        </PayKitProvider>
      </WalletProvider>
    </QueryClientProvider>
  );
}

PayKitProvider Configuration Options

The PayKitProvider allows you to directly configure the theme, style and more of the PayModal (see image). The PayModal takes the user through the payment process and is shown upon interaction with the PayButton

The PayKitProvider accepts the following configuration parameters:

Option
Required?
Description

apiKey

Yes

API Key of the organization, acquired in the developers tab of the dashboard.

customTheme

No

Gives you the flexibility to modify the PayKit modal styling. See also Themes & customisation

environment

No

Environment to connect to:

  • production (default)

  • development

The development environment exposes additional testnet chains.

debugMode

No

Will log debug logs into the console, helpful when integrating.

mode

No

"light", "dark" or "auto"

onConnect

No

Callback triggered upon connection of a new wallet.

onConnectValidation

No

Allows you to pass a custom function that is run upon connecting of a wallet.

onDisconnect

No

Callback triggered upon disconnect of a wallet.

options

No

Multiple options to modify PayKit modal, including:

  • add a disclaimer

  • control display language

  • hide tooltips

and more

theme

No

Select a predefined styling for the PayKit modal, options include:

  • auto

  • web95

  • retro

  • soft

  • midnight

  • minimal

  • rounded

  • nouns

WalletProvider

The WalletProvider wraps the PayKitProvider , and is required if you want to utilize the PayButton and usePayStatus. It facilitates the configuration of specific chain types, such as setting a specific rpcUrl or adding additional wallet connectors.

"use client"

import { PayKitProvider, WalletProvider } from "@coin-voyage/paykit"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"

const queryClient = new QueryClient()

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <QueryClientProvider client={queryClient}>
      <WalletProvider config={{
          evm: {
            coinbase: {
              appName: "My App"
            },
            walletConnect: {
              projectId: "your-project-id",
            }
          },
          solana: {
            rpcUrl: "my-solana-rpc-url",
            walletConfiguration: {
              wallets: [customWalletAdapter()],
            }
          },
          utxo: {
            lazy: true
          },
        }}
      >
        <PayKitProvider {...}>
          {children}
        </PayKitProvider>
      </WalletProvider>
    </QueryClientProvider>
  )
}

WalletProvider Configuration Options

The WalletProvider accepts the following configuration parameters:

Option
Required?
Description

config

No

Object that contains chain type specific configurations.

config.evm

No

Configuration for EVM chain types. Allows configuration of wallets, connectors, and other evm specific properties.

Also includes options to configure WalletConnect, Coinbase Wallet and MetaMask

config.solana

No

Configuration of the Solana chain. Set a custom rpcUrl and configure wallet adapters.

config.sui

No

Configuration of the Sui chain. Set a custom rpcUrl and configure wallet adapters.

config.utxo

No

Configuration of UTXO chain types. Allows configuration of wallet connectors and few additional options.

PayButton

UI component you can add to your application. The button comes in multiple themes and its style is customizable to your branding.

Clicking the button opens a modal that allows the user to select a payment methods in order to complete the pay order.

deposit-pay-button-example
<PayButton
    intent="Deposit"
    toAddress={"0xYourWalletToDepositInto"}
    toAmount={100}
    toChain={ChainId.ETH}
    toToken={"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"} // USDC
    
    mode="auto"
    style={{
       backgroundColor: "#CF276B",
       color: "white",
    }}
    onClose={() => {
       console.log("Modal Closed")
    }}
    onOpen={() => {
       console.log("Modal Opened")
    }}
    closeOnSuccess={true}

    onPaymentCreationError={(event) => {
       console.log(event.errorMessage)
    }}
    onPaymentBounced={() => {
       console.error("Payment Bounced")
    }}
    onPaymentStarted={() => {
       console.log("Payment Started", {
         description: "Your payment is being processed.",
       })
    }}
    onPaymentCompleted={() => {
       console.log("Payment Complete", {
         description: "Your payment was successful.",
       })
    }}
/>

PayButton Configuration Options

The PayButton accepts the following configuration parameters:

Option
Required?
Description

payId

Conditional*

The payment ID, generated via the Coin Voyage API. Replaces the deposit parameters below. Use this to display a pay order created on the server, like a SALE pay order.

toChain

Conditional*

Destination chain ID. The chain to deposit to.

toToken

No

The destination token to receive. Specify the contract address of the token (ERC-20/SPL/...). Omitting (undefined) indicates the native token (ETH/SOL/SUI/...).

toAmount

Conditional*

The amount of destination token to receive.

toAddress

Conditional*

The recipient of the deposit. Must be an address on the toChain.

metadata

No

Metadata to attach to the deposit.

intent

No

The intent verb displayed on the button, such as "Pay", "Deposit", or "Purchase".

onPaymentCreationError

No

Callback triggered when invalid properties are used to create a deposit payOrder.

onPaymentStarted

No

Callback triggered when user sends payment and transaction is seen on chain.

onPaymentCompleted

No

Callback triggered when destination transfer or call completes successfully.

onPaymentBounced

No

Callback triggered when destination call reverts and funds are refunded.

onOpen

No

Callback triggered when the modal is opened.

onClose

No

Callback triggered when the modal is closed.

defaultOpen

No

Open the modal by default on component mount.

mode

No

Visual appearance mode: "light", "dark", or "auto".

theme

No

Named theme preset. See Themes & customization for available options.

customTheme

No

Custom theme object for advanced styling. See Themes & customization for details.

*Required Parameters: Either provide payId OR all three of toAddress, toChain, and toAmount. The payId approach is used for server-generated pay orders, while the direct parameters are used for client-side deposit flows.

ApiClient

The API client is the easiest way to interact with the CoinVoyage backend. It allows you to safely create PayOrders on the server and perform various payment-related operations.

Initialization

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

export const apiClient = (apiKey: string) =>
  ApiClient({
    apiKey,
    environment: "development",
  });

Configuration Options

Option
Required?
Description

apiKey

Yes

API Key of the organization, acquired in the developers tab of the dashboard.

environment

No

Environment to connect to: production (default) or development.


ApiClient Methods

The API client exposes the following methods to interact with the backend:


getPayOrder

Fetches a PayOrder by its ID. Retrieves a PayOrder object from the API using the provided payOrderId.

const payOrder = await apiClient.getPayOrder("pay-order-id-123");
console.log(payOrder);

Parameters:

  • payOrderId (string): The unique identifier of the PayOrder.

Returns: Promise<PayOrder | undefined> - The PayOrder object if successful.


generateAuthorizationSignature

Generates an authorization signature for API requests that require enhanced security. This signature is required for creating SALE and REFUND PayOrders.

const apiSecret = process.env.COIN_VOYAGE_API_SECRET!;
const signature = apiClient.generateAuthorizationSignature(apiSecret);

The signature is a SHA-512 hash of the concatenated API key, secret, and timestamp, formatted as:

APIKey=<apiKey>,signature=<signature>,timestamp=<timestamp>

Parameters:

  • apiSecret (string): The API secret obtained from the dashboard.

Returns: string - A formatted authorization string.


createDepositPayOrder

Creates a PayOrder with mode DEPOSIT. This allows users to deposit funds to a specific address on a target chain.

You may perform this operation on either the client or server. Executing on the server ensures users cannot perform malicious actions.

Creating a deposit PayOrder on the server is not required. The same result can be achieved by passing the required properties directly to the PayButton component on the client side.

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

const payOrder = await apiClient.createDepositPayOrder({
  destination_currency: {
    address: undefined, // undefined for native token (ETH/SOL/SUI)
    chain_id: ChainId.SUI,
  },
  receiving_address: "0xYourReceivingAddressHere",
  destination_amount: "10",
  metadata: {
    description: "Deposit to SUI wallet",
  },
});

Parameters:

  • params (DepositPayOrderParams): Parameters required to create a deposit PayOrder

    • destination_currency: Object containing address (token contract address or undefined for native) and chain_id

    • receiving_address: The recipient address on the destination chain

    • destination_amount: The amount to receive (as string)

    • metadata (optional): Additional metadata for the PayOrder

  • throwOnFailure (boolean, optional): Whether to throw an error if the request fails

Returns: Promise<PayOrder | undefined> - The created PayOrder object if successful.


createSalePayOrder

Creates a PayOrder with mode SALE. This is used for merchant sales where the payment is settled to the merchant's configured settlement currency.

This method requires an authorization signature generated using generateAuthorizationSignature.

const signature = apiClient.generateAuthorizationSignature(apiSecret);

const payOrder = await apiClient.createSalePayOrder(
  {
    destination_value_usd: 200,
    metadata: {
      items: [
        {
          name: "t-shirt",
          description: "A nice t-shirt",
          image: "https://example.com/tshirt.jpg",
          quantity: 1,
          unit_price: 200,
          currency: "USD",
        },
      ],
    },
  },
  signature
);

Parameters:

  • params (SalePayOrderParams): Parameters required to create a sale PayOrder

    • destination_value_usd: The USD value of the sale

    • metadata (optional): Additional metadata including items, customer info, etc.

  • signature (string): Authorization signature from generateAuthorizationSignature

Returns: Promise<PayOrder | undefined> - The created PayOrder object if successful.


createRefundPayOrder

Creates a PayOrder with mode REFUND for an existing PayOrder. This allows merchants to refund full or partial payments.

This method requires an authorization signature generated using generateAuthorizationSignature.

const signature = apiClient.generateAuthorizationSignature(apiSecret);

const refundPayOrder = await apiClient.createRefundPayOrder(
  "original-payorder-id",
  {
    amount: {
      fiat: {
        value: 100,
        unit: "USD",
      },
    },
    metadata: {
      items: [
        {
          name: "refund",
          description: "Refund for t-shirt purchase",
          unit_price: 100,
          currency: "USD",
        },
      ],
    },
  },
  signature
);

Parameters:

  • payOrderId (string): The unique identifier of the PayOrder to be refunded

  • params (RefundOrderParams): Parameters required to create a refund

    • amount: Object containing fiat value and unit

    • metadata (optional): Additional metadata for the refund

  • signature (string): Authorization signature from generateAuthorizationSignature

Returns: Promise<PayOrder | undefined> - The created refund PayOrder object if successful.


payOrderQuote

Generates a PayOrder quote by providing wallet information and chain details. This returns available payment tokens with balances for the user's wallet.

const quote = await apiClient.payOrderQuote("pay-order-id", {
  wallet_address: "0x1234...abcd",
  chain_type: ChainType.EVM,
  chain_id: 1, // Ethereum Mainnet
});

console.log(quote); // Array of available currencies with balances

Parameters:

  • orderId (string): The unique identifier of the PayOrder

  • quoteParams (PayOrderQuoteParams): Contains wallet_address, chain_type, and chain_id

Returns: Promise<CurrencyWithBalance[] | undefined> - An array of available payment tokens with balances.


payOrderPaymentDetails

Retrieves payment details for a specific PayOrder. This provides the information needed to complete the payment, including the destination address and amount.

const paymentDetails = await apiClient.payOrderPaymentDetails({
  payorder_id: "12345",
  token_address: "0x1234567890abcdef1234567890abcdef12345678", // Optional
  chain_id: ChainId.ETH,
  refund_address: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
});

console.log(paymentDetails);

Parameters:

  • params (PaymentDetailsParams):

    • payorder_id: The unique identifier of the PayOrder

    • token_address (optional): The token address of the source currency

    • chain_id: The blockchain network ID

    • refund_address: The address where funds will be refunded in case of failure

Returns: Promise<PaymentDetails | undefined> - The payment details object if successful.


processPayOrder

Triggers the processing of a PayOrder by providing the transaction hash that represents the payment on the blockchain.

await apiClient.processPayOrder("pay-order-id", "0xabcdef...");

Parameters:

  • payOrderId (string): The unique identifier of the PayOrder

  • sourceTransactionHash (string): The transaction hash representing the payment

Returns: Promise<void>

usePayStatus

A React hook that returns the current payment status and ID, or undefined if there is no active payment. This hook allows you to track the payment lifecycle in your application.

Usage

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

function PaymentTracker() {
  const paymentStatus = usePayStatus();

  if (!paymentStatus) {
    return <div>No active payment</div>;
  }

  return (
    <div>
      <p>Payment ID: {paymentStatus.paymentId}</p>
      <p>Status: {paymentStatus.status}</p>

      {paymentStatus.status === "payment_pending" && (
        <p>Waiting for payment...</p>
      )}
      {paymentStatus.status === "payment_started" && (
        <p>Processing your payment...</p>
      )}
      {paymentStatus.status === "payment_completed" && (
        <p>✅ Payment successful!</p>
      )}
      {paymentStatus.status === "payment_bounced" && (
        <p>⚠️ Payment bounced - funds refunded</p>
      )}
      {paymentStatus.status === "payment_expired" && (
        <p>Payment expired</p>
      )}
      {paymentStatus.status === "payment_failed" && (
        <p>❌ Payment failed</p>
      )}
    </div>
  );
}

Return Value

Returns { paymentId: string; status: PaymentStatus } | undefined

  • paymentId: The unique identifier of the PayOrder

  • status: The current payment status (see below)

  • Returns undefined if there is no active payment

Payment Status Values

Status
Description

payment_pending

The user has not paid yet. The PayOrder is awaiting payment.

payment_started

The user has paid and the payment is in progress. This status typically lasts a few seconds while the transaction is being confirmed.

payment_completed

The final call or transfer succeeded. Payment completed successfully.

payment_bounced

The final call or transfer reverted. Funds were sent to the payment's configured refund address on the destination chain.

payment_expired

The payment expired before the user paid.

payment_failed

The payment failed for some reason.

Status Mapping

The hook maps internal PayOrderStatus values to user-friendly PaymentStatus values:

  • AWAITING_PAYMENT, PENDINGpayment_pending

  • AWAITING_CONFIRMATIONpayment_started

  • EXECUTING_ORDER, COMPLETEDpayment_completed

  • REFUNDEDpayment_bounced

  • EXPIREDpayment_expired

  • FAILEDpayment_failed

Themes & Customization

CoinVoyage PayKit offers extensive theming and customization options to match your brand and design preferences. You can choose from predefined themes or create custom themes using CSS variables.


Using Predefined Themes

Apply a theme to your PayKit modal by setting the theme prop on the PayKitProvider or PayButton:

<PayKitProvider
  apiKey={process.env.NEXT_PUBLIC_COIN_VOYAGE_API_KEY!}
  theme="midnight"
  mode="auto"
>
  {children}
</PayKitProvider>

Available Themes

Theme Name
Description

auto

Automatically adapts to system light/dark mode preferences (default).

web95

Retro Windows 95-inspired design with classic UI elements.

retro

Vintage aesthetic with nostalgic styling.

soft

Gentle, rounded design with soft colors and shadows.

midnight

Dark theme optimized for low-light environments.

minimal

Clean, minimalist design with reduced visual elements.

rounded

Emphasis on rounded corners and smooth edges.

nouns

Nouns DAO-inspired design with bold, playful elements.


Mode Settings

Control the light/dark appearance independently from themes:

<PayKitProvider
  apiKey={process.env.NEXT_PUBLIC_COIN_VOYAGE_API_KEY!}
  mode="dark" // "light" | "dark" | "auto"
>
  {children}
</PayKitProvider>

Mode Options

  • light - Force light mode

  • dark - Force dark mode

  • auto - Automatically adapt to system preferences (default)


Custom Themes

For advanced customization, use the customTheme prop to override specific CSS variables. This allows you to fine-tune colors, shadows, borders, and other visual properties.

<PayKitProvider
  apiKey={process.env.NEXT_PUBLIC_COIN_VOYAGE_API_KEY!}
  customTheme={{
    "--ck-primary-button-background": "#CF276B",
    "--ck-primary-button-color": "#FFFFFF",
    "--ck-primary-button-border-radius": "12px",
    "--ck-body-background": "#1a1a1a",
    "--ck-body-color": "#ffffff",
    "--ck-modal-box-shadow": "0 8px 32px rgba(0, 0, 0, 0.4)",
  }}
>
  {children}
</PayKitProvider>

Custom Theme Variables

The customTheme object accepts CSS variable overrides organized by component:

Connect Button

Variable
Description

--ck-connectbutton-font-size

Font size for the connect button text

--ck-connectbutton-color

Text color of the connect button

--ck-connectbutton-background

Background color of the connect button

--ck-connectbutton-background-secondary

Secondary background color

--ck-connectbutton-hover-color

Text color on hover

--ck-connectbutton-hover-background

Background color on hover

--ck-connectbutton-active-color

Text color when active/pressed

--ck-connectbutton-active-background

Background color when active/pressed

--ck-connectbutton-balance-color

Text color for balance display

--ck-connectbutton-balance-background

Background color for balance display

--ck-connectbutton-balance-box-shadow

Box shadow for balance display

--ck-connectbutton-balance-hover-background

Balance background on hover

--ck-connectbutton-balance-hover-box-shadow

Balance box shadow on hover

--ck-connectbutton-balance-active-background

Balance background when active

--ck-connectbutton-balance-active-box-shadow

Balance box shadow when active

Primary Button

Variable
Description

--ck-primary-button-border-radius

Border radius for primary buttons

--ck-primary-button-color

Text color for primary buttons

--ck-primary-button-background

Background color for primary buttons

--ck-primary-button-box-shadow

Box shadow for primary buttons

--ck-primary-button-font-weight

Font weight for primary button text

--ck-primary-button-hover-color

Text color on hover

--ck-primary-button-hover-background

Background color on hover

--ck-primary-button-hover-box-shadow

Box shadow on hover

--ck-primary-button-active-background

Background color when active/pressed

Secondary & Tertiary Buttons

Variable
Description

--ck-secondary-button-border-radius

Border radius for secondary buttons

--ck-secondary-button-color

Text color for secondary buttons

--ck-secondary-button-background

Background color for secondary buttons

--ck-secondary-button-box-shadow

Box shadow for secondary buttons

--ck-secondary-button-font-weight

Font weight for secondary button text

--ck-secondary-button-hover-background

Background color on hover

--ck-tertiary-button-background

Background color for tertiary buttons

Modal & Body

Variable
Description

--ck-modal-box-shadow

Box shadow for the modal container

--ck-overlay-background

Background color for the modal overlay

--ck-body-color

Primary text color for modal content

--ck-body-color-muted

Muted/secondary text color

--ck-body-color-muted-hover

Muted text color on hover

--ck-body-background

Primary background color for modal body

--ck-body-background-transparent

Transparent background variant

--ck-body-background-secondary

Secondary background color

--ck-body-background-secondary-hover-background

Secondary background on hover

--ck-body-background-secondary-hover-outline

Outline color on hover

--ck-body-background-tertiary

Tertiary background color

--ck-body-action-color

Color for actionable elements

--ck-body-divider

Color for divider lines

--ck-body-divider-secondary

Secondary divider color

--ck-body-color-danger

Color for error/danger states

--ck-body-color-valid

Color for success/valid states

--ck-siwe-border

Border color for Sign-In with Ethereum elements

Disclaimer

Variable
Description

--ck-body-disclaimer-background

Background color for disclaimer sections

--ck-body-disclaimer-box-shadow

Box shadow for disclaimer sections

--ck-body-disclaimer-color

Text color for disclaimers

--ck-body-disclaimer-link-color

Link color in disclaimers

--ck-body-disclaimer-link-hover-color

Link color on hover

Tooltips

Variable
Description

--ck-tooltip-background

Background color for tooltips

--ck-tooltip-background-secondary

Secondary background for tooltips

--ck-tooltip-color

Text color for tooltips

--ck-tooltip-shadow

Shadow for tooltip containers

Network Dropdown

Variable
Description

--ck-dropdown-button-color

Text color for dropdown buttons

--ck-dropdown-button-box-shadow

Box shadow for dropdown buttons

--ck-dropdown-button-background

Background color for dropdown buttons

--ck-dropdown-button-hover-color

Text color on hover

--ck-dropdown-button-hover-background

Background color on hover

QR Code

Variable
Description

--ck-qr-dot-color

Color of QR code dots

--ck-qr-border-color

Border color around QR code

Miscellaneous

Variable
Description

--ck-focus-color

Color for focused elements

--ck-spinner-color

Color for loading spinners

--ck-copytoclipboard-stroke

Stroke color for copy-to-clipboard icons


Complete Custom Theme Example

<PayKitProvider
  apiKey={process.env.NEXT_PUBLIC_COIN_VOYAGE_API_KEY!}
  customTheme={{
    // Primary Button
    "--ck-primary-button-background": "#CF276B",
    "--ck-primary-button-color": "#FFFFFF",
    "--ck-primary-button-border-radius": "8px",
    "--ck-primary-button-hover-background": "#A01F54",

    // Modal
    "--ck-modal-box-shadow": "0 10px 40px rgba(0, 0, 0, 0.2)",
    "--ck-body-background": "#FFFFFF",
    "--ck-body-color": "#1A1A1A",
    "--ck-body-background-secondary": "#F5F5F5",

    // Colors
    "--ck-body-color-danger": "#DC2626",
    "--ck-body-color-valid": "#10B981",
    "--ck-body-action-color": "#3B82F6",

    // Buttons
    "--ck-secondary-button-background": "#E5E7EB",
    "--ck-secondary-button-color": "#374151",

    // QR Code
    "--ck-qr-dot-color": "#1A1A1A",
    "--ck-qr-border-color": "#E5E7EB",
  }}
>
  {children}
</PayKitProvider>

Tip: You can combine a predefined theme with customTheme to override specific variables while maintaining the base theme's styling.

Last updated