Skip to content

mpac-pgw API Authentication Guide

This guide explains how to authenticate with the mpac-pgw API.

Overview

mpac-pgw uses two authentication methods:

MethodUse CaseEndpoints
HMAC-SHA256Server-to-server callsCreate, List, Capture, Sync
payment_tokenClient/SDK callsRetrieve, Confirm, Cancel

API Keys

Each Organization receives API credentials:

  • api_key (client_id): Public identifier, e.g., pk_test_abc123...
  • secret_key: Private key for signing, e.g., sk_test_xyz789...

Security: Never expose your secret_key in client-side code. It should only be used on your backend servers.


HMAC-SHA256 Authentication

Used for server-to-server API calls that require organization-level authentication.

Header Format

Authorization: HMAC-SHA256 <api_key>:<timestamp>:<signature>

Signature Calculation

1. Build the message:
   MESSAGE = METHOD + "\n" + PATH + "\n" + TIMESTAMP + "\n" + SHA256(BODY)

2. Hash the secret key:
   SECRET_KEY_HASH = SHA256(secret_key)

3. Calculate signature:
   SIGNATURE = HMAC-SHA256(SECRET_KEY_HASH, MESSAGE)

Parameters

ParameterDescriptionExample
METHODHTTP method (uppercase)POST
PATHRequest path (without query string)/v1/payment_intents
TIMESTAMPUnix timestamp (seconds)1702123456
BODYRequest body (empty string if no body){"amount": 1000}

Code Examples

JavaScript/Node.js

javascript
const crypto = require('crypto');

function generateHMACAuth(apiKey, secretKey, method, path, body = '') {
    const timestamp = Math.floor(Date.now() / 1000).toString();

    // Hash the body
    const bodyHash = crypto.createHash('sha256')
        .update(body)
        .digest('hex');

    // Build message
    const message = `${method}\n${path}\n${timestamp}\n${bodyHash}`;

    // Hash the secret key
    const secretKeyHash = crypto.createHash('sha256')
        .update(secretKey)
        .digest('hex');

    // Calculate HMAC signature
    const signature = crypto.createHmac('sha256', secretKeyHash)
        .update(message)
        .digest('hex');

    return `HMAC-SHA256 ${apiKey}:${timestamp}:${signature}`;
}

// Usage
const authHeader = generateHMACAuth(
    'pk_test_abc123',
    'sk_test_xyz789',
    'POST',
    '/v1/payment_intents',
    JSON.stringify({ merchant_id: '...', store_id: '...', amount: 1000 })
);

fetch('https://api.example.com/v1/payment_intents', {
    method: 'POST',
    headers: {
        'Authorization': authHeader,
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({ merchant_id: '...', store_id: '...', amount: 1000 })
});

Python

python
import hashlib
import hmac
import time
import json
import requests

def generate_hmac_auth(api_key: str, secret_key: str, method: str, path: str, body: str = '') -> str:
    timestamp = str(int(time.time()))

    # Hash the body
    body_hash = hashlib.sha256(body.encode()).hexdigest()

    # Build message
    message = f"{method}\n{path}\n{timestamp}\n{body_hash}"

    # Hash the secret key
    secret_key_hash = hashlib.sha256(secret_key.encode()).hexdigest()

    # Calculate HMAC signature
    signature = hmac.new(
        secret_key_hash.encode(),
        message.encode(),
        hashlib.sha256
    ).hexdigest()

    return f"HMAC-SHA256 {api_key}:{timestamp}:{signature}"

# Usage
body = json.dumps({"merchant_id": "...", "store_id": "...", "amount": 1000})
auth_header = generate_hmac_auth(
    'pk_test_abc123',
    'sk_test_xyz789',
    'POST',
    '/v1/payment_intents',
    body
)

response = requests.post(
    'https://api.example.com/v1/payment_intents',
    headers={
        'Authorization': auth_header,
        'Content-Type': 'application/json'
    },
    data=body
)

Go

go
package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
    "strconv"
    "time"
)

func generateHMACAuth(apiKey, secretKey, method, path, body string) string {
    timestamp := strconv.FormatInt(time.Now().Unix(), 10)

    // Hash the body
    bodyHashBytes := sha256.Sum256([]byte(body))
    bodyHash := hex.EncodeToString(bodyHashBytes[:])

    // Build message
    message := method + "\n" + path + "\n" + timestamp + "\n" + bodyHash

    // Hash the secret key
    secretKeyHashBytes := sha256.Sum256([]byte(secretKey))
    secretKeyHash := hex.EncodeToString(secretKeyHashBytes[:])

    // Calculate HMAC signature
    mac := hmac.New(sha256.New, []byte(secretKeyHash))
    mac.Write([]byte(message))
    signature := hex.EncodeToString(mac.Sum(nil))

    return fmt.Sprintf("HMAC-SHA256 %s:%s:%s", apiKey, timestamp, signature)
}

Timestamp Tolerance

The server accepts timestamps within 5 minutes of server time. Requests with older timestamps will be rejected with expired_signature error.

Common Errors

Error CodeDescriptionSolution
invalid_signatureSignature doesn't matchCheck your signing logic
expired_signatureTimestamp too oldUse current Unix timestamp
client_not_foundInvalid API keyVerify your api_key
client_suspendedOrganization is suspendedContact support

Payment Token Authentication

Used for client-side SDK calls after a PaymentIntent is created.

How It Works

  1. Your backend creates a PaymentIntent (using HMAC auth)
  2. Backend receives payment_token in response
  3. Backend passes payment_token to client/SDK
  4. Client uses payment_token for subsequent operations

Usage

GET requests: Pass as query parameter

GET /v1/payment_intents/{id}?payment_token=pi_xxx_secret_yyy

POST requests: Include in request body

json
POST /v1/payment_intents/{id}/confirm
{
    "payment_token": "pi_xxx_secret_yyy",
    "payment_method_type": "qr_mpm",
    "provider": "PAYPAY"
}

Security Notes

  • payment_token is tied to a specific PaymentIntent
  • It expires when the PaymentIntent expires (default: 30 minutes)
  • It can only be used for operations on its associated PaymentIntent
  • Token format: {payment_intent_id}_secret_{random_hex}

Best Practices

  1. Store secrets securely: Use environment variables or secret managers
  2. Never log secrets: Avoid logging full API keys or signatures
  3. Use HTTPS: Always use TLS in production
  4. Rotate keys: Periodically rotate API keys (you can have multiple active keys)
  5. Separate environments: Use different API keys for test/staging/production

Testing with Postman

  1. Import postman/mpac-pgw.postman_collection.json
  2. Import postman/mpac-pgw-Test.postman_environment.json
  3. Set environment variables:
    • client_id: Your API key (e.g., pk_test_...)
    • secret_key: Your secret key (e.g., sk_test_...)
    • merchant_id: Merchant ID
    • store_id: Store ID
  4. The collection includes a pre-request script that auto-generates HMAC signatures

Quick Reference

Endpoints by Authentication Type

EndpointMethodAuth Type
/v1/payment_intentsPOSTHMAC
/v1/payment_intentsGETHMAC
/v1/payment_intents/{id}GETpayment_token
/v1/payment_intents/{id}/confirmPOSTpayment_token
/v1/payment_intents/{id}/cancelPOSTpayment_token
/v1/payment_intents/{id}/capturePOSTHMAC
/v1/payment_intents/{id}/transactionsGETpayment_token
/v1/transactions/{id}GETHMAC
/v1/sync/merchantsPOSTHMAC

MPAC — MP-Solution Advanced Cloud Service