Skip to main content
POST
/
v1
/
pay
/
qr
Create Dynamic QR Ph
curl --request POST \
  --url https://qrph.sbx.moduluslabs.io/v1/pay/qr \
  --header 'Authorization: Basic <encoded-value>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "Token": "eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0..."
}
'
{
  "Token": "eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0..."
}
How it works: Generate a unique QR code → Customer scans with banking app → Payment completed → Webhook notification sent

Authentication

This endpoint requires HTTP Basic Authentication using your Secret Key.

Encrypted Payload Structure

The Token field must contain a JWE-encrypted JSON payload with the following fields:
FieldTypeRequiredDescription
activationCodestringYesActivation Code from Modulus Labs. Format: XXXX-XXXX-XXXX-XXXX
currencystringYesISO 4217 currency code (3 chars). Currently only PHP supported
amountstringYesPayment amount with 2 decimals. Range: 1.00 to 99999.99
merchantReferenceNumberstringYesYour unique reference (1-36 chars, alphanumeric and hyphens)
Activation Code assigned to your sub-merchant account by Modulus Labs.
  • Format: XXXX-XXXX-XXXX-XXXX (19 characters including hyphens)
  • Example: A9X4-B7P2-Q6Z8-M3L5
ISO 4217 currency code.
  • Length: Exactly 3 characters
  • Supported: PHP (production), USD, SGD (sandbox only)
  • Example: PHP
Payment amount in decimal format.
  • Min: 1.00 (₱1.00)
  • Max: 99999.99 (₱99,999.99)
  • Format: String with exactly 2 decimal places
  • Example: "500.00", "1234.56"
Pass amount as a string, not a number, to preserve decimal precision.
Your unique reference number for this transaction.
  • Min Length: 1 character
  • Max Length: 36 characters
  • Allowed: Alphanumeric characters and hyphens
  • Example: "ORDER-12345", "5e91bc6c-f7e2-4a39-ae0e-5e93985c94a4"
Use UUIDs for guaranteed uniqueness across transactions.

Example Payload (Before Encryption)

{
  "activationCode": "A9X4-B7P2-Q6Z8-M3L5",
  "currency": "PHP",
  "amount": "500.00",
  "merchantReferenceNumber": "ORDER-2025-001"
}

Decrypted Response

When you decrypt the response Token, you’ll get:
FieldTypeDescription
idstringUnique transaction identifier generated by Modulus Labs
qrBodystringBase64-encoded PNG image of the QR code
{
  "id": "0ce32626-08cf-405c-adab-6d384a8871da",
  "qrBody": "iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51AAAMTElEQVR4nO..."
}

Code Examples

# Note: You need to encrypt the payload first using a script/tool
# See the Encryption Guide for JWE token creation

# 1. Create encrypted JWE token (using external tool/script)
ENCRYPTED_TOKEN="eyJhbGciOiJBMjU2S1ciL..."

# 2. Make API request
curl -X POST https://qrph.sbx.moduluslabs.io/v1/pay/qr \
  -u sk_YOUR_SECRET_KEY: \
  -H "Content-Type: application/json" \
  -d "{\"Token\": \"$ENCRYPTED_TOKEN\"}"

# 3. Response will be an encrypted JWE token that needs decryption

Using the QR Code

After receiving the qrBody, you need to convert it to an image that customers can scan:

Display in Web Application

<img src="data:image/png;base64,${qrBody}" alt="Scan to Pay" />

Save as File

const fs = require('fs');

function saveQRCode(qrBody, filename = 'qr-code.png') {
  const buffer = Buffer.from(qrBody, 'base64');
  fs.writeFileSync(filename, buffer);
}

Best Practices

Use UUIDs

Use UUIDs for merchantReferenceNumber to ensure uniqueness

Validate Amount

Validate amount format and range before sending to API

Handle Errors

Implement proper error handling for all possible scenarios

Store Transaction ID

Save the returned id for reconciliation and support

Common Issues

Symptoms:
  • Cannot decrypt response token
  • “Invalid token” errors
Solutions:
  • Verify you’re using the correct Encryption Key
  • Check encryption algorithms match (A256KW, A256CBC-HS512)
  • Ensure no whitespace in keys
Symptoms:
  • API returns “Invalid amount” error
  • Request rejected with 400 status
Solutions:
  • Ensure amount is a string, not a number: "500.00" not 500
  • Always include 2 decimal places: "5.00" not "5"
  • Stay within min/max range (1.00 to 99999.99)
Symptoms:
  • Base64 decode fails
  • Invalid image format
Solutions:
  • Ensure full Base64 string was received (not truncated)
  • Check for proper Base64 padding
  • Verify you’re decoding as PNG format

Next Steps

Authorizations

Authorization
string
header
required

HTTP Basic Authentication using your Secret Key as the username and an empty password

Body

application/json
Token
string
required

JWE-encrypted token containing the payment payload. Algorithm: A256KW | Encryption: A256CBC-HS512. See the Encryption Guide for how to create this token.

Response

QR code generated successfully. Response contains an encrypted JWE token.

Token
string

JWE-encrypted response token. When decrypted, contains the transaction ID and QR code image.