Saltar al contenido principal

Autenticación

La API de Pago46 firma cada petición con HMAC SHA-256. Tú calculas una firma a partir de tu llave secreta y del contenido de la petición; el servidor la recalcula y la compara. Si coincide, confirma dos cosas: que la petición es tuya y que nadie alteró el contenido en tránsito.

El esquema es idéntico para Comercios y Proveedores de Pago. Lo único que cambia es el nombre de la cabecera donde envías tu llave pública.

Cabeceras obligatorias

Cada petición HTTP debe incluir estas tres cabeceras:

CabeceraDescripción
Merchant-Key o Provider-KeyTu llave pública. Usa Merchant-Key si eres Comercio y Provider-Key si eres Proveedor de Pago.
Message-DateMarca de tiempo Unix en segundos (entero o decimal).
Message-HashLa firma HMAC SHA-256 en hexadecimal (ver abajo).
Ventana de validez

El servidor rechaza la petición si Message-Date difiere de la hora del servidor en más de 5 minutos, para prevenir ataques de repetición (replay attacks). Usa siempre la hora actual y en segundos: enviar milisegundos la coloca fuera de la ventana y la petición se rechaza.

Construir la firma

1. Cadena a firmar

Concatena estos cinco valores separados por dos puntos (:), en este orden exacto:

LLAVE:MESSAGE_DATE:MÉTODO:PATH:BODY
  1. Llave pública — el mismo valor de tu cabecera Merchant-Key o Provider-Key.
  2. Message-Date — el mismo valor que envías en la cabecera.
  3. Método HTTPPOST, GET, etc.
  4. Path — la ruta del recurso sin query string, por ejemplo /api/v1/merchants/orders/pay-in/.
  5. Body — el cuerpo crudo de la petición en UTF-8. Si la petición no tiene cuerpo (por ejemplo un GET), usa una cadena vacía.

No se ordenan parámetros ni se normaliza el JSON. Firma exactamente los mismos bytes que envías en el cuerpo: cualquier espacio o cambio de orden produce una firma distinta.

2. Calcular el hash

Firma la cadena con HMAC SHA-256 usando tu secret como llave y representa el resultado en hexadecimal (hexdigest).

Ejemplos de implementación

El mismo firmante sirve para Comercios y Proveedores; solo cambia el nombre de la cabecera de la llave.

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 en segundos
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" o "Provider-Key"
"Message-Date": timestamp,
"Message-Hash": signature,
"Content-Type": "application/json",
}
return requests.request(method, f"{HOST}{path}", headers=headers, data=body_str)


# Ejemplo: un Comercio crea una orden de pay-in
response = signed_request(
key="TU_MERCHANT_KEY",
secret="TU_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)

Errores de autenticación

Cuando la autenticación falla, la API devuelve 403 Forbidden con el formato estándar de errores:

{
"type": "client_error",
"errors": [
{
"code": "authentication_failed",
"detail": "Incorrect authentication credentials.",
"attr": null
}
]
}
Causa probableCómo resolverlo
Falta una cabecera obligatoriaIncluye Merchant-Key/Provider-Key, Message-Date y Message-Hash.
Message-Date fuera de la ventana de 5 minutosUsa la hora actual del sistema en segundos.
Llave pública desconocidaVerifica que usas la llave del ambiente correcto (sandbox vs. producción).
La firma no coincideRevisa el orden de la cadena, el separador :, el path sin query string y que el body sea idéntico al enviado.

Elige tu guía

Soy un Comercio

Quiero cobrar pagos o enviar dinero a mis usuarios.

Soy un Proveedor de Pago

Tengo puntos físicos y quiero procesar transacciones de Pago46.