# Utilities

Helper functions for common operations like fee calculations and webhook verification.


# Fee Calculations

# getSplitAmount

Calculate fee and net amounts from satoshis:

import { getSplitAmount } from '@hivepay/client';

const grossAmount = 10500n;  // 10.500 HIVE/HBD in satoshis
const feePercent = 1.5;

const { fee, net } = getSplitAmount(grossAmount, feePercent);

console.log('Gross:', grossAmount); // 10500n
console.log('Fee:', fee);           // 158n (0.158)
console.log('Net:', net);           // 10342n (10.342)

# Parameters

Parameter Type Description
amount bigint Amount in satoshis
percentFee number Fee percentage (e.g., 1.5)

# Returns

Field Type Description
fee bigint Fee amount in satoshis
net bigint Net amount in satoshis

# getSplitAmountFromFormatted

Calculate from decimal string:

import { getSplitAmountFromFormatted } from '@hivepay/client';

const grossAmount = '10.500';  // Decimal format
const feePercent = 1.5;

const { fee, net } = getSplitAmountFromFormatted(grossAmount, feePercent);

console.log('Fee:', fee);   // 158n
console.log('Net:', net);   // 10342n

# formatSatoshis

Convert satoshis to readable decimal string:

import { formatSatoshis } from '@hivepay/client';

console.log(formatSatoshis(10500n));     // "10.500"
console.log(formatSatoshis(10500n, 2));  // "10.50"
console.log(formatSatoshis(158n));       // "0.158"
console.log(formatSatoshis(1n));         // "0.001"

# Parameters

Parameter Type Default Description
satoshis bigint - Amount in satoshis
precision number 3 Decimal places

# Webhook Verification

# verifyWebhook

Verify webhook signature and parse payload:

import { HivePay } from '@hivepay/client';

const hivepay = new HivePay({ apiKey: 'sk_live_xxx' });

async function handleWebhook(req: Request) {
  const result = await hivepay.verifyWebhook({
    payload: await req.text(),
    signature: req.headers.get('X-HivePay-Signature')!,
    timestamp: req.headers.get('X-HivePay-Timestamp')!,
    maxAge: 300000  // 5 minutes (optional)
  });

  if (!result.valid) {
    console.error('Invalid webhook:', result.error);
    return new Response('Unauthorized', { status: 401 });
  }

  // Access verified event
  const { event } = result;
  console.log('Event type:', event.type);
  console.log('Payment ID:', event.data.paymentId);
  console.log('Status:', event.data.status);

  return new Response('OK');
}

# Parameters

Parameter Type Required Description
payload string Yes Raw request body
signature string Yes X-HivePay-Signature header
timestamp string Yes X-HivePay-Timestamp header
maxAge number No Max age in ms (default: 300000)

# Returns

// Success
{ valid: true, event: WebhookEvent }

// Failure
{ valid: false, error: string }

# createTestWebhook

Generate test webhook signatures for development:

import { HivePay } from '@hivepay/client';

const hivepay = new HivePay({ apiKey: 'sk_test_xxx' });

// Create test webhook
const { signature, timestamp, body } = await hivepay.createTestWebhook({
  type: 'payment.status_changed',
  data: {
    paymentId: 'pay_test_123',
    status: 'completed'
  }
});

// Send to your endpoint
const response = await fetch('http://localhost:3000/webhooks/hivepay', {
  method: 'POST',
  headers: {
    'X-HivePay-Signature': signature,
    'X-HivePay-Timestamp': timestamp,
    'Content-Type': 'application/json'
  },
  body
});

# Type Guards

# isHivePayError

Check if an error is a HivePay error:

import { isHivePayError } from '@hivepay/client';

try {
  await hivepay.payments.get('invalid-id');
} catch (error) {
  if (isHivePayError(error)) {
    // TypeScript knows this is HivePayError
    console.log(error.code);
    console.log(error.statusCode);

    // Use type guards
    if (error.isNotFound()) {
      // Handle 404
    }
  }
}

# Examples

# Display Price Breakdown

import { getSplitAmount, formatSatoshis } from '@hivepay/client';

function displayPriceBreakdown(
  amount: bigint,
  feePercent: number,
  currency: 'HIVE' | 'HBD'
) {
  const { fee, net } = getSplitAmount(amount, feePercent);

  return {
    total: `${formatSatoshis(amount)} ${currency}`,
    fee: `${formatSatoshis(fee)} ${currency}`,
    youReceive: `${formatSatoshis(net)} ${currency}`
  };
}

const breakdown = displayPriceBreakdown(10500n, 1.5, 'HBD');
// {
//   total: '10.500 HBD',
//   fee: '0.158 HBD',
//   youReceive: '10.342 HBD'
// }

# Webhook Handler with Full Validation

import { HivePay, isHivePayError } from '@hivepay/client';

const hivepay = new HivePay({ apiKey: process.env.HIVEPAY_API_KEY! });

export async function POST(req: Request) {
  // Extract headers
  const signature = req.headers.get('X-HivePay-Signature');
  const timestamp = req.headers.get('X-HivePay-Timestamp');

  if (!signature || !timestamp) {
    return new Response('Missing headers', { status: 400 });
  }

  // Verify webhook
  const result = await hivepay.verifyWebhook({
    payload: await req.text(),
    signature,
    timestamp
  });

  if (!result.valid) {
    return new Response(result.error, { status: 401 });
  }

  // Handle event
  const { event } = result;

  if (event.type === 'payment.status_changed') {
    const { paymentId, status } = event.data;

    try {
      // Fetch full payment details
      const payment = await hivepay.payments.get(paymentId);

      if (status === 'completed') {
        await fulfillOrder(payment);
      }
    } catch (error) {
      if (isHivePayError(error) && error.isNotFound()) {
        console.warn('Payment not found:', paymentId);
      }
      throw error;
    }
  }

  return new Response('OK');
}