# PayHere.lk — LLM Context File > **Created by:** Theepan Kaja — https://theepankaja.website > **Disclaimer:** This is NOT an official PayHere document. This file is an independently created community resource compiled from publicly available PayHere documentation for use by AI coding agents. PayHere™ is a trademark of PayHere (Pvt) Ltd. All product names, logos, and brands are property of their respective owners. For official documentation, visit https://support.payhere.lk > PayHere is Sri Lanka's first Central Bank approved Aggregated Internet Payment Gateway. > It enables businesses to accept online payments locally and globally from customers worldwide. > This file provides comprehensive context for AI agents (Claude Code, Cursor, Copilot, Windsurf, Cline, etc.) to understand and assist with PayHere integrations. --- ## Table of Contents - [Overview](#overview) - [Key Concepts & Terminology](#key-concepts--terminology) - [Authentication & Credentials](#authentication--credentials) - [API Endpoints Reference](#api-endpoints-reference) - [Checkout API](#checkout-api) - [Recurring API](#recurring-api) - [Preapproval API](#preapproval-api) - [Charging API (Tokenization)](#charging-api-tokenization) - [Retrieval API](#retrieval-api) - [Subscription Manager API](#subscription-manager-api) - [Refund API](#refund-api) - [Authorize API](#authorize-api) - [Capture API](#capture-api) - [JavaScript SDK (payhere.js)](#javascript-sdk-payherejs) - [Mobile SDKs](#mobile-sdks) - [Shopping Cart Plugins](#shopping-cart-plugins) - [PayHere Links & Buttons](#payhere-links--buttons) - [Payment Notification (notify_url)](#payment-notification-notify_url) - [Hash Generation](#hash-generation) - [OAuth Authentication (Merchant APIs)](#oauth-authentication-merchant-apis) - [Sandbox & Testing](#sandbox--testing) - [Payment Limits, Fees & Plans](#payment-limits-fees--plans) - [Supported Payment Methods & Currencies](#supported-payment-methods--currencies) - [Application Process](#application-process) - [Policy Requirements](#policy-requirements) - [Onsite Checkout](#onsite-checkout) - [Common Pitfalls & FAQs](#common-pitfalls--faqs) - [Documentation Links](#documentation-links) --- ## Overview PayHere provides multiple integration methods for accepting online payments: 1. **PayHere Links** — Accept payments without a website (shareable payment links) 2. **PayHere Buttons** — Embeddable payment buttons for websites 3. **Checkout API** — HTML form-based redirect to PayHere payment gateway 4. **Recurring API** — Subscription/recurring billing via HTML form redirect 5. **Preapproval API** — Tokenize customer cards for future automated charges 6. **Charging API** — Programmatically charge preapproved customers on demand 7. **Authorize API** — Hold on Card (authorize amount without capturing) 8. **Capture API** — Capture previously authorized payments 9. **Retrieval API** — Retrieve payment details programmatically 10. **Subscription Manager API** — View, retry, cancel subscriptions programmatically 11. **Refund API** — Programmatic refunds 12. **JavaScript SDK** — Onsite checkout popup (no redirect, iframe-based) 13. **Mobile SDKs** — Android, iOS, React Native, Flutter (in-app payments) 14. **Shopping Cart Plugins** — OpenCart, WooCommerce, Magento, Prestashop, Shopify, WHMCS, CS-Cart, Moodle, ShopHere **Website:** https://www.payhere.lk **Support/Docs:** https://support.payhere.lk **Sandbox Portal:** https://sandbox.payhere.lk **GitHub:** https://github.com/PayHereLK **Support Email:** support@payhere.lk / techsupport@payhere.lk --- ## Key Concepts & Terminology - **Merchant ID** — Unique identifier for your PayHere business account. Found at Side Menu > Integrations. - **Merchant Secret** — Secret key tied to a specific domain/app. Generated per domain at Side Menu > Integrations > Add Domain/App. - **notify_url** — Server-to-server callback URL where PayHere sends payment status. Must be publicly accessible (not localhost). - **return_url** — URL where the customer is redirected after payment. No payment params are sent here. - **cancel_url** — URL where the customer is redirected if they cancel. - **order_id** — Merchant-defined unique reference for each transaction. PayHere does NOT validate uniqueness. - **customer_token** — Encrypted token from Preapproval API, used to charge customers later via Charging API. - **authorization_token** — Token from Authorize API, used to capture payment later via Capture API. - **status_code** — Payment result: `2` = success, `0` = pending, `-1` = canceled, `-2` = failed/chargebacked, `-3` = charged back. - **md5sig** — Checksum sent with payment notifications to verify authenticity. - **Sandbox** — Test environment at sandbox.payhere.lk. No real payments processed. - **Onsite Checkout** — Payment popup within your site (iframe-based, no redirect). Requires HTTPS. - **Recurring Billing** — Automatic periodic charges (subscriptions) at fixed intervals. - **Automated Charging (Tokenization)** — Preapprove customer cards, then charge on-demand any amount any time. - **Hold on Card (Auth & Capture)** — Authorize (hold) an amount, then capture later (full or partial). --- ## Authentication & Credentials ### Merchant ID & Secret (for Checkout/Recurring/Preapproval/Authorize APIs + JS SDK + Mobile SDKs) 1. Find Merchant ID: PayHere Account > Side Menu > Integrations 2. Generate Merchant Secret: - Go to Side Menu > Integrations - Click "Add Domain/App" - Enter your top-level domain or app package name - Click "Request to Allow" - Wait for approval (up to 24 hours) - Copy the Merchant Secret shown for your domain/app ### OAuth (for Charging, Retrieval, Subscription Manager, Refund, Capture APIs) These server-side APIs use OAuth Bearer tokens. See [OAuth Authentication](#oauth-authentication-merchant-apis) section below. --- ## API Endpoints Reference ### Base URLs | Environment | Base URL | |---|---| | Live | `https://www.payhere.lk` | | Sandbox | `https://sandbox.payhere.lk` | ### Endpoint Summary | API | Method | Live Endpoint | Purpose | |---|---|---|---| | Checkout | POST | `/pay/checkout` | One-time payment redirect | | Recurring | POST | `/pay/checkout` | Subscription payment redirect | | Preapproval | POST | `/pay/preapprove` | Tokenize card for future charges | | Authorize | POST | `/pay/authorize` | Hold on Card authorization | | OAuth Token | POST | `/merchant/v1/oauth/token` | Get access token | | Charging | POST | `/merchant/v1/payment/charge` | Charge preapproved customer | | Retrieval | GET | `/merchant/v1/payment/search?order_id=XXX` | Get payment details | | Subscription | GET | `/merchant/v1/subscription` | List subscriptions | | Subscription Payments | GET | `/merchant/v1/subscription/{id}/payments` | List subscription payments | | Subscription Retry | POST | `/merchant/v1/subscription/retry` | Retry failed subscription | | Subscription Cancel | POST | `/merchant/v1/subscription/cancel` | Cancel subscription | | Refund | POST | `/merchant/v1/payment/refund` | Refund a payment | | Capture | POST | `/merchant/v1/payment/capture` | Capture authorized payment | --- ## Checkout API **Purpose:** One-time payment via HTML form redirect. **Docs:** https://support.payhere.lk/api-&-mobile-sdk/checkout-api ### Integration Steps 1. Submit HTML form with POST params to PayHere 2. Listen for payment notification at notify_url (server callback) 3. Verify the md5sig checksum and update your database ### Form Action URLs - Live: `https://www.payhere.lk/pay/checkout` - Sandbox: `https://sandbox.payhere.lk/pay/checkout` ### Required Parameters | Parameter | Type | Description | |---|---|---| | `merchant_id` | string | Your Merchant ID | | `return_url` | string | URL to redirect after payment | | `cancel_url` | string | URL to redirect on cancel | | `notify_url` | string | Server callback URL (public IP/domain required) | | `order_id` | string | Unique order reference | | `items` | string | Item description | | `currency` | string | `LKR`, `USD`, `EUR`, `GBP`, `AUD` | | `amount` | decimal | Payment amount (format: `1000.00`) | | `first_name` | string | Customer first name | | `last_name` | string | Customer last name | | `email` | string | Customer email | | `phone` | string | Customer phone | | `address` | string | Customer address | | `city` | string | Customer city | | `country` | string | Customer country | | `hash` | string | MD5 hash for verification (generated server-side) | ### Optional Parameters | Parameter | Type | Description | |---|---|---| | `delivery_address` | string | Delivery address | | `delivery_city` | string | Delivery city | | `delivery_country` | string | Delivery country | | `custom_1` | string | Custom field 1 | | `custom_2` | string | Custom field 2 | | `platform` | string | Platform identifier | | `item_number_X` | string | Item number for item X (1-indexed) | | `item_name_X` | string | Item name for item X | | `quantity_X` | int | Quantity for item X | | `amount_X` | decimal | Unit amount for item X | ### Example HTML Form ```html
``` --- ## Recurring API **Purpose:** Accept recurring/subscription payments. Customer enters card once, auto-charged at set intervals. **Docs:** https://support.payhere.lk/api-&-mobile-sdk/recurring-api ### Form Action URLs Same as Checkout API: - Live: `https://www.payhere.lk/pay/checkout` - Sandbox: `https://sandbox.payhere.lk/pay/checkout` ### Additional Required Parameters (on top of Checkout params) | Parameter | Type | Description | |---|---|---| | `recurrence` | string | Charging frequency: `1 Month`, `2 Week`, `6 Month`, `1 Year`, etc. Word must be singular (`Week`, `Month`, `Year`). | | `duration` | string | How long to charge: `Forever`, `1 Year`, `3 Month`, etc. Must be compatible with recurrence. | ### Optional Recurring Parameters | Parameter | Type | Description | |---|---|---| | `startup_fee` | decimal | Extra amount added/subtracted from first charge (can be negative for discount) | ### Additional Notification Parameters for Recurring | Parameter | Description | |---|---| | `recurring` | `1` if recurring payment, `0` if one-time | | `item_rec_status` | Recurring status: `0`=active, `1`=completed, `-1`=cancelled, `-2`=failed, `-3`=pending retry | | `item_rec_date_next` | Next scheduled charge date | | `item_rec_install_paid` | Number of successful recurring installments charged | --- ## Preapproval API **Purpose:** Tokenize customer's card for future on-demand charges via Charging API. **Docs:** https://support.payhere.lk/api-&-mobile-sdk/preapproval-api ### Form Action URLs - Live: `https://www.payhere.lk/pay/preapprove` - Sandbox: `https://sandbox.payhere.lk/pay/preapprove` ### Key Differences from Checkout - The `amount` field can be set to `0` (or minimum `10.00` LKR / `1.01` for other currencies) — this is just for card validation, not an actual charge (unless you want to charge as part of preapproval). - The notification callback includes a `customer_token` — an encrypted token to store securely for future charges. ### Notification Response Includes | Parameter | Description | |---|---| | `customer_token` | Encrypted token for the customer's card. Store this securely for use with Charging API. | --- ## Charging API (Tokenization) **Purpose:** Programmatically charge preapproved customers on demand using their stored customer_token. **Docs:** https://support.payhere.lk/api-&-mobile-sdk/charging-api **Auth:** OAuth Bearer Token ### Endpoint - Live: `POST https://www.payhere.lk/merchant/v1/payment/charge` - Sandbox: `POST https://sandbox.payhere.lk/merchant/v1/payment/charge` ### Headers ``` Authorization: Bearer Content-Type: application/json ``` ### Request Body ```json { "type": "PAYMENT", "order_id": "Order12345", "items": "Taxi Hire 123", "currency": "LKR", "amount": 345.67, "customer_token": "59AFEE022CC69CA39D325E1B59130862", "custom_1": "custom parameter 1", "custom_2": null, "notify_url": "http://www.abc.com/notify", "itemList": [ { "name": "Item Name", "number": "ITEM_001", "quantity": 1, "unit_amount": 345.67 } ] } ``` ### Type Field Values - `PAYMENT` — Capture payment immediately (default) - `AUTHORIZE` — Authorize (hold) amount, returns `authorization_token` for later capture ### Response ```json { "status": 1, "msg": "Automatic payment charged successfully", "data": { "order_id": "Order12345", "items": "Taxi Hire 123", "currency": "LKR", "amount": 345.67, "custom_1": null, "custom_2": null, "payment_id": 320025021815, "status_code": 2, "status_message": "Successfully completed the payment.", "md5sig": "A098FEBCC06293734641770555B4D569", "authorization_token": null } } ``` ### Status Codes - `2` = Success - `0` = Pending - `-1` = Canceled - `-2` = Failed/Chargebacked ### Live Environment Security In live environment, this API can only be consumed from whitelisted domains/IPs. To enable access, email `support@payhere.lk` with your server IP address for whitelisting. --- ## Retrieval API **Purpose:** Retrieve details of successful payments processed through your PayHere account. **Docs:** https://support.payhere.lk/api-&-mobile-sdk/retrieval-api **Auth:** OAuth Bearer Token ### Endpoint - Live: `GET https://www.payhere.lk/merchant/v1/payment/search?order_id=` - Sandbox: `GET https://sandbox.payhere.lk/merchant/v1/payment/search?order_id=` ### Headers ``` Authorization: Bearer Content-Type: application/json ``` ### Response ```json { "status": 1, "msg": "Found 1 payments", "data": [ { "payment_id": 320025023469, "order_id": "LP8006126139", "date": "2018-10-04 20:24:52", "description": "LP8006126139 - Outstanding Payment", "status": "RECEIVED", "currency": "LKR", "amount": 50, "customer": { "fist_name": "Saman", "last_name": "Perera", "email": "samanperera@gmail.com", "phone": "+94771234567", "delivery_details": { "address": "N0.1, Galle Road", "city": "Colombo", "country": "Sri Lanka" } }, "amount_detail": { "currency": "LKR", "gross": 500, "fee": 14.50, "net": 485.50, "exchange_rate": 1, "exchange_from": "LKR", "exchange_to": "LKR" }, "payment_method": { "method": "VISA", "card_customer_name": "S Perera", "card_no": "************1234" }, "items": null } ] } ``` ### Payment Status Values - `RECEIVED` — Payment received - `REFUNDED` — Payment has been refunded - `CHARGEBACKED` — Payment has been chargebacked - `REFUND REQUESTED` — Refund request received, waiting processing - `HOLD` — Payment is on hold **Note:** PayHere does NOT validate order_id uniqueness. Multiple payments may be returned for the same order_id. --- ## Subscription Manager API **Purpose:** View, retry, and cancel subscriptions created via Recurring API. **Docs:** https://support.payhere.lk/api-&-mobile-sdk/subscription-manager-api **Auth:** OAuth Bearer Token ### Endpoints **View Subscriptions:** - Live: `GET https://www.payhere.lk/merchant/v1/subscription` - Sandbox: `GET https://sandbox.payhere.lk/merchant/v1/subscription` **View Subscription Payments:** - Live: `GET https://www.payhere.lk/merchant/v1/subscription/{subscription_id}/payments` - Sandbox: `GET https://sandbox.payhere.lk/merchant/v1/subscription/{subscription_id}/payments` **Retry Failed Subscription:** - Live: `POST https://www.payhere.lk/merchant/v1/subscription/retry` - Sandbox: `POST https://sandbox.payhere.lk/merchant/v1/subscription/retry` **Cancel Subscription:** - Live: `POST https://www.payhere.lk/merchant/v1/subscription/cancel` - Sandbox: `POST https://sandbox.payhere.lk/merchant/v1/subscription/cancel` ### Subscription Statuses - `ACTIVE` — Currently active and charging - `COMPLETED` — All recurring payments finished - `CANCELLED` — Cancelled by merchant - `FAILED` — Payment failed --- ## Refund API **Purpose:** Programmatically refund payments or authorized holds. **Docs:** https://support.payhere.lk/api-&-mobile-sdk/refund-api **Auth:** OAuth Bearer Token ### Endpoint - Live: `POST https://www.payhere.lk/merchant/v1/payment/refund` - Sandbox: `POST https://sandbox.payhere.lk/merchant/v1/payment/refund` ### Request Body To refund a **payment**: ```json { "payment_id": "320027150501", "description": "Item is out of stock" } ``` To refund an **authorization** (hold): ```json { "authorization_token": "74d7f304-7f9d-481d-b47f-6c9cad32d3d5", "description": "Customer cancelled order" } ``` **Note:** Set either `payment_id` OR `authorization_token`, not both. --- ## Authorize API **Purpose:** Hold on Card — authorize (hold) an amount on the customer's card for later capture. **Docs:** https://support.payhere.lk/api-&-mobile-sdk/authorize-api ### Form Action URLs - Live: `https://www.payhere.lk/pay/authorize` - Sandbox: `https://sandbox.payhere.lk/pay/authorize` ### Parameters Same as Checkout API parameters. The form submit redirects the customer to authorize the hold. ### Notification Response Includes | Parameter | Description | |---|---| | `authorization_token` | Token to use with Capture API to capture the authorized amount | --- ## Capture API **Purpose:** Capture a previously authorized Hold on Card payment. **Docs:** https://support.payhere.lk/api-&-mobile-sdk/capture-api **Auth:** OAuth Bearer Token ### Endpoint - Live: `POST https://www.payhere.lk/merchant/v1/payment/capture` - Sandbox: `POST https://sandbox.payhere.lk/merchant/v1/payment/capture` ### Request Body ```json { "authorization_token": "74d7f304-7f9d-481d-b47f-6c9cad32d3d5", "amount": 80.00, "deduction_details": "Partial capture - item was discounted" } ``` **Note:** You can capture the full authorized amount or a lesser amount (partial capture). ### Response ```json { "status": 1, "msg": "Successfully captured payment", "data": { "status_code": 2, "status_message": "Successfully received the VISA payment", "payment_id": 320025527952, "currency": "LKR", "amount": 100.00, "captured_amount": 80.00, "items": "Toy Car", "order_id": "Order12345", "md5sig": "27EE69A66E761D20429984A0CB0AFC27", "custom_1": "ABCD", "custom_2": null } } ``` --- ## JavaScript SDK (payhere.js) **Purpose:** Onsite checkout popup — payment processes inside an iframe on your page, no redirect needed. **Docs:** https://support.payhere.lk/api-&-mobile-sdk/javascript-sdk **Requires:** HTTPS on your website ### Include the SDK ```html ``` ### One-Time Payment Example ```javascript // Event handlers payhere.onCompleted = function onCompleted(orderId) { console.log("Payment completed. OrderID:" + orderId); // Validate payment and show success/failure page }; payhere.onDismissed = function onDismissed() { console.log("Payment dismissed"); // Prompt user to pay again or show error }; payhere.onError = function onError(error) { console.log("Error:" + error); // Show error page }; var payment = { "sandbox": true, "merchant_id": "121XXXX", "return_url": undefined, // Important: set to undefined for JS SDK "cancel_url": undefined, // Important: set to undefined for JS SDK "notify_url": "http://sample.com/notify", "order_id": "ItemNo12345", "items": "Door bell wireless", "amount": "1000.00", "currency": "LKR", "hash": "GENERATED_HASH_FROM_BACKEND", // Must be generated server-side! "first_name": "Saman", "last_name": "Perera", "email": "samanp@gmail.com", "phone": "0771234567", "address": "No.1, Galle Road", "city": "Colombo", "country": "Sri Lanka" }; payhere.startPayment(payment); ``` ### Recurring Payment via JS SDK Add these fields to the payment object: ```javascript "recurrence": "1 Month", // Frequency "duration": "1 Year", // Duration "startup_fee": "10.00" // Optional: extra amount for first payment ``` ### Preapproval via JS SDK Add this field: ```javascript "preapprove": true ``` ### Authorize (Hold on Card) via JS SDK Add this field: ```javascript "authorize": true ``` ### CRITICAL: return_url and cancel_url must be `undefined` when using JS SDK **SECURITY WARNING:** The `hash` parameter must NEVER be generated on the client-side as it would expose your `merchant_secret`. Always generate the hash on your server and retrieve it to the client. --- ## Mobile SDKs ### Android SDK **Docs:** https://support.payhere.lk/api-&-mobile-sdk/android-sdk **GitHub:** https://github.com/PayHereLK/payhere-mobilesdk-android **Min API Level:** 17 #### Gradle Dependency ```groovy implementation 'lk.payhere:android-sdk:4.0.18' ``` #### One-Time Payment ```java InitRequest req = new InitRequest(); req.setMerchantId("1210XXX"); req.setCurrency("LKR"); req.setAmount(1000.00); req.setOrderId("230000123"); req.setItemsDescription("Door bell wireless"); req.setCustom1("Custom message 1"); req.setCustom2("Custom message 2"); req.getCustomer().setFirstName("Saman"); req.getCustomer().setLastName("Perera"); req.getCustomer().setEmail("samanp@gmail.com"); req.getCustomer().setPhone("+94771234567"); req.getCustomer().getAddress().setAddress("No.1, Galle Road"); req.getCustomer().getAddress().setCity("Colombo"); req.getCustomer().getAddress().setCountry("Sri Lanka"); req.setNotifyUrl("https://yourserver.com/notify"); Intent intent = new Intent(this, PHMainActivity.class); intent.putExtra(PHConstants.INTENT_EXTRA_DATA, req); launcher.launch(intent); ``` #### Recurring Payment (add to InitRequest) ```java req.setRecurrence("1 Month"); req.setDuration("Forever"); req.setStartupFee(0); ``` ### iOS SDK **Docs:** https://support.payhere.lk/api-&-mobile-sdk/payhere-ios **GitHub:** https://github.com/PayHereLK/payhere-mobilesdk-ios **Min iOS:** 13.0 #### CocoaPods ```ruby pod 'payHereSDK' ``` #### One-Time Payment (Swift) ```swift let item = Item(id: "item_1", name: "Item 1", quantity: 1, amount: 50.0) let initRequest = PHInitialRequest( merchantID: merchantID, notifyURL: "https://yourserver.com/notify", firstName: "Saman", lastName: "Perera", email: "samanp@gmail.com", phone: "+9477123456", address: "No.1, Galle Road", city: "Colombo", country: "Sri Lanka", orderID: "001", itemsDescription: "Greeting Card", itemsMap: [item], currency: .LKR, amount: 50.00, deliveryAddress: "", deliveryCity: "", deliveryCountry: "", custom1: "", custom2: "" ) PHPrecentController.precent( from: self, isSandBoxEnabled: true, withInitRequest: initRequest!, delegate: self ) ``` #### Delegate Response ```swift extension ViewController: PHViewControllerDelegate { func onResponseReceived(response: PHResponse?) { if response?.isSuccess() == true { guard let resp = response?.getData() as? StatusResponse else { return } // Payment success } else { // Payment failed: response?.getMessage() } } } ``` ### React Native SDK **Docs:** https://support.payhere.lk/api-&-mobile-sdk/react-native-sdk **GitHub:** https://github.com/PayHereLK/payhere-mobilesdk-reactnative **NPM:** `@payhere/payhere-mobilesdk-reactnative` ```bash npm install @payhere/payhere-mobilesdk-reactnative ``` ```javascript import PayHere from '@payhere/payhere-mobilesdk-reactnative'; const paymentObject = { "sandbox": true, "merchant_id": "1211149", "notify_url": "http://sample.com/notify", "order_id": "ItemNo12345", "items": "Hello from React Native!", "amount": "50.00", "currency": "LKR", "first_name": "Saman", "last_name": "Perera", "email": "samanp@gmail.com", "phone": "0771234567", "address": "No.1, Galle Road", "city": "Colombo", "country": "Sri Lanka" }; PayHere.startPayment( paymentObject, (paymentId) => { console.log("Payment Completed", paymentId); }, (errorData) => { console.log("Payment Failed", errorData); }, () => { console.log("Payment Dismissed"); } ); ``` ### Flutter SDK **Docs:** https://support.payhere.lk/api-&-mobile-sdk/flutter-sdk **GitHub:** https://github.com/PayHereLK/payhere-mobilesdk-flutter **Pub.dev:** `payhere_mobilesdk_flutter` ```yaml dependencies: payhere_mobilesdk_flutter: ^4.0.5 ``` ```dart import 'package:payhere_mobilesdk_flutter/payhere_mobilesdk_flutter.dart'; Map paymentObject = { "sandbox": true, "merchant_id": "1211149", "merchant_secret": "xyz", // Required for Flutter SDK "notify_url": "http://sample.com/notify", "order_id": "ItemNo12345", "items": "Hello from Flutter!", "amount": 50.00, "currency": "LKR", "first_name": "Saman", "last_name": "Perera", "email": "samanp@gmail.com", "phone": "0771234567", "address": "No.1, Galle Road", "city": "Colombo", "country": "Sri Lanka", }; PayHere.startPayment( paymentObject, (paymentId) { print("One Time Payment Success. Payment Id: $paymentId"); }, (error) { print("One Time Payment Failed. Error: $error"); }, () { print("One Time Payment Dismissed"); }, ); ``` #### Flutter Recurring Payment Add to paymentObject: ```dart "recurrence": "1 Month", "duration": "1 Year", "startup_fee": "10.00", ``` #### Flutter Preapproval (Tokenization) ```dart "preapprove": true, ``` #### Flutter Authorize (Hold on Card) ```dart "authorize": true, ``` #### Flutter ProGuard Rules (Android release builds) ```proguard -keep class lk.payhere.** { *; } -keep interface lk.payhere.androidsdk.PayhereSDK { *; } -keep class lk.payhere.androidsdk.models.** { *; } -keep class okhttp3.** { *; } -keep class okio.** { *; } -keep class retrofit2.** { *; } -keepattributes Signature -keepattributes *Annotation* ``` #### Flutter iOS Setup Run `pod install` in your iOS project directory after adding the dependency. --- ## Shopping Cart Plugins | Platform | Docs | |---|---| | OpenCart | https://support.payhere.lk/shopping-cart-plugins/plugin-for-opencart | | WooCommerce | https://support.payhere.lk/shopping-cart-plugins/plugin-for-woocommerce | | Magento | https://support.payhere.lk/shopping-cart-plugins/plugin-for-magento | | Prestashop | https://support.payhere.lk/shopping-cart-plugins/plugin-for-prestashop | | ShopHere | https://support.payhere.lk/shopping-cart-plugins/plugin-for-shophere | | Shopify | https://support.payhere.lk/shopping-cart-plugins/plugin-for-shopify-oneclick | | WHMCS | https://support.payhere.lk/shopping-cart-plugins/plugin-for-whmcs | | CS-Cart | https://support.payhere.lk/shopping-cart-plugins/plugin-for-cs-cart | | Moodle | https://support.payhere.lk/shopping-cart-plugins/plugin-for-moodle | **GitHub repos:** - WooCommerce: https://github.com/PayHereLK/payhere-woocommerce - OpenCart: https://github.com/PayHereLK/payhere-opencart - Moodle: https://github.com/PayHereLK/moodleplugin ### Shopify Plugin Setup 1. Go to PayHere Payment App installation page on Shopify 2. Click "Add App" > Choose your Shopify account > Click "Install app" 3. Enter Merchant ID and Merchant Secret 4. Untick "Sandbox Mode" for live payments 5. Click "Save" then "Activate PayHere Payment Gateway" --- ## PayHere Links & Buttons **Links:** Accept payments without a website. Create shareable payment links from your PayHere dashboard. **Buttons:** Embed a payment button on your website with minimal code (no API integration needed). --- ## Payment Notification (notify_url) This is the most critical part of the integration. PayHere sends a server-to-server POST callback to your `notify_url` after each payment. ### Notification POST Parameters | Parameter | Description | |---|---| | `merchant_id` | Your Merchant ID | | `order_id` | Your order reference | | `payment_id` | PayHere payment reference number | | `payhere_amount` | Amount paid | | `payhere_currency` | Currency of payment | | `status_code` | `2`=success, `0`=pending, `-1`=canceled, `-2`=failed, `-3`=chargebacked | | `md5sig` | Verification checksum | | `method` | Payment method: `VISA`, `MASTER`, `AMEX`, `EZCASH`, `MCASH`, `GENIE`, `VISHWA`, `PAYAPP`, `HNB`, `FRIMI` | | `status_message` | Gateway message | | `custom_1` | Custom field 1 | | `custom_2` | Custom field 2 | ### VISA/MASTER Card Additional Parameters | Parameter | Description | |---|---| | `card_holder_name` | Name on card | | `card_no` | Masked card number | | `card_expiry` | Card expiry date | ### CRITICAL: Verifying md5sig Always verify the md5sig checksum before trusting the notification: ``` md5sig = UPPER(MD5( merchant_id + order_id + payhere_amount + payhere_currency + status_code + UPPER(MD5(merchant_secret)) )) ``` Compare your locally generated md5sig with the one received. If they don't match, the notification may be tampered with — do NOT process the payment. ### Important Notes About notify_url - Notification is sent as `application/x-www-form-urlencoded`, NOT `application/json` - `notify_url` must be a publicly accessible URL (no localhost) - Cannot test with `print`/`echo` — it's a server callback, not a browser request - No payment params are sent to `return_url` — update your DB from `notify_url`, then read from DB on `return_url` --- ## Hash Generation The hash is used to verify the integrity of payment request parameters. It MUST be generated server-side to protect your merchant_secret. ### Formula ``` hash = UPPER(MD5( merchant_id + order_id + amount_formatted + currency + UPPER(MD5(merchant_secret)) )) ``` **Where `amount_formatted`** is the amount with exactly 2 decimal places (e.g., `1000.00`). ### PHP Example ```php $hash = strtoupper( md5( $merchant_id . $order_id . number_format($amount, 2, '.', '') . $currency . strtoupper(md5($merchant_secret)) ) ); ``` ### Node.js Example ```javascript const crypto = require('crypto'); function generateHash(merchantId, orderId, amount, currency, merchantSecret) { const hashedSecret = crypto.createHash('md5') .update(merchantSecret) .digest('hex') .toUpperCase(); const amountFormatted = parseFloat(amount).toFixed(2); const hash = crypto.createHash('md5') .update(merchantId + orderId + amountFormatted + currency + hashedSecret) .digest('hex') .toUpperCase(); return hash; } ``` ### Python Example ```python import hashlib def generate_hash(merchant_id, order_id, amount, currency, merchant_secret): hashed_secret = hashlib.md5(merchant_secret.encode()).hexdigest().upper() amount_formatted = f"{float(amount):.2f}" raw = merchant_id + order_id + amount_formatted + currency + hashed_secret return hashlib.md5(raw.encode()).hexdigest().upper() ``` ### Java Example ```java import java.math.BigInteger; import java.security.MessageDigest; import java.text.DecimalFormat; public static String generateHash(String merchantId, String orderId, double amount, String currency, String merchantSecret) { DecimalFormat df = new DecimalFormat("0.00"); String amountFormatted = df.format(amount); String hash = getMd5(merchantId + orderId + amountFormatted + currency + getMd5(merchantSecret)); return hash; } public static String getMd5(String input) { try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] messageDigest = md.digest(input.getBytes()); BigInteger no = new BigInteger(1, messageDigest); String hashtext = no.toString(16); while (hashtext.length() < 32) hashtext = "0" + hashtext; return hashtext.toUpperCase(); } catch (Exception e) { throw new RuntimeException(e); } } ``` ### C# Example ```csharp using System.Security.Cryptography; using System.Text; static string GenerateHash(string merchantId, string merchantSecret, string orderId, double amount, string currency) { string hashedSecret = ComputeMD5(merchantSecret); string amountFormatted = amount.ToString("####0.00"); return ComputeMD5(merchantId + orderId + amountFormatted + currency + hashedSecret); } static string ComputeMD5(string s) { StringBuilder sb = new StringBuilder(); using (MD5 md5 = MD5.Create()) { byte[] hashValue = md5.ComputeHash(Encoding.UTF8.GetBytes(s)); foreach (byte b in hashValue) sb.Append($"{b:X2}"); } return sb.ToString(); } ``` --- ## OAuth Authentication (Merchant APIs) The Charging, Retrieval, Subscription Manager, Refund, and Capture APIs all use OAuth Bearer tokens. ### Step 1: Create API Key 1. Sign in to PayHere > Settings > API Keys 2. Click "Create API Key" 3. Enter app name and comma-separated domains to whitelist 4. Copy the **App ID** and **App Secret** ### Step 2: Generate Authorization Code Base64-encode your `App_ID:App_Secret`: ``` Base64Encode("4OVx33RVOPg4DzdZUzq4A94D2:8n4VCj25MXp4JLDFyvsE9h4a8qgbPaZUI4JEWK4FCvop") ``` ### Step 3: Get Access Token ``` POST https://www.payhere.lk/merchant/v1/oauth/token (Live) POST https://sandbox.payhere.lk/merchant/v1/oauth/token (Sandbox) Headers: Authorization: Basic Content-Type: application/x-www-form-urlencoded Body: grant_type=client_credentials ``` Response: ```json { "access_token": "cb5c47fd-741c-489a-b69e-fd73155ca34e", "token_type": "bearer", "expires_in": 599, "scope": "SANDBOX" } ``` ### Step 4: Use Access Token Include in all subsequent API requests: ``` Authorization: Bearer cb5c47fd-741c-489a-b69e-fd73155ca34e ``` **Note:** Access tokens expire (default ~10 minutes). Retrieve a new one when expired. ### Live Environment IP Whitelisting For live Merchant APIs, PayHere enforces IP-based whitelisting. Email `support@payhere.lk` with your server IP address to get whitelisted. --- ## Sandbox & Testing **Docs:** https://support.payhere.lk/sandbox-and-testing ### Sandbox Portal - URL: https://sandbox.payhere.lk - Create a separate sandbox account (not linked to live account) - No real payments processed — all transactions are simulated ### Test Card Numbers (Successful Payments) | Card Number | Type | |---|---| | `4916217501611292` | Visa | | `5307732125531191` | Mastercard | | `346781005510225` | Amex | For "Name on Card", "CVV" & "Expiry date" — enter any valid data. ### Test Cards for Decline Scenarios Any card number NOT in the list above will result in a failed payment in sandbox. ### Switching to Sandbox in Code - Change API endpoint from `www.payhere.lk` to `sandbox.payhere.lk` - Set `sandbox: true` in JS SDK / Mobile SDK payment objects - For plugins: enable "Sandbox Mode" checkbox in plugin settings --- ## Payment Limits, Fees & Plans **Docs:** https://support.payhere.lk/limits-and-fees ### Service Plans | Plan | Monthly Fee | Processing Fee | Per Payment Limit | Monthly Limit | Features | |---|---|---|---|---|---| | **LITE** | Free | 3.99% | Rs.50,000 | Rs.200,000 | LKR & USD one-time payments only | | **PLUS** | Rs.3,990 | 2.99% | Rs.250,000 | Rs.3,000,000 | One-time + Recurring. LKR/USD/EUR/GBP/AUD | | **PREMIUM** | Rs.9,990 | 2.69% | Rs.1,000,000 | Unlimited | All features + Automatic Payments (Tokenization) | | **EDU** | Rs.9,990 | 2.49% | Rs.1,000,000 | Unlimited | Education-only payments | | **GOV** | Free | 1.99% | Rs.1,000,000 | Unlimited | Government-only. LKR via Visa/Master/HelaPay | ### Limit Types - **Per Payment Limit** — Max amount per single transaction - **Monthly Payment Limit** — Max total accepted within a billing month - **Over Limit** — Customer sees error on payment page when limits exceeded --- ## Supported Payment Methods & Currencies ### Payment Methods - Visa (credit/debit) - Mastercard (credit/debit) - American Express (AMEX) - eZ Cash (mobile wallet) - mCash (mobile wallet) - Genie (mobile wallet) - Vishwa (mobile wallet) - PayApp - HNB (bank) - FriMi (mobile wallet) - HelaPay ### Supported Currencies - `LKR` — Sri Lankan Rupee - `USD` — US Dollar - `EUR` — Euro - `GBP` — British Pound - `AUD` — Australian Dollar ### USD Payouts PayHere supports USD payouts for merchants who accept payments in USD. See: https://support.payhere.lk/usd-payouts --- ## Application Process **Docs:** https://support.payhere.lk/application-process ### Who Can Apply Any registered business entity in Sri Lanka: - Private Limited Companies - Sole Proprietorships - Partnerships - Home-based businesses (social media) - Freelancers - Clubs/Associations - Government Organizations ### Prerequisites - **No application fees or setup fees** — completely free to apply - Website/app must be complete and ready to go live (not under construction) - Must display: Terms & Conditions, Return/Refund Policy, Privacy Policy - Must display: Business name, phone, email, postal address ### Required Signatories - Private Limited Company: Two directors + company secretary - Other types: Varies by business type ### Important Notes - PayHere is strictly for business payments (goods/services exchanged) - Mock products/services or incomplete content will be rejected - Applications typically processed within a few business days --- ## Policy Requirements **Docs:** https://support.payhere.lk/policy-samples Your website/app MUST display these policy documents (activation will be rejected without them): 1. **Refund Policy** — Conditions for refunds, timeframes, process 2. **Privacy Policy** — Data collection, usage, protection practices 3. **Terms & Conditions** — Usage terms, purchase terms, liability PayHere provides sample policy templates at the docs link above. Customize them for your business. --- ## Onsite Checkout **Docs:** https://support.payhere.lk/faq/onsite-checkout Onsite Checkout displays the payment form as a popup within your website (via iframe), instead of redirecting to PayHere's site. ### Requirements - Website must be served over HTTPS (SSL certificate required) - Use the JavaScript SDK (payhere.js) for web integration - Use Mobile SDKs for in-app payment experience ### Security Payment credentials are captured inside a PCI DSS certified secure iframe served directly by PayHere's servers. Security is not compromised. ### Benefits - Better conversion rates (no redirect) - Seamless customer experience - Customer stays on your website throughout --- ## Common Pitfalls & FAQs ### Integration Pitfalls 1. **notify_url cannot be localhost** — Must be publicly accessible IP/domain 2. **Hash must be generated server-side** — Never expose merchant_secret in client code 3. **Notification is URL-encoded, not JSON** — Parse as `application/x-www-form-urlencoded` 4. **No payment data in return_url** — Update DB from notify_url, read from DB on return_url 5. **Always verify md5sig** — Never trust notification data without checksum verification 6. **Amount must have exactly 2 decimal places** in hash calculation (e.g., `1000.00`) 7. **order_id uniqueness not enforced** — PayHere doesn't validate; you must ensure uniqueness 8. **JS SDK: set return_url and cancel_url to undefined** — Not empty string, must be `undefined` 9. **Access tokens expire** — Re-fetch OAuth token when expired (~10 min) 10. **Live Merchant APIs require IP whitelisting** — Email support@payhere.lk with server IP ### FAQ **Q: Can I test on localhost?** A: The payment gateway itself can be tested on localhost, but the `notify_url` callback cannot reach localhost. Use a tunneling service (ngrok) or a public server for testing notifications. **Q: What happens when monthly limit is exceeded?** A: Customer sees an "Over Limit" error on the payment page. Upgrade your plan for higher limits. **Q: Can I accept payments without a website?** A: Yes! Use PayHere Links to create shareable payment URLs. No website needed. **Q: How long does domain/app approval take?** A: Up to 24 hours for domain/app approval for Merchant Secret generation. Live account app package names may require manual review (up to 1 business day). **Q: What are the supported recurrence values?** A: Format is `{number} {unit}` where unit is `Week`, `Month`, or `Year` (singular). Examples: `1 Month`, `2 Week`, `6 Month`, `1 Year`. **Q: What are the supported duration values?** A: Same format as recurrence, or `Forever` for unlimited. Duration must be compatible with recurrence unit. --- ## Documentation Links ### Main Docs | Page | URL | |---|---| | Knowledge Base Home | https://support.payhere.lk/ | | General Questions | https://support.payhere.lk/general-questions | | Application Process | https://support.payhere.lk/application-process | | Payment Limits & Fees | https://support.payhere.lk/limits-and-fees | | Sandbox & Testing | https://support.payhere.lk/sandbox-and-testing | | Policy Samples | https://support.payhere.lk/policy-samples | | Onsite Checkout | https://support.payhere.lk/faq/onsite-checkout | ### APIs | API | URL | |---|---| | Checkout API | https://support.payhere.lk/api-&-mobile-sdk/checkout-api | | Recurring API | https://support.payhere.lk/api-&-mobile-sdk/recurring-api | | Preapproval API | https://support.payhere.lk/api-&-mobile-sdk/preapproval-api | | Charging API | https://support.payhere.lk/api-&-mobile-sdk/charging-api | | Retrieval API | https://support.payhere.lk/api-&-mobile-sdk/retrieval-api | | Subscription Manager API | https://support.payhere.lk/api-&-mobile-sdk/subscription-manager-api | | Refund API | https://support.payhere.lk/api-&-mobile-sdk/refund-api | | Authorize API | https://support.payhere.lk/api-&-mobile-sdk/authorize-api | | Capture API | https://support.payhere.lk/api-&-mobile-sdk/capture-api | ### SDKs | SDK | URL | |---|---| | JavaScript SDK | https://support.payhere.lk/api-&-mobile-sdk/javascript-sdk | | Android SDK | https://support.payhere.lk/api-&-mobile-sdk/android-sdk | | iOS SDK | https://support.payhere.lk/api-&-mobile-sdk/payhere-ios | | React Native SDK | https://support.payhere.lk/api-&-mobile-sdk/react-native-sdk | | Flutter SDK | https://support.payhere.lk/api-&-mobile-sdk/flutter-sdk | ### Plugins | Plugin | URL | |---|---| | OpenCart | https://support.payhere.lk/shopping-cart-plugins/plugin-for-opencart | | WooCommerce | https://support.payhere.lk/shopping-cart-plugins/plugin-for-woocommerce | | Magento | https://support.payhere.lk/shopping-cart-plugins/plugin-for-magento | | Prestashop | https://support.payhere.lk/shopping-cart-plugins/plugin-for-prestashop | | Shopify | https://support.payhere.lk/shopping-cart-plugins/plugin-for-shopify-oneclick | | WHMCS | https://support.payhere.lk/shopping-cart-plugins/plugin-for-whmcs | | CS-Cart | https://support.payhere.lk/shopping-cart-plugins/plugin-for-cs-cart | | Moodle | https://support.payhere.lk/shopping-cart-plugins/plugin-for-moodle | | ShopHere | https://support.payhere.lk/shopping-cart-plugins/plugin-for-shophere | ### GitHub Repositories | Repo | URL | |---|---| | PayHere Org | https://github.com/PayHereLK | | Android SDK | https://github.com/PayHereLK/payhere-mobilesdk-android | | iOS SDK | https://github.com/PayHereLK/payhere-mobilesdk-ios | | React Native SDK | https://github.com/PayHereLK/payhere-mobilesdk-reactnative | | Flutter SDK | https://github.com/PayHereLK/payhere-mobilesdk-flutter | | WooCommerce Plugin | https://github.com/PayHereLK/payhere-woocommerce | | OpenCart Plugin | https://github.com/PayHereLK/payhere-opencart | | Demo (PHP) | https://github.com/PayHereLK/payhere-demo-beta | | Laravel Package (Community) | https://github.com/Visanduma/laravel-payhere | | JS SDK (Community) | https://github.com/pavinduLakshan/payhere-js-sdk | ### Community Packages | Package | Platform | URL | |---|---|---| | `@payhere-js-sdk/client` | NPM (Browser) | https://github.com/pavinduLakshan/payhere-js-sdk | | `@payhere-js-sdk/server` | NPM (Node.js) | https://github.com/pavinduLakshan/payhere-js-sdk | | `lahirulhr/laravel-payhere` | Composer (Laravel) | https://github.com/Visanduma/laravel-payhere | | `payhere_mobilesdk_flutter` | pub.dev (Flutter) | https://pub.dev/packages/payhere_mobilesdk_flutter | | `@payhere/payhere-mobilesdk-reactnative` | NPM (React Native) | https://www.npmjs.com/package/@payhere/payhere-mobilesdk-reactnative | --- ## Quick Reference: Integration Decision Tree ``` Need to accept payments? ├── No website? → Use PayHere Links ├── Website, no coding? → Use PayHere Buttons or Shopping Cart Plugins ├── Website, with coding? │ ├── Want redirect flow? → Checkout API (one-time) or Recurring API (subscription) │ ├── Want popup/onsite? → JavaScript SDK (payhere.js) │ └── Need server-to-server? │ ├── Charge on demand? → Preapproval API + Charging API │ ├── Hold then capture? → Authorize API + Capture API │ ├── Get payment details? → Retrieval API │ ├── Manage subscriptions? → Subscription Manager API │ └── Process refunds? → Refund API └── Mobile App? ├── Android? → Android SDK ├── iOS? → iOS SDK ├── React Native? → React Native SDK └── Flutter? → Flutter SDK ``` --- ## Quick Reference: Status Codes | Code | Meaning | Action | |---|---|---| | `2` | Payment success | Fulfill order | | `0` | Payment pending | Wait for final status | | `-1` | Payment canceled | Show cancellation to user | | `-2` | Payment failed/chargebacked | Do not fulfill, contact customer | | `-3` | Chargebacked | Payment reversed by bank | --- *This file was created by Theepan Kaja (https://theepankaja.website) as a community resource for AI coding assistants and agents. This is NOT an official PayHere product or document. For the most up-to-date and authoritative information, always refer to the official documentation at https://support.payhere.lk*