SADAD Payment Gateway Integration for Shopify Stores

    SADAD Payment Gateway Integration for Shopify Stores

    345 views
    software

    Open source Shopify integration template for SADAD Payment Gateway. Node.js custom payment app for Qatar Shopify merchants.

    Louis Innovations has released an open source Shopify integration template that enables Qatar-based merchants to accept SADAD payments directly within their Shopify stores. This Node.js custom payment app connects Shopify's checkout system to the SADAD Payment Gateway, supporting both card payments and QPay, the national Qatar mobile payment scheme.

    Building the Custom Payment App

    Shopify does not include SADAD as a built-in payment provider, so integration requires a custom payment app built with Shopify's Payment Extensibility framework. The app acts as a bridge between Shopify's checkout and the SADAD API:

    const express = require('express');
    const { Shopify } = require('@shopify/shopify-api');
    const SadadClient = require('@louisinnovations/sadad-node');
    
    const app = express();
    const sadad = new SadadClient({
      merchantId: process.env.SADAD_MERCHANT_ID,
      apiKey: process.env.SADAD_API_KEY,
      environment: process.env.SADAD_ENV || 'sandbox',
    });
    
    app.post('/payments/initiate', async (req, res) => {
      try {
        const { amount, currency, orderId, returnUrl } = req.body;
        const transaction = await sadad.createTransaction({
          amount,
          currency: currency || 'QAR',
          orderId,
          callbackUrl: `${process.env.APP_URL}/payments/callback`,
          customerId: req.body.customer.email,
        });
        res.json({ redirectUrl: transaction.paymentUrl, transactionId: transaction.id });
      } catch (error) {
        res.status(500).json({ error: error.message });
      }
    });
    

    Webhook Handling for Payment Callbacks

    The SADAD gateway sends asynchronous payment notifications to a callback URL configured in the merchant dashboard. Your Shopify app must handle these webhooks to update order status:

    app.post('/payments/callback', async (req, res) => {
      const { transactionId, status, signature } = req.body;
    
      if (!sadad.verifySignature(signature, req.body)) {
        return res.status(403).json({ error: 'Invalid signature' });
      }
    
      const shopifyClient = new Shopify.Clients.Rest(
        req.session.shop,
        process.env.SHOPIFY_ACCESS_TOKEN
      );
    
      if (status === 'SUCCESS') {
        await shopifyClient.post({
          path: `orders/${req.body.orderId}/transactions`,
          data: {
            transaction: {
              kind: 'sale',
              status: 'success',
              gateway: 'sadad',
              amount: req.body.amount,
            },
          },
        });
      }
    
      res.status(200).send('OK');
    });
    

    App Configuration and Environment Variables

    The integration template reads configuration from environment variables. Create a .env file in the app root directory with the following values:

    PORT=3000
    SADAD_MERCHANT_ID=your_merchant_id_here
    SADAD_API_KEY=your_api_key_here
    SADAD_ENV=sandbox
    SHOPIFY_API_KEY=your_shopify_api_key
    SHOPIFY_API_SECRET=your_shopify_api_secret
    SHOPIFY_ACCESS_TOKEN=your_shopify_access_token
    APP_URL=https://your-app-domain.com
    

    The SHOPIFY_ACCESS_TOKEN is generated when you install the app on your store. For development, use a private app token from your Shopify admin under Settings > Apps > Develop apps.

    Order Fulfillment Flow

    Once a payment is confirmed, the Shopify order transitions to the fulfillment_pending state. The app should automatically trigger fulfillment for digital goods or send a notification for manual fulfillment of physical products.

    Implement a fulfillment webhook handler in the app:

    app.post('/fulfillment/auto', async (req, res) => {
      const { orderId, lineItems } = req.body;
      const digitalItems = lineItems.filter(item => item.requires_shipping === false);
    
      if (digitalItems.length > 0) {
        // Fulfill digital items automatically
        await shopifyClient.post({
          path: `orders/${orderId}/fulfillments`,
          data: {
            fulfillment: {
              location_id: process.env.SHOPIFY_LOCATION_ID,
              tracking_numbers: [],
              line_items: digitalItems,
            },
          },
        });
      }
      res.status(200).send('OK');
    });
    

    For cash-on-delivery orders, the flow differs: the order is created in pending state and only marked as paid once the COD amount is confirmed as collected. A separate admin endpoint allows store staff to mark COD orders as paid after confirming collection.

    QPay Integration

    QPay is the national mobile payment scheme in Qatar, operated by Qatar Central Bank alongside QNB. The integration template supports QPay transactions without additional configuration. When a customer selects QPay at checkout, the app generates a QPay payment request through the SADAD API:

    app.post('/qpay/generate', async (req, res) => {
      const qrPayload = await sadad.createQPayRequest({
        amount: req.body.amount,
        merchantId: process.env.SADAD_MERCHANT_ID,
        orderId: req.body.orderId,
        expiryMinutes: 15,
      });
      res.json({ qrCode: qrPayload.qrBase64, expiresAt: qrPayload.expiry });
    });
    

    The customer scans the generated QR code using any QPay-enabled banking app (QNB, Doha Bank, Commercial Bank, or Qatar Islamic Bank mobile apps all support QPay scanning). The app polls the SADAD API for payment confirmation and completes the order when the QR code is scanned and paid.

    Testing in Sandbox

    Before going live, test the integration using the SADAD sandbox environment. Create a test merchant account through QNB's developer portal. Use the following test card numbers:

    Card Type Card Number Result
    QNB Credit 4921 8112 3456 7890 Success
    QNB Debit 4921 8112 3456 7891 Success
    Insufficient Funds 4921 8112 3456 7899 Failed
    Expired Card 4921 8112 3456 7888 Declined

    Configure the sandbox endpoint in your app by setting the environment variable SADAD_ENV=sandbox. All sandbox transactions reset every 24 hours, making it easy to run repeated test cycles during development. For QPay testing, the sandbox environment generates a mock QR code that simulates a successful scan after 10 seconds.

    Deployment to Shopify

    Deploy the app to any Node.js hosting platform (Heroku, DigitalOcean, or a Qatar-based provider like Ooredoo Cloud or MEEZA). The app requires Node.js 18 or later and an HTTPS endpoint with a valid SSL certificate for production use.

    Register the app in your Shopify Partners dashboard, set the app URL and callback URLs, then install it on your store. The app will appear as a custom payment method in your Shopify admin under Settings > Payments > Alternative Payment Methods. From there, you can activate it for your checkout.

    For stores that need both SADAD and QPay, the integration template supports both payment methods with a single app installation. Customers select their preferred method at checkout, and the app routes the payment request to the appropriate SADAD API endpoint. The template also supports a unified checkout page that shows both options with clear pricing and estimated processing times.

    Frequently Asked Questions

    Q: Can I use SADAD with Shopify Payments?

    No. Shopify Payments only supports banks in select countries, and Qatar is not currently included. The custom payment app approach is the recommended method for SADAD integration on Shopify.

    Q: Does the integration support multi-currency?

    Yes. The SADAD gateway processes transactions in QAR by default but supports SAR, AED, and USD for cross-border transactions. You can configure accepted currencies in the app configuration.

    Q: How are refunds handled?

    Refunds are processed through the Shopify admin. When you issue a refund on an order, the app sends a refund request to the SADAD API. Full and partial refunds are supported. Refunded amounts typically appear in the customers account within 3-5 business days.

    Q: What happens if the SADAD gateway is down during checkout?

    The app includes a failover mechanism. If the SADAD API does not respond within the configured timeout (default 15 seconds), the checkout will display an error message prompting the customer to try again. For high-availability setups, consider implementing a secondary payment method fallback. Our enterprise software services can help architect a resilient payment infrastructure.