Magento 2 Integration
The BINKPAY Magento 2 module adds a certified payment gateway to your Magento store, enabling credit and debit card payments, Apple Pay, and Google Pay across USD, AED, EUR, GBP, and SAR. It supports multi-store and multi-website configurations, full and partial refunds via credit memos, webhook-driven order state updates, and is compatible with Magento 2.4.5 through the latest 2.4.x release.
Hosted Checkout
Cards · Apple Pay · Google Pay
Refunds sync
No code changes
Prerequisites
Confirm your server and Magento environment meet the following requirements before installing the BINKPAY module.
| Requirement | Minimum version | Notes |
|---|---|---|
| PHP | 8.1+ | PHP 8.2 recommended; required extensions: curl, json, openssl |
| Magento | 2.4.5+ | Open Source and Commerce editions are both supported |
| Composer | 2.x | Composer 1.x is not supported |
| BINKPAY account | — | Sign up at dashboard.binkpay.net and retrieve your API keys from Developers → API Keys |
| SSL certificate | — | Required for Apple Pay domain verification and PCI compliance |
Installation
The BINKPAY module is installed via Composer and registered through the standard Magento module management CLI. Run each command from the root of your Magento installation as a user who has write access to the codebase.
Require the module via Composer
Pull the latest stable release of the BINKPAY Magento 2 module from Packagist. Composer will resolve the module's dependencies (including the BINKPAY PHP SDK) and add entries to your composer.json.
composer require binkpay/magento2-moduleEnable the BinkPay_Checkout module
Register the module with Magento's module registry. This adds BinkPay_Checkout to app/etc/config.php.
php bin/magento module:enable BinkPay_CheckoutRun setup upgrade and compile the dependency injection container
Apply the module's database schema and data patches, then regenerate the DI container. On large stores, setup:di:compile may take several minutes.
php bin/magento setup:upgrade && php bin/magento setup:di:compileFlush all caches
Clear and flush the Magento full-page cache and configuration cache so that the newly registered module is visible in the Admin.
php bin/magento cache:clean && php bin/magento cache:flushReindex all indexers
Reindex to ensure product and catalog data is consistent after the schema changes introduced by the module.
php bin/magento indexer:reindexAdmin Configuration
After installation, configure BINKPAY in the Magento Admin by navigating to Stores → Configuration → Sales → Payment Methods → BINKPAY. Expand the BINKPAY section and fill in the fields below.
| Field | Description |
|---|---|
| Enabled | Toggle the gateway on or off for this store view |
| Title | Label shown to customers at checkout (e.g., "Pay by Card") |
| Secret Key | Your sk_live_... or sk_test_... key |
| Publishable Key | Your pk_live_... or pk_test_... key |
| Webhook Secret | The whsec_... value from your BINKPAY webhook endpoint |
| Payment Action | Authorize Only or Authorize and Capture. Use Authorize Only if you fulfill before charging. |
| Enable Apple Pay | Shows the Apple Pay button on supported browsers. Domain verification must be complete. |
| Enable Google Pay | Shows the Google Pay button on supported browsers |
| Statement Descriptor | Up to 22 characters shown on the customer's bank statement |
These settings correspond to the following XML node in the module's etc/config.xml. This file ships with safe defaults and is the source of truth for the Admin form. You do not need to edit it directly — use the Admin UI or override values per store (see Multi-Store below).
app/code/BinkPay/Checkout/etc/config.xml
<?xml version= "1.0"?>
<config xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation= "urn:magento:module:Magento_Store:etc/config.xsd">
< default>
<payment>
<binkpay_checkout>
<active> 0</active>
<title>Credit / Debit Card</title>
<model>BinkPayCheckoutModelMethodBinkPayCheckout</model>
<order_status>pending</order_status>
<payment_action>authorize_capture</payment_action>
<!-- API credentials — override these in Admin or via env variables -->
<secret_key backend_model= "MagentoConfigModelConfigBackendEncrypted"/>
<publishable_key backend_model= "MagentoConfigModelConfigBackendEncrypted"/>
<webhook_secret backend_model= "MagentoConfigModelConfigBackendEncrypted"/>
<!-- Wallet methods -->
<enable_apple_pay> 1</enable_apple_pay>
<enable_google_pay> 1</enable_google_pay>
<!-- Statement descriptor shown on customer bank statements (max 22chars) -->
<statement_descriptor>BINKPAY</statement_descriptor>
<!-- Test mode: set to 1to use sk_test_... keys; routes calls to sandbox -->
<test_mode> 1</test_mode>
<!-- Accepted currencies for this gateway (comma-separated ISO 4217codes) -->
<allowspecific> 0</allowspecific>
<specificcountry/>
<sort_order> 10</sort_order>
</binkpay_checkout>
</payment>
</ default>
</config>Multi-Store Configuration
Magento's configuration scoping lets you set different BINKPAY API keys per website or store view. This is useful if you operate multiple brands or regional stores from a single Magento instance, each with separate BINKPAY accounts or separate live/test environments.
In the Admin, select the target website or store view in the scope switcher at the top of the Configuration page before saving credentials. To set credentials programmatically (for example, via a deployment script), use the Magento config:set CLI command or inject values via the Magento\Framework\App\Config\Storage\WriterInterface. The snippet below demonstrates the programmatic approach with scoped configuration:
app/code/MyStore/Setup/Patch/Data/ConfigureBinkPay.php
<?php
declare(strict_types= 1);
namespace MyStoreSetupPatchData;
use MagentoFrameworkAppConfigStorageWriterInterface;
use MagentoFrameworkEncryptionEncryptorInterface;
use MagentoFrameworkSetupPatchDataPatchInterface;
use MagentoStoreModelScopeInterface;
/**
* Sets per-website BINKPAY credentials during deployment.
* Replace the website IDs and key values with your own.
*/ classConfigureBinkPay implements DataPatchInterface
{ // Magento config paths for BinkPay_Checkout settings
private const PATH_SECRET_KEY = 'payment/binkpay_checkout/secret_key';
private const PATH_PUB_KEY = 'payment/binkpay_checkout/publishable_key';
private const PATH_WEBHOOK_SECRET = 'payment/binkpay_checkout/webhook_secret';
private const PATH_TEST_MODE = 'payment/binkpay_checkout/test_mode';
private const PATH_ACTIVE = 'payment/binkpay_checkout/active';
public function__construct(
private readonly WriterInterface $configWriter,
private readonly EncryptorInterface $encryptor,
) {}
public function apply(): self
{
// --- Website 1: main storefront (live keys) ---$this->setWebsiteConfig( 1, [
self::PATH_SECRET_KEY => $this->encryptor->encrypt( 'sk_live_WEBSITE_1_SECRET'),
self::PATH_PUB_KEY => 'pk_live_WEBSITE_1_PUBLISHABLE',
self::PATH_WEBHOOK_SECRET => $this->encryptor->encrypt( 'whsec_WEBSITE_1_WEBHOOK_SECRET'),
self::PATH_TEST_MODE => '0',
self::PATH_ACTIVE => '1',
]);
// --- Website 2: secondary brand storefront (separate BINKPAY account) ---$this->setWebsiteConfig( 2, [
self::PATH_SECRET_KEY => $this->encryptor->encrypt( 'sk_live_WEBSITE_2_SECRET'),
self::PATH_PUB_KEY => 'pk_live_WEBSITE_2_PUBLISHABLE',
self::PATH_WEBHOOK_SECRET => $this->encryptor->encrypt( 'whsec_WEBSITE_2_WEBHOOK_SECRET'),
self::PATH_TEST_MODE => '0',
self::PATH_ACTIVE => '1',
]);
return $this;
}
private functionsetWebsiteConfig(int $websiteId, array $values): void
{
foreach ($values as $path => $value) {
$this->configWriter->save($path, $value, ScopeInterface::SCOPE_WEBSITES, $websiteId);
}
}
public static functiongetDependencies(): array
{ return [];
}
public functiongetAliases(): array
{ return [];
}
}Encrypted fields
Always encrypt secret keys and webhook secrets using
EncryptorInterface::encrypt()
backend_model="Magento\Config\Model\Config\Backend\Encrypted"
config.xml
Webhook Setup
BINKPAY sends signed webhook events to your Magento store to update order state after payments, refunds, and disputes. The module registers a built-in webhook endpoint at:
https://your-store.com/binkpay/webhook/receiveRegister this URL in the BINKPAY Dashboard under Developers → Webhooks → Add endpoint. Enable at minimum the following event types: payment.succeeded, payment.failed, refund.created, and dispute.created. Copy the whsec_... signing secret into the Webhook Secret field in Magento Admin (Stores → Configuration → Sales → Payment Methods → BINKPAY).
The module ships with an observer class that handles signature verification and dispatches Magento events for each BINKPAY webhook type. You can listen to these events in your own module. Below is the full observer implementation for reference:
app/code/BinkPay/Checkout/Observer/WebhookObserver.php
<?php
declare(strict_types= 1);
namespace BinkPayCheckoutObserver;
use BinkPayCheckoutModelWebhookSignatureValidator;
use BinkPayCheckoutModelOrderStateUpdater;
use MagentoFrameworkEventObserver;
use MagentoFrameworkEventObserverInterface;
use MagentoFrameworkExceptionLocalizedException;
use PsrLogLoggerInterface;
/**
* Dispatched by BinkPayCheckoutControllerWebhookReceive after
* the raw HTTP request is validated.
*
* Listens to: binkpay_webhook_received
*/ classWebhookObserver implements ObserverInterface
{
public function__construct(
private readonly WebhookSignatureValidator $signatureValidator,
private readonly OrderStateUpdater $orderStateUpdater,
private readonly LoggerInterface $logger,
) {}
public functionexecute(Observer $observer): void
{
/** @ varMagentoFrameworkDataObject $transport */
$transport = $observer->getData( 'transport');
$rawBody = (string) $transport->getData( 'raw_body');
$signature = (string) $transport->getData( 'signature_header');
$storeId = (int) $transport->getData( 'store_id');
// 1. Verify HMAC-SHA256 signature before trusting payload contenttry {
$this->signatureValidator->verify($rawBody, $signature, $storeId);
} catch (LocalizedException $e) {
$this->logger->error( '[BINKPAY] Webhook signature invalid', [
'error'=> $e->getMessage(), 'store_id' => $storeId,
]);
// Return early — controller returns HTTP 401$transport->setData( 'rejected', true);
return;
}
$payload = json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);
$type = $payload[ 'type'] ?? 'unknown';
$data = $payload[ 'data'] ?? [];
$this->logger->info( '[BINKPAY] Webhook received', [
'event_id' => $payload[ 'id'] ?? null,
'type' => $type,
'livemode' => $payload[ 'livemode'] ?? false,
]);
match ($type) { 'payment.succeeded'=> $this->orderStateUpdater->markPaid($data), 'payment.failed'=> $this->orderStateUpdater->markFailed($data), 'refund.created'=> $this->orderStateUpdater->applyRefund($data), 'dispute.created'=> $this->orderStateUpdater->openDispute($data), 'dispute.resolved'=> $this->orderStateUpdater->closeDispute($data), default=> $this->logger->debug( "[BINKPAY] Unhandled event type: {$type}"),
};
}
}Never disable signature verification
The WebhookSignatureValidator uses a timing-safe HMAC-SHA256 comparison. Disabling or bypassing it allows any party to forge webhook events and fraudulently mark orders as paid. Do not skip this step, even in development.
Refund and Dispute Flow
BINKPAY refunds are initiated from Magento Admin by creating a credit memo on the order. The module intercepts the credit memo submission event, calls the BINKPAY Refunds API, and stores the resulting BINKPAY refund ID on the credit memo for reconciliation.
Issuing a Refund via Credit Memo
Open the order in Magento Admin
Navigate to Sales → Orders and open the order you want to refund. The order must have status Processing or Complete and payment method BINKPAY.
Click "Credit Memo"
In the order detail page, click the Credit Memo button in the top-right action bar. If the button is absent, the order is either not invoiced yet or the payment method does not support refunds.
Enter refund amounts
Adjust the Qty to Refund per line item for a partial refund, or leave defaults for a full refund. You can also adjust the Refund Shipping amount. The Refund Totals section shows the calculated refund amount in the order's currency.
Click "Refund" to submit to BINKPAY
Click Refund (not "Refund Offline"). This triggers the module to call the BINKPAY Refunds API. On success, the credit memo is saved with the BINKPAY refund ID, and the order status updates to Closed (full refund) or Processing (partial refund). Refunds typically appear on the customer's statement within 5–10 business days.
Dispute Handling
When a customer files a chargeback, BINKPAY sends a dispute.created webhook event. The module automatically adds an order comment with the dispute ID and evidence due date, and changes the order status to Payment Review. To respond to a dispute:
- Log in to the BINKPAY Dashboard → Disputesand open the dispute by its ID (shown in the Magento order comment).
- Upload your evidence (shipping confirmation, customer correspondence, etc.) before the evidence due date shown on the dispute detail page.
- Click Submit Evidence. BINKPAY forwards your evidence to the card network. Resolution typically takes 60–90 days depending on the issuer.
- When the dispute is resolved, BINKPAY sends a
dispute.resolvedevent. The module updates the Magento order status accordingly — back to Complete if the dispute was decided in your favour, or Closed if the chargeback was upheld.
Production Deployment
Switch Magento to production mode and flush all generated files before going live. Use the following deployment sequence in your CI/CD pipeline or deployment script.
#!/usr/bin/env bash
set -euo pipefail
# 1. Put the store in maintenance mode to block customer traffic during deploymentphp bin/magento maintenance:enable # 2. Pull the latest code (adjust to your VCS workflow)
git pull origin main
# 3. Install/update Composer dependencies without dev packagescomposer install --no-dev --optimize-autoloader --no-interaction # 4. Run any pending schema upgrades and data patchesphp bin/magento setup:upgrade --keep-generated # 5. Compile the dependency injection container (required in production mode)php bin/magento setup:di:compile # 6. Deploy static content for all locales used by your stores
# Add -f to force regeneration; adjust locales as neededphp bin/magento setup:static-content:deploy en_US ar_EG fr_FR -f # 7. Switch to production mode (disables Magento's developer error pages)php bin/magento deploy:mode:set production # 8. Reindex all indexers to reflect any data changesphp bin/magento indexer:reindex # 9. Flush all cachesphp bin/magento cache:flush # 10. Bring the store back onlinephp bin/magento maintenance:disable
echo "Deployment complete. Store is live."Pre-Launch Checklist
- Set Test Mode to No in Stores → Configuration → Sales → Payment Methods → BINKPAY.
- Replace all
sk_test_/pk_test_credentials with live keys from the BINKPAY Dashboard. - Confirm the webhook endpoint (
https://your-store.com/binkpay/webhook/receive) returns HTTP 200 when tested from Dashboard → Developers → Webhooks → Send test event. - Register your live domain for Apple Pay via the BINKPAY API if you have enabled Apple Pay.
- Place one live test transaction with a real card and verify it appears as Succeeded in the BINKPAY Dashboard and as Processing in Magento Admin.
- Issue a full refund on that test transaction and confirm the credit memo is created and the BINKPAY Dashboard shows the refund.
Test Mode
Enable test mode before running any test transactions
In Magento Admin, go to Stores → Configuration → Sales → Payment Methods → BINKPAY and set Test Mode to Yes. The module will automatically use your sk_test_ and pk_test_ keys and route all API calls to the BINKPAY sandbox. No real charges are processed in test mode.
Use the following test card at checkout to simulate a successful payment. Use any future expiry date and any three-digit CVV.
| Card number | Expiry | CVV | Outcome |
|---|---|---|---|
| 4242 4242 4242 4242 | Any future date | Any 3 digits | Succeeded |
| 4000 0000 0000 0002 | Any future date | Any 3 digits | Card declined |
| 4000 0000 0000 9995 | Any future date | Any 3 digits | Insufficient funds |
| 4000 0027 6000 3184 | Any future date | Any 3 digits | 3DS authentication required |
Troubleshooting
BINKPAY does not appear under Payment Methods in Magento Admin
This almost always means the module registration step was skipped or failed. From the Magento root, run php bin/magento module:status BinkPay_Checkout. If the output shows disabled, run php bin/magento module:enable BinkPay_Checkout followed by php bin/magento setup:upgrade and a cache flush. If the module does not appear in the status output at all, the Composer install did not complete — re-run composer require binkpay/magento2-module and confirm there are no version constraint conflicts with your other modules.
Webhook events are not being received — orders stay in "Pending Payment"
First, verify the endpoint URL is publicly reachable: from outside your server, curl -X POST https://your-store.com/binkpay/webhook/receive should return HTTP 200 (or 401 for a missing signature — both mean the endpoint is reachable). Next, check the BINKPAY Dashboard under Developers → Webhooks for delivery failure logs. Common causes: (1) the Magento web server blocks POST requests from external IPs — whitelist BINKPAY's IP ranges in your firewall or WAF; (2) Magento is in maintenance mode; (3) the webhook URL was registered with http:// instead of https:// and your server redirects, which causes the POST body to be lost.
Credit memo refund fails with "BINKPAY API error: charge already fully refunded"
This error means the underlying BINKPAY charge has already been fully refunded — either via a previous credit memo, from the BINKPAY Dashboard directly, or because the original authorization was voided before capture. Open the BINKPAY Dashboard, search for the charge using the BINKPAY Payment ID stored in the Magento order's payment additional information, and confirm its refund state. If the charge is fully refunded, manually set the Magento order status to Closed via Order → Comments History → Submit Comment with a status change.
Multi-store currency mismatch: "Currency EGP is not supported in the Global environment"
The BINKPAY Global environment (api.binkpay.net) does not process EGP. If you are operating a store with EGP as the base currency, you must use a separate BINKPAY account configured for the Egypt environment and enter the Egypt API keys (pointing to api.binkpay.eg) in the website-scope configuration for that store. Confirm the correct website scope is selected in the Admin scope switcher when saving BINKPAY credentials — saving at the Default Config scope overwrites all website-level overrides.
Was this page helpful?
