Query vs Execute
Understanding the difference between Query and Execute is one of the most important concepts in building a secure, reliable Bohudur integration. Using the wrong one can cause duplicate orders, repeated product delivery, or payment fraud.
At a Glance
Read Only
Checks the current status of a payment. Can be called unlimited times. Never changes anything. Safe to use anywhere.
Write Once
Finalizes a payment permanently. Can only be called exactly once. Triggers your order fulfillment. Blocks all repeat attempts.
| Query | Execute | |
|---|---|---|
| Endpoint | POST /query/v2/ | POST /execute/v2/ |
| Purpose | Check payment status | Finalize and process payment |
| Can be called | Unlimited times | Exactly once |
| Changes payment state | No | Yes — COMPLETED → EXECUTED |
| Triggers fulfillment | Never | Yes |
| Safe on page reload | Yes | No — causes error 3108 |
| Duplicate protection | None | Built-in — blocks repeats |
| Error on repeat call | Never | 3108 — Payment already executed |
| Use for | Status display, admin panels, logs, webhooks | Order processing, product delivery, subscriptions |
Complete Payment Flow
This is the full payment lifecycle showing where Query and Execute fit:
POST /create/v2/ → gets payment_urlpayment_url (Bohudur hosted checkout)Status → COMPLETED
Status → CANCELLED
redirect_url?paymentkey=XXXCall
Query → check COMPLETED → fulfill orderRepeatable! Exploitable!
Call
Execute → status becomes EXECUTED → fulfill orderOne-time. Secure.
Query anytime after to check status, display receipts, audit logsWhat is Query?
POST /query/v2/ is a read-only operation. It retrieves the current state of a payment without changing anything.
curl -X POST "https://request.bohudur.one/query/v2/" \
-H "Content-Type: application/json" \
-H "AH-BOHUDUR-API-KEY: YOUR_API_KEY" \
-d '{"paymentkey": "YOUR_PAYMENT_KEY"}'Query returns one of four statuses:
| Status | Meaning |
|---|---|
PENDING | Customer hasn't paid yet |
COMPLETED | Customer paid — ready for Execute |
EXECUTED | Payment finalized by your server |
CANCELLED | Payment was cancelled |
Safe uses of Query:
- Show order status to a customer
- Admin panel transaction lookup
- Cron job polling for pending payments
- Logging and auditing
- Verifying a webhook before acting on it
Never use Query to trigger fulfillment — because it can be called repeatedly.
What is Execute?
POST /execute/v2/ is a write-once operation. It permanently changes the payment status from COMPLETED to EXECUTED and returns the full payment data.
curl -X POST "https://request.bohudur.one/execute/v2/" \
-H "Content-Type: application/json" \
-H "AH-BOHUDUR-API-KEY: YOUR_API_KEY" \
-d '{"paymentkey": "YOUR_PAYMENT_KEY"}'First call — succeeds:
{
"full_name": "Jane Doe",
"email": "[email protected]",
"amount": 150,
"paymentkey": "5RWS4w2w1R5nFAvoP5U0JS4O74UrMXGt",
"receipt": "https://pay.bohudur.one/receipt/download/102f89389f9e",
"status": "EXECUTED"
}Any repeat call — permanently blocked:
{
"responseCode": 3108,
"message": "Payment already executed!",
"status": "failed"
}The Duplicate Order Problem — Visualized
After payment, your app redirects the customer to:
https://example.com/order/success/?paymentkey=5RWS4w2w1R5nFAvoP5U0JS4O74UrMXGtThis URL is visible in the browser. The customer can copy it, bookmark it, share it, or revisit it anytime.
❌ What happens if you use Query to fulfill orders:
Customer visits success URL → Query returns COMPLETED → Order #1001 processed Order sent ❌
Customer revisits the same URL → Query returns EXECUTED → Order #1001 processed again Duplicate ❌
Customer shares URL with a friend → Friend visits → Order #1001 processed a 3rd time Fraud ❌
Anyone with the URL → Query still returns data → Order processed forever No protection ❌
Any person with the success URL can trigger order fulfillment unlimited times. Query has no protection against this — it is not designed to be a fulfillment trigger.
What happens if you use Execute to fulfill orders:
Customer visits success URL → Execute called → Order #1001 processed → status becomes EXECUTED Order sent
Customer revisits the same URL → Execute returns 3108 → Order blocked Protected
Customer shares URL with friend → Execute returns 3108 → Blocked Protected
Anyone with the URL → Execute returns 3108 → Always blocked forever Safe
The first Execute wins. Every attempt after that is permanently rejected — no matter who makes the request or when. One payment. One fulfillment. Always.
State Machine — Payment Lifecycle
┌─────────────┐
│ CREATED │
└──────┬──────┘
│ Customer redirected to checkout
▼
┌─────────────┐
│ PENDING │ ◄── Query: returns PENDING
└──────┬──────┘
│
┌────────────┴────────────┐
│ Customer pays │ Customer cancels
▼ ▼
┌─────────────┐ ┌─────────────┐
│ COMPLETED │ │ CANCELLED │ ◄── Query: returns CANCELLED
└──────┬──────┘ └─────────────┘ Execute: error 3107
│
│ Query: returns COMPLETED (read-only, no side effects)
│ Execute: finalizes payment (one-time only)
│
▼
┌─────────────┐
│ EXECUTED │ ◄── Query: returns EXECUTED
└─────────────┘ Execute: error 3108 (blocked forever)The Correct Code Pattern
// success.php — called when customer returns from checkout
$paymentkey = $_GET['paymentkey'];
// Use Execute — finalizes payment, one-time only
$execute = Bohudur::Execute($paymentkey);
if ($execute->status === 'EXECUTED') {
// Payment finalized — fulfill the order exactly once
$orderId = $execute->metadata->order_id;
fulfillOrder($orderId);
saveToDatabase($execute);
sendConfirmationEmail($execute->email, $execute->receipt);
showSuccessPage();
} else {
// Payment pending, cancelled, or already executed
showErrorPage($execute->status);
}// success.php — WRONG APPROACH
$paymentkey = $_GET['paymentkey'];
// Query does not protect against repeated calls
$query = Bohudur::Query($paymentkey);
// This runs EVERY TIME the page loads — duplicates guaranteed
if ($query->status === 'COMPLETED' || $query->status === 'EXECUTED') {
fulfillOrder($query->metadata->order_id); // ❌ Runs on every visit!
}When to Use Each — Decision Guide
I need to... Use
─────────────────────────────────────────────────────
Fulfill an order after payment → Execute
Deliver a digital product → Execute
Activate a subscription → Execute
Confirm a booking → Execute
Check if customer has paid → Query
Show payment status on a page → Query
Poll from a background job → Query
Admin panel transaction lookup → Query
Verify a webhook payload → Query
Audit/log a transaction → QueryExecute Error Codes
| Code | Message | Meaning |
|---|---|---|
3100 | API key not found | AH-BOHUDUR-API-KEY header is missing |
3101 | API key not valid | API key is invalid or inactive |
3102 | Invalid Payment Key | paymentkey is malformed or doesn't exist |
3104 | You don't have access | Your server IP is not authorized |
3105 | Payment Data Not Found | No payment found for this key |
3106 | Payment is pending! | Customer hasn't paid yet — wait or poll |
3107 | Payment is cancelled! | Cannot execute a cancelled payment |
3108 | Payment already executed! | Already finalized — this IS the protection |
3109 | Failed to execute payment | Server error — retry once |
Handle 3108 gracefully
3108 is not always an error in your logic — it means the payment was already finalized. Show a "your order is already confirmed" message rather than an error screen.
বাংলা ব্যাখ্যা — Query বনাম Execute
Bohudur payment integration-এ Query এবং Execute — এই দুটি API call-এর পার্থক্য বোঝা অত্যন্ত জরুরি। ভুল ব্যবহার করলে একই অর্ডার বারবার process হতে পারে।
Query কী?
Query হলো শুধুমাত্র পড়ার জন্য (Read Only)। এটি payment-এর বর্তমান অবস্থা দেখায়, কিন্তু কোনো পরিবর্তন করে না। যতবার ইচ্ছা ডাকা যায়।
Query কখন ব্যবহার করবেন:
- Customer-কে payment status দেখাতে
- Admin panel-এ transaction দেখতে
- Background job থেকে payment check করতে
- Webhook verify করতে
Execute কী?
Execute হলো payment চূড়ান্ত করার জন্য (Write Once)। এটি payment-এর status COMPLETED থেকে EXECUTED-এ বদলে দেয়। এটি সারাজীবনে একটি payment-এর জন্য মাত্র একবারই সফল হবে।
Execute কখন ব্যবহার করবেন:
- Order process করতে
- Digital product deliver করতে
- Subscription activate করতে
- যেকোনো কাজ যা একবারই হওয়া উচিত
সমস্যাটা কোথায়?
Customer payment করার পর আপনার success page-এ redirect হয়:
https://example.com/order/success/?paymentkey=5RWS4w2w...এই URL টি browser-এ দেখা যায়। Customer এটি copy করে রাখতে পারে, bookmark করতে পারে, বা অন্যকে share করতে পারে।
ভুল পদ্ধতি (Query দিয়ে order process করা):
যদি আপনি success page-এ Query করে order process করেন — তাহলে যতবার কেউ সেই URL visit করবে, ততবার order process হবে। ১ম দিন customer visit করলো → order গেলো। ২য় দিন আবার visit করলো → আবার order গেলো। ৭ম দিন অন্য কেউ URL পেয়ে visit করলো → আবার order গেলো। কোনো সুরক্ষা নেই।
সঠিক পদ্ধতি (Execute দিয়ে order process করা):
যদি আপনি Execute ব্যবহার করেন — ১ম বার সফল হবে এবং order যাবে। এরপর যতবারই কেউ সেই URL visit করুক না কেন, Execute error 3108 দেবে এবং order আর process হবে না। একটি payment, একটি order — সবসময়।
সহজ মনে রাখার উপায়
Query = একটি বইয়ের মতো। যতবার খুশি পড়া যায়, কিন্তু বই পড়লে বইয়ের ভেতরে কিছু বদলায় না।
Execute = একটি চেকের মতো। একবার ব্যাংকে জমা দিলে আর দ্বিতীয়বার জমা দেওয়া যায় না — rejected হবে।
সংক্ষেপে
| Query | Execute | |
|---|---|---|
| কতবার ডাকা যায় | অসীমবার | মাত্র একবার |
| কী করে | শুধু দেখায় | চূড়ান্ত করে |
| Order process করতে | কখনো না | হ্যাঁ |
| সুরক্ষা আছে? | নেই | আছে |
Summary
- Query → Read-only. Unlimited calls. Never changes anything. Use for display and checks.
- Execute → Write-once. One call per payment. Finalizes and protects. Use for fulfillment.
- Rule: Always Execute first on your success page. Use Query for everything after.
Support
- Telegram: t.me/bohudur
- Facebook: Group
- YouTube: youtube.com/@bohudurpay
