Merchant Integration Guide
This guide is for merchant developers integrating with Epara. Small merchants can start with no-code Payment Links. Larger merchants should use Merchant API, Hosted Checkout, and Webhooks for automation.
Integration options
| Option | Who uses it? | When to choose it |
|---|---|---|
| Payment Link | Merchant without engineering team | WhatsApp, Instagram, SMS, or email collection. |
| Hosted Checkout | Merchant with website or app | Epara hosts the secure payment page. |
| Merchant API | Merchant with backend system | Orders, invoices, refunds, payouts, and reports need automation. |
| QR / Code Payment | Physical shop or field collection | Customer pays at counter or in person. |
| Webhooks | Merchant with order system | Merchant system must receive payment, refund, payout, or dispute events. |
Environments
| Environment | Purpose | Money movement |
|---|---|---|
| test | Integration, demo, QA, and test credential | No real money movement. |
| live | Real merchant and consumer activity | Real provider and ledger records. |
Test and live credentials are separate. A test credential cannot create live payments.
Base request rule
Merchant API requests must include signing headers:
POST /api/merchant/payment-links HTTP/1.1
Host: api.epara.example
Content-Type: application/json
X-Epara-Key-Id: key_test_...
X-Epara-Timestamp: 2026-06-16T12:00:00Z
X-Epara-Nonce: 0f7d8a1a-6f0b-4c9d-9f92-8d865bb2a111
X-Epara-Signature: hmac_sha256_signature
X-Epara-API-Version: 2026-06-14.basra
Idempotency-Key: plink_school_2026_001
Signing model
Epara signs method, path, timestamp, nonce, API version, and body hash. This proves:
- The request came from the merchant server.
- The body was not modified in transit.
- The nonce was not reused.
- Timestamp drift is acceptable.
- Merchant is using the expected API version.
Canonical string example:
POST
/api/merchant/payment-links
2026-06-16T12:00:00Z
0f7d8a1a-6f0b-4c9d-9f92-8d865bb2a111
2026-06-14.basra
sha256:6fd0a4...
Idempotency
Every request that creates persistent state or moves money must include Idempotency-Key.
| Operation | Required? | Why |
|---|---|---|
| Payment create/capture | Yes | Same payment must not be created twice. |
| Refund create | Yes | Same refund must not run twice. |
| Payout request | Yes | Merchant must not be paid twice for one request. |
| Payment Link create | Yes | Retry should return same link. |
| Read/list requests | No | No durable state or money movement. |
Create Payment Link example
{
"merchantId": "mrc_demo_market",
"title": "School fee - June 2026",
"amount": 255000,
"currency": "IQD",
"referencePrefix": "SCH-2026",
"allowedMethods": ["card", "consumer_wallet", "local_method"],
"successUrl": "https://merchant.example/success",
"cancelUrl": "https://merchant.example/cancel"
}
Successful response:
{
"id": "plink_school_2026",
"status": "active",
"hostedUrl": "https://pay.epara.example/pay/school-fee",
"amount": { "amount": 255000, "currency": "IQD" }
}
Webhook events
Merchants must not rely only on redirect URLs. The durable final result should come from signed webhooks.
| Event | When it fires |
|---|---|
checkout.session.completed | Hosted Checkout completed successfully. |
payment.captured | Payment became final ledger movement. |
payment.failed | Payment could not complete. |
refund.succeeded | Refund completed successfully. |
payout.paid | Provider confirmed payout paid. |
dispute.opened | Dispute or chargeback case opened. |
Webhook verification
Merchant should verify:
X-Epara-Webhook-Signatureis valid.- Timestamp is inside accepted drift window.
- Event id was not processed before.
- Event type is supported.
- Object id belongs to expected merchant-side object.
Error model
| HTTP status | Meaning |
|---|---|
| 400 | Invalid payload or missing required field. |
| 401 | Missing credential or invalid signature. |
| 403 | Credential scope does not allow operation. |
| 404 | Object not found or does not belong to merchant. |
| 409 | Idempotency or object-state conflict. |
| 422 | Business rule, limit, risk, or verification block. |
| 429 | Rate limit. |
| 500 | Platform internal error. Retry with idempotency. |
Integration checklist
- Test API credential created.
- Test payment link or checkout session completed.
- Webhook endpoint verifies signed events.
- Retry and idempotency tested.
- Refund flow tested.
- Payout destination and schedule approved.
- Live API credential separated from test credential.
- Live webhook endpoint tested.
- Merchant go-live review completed.