Skip to navigation Skip to main content EpicPay API Documentation

EpicPay API Documentation

Secure payment API documentation for merchants and developers. Create payment sessions, redirect customers to checkout, verify payments, and receive webhook notifications.

Hosted Checkout REST API Webhook Security Next.js 15 Ready

Overview

EpicPay allows merchants to create payment sessions from their backend, redirect customers to a secure hosted checkout page, receive payment status updates through webhooks, and verify payment status through API.

Important: EpicPay can be integrated with any platform that supports HTTP requests, including Next.js, Laravel, Node.js, PHP, React, Vue, mobile apps, and custom systems.

API Environments

Test Environment

Use this environment for development and testing only.

https://epicstore-key.com/wp-json/epicpay/v1

Live Environment

Use this environment only after your merchant account is approved for production.

https://epicstore-key.com/wp-json/epicpay/v1

Integration Flow

The customer clicks Pay Now on the merchant website.

The merchant backend creates a payment session through EpicPay API.

EpicPay returns a secure payment_url.

The merchant redirects the customer to the EpicPay checkout page.

The customer completes or cancels the payment.

EpicPay redirects the customer back to the merchant website.

EpicPay sends a webhook to the merchant backend.

The merchant verifies the payment status and updates the order.

Do not rely only on return URL. Final order status should be updated using Webhook or Verify Payment API.

Authentication

Every server-side API request must include your merchant API credentials.

Required Headers

Content-Type: application/json
X-EPICPAY-KEY: epk_live_xxxxxxxxxxxxxxxxx
X-EPICPAY-SECRET: eps_live_xxxxxxxxxxxxxxxxx
KeyDescriptionVisibility
Public KeyUsed to identify the merchant.Server-side recommended.
Secret KeyUsed to authenticate API requests.Server-side only. Never expose publicly.
Webhook SecretUsed to verify webhook signatures.Server-side only.
Never place your Secret Key or Webhook Secret inside frontend code, JavaScript bundles, mobile apps, browser storage, or public repositories.

Security Requirements

  • Always call EpicPay API from your backend/server only.
  • Never expose X-EPICPAY-SECRET in frontend code.
  • Always use HTTPS in live mode.
  • Always verify webhook signatures.
  • Always verify payment status before marking an order as paid.
  • Use a unique order_id for each order.
  • Do not trust amount, currency, or status values sent from frontend.
  • Store API keys in environment variables.
  • Log failed API responses without exposing sensitive keys.
  • Use Live API keys only in production.

Create Payment

Creates a new payment session and returns a hosted checkout URL.

POST /payments/create

Full URL

POST https://epicstore-key.com/wp-json/epicpay/v1/payments/create

Request Headers

Content-Type: application/json
X-EPICPAY-KEY: epk_test_xxxxxxxxxxxxxxxxx
X-EPICPAY-SECRET: eps_test_xxxxxxxxxxxxxxxxx

Request Body

{
  "amount": 25000,
  "currency": "IQD",
  "order_id": "ORDER-1001",
  "customer_name": "Ahmed Ali",
  "customer_email": "[email protected]",
  "customer_phone": "+9647700000000",
  "description": "Order payment for ORDER-1001",
  "return_url": "https://merchant-site.com/payment/success",
  "cancel_url": "https://merchant-site.com/payment/cancel",
  "webhook_url": "https://merchant-site.com/api/epicpay/webhook"
}

Parameters

FieldTypeRequiredDescription
amountnumberYesPayment amount. For IQD, use the full amount, e.g. 25000.
currencystringYesCurrency code, e.g. IQD or USD.
order_idstringYesUnique order reference from merchant system.
customer_namestringRecommendedCustomer full name.
customer_emailstringOptionalCustomer email address.
customer_phonestringRecommendedCustomer phone number.
descriptionstringOptionalPayment description.
return_urlstringYesURL where customer returns after payment.
cancel_urlstringYesURL where customer returns if payment is cancelled.
webhook_urlstringRecommendedMerchant backend endpoint that receives payment status updates.

Success Response

{
  "success": true,
  "payment_id": "pay_9f8a7b6c5d4e",
  "order_id": "ORDER-1001",
  "amount": 25000,
  "currency": "IQD",
  "status": "pending",
  "payment_url": "https://epicstore-key.com/epicpay/checkout/pay_9f8a7b6c5d4e",
  "expires_at": "2026-05-27T12:30:00+03:00"
}

Error Response

{
  "success": false,
  "error": {
    "code": "invalid_amount",
    "message": "The payment amount is invalid."
  }
}

Verify Payment

Use this endpoint to confirm the payment status from your backend.

GET /payments/verify/{payment_id}

Full URL

GET https://epicstore-key.com/wp-json/epicpay/v1/payments/verify/pay_9f8a7b6c5d4e

Request Headers

X-EPICPAY-KEY: epk_test_xxxxxxxxxxxxxxxxx
X-EPICPAY-SECRET: eps_test_xxxxxxxxxxxxxxxxx

Success Response

{
  "success": true,
  "payment_id": "pay_9f8a7b6c5d4e",
  "order_id": "ORDER-1001",
  "amount": 25000,
  "currency": "IQD",
  "status": "paid",
  "paid_at": "2026-05-27T12:20:00+03:00"
}

Payment Status Values

StatusMeaning
pendingPayment session created, waiting for customer payment.
paidPayment completed successfully.
failedPayment failed.
cancelledCustomer cancelled the payment.
expiredPayment session expired.
refundedPayment was refunded.

Webhooks

EpicPay sends webhooks to your backend when payment status changes. Webhooks are the recommended way to update order status automatically.

Webhook URL Example

https://merchant-site.com/api/epicpay/webhook

Webhook Headers

Content-Type: application/json
X-EPICPAY-SIGNATURE: sha256=xxxxxxxxxxxxxxxxxxxxxxxx
X-EPICPAY-EVENT: payment.paid
X-EPICPAY-TIMESTAMP: 1779870000

Webhook Body

{
  "event": "payment.paid",
  "payment_id": "pay_9f8a7b6c5d4e",
  "order_id": "ORDER-1001",
  "amount": 25000,
  "currency": "IQD",
  "status": "paid",
  "paid_at": "2026-05-27T12:20:00+03:00"
}

Webhook Events

EventDescription
payment.createdPayment session was created.
payment.paidPayment completed successfully.
payment.failedPayment failed.
payment.cancelledPayment was cancelled.
payment.expiredPayment session expired.
payment.refundedPayment was refunded.

Webhook Signature Verification

The recommended signature format is:

HMAC_SHA256(timestamp + "." + raw_body, webhook_secret)

The final header value should be:

sha256=generated_hash

Node.js Verification Example

import crypto from "crypto";

function verifyEpicPayWebhook(rawBody, signatureHeader, timestamp, webhookSecret) {
  const payload = `${timestamp}.${rawBody}`;
  const expectedSignature =
    "sha256=" +
    crypto.createHmac("sha256", webhookSecret).update(payload).digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(signatureHeader),
    Buffer.from(expectedSignature)
  );
}
Use the raw request body for signature verification. Do not use a parsed JSON object to generate the signature.

Next.js 15 Integration Example

Environment Variables

Create .env.local:

EPICPAY_API_URL=https://epicstore-key.com/wp-json/epicpay/v1
EPICPAY_PUBLIC_KEY=epk_test_xxxxxxxxxxxxxxxxx
EPICPAY_SECRET_KEY=eps_test_xxxxxxxxxxxxxxxxx
EPICPAY_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxx
Do not use NEXT_PUBLIC_ for secret values.

Create Payment Route

File: app/api/epicpay/create-payment/route.ts

import { NextResponse } from "next/server";

export async function POST(req: Request) {
  try {
    const body = await req.json();

    const response = await fetch(`${process.env.EPICPAY_API_URL}/payments/create`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-EPICPAY-KEY": process.env.EPICPAY_PUBLIC_KEY || "",
        "X-EPICPAY-SECRET": process.env.EPICPAY_SECRET_KEY || ""
      },
      body: JSON.stringify({
        amount: body.amount,
        currency: body.currency || "IQD",
        order_id: body.order_id,
        customer_name: body.customer_name,
        customer_email: body.customer_email,
        customer_phone: body.customer_phone,
        description: body.description,
        return_url: `${body.site_url}/payment/success`,
        cancel_url: `${body.site_url}/payment/cancel`,
        webhook_url: `${body.site_url}/api/epicpay/webhook`
      })
    });

    const data = await response.json();

    if (!response.ok || !data.success) {
      return NextResponse.json(
        { success: false, error: data.error || "Payment creation failed" },
        { status: response.status || 400 }
      );
    }

    return NextResponse.json(data);
  } catch (error) {
    return NextResponse.json(
      { success: false, error: "Internal server error" },
      { status: 500 }
    );
  }
}

Frontend Pay Button Example

"use client";

export default function PayButton() {
  async function handlePayment() {
    const response = await fetch("/api/epicpay/create-payment", {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        amount: 25000,
        currency: "IQD",
        order_id: "ORDER-1001",
        customer_name: "Ahmed Ali",
        customer_email: "[email protected]",
        customer_phone: "+9647700000000",
        description: "Order payment",
        site_url: window.location.origin
      })
    });

    const data = await response.json();

    if (data.success && data.payment_url) {
      window.location.href = data.payment_url;
    } else {
      alert("Payment could not be started.");
    }
  }

  return <button onClick={handlePayment}>Pay with EpicPay</button>;
}

Webhook Route

File: app/api/epicpay/webhook/route.ts

import { NextResponse } from "next/server";
import crypto from "crypto";

function verifySignature(rawBody: string, signature: string, timestamp: string) {
  const secret = process.env.EPICPAY_WEBHOOK_SECRET || "";
  const payload = `${timestamp}.${rawBody}`;
  const expected =
    "sha256=" + crypto.createHmac("sha256", secret).update(payload).digest("hex");

  try {
    return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
  } catch {
    return false;
  }
}

export async function POST(req: Request) {
  const rawBody = await req.text();
  const signature = req.headers.get("x-epicpay-signature") || "";
  const timestamp = req.headers.get("x-epicpay-timestamp") || "";

  if (!verifySignature(rawBody, signature, timestamp)) {
    return NextResponse.json({ success: false, error: "Invalid signature" }, { status: 401 });
  }

  const payload = JSON.parse(rawBody);

  if (payload.event === "payment.paid" && payload.status === "paid") {
    // Update merchant order status as paid using payload.order_id
  }

  return NextResponse.json({ received: true });
}

cURL Examples

Create Payment

curl -X POST "https://epicstore-key.com/wp-json/epicpay/v1/payments/create" \
  -H "Content-Type: application/json" \
  -H "X-EPICPAY-KEY: epk_test_xxxxxxxxxxxxxxxxx" \
  -H "X-EPICPAY-SECRET: eps_test_xxxxxxxxxxxxxxxxx" \
  -d '{
    "amount": 25000,
    "currency": "IQD",
    "order_id": "ORDER-1001",
    "customer_name": "Ahmed Ali",
    "customer_email": "[email protected]",
    "customer_phone": "+9647700000000",
    "description": "Order payment",
    "return_url": "https://merchant-site.com/payment/success",
    "cancel_url": "https://merchant-site.com/payment/cancel",
    "webhook_url": "https://merchant-site.com/api/epicpay/webhook"
  }'

Verify Payment

curl -X GET "https://epicstore-key.com/wp-json/epicpay/v1/payments/verify/pay_9f8a7b6c5d4e" \
  -H "X-EPICPAY-KEY: epk_test_xxxxxxxxxxxxxxxxx" \
  -H "X-EPICPAY-SECRET: eps_test_xxxxxxxxxxxxxxxxx"

API Test Page Requirements

You can add an API Test page for merchants inside the dashboard.

Recommended Test Fields

FieldTypeRequired
API URLtextYes
Public KeytextYes
Secret KeypasswordYes
AmountnumberYes
CurrencyselectYes
Order IDtextYes
Customer NametextOptional
Customer EmailemailOptional
Customer PhonetextOptional
Return URLurlYes
Cancel URLurlYes
Webhook URLurlOptional

API Test Actions

Test API Credentials

Check if merchant keys are valid.

Create Test Payment

Create a payment session in test mode.

Open Payment URL

Open the hosted checkout page.

Verify Payment

Verify payment status by payment ID.

Send Test Webhook

Send a simulated webhook event.

View Last API Response

Display last request and response safely.

API Test Safety Rules

  • Hide Secret Key by default.
  • Do not save Secret Key in browser localStorage.
  • Do not print full Secret Key in logs.
  • Mask sensitive values like eps_test_************abcd.
  • Only allow API Test for logged-in approved merchants.
  • Use test mode by default.
  • Add a clear warning before switching to live mode.

Errors

Recommended Error Codes

CodeMeaning
invalid_api_keyPublic key is invalid.
invalid_secret_keySecret key is invalid.
unauthorized_merchantMerchant is not allowed to use API.
inactive_merchantMerchant account is inactive.
invalid_amountAmount is missing or invalid.
invalid_currencyCurrency is unsupported.
duplicate_order_idThis order ID already exists.
invalid_return_urlReturn URL is invalid.
invalid_cancel_urlCancel URL is invalid.
invalid_webhook_urlWebhook URL is invalid.
payment_not_foundPayment ID was not found.
payment_expiredPayment session has expired.
internal_errorUnexpected server error.

Recommended HTTP Status Codes

HTTP CodeUsage
200Request completed successfully.
201Payment session created.
400Invalid request data.
401Authentication failed.
403Merchant is not allowed to perform this action.
404Payment not found.
409Duplicate order ID or conflict.
422Validation error.
500Server error.

Merchant Go-Live Checklist

  • Your website uses HTTPS.
  • Your Secret Key is stored server-side only.
  • Webhook signature verification is enabled.
  • Verify Payment API is implemented.
  • Duplicate webhook protection is implemented.
  • Test payments are completed successfully.
  • Live API keys are activated by EpicPay.
  • Return URL and Cancel URL are correct.
  • Webhook URL is publicly accessible.
  • Order status is updated only after confirmed payment.

Epic Store

Login with OTP

A quick, secure way to access your account.
No password needed.

Use the email address registered to your account.

Select your currency

ما هى سياسة الاستبدال والاسترجاع ؟


من حق المستهلك أن يستبدل أو يعيد المنتج أو السلعة التي قام بشرائها خلال 14 يوم إذا كانت معيبة أو غير مطابقة للمواصفات او الغرض الذى تم التعاقد عليها من أجله .