// require('dotenv').config(); const express = require('express'); const axios = require('axios'); const bodyParser = require('body-parser'); const app = express(); const PORT = 7860; // ========================================== // CONFIGURATION // ========================================== // REPLACE THIS WITH YOUR PAYSTACK SECRET KEY const PAYSTACK_SECRET_KEY = 'sk_test_4aa42b4105d33d191eda94d543a2a82ad3c420c7'; // const PAYSTACK_SECRET_KEY = 'sk_live_31c44ef2b81a591d771202b7ffcbcaab765e977e'; // MOCK DATABASE // In a real app, you would save these details to MongoDB, Postgres, etc. let mockUserDB = { email: null, customer_code: null, authorization_code: null, // This is the "Token" to charge the card later last_log: "Server started. Waiting for user input..." }; // Middleware app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); // Helper to log to console and "DB" const log = (msg) => { const timestamp = new Date().toLocaleTimeString(); console.log(`[${timestamp}] ${msg}`); mockUserDB.last_log = `[${timestamp}] ${msg}`; }; // ========================================== // ROUTES // ========================================== // 1. Render the Embedded HTML Interface app.get('/', (req, res) => { // We check if we have a saved token to adjust the UI state const isAuthorized = !!mockUserDB.authorization_code; const html = ` Paystack Card Tokenization Demo

💳 Paystack Recurring Charge Demo

Status: ${isAuthorized ? '✅ Card Authorized' : '❌ No Card stored'}
Customer Email: ${mockUserDB.email || 'N/A'}
Auth Code: ${mockUserDB.authorization_code || 'N/A'}
${!isAuthorized ? `

Step 1: Authorize Card

We will charge a tiny amount (e.g., NGN 50) to authorize the card.

` : `

Step 2: Charge Saved Card

The card is tokenized. You can now charge it anytime without user interaction.



Reset Demo `}

Server Logs

${mockUserDB.last_log}
`; res.send(html); }); // 2. Initialize Transaction (Get Redirect URL) app.post('/initialize', async (req, res) => { const { email } = req.body; // Amount is in Kobo (or lowest currency unit). 5000 kobo = 50 Naira. // Paystack requires a small amount to verify the card (which can be refunded later). const amount = 5000; log(`Initializing transaction for ${email}...`); try { const response = await axios.post('https://api.paystack.co/transaction/initialize', { email: email, amount: amount, // Important: This is where Paystack returns the user after payment callback_url: `https://pepguy-authorize-card.hf.space/callback`, channels: ['card'] // Force card payment to ensure we get an auth token }, { headers: { Authorization: `Bearer ${PAYSTACK_SECRET_KEY}` } }); const authUrl = response.data.data.authorization_url; log(`Redirecting user to Paystack: ${authUrl}`); // Save email temporarily mockUserDB.email = email; // Redirect user to Paystack secure page res.redirect(authUrl); } catch (error) { log(`Error initializing: ${error.response ? error.response.data.message : error.message}`); res.send("Error initializing transaction. Check console."); } }); // 3. Callback (Handle Return from Paystack) app.get('/callback', async (req, res) => { const reference = req.query.reference; // Paystack sends this in the URL log(`Callback received. Verifying reference: ${reference}...`); try { // Verify the transaction to get the Authorization Code const response = await axios.get(`https://api.paystack.co/transaction/verify/${reference}`, { headers: { Authorization: `Bearer ${PAYSTACK_SECRET_KEY}` } }); const data = response.data.data; if (data.status === 'success') { // SUCCESS! We now have the Authorization Code (The Token) const authCode = data.authorization.authorization_code; const customerCode = data.customer.customer_code; const cardType = data.authorization.card_type; const last4 = data.authorization.last4; // Save to "Database" mockUserDB.authorization_code = authCode; mockUserDB.customer_code = customerCode; mockUserDB.email = data.customer.email; log(`SUCCESS! Card authorized. Type: ${cardType} *${last4}. Auth Code: ${authCode}`); } else { log(`Transaction failed or incomplete.`); } } catch (error) { log(`Verification failed: ${error.message}`); } // Redirect back to our main page res.redirect('/'); }); // 4. Charge the Saved Card (Recurring Charge) app.post('/charge-token', async (req, res) => { if (!mockUserDB.authorization_code) { return res.status(400).json({ message: "No card authorized yet." }); } // Amount to charge (e.g., 100 Naira = 10000 kobo) const chargeAmount = 10000; log(`Attempting to charge saved card (Auth: ${mockUserDB.authorization_code}) amount: ${chargeAmount}...`); try { const response = await axios.post('https://api.paystack.co/transaction/charge_authorization', { email: mockUserDB.email, amount: chargeAmount, authorization_code: mockUserDB.authorization_code }, { headers: { Authorization: `Bearer ${PAYSTACK_SECRET_KEY}` } }); const data = response.data.data; if (response.data.status) { log(`CHARGE SUCCESSFUL! Ref: ${data.reference} - Status: ${data.status}`); res.json({ message: "Charge Successful! check logs." }); } else { log(`Charge Failed: ${response.data.message}`); res.json({ message: "Charge Failed." }); } } catch (error) { const errMsg = error.response ? error.response.data.message : error.message; log(`API Error during charge: ${errMsg}`); res.status(500).json({ message: `Error: ${errMsg}` }); } }); // Utility: Get Logs for Frontend app.get('/logs', (req, res) => { res.json({ log: mockUserDB.last_log }); }); // Utility: Reset Demo app.get('/reset', (req, res) => { mockUserDB = { email: null, customer_code: null, authorization_code: null, last_log: "System Reset." }; res.redirect('/'); }); // Start Server app.listen(PORT, () => { console.log(`Server running at http://localhost:${PORT}`); console.log(`Make sure to set your PAYSTACK_SECRET_KEY in code or .env`); });