Bin Discount is a feature on XPay that allows merchants to configure discounts based on card BINs (the first 6 or 8 digits of a card). Merchants can apply discounts for specific BINs using either a fixed value or a percentage of the order price.
The Bin Discount module supports multiple configurable options, including:
- Minimum Order Value — Apply discounts only when the transaction amount meets a defined minimum value.
- Discounted Days — Restrict discounts to specific days of the week or promotional periods.
- Daily Usage Frequency—Limit how many times a customer can avail themselves of the discount in a single day.
- Monthly Usage Frequency — Control the maximum number of times a customer can use the discount within a month.
How It Works
You need to pass apply_bin_discount: true in the payment intent create API payload, the system could process the bin discount based on the configurations in the store.
- Customer initiates a payment.
- XPay extracts the card BIN from the payment card.
- The system checks:Loading…
- If all validations pass:Loading…
- If validation fails:Loading…
If a merchant has configured bin discounts on the XPay portal, then when a user enters their card in the SDK:
- In React, the
onBinDiscountevent will return discount details. - In Vanilla JavaScript, the
binDiscountevent will return discount details.
Using these details, you need to apply the discount to the order.
BIN Discount & Pre-calculation Requirement
If you want to use the BIN discount feature and enable pre-calculation, you must pass the piClientSecret while initializing the XPay SDK.
BIN discount and pre-calculation features are supported only in XPay SDK v4.1 versions.
const xpayy = new window.Xpay({
publishableKey: xpay?.publishableKey,
accountId: xpay?.accountId,
email: xpay?.email || null,
customerName: xpay?.customerName || null,
piClientSecret: xpay?.piClientSecret || null,
});React
<xpay
xpay={{
publishableKey: storePK,
accountId: user_id,
customerName: customer?.name || null,
email: customer?.email || null,
piClientSecret: pi_client_secret,
}}
>
<PaymentElement
onBinDiscount={(data) => console.log("discount event data", data)}
/>
</xpay>;How to Listen for the Event
Vanilla JavaScript (binDiscount Event)
In Vanilla JavaScript, you can listen for the binDiscount event using the xpay.on() method:
xpay.on('binDiscount', function (event) {
console.log(event, 'bin discount event');
// Apply the discount based on event data
});React.js (onBinDiscount Event)
In React.js, you can listen for the event using the onBinDiscount prop inside the <PaymentElement /> component:
<PaymentElement
onBinDiscount={(data)=> console.log("discount event data", data)}
/>Event Response Example
If you pass payment intent secret before SDK load and bin discount is applicable, you will get pre-calculated discount details in the event in the following format:
{
"bin": 512345,
"bank_name": "Bank ALafalah (MPGS)",
"account_id": "0ddb82950784f875",
"store_id": "65ccc486e9c7cd07445f6d28",
"bank_acronym": "BAFL",
"bank_logo": "https://xstak-pay-admin.s3.us-east-2.amazonaws.com/assets/bank-logos/HBL.png",
"discount_type": "percentage",
"discount_value": 10,
"discount_limit": 1,
"active_days": "monday,tuesday",
"max_daily_usage": 1,
"max_monthly_usage": 3,
"on_discounted_items": false,
"rule_enabled": true,
"id": "d0b80c34-7bc1-4f02-8f25-9fbbef6f4208",
"_id": "6a0318717eacae338fe7379b",
"createdAt": "2026-05-12T12:09:21.729Z",
"updatedAt": "2026-05-12T12:09:21.729Z",
"__v": 0,
"discount_applicable": true,
"discount_details": {
"discount_amount": 10,
"amount_after_discounted": 990,
"original_amount": 1000,
"amount_summary": {
"currency": "PKR",
"tax_amount": 89.76,
"tax_rate": 8,
"tax_type": "exclusive",
"base_amount": 1122,
"discount_amount": 5,
"total_before_discount": 1211.76,
"total_after_discount": 1206.76,
"computed_at": "2026-06-11T11:41:43.970Z"
}
},
"hash": "42a56aa1413773ab1652a04e1e170adeec5b9e359900ba8ebeaa904a84aa8069"
}When a bin discount is applied and payment intent secret is not passed before SDK load, the event will return a response in the following format:
{
"account_id": "0ddb82950784f875",
"bank_acronym": "HBL",
"bank_logo": "https://js.xstak.com/assets/logos/HBL.png",
"bank_name": "Habib Bank Limited",
"bin": 512345,
"createdAt": "2025-01-06T09:53:45.148Z",
"discount_type": "percentage",
"discount_value": 70,
"hash": "df49774ea1bcf4ff15ab18af6a989fc84e2e821b19700fb8bc9aa9577d57abe4",
"id": "d1dffc51-7b7c-4af0-b306-a8cf76c344d4",
"on_discounted_items": false,
"rule_enabled": true,
"store_id": "64f06b2fcabbf492b6d3a1e1",
"updatedAt": "2025-01-06T09:53:45.148Z",
"__v": 0,
"_id": "677ba829b48208d8392c7633"
}Webhook Response Example
When the order payment is captured, you will receive a webhook response containing the transaction details, including the unique hash for tracking discounts.
{
"type": "PAYMENT_INTENT_NOTIFICATION",
"payment_intent_id": "xpay_pi_1f4ebd77fe08624ee1216d4138d6f29227556a85473f2e7c128a622c2be56d2b",
"refund_id": null,
"amount": 9999,
"currency": "PKR",
"status": "succeeded",
"customer": {
"name": "Guest User",
"email": "testuser@gmail.com",
"phone": "03415682456"
},
"shipping": {
"address1": "Gulberg",
"city": "Lahore",
"country": "Pakistan",
"province": "Punjab",
"zip": "65191",
"shipping_method": "Standard"
},
"payment_method_types": "card",
"product": {},
"transaction_details": {
"_id": "6a045b5d088c8840474298c7",
"order": {
"customer": {
"name": "Guest User",
"email": "testuser@gmail.com",
"phone": "03415682456"
},
"name": "b2b-pl-02",
"type": "headless"
},
"status": "CAPTURED",
"secure": "3DS2",
"refunded_amount": 0,
"gateway": "bank-alfalah",
"response_from_bank": "The payment was completed successfully",
"status_message_from_bank": "PAYMENT_CAPTURED",
"activity": [
{
"status": "AUTHENTICATION_SUCCESSFUL",
"amount": 9999,
"timestamp": "2026-05-13T11:07:11.348Z",
"createdAt": "2026-05-13T11:07:13.300Z",
"token": "",
"card": {
"bin": "512345",
"last4digits": "2346",
"name": "Guest User",
"funding_method": "DEBIT",
"type": "MASTERCARD",
"issuer_details": {
"card_issuer": "Habib Bank Limited",
"card_network": "VISA",
"card_type": "DEBIT"
}
},
"3ds": { "authorization_code": "", "secure": "3DS2", "eci": "02" },
"processing": { "acquirer_transaction_id": "trans-MHdo1pHUgK" }
},
{
"status": "CAPTURED",
"amount": 9999,
"timestamp": "2026-05-13T11:07:12.478Z",
"createdAt": "2026-05-13T11:07:13.300Z",
"token": "",
"card": {
"hash": "42a56aa1413773ab1652a04e1e170adeec5b9e359900ba8ebeaa904a84aa8069",
"bin": "512345",
"last4digits": "2346",
"name": "Guest User",
"funding_method": "DEBIT",
"type": "MASTERCARD",
"issuer_details": {
"card_issuer": "Habib Bank Limited",
"card_network": "VISA",
"card_type": "DEBIT"
}
},
"3ds": {
"authorization_code": "134697",
"secure": "3DS2",
"eci": "02"
},
"processing": { "acquirer_transaction_id": "trans-XSVwnVKIG5" }
}
]
},
"metadata": { "order_reference": "b2b-pl-02" },
"store_id": "65ccc486e9c7cd07445f6d28",
"mode": "test",
"account_id": "0ddb82950784f875",
"discount_details": {
"bin": 411111,
"binId": "6a1ee8da531310939bc45991",
"type": "percentage",
"limit": 1999,
"value": 10,
"acronym": "UBL",
"max_daily_usage": null,
"max_monthly_usage": null,
"minimum_order_value": 4000,
"active_days": null,
"amount_summary": {
"currency": "PKR",
"tax_amount": 681.6,
"tax_rate": 8,
"tax_type": "exclusive",
"base_amount": 8520,
"discount_amount": 852,
"total_before_discount": 9201.6,
"total_after_discount": 8349.6,
"computed_at": "2026-06-11T13:24:19.145Z",
"additional_charges": 0
}
}
}
How to Track Discounts Against a Card
If you have configured bin discounts, the event will return a unique hash corresponding to the user's card:
- React:
onBinDiscountevent - Vanilla JS:
binDiscountevent
When the order payment is captured, you will receive the same hash in the webhook data for the transaction captured status event.
Example Use Case: Restricting Discounts Per Day
If you want to allow only one discount per day for a card, follow these steps:
- The event (
onBinDiscountin React,binDiscountin Vanilla JS) will return a unique hash for the card. - When the order is captured, the same unique hash will be received in the webhook captured activity details.
- Save this hash in your system.
- On the next order, before applying the discount, check if the hash already exists. If it does, you can decide whether to allow the discount again.
This ensures that discounts are applied according to your business logic while preventing multiple discounts for the same card within a specified period.
APIs
Create Bin Discount Configuration
POST /bin/config/create/:store_id
Creates a new BIN discount configuration for a specific store
Request Payload
{
"bin": 437585,
"discount_type": "percentage",
"discount_value": 300,
"minimum_order_value": 1000,
"active_days": "monday,thursday,friday",
"max_daily_usage": 1,
"max_monthly_usage": 3,
"rule_enabled": true
}Response
{
"success": true,
"responseStatus": "OK",
"message": "Request processed successfully.",
"data": {
"_id": "69ddec858da4120a0355d13c",
"bin": 51234567,
"bank_name": "Bank Alfalah Limited",
"account_id": "xxxb8295xxxxf875",
"store_id": "670cc16c5x5x5xe748916396",
"bank_acronym": "BAFL",
"bank_logo": "",
"discount_type": "percentage",
"discount_value": 10,
"discount_limit": 5,
"on_discounted_items": false,
"rule_enabled": true,
"id": "",
"createdAt": "2026-04-14T07:28:05.954Z",
"updatedAt": "2026-05-13T08:10:48.424Z",
"__v": 0,
"active_days": null,
"max_daily_usage": 1,
"max_monthly_usage": 3,
"minimum_order_value": null
}
}Update Bin Discount Configuration
PUT /bin/config/create/:store_id
Updates a new BIN discount configuration for a specific store
Request Payload
{
"_id": "6a0318717eacae338fe7379b"
"bin": 437585,
"discount_type": "percentage",
"discount_value": 300,
"minimum_order_value": 1000,
"active_days": "monday,thursday,friday",
"max_daily_usage": 1,
"max_monthly_usage": 3,
"rule_enabled": true
}Response
{
"success": true,
"responseStatus": "OK",
"message": "Request processed successfully.",
"data": {
"_id": "69ddec858da4120a0355d13c",
"bin": 51234567,
"bank_name": "Bank Alfalah Limited",
"account_id": "xxxb8295xxxxf875",
"store_id": "670cc16c5x5x5xe748916396",
"bank_acronym": "BAFL",
"bank_logo": "",
"discount_type": "percentage",
"discount_value": 10,
"discount_limit": 5,
"on_discounted_items": false,
"rule_enabled": true,
"id": "",
"createdAt": "2026-04-14T07:28:05.954Z",
"updatedAt": "2026-05-13T08:10:48.424Z",
"__v": 0,
"active_days": null,
"max_daily_usage": 1,
"max_monthly_usage": 3,
"minimum_order_value": null
}
}Get Bin Discount Configuration Details
POST /bin/config
Request Payload
{
"bin": 123456 // 123456 or 12345678
}Response
{
"success": true,
"responseStatus": "OK",
"message": "Request processed successfully.",
"data": {
"_id": "69ddec858da4120a0355d13c",
"bin": 51234567,
"bank_name": "Bank Alfalah Limited",
"account_id": "xxxb8295xxxxf875",
"store_id": "670cc16c5x5x5xe748916396",
"bank_acronym": "BAFL",
"bank_logo": "",
"discount_type": "percentage",
"discount_value": 10,
"discount_limit": 5,
"on_discounted_items": false,
"rule_enabled": true,
"id": "",
"createdAt": "2026-04-14T07:28:05.954Z",
"updatedAt": "2026-05-13T08:10:48.424Z",
"__v": 0,
"active_days": null,
"max_daily_usage": 1,
"max_monthly_usage": 3,
"minimum_order_value": null
}
}Delete Bin Discount Configuration
DELETE /bin/config/:store_id/:id
The bin discount configuration against _id will be deleted from the store.