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.2pnpm add @coin-voyage/paykit @tanstack/react-query@^5.80.2yarn add @coin-voyage/paykit @tanstack/react-query@^5.80.2bun add @coin-voyage/paykit @tanstack/react-query@^5.80.2PayKitProvider
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:
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:
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.

<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:
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".
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
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.
Security Warning: This function should only be run on the server. It uses the API secret, which must remain confidential. Never expose your API secret in client-side code.
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.
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 PayOrderdestination_currency: Object containingaddress(token contract address orundefinedfor native) andchain_idreceiving_address: The recipient address on the destination chaindestination_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.
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 PayOrderdestination_value_usd: The USD value of the salemetadata(optional): Additional metadata including items, customer info, etc.
signature(string): Authorization signature fromgenerateAuthorizationSignature
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.
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 refundedparams(RefundOrderParams): Parameters required to create a refundamount: Object containing fiat value and unitmetadata(optional): Additional metadata for the refund
signature(string): Authorization signature fromgenerateAuthorizationSignature
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 balancesParameters:
orderId(string): The unique identifier of the PayOrderquoteParams(PayOrderQuoteParams): Containswallet_address,chain_type, andchain_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 PayOrdertoken_address(optional): The token address of the source currencychain_id: The blockchain network IDrefund_address: The address where funds will be refunded in case of failure
Returns: Promise<PaymentDetails | undefined> - The payment details object if successful.
processPayOrder
Deprecated: This function is deprecated and will be removed in future versions. The backend now automatically scans for incoming transactions.
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 PayOrdersourceTransactionHash(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 PayOrderstatus: The current payment status (see below)Returns
undefinedif there is no active payment
Payment Status Values
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,PENDING→payment_pendingAWAITING_CONFIRMATION→payment_startedEXECUTING_ORDER,COMPLETED→payment_completedREFUNDED→payment_bouncedEXPIRED→payment_expiredFAILED→payment_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
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 modedark- Force dark modeauto- 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
--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
--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
--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
--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
--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
--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
--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
--ck-qr-dot-color
Color of QR code dots
--ck-qr-border-color
Border color around QR code
Miscellaneous
--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>Last updated