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.

Example in Python
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.

Steps

  1. Generate a nonce — Secure random string, at least 16 chars

    # Example in Python def generate_nonce(): return str(uuid.uuid4())

  2. Build canonical string using the rules:

    1. The request’s signature is calculated over this exact concatenation (no delimiters):

      METHOD + PATH + NONCE + QUERY + BODY

  3. Sign with your merchant’s private key using RSA-SHA256.

  4. Base64-encode the signature.

  5. Send it in the X-API-Signature header

Example Python


Example Authenticated Request


Error Codes

Error Type: missing signature

Status Code: 401

Response Body:

Error Type: missing api key

Status Code: 401

Response Body:

Error Type: invalid api key

Status Code: 401

Response Body:

Error Type: nonce too short

Status Code: 400

Response Body:

Error Type: nonce already used

Status Code: 401

Response Body:

Error Type: invalid nonce

  • Status Code: 400

  • Response Body:

Error Type: missing nonce

Status Code: 401

Response Body:

Error Type: timestamp expired

Status Code: 401

Response Body:

Error Type: multiple nonces

Status Code: 401

Response Body:

Last updated