API Documentation

v1.0

Getting Started

Universal Pay provides a unified API to accept payments through mobile wallets, bank transfers, and cards in Pakistan. This documentation covers everything you need to integrate payments into your application.

Quick Integration Steps
1

Create a Merchant Account

Sign up and complete your merchant profile in the dashboard.

2

Generate API Keys

Create API keys with appropriate scopes for your integration.

3

Create Payment Intents

Use the API to create payment intents and redirect customers to checkout.

4

Handle Webhooks

Configure webhooks to receive real-time payment status updates.

Base URL

https://api.universalpay.pk/v1

Authentication

All API requests must include your API key in the Authorization header. API keys can be created and managed in your merchant dashboard.

API Key Format

API keys follow the format: upk_live_xxxxxxxxxxxxxxxx for production or upk_test_xxxxxxxxxxxxxxxx for sandbox.

Request Header

Authorization: Bearer upk_live_your_api_key_here

API Key Scopes

payments:readRead payment information
payments:writeCreate and modify payments
webhooks:manageConfigure webhook endpoints

Payments

Payment Intents represent a customer's intent to pay. Create a payment intent, redirect the customer to checkout, and handle the result via webhooks.

POST/v1/payment-intents
Create a new payment intent
{
  "amount": 150000,
  "currency": "PKR",
  "merchant_order_id": "order_123456",
  "customer_email": "[email protected]",
  "customer_name": "John Doe",
  "return_url": "https://yoursite.com/payment/complete",
  "allowed_methods": ["WALLET", "BANK", "CARD"],
  "metadata": {
    "product_id": "prod_abc",
    "customer_id": "cust_xyz"
  },
  "idempotency_key": "unique_request_id_123"
}

amount (required): Amount in smallest currency unit (paisa for PKR)

currency (required): Three-letter ISO currency code

merchant_order_id: Your internal order reference

return_url (required): URL to redirect after payment

idempotency_key: Unique key to prevent duplicate payments

GET/v1/payment-intents/:id
Retrieve a payment intent by ID
curl -X GET https://api.universalpay.pk/v1/payment-intents/pi_abc123def456 \
  -H "Authorization: Bearer upk_live_your_api_key"
POST/v1/payment-intents/:id/cancel
Cancel a payment intent (only if status is 'created' or 'pending')
curl -X POST https://api.universalpay.pk/v1/payment-intents/pi_abc123def456/cancel \
  -H "Authorization: Bearer upk_live_your_api_key"

Payment Status Flow

createdpendingsucceededorfailedorcanceledorexpired

Webhooks

Webhooks notify your server about payment events in real-time. Configure webhook endpoints in your dashboard to receive these notifications.

Webhook Events

payment.createdPayment intent created
payment.pendingCustomer initiated payment
payment.succeededPayment completed successfully
payment.failedPayment failed
refund.createdRefund initiated
refund.succeededRefund completed

Webhook Payload

{
  "id": "evt_abc123",
  "type": "payment.succeeded",
  "created_at": "2024-01-15T12:30:00Z",
  "data": {
    "payment_intent_id": "pi_abc123def456",
    "amount": 150000,
    "currency": "PKR",
    "status": "succeeded",
    "provider": "easypaisa",
    "provider_payment_id": "EP1234567890"
  }
}

Signature Verification

All webhooks include an HMAC-SHA256 signature in the X-Webhook-Signature header. Always verify this signature before processing the webhook.

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

Security

We take security seriously. Here are the security measures in place and best practices for your integration.

API Key Security
API keys are hashed using SHA-256 before storage. Never expose your API keys in client-side code or version control.
HTTPS Only
All API requests must be made over HTTPS. Webhook endpoints must also use HTTPS.
No Card Data Storage
We never store card numbers, CVVs, or expiry dates. All card payments are processed through tokenized hosted checkout.
Rate Limiting
API requests are rate limited per API key. Default limits are 100 requests/minute for general endpoints and 30 requests/minute for payment creation.

Code Examples

Create a Payment Intent

const axios = require('axios');

async function createPaymentIntent(orderData) {
  const response = await axios.post(
    'https://api.universalpay.pk/v1/payment-intents',
    {
      amount: orderData.amount * 100, // Convert to paisa
      currency: 'PKR',
      merchant_order_id: orderData.orderId,
      customer_email: orderData.customerEmail,
      return_url: 'https://yoursite.com/payment/complete',
      idempotency_key: `order_${orderData.orderId}`,
    },
    {
      headers: {
        'Authorization': `Bearer ${process.env.UNIVERSAL_PAY_API_KEY}`,
        'Content-Type': 'application/json',
      },
    }
  );
  
  return response.data;
}

// Usage
const payment = await createPaymentIntent({
  amount: 1500, // PKR 1,500
  orderId: 'order_123',
  customerEmail: '[email protected]',
});

// Redirect customer to checkout
res.redirect(payment.checkout_url);
Need Help?
Our developer support team is here to help you integrate Universal Pay.