Integrating 4Geeks Payments API into a Node.js Application¶
Overview¶
4Geeks Payments is a Merchant of Record (MoR) platform that handles the entire transaction lifecycle β from accepting payments to managing subscriptions, tax compliance, and fraud prevention. This tutorial shows you how to integrate the 4Geeks Payments REST API into a Node.js application.
In this tutorial, you will:
- Set up your 4Geeks Payments account and get API keys
- Create a charge (one-time payment)
- Create and manage customers
- Generate payment links
- Handle webhooks for payment events
- Process refunds
Prerequisites¶
- An activated 4Geeks Payments account (activate service)
- Node.js 18+ installed
- npm or yarn package manager
- Basic understanding of REST APIs and Express.js
Step 1: Get Your API Keys¶
- Log in to console.4geeks.io
- Navigate to Payments β Settings β API Keys
- Click “Generate API Key”
- Copy and securely store your:
- Public Key (for client-side operations)
- Secret Key (for server-side operations β never expose this)
Important: Use sandbox keys for testing. Switch to production keys when you’re ready to go live.
Step 2: Set Up Your Project¶
Create your project structure:
my-payment-app/
βββ .env
βββ server.js
βββ routes/
β βββ payments.js
βββ package.json
Step 3: Configure Environment Variables¶
Create a .env file:
FOURGEEKS_PAYMENTS_SECRET_KEY=sk_test_your_secret_key_here
FOURGEEKS_PAYMENTS_PUBLIC_KEY=pk_test_your_public_key_here
FOURGEEKS_PAYMENTS_API_URL=https://api.4geeks.io/v1
PORT=3000
Step 4: Create the Express Server¶
Create server.js:
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const paymentRoutes = require('./routes/payments');
const app = express();
app.use(cors());
app.use(express.json());
app.use('/api/payments', paymentRoutes);
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Step 5: Create Payment Routes¶
Create routes/payments.js:
const express = require('express');
const axios = require('axios');
const router = express.Router();
const API_URL = process.env.FOURGEEKS_PAYMENTS_API_URL;
const SECRET_KEY = process.env.FOURGEEKS_PAYMENTS_SECRET_KEY;
const api = axios.create({
baseURL: API_URL,
headers: {
'Authorization': `Bearer ${SECRET_KEY}`,
'Content-Type': 'application/json',
},
});
// Create a one-time charge
router.post('/charges', async (req, res) => {
try {
const { amount, currency, customer_id, description } = req.body;
const response = await api.post('/charges', {
amount, // Amount in cents (e.g., 1000 = $10.00)
currency, // e.g., 'USD', 'EUR', 'CRC'
customer_id, // Existing customer ID or create new
description,
capture: true, // Auto-capture the charge
});
res.json({ success: true, charge: response.data });
} catch (error) {
console.error('Charge error:', error.response?.data || error.message);
res.status(error.response?.status || 500).json({
success: false,
error: error.response?.data || 'Failed to create charge',
});
}
});
// Create a customer
router.post('/customers', async (req, res) => {
try {
const { email, name, phone, metadata } = req.body;
const response = await api.post('/customers', {
email,
name,
phone,
metadata, // Optional: custom key-value pairs
});
res.json({ success: true, customer: response.data });
} catch (error) {
res.status(error.response?.status || 500).json({
success: false,
error: error.response?.data || 'Failed to create customer',
});
}
});
// Generate a payment link
router.post('/payment-links', async (req, res) => {
try {
const { amount, currency, description, customer_email, success_url, cancel_url } = req.body;
const response = await api.post('/payment-links', {
amount,
currency,
description,
customer_email,
success_url, // Redirect after successful payment
cancel_url, // Redirect if customer cancels
});
res.json({ success: true, payment_link: response.data });
} catch (error) {
res.status(error.response?.status || 500).json({
success: false,
error: error.response?.data || 'Failed to create payment link',
});
}
});
// Process a refund
router.post('/charges/:charge_id/refund', async (req, res) => {
try {
const { charge_id } = req.params;
const { amount, reason } = req.body;
const response = await api.post(`/charges/${charge_id}/refunds`, {
amount, // Optional: partial refund (in cents). Omit for full refund
reason, // e.g., 'duplicate', 'fraudulent', 'requested_by_customer'
});
res.json({ success: true, refund: response.data });
} catch (error) {
res.status(error.response?.status || 500).json({
success: false,
error: error.response?.data || 'Failed to process refund',
});
}
});
// Get charge details
router.get('/charges/:charge_id', async (req, res) => {
try {
const { charge_id } = req.params;
const response = await api.get(`/charges/${charge_id}`);
res.json({ success: true, charge: response.data });
} catch (error) {
res.status(error.response?.status || 500).json({
success: false,
error: error.response?.data || 'Failed to get charge',
});
}
});
module.exports = router;
Step 6: Handle Webhooks¶
Webhooks notify your server about payment events (successful charges, failed payments, refunds, etc.).
Add to server.js:
// Webhook endpoint
app.post('/webhooks/payments', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-4geeks-signature'];
const payload = req.body;
// Verify webhook signature (implement verification logic)
// const isValid = verifyWebhookSignature(payload, signature);
// if (!isValid) return res.status(401).send('Invalid signature');
const event = JSON.parse(payload);
switch (event.type) {
case 'charge.succeeded':
console.log('Payment successful:', event.data.charge_id);
// Update order status, send confirmation email, etc.
break;
case 'charge.failed':
console.log('Payment failed:', event.data.charge_id);
// Notify customer, retry logic, etc.
break;
case 'refund.completed':
console.log('Refund processed:', event.data.refund_id);
// Update order status, notify customer, etc.
break;
case 'subscription.created':
console.log('New subscription:', event.data.subscription_id);
// Activate subscription, send welcome email, etc.
break;
default:
console.log('Unhandled event type:', event.type);
}
res.json({ received: true });
});
Step 7: Test Your Integration¶
Start the server:
Test with curl:
# Create a customer
curl -X POST http://localhost:3000/api/payments/customers \
-H "Content-Type: application/json" \
-d '{"email": "test@example.com", "name": "John Doe"}'
# Create a charge
curl -X POST http://localhost:3000/api/payments/charges \
-H "Content-Type: application/json" \
-d '{"amount": 1000, "currency": "USD", "customer_id": "cus_xxx", "description": "Test charge"}'
# Generate a payment link
curl -X POST http://localhost:3000/api/payments/payment-links \
-H "Content-Type: application/json" \
-d '{"amount": 2500, "currency": "USD", "description": "Premium Plan", "success_url": "https://yoursite.com/success", "cancel_url": "https://yoursite.com/cancel"}'
Testing Cards¶
Use these test cards in sandbox mode:
| Card Number | Result |
|---|---|
| 4242 4242 4242 4242 | Successful payment |
| 4000 0000 0000 9995 | Declined (insufficient funds) |
| 4000 0000 0000 0002 | Requires 3D Secure authentication |
| 4000 0000 0000 0010 | Requires CVC verification |
Best Practices¶
Security¶
- Never expose your secret key in client-side code
- Use environment variables for all credentials
- Verify webhook signatures to prevent spoofed events
- Implement idempotency keys for charge creation to prevent duplicates
Error Handling¶
- Always check
error.response?.datafor detailed error messages - Implement retry logic for transient failures
- Log all payment events for auditing
- Handle 3D Secure redirects gracefully
Compliance¶
- 4Geeks Payments is PCI DSS compliant β card data never touches your servers
- Tax compliance is handled automatically (VAT, sales tax, GST)
- As Merchant of Record, 4Geeks handles chargeback liability
What’s Next?¶
- Learn about Recurring Subscription Billing
- Explore 3D Secure Implementation
- Read about Multi-Currency Checkout
- Check the full API Reference
Need Help?¶
- Documentation: docs.4geeks.io/en/payments
- API Reference: docs.4geeks.io/en/api
- Community: community.4geeks.io
- Support: Available through the console dashboard
Still questions? Ask the community.