Documentation Index
Fetch the complete documentation index at: https://docs.halliday.xyz/llms.txt
Use this file to discover all available pages before exploring further.
The Halliday Payments Widget allows users to perform onramps, swaps, and exchange withdrawals to or from any chain or token with minimal integration effort.
It provides the most rapid integration of Halliday Payments with a feature-rich configuration.
To have more fine-grained control over the user interface, review the Halliday API documentation.
To use the Halliday SDK, first get a free API key at dashboard.halliday.xyz.
Following this guide, or the Payments Hello World guide will result in an onramp experience like the following.
Try out onramping to an external wallet with this button:
Installation
Install the Payments SDK, which is available on NPM.
npm install @halliday-sdk/payments
yarn add @halliday-sdk/payments
Next the SDK can be imported into a front-end TypeScript or JavaScript project.
import { openHallidayPayments } from '@halliday-sdk/payments'
Options
The openHallidayPayments function opens the Halliday Payments widget and accepts the following configuration options:
| Name | Type | Description |
|---|
apiKey | string | Your API key for authorization. |
destinationAddress | string | The address of the destination wallet for onramps and swaps. |
inputs (optional) | Asset[] | The input assets for the widget. |
outputs | Asset[] | The output assets for the widget. |
customStyles (optional) | object (CustomStyles) | A list of custom styles to show in the widget. See customizing styles. |
targetElementId (optional) | string | The ID of the DOM element where the widget should be embedded if modal mode is not desired. |
onStatus (optional) | OnStatus | Callback to receive status events. |
onConnectUserWallet (optional) | () => void | Callback invoked when the user requests to connect their wallet. |
onReady (optional) | () => void | Callback invoked when the widget is fully preloaded and ready. |
onError (optional) | OnError | Callback invoked when the widget fails to load or another error occurs. |
userWallet (optional) | UserWallet | User wallet configuration with signing functions. This wallet address is the sole controller of the payment. If this is not provided, the user will be prompted to sign-in with an embedded wallet. |
funder (optional) | Funder | Funder wallet configuration with signing functions. If funder is not provided, the “pay with wallet” option will not be available to the user. |
fontName (optional) | FontName | Font for the widget. Default is ‘haffer’. ‘wudoo-mono’ or ‘inter’ available. |
headerTitle (optional) | string | Custom title for the widget header. |
Type Definitions
type Address = string;
type TypedData = string;
interface TransactionRequest {
to: string;
from?: string;
nonce?: number;
gasLimit?: bigint;
gasPrice?: bigint;
maxPriorityFeePerGas?: bigint;
maxFeePerGas?: bigint;
data?: string;
value?: bigint;
chainId: number;
}
interface TransactionReceipt {
transactionHash?: string;
blockHash?: string;
blockNumber?: number;
from?: string;
to?: string;
// Preserves the original receipt from ethers or viem
rawReceipt: any;
}
interface CustomStyles {
primaryColor?: string;
backgroundColor?: string;
borderColor?: string;
textColor?: string;
textSecondaryColor?: string;
accentColor?: string;
componentShadow?: string;
borderStyle?: "SQUARE" | "DEFAULT";
backgroundStyle?: "OFF" | "BLUR";
successColor?: string;
alertColor?: string;
}
type FontName = "haffer" | "wudoo-mono"| "inter";
type HeaderTitle = string;
type Asset = string; // Format: "chainId:tokenAddress" or native token identifier or fiat symbol
// i.e. 'stripe'
type RampName = string; // Onramp/offramp provider names
type OnStatus = (input: { type: string; payload: any }) => void;
type OnConnectUserWallet = () => void;
type OnReady = () => void;
type OnError = (error: Error) => void;
type SignMessage = (input: { message: string; ownerAddress?: Address }) => Promise<string>;
type SignTypedData = (input: { typedData: string; ownerAddress?: Address }) => Promise<string>;
type SendTransaction = (
transaction: TransactionRequest,
chainConfig: EVMChainConfig,
) => Promise<TransactionReceipt>;
interface Funder {
getAddress: () => Promise<Address>;
sendTransaction: SendTransaction;
}
interface UserWallet {
getAddress: () => Promise<Address>;
signMessage: SignMessage;
signTypedData: SignTypedData;
sendTransaction?: SendTransaction;
}
interface PaymentsWidgetSDKParams {
apiKey: string;
outputs: Asset[];
sandbox?: boolean;
destinationAddress: Address;
customStyles?: CustomStyles;
targetElementId?: string;
fontName?: FontName;
headerTitle?: HeaderTitle;
userWallet?: UserWallet;
onStatus?: OnStatus;
onConnectUserWallet?: () => void;
onReady?: () => void;
onError?: (error: Error) => void;
}
Usage Patterns
Using the wallet connector
Halliday can prompt users to choose a wallet to connect to the app. The wallet connector provides many options including MetaMask, Coinbase Wallet, Rainbow, or Wallet Connect.
Clicking the button will trigger the connect-wallet prompt. If the application already prompts the user to connect a wallet, see using a connected wallet.
import { openHallidayPayments } from "@halliday-sdk/payments";
openHallidayPayments({
apiKey: HALLIDAY_PUBLIC_API_KEY,
// USDC on Base
outputs: ["base:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"],
});
Using a connected wallet
The Halliday SDK can accept an existing wallet connection object that an app has already established.
With this flow, users do not need to reconnect their wallet using the Halliday external wallet modal, creating an optimal user experience for Web3 applications.
If the application does not already have a connected wallet, see using the wallet connector.
Support for existing Viem, Wagmi, and Ethers.js wallet connections are available to Halliday SDK developers. These functions also allow the widget to utilize the proper account if the user switches the address or network in their wallet extension.
// For Viem or Wagmi
import { connectWalletClient } from "@halliday-sdk/payments/viem";
// For Ethers.js
import { connectSigner } from "@halliday-sdk/payments/ethers";
openHallidayPayments({
// ...
userWallet: {
getAddress: async () => "0x...", // required, async
signMessage: async ({ message }) => "...", // required
signTypedData: async ({ typedData }) => "...", // required
sendTransaction: async (tx, chain) => TransactionReceipt,
},
onConnectUserWallet: () => { /* trigger wallet connect */ },
// ...
});
Viem
import { openHallidayPayments } from "@halliday-sdk/payments";
import { connectWalletClient } from "@halliday-sdk/payments/viem";
import { createWalletClient, custom } from "viem";
import { base } from "viem/chains";
const connect = async () => {
const accounts = await window.ethereum.request({ method: "eth_requestAccounts" });
const destinationAddress = accounts[0];
const userWallet = connectWalletClient(() =>
createWalletClient({
chain: base,
transport: custom(window.ethereum),
}),
);
openHallidayPayments({
apiKey: HALLIDAY_PUBLIC_API_KEY,
outputs: ["base:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"],
userWallet,
destinationAddress,
});
};
Wagmi
import { useEffect } from "react";
import { openHallidayPayments } from "@halliday-sdk/payments";
import { connectWalletClient } from "@halliday-sdk/payments/viem";
import { useAccount, useWalletClient } from "wagmi";
export default function App() {
const { address, isConnected } = useAccount();
const { data: walletClient, isSuccess } = useWalletClient();
useEffect(() => {
if (!isConnected || !isSuccess || !walletClient || !address) return;
const userWallet = connectWalletClient(() => walletClient);
openHallidayPayments({
apiKey: HALLIDAY_API_KEY,
outputs: ["base:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"],
targetElementId: "halliday",
destinationAddress: address,
userWallet,
});
}, [isConnected, isSuccess, walletClient, address]);
return <div id="halliday" />;
}
Ethers.js
import { openHallidayPayments } from "@halliday-sdk/payments";
import { connectSigner } from "@halliday-sdk/payments/ethers";
import { BrowserProvider } from "ethers";
const connect = async () => {
const [address] = await window.ethereum.request({ method: "eth_requestAccounts" });
const userWallet = connectSigner(() =>
new BrowserProvider(window.ethereum).getSigner(),
);
openHallidayPayments({
apiKey: HALLIDAY_PUBLIC_API_KEY,
outputs: ["base:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"],
destinationAddress: address,
userWallet,
});
};
Dynamic
The following code example is a demonstration of passing a Dynamic embedded wallet provider to the Halliday SDK in a full React app which is available in the SDK example apps section.
import { useDynamicContext, useIsLoggedIn } from '@dynamic-labs/sdk-react-core'
import { useAccount, useWalletClient } from 'wagmi'
import { openHallidayPayments } from '@halliday-sdk/payments'
import { connectWalletClient } from '@halliday-sdk/payments/viem'
const HALLIDAY_PUBLIC_API_KEY = import.meta.env.VITE_HALLIDAY_API_KEY
function App() {
const { sdkHasLoaded, setShowAuthFlow, handleLogOut } = useDynamicContext();
const isLoggedIn = useIsLoggedIn();
const { address, isConnected } = useAccount();
const { data: walletClient, isSuccess } = useWalletClient();
const launchHalliday = async () => {
if (!isConnected || !address || !isSuccess || !walletClient) return;
// Remember to add Base in the Dynamic dashboard beforehand
const userWallet = connectWalletClient(() => walletClient);
openHallidayPayments({
apiKey: HALLIDAY_PUBLIC_API_KEY,
outputs: ['base:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'],
destinationAddress: address,
userWallet,
});
};
if (!sdkHasLoaded) return <p>Loading...</p>;
if (!isLoggedIn) {
return <button onClick={() => setShowAuthFlow(true)}>Sign in</button>;
}
return (
<div>
<button onClick={handleLogOut}>Log out</button>
<p>Wallet: {address}</p>
<button onClick={launchHalliday}>Open Halliday</button>
</div>
);
}
export default App
Privy
In addition to the following code example, a demonstration of passing a connected Privy wallet to the Halliday SDK in a full React app is available in the SDK example apps section.
import { openHallidayPayments } from '@halliday-sdk/payments'
import { usePrivy, useWallets } from '@privy-io/react-auth'
import { connectSigner } from '@halliday-sdk/payments/ethers'
import { BrowserProvider } from 'ethers'
function Component() {
const { ready, authenticated, login, logout } = usePrivy()
const { wallets } = useWallets()
const connect = async () => {
// Get the embedded wallet (or find the one you want)
// const wallet = wallets.find(w => w.walletClientType === 'privy');
const wallet = wallets[0];
if (!wallet) return;
const provider = await wallet.getEthereumProvider();
const userWallet = connectSigner(() =>
new BrowserProvider(provider).getSigner(),
);
openHallidayPayments({
apiKey: HALLIDAY_PUBLIC_API_KEY,
outputs: ["base:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"],
destinationAddress: wallet.address,
userWallet,
});
};
return (<div>...</div>);
}
export default Component
For the best user experience, the widget can be preloaded so it appears instantly when shown.
The initializeClient call should be done in the initial loading phase of the app.
Later, the openHallidayPayments call can be executed once the widget user interface is ready to be shown to the user.
import { initializeClient } from "@halliday-sdk/payments";
// Call early in your app (e.g., on mount)
initializeClient({
apiKey: HALLIDAY_PUBLIC_API_KEY,
onReady: () => { console.log('Preloaded and ready') }, // optional
onError: (error) => { console.error(error) }, // optional
});
// Next, call openHallidayPayments
By default, the Payments Widget opens as a modal overlaying the web page.
Another option is to embed it within a page. This can be done by providing one option: targetElementId.
import { openHallidayPayments } from "@halliday-sdk/payments";
openHallidayPayments({
apiKey: HALLIDAY_PUBLIC_API_KEY,
outputs: ["base:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"],
targetElementId: "element-id", // Embed the widget inside an HTML element by id
});
Customizing styles
Halliday supports setting custom styles on the Payments Widget in order to match an application’s existing user interface.
import { openHallidayPayments } from "@halliday-sdk/payments";
openHallidayPayments({
apiKey: HALLIDAY_PUBLIC_API_KEY,
outputs: ["base:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"],
customStyles: {
primaryColor: '#8b5cf6',
backgroundColor: '#faf5ff',
borderColor: 'rgba(37, 56, 167, 1)',
textColor: '#1f1f23',
textSecondaryColor: '#a78bfa',
accentColor: '#7c3aed',
componentShadow: '2px 5px #e6e6e6',
borderStyle: 'SQUARE', // or use DEFAULT
backgroundStyle: 'OFF', // or BLUR (uppercase only)
zIndex: 1000, // number only
},
fontName: 'haffer', // also 'wudoo-mono' or 'inter'
headerTitle: 'Checkout',
// ...
});
The following diagram shows how these values are used:
For further customization, please contact the Halliday team.
Building a completely custom user interface is possible by implementing the Halliday API, instead of the Halliday SDK.