Developer Documentation
Merchant Integration Guide
Payments API v1
A production-oriented guide for integrating Pementek payments, hosted checkout, asynchronous verification, idempotency and signed webhooks into your website or application.
This document is written as the public merchant-facing integration guide. Internal provider routing, device-health thresholds, provider limits and operational algorithms are intentionally not exposed. API fields should be kept synchronized with the final backend implementation before production launch.
Contents
Use this guide as the canonical public integration reference for Pementek merchants.
- Overview
- Quick start
- Authentication & environments
- Create a payment
- Idempotency & merchant references
- Hosted Checkout
- Payment lifecycle
- Retrieve payment status
- Webhooks
- Webhook signature verification
- Webhook delivery & deduplication
- Errors, retries & timeouts
- Payment methods & markets
- Merchant-side data model
- Integration examples
- Security best practices
- Customer experience guidance
- Sandbox testing & launch checklist
- Payouts / withdrawals - API preview
- Glossary & support
1. Overview
Pementek provides a unified API and hosted checkout for local payment methods. Merchants create a payment on their backend, redirect the customer to Pementek Checkout, and update their own system only after Pementek reports the verified result through a signed webhook or server-side status query.
Create payment from your backend
|
v
Redirect to Pementek Checkout
|
v
Customer completes local payment
|
v
Pementek verifies the transaction
|
v
Your backend receives the resultA browser redirect is never proof of payment. Credit a customer only from a verified server-to-server result.
Integration model
Customer Browser
|
v
Your Website / App ----> Your Backend
|
v
Pementek API
|
v
Pementek Checkout
|
v
Local Payment
|
v
Verification
|
v
Signed Webhook to YouDesigned for multiple markets
The API contract is country-, currency- and payment-method aware. Market availability is enabled per merchant account. The initial implementation can launch market-by-market while preserving the same integration model for future local payment methods.
2. Quick start
The shortest production-safe integration has four responsibilities: authenticate from your backend, create a payment with an idempotency key, redirect the customer to the returned checkout URL, and process signed webhook events exactly once.
1. Store API credentials server-side
2. POST /v1/payments
3. Redirect to checkout_url
4. Verify and process webhooksBase URLs
| Purpose | URL |
|---|---|
| Production API | https://api.pementek.com/v1 |
| Hosted Checkout | https://pay.pementek.com |
| Documentation | https://docs.pementek.com |
| Sandbox | A separate sandbox base URL can be enabled for testing. |
Keep production and sandbox endpoints in environment configuration. Never ship production credentials into browser JavaScript or mobile application bundles.
Minimal create-payment request
curl -X POST "https://api.pementek.com/v1/payments" \
-H "Authorization: Bearer $PEMENTEK_API_KEY" \
-H "Idempotency-Key: order-847291-payment-1" \
-H "Content-Type: application/json" \
-d '{
"merchant_reference": "ORDER-847291",
"amount": 1500.00,
"currency": "BDT",
"country": "BD",
"payment_method": "BKASH",
"return_url": "https://merchant.example/payment/return"
}'3. Authentication & environments
API credentials authenticate your merchant backend. They must never be exposed to the customer. Use different credentials for sandbox and production, and rotate credentials when staff, servers or security posture changes.
Authentication header
Authorization: Bearer YOUR_API_KEYWhere credentials may live
| Location | Allowed? | Reason |
|---|---|---|
| Backend environment / secret manager | Yes | Server-side and access controlled. |
| Browser JavaScript | No | Any visitor can inspect the bundle or requests. |
| Mobile app package | No | App binaries can be inspected or instrumented. |
| Public Git repository | No | Secrets can be harvested and reused. |
| CI/CD secret store | Yes | Use least-privilege access and protected environments. |
Issue separate credentials per environment and, where practical, per production application. This makes revocation and audit easier.
4. Create a payment
Create a payment only from your server. A successful response returns the Pementek payment identifier and a hosted checkout URL. Persist both the Pementek ID and your own merchant reference before redirecting the customer.
Endpoint
POST /v1/paymentsRequest fields
| Field | Type | Required | Description |
|---|---|---|---|
merchant_reference | string | Yes | Your unique order, deposit or transaction reference. |
amount | decimal | Yes | Requested amount in the selected currency. |
currency | string | Yes | ISO-style currency code, for example BDT. |
country | string | Yes | Market code, for example BD. |
payment_method | string | Yes | Enabled local method, for example BKASH or NAGAD. |
customer.reference | string | No | Your internal customer/user reference. Do not send secrets. |
return_url | URL | Recommended | Where the browser may return after checkout. |
metadata | object | No | Small merchant-defined values useful for reconciliation. |
Example response
{
"id": "PMT-PAY-20261008-X82F91",
"merchant_reference": "ORDER-847291",
"type": "PAYMENT",
"status": "CREATED",
"amount": 1500.00,
"currency": "BDT",
"country": "BD",
"payment_method": "BKASH",
"checkout_url": "https://pay.pementek.com/p/PMT-PAY-20261008-X82F91",
"created_at": "2026-10-08T03:05:21Z"
}Use the returned checkout_url. Do not construct a Pementek checkout URL yourself.
5. Idempotency & merchant references
Network timeouts can make it unclear whether a payment was created. Idempotency lets you retry the same logical create request without accidentally creating a second financial transaction.
Idempotency-Key
Idempotency-Key: order-847291-payment-1| Situation | Correct behaviour |
|---|---|
| First create attempt | Send a new unique idempotency key for the logical payment. |
| HTTP timeout / connection reset | Retry with the same idempotency key. |
| User intentionally starts a different payment | Use a new key and a new merchant reference as appropriate. |
| Duplicate webhook | Do not use create-payment idempotency; deduplicate by webhook event_id. |
If every retry uses a new key, the merchant can accidentally create multiple valid payments for one order.
Merchant reference
merchant_reference links your record to the Pementek payment. It should be unique within the appropriate merchant scope and must be stored in your database together with the returned Pementek payment ID.
6. Hosted Checkout
Pementek Checkout handles the customer-facing payment instructions and verification hand-off. The customer can be redirected tocheckout_url from a web application or opened in an appropriate browser context from a mobile application.
Open checkout_url
|
v
Payment route is prepared
|
v
Instructions are shown
|
v
Customer completes payment
|
v
Customer confirms completion
|
v
Verification startsReturn URL is not authoritative
The return URL is a convenience for browser navigation. A user can close the page, refresh it, manipulate navigation history or revisit the URL later. Your backend must therefore ignore browser navigation as a financial signal.
Show “Checking payment status…” and query your own backend. Your backend can serve the latest Pementek status or wait for the webhook.
Unavailable payment capacity
A selected method can temporarily have no eligible processing capacity. Pementek may place the payment inWAITING_FOR_PROVIDER for a short routing window. This is not a financial failure because the customer has not yet been instructed to send money.
ROUTING
|
+-- provider available --> AWAITING_USER_CONFIRMATION
|
+-- none available ------> WAITING_FOR_PROVIDER
|
+-- becomes available --> continue
|
+-- window expires ----> ROUTING_UNAVAILABLE7. Payment lifecycle
Integrations must support asynchronous payment states. Do not collapse every non-success state into “failed”.
| Status | Merchant meaning |
|---|---|
CREATED | Payment resource exists. |
ROUTING | Pementek is preparing processing capacity. |
WAITING_FOR_PROVIDER | Selected method is temporarily waiting for capacity. |
AWAITING_USER_CONFIRMATION | Checkout instructions are available and the customer can complete payment. |
VERIFYING | Pementek is verifying transaction evidence. |
PENDING_RECONCILIATION | Verification is not yet conclusive; do not ask the customer to pay again. |
MANUAL_REVIEW | The transaction requires operational review. |
SUCCESS | The payment has been verified. This is the positive terminal result. |
FINAL_FAILED | Pementek has definitively failed the payment. |
ROUTING_UNAVAILABLE | The selected payment method could not obtain capacity in the routing window. |
CANCELLED | The payment was cancelled. |
EXPIRED | The payment session expired. |
Pending does not mean failed
Verification can be delayed by temporary connectivity or evidence delivery conditions. A payment may therefore move fromPENDING_RECONCILIATION toSUCCESS later. Your business logic must allow that transition.
When a payment is pending, tell the customer not to pay again. A second real-world payment can create a duplicate-payment support case.
8. Retrieve payment status
Use the status endpoint for server-side reconciliation, customer return pages, support tooling and recovery from missed or delayed webhooks.
Endpoint
GET /v1/payments/{payment_id}Example
curl "https://api.pementek.com/v1/payments/PMT-PAY-20261008-X82F91" \
-H "Authorization: Bearer $PEMENTEK_API_KEY"Example response
{
"id": "PMT-PAY-20261008-X82F91",
"merchant_reference": "ORDER-847291",
"status": "SUCCESS",
"amount": 1500.00,
"currency": "BDT",
"payment_method": "BKASH",
"created_at": "2026-10-08T03:05:21Z",
"completed_at": "2026-10-08T03:06:48Z"
}Match the Pementek payment ID, merchant reference, amount and currency against your stored record before applying any customer credit.
9. Webhooks
Webhooks are the recommended way to receive final and important asynchronous status updates. Pementek may retry an event until your endpoint acknowledges it successfully, so handlers must be idempotent.
Typical events
payment.pending
payment.succeeded
payment.failedExample payload
{
"event_id": "evt_01K7XX9J4JFA",
"event": "payment.succeeded",
"created_at": "2026-10-08T03:06:48Z",
"data": {
"id": "PMT-PAY-20261008-X82F91",
"merchant_reference": "ORDER-847291",
"status": "SUCCESS",
"amount": 1500.00,
"currency": "BDT",
"country": "BD",
"payment_method": "BKASH"
}
}Webhook endpoint behaviour
1. Receive raw request
2. Verify signature
3. Check event_id
4. Store/process safely
5. Return HTTP 2xx10. Webhook signature verification
A webhook must be authenticated before it changes financial state in your system. Use the raw request body when computing the signature. Parsing and re-serializing JSON can change whitespace or field ordering and break verification.
Suggested headers
Pementek-Event-Id: evt_01K7XX9J4JFA
Pementek-Timestamp: 1791428808
Pementek-Signature: sha256=...Signing model
signed_payload = timestamp + "." + raw_request_body
expected = HMAC_SHA256(webhook_secret, signed_payload)- Reject signatures that do not match using a constant-time comparison.
- Reject timestamps outside your acceptable replay window.
- Store
event_idand process each event exactly once in your business layer. - Keep webhook signing secrets server-side and rotate them under a controlled procedure.
The final production header names and canonical signing string must be treated as part of the API contract. Keep this page synchronized with the backend implementation and SDKs.
11. Webhook delivery & deduplication
Pementek uses at-least-once delivery semantics. Your endpoint can receive the same event multiple times because the original response may have been lost, delayed or non-successful.
event evt_123 arrives
|
v
Is event_id already processed?
| |
yes no
| |
ignore safely verify transaction
|
v
apply once
|
v
mark processedRecommended persistence
| Table/field | Purpose |
|---|---|
pementek_webhook_events.event_id | Unique key used to deduplicate delivery. |
payment_id | Links event to the payment stored by your merchant system. |
processed_at | Audit evidence that the event was consumed. |
payload_hash (optional) | Useful for operational diagnostics and tamper detection. |
Verify and persist the event, then return HTTP 2xx promptly. Move expensive business work to your own durable queue when appropriate.
12. Errors, retries & timeouts
Applications should rely on stable error codes rather than parsing human-readable messages. A transient network error must not be interpreted as proof that a payment was never created.
Example error
{
"error": {
"code": "INVALID_AMOUNT",
"message": "The supplied payment amount is invalid.",
"request_id": "req_01K7XY..."
}
}| HTTP | Meaning / action |
|---|---|
| 200 | Successful request. |
| 201 | Resource created. |
| 400 | Invalid request. |
| 401 | Authentication failed. |
| 403 | Operation not permitted. |
| 404 | Resource not found. |
| 409 | Conflict or duplicate semantic request. |
| 422 | Valid format but cannot be processed. |
| 429 | Rate limit exceeded; retry according to policy. |
| 500 | Temporary server error; retry safe operations. |
| 503 | Service temporarily unavailable. |
Common error codes
AUTHENTICATION_FAILED
INVALID_REQUEST
INVALID_AMOUNT
UNSUPPORTED_CURRENCY
UNSUPPORTED_COUNTRY
PAYMENT_METHOD_UNAVAILABLE
DUPLICATE_REFERENCE
RATE_LIMITED
INTERNAL_ERRORBrowser timeout != payment failure. HTTP timeout != payment failure. Verification delay != payment failure. Retry creation with the same idempotency key or query the existing payment status.
13. Payment methods & markets
Payment method availability can vary by country, currency, merchant account, transaction amount and current channel availability. Merchants should avoid permanently hardcoding a global list of methods into their product.
Capabilities endpoint
GET /v1/payment-methods?country=BD¤cy=BDTExample response
{
"country": "BD",
"currency": "BDT",
"methods": [
{
"code": "BKASH",
"name": "bKash",
"payment_enabled": true
},
{
"code": "NAGAD",
"name": "Nagad",
"payment_enabled": true
}
]
}Pementek is designed for local-payment expansion across multiple markets, but public documentation should list a market or method as live only after it is operationally enabled.
Alternative methods
If the customer selects a method that becomes temporarily unavailable, do not silently switch them to another method. Show the unavailable state and let the customer explicitly choose another enabled method.
14. Merchant-side data model
Pementek does not replace your own order or customer ledger. Your system should maintain a local payment record that links your business transaction to the Pementek resource.
Minimum recommended fields
pementek_payment_id
merchant_reference
customer_id
amount
currency
payment_method
status
created_at
updated_at
completed_atWebhook event table
event_id UNIQUE
payment_id
event_type
processed_atCredit exactly once
BEGIN DATABASE TRANSACTION
lock local payment row
verify local payment not already credited
verify Pementek status == SUCCESS
verify payment_id / reference / amount / currency
credit customer or fulfill order
mark local payment credited
store event_id processed
COMMITThe operation that applies customer credit and marks the event/payment processed should be atomic in your own database whenever possible.
15. Integration examples
Node.js / server-side JavaScript
const response = await fetch(
"https://api.pementek.com/v1/payments",
{
method: "POST",
headers: {
Authorization: `Bearer ${'{'}process.env.PEMENTEK_API_KEY{'}'}`,
"Content-Type": "application/json",
"Idempotency-Key": "order-847291-payment-1"
},
body: JSON.stringify({
merchant_reference: "ORDER-847291",
amount: 1500.00,
currency: "BDT",
country: "BD",
payment_method: "BKASH",
return_url: "https://merchant.example/payment/return"
})
}
);
const payment = await response.json();PHP
<?php
$payload = [
"merchant_reference" => "ORDER-847291",
"amount" => 1500.00,
"currency" => "BDT",
"country" => "BD",
"payment_method" => "BKASH",
"return_url" => "https://merchant.example/payment/return"
];
$ch = curl_init(
"https://api.pementek.com/v1/payments"
);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("PEMENTEK_API_KEY"),
"Content-Type: application/json",
"Idempotency-Key: order-847291-payment-1"
],
CURLOPT_POSTFIELDS => json_encode($payload)
]);
$response = curl_exec($ch);16. Security best practices
Merchant security is part of the end-to-end payment security model. A correct Pementek integration can still become unsafe if the merchant trusts browser state, exposes API keys or processes webhook events more than once.
- Use HTTPS for every production endpoint.
- Store API keys and webhook secrets only on trusted backend systems.
- Verify every webhook signature before reading it as an authoritative event.
- Use idempotency keys for create operations and
event_iddeduplication for webhooks. - Validate payment ID, merchant reference, amount and currency before crediting a user.
- Use MFA and role-based access for merchant dashboard users.
- Keep production and sandbox credentials separate.
- Keep audit logs for payment state changes and manual operational actions.
- Never request or store a customer mobile-money PIN or OTP as part of your Pementek integration.
Send only transaction data Pementek actually needs. Do not attach passwords, OTP codes, PINs, full identity documents or unrelated personal data in metadata.
17. Customer experience guidance
Good status messaging reduces duplicate payments and support load. The customer should always understand whether they need to take an action or simply wait for verification.
| State | Recommended customer message |
|---|---|
WAITING_FOR_PROVIDER | “Preparing this payment method. Please wait a moment…” |
AWAITING_USER_CONFIRMATION | Show the Pementek payment instructions. |
VERIFYING | “We are verifying your payment.” |
PENDING_RECONCILIATION | “Your payment is still being verified. You do not need to pay again.” |
SUCCESS | “Payment confirmed.” |
ROUTING_UNAVAILABLE | “This payment method is temporarily unavailable. Try again or choose another method.” |
FINAL_FAILED | “The payment could not be completed.” |
Do not show provider counts, provider balances, cooldowns, device health, routing priorities or provider identity details. These are internal Pementek infrastructure concerns.
18. Sandbox testing & launch checklist
A merchant integration is not production-ready until failure, delay and duplicate-delivery cases are tested. Happy-path testing alone is insufficient for a financial workflow.
Minimum test scenarios
- Successful payment and successful webhook processing.
- Payment that remains pending before later success.
- Definitively failed payment.
- Duplicate create request with the same idempotency key.
- Duplicate webhook delivery with the same event_id.
- Webhook endpoint temporarily unavailable, then recovered.
- Customer closes checkout before return.
- Selected payment method temporarily unavailable.
- Invalid amount or unsupported currency.
- Invalid credentials and permission errors.
- Network timeout during create-payment request.
- Mismatch between webhook amount/reference and merchant local record.
Production launch checklist
19. Payouts / withdrawals - API preview
Payout support is a planned extension of the same merchant platform. Do not integrate against this section until the Payout API is enabled and marked stable for your merchant account.
The intended payout model lets a merchant submit an approved withdrawal to a supported personal wallet. Pementek processes the transfer asynchronously and reports the verified result through the same server-to-server principles used for payments.
Customer requests withdrawal
|
v
Merchant approves it
|
v
Create Pementek payout
|
v
Pementek processes transfer
|
v
Receive verified payout webhookProposed endpoint
POST /v1/payoutsProposed request
{
"merchant_reference": "WD-829182",
"amount": 1000.00,
"currency": "BDT",
"country": "BD",
"payment_method": "BKASH",
"recipient": {
"wallet_type": "PERSONAL",
"wallet_number": "017XXXXXXXX"
}
}Payouts should also be treated asynchronously. The merchant should mark a customer withdrawal complete only after Pementek returns the verified SUCCESS result through the supported API/webhook contract.
20. Glossary & support
| Term | Meaning |
|---|---|
| Merchant | The business integrating Pementek. |
| Payment | A customer-to-merchant collection transaction processed through Pementek. |
| Payout | A merchant-initiated transfer to a customer wallet when this feature is enabled. |
| Hosted Checkout | Pementek customer-facing flow at pay.pementek.com. |
| Idempotency key | A merchant-supplied key that makes retries of the same create operation safe. |
| Webhook | A signed server-to-server event sent by Pementek to the merchant. |
| Pending reconciliation | A non-final payment state in which verification is still unresolved. |
| Merchant reference | The merchant's own unique business transaction reference. |
Support information
For production documentation, publish your merchant support channel, operational status page and escalation process here. Recommended destinations include the merchant dashboard support area andstatus.pementek.com.
Once the backend is live,docs.pementek.com should be the canonical public source for endpoint URLs, field names, status values, webhook signature rules and SDK examples. Update the site documentation and this PDF together.
Pementek — Local payments. One integration.
Merchant Integration Guide — API v1 — Draft 1.0