Quickstart · UAT environment

Accept your first payment.

Add Hamro Pay’s hosted checkout to your website or app. Your server creates the payment, your customer chooses how to pay, and your server confirms the result.

New to hosted payments?

Before you start

You’ll need a backend that can make HTTPS requests, a test merchant account, and pages to return customers to after checkout. Create a test merchant account.

1 Set up your test account

Follow these steps to create and verify your test merchant, get your credentials, and reach the checkout endpoints.

Merchant Onboarding

1.1. Create and Verify Your Test Merchant Account

Register your merchant account through the UAT Merchant Portal to start your checkout integration.

Use verification OTP 000000
Step 2: Credentials & Webhook

1.2. Get Credentials and Configure Webhook

Once your merchant account is verified, navigate to:

You will find:

  • Client ID
  • Client Secret
  • Client API Key
  • Merchant ID
Hamro Pay UAT Merchant Portal - Client Credentials

Configure your Webhook:

  1. Enter your Target Endpoint URL.
  2. Save the configuration.
  3. The Webhook Secret (merchantWebHookSigningSecret) will be generated/displayed after saving.
  4. Use this secret to verify webhook requests from Hamro Pay.
Hamro Pay UAT Merchant Portal - Webhook Configuration
Security Warning: Keep your credentials and webhook secret secure. Do not expose them in frontend client-side code or public repositories.
Step 3: API Integration

1.3. Integrate Hamro Pay Checkout

Use the credentials obtained from the UAT Merchant Portal and the following UAT endpoints to connect your backend and frontend:

Environment Variable UAT Value Action
BASE_URL https://uat-payclient.hamropatro.com/
GATEWAY_URL https://uat-checkout-pay.hamropatro.com/
Follow the Checkout API documentation to implement session creation, proceed forms, and signature validation.
View API Documentation

Keep secret values on your server. Collect the credentials and UAT endpoints from the steps above into your backend’s environment configuration.

.env · server configuration
# .env — your server only; never commit this file
# Copy these from UAT Merchant Portal → Client Credentials:
# https://pay-sandbox.hamropatro.com/client-credentials
HAMRO_MERCHANT_ID=REPLACE_ME
HAMRO_CLIENT_ID=REPLACE_ME
HAMRO_API_KEY=REPLACE_ME
HAMRO_CLIENT_SECRET=REPLACE_ME

# Generated when you save your webhook URL in
# UAT Merchant Portal → Configuration → Webhook.
HAMRO_WEBHOOK_SECRET=REPLACE_ME

# UAT endpoints from step 1.3 above.
HAMRO_CREATE_SESSION_URL=https://uat-payclient.hamropatro.com/v1/checkout/sessionId
HAMRO_GET_TRANSACTION_URL=https://uat-payclient.hamropatro.com/v1/checkout/transaction
HAMRO_GATEWAY_URL=https://uat-checkout-pay.hamropatro.com/api/checkout

# Set these to pages in your application.
CHECKOUT_SUCCESS_URL=https://your-domain.example/payment/success
CHECKOUT_FAILURE_URL=https://your-domain.example/payment/failure
Ready when:
Your test merchant is verified and your server has its test credentials.

2 Create a payment session

Build a request from the order saved on your server. Set the amount in paisa, and give each order a unique merchantTxnId of no more than 25 characters. This example charges NPR 125.50 (12550 paisa).

Create Session · request body
{
  "merchantTxnId": "ORDER-1001",
  "merchantId": "YOUR_TEST_MERCHANT_ID",
  "transactionAmount": "12550",
  "failedRedirectionUrl": "https://your-domain.example/payment/failure",
  "successRedirectionUrl": "https://your-domain.example/payment/success",
  "remarks": "Order ORDER-1001"
}

Building a platform that hosts other merchants? Use the selling merchant’s ID and explore Payments for Platforms to allocate your platform’s share automatically.

Sign the request

A signature lets Hamro Pay verify your request. Join the five fields in the order shown below, sign them with your client secret using HMAC-SHA512, and encode the result as Base64. How signatures work.

signature
import { createHmac } from 'node:crypto';

export function signSession(request, clientId, clientApiKey, clientSecret) {
  const message = [
    request.merchantTxnId,
    request.transactionAmount,
    request.merchantId,
    clientId,
    clientApiKey,
  ].join(',');

  return createHmac('sha512', clientSecret)
    .update(message, 'utf8')
    .digest('base64');
}

// request is the exact JSON object you send to Create Session.
// Read the client id, api key and secret from your server environment.

Send the JSON body with POST to {{API_BASE_URL}}/v1/checkout/sessionId (UAT: https://uat-payclient.hamropatro.com/v1/checkout/sessionId) with these headers. Sign the values you actually send; don’t change the amount or field values after signing.

Create Session · request headers
Signature: YOUR_GENERATED_BASE64_SIGNATURE
Client-Id: YOUR_TEST_CLIENT_ID
Client-API-Key: YOUR_TEST_API_KEY
Content-Type: application/json
Keep payment creation on your server
Read prices from your own order records. Don’t trust an amount submitted by the browser, and don’t send your API key, client secret, or webhook secret to the browser.
Ready when:
You have a successful session response containing sessionId and merchantId. Save the order’s transaction ID for step 4.
See all request fields and the full response example

3 Send your customer to checkout

Use sessionId from the response in step 2, and compute the checkout token as a form signature. Pass only the checkout fields to your page, never the full session response.

checkout fields · server only
import { createHmac } from 'node:crypto';

// Run on your server after a successful Create Session call.
// request = the exact body you sent to Create Session (step 2).
// session = Hamro Pay's response. It contains only sessionId and merchantId;
//           it does not contain a token, so your server generates it here.
export function checkoutFields(request, session, clientId, clientApiKey, clientSecret) {
  const tokenMessage = [
    request.merchantId,
    request.merchantTxnId,
    session.sessionId,
    request.transactionAmount, // same paisa value you signed in step 2
    clientId,
    clientApiKey,
  ].join(',');

  const token = createHmac('sha512', clientSecret)
    .update(tokenMessage, 'utf8')
    .digest('base64');

  const fields = {
    merchant_id: request.merchantId,
    session_id: session.sessionId,
    token,
    merchant_transaction_id: request.merchantTxnId,
  };
  for (const [name, value] of Object.entries(fields)) {
    if (typeof value !== 'string' || value.length === 0) {
      throw new Error('Missing checkout field: ' + name);
    }
  }
  return fields;
}

// Render only these fields in the checkout form.
// Never serialize the full session response into the page.

The token is the form signature generated from merchant_id, merchant_transaction_id, session_id, transaction_amount, client_id, client_api_key using your client secret.

Render these fields in your checkout form. When the customer clicks the button, the browser submits the form to Hamro Pay’s checkout gateway.

checkout.html · server-rendered template
<!-- Template: replace these values on your server.
     HTML-escape every value before inserting it.
     HAMRO_GATEWAY_URL is {{GATEWAY_URL}}/api/checkout
     (UAT: https://uat-checkout-pay.hamropatro.com/api/checkout). -->
<form method="POST"
      action="{{ HAMRO_GATEWAY_URL }}"
      enctype="application/x-www-form-urlencoded">
  <input type="hidden" name="merchant_id"
         value="{{ merchant_id }}">
  <input type="hidden" name="session_id"
         value="{{ session_id }}">
  <input type="hidden" name="token"
         value="{{ token }}">
  <input type="hidden" name="merchant_transaction_id"
         value="{{ merchant_transaction_id }}">
  <button type="submit">Pay with Hamro Pay</button>
</form>

The double braces are template variables. Replace them using your backend’s HTML template engine and its HTML escaping. Keep merchant_transaction_id identical to the merchantTxnId used to create the session.

Ready when:
Clicking “Pay with Hamro Pay” opens the test checkout for the correct order and amount.

4 Confirm payment before fulfilling the order

The return URL includes MerchantTxnId (capital M and T). Use it to look up your saved order. A success-page visit alone is not proof of payment.

Call Get Transaction with POST to {{API_BASE_URL}}/v1/checkout/transaction from your server with the following body. Generate a new signature in this order: merchantTxnId,merchantId,client_id,clientApiKey. Use the same HMAC-SHA512 and Base64 process, and your client secret.

Get Transaction · request body
{
  "merchantId": "YOUR_TEST_MERCHANT_ID",
  "merchantTxnId": "ORDER-1001"
}

Fulfill only when the server response reports COMPLETED and its transaction ID and amount match your saved order. The reference names the response field merchantTransactionId; the UAT API has been observed returning merchantTxnId, so accept either. The response amount is in rupees, not paisa.

verify payment · server only
// Run on your server after calling Get Transaction.
// payment = Hamro Pay's response, not the browser's data.
// order = your saved order, loaded using its transaction ID.
export function isPaid(payment, order) {
  if (!payment || !order || typeof order.merchantTxnId !== 'string'
      || !order.merchantTxnId) return false;
  // The reference names this field merchantTransactionId; the UAT API has been
  // observed returning merchantTxnId. Accept either.
  const txnId = payment.merchantTransactionId ?? payment.merchantTxnId;
  if (!['number', 'string'].includes(typeof payment.amount)
      || !['number', 'string'].includes(typeof order.amount)) return false;
  const amount = Number(payment.amount);
  const expected = Number(order.amount);
  return payment.status === 'COMPLETED'
    && txnId === order.merchantTxnId
    && Number.isFinite(amount)
    && amount > 0
    && Number.isFinite(expected)
    && amount === expected;
}

// Fulfill only after isPaid returns true, and save the paid state
// atomically so repeated checks or webhooks cannot fulfill twice.

Keep PENDING or PROCESSING orders unpaid while awaiting confirmation. Show a retry option for FAILED. Return-page checks work when the customer returns; add verified webhooks to handle customers who close the page.

Ready when:
A verified test payment marks the correct order as paid exactly once.

Test the whole flow

Create a test user, complete the checkout with the test credentials below, then run through these cases before switching to live credentials.

Step 4: End-to-End Testing

Test Your Checkout Integration

Perform end-to-end Checkout transactions to ensure your backend and webhooks respond correctly:

Use these test credentials to complete the checkout:
Hamro Pay number 9841414141
T-PIN 0000
OTP 000000
Choose the result with the OTP:

At the OTP step of checkout, enter one of these codes to get that transaction status.

000000 Successful payment COMPLETED
111111 Pending payment PENDING
222222 Failed payment FAILED
Test the complete lifecycle scenarios:
  • Successful Payment Flow Use OTP 000000. Verify browser redirect and webhook payload with status: COMPLETED.
  • Failed / Cancelled Flow Use OTP 222222 for a FAILED transaction, and cancel checkout to test an abort. Verify the order stays unpaid and the customer can retry.
  • Pending / Timeout Flow Use OTP 111111 for a PENDING transaction. Verify the order stays unpaid, and check it later with the Get Transaction API or asynchronous webhook delivery.

Run through these cases

  • Successful payment (OTP 000000): the correct amount is shown and your server confirms the order as paid.
  • Failed payment (OTP 222222) or canceled checkout: the customer can try again and the order stays unpaid.
  • Pending payment (OTP 111111): the order stays unpaid until a later server check confirms completion.
  • Repeated return or notification: the order is fulfilled only once.
  • Changed transaction ID or amount: your server rejects the mismatch.
  • Customer closes checkout: verified webhooks or server reconciliation still update the order.

Ready for real payments?

Ask Hamro Pay to approve live onboarding and confirm your live credentials, endpoints, payment methods, and transaction rate. Replace test settings, verify your production return URLs and webhook, and confirm a live payment with your team.

Contact the integration team

Need field details?

They’re all in the API reference.

Next: API reference

Hamro Pay Support

Grievance officer

Follow Us

© 2026 HamroPay. All Rights Reserved.