Node.js Examples
Complete Node.js examples for integrating with the Pixlpay API.
API Client Class
javascript
const axios = require('axios');
const crypto = require('crypto');
class PixlpayClient {
constructor(storeUrl, token) {
this.client = axios.create({
baseURL: `${storeUrl.replace(/\/$/, '')}/api/external/v1`,
headers: {
'Authorization': `Bearer ${token}`,
'Accept': 'application/json',
'Content-Type': 'application/json',
},
timeout: 30000,
});
this.client.interceptors.response.use(
response => response.data,
error => {
if (error.response) {
const { data, status } = error.response;
throw new PixlpayError(
data.message || 'Unknown error',
data.error || 'UNKNOWN',
status,
data.errors
);
}
throw error;
}
);
}
// Products
async getProducts(params = {}) {
return this.client.get('/products', { params });
}
async getProduct(id) {
return this.client.get(`/products/${id}`);
}
// Orders
async getOrders(params = {}) {
return this.client.get('/orders', { params });
}
async getOrder(id) {
return this.client.get(`/orders/${id}`);
}
async fulfillOrder(id) {
return this.client.post(`/orders/${id}/fulfill`);
}
// Customers
async getCustomers(params = {}) {
return this.client.get('/customers', { params });
}
async getCustomer(id) {
return this.client.get(`/customers/${id}`);
}
// Analytics
async getRevenueAnalytics(params = {}) {
return this.client.get('/analytics/revenue', { params });
}
async getSalesAnalytics(params = {}) {
return this.client.get('/analytics/sales', { params });
}
// Webhooks
async getWebhooks() {
return this.client.get('/webhooks');
}
async createWebhook(url, events) {
return this.client.post('/webhooks', { url, events });
}
async deleteWebhook(id) {
return this.client.delete(`/webhooks/${id}`);
}
}
class PixlpayError extends Error {
constructor(message, code, status, errors = null) {
super(message);
this.name = 'PixlpayError';
this.code = code;
this.status = status;
this.errors = errors;
}
isValidationError() {
return this.code === 'VALIDATION_ERROR';
}
isRateLimited() {
return this.status === 429;
}
}
module.exports = { PixlpayClient, PixlpayError };Usage Examples
List Products
javascript
const { PixlpayClient } = require('./pixlpay');
const client = new PixlpayClient(
process.env.PIXLPAY_STORE_URL,
process.env.PIXLPAY_API_TOKEN
);
async function listProducts() {
try {
const response = await client.getProducts({
is_active: true,
per_page: 50,
});
for (const product of response.data) {
console.log(`${product.name} - $${product.price}`);
}
} catch (error) {
console.error('Error:', error.message);
}
}
listProducts();Fulfill an Order
javascript
async function fulfillOrder(orderId) {
try {
const result = await client.fulfillOrder(orderId);
console.log(`Order ${result.data.order_number} fulfilled!`);
} catch (error) {
if (error.code === 'ORDER_ALREADY_COMPLETED') {
console.log('Order was already completed');
} else {
console.error('Error:', error.message);
}
}
}Get All Orders with Pagination
javascript
async function getAllOrders() {
const allOrders = [];
let page = 1;
let hasMore = true;
while (hasMore) {
const response = await client.getOrders({
page,
per_page: 100,
payment_status: 'paid',
});
allOrders.push(...response.data);
hasMore = page < response.meta.last_page;
page++;
}
return allOrders;
}Express Webhook Handler
javascript
const express = require('express');
const crypto = require('crypto');
const app = express();
// Use raw body for signature verification
app.use('/webhooks/pixlpay', express.raw({ type: 'application/json' }));
function verifySignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}
app.post('/webhooks/pixlpay', async (req, res) => {
const signature = req.headers['x-webhook-signature'];
const secret = process.env.PIXLPAY_WEBHOOK_SECRET;
// Verify signature
if (!verifySignature(req.body, signature, secret)) {
console.error('Invalid webhook signature');
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(req.body);
console.log(`Received: ${event.event_type} (${event.id})`);
// Respond immediately
res.status(200).json({ status: 'received' });
// Process asynchronously
try {
await processEvent(event);
} catch (error) {
console.error('Error processing webhook:', error);
}
});
async function processEvent(event) {
switch (event.event_type) {
case 'order.paid':
await handleOrderPaid(event.data);
break;
case 'order.refunded':
await handleOrderRefunded(event.data);
break;
case 'subscription.created':
await handleSubscriptionCreated(event.data);
break;
case 'subscription.cancelled':
await handleSubscriptionCancelled(event.data);
break;
default:
console.log(`Unhandled event: ${event.event_type}`);
}
}
async function handleOrderPaid(data) {
const { order_id, customer_email, items } = data;
for (const item of items) {
await deliverItem(customer_email, item);
}
console.log(`Delivered order ${order_id} to ${customer_email}`);
}
async function handleOrderRefunded(data) {
console.log(`Refund processed for order ${data.order_id}`);
}
async function handleSubscriptionCreated(data) {
console.log(`Subscription ${data.plan_name} created`);
}
async function handleSubscriptionCancelled(data) {
console.log(`Subscription ${data.subscription_id} cancelled`);
}
async function deliverItem(email, item) {
// Implement your delivery logic
}
app.listen(3000, () => {
console.log('Webhook server running on port 3000');
});TypeScript Types
typescript
interface Product {
id: number;
name: string;
description: string;
price: string;
type: 'digital' | 'physical' | 'subscription';
is_active: boolean;
category?: {
id: number;
name: string;
};
images: Array<{
id: number;
url: string;
is_primary: boolean;
}>;
created_at: string;
updated_at: string;
}
interface Order {
id: number;
order_number: string;
status: 'pending' | 'processing' | 'completed' | 'cancelled';
payment_status: 'pending' | 'paid' | 'failed' | 'refunded';
total: string;
currency: string;
customer_email: string;
customer_name: string;
items: OrderItem[];
created_at: string;
updated_at: string;
}
interface OrderItem {
id: number;
product_id: number;
product_name: string;
quantity: number;
price: string;
total: string;
}
interface WebhookEvent {
id: string;
event_type: string;
created_at: string;
data: Record<string, unknown>;
}
interface PaginatedResponse<T> {
success: boolean;
data: T[];
meta: {
current_page: number;
last_page: number;
per_page: number;
total: number;
};
}Using with Queue (Bull)
javascript
const Queue = require('bull');
const webhookQueue = new Queue('pixlpay-webhooks');
// In webhook handler
app.post('/webhooks/pixlpay', async (req, res) => {
// Verify signature...
const event = JSON.parse(req.body);
// Add to queue
await webhookQueue.add(event, {
attempts: 3,
backoff: {
type: 'exponential',
delay: 1000,
},
});
res.status(200).json({ status: 'queued' });
});
// Process queue
webhookQueue.process(async (job) => {
const event = job.data;
await processEvent(event);
});
webhookQueue.on('failed', (job, err) => {
console.error(`Job ${job.id} failed:`, err);
});