Skip to main content

Authentication

The Pago46 API signs every request with HMAC SHA-256. You compute a signature from your secret key and the request contents; the server recomputes it and compares. A match confirms two things: that the request is yours and that nobody altered the contents in transit.

The scheme is identical for Merchants and Payment Providers. The only thing that changes is the name of the header where you send your public key.

Required headers

Every HTTP request must include these three headers:

HeaderDescription
Merchant-Key or Provider-KeyYour public key. Use Merchant-Key if you are a Merchant and Provider-Key if you are a Payment Provider.
Message-DateUnix timestamp in seconds (integer or decimal).
Message-HashThe HMAC SHA-256 signature in hexadecimal (see below).
Validity window

The server rejects the request if Message-Date differs from the server time by more than 5 minutes, to prevent replay attacks. Always use the current time, in seconds: sending milliseconds puts it outside the window and the request is rejected.

Building the signature

1. String to sign

Concatenate these five values separated by colons (:), in this exact order:

KEY:MESSAGE_DATE:METHOD:PATH:BODY
  1. Public key — the same value as your Merchant-Key or Provider-Key header.
  2. Message-Date — the same value you send in the header.
  3. HTTP methodPOST, GET, etc.
  4. Path — the resource path without the query string, for example /api/v1/merchants/orders/pay-in/.
  5. Body — the raw request body in UTF-8. If the request has no body (for example a GET), use an empty string.

Parameters are not sorted and the JSON is not normalized. Sign exactly the same bytes you send in the body: any extra space or reordering produces a different signature.

2. Compute the hash

Sign the string with HMAC SHA-256 using your secret as the key, and output the result in hexadecimal (hexdigest).

Implementation examples

The same signer works for Merchants and Providers; only the key header name changes.

import hashlib
import hmac
import json
import time

import requests

HOST = "https://api.dev.pago46.io"


def signed_request(key, secret, key_header, method, path, body=None):
timestamp = str(time.time()) # Unix in seconds
body_str = json.dumps(body) if body else ""

string_to_sign = f"{key}:{timestamp}:{method}:{path}:{body_str}"
signature = hmac.new(
secret.encode("utf-8"),
string_to_sign.encode("utf-8"),
hashlib.sha256,
).hexdigest()

headers = {
key_header: key, # "Merchant-Key" or "Provider-Key"
"Message-Date": timestamp,
"Message-Hash": signature,
"Content-Type": "application/json",
}
return requests.request(method, f"{HOST}{path}", headers=headers, data=body_str)


# Example: a Merchant creates a pay-in order
response = signed_request(
key="YOUR_MERCHANT_KEY",
secret="YOUR_MERCHANT_SECRET",
key_header="Merchant-Key",
method="POST",
path="/api/v1/merchants/orders/pay-in/",
body={"order_type": "LocalCurrencyOrder", "price": "100.00", "price_currency": "CLP"},
)
print(response.status_code)

Authentication errors

When authentication fails, the API returns 403 Forbidden with the standard error format:

{
"type": "client_error",
"errors": [
{
"code": "authentication_failed",
"detail": "Incorrect authentication credentials.",
"attr": null
}
]
}
Probable causeHow to fix it
A required header is missingInclude Merchant-Key/Provider-Key, Message-Date and Message-Hash.
Message-Date outside the 5-minute windowUse the current system time, in seconds.
Unknown public keyMake sure you are using the key for the correct environment (sandbox vs. production).
The signature does not matchCheck the string order, the : separator, the path without query string, and that the body is identical to the one sent.

Choose your guide

I'm a Merchant

I want to collect payments or send money to my users.

I'm a Payment Provider

I have physical points and want to process Pago46 transactions.