Skip to main content

Your First Payment

A step-by-step walkthrough of creating and processing your first Pelago payment.

What We'll Build

A complete payment flow that:

  1. Creates a payment request
  2. Displays a QR code for the customer
  3. Handles the payment webhook
  4. Confirms the successful payment

Prerequisites

  • Completed SDK installation (Quick Start)
  • Sandbox environment configured (Sandbox Setup)
  • A basic web server (Node.js/Express example below)

Full Example: Express.js Payment Server

import express from 'express';
import { PelagoClient } from '@pelago/sdk';

const app = express();
app.use(express.json());

// Initialize Pelago client
const pelago = new PelagoClient({
apiKey: process.env.PELAGO_API_KEY!,
apiSecret: process.env.PELAGO_API_SECRET!,
environment: 'sandbox'
});

// Store pending orders (use a database in production)
const orders = new Map<string, { status: string; amount: number }>();

// 1. Create a new order and payment
app.post('/api/checkout', async (req, res) => {
const { productId, email } = req.body;

// Create your order
const orderId = `order_${Date.now()}`;
const amount = 25.00; // Product price

orders.set(orderId, { status: 'pending', amount });

try {
// Create Pelago payment
const payment = await pelago.payments.create({
amount,
currency: 'USD',
cryptocurrency: 'USDC',
network: 'stellar-testnet',
merchantWallet: process.env.MERCHANT_WALLET!,
redirectUrl: `${process.env.APP_URL}/order/${orderId}/success`,
webhookUrl: `${process.env.APP_URL}/api/webhook`,
metadata: {
orderId,
customerEmail: email,
productId
}
});

res.json({
orderId,
paymentId: payment.id,
paymentUrl: payment.url,
qrCode: payment.qrCode,
expiresAt: payment.expiresAt
});

} catch (error) {
console.error('Payment creation failed:', error);
res.status(500).json({ error: 'Failed to create payment' });
}
});

// 2. Check payment/order status
app.get('/api/orders/:orderId', (req, res) => {
const order = orders.get(req.params.orderId);

if (!order) {
return res.status(404).json({ error: 'Order not found' });
}

res.json(order);
});

// 3. Handle Pelago webhooks
app.post('/api/webhook', async (req, res) => {
const signature = req.headers['x-pelago-signature'] as string;

// Verify the webhook signature
if (!pelago.webhooks.verify(req.body, signature)) {
console.warn('Invalid webhook signature');
return res.status(401).json({ error: 'Invalid signature' });
}

const event = req.body;
const { orderId } = event.data.metadata;

console.log(`Received webhook: ${event.type} for order ${orderId}`);

switch (event.type) {
case 'payment.completed':
// Update order status
const order = orders.get(orderId);
if (order) {
order.status = 'paid';
orders.set(orderId, order);
}

// Trigger fulfillment (send email, ship product, etc.)
console.log(`✅ Order ${orderId} paid successfully!`);
break;

case 'payment.failed':
const failedOrder = orders.get(orderId);
if (failedOrder) {
failedOrder.status = 'failed';
orders.set(orderId, failedOrder);
}
console.log(`❌ Order ${orderId} payment failed`);
break;

case 'payment.expired':
const expiredOrder = orders.get(orderId);
if (expiredOrder) {
expiredOrder.status = 'expired';
orders.set(orderId, expiredOrder);
}
console.log(`⏱️ Order ${orderId} payment expired`);
break;
}

// Always respond with 200 to acknowledge receipt
res.status(200).json({ received: true });
});

// Start server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});

Testing Your Integration

1. Start Your Server

# Set environment variables
export PELAGO_API_KEY=test_pk_xxxxx
export PELAGO_API_SECRET=test_sk_xxxxx
export MERCHANT_WALLET=GXXXXX...
export APP_URL=https://your-ngrok-url.ngrok.io

# Start the server
npx ts-node server.ts

2. Expose Webhooks with ngrok

ngrok http 3000
# Copy the https:// URL

3. Create a Test Order

curl -X POST http://localhost:3000/api/checkout \
-H "Content-Type: application/json" \
-d '{"productId": "prod_123", "email": "[email protected]"}'

Response:

{
"orderId": "order_1707401234567",
"paymentId": "pay_abc123",
"paymentUrl": "https://pay.sandbox.pelago.tech/pay_abc123",
"qrCode": "data:image/png;base64,...",
"expiresAt": "2025-02-08T22:30:00Z"
}

4. Complete the Payment

  1. Open the paymentUrl in your browser
  2. Connect your test wallet
  3. Approve the test USDC transfer
  4. Watch your webhook receive the payment.completed event

5. Verify the Order Status

curl http://localhost:3000/api/orders/order_1707401234567
{
"status": "paid",
"amount": 25.00
}

Payment Flow Visualization

Common Issues

Webhook Not Received

  1. Ensure your webhook URL is publicly accessible
  2. Check ngrok logs for incoming requests
  3. Verify webhook URL doesn't have typos

Payment Creation Fails

  1. Check API key environment variable
  2. Verify wallet address format
  3. Ensure you're using the correct network

Signature Verification Fails

  1. Use raw request body (not parsed)
  2. Ensure x-pelago-signature header is present
  3. Pass correct API secret to verify function

Next Steps

Now that you've processed your first payment: