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": "test@example.com"}'

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: