Embedded Integration — Node.js
Build your own checkout in Node.js — hash, direct sale, 3DS, capture, webhooks.
Embedded Integration lets you collect card data on your website and charge via DigetPay from your Node.js backend. You build the checkout UI — including Apple Pay if needed (separate guide).
PCI DSS: Embedded Integration requires secure handling of card data (SAQ D or equivalent). Prefer Hosted Checkout unless compliance approves embedded card collection.
Never send card data from browser JavaScript directly to DigetPay. Post card fields to your server first, then your server calls the embedded sale APIs.
Prerequisites: Embedded Integration Overview, Sandbox Setup, Node.js 18+ with native
fetch.
Architecture
sequenceDiagram participant Browser as Customer Browser participant Shop as Your Node Server participant API as DigetPay API Browser->>Shop: POST checkout form (card fields) Shop->>Shop: Compute MD5 hash Shop->>API: POST /payment/s2s/sale API-->>Shop: status + html (3DS if needed) Shop->>Browser: Render 3DS or success page API->>Shop: Webhook notification
Step 1 — Configuration
// config/digetpay.js
const env = process.env.DIGETPAY_ENV || 'staging';
const API_BASES = {
staging: 'https://fin-api.digetpay.com/v1',
production: 'https://api.digetpay.com/v1',
};
export const config = {
environment: env,
apiKey: process.env.DIGETPAY_API_KEY || '',
apiBase: API_BASES[env],
};
if (!config.apiKey) throw new Error('DIGETPAY_API_KEY is not set');Step 2 — Hash helper
// src/digetpayHash.js
import crypto from 'crypto';
export function digetpayEmbeddedHash(email, cardNumber, apiKey) {
const card = cardNumber.replace(/\s+/g, '');
const reversedEmail = email.split('').reverse().join('');
const reversedCard = (card.slice(0, 6) + card.slice(-4)).split('').reverse().join('');
const raw = (reversedEmail + apiKey + reversedCard).toUpperCase();
return crypto.createHash('md5').update(raw).digest('hex');
}Full explanation: Request Hash (MD5).
Step 3 — Embedded client
// src/digetpayEmbeddedClient.js
import { config } from '../config/digetpay.js';
import { digetpayEmbeddedHash } from './digetpayHash.js';
async function request(method, path, body) {
const res = await fetch(`${config.apiBase}${path}`, {
method,
headers: { 'Content-Type': 'application/json', 'x-api-key': config.apiKey },
body: body ? JSON.stringify(body) : undefined,
});
const data = await res.json().catch(() => ({}));
if (!res.ok) throw new Error(`DigetPay HTTP ${res.status}: ${JSON.stringify(data)}`);
return data;
}
export function directSale({ order, card, customer, successUrl, failureUrl }) {
const hash = digetpayEmbeddedHash(customer.email, card.cardNumber, config.apiKey);
return request('POST', '/payment/s2s/sale', {
orderId: order.orderId,
amount: order.amount,
currency: order.currency || 'SAR',
paymentMethod: 'card',
auth: order.auth || 'N',
card: {
cardNumber: card.cardNumber.replace(/\s+/g, ''),
cardExpiryMonth: card.cardExpiryMonth,
cardExpiryYear: card.cardExpiryYear,
cardCvv: card.cardCvv,
cardHolder: card.cardHolder,
},
customer,
successUrl,
failureUrl,
hash,
});
}
export function capture(transactionId, amount) {
return request('POST', '/payment/s2s/capture', { transactionId, amount });
}
export function voidTransaction(transactionId) {
return request('POST', '/payment/s2s/void', { transactionId });
}
export function getStatus(transactionId) {
return request('POST', `/payment/s2s/status/${encodeURIComponent(transactionId)}`);
}Step 4 — Process payment route
// routes/payment.js
import express from 'express';
import { directSale } from '../src/digetpayEmbeddedClient.js';
const router = express.Router();
router.post('/process-payment', express.urlencoded({ extended: true }), async (req, res) => {
try {
const result = await directSale({
order: { orderId: req.body.order_id, amount: parseFloat(req.body.amount), auth: 'N' },
card: {
cardNumber: req.body.card_number,
cardExpiryMonth: req.body.exp_month,
cardExpiryYear: req.body.exp_year,
cardCvv: req.body.cvv,
cardHolder: req.body.card_holder,
},
customer: { name: req.body.card_holder, email: req.body.email, phone: req.body.phone },
successUrl: 'https://yourstore.com/payment/3ds-return',
failureUrl: 'https://yourstore.com/payment/failed',
});
const data = result.data ?? result;
const html = data.html ?? data.htmlContent;
if (html) return res.send(html);
if (data.status === 'APPROVED') return res.redirect('/order/complete');
return res.redirect('/payment/failed');
} catch (err) {
console.error(err);
res.status(500).send('Payment failed');
}
});
export default router;For Apple Pay, use a separate button and server flow — Apple Pay Embedded. See Apple Pay Code (Node.js).
Step 5 — Capture, void, and webhooks
import { capture, voidTransaction } from '../src/digetpayEmbeddedClient.js';
await capture('2232e99b-0257-47d5-bbfd-022c8951767f', 10.0);
await voidTransaction('2232e99b-0257-47d5-bbfd-022c8951767f');Webhook handler — see Webhooks Code (Node.js).
Next steps
Updated about 1 month ago
