For the complete documentation index, see llms.txt. This page is also available as Markdown.

Authorisation

Authorisation

All Pay.io API requests must be authenticated with three headers:

Header
Description

X-API-Key

Your unique merchant API key from Merchant Console.

X-API-Nonce

Unique identifier (UUID) per request.

X-API-Signature

RSA-SHA256 signature generated using your private key.


Creating a Public and Private Key

Merchants must provide Pay.io with a public key during onboarding.

Requirements:

  • At least 2048 bits

  • PEM format

You can use the following code sample to generate the public key and private key.

from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization

# Generate 2048-bit private key
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)

# Serialize keys to PEM
pem_private = private_key.private_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PrivateFormat.TraditionalOpenSSL,
    encryption_algorithm=serialization.NoEncryption()
)

pem_public = private_key.public_key().public_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PublicFormat.SubjectPublicKeyInfo
)

Creating a Merchant Signature

Every API request must be signed with your merchant's RSA private key. Pay.io verifies the signature using the public key you provided during onboarding. This is an asymmetric scheme — there is no shared secret.

Steps:

1

Generate a nonce - a secure random string of at least 16 characters. A UUID4 works well.

2

Normalize the body - strip all whitespace from the request body before signing. The server silently normalizes the body the same way, so signing pretty-printed JSON without stripping whitespace will fail signature verification.

3

Build the canonical string using the rule below (no delimiters): METHOD + PATH + NONCE + QUERY + BODY

4

Sign the canonical string with your merchant's private key using RSA-SHA256 (PKCS#1 v1.5).

5

Base64-encode the signature (standard Base64, not URL-safe).

6

Send the request with all three headers: X-API-Key, X-API-Nonce, and X-API-Signature.

Example in Python:


Example Authenticated Request


Error Codes

missing signature — Status 401

missing api key — Status 401

invalid api key — Status 401

nonce too short — Status 400

nonce already used — Status 401

invalid nonce — Status 400

missing nonce — Status 401

timestamp expired — Status 401

multiple nonces — Status 401

Last updated