Category: Payment Gateways

  • Migrating a Legacy Payment Platform Without Breaking Production Transactions

    Migrating a Legacy Payment Platform Without Breaking Production Transactions

    Payment gateway migrations are some of the highest risk projects in software engineering. A failed deployment can immediately impact transactions, customer trust, and business operations. In early 2026, Mastercard officially decommissioned the ANZ MIGS and eGate platform, forcing a migration to ANZ Worldline WGOP before live payments stopped working entirely.

    The Existing Payment Architecture

    The CRM platform already had a mature payment abstraction layer built around Omnipay. Controllers and booking flows communicated with a unified payment interface rather than individual gateways. This became the key reason the migration was possible without major rewrites.

    Why Abstraction Layers Matter

    Many payment systems become difficult to evolve because provider logic leaks into controllers and services. In this case, Omnipay isolated the application from provider-specific implementations, allowing the migration to happen at the infrastructure layer rather than across the entire codebase.

    The Migration Challenge

    WGOP introduced REST APIs, HMAC-SHA256 signing, different response structures, and different authentication flows. No Omnipay driver existed for the platform, while the migration deadline remained fixed and production traffic continued daily.

    Why We Built a Proper Omnipay Package

    Rather than tightly coupling the CRM to WGOP directly, we developed a standalone Omnipay driver package. This preserved backward compatibility, reduced deployment risk, avoided controller rewrites, and maintained future flexibility for additional gateways.

    Backward Compatibility Was the Key

    The payment service only needed to initialise a different gateway implementation. Booking systems, refunds, reporting, customer records, and operational dashboards continued functioning without modification.

    Zero Downtime Deployment Strategy

    The new gateway was tested independently before production rollout. WGOP was introduced alongside the legacy gateway, allowing rollback capability, safer testing, and configuration-driven switching without rewriting transaction logic.

    Transactional Safety and Edge Cases

    The migration effort focused heavily on transactional safety. This included handling multiple success states, normalising inconsistent responses, protecting against duplicate charges, and preserving refund compatibility.

    The Most Difficult Technical Challenge

    The most technically demanding part of the migration was implementing WGOP’s HMAC-SHA256 signing system. Even very small inconsistencies in timestamps, canonical strings, or headers caused authentication failures, requiring extensive testing and validation.

    Rollback Planning and Operational Safety

    Maintaining the Omnipay abstraction allowed both gateways to coexist temporarily. Rollback remained possible instantly, deployments stayed reversible, and production traffic remained protected throughout the migration process.

    Key Lessons from the Migration

    Good abstractions pay for themselves. Payment providers eventually change. Backward compatibility dramatically reduces risk. Payment migrations are operational projects as much as technical ones.

    Conclusion

    By building a dedicated Omnipay driver, preserving the existing abstraction layer, and focusing heavily on deployment safety, we successfully migrated away from ANZ MIGS without rewriting the application or disrupting live transactions.

    Official package link: https://github.com/SmartWebAgencyGit/omnipay-wgop

  • Dubai Pay Integration in PHP for Secure Online Donations

    Dubai Pay Integration in PHP for Secure Online Donations

    When building a secure online donation platform in the UAE, choosing a trusted government backed payment gateway is critical. Dubai Pay provides a reliable and compliant infrastructure that enables organisations to collect payments safely while meeting regulatory standards.

    In this guide, we walk through the complete process of integrating Dubai Pay into a PHP application. The implementation is demonstrated in the context of developing an online donation system for Dubai Cares, covering authentication, payment creation, signature validation, and transaction confirmation. The aim is to clearly explain each step so developers can understand both the technical flow and the security principles behind the integration.

    dubai pay integration

    Results

    QA credential requirements

    OAuth authentication

    Required keys for authorisation

    HMAC SHA512 signature generation

    Payment registration and redirect handling

    Token verification and confirmation

    Hosted versus self managed checkout

    Understanding the Dubai Pay Architecture

    Dubai Pay uses:

    • OAuth 2 client credentials flow for authentication
    • Bearer token based API authorisation
    • HMAC SHA512 signature validation for request integrity
    • Batch based transaction processing
    • Hosted redirection checkout model

    The gateway is designed to ensure:

    • Payload integrity
    • Non tampering of transaction data
    • Secure government compliant processing
    • Clear batch reconciliation

    Required QA Credentials

    Before integration begins, you must obtain QA environment credentials from Dubai Pay.

    Required QA Credentials

    Before integration begins, you must obtain QA environment credentials from Dubai Pay.

    Typically, you will receive:

    php:
    $CLIENT_ID = “XXXX-XXXX-XXX”; $CLIENT_SECRET = “XXXX-XXXX-XXX”; $ENTITY_CODE = “XXXX”;
    $SP_CODE = “XXXX”;
    $SERV_CODE = “XXXX”;
    $CHECKSUM_KEY = “XXXXXXXXXXXXXXXXXXX”; $BASE_URL = “https://api.qa.dubai.gov.ae”; $RETURN_URL = “https://your-domain.com/return.php“;

    What Each Key Is Used For

    KeyPurpose
    Client IDOAuth authentication
    Client SecretOAuth authentication
    Access TokenAPI authorisation
    Entity CodeIdentifies organisation
    SP CodeService provider reference
    Service CodeSpecific service mapping
    Checksum KeyHMAC signature generation

    You may be required to provide:

    • Official onboarding request
    • Technical contact details
    • Callback and return URLs
    • Whitelisted IP addresses
    • Organisation authorisation documents

    Step 1: OAuth Authentication

    Dubai Pay requires a Bearer access token before any API call can be made.

    Generating Access Token

    function getAccessToken($clientId, $clientSecret)
    
    
    {
    
    
    $url = “https://ids.qa.dubai.gov.ae/oauth2/token”;
    
    
    $credentials = base64_encode($clientId . “:” . $clientSecret);
    
    
    $ch = curl_init($url);
    
    
    curl_setopt_array($ch, [
    
    
    CURLOPT_RETURNTRANSFER => true,
    
    
    CURLOPT_POST => true,
    
    
    CURLOPT_HTTPHEADER => [
    
    
    “Authorization: Basic ” . $credentials,
    
    
    “Content-Type: application/x-www-form-urlencoded”
    
    
    ],
    
    
    CURLOPT_POSTFIELDS => http_build_query([
    
    
    “grant_type” => “client_credentials”,
    
    
    “scope” => “openid”
    
    
    ])
    
    
    ]);
    
    
    $response = curl_exec($ch);
    
    
    curl_close($ch);
    
    
    $data = json_decode($response, true);
    
    
    if (!isset($data[‘access_token’])) {
    
    
    die(“OAuth authentication failed.”);
    
    
    }
    
    
    return $data[‘access_token’];
    
    
    }

    This token must be included in every subsequent API request:

    Authorization: Bearer {access_token}

    Step 2: Generating HMAC SHA512 Signature

    Every Dubai Pay API request requires a signature header called:

    dubaiPaySignature

    The signature is created from:

    • The exact JSON payload
    • SHA512 hashing
    • The Checksum Key
    • Uppercase output

    Signature Example

    $jsonPayload = json_encode($jsonPayload = json_encode(
    
    $jsonPayload = json_encode(
    
    $payload,
    
    JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
    
    );
    
    $jsonPayload = mb_convert_encoding($jsonPayload, ‘UTF-8’);
    
    $signature = strtoupper(
    
    hash_hmac(‘sha512’, $jsonPayload, $CHECKSUM_KEY)
    
    );
    
    $payload,
    
    JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
    
    );
    
    $jsonPayload = mb_convert_encoding($jsonPayload, ‘UTF-8’);
    
    $signature = strtoupper(
    
    hash_hmac(‘sha512’, $jsonPayload, $CHECKSUM_KEY)
    
    );

    This ensures:

    • Payload integrity
    • Tamper prevention
    • Government grade request validation

    Step 3: Creating the Payment and Getting Redirect URL

    Dubai Pay follows a hosted redirection model. You register a batch transaction, and the response contains a uri for redirection.

    callAPI Helper Function

    function callAPI($endpoint, $payload, $token, $baseUrl, $checksumKey)
    
    
    {
    
    
    $jsonPayload = json_encode(
    
    
    $payload,
    
    
    JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
    
    
    );
    
    
    $jsonPayload = mb_convert_encoding($jsonPayload, ‘UTF-8’);
    
    
    $signature = strtoupper(
    
    
    hash_hmac(‘sha512’, $jsonPayload, $checksumKey)
    
    
    );
    
    
    $ch = curl_init($baseUrl . $endpoint);
    
    
    curl_setopt_array($ch, [
    
    
    CURLOPT_RETURNTRANSFER => true,
    
    
    CURLOPT_POST => true,
    
    
    CURLOPT_HTTPHEADER => [
    
    
    “Authorization: Bearer $token”,
    
    
    “Content-Type: application/json”,
    
    
    “dubaiPaySignature: $signature”
    
    
    ],
    
    
    CURLOPT_POSTFIELDS => $jsonPayload
    
    
    ]);
    
    
    $response = curl_exec($ch);
    
    
    curl_close($ch);
    
    
    return json_decode($response, true);
    
    
    }
    
    Creating the Payment
    
    $accessToken = getAccessToken($CLIENT_ID, $CLIENT_SECRET);
    
    
    $payload = [
    
    
    “entityCode” => $ENTITY_CODE,
    
    
    “batchId” => “batch_” . time(),
    
    
    “totalAmount” => 10.00,
    
    
    “totalTransactions” => 1,
    
    
    “returnUrl” => $RETURN_URL,
    
    
    “transactions” => [[
    
    
    “spCode” => $SP_CODE,
    
    
    “servCode” => $SERV_CODE,
    
    
    “spTrn” => uniqid(“DONATION_”),
    
    
    “amount” => 10.00,
    
    
    “currency” => “AED”,
    
    
    “timestamp” => date(“d-m-Y H:i:s”),
    
    
    “channel” => “100”,
    
    
    “description” => “Online Donation”,
    
    
    “type” => “sale”,
    
    
    “version” => “2.1”,
    
    
    “settlementType” => “gov”
    
    
    ]]
    
    
    ];

    Calling Register Endpoint

    $response = callAPI(
    
    
    “/secure/dubaipay/batch/1.0.0/register”,
    
    
    $payload,
    
    
    $accessToken,
    
    
    $BASE_URL,
    
    
    $CHECKSUM_KEY
    
    
    );
    
    
    Redirecting the Donor
    
    
    if (!isset($response[‘uri’])) {
    
    
    die(“Payment registration failed.”);
    
    
    }
    
    
    header(“Location: ” . $response[‘uri’]);
    
    
    exit;

    The donor is redirected to Dubai Pay secure hosted checkout.

    Hosted Checkout Versus Self Managed Checkout

    Dubai Pay primarily supports hosted redirection checkout.

    This means:

    • Card data is entered on Dubai Pay servers
    • Your server does not handle card details
    • PCI scope is reduced
    • Security responsibility is simplified

    Direct self managed card form processing is not the standard model.

    Step 4: Handling Payment Confirmation

    After payment completion, Dubai Pay posts a TOKEN to your return URL.

    Retrieve Token

    $responseToken = $_POST[‘TOKEN’];

    Verify Using tokenDetails API

    $verification = callAPI(
    
    
       “/secure/dubaipay/batch/1.0.0/tokenDetails”,
    
    
       [
    
    
           “token” => $responseToken,
    
    
           “entityCode” => $ENTITY_CODE
    
    
       ],
    
    
       $accessToken,
    
    
       $BASE_URL,
    
    
       $CHECKSUM_KEY
    
    
    );
    
    Validate Transaction
    
    if (
    
    
       $verification[‘batchStatus’] == ‘completed’ &&
    
    
       $verification[‘transactions’][0][‘message’][‘code’] == 0
    
    
    ) {

    Only when both conditions are satisfied should the transaction be considered successful.

    Step 5: Confirm API Call

    Dubai Pay recommends confirming transactions after successful verification.

    $confirmPayload = [
    
    
       “entityCode” => $ENTITY_CODE,
    
    
       “batchId”    => $verification[‘batchId’],
    
    
       “confirmAll” => true,
    
    
       “message” => [
    
    
           “code” => “0”,
    
    
           “text” => “confirmed”
    
    
       ]
    
    
    ];
    
    $confirmResponse = callAPI(
    
    
       “/secure/dubaipay/batch/1.0.0/confirm”,
    
    
       $confirmPayload,
    
    
       $accessToken,
    
    
       $BASE_URL,
    
    
       $CHECKSUM_KEY
    
    
    );

    Only after confirmation should you:

    • Update the donation record
    • Store the gateway reference
    • Trigger receipt email
    • Mark transaction as settled

    Security and Production Best Practices

    When moving from QA to production:

    • Replace QA endpoints with production URLs
    • Update Client ID and Client Secret
    • Replace Checksum Key
    • Validate return URL handling
    • Log all API responses
    • Use idempotent transaction references
    • Implement server side validation

    Conclusion

    Dubai Pay integration in PHP requires structured implementation of OAuth authentication, HMAC SHA512 request signing and strict transaction verification.

    For organisations such as Dubai Cares, this integration provides:

    • Government compliant payment processing
    • Hosted secure checkout
    • Strong request integrity validation
    • Clear batch reconciliation

    When implemented correctly, Dubai Pay offers a reliable and scalable solution for secure online donation platforms in the UAE.

  • Which eCommerce platform is best for me?

    Which eCommerce platform is best for me?

    For greater complexity eCommerce platforms such as product configuration with multiple elements to choose from, Woocommerce seems to be the best choice as it gives full freedom to add plugins or custom code. For simpler products with less variations, the no-code platforms such as Shopify, Wix, Squarespace and Webflow are a better choice. For integration with the Accounting or Logistics systems such as Sage or Merlin for pricing and customer control, Opencart seems to be a good choice.

    The best eCommerce platform for you depends entirely on your project requirements and how complex your store needs to be.

    When we start working with a new business, we always begin with an initial consultation to understand the scale of their products, how they want to sell, and what systems they need connected. Once we have a clear picture, we can recommend the most suitable platform.

    For eCommerce stores that involve complex product configuration with multiple elements to choose from, we usually recommend WooCommerce. It’s a highly flexible platform that allows you to use plugins or even add custom code to make the system do exactly what you need. We’ve used it for businesses like Master Spa, Hot Tub and Any Occasion Boutique, where customers can customise products in detail before buying.

    If your product range is simpler and you just need a clean online shop with straightforward management, then no-code platforms like Shopify, Wix, Squarespace or Webflow can work really well. They’re user-friendly, fast to set up, and don’t require technical skills to manage day to day. We’ve used this approach for stores like Army and Navy Stores.

    And for businesses that need to integrate their online shop with accounting or logistics systems like Sage or Merlin for pricing, stock, and customer control, we often suggest OpenCart. It gives a lot of flexibility for linking with back-office systems. We’ve done this for companies such as Roast and Ground and Deanta.

    Choosing the right platform early on can save you time, money, and headaches later, so it’s always worth having that initial conversation before diving in.