SDK
The ICPay SDK provides a typed API for payments on the Internet Computer. It supports public client-side operations with a publishable key and private server-side operations with a secret key.
Intro
- Public operations: fetch account info, verified ledgers, pricing, start payments from a connected wallet.
- Private operations: account details, payment history, transactions. Use only on servers with your secret key.
Get your keys
Create an account in the icpay.org to obtain your Publishable Key (client) and Secret Key (server). Keep your Secret Key private.
Quickstart
Initialize the SDK with your publishable key on the client. Only when using createPayment
or createPaymentUsd
, you must provide an actorProvider
and a connected wallet.
Client setup (TypeScript)
import { Icpay, IcpayError } from '@ic-pay/icpay-sdk'
const icpay = new Icpay({
publishableKey: process.env.NEXT_PUBLIC_ICPAY_PK!,
// actorProvider + connected wallet are required only when calling
// createPayment or createPaymentUsd (e.g. Plug, Internet Identity, Oisy)
})
try {
// Add your code here
} catch (e) {
if (e instanceof IcpayError) {
// Handle gracefully
}
}
Create a payment
There are two common ways to pay: fixed token amount or USD amount automatically converted to tokens.
Send fixed token amount
import { Icpay } from '@ic-pay/icpay-sdk'
const icpay = new Icpay({
publishableKey: process.env.NEXT_PUBLIC_ICPAY_PK!,
actorProvider: (canisterId, idl) => /* return agent-js actor from your wallet */ (window as any).pnp.getActor(),
connectedWallet: { owner: '<principal-id>' },
})
// We can send either symbol or ledgerCanisterId field to the createPayment and createPaymentUsd (symbol is preferred)
const ledgers = await icpay.getVerifiedLedgers()
const icpLedger = ledgers.find(l => l.symbol === 'ICP')!
let ledgerCanisterId = icpLedger.canisterId
// or
// ledgerCanisterId = await icpay.getLedgerCanisterIdBySymbol('ICP')
const tx = await icpay.createPayment({
ledgerCanisterId, // ICP ledger or any ICRC ledger
symbol: 'ICP', // Its either symbol or ledgerCanisterId (symbol is preferred)
amount: '150000000', // smallest unit (e.g. 1.5 ICP with 8 decimals)
metadata: { myProductId: '511234', myOrderId: '511234', anyInternalField: 'allowed' },
})
Send by USD amount (auto conversion)
const res = await icpay.createPaymentUsd({
usdAmount: 5,
ledgerCanisterId,
symbol: 'ICP', // Its either symbol or ledgerCanisterId (symbol is preferred)
metadata: { context: 'tip-jar', myProductId: '511234', myOrderId: '511234', anyInternalField: 'allowed' },
})
Events are emitted throughout the flow when enableEvents
is true. See Events section below.
Configuration
IcpayConfig
options:
publishableKey
(string): Public key for client operations.secretKey
(string): Server-only key for private endpoints.environment
('development' | 'production'): Default 'production'.apiUrl
(string): Defaulthttps://api.icpay.org
.connectedWallet
(object): Connected wallet/principal for signing.icHost
(string): IC network host for agent-js. Defaulthttps://icp0.io
.actorProvider
(fn):(canisterId, idl) => Actor
used to sign ICRC transfers.debug
(boolean): Verbose logging in SDK internals.enableEvents
(boolean): Emit SDK lifecycle events.
Price helpers and ledger info:
// Get list of Verified Ledgers
const ledgers = await icpay.getVerifiedLedgers()
// Get Ledger Canister Id by Symbol string. eg. ckUSDC or ICP
const bySymbol = await icpay.getLedgerCanisterIdBySymbol('ICP')
// Get all information (eg. decimals, current price, ...) about a ledger by passing a Ledger Canister Id (eg. ICP ledger id is 'ryjl3-tyaaa-aaaaa-aaaba-cai')
const info = await icpay.getLedgerInfo('ryjl3-tyaaa-aaaaa-aaaba-cai')
// Fetch all ledgers with current price for 1 token unit
const priced = await icpay.getAllLedgersWithPrices()
// Get number of token that is needed for a fixed price in USD
const calc = await icpay.calculateTokenAmountFromUSD({ usdAmount: 10, ledgerCanisterId: info.canisterId })
Events
Enable with enableEvents: true
. Subscribe via on
or standard addEventListener
.
Event names:
icpay-sdk-error
icpay-sdk-transaction-created
icpay-sdk-transaction-updated
icpay-sdk-transaction-completed
icpay-sdk-transaction-failed
icpay-sdk-transaction-mismatched
icpay-sdk-connect-wallet
icpay-sdk-method-start
icpay-sdk-method-success
icpay-sdk-method-error
const unsubscribe = icpay.on('icpay-sdk-transaction-completed', (detail) => {
// e.g., show success toast, update UI
})
icpay.on('icpay-sdk-transaction-mismatched', (detail) => {
// detail.requestedAmount, detail.paidAmount
})
// Later
unsubscribe()
Types reference (payments)
Payment objects now include split-aware fields when applicable:
type SdkPayment = {
id: string
accountId: string
paymentIntentId: string
transactionId: string | null
transactionSplitId?: string | null
canisterTxId: number | null
amount: string
ledgerCanisterId: string
ledgerTxId?: string | null
accountCanisterId?: number | null
basePaymentAccountId?: string | null
status: 'pending' | 'completed' | 'failed' | 'canceled' | 'refunded' | 'mismatched'
// Optional clarity fields on webhook payloads and some responses
requestedAmount?: string | null // from payment_intent.amount
paidAmount?: string | null // from transaction.amount
invoiceId: string | null
metadata: Record<string, unknown>
createdAt: string
updatedAt: string
}
Public responses (publishable key) expose the same fields via PaymentPublic
where returned.
Alternatively, DOM-style listeners:
const onCompleted = (evt: any) => {
const detail = evt && typeof evt === 'object' ? (evt as any).detail ?? evt : evt
// e.g., show success toast, update UI
}
icpay.addEventListener('icpay-sdk-transaction-completed', onCompleted)
// Later
icpay.removeEventListener('icpay-sdk-transaction-completed', onCompleted)
Event reference
Event | When it fires | Payload (shape) |
---|---|---|
icpay-sdk-error | Any SDK error is emitted (if enableEvents is true) | IcpayError instance (code , message , details? , retryable? , userAction? ) |
icpay-sdk-transaction-created | After creating a payment intent before transfer | { paymentIntentId, amount, ledgerCanisterId, expectedSenderPrincipal } |
icpay-sdk-transaction-updated | While polling/awaiting status; intermediate updates | TransactionResponse -like: { transactionId, status, amount, recipientCanister, timestamp, description?, metadata?, payment? } |
icpay-sdk-transaction-completed |