Tap
The @commercejs/payment-tap package implements the PaymentProvider interface for Tap Payments, the leading payment gateway in the MENA region.
Installation
pnpm add @commercejs/payment-tap
Configuration
import { TapPaymentProvider } from '@commercejs/payment-tap'
const provider = new TapPaymentProvider({
secretKey: 'sk_test_xxx',
baseUrl: 'https://api.tap.company/v2',
merchantId: '1632424', // optional
})
| Option | Type | Required | Description |
|---|---|---|---|
secretKey | string | Yes | Tap secret API key |
baseUrl | string | No | API base URL (default: https://api.tap.company/v2) |
merchantId | string | No | Tap merchant ID for multi-merchant setups |
Creating a Charge
The createSession method creates a Tap charge and returns a PaymentSession:
const session = await provider.createSession({
amount: 99.999,
currency: 'BHD',
sourceToken: 'tok_xxx', // From Tap Card SDK tokenization
returnUrl: 'https://myapp.com/confirm',
webhookUrl: 'https://myapp.com/api/webhooks/tap',
customer: {
email: 'ahmed@example.com',
firstName: 'Ahmed',
lastName: 'Al-Rashid',
phone: '+97312345678',
},
orderId: 'order-001',
})
The webhookUrl maps to Tap's post.url field — Tap sends charge results to this URL asynchronously.
redirectUrl for 3DS verification. Redirect the customer to this URL, and Tap will redirect back to your returnUrl after verification.Confirming a Charge
After 3DS redirect, confirm the payment by charge ID:
const confirmed = await provider.confirmSession('chg_abc123')
// confirmed.status === 'captured' | 'failed' | 'cancelled'
Tap Status Mapping
The provider maps Tap's charge statuses to PaymentSessionStatus:
| Tap Status | PaymentSessionStatus |
|---|---|
INITIATED | pending |
IN_PROGRESS | processing |
CAPTURED | captured |
FAILED | failed |
DECLINED | failed |
CANCELLED | cancelled |
ABANDONED | cancelled |
TIMEDOUT | failed |
VOID | cancelled |
Webhook Handling
Tap sends charge results to the post.url specified in the charge request. Use @commercejs/webhook-verifier to verify these events:
import { WebhookVerifier } from '@commercejs/webhook-verifier'
import { tap as tapConfig } from '@commercejs/webhook-verifier/configs'
const verifier = new WebhookVerifier({
...tapConfig,
secretKey: 'sk_test_xxx',
})
const result = verifier.verify(body, headers)
if (result.isValid) {
// Process the charge update
}
Saved Card Support
The createSession response includes a savedCard field when a card was used for payment. This data can be stored for returning customers:
const session = await provider.createSession({ ... })
if (session.providerData?.savedCard) {
const card = session.providerData.savedCard
// { id, last4, brand, expMonth, expYear, ... }
}
The TapSavedCard type is exported for working with saved card data:
import type { TapSavedCard } from '@commercejs/payment-tap'
Multi-Merchant Support
For marketplace scenarios where each merchant has their own Tap account, create a provider instance per merchant:
function getProviderForMerchant(merchantId: string): TapPaymentProvider {
const config = getMerchantConfig(merchantId)
return new TapPaymentProvider({
secretKey: config.tapSecretKey,
merchantId: config.tapMerchantId,
})
}
Supported Currencies
Tap supports currencies across the MENA region:
| Currency | Code | Decimals |
|---|---|---|
| Bahraini Dinar | BHD | 3 |
| Saudi Riyal | SAR | 2 |
| Kuwaiti Dinar | KWD | 3 |
| UAE Dirham | AED | 2 |
| Omani Rial | OMR | 3 |
| Qatari Riyal | QAR | 2 |
| Egyptian Pound | EGP | 2 |
| US Dollar | USD | 2 |