Skip to main content

Overview

This guide walks you through creating a complete payment flow: initializing a transaction, redirecting the customer to pay, and verifying the payment.
This guide uses test mode. Remember to switch to live keys when you’re ready to accept real payments.

Prerequisites

Before starting, make sure you have:

Step 1: Initialize the SDK

First, import and initialize the Paystack SDK with your secret key:
index.ts
import { Paystack } from '@efobi/paystack';

// Initialize with your secret key
const paystack = new Paystack(process.env.PAYSTACK_SECRET_KEY!);
The SDK automatically validates your secret key format. It must start with sk_test_ or sk_live_.

Step 2: Initialize a Transaction

To accept a payment, first initialize a transaction. This creates a payment session and returns an authorization URL:
initialize.ts
const result = await paystack.transaction.initialize({
  email: 'customer@email.com',
  amount: '50000', // Amount in kobo (₦500.00)
  currency: 'NGN' // Optional, defaults to NGN
});

if (result.error) {
  console.error('Validation error:', result.error.flatten());
} else if (result.data) {
  console.log('Authorization URL:', result.data.data.authorization_url);
  console.log('Reference:', result.data.data.reference);
  console.log('Access Code:', result.data.data.access_code);
  
  // Redirect customer to result.data.data.authorization_url
}
Amounts in Paystack are specified in the smallest currency unit (kobo for NGN, cents for USD). To charge ₦500.00, pass 50000.

Understanding the Response

The initialize method returns:
  • authorization_url - Redirect your customer here to complete payment
  • access_code - Alternative payment access code
  • reference - Unique transaction reference (auto-generated if not provided)

Custom Transaction Options

You can customize the transaction with additional parameters:
advanced-initialize.ts
const result = await paystack.transaction.initialize({
  email: 'customer@email.com',
  amount: '50000',
  currency: 'NGN',
  reference: 'ORDER_12345', // Your own unique reference
  callback_url: 'https://yoursite.com/verify', // Redirect after payment
  metadata: {
    custom_fields: [
      {
        display_name: 'Order ID',
        variable_name: 'order_id',
        value: 'ORDER_12345'
      }
    ]
  },
  channels: ['card', 'bank_transfer'], // Limit payment methods
  split_code: 'SPL_xxx' // For split payments
});

Step 3: Verify the Transaction

After the customer completes payment, verify the transaction using the reference:
verify.ts
const reference = 'your_transaction_reference';

const result = await paystack.transaction.verify(reference);

if (result.error) {
  console.error('Verification failed:', result.error.flatten());
} else if (result.data) {
  const transaction = result.data.data;
  
  console.log('Status:', transaction.status); // 'success', 'failed', or 'abandoned'
  console.log('Amount:', transaction.amount);
  console.log('Customer:', transaction.customer.email);
  console.log('Paid at:', transaction.paidAt);
  
  if (transaction.status === 'success') {
    // Payment successful - fulfill order
    console.log('✅ Payment verified successfully!');
  }
}
Always verify transactions on your server, not in client-side code. Never trust payment status from the client.

Complete Example

Here’s a complete example combining initialization and verification:
import express from 'express';
import { Paystack } from '@efobi/paystack';

const app = express();
const paystack = new Paystack(process.env.PAYSTACK_SECRET_KEY!);

app.use(express.json());

// Initialize payment
app.post('/api/payment/initialize', async (req, res) => {
  try {
    const { email, amount } = req.body;
    
    const result = await paystack.transaction.initialize({
      email,
      amount,
      callback_url: `${req.protocol}://${req.get('host')}/api/payment/verify`
    });
    
    if (result.error) {
      return res.status(400).json({ error: result.error.flatten() });
    }
    
    res.json({
      authorization_url: result.data?.data.authorization_url,
      reference: result.data?.data.reference
    });
  } catch (error) {
    res.status(500).json({ error: 'Payment initialization failed' });
  }
});

// Verify payment
app.get('/api/payment/verify', async (req, res) => {
  try {
    const { reference } = req.query;
    
    if (!reference || typeof reference !== 'string') {
      return res.status(400).json({ error: 'Reference is required' });
    }
    
    const result = await paystack.transaction.verify(reference);
    
    if (result.error) {
      return res.status(400).json({ error: result.error.flatten() });
    }
    
    const transaction = result.data?.data;
    
    if (transaction?.status === 'success') {
      // Fulfill order here
      res.json({ message: 'Payment verified', transaction });
    } else {
      res.status(400).json({ message: 'Payment not successful' });
    }
  } catch (error) {
    res.status(500).json({ error: 'Verification failed' });
  }
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Expected Output

When you initialize a transaction, you’ll get a response like:
{
  "status": true,
  "message": "Authorization URL created",
  "data": {
    "authorization_url": "https://checkout.paystack.com/xxxxx",
    "access_code": "xxxxx",
    "reference": "xxxxx"
  }
}
After verification, a successful payment returns:
{
  "status": true,
  "message": "Verification successful",
  "data": {
    "status": "success",
    "reference": "xxxxx",
    "amount": 50000,
    "currency": "NGN",
    "customer": {
      "email": "customer@email.com",
      "customer_code": "CUS_xxxxx"
    },
    "paidAt": "2024-01-15T10:30:00.000Z"
  }
}

Error Handling

The SDK provides structured error handling:
error-handling.ts
try {
  const result = await paystack.transaction.verify('invalid_reference');
  
  if (result.error) {
    // Validation or API error
    console.error('Validation errors:', result.error.flatten());
    
    // Access specific errors
    result.error.issues.forEach(issue => {
      console.error(`${issue.path}: ${issue.message}`);
    });
  } else if (result.data) {
    // Success
    console.log('Transaction:', result.data);
  }
} catch (error) {
  // Network or unexpected errors
  console.error('Unexpected error:', error.message);
}

Testing Your Integration

1

Use test credentials

Always use test keys (sk_test_...) during development.
2

Test with Paystack test cards

Paystack provides test card numbers:
  • Success: 4084 0840 8408 4081 (CVV: any 3 digits)
  • Insufficient funds: 5060 6666 6666 6666
3

Verify on your server

Never rely on client-side verification alone.
4

Test error scenarios

Test failed payments, abandoned transactions, and network errors.

Next Steps

Now that you’ve completed your first integration, explore more features:

Common Patterns

Generating Custom References

function generateReference(prefix: string): string {
  const timestamp = Date.now();
  const random = Math.random().toString(36).substring(2, 9);
  return `${prefix}_${timestamp}_${random}`;
}

const result = await paystack.transaction.initialize({
  email: 'customer@email.com',
  amount: '50000',
  reference: generateReference('ORDER')
});

Handling Webhook Verification

app.post('/webhooks/paystack', express.raw({ type: 'application/json' }), async (req, res) => {
  const signature = req.headers['x-paystack-signature'];
  const rawBody = req.body.toString('utf-8');
  
  try {
    await paystack.webhook.process(rawBody, signature);
    res.sendStatus(200);
  } catch (error) {
    res.sendStatus(400);
  }
});

paystack.webhook.on('charge.success', (data) => {
  console.log('Payment received:', data.reference);
  // Fulfill order
});

Retry Logic for Verification

async function verifyWithRetry(reference: string, maxRetries = 3): Promise<any> {
  for (let i = 0; i < maxRetries; i++) {
    const result = await paystack.transaction.verify(reference);
    
    if (result.data) {
      return result.data;
    }
    
    // Wait before retry
    await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
  }
  
  throw new Error('Verification failed after retries');
}

Getting Help