Bohudur Laravel SDK
Developer-first Laravel SDK for the Bohudur Payment Automation Platform.
This package is a Laravel wrapper around the Bohudur Payment API, providing a clean service-based architecture, Facade access, and fluent request builders.
Requirements
| Requirement | Value |
|---|---|
| PHP | ^8.0 |
| Laravel | 10.x, 11.x, 12.x, 13.x |
| Extensions | curl, json |
Installation
Step 1: Install Package
composer require bohudur/laravel-sdk:^1.1.1Step 2: Add Your API Key
The SDK supports two ways to provide your API key. Both work independently — you don't need to set up both, just pick whichever fits your use case.
- Option 1 — From
.env(recommended for most projects)
This is the standard approach. Add your Bohudur API key to your Laravel .env file:
BOHUDUR_API_KEY=your_api_key_hereThat's all. The SDK automatically reads this value every time you make a request — no extra code, no configuration needed. This is the best choice when your entire application uses a single API key.
- Option 2 — At runtime via
Bohudur::init()(for dynamic keys)
Sometimes you can't hardcode the API key in .env — for example, if you are building a multi-merchant platform where each merchant has their own Bohudur account and their own API key. In that case, use Bohudur::init() to pass the key at runtime before making any request.
use App\Modules\Bohudur\Facades\Bohudur;
use App\Modules\Bohudur\Exceptions\BohudurException;
try {
Bohudur::init('your_api_key_here'); // Set the key first
} catch (BohudurException $e) {
echo $e->getMessage();
}Important
Always call Bohudur::init() before calling request(), execute(), or query(). If you call init(), it takes priority over whatever is set in .env for that request. If you do not call init(), the SDK falls back to BOHUDUR_API_KEY from .env automatically.
Keep your API key secret
Never expose your API key in frontend JavaScript, mobile apps, or public repositories. Your API key gives full access to your Bohudur account. Always use this SDK on a secure backend server only.
API Flow Overview (Laravel)
- Create payment
- Redirect customer to hosted checkout
- Customer completes or cancels payment
- Execute payment
- Receive webhook (optional)
- Query payment anytime
This flow is identical to the PHP SDK and cURL API.
Create Payment (Laravel)
Creates a new payment session and returns a hosted checkout URL.
Example
use App\Modules\Bohudur\Facades\Bohudur;
use App\Modules\Bohudur\Exceptions\BohudurException;
try {
$response = Bohudur::request()
->fullName('Jane Doe')
->email('janedoe@gmail.com')
->amount(10)
->returnType('GET')
->redirectUrl('https://example.com/redirect')
->cancelUrl('https://example.com/cancel')
->metadata([
'order_id' => 'ORD-1001',
'user_id' => 55
])
->webhook([
'success' => 'https://example.com/success',
'cancel' => 'https://example.com/cancel'
])
->send();
} catch (BohudurException $e) {
echo $e->getMessage();
}Create Payment Parameters
| Method | Required | Type | Description |
|---|---|---|---|
fullName() | YES | string | Customer full name |
email() | YES | string | Customer email |
amount() | YES | float | Payment amount |
returnType() | YES | string | GET or POST |
redirectUrl() | YES | string | Redirect URL after success |
cancelUrl() | YES | string | Redirect URL after cancellation |
metadata() | NO | array | Custom key-value data |
webhook() | NO | array | Webhook URLs |
Success Response
{
"responseCode": 200,
"message": "Payment created successfully",
"status": "success",
"paymentkey": "5RWS4w2w1R5nFAvoP5U0JS4O74UrMXGt",
"payment_url": "https://checkout.bohudur.one/payment/5RWS4w2w1R5nFAvoP5U0JS4O74UrMXGt"
}| Field | Type | Description |
|---|---|---|
responseCode | number | 200 on success |
message | string | Human-readable result message |
status | string | Always "success" on success |
paymentkey | string | Unique 32-character key for this payment — store this |
payment_url | string | Hosted checkout URL — redirect your customer here |
Failed Response
{
"responseCode": 3018,
"message": "Oops! Internal error. Try again",
"status": "failed"
}Create Payment Error Codes
| Code | Message | Description |
|---|---|---|
3000 | API key not found | AH-BOHUDUR-API-KEY header is missing |
3001 | Required parameters not found | One or more required fields are missing |
3002 | --- parameter is empty | Specific field value is empty |
3003 | Invalid Full Name Format | full_name must be a valid non-empty string |
3004 | Invalid Email Format | Email address is not valid |
3005 | Invalid Amount Format | Amount must be a positive numeric value |
3006 | Invalid Return Type Format | Only GET or POST allowed |
3007 | Invalid Return URL Format | redirect_url is not a valid URL |
3008 | Invalid Cancel URL Format | cancel_url is not a valid URL |
3009 | Invalid JSON format in metadata | metadata must be a valid JSON object |
3010 | Invalid JSON format in webhook | webhook must be a valid JSON object |
3011 | Invalid webhook actions | Only success and cancel keys allowed in webhook |
3012 | Invalid JSON format in metadata or webhook | One or both JSON objects are malformed |
3013 | Invalid API key | API key is incorrect or inactive |
3014 | Oops! internal error. Try again. | Temporary server-side issue — retry |
3015 | Unknown amount provided | Amount value is not acceptable |
3016 | You don't have access | Request blocked due to IP restriction |
3017 | Oops! Internal error. Try again. | Unexpected internal server error |
3018 | Unable to create payment | Payment session could not be created |
Response objects are returned as stdClass, allowing direct access like:
$response->responseCode;
$response->payment_url;Redirecting Customer
if ($response->status === 'success') {
return redirect()->away($response->payment_url);
}Execute Payment (Laravel)
Finalizes a completed payment.
Example
$execute = Bohudur::execute('PAYMENT_KEY');Rules
- Can be executed only once
- Payment must be COMPLETED
- Executed payments are final
Execute Response (Success)
{
"full_name": "Gabriel Adams",
"email": "janedoe@gmail.com",
"amount": 40,
"converted_amount": 4878,
"total_amount": 40,
"transaction_fee": 0,
"default_currency": "USD",
"payment_currency": "BDT",
"currency_value": 121.951,
"metadata": [],
"created_time": "2026-01-04 16:04:35",
"payment_time": "2026-01-04 16:12:37",
"paymentkey": "fnPwIkdIsMjN4FJxYxw6DF75GuW9qStn",
"webhook": [],
"payment_info": {
"m0": "SSLCommerz",
more....
},
"status": "EXECUTED"
}Execute Response Parameters
| Field | Type | Description |
|---|---|---|
full_name | string | Customer full name |
email | string | Customer email address |
amount | number | Original payment amount in your default currency |
converted_amount | number | Amount converted to the payment currency |
total_amount | number | Total amount charged including any fees |
transaction_fee | number | Transaction fee applied (0 if none) |
default_currency | string | Your account's default currency code |
payment_currency | string | Currency the customer actually paid in |
currency_value | number | Exchange rate used (default → payment currency) |
metadata | array/object | Custom data attached during payment creation |
created_time | string | Timestamp when payment session was created |
payment_time | string | Timestamp when customer completed payment |
paymentkey | string | Unique 32-character payment identifier |
receipt | string | URL to download the PDF receipt for this payment |
webhook | array/object | Webhook URLs configured for this payment |
payment_info | object | Gateway-specific transaction details |
payment_info.m0 | string | Payment gateway used (e.g. "Stripe", "SSLCommerz") |
status | string | Always "EXECUTED" on success |
Execute Error Response
{
"responseCode": 3108,
"message": "Payment already executed!",
"status": "failed"
}Execute Error Codes
| Code | Message | Description |
|---|---|---|
3100 | API key not found | AH-BOHUDUR-API-KEY header missing |
3101 | API key not valid | API key is invalid or inactive |
3102 | Invalid Payment Key | paymentkey is malformed or does not exist |
3103 | Invalid api key | API key does not match any active account |
3104 | You don't have access! Your IP: ... | Your server IP is not authorized |
3105 | Payment Data Not Found | No payment exists for this paymentkey |
3106 | Payment is pending! | Customer has not completed payment yet |
3107 | Payment is cancelled! | Payment was cancelled — cannot be executed |
3108 | Payment already executed! | This payment was already executed once |
3109 | Failed to execute payment | Server or processing error |
Response objects are returned as stdClass, allowing direct access like:
$response->responseCode;
$response->status;
$response->amount;Execute is One-Time Only
A payment can be executed exactly once. Any second attempt returns 3108. This is intentional — it prevents duplicate charges. Always store the execute response in your database immediately after a successful execution.
Query Payment (Laravel)
Retrieve payment information at any time.
Example
$query = Bohudur::query('PAYMENT_KEY');Query Response Types
The Query API returns one of four responses based on the current payment status.
1. PENDING
Payment session created but the user has not yet completed payment.
{
"full_name": "Chloe Morales",
"email": "chloe@gmail.com",
"amount": 1,
"converted_amount": 1,
"total_amount": 1,
"transaction_fee": 0,
"default_currency": "USD",
"payment_currency": "USD",
"currency_value": 1,
"metadata": [],
"created_time": "2026-01-07 10:02:20",
"payment_time": "NONE",
"paymentkey": "7QWQsOhg9X7dgQlfRO4EPxWKK9qaCWka",
"receipt": "NONE",
"webhook": [],
"payment_info": [],
"status": "PENDING"
}2. COMPLETED
User has paid. Payment is ready to be executed by your server.
{
"full_name": "Jane Doe",
"email": "jane@gmail.com",
"amount": 150,
"converted_amount": 150,
"total_amount": 150,
"transaction_fee": 0,
"default_currency": "USD",
"payment_currency": "USD",
"currency_value": 1,
"metadata": [],
"created_time": "2025-12-11 21:47:11",
"payment_time": "2025-12-11 23:11:25",
"paymentkey": "TYtsYll15iqsDqsR4h8EJrMfou9NavE2",
"receipt": "https://pay.bohudur.one/receipt/download/102f89389f9e",
"webhook": [],
"payment_info": {
"m0": "Stripe",
more....
},
"status": "COMPLETED"
}Note
status: "COMPLETED" means the customer has paid. You must now call /execute/v2/ to finalize and deliver your product or service.
3. EXECUTED
Payment has been finalized by your server via the Execute API.
{
"full_name": "Gabriel Adams",
"email": "gabriel@gmail.com",
"amount": 40,
"converted_amount": 4878,
"total_amount": 40,
"transaction_fee": 0,
"default_currency": "USD",
"payment_currency": "BDT",
"currency_value": 121.951,
"metadata": [],
"created_time": "2026-01-04 16:04:35",
"payment_time": "2026-01-04 16:12:37",
"paymentkey": "fnPwIkdIsMjN4FJxYxw6DF0I92W9qStn",
"receipt": "https://pay.bohudur.one/receipt/download/102f89389f9e",
"webhook": [],
"payment_info": {
"m0": "SSLCommerz",
more....
},
"status": "EXECUTED"
}4. CANCELLED
Payment was cancelled by the user or system. Cannot be executed.
{
"full_name": "Jane Doe",
"email": "jane@gmail.com",
"amount": 1,
"converted_amount": 1,
"total_amount": 1,
"transaction_fee": 0,
"default_currency": "USD",
"payment_currency": "USD",
"currency_value": 1,
"metadata": {
"order_id": "ORD-1001",
"user_id": 55
},
"created_time": "2026-01-18 19:30:56",
"payment_time": "NONE",
"paymentkey": "P4m1OEiopqPy4cFx9QO0mARuzqxx7bsf",
"receipt": "NONE",
"webhook": {
"success": "https://example.com/success.php",
"cancel": "https://example.com/cancel.php"
},
"payment_info": [],
"status": "CANCELLED"
}The Query API may return one of the following statuses:
| Status | Description |
|---|---|
PENDING | Payment created but not completed |
COMPLETED | Payment completed, ready for execute |
EXECUTED | Payment finalized |
CANCELLED | Payment cancelled |
Payment Info By Gateways
{
"payment_info": {
"id": 1,
"gateway": "bkash",
"method": "Send Money",
"number": "01XXXXXXXXX",
"amount": 100,
"trx": "TRX123ABC456",
"time": "01/01/2026 12:00",
"m0": "Bkash Send Money"
}
}{
"payment_info": {
"id": 1,
"gateway": "nagad",
"method": "Send Money",
"number": "01XXXXXXXXX",
"amount": 100,
"trx": "TRX123ABC456",
"time": "01/01/2026 12:00",
"m0": "Nagad Send Money"
}
}{
"payment_info": {
"id": 1,
"gateway": "rocket",
"method": "Send Money",
"number": "01XXXXXXXXX",
"amount": 100,
"trx": "TRX123ABC456",
"time": "01/01/2026 12:00",
"m0": "Rocket Send Money"
}
}{
"payment_info": {
"id": 1,
"gateway": "upay",
"method": "Send Money",
"number": "01XXXXXXXXX",
"amount": 100,
"trx": "TRX123ABC456",
"time": "01/01/2026 12:00",
"m0": "Upay Send Money"
}
}{
"payment_info": {
"id": 1,
"gateway": "mcash",
"method": "Send Money",
"number": "01XXXXXXXXX",
"amount": 100,
"trx": "TRX123ABC456",
"time": "01/01/2026 12:00",
"m0": "mCash Send Money"
}
}{
"paymentID": "TRX_PAYMENT_ID_EXAMPLE",
"trxID": "TRX123ABC456",
"transactionStatus": "Completed",
"amount": "100",
"currency": "BDT",
"intent": "sale",
"paymentExecuteTime": "2026-01-01T12:00:00 GMT+0600",
"merchantInvoiceNumber": "invoice_demo_12345",
"payerType": "Customer",
"payerReference": "CUSTOMER_REF",
"customerMsisdn": "01XXXXXXXXX",
"payerAccount": "01XXXXXXXXX",
"maxRefundableAmount": "100",
"statusCode": "0000",
"statusMessage": "Successful",
"m0": "Bkash Merchant"
}{
"status": "VALID",
"tran_date": "2026-01-01 12:00:00",
"tran_id": "SSLCZ_DEMO_TRANSACTION",
"val_id": "VALIDATION_ID_EXAMPLE",
"amount": "100.00",
"store_amount": "97.50",
"currency": "BDT",
"bank_tran_id": "BANK_TRANSACTION_ID",
"card_type": "NAGAD-Nagad",
"card_no": "",
"card_issuer": "Nagad",
"card_brand": "MOBILEBANKING",
"card_category": "MOBILE",
"card_sub_brand": "",
"card_issuer_country": "Bangladesh",
"card_issuer_country_code": "BD",
"currency_type": "BDT",
"currency_amount": "100.00",
"currency_rate": "1.0000",
"base_fair": "0.00",
"value_a": "",
"value_b": "",
"value_c": "",
"value_d": "",
"emi_instalment": "0",
"emi_amount": "0.00",
"emi_description": "",
"emi_issuer": "Nagad",
"account_details": "",
"risk_title": "Safe",
"risk_level": "0",
"discount_percentage": "0",
"discount_amount": "0.00",
"discount_remarks": "",
"APIConnect": "DONE",
"validated_on": "2026-01-01 12:00:10",
"gw_version": "",
"offer_avail": 1,
"card_ref_id": "CARD_REFERENCE_ID_EXAMPLE",
"isTokeizeSuccess": 0,
"campaign_code": "",
"m0": "SSLCommerz"
}{
"id": "pi_demo_payment_intent",
"object": "payment_intent",
"amount": 10000,
"amount_capturable": 0,
"amount_details": {
"tip": []
},
"amount_received": 10000,
"application": null,
"application_fee_amount": null,
"automatic_payment_methods": null,
"canceled_at": null,
"cancellation_reason": null,
"capture_method": "automatic_async",
"client_secret": "pi_demo_payment_intent_secret_example",
"confirmation_method": "automatic",
"created": 1767225600,
"currency": "usd",
"customer": null,
"customer_account": null,
"description": "Demo Payment",
"excluded_payment_method_types": null,
"last_payment_error": null,
"latest_charge": "ch_demo_charge_id",
"livemode": false,
"managed_payments": {
"enabled": false
},
"metadata": [],
"next_action": null,
"on_behalf_of": null,
"payment_details": {
"customer_reference": null,
"order_reference": "ORDER_REFERENCE_EXAMPLE"
},
"payment_method": "pm_demo_payment_method",
"payment_method_configuration_details": null,
"payment_method_options": {
"card": {
"installments": null,
"mandate_options": null,
"network": null,
"request_three_d_secure": "automatic"
}
},
"payment_method_types": [
"card"
],
"presentment_details": {
"presentment_amount": 12000,
"presentment_currency": "bdt"
},
"processing": null,
"receipt_email": "customer@example.com",
"review": null,
"setup_future_usage": null,
"shared_payment_granted_token": null,
"shipping": null,
"source": null,
"statement_descriptor": null,
"statement_descriptor_suffix": null,
"status": "succeeded",
"transfer_data": null,
"transfer_group": null,
"m0": "Stripe"
}{
"uid": 123456789,
"counterpartyId": 987654321,
"orderId": "ORDER_ID_EXAMPLE",
"orderType": "CRYPTO_BOX",
"transactionId": "TRANSACTION_ID_EXAMPLE",
"transactionTime": 1767225600000,
"amount": "10.00",
"currency": "USDT",
"walletType": 1,
"walletTypes": [
"1"
],
"fundsDetail": [
{
"currency": "USDT",
"amount": "10.00"
"walletAssetCost": {
"1": "10.00"
}
}
],
"payerInfo": {
"name": "John Doe",
"type": "USER",
"email": "customer@example.com",
"countryCode": 880,
"phoneNumber": "01XXXXXXXXX",
"mobileCode": "BD",
"unmaskData": false
},
"receiverInfo": {
"binanceId": 123456789,
"accountId": 987654321,
"unmaskData": false
},
"totalPaymentFee": "0",
"m0": "Binance Personal"
}Query Response Fields
| Field | Type | Description |
|---|---|---|
full_name | string | Customer full name |
email | string | Customer email |
amount | number | Original payment amount |
converted_amount | number | Amount in the payment currency |
total_amount | number | Total charged including fees |
transaction_fee | number | Fee applied (0 if none) |
default_currency | string | Your account default currency |
payment_currency | string | Currency customer paid in |
currency_value | number | Exchange rate applied |
metadata | array/object | Custom data from payment creation |
created_time | string | Payment creation timestamp |
payment_time | string | When customer completed payment ("NONE" if not yet) |
paymentkey | string | Unique payment identifier |
receipt | string | PDF receipt download URL ("NONE" if not yet available) |
webhook | array/object | Configured webhook URLs |
payment_info | array/object | Gateway transaction data (empty if pending) |
status | string | PENDING / COMPLETED / EXECUTED / CANCELLED |
Note
m0 indicates gateway name. It's available in all payments. To get payment method developers can use this.
Query Error Codes
| Code | Message | Description |
|---|---|---|
3050 | API key not found | AH-BOHUDUR-API-KEY header missing |
3051 | API key not valid | API key invalid or inactive |
3052 | Invalid Payment Key | paymentkey does not exist or is malformed |
3053 | Invalid api key | API key does not match any active account |
3054 | You don't have access! Your IP: ... | IP not authorized |
3055 | Payment Data Not Found | No payment found for this key |
Response objects are returned as stdClass, allowing direct access like:
$query->full_name;
$query->status;Webhooks (Laravel)
Bohudur sends webhook notifications using POST JSON.
Success Payload
{
"full_name": "Jane Doe",
"email": "janedoe@gmail.com",
"amount": 1,
"paymentkey": "CrD85r3ibMK6ip38reUcuECvVhaF0xOT",
"status": "COMPLETED"
}Cancel Payload
{
"full_name": "Jane Doe",
"email": "janedoe@gmail.com",
"amount": 1,
"paymentkey": "CrD85r3ibMK6ip38reUcuECvVhaF0xOT",
"status": "CANCELLED"
}Webhook Handler Example
Route::post('/bohudur/webhook', function () {
$data = request()->all();
// Always verify
Bohudur::query($data['paymentkey']);
});Best Practices
- Always verify payments using Query API
- Never execute payments from frontend
- Webhooks are not final truth
- Execute payments only once
Support
- Telegram: t.me/bohudur
- WhatsApp: Channel
- YouTube: youtube.com/@bohudurpay
