Payment Links API

The Payment Links service (client.paymentLinks) allows you to create payment requests that can be shared with customers. When a customer accesses a payment link, they will be directed to a checkout page where they can complete the payment using SUI or other supported cryptocurrencies.

Create a new payment link using the SDK:

import { PaymentDestinationType } from '@suipay/api';

// Create payment link with POLAR_BALANCE destination
const paymentLink = await client.paymentLinks.create({
  amount_usdc: 100,
  description: 'Test payment',
  destination_type: PaymentDestinationType.POLAR_BALANCE
});

console.log(`Payment URL: ${paymentLink.url}`);

Method Signature

client.paymentLinks.create(options: CreatePaymentLinkRequest): Promise<PaymentLink>

Request Parameters

Field
Type
Required
Description

amount_usdc

number

Yes

The amount in USDC to be paid

description

string

No

A description of what the payment is for

destination_type

PaymentDestinationType

Yes

Where the funds should be sent after payment

custom_sui_address

string

Conditional

Required when destination_type is CUSTOM_ADDRESS

bank_account_id

string

Conditional

Required when destination_type is BANK_ACCOUNT

Response Type

interface PaymentLink {
  id: string;
  amount_usdc: number;
  description: string;
  destination_type: PaymentDestinationType;
  custom_sui_address: string | null;
  bank_account_id: string | null;
  enabled: boolean;
  created_at: string;
  url: string;
}

Usage Examples

import { PaymentDestinationType } from '@suipay/api';

// Create payment link with POLAR_BALANCE destination
const basicPayment = await client.paymentLinks.create({
  amount_usdc: 50,
  description: 'Service payment',
  destination_type: PaymentDestinationType.POLAR_BALANCE
});

// Create payment link with custom SUI address
const customAddressPayment = await client.paymentLinks.create({
  amount_usdc: 100,
  description: 'Payment to custom wallet',
  destination_type: PaymentDestinationType.CUSTOM_ADDRESS,
  custom_sui_address: '0x1234567890abcdef1234567890abcdef12345678'
});

// Create payment link with bank account destination
const bankPayment = await client.paymentLinks.create({
  amount_usdc: 200,
  description: 'Payment to bank account',
  destination_type: PaymentDestinationType.BANK_ACCOUNT,
  bank_account_id: 'bank_account_id_here'
});

console.log(`Share this payment link: ${basicPayment.url}`);

Retrieve all payment links for your account:

const paymentLinks = await client.paymentLinks.list();
console.log(`Found ${paymentLinks.length} payment link(s)`);

paymentLinks.forEach(link => {
  console.log(`${link.description}: ${link.amount_usdc} USDC`);
  console.log(`Status: ${link.enabled ? 'Active' : 'Disabled'}`);
  console.log(`URL: ${link.url}`);
});

Method Signature

client.paymentLinks.list(): Promise<PaymentLinkSummary[]>

Response Type

interface PaymentLinkSummary {
  id: string;
  amount_usdc: number;
  description: string;
  enabled: boolean;
  created_at: string;
}

Retrieve details of a specific payment link:

const paymentLinkId = 'payment_link_id_here';
const paymentLink = await client.paymentLinks.get(paymentLinkId);

console.log(`Payment Link: ${paymentLink.description}`);
console.log(`Amount: ${paymentLink.amount_usdc} USDC`);
console.log(`Status: ${paymentLink.enabled ? 'Active' : 'Disabled'}`);
console.log(`Destination: ${paymentLink.destination_type}`);
console.log(`URL: ${paymentLink.url}`);

// Check payment status
if (paymentLink.paid) {
  console.log(`✅ Payment completed at: ${paymentLink.paid_at}`);
  console.log(`Transaction: ${paymentLink.transaction_digest}`);
} else {
  console.log('⏳ Payment pending');
}

Method Signature

client.paymentLinks.get(id: string): Promise<PaymentLink>

Response Type

interface PaymentLink {
  id: string;
  user_id: string;
  amount_usdc: number;
  description?: string;
  shopify_payment_session_id?: string;
  destination_type: PaymentDestinationType;
  custom_sui_address?: string;
  bank_account_id?: string;
  enabled: boolean;
  off_ramp_status: OffRampStatus;
  sui_usdc_transfer_tx?: string;
  solana_usdc_transfer_tx?: string;
  cctp_message_hash?: string;
  off_ramp_error?: string;
  off_ramp_started_at?: string;
  off_ramp_completed_at?: string;
  bridge_transfer_id?: string;
  sui_wallet_deposit_address?: string;
  polar_balance_processed: boolean;
  created_at: string;
  expires_at?: string;
  paid: boolean;
  paid_at?: string;
  transaction_digest?: string;
  transaction_payer?: string;
  refunded: boolean;
  refund_digest?: string;
  woocommerce_metadata?: any;
}

Checking Payment Status

Monitor payment link status and track completion:

async function checkPaymentStatus(paymentLinkId: string) {
  const paymentLink = await client.paymentLinks.get(paymentLinkId);
  
  console.log(`Payment Link: ${paymentLink.description}`);
  console.log(`Amount: ${paymentLink.amount_usdc} USDC`);
  
  if (!paymentLink.enabled) {
    console.log('❌ Payment link is disabled');
    return;
  }
  
  if (paymentLink.paid) {
    console.log('✅ Payment completed!');
    console.log(`  Paid at: ${new Date(paymentLink.paid_at!).toLocaleString()}`);
    console.log(`  Transaction: ${paymentLink.transaction_digest}`);
    console.log(`  Payer: ${paymentLink.transaction_payer}`);
    
    // Check off-ramp status for bank account destinations
    if (paymentLink.destination_type === PaymentDestinationType.BANK_ACCOUNT) {
      console.log(`  Off-ramp status: ${paymentLink.off_ramp_status}`);
    }
  } else {
    console.log('⏳ Payment pending');
    if (paymentLink.expires_at) {
      const expiryDate = new Date(paymentLink.expires_at);
      console.log(`  Expires: ${expiryDate.toLocaleString()}`);
    }
  }
  
  if (paymentLink.refunded) {
    console.log('🔄 Payment has been refunded');
    console.log(`  Refund transaction: ${paymentLink.refund_digest}`);
  }
}
Field
Type
Description

id

string

Unique payment link identifier

user_id

string

Associated user identifier

amount_usdc

number

Payment amount in USDC

description

string?

Optional payment description

shopify_payment_session_id

string?

Shopify integration session ID

destination_type

PaymentDestinationType

Where funds are sent after payment

custom_sui_address

string?

Custom SUI address (for CUSTOM_ADDRESS type)

bank_account_id

string?

Bank account ID (for BANK_ACCOUNT type)

enabled

boolean

Whether the payment link is active

off_ramp_status

OffRampStatus

Current off-ramp processing status

sui_usdc_transfer_tx

string?

SUI USDC transfer transaction hash

solana_usdc_transfer_tx

string?

Solana USDC transfer transaction hash

cctp_message_hash

string?

CCTP (Cross-Chain Transfer Protocol) message hash

off_ramp_error

string?

Error message if off-ramp processing failed

off_ramp_started_at

string?

When off-ramp processing started

off_ramp_completed_at

string?

When off-ramp processing completed

bridge_transfer_id

string?

Bridge service transfer identifier

sui_wallet_deposit_address

string?

SUI wallet deposit address used

polar_balance_processed

boolean

Whether funds have been processed to balance

created_at

string

Payment link creation timestamp

expires_at

string?

When the payment link expires

paid

boolean

Whether the payment has been completed

paid_at

string?

When the payment was completed

transaction_digest

string?

The SUI transaction hash of the payment

transaction_payer

string?

The SUI address of the payer

refunded

boolean

Whether the payment has been refunded

refund_digest

string?

The SUI transaction hash of the refund

woocommerce_metadata

any?

WooCommerce integration metadata

Off-ramp Status Enum

enum OffRampStatus {
  PENDING = 'PENDING',
  CCTP_TRANSFER_INITIATED = 'CCTP_TRANSFER_INITIATED',
  CCTP_TRANSFER_COMPLETED = 'CCTP_TRANSFER_COMPLETED',
  BRIDGE_TRANSFER_INITIATED = 'BRIDGE_TRANSFER_INITIATED',
  BRIDGE_TRANSFER_COMPLETED = 'BRIDGE_TRANSFER_COMPLETED',
  COMPLETED = 'COMPLETED',
  FAILED = 'FAILED'
}

Off-ramp Processing Monitoring

Monitor the off-ramp processing status for bank account destinations:

async function monitorOffRampStatus(paymentLinkId: string) {
  const paymentLink = await client.paymentLinks.get(paymentLinkId);
  
  if (!paymentLink.paid) {
    console.log('Payment not yet received');
    return;
  }
  
  console.log(`Off-ramp Status: ${paymentLink.off_ramp_status}`);
  
  switch (paymentLink.off_ramp_status) {
    case 'PENDING':
      console.log('⏳ Processing payment...');
      break;
    case 'CCTP_TRANSFER_INITIATED':
      console.log('🔄 Cross-chain transfer started');
      break;
    case 'CCTP_TRANSFER_COMPLETED':
      console.log('✅ Cross-chain transfer complete');
      break;
    case 'BRIDGE_TRANSFER_INITIATED':
      console.log('🏦 Bank transfer initiated');
      break;
    case 'BRIDGE_TRANSFER_COMPLETED':
    case 'COMPLETED':
      console.log('✅ All processing complete!');
      break;
    case 'FAILED':
      console.log('❌ Processing failed:', paymentLink.off_ramp_error);
      break;
  }
}

Destination Types

POLAR_BALANCE

Funds are added to your SuiPay balance and can be withdrawn later:

const balancePayment = await client.paymentLinks.create({
  amount_usdc: 100,
  description: 'Add to balance',
  destination_type: PaymentDestinationType.POLAR_BALANCE
});
// Funds will be added to your polar_balance_usdc after payment

BANK_ACCOUNT

Funds are automatically sent to your connected bank account:

// First, get your bank accounts
const bankAccounts = await client.user.getBankAccounts();
const primaryAccount = bankAccounts.find(account => account.is_verified);

if (primaryAccount) {
  const bankPayment = await client.paymentLinks.create({
    amount_usdc: 200,
    description: 'Payment to bank',
    destination_type: PaymentDestinationType.BANK_ACCOUNT,
    bank_account_id: primaryAccount.id
  });
} else {
  console.log('No verified bank account available');
}

Requirements:

  • KYC verification must be completed (user.kyc_complete === true)

  • Bank account must be connected and verified

  • More complex processing with multiple steps

CUSTOM_ADDRESS

Funds are sent directly to a specified SUI address:

const customPayment = await client.paymentLinks.create({
  amount_usdc: 50,
  description: 'Direct wallet payment',
  destination_type: PaymentDestinationType.CUSTOM_ADDRESS,
  custom_sui_address: '0x1234567890abcdef1234567890abcdef12345678'
});

Requirements:

  • Valid SUI address starting with "0x"

  • Address format is validated during creation

Error Handling

Handle common errors when working with payment links:

import { 
  SuiPayValidationError, 
  SuiPayAuthenticationError 
} from '@suipay/api';

try {
  const paymentLink = await client.paymentLinks.create({
    amount_usdc: 100,
    description: 'Test payment',
    destination_type: PaymentDestinationType.BANK_ACCOUNT,
    bank_account_id: 'invalid_bank_id'
  });
} catch (error) {
  if (error instanceof SuiPayValidationError) {
    console.error('Validation error:', error.response?.error);
    // Common issues: invalid bank_account_id, missing custom_sui_address
  } else if (error instanceof SuiPayAuthenticationError) {
    console.error('Authentication failed');
  } else {
    console.error('Unexpected error:', error);
  }
}

Complete Example

Here's a comprehensive example showing payment link creation and monitoring:

import { PaymentDestinationType, OffRampStatus } from '@suipay/api';

async function createAndMonitorPayment() {
  try {
    // Create payment link
    const paymentLink = await client.paymentLinks.create({
      amount_usdc: 100,
      description: 'Service payment',
      destination_type: PaymentDestinationType.POLAR_BALANCE
    });
    
    console.log(`Payment link created: ${paymentLink.url}`);
    console.log('Share this link with your customer');
    
    // Monitor payment status (you might do this in a webhook or polling)
    const checkStatus = async () => {
      const updated = await client.paymentLinks.get(paymentLink.id);
      
      if (updated.paid) {
        console.log('✅ Payment received!');
        console.log(`Transaction: ${updated.transaction_digest}`);
        console.log(`From: ${updated.transaction_payer}`);
        return true;
      } else {
        console.log('⏳ Still waiting for payment...');
        return false;
      }
    };
    
    // Poll every 30 seconds (in production, use webhooks instead)
    const pollInterval = setInterval(async () => {
      const completed = await checkStatus();
      if (completed) {
        clearInterval(pollInterval);
      }
    }, 30000);
    
  } catch (error) {
    console.error('Error creating payment link:', error);
  }
}

Important Notes

  • Minimum payment: 0.01 USDC

  • Expiration: Payment links can have expiration times

  • Status tracking: Use webhooks or polling to monitor payment status

  • Off-ramp timing: Bank account destinations take longer due to settlement times

  • Transaction hashes: Stored for audit trails and verification

Last updated