Skip to main content

Step 1 — Get your API key

  1. Sign up at merchant.gosurge.xyz/register.
  2. After your account is approved, the Surge team enables API access for your account.
  3. Log in to your merchant dashboard, go to Settings → API Keys, and click Generate API Key.
  4. Copy the key immediately — it is shown once. Note your Merchant ID (mer_...) on the same page.
Never hard-code your API key in source files. Use environment variables and never commit them to git.

Step 2 — Create a checkout session (backend)

Your server calls Surge to create a short-lived checkout session tied to the order. Pass the session token to your frontend to open the widget.
const express = require('express');
const { v4: uuidv4 } = require('uuid');

const app = express();

// ⚠️ Register the webhook route BEFORE app.use(express.json())
// so Express does not consume the raw body before signature verification.
// The full handler is defined below — JavaScript hoists function declarations.
app.post('/webhooks/surge', express.raw({ type: 'application/json' }), handleSurgeWebhook);

// Global JSON middleware for all other routes
app.use(express.json());

// --- Checkout session endpoint ---
// Called by your frontend when the customer clicks "Buy Now, Pay Later"
app.post('/api/surge-checkout', async (req, res) => {
  const { amount, title, orderReference, customerEmail } = req.body;

  try {
    const idempotencyKey = uuidv4();

    const response = await fetch('https://api.gosurge.xyz/api/v1/checkout/sessions', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.SURGE_API_KEY}`,
        'Content-Type': 'application/json',
        'Idempotency-Key': idempotencyKey,
      },
      body: JSON.stringify({
        merchant_id: process.env.SURGE_MERCHANT_ID,
        amount,           // in kobo — e.g. 120000 = ₦1,200.00
        currency: 'NGN',
        title,
        order_reference: orderReference,
        customer_email: customerEmail,
      }),
    });

    if (!response.ok) {
      const error = await response.json();
      return res.status(response.status).json({ error: error.detail ?? 'Checkout failed' });
    }

    const { data } = await response.json();
    res.json({ sessionToken: data.session_token });

  } catch (err) {
    res.status(500).json({ error: 'Failed to create checkout session' });
  }
});

app.listen(3000);
Environment variables you need:
.env
SURGE_API_KEY=surge_live_sk_...
SURGE_MERCHANT_ID=mer_...
SURGE_WEBHOOK_SECRET=whsec_...
All amounts are in kobo (Nigerian lowest denomination). ₦1,200.00 = 120000 kobo. Never pass naira values directly — divide by 100 to display to the customer.

Step 3 — Open the widget (frontend)

Once your server returns the sessionToken, open the Surge checkout modal.
import { useCallback } from 'react';

// Add this once to your index.html:
// <script src="https://consumer.gosurge.xyz/surge.js"></script>

export default function BuyNowPayLaterButton({ product }) {
  const handleSurgeCheckout = useCallback(async () => {
    // 1. Ask your backend to create a checkout session
    const res = await fetch('/api/surge-checkout', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        amount: product.priceKobo,       // e.g. 120000 = ₦1,200
        title: product.name,
        orderReference: `ORD-${Date.now()}`,
        customerEmail: product.customerEmail,
      }),
    });

    const { sessionToken, error } = await res.json();
    if (error || !sessionToken) {
      alert('Could not start checkout. Please try again.');
      return;
    }

    // 2. Open the Surge widget
    const surge = window.SurgeConnect.init();
    surge.openCheckout({
      sessionToken,

      onSuccess: ({ paymentPlanId }) => {
        // Plan confirmed — NOT yet charged. Show a pending state.
        window.location.href = `/orders/pending?ref=${paymentPlanId}`;
      },

      onCancel: () => {
        console.log('Customer closed the widget.');
      },

      onError: (err) => {
        console.error('Surge error:', err.message);
      },
    });
  }, [product]);

  return (
    <button onClick={handleSurgeCheckout}>
      Buy Now, Pay Later with Surge
    </button>
  );
}
onSuccess fires when the customer confirms the plan, not when their deposit is charged. Always use the payment.success webhook (Step 4) as your trigger to fulfill the order.

Step 4 — Listen for webhooks

Surge sends a payment.success event to your configured webhook URL after the deposit is collected and the plan is activated.

Configure your webhook URL

In your merchant dashboard go to Settings → Webhooks and enter your endpoint URL. Set a strong random string as your Webhook Secret and save it to your SURGE_WEBHOOK_SECRET env var.

Handle the event

Node.js
// ⚠️ This function must be declared BEFORE app.use(express.json()) is called,
// and the route is registered at the top of the file (see Step 2).
// JavaScript function declarations are hoisted, so this works even though
// it appears later in the file.

const crypto = require('crypto');

function handleSurgeWebhook(req, res) {
  const signature = req.headers['x-surge-signature'];
  const expected = crypto
    .createHmac('sha256', process.env.SURGE_WEBHOOK_SECRET)
    .update(req.body)  // req.body is a Buffer when using express.raw()
    .digest('hex');

  // timingSafeEqual throws if buffers differ in length, so check first
  const sigBuf = Buffer.from(signature ?? '');
  const expBuf = Buffer.from(expected);
  if (sigBuf.length !== expBuf.length || !crypto.timingSafeEqual(expBuf, sigBuf)) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(req.body.toString());

  if (event.eventType === 'payment.success') {
    const { orderReference, resourceId } = event.data;
    // ✅ Safe to fulfill the order now
    fulfillOrder(orderReference, resourceId);
  }

  res.status(200).send('OK');
}
Surge signs outbound webhooks with HMAC-SHA256 using your webhook_secret. The header is X-Surge-Signature. Return 200 OK immediately and process fulfillment asynchronously to avoid retry storms.
See the Webhooks guide for all event types and retry behaviour.

You’re done

StepWhat you built
Step 1Merchant account + API key
Step 2Server endpoint that creates a checkout session
Step 3Frontend button that opens the Surge widget
Step 4Webhook handler to fulfill orders after payment
Next steps: