Saltar al contenido

Guías

Autenticación

Cada llamada va firmada con HMAC-SHA256 en cabeceras HTTP. Ningún valor de seguridad (clave, firma, uid, mid) viaja en la URL: si aparece en la query, la API responde 400 credentials_in_url.

Cabeceras

CabeceraValor
X-Api-Key-IdTu Key ID (tu panel de comercio → API).
X-Api-TimestampHora actual en segundos Unix. Se aceptan ±300 s: mantené el reloj sincronizado (NTP).
X-Api-NonceValor aleatorio nuevo en cada llamada (16 a 64 caracteres A-Z a-z 0-9 _ -). Un nonce repetido se rechaza (401 replayed_request).
X-Api-SignatureLa firma, en hexadecimal (64 caracteres).

Qué se firma

Unís con puntos estos cinco valores y calculás el HMAC-SHA256 con tu secreto:

Texto canónico
<timestamp>.<nonce>.<MÉTODO>.<ruta con query>.<sha256 hex del cuerpo>
  • MÉTODO en mayúsculas: GET, POST.
  • La ruta exactamente como la enviás, con la query: /v2/payments?ucode=A-1&limit=10.
  • El hash del cuerpo exacto que enviás (los mismos bytes). Sin cuerpo (GET): el hash de la cadena vacía, e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.

Ejemplos

PHP
<?php
$keyId  = getenv('EPAYOUTS_KEY_ID');
$secret = getenv('EPAYOUTS_SECRET');
$base   = 'https://api.e-payouts.com';

function epayouts(string $method, string $path, ?array $payload = null): array
{
    global $keyId, $secret, $base;
    $body  = $payload === null ? '' : json_encode($payload, JSON_UNESCAPED_SLASHES);
    $ts    = (string) time();
    $nonce = bin2hex(random_bytes(16));
    $sig   = hash_hmac('sha256', "$ts.$nonce.$method.$path." . hash('sha256', $body), $secret);

    $ch = curl_init($base . $path);
    curl_setopt_array($ch, [
        CURLOPT_CUSTOMREQUEST  => $method,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POSTFIELDS     => $body === '' ? null : $body,
        CURLOPT_HTTPHEADER     => [
            "X-Api-Key-Id: $keyId",
            "X-Api-Timestamp: $ts",
            "X-Api-Nonce: $nonce",
            "X-Api-Signature: $sig",
            'Content-Type: application/json',
        ],
    ]);
    $response = json_decode((string) curl_exec($ch), true);
    return ['status' => curl_getinfo($ch, CURLINFO_HTTP_CODE), 'body' => $response];
}

$r = epayouts('POST', '/v2/payments', [
    'module' => '65cdef71-b6b8-11f1-8ee3-d721203bc734',
    'amount' => '25.00',
    'currency' => 'EUR',
    'ucode' => 'PEDIDO-1001',
]);
header('Location: ' . $r['body']['data']['checkout_url']);

Errores de autenticación

  • 401 missing_credentials · invalid_credentials — falta una cabecera o tiene formato inválido.
  • 401 timestamp_out_of_range — tu reloj está desfasado más de 5 minutos.
  • 401 invalid_signature — la firma no coincide (revisá ruta, query y cuerpo exactos) o la clave no existe o fue regenerada.
  • 401 replayed_request — reusaste un nonce.
  • 403 ip_not_allowed — el módulo tiene lista de IPs permitidas y la tuya no está (tu panel de comercio → Sitios → módulo).
  • 429 rate_limited — 20 fallos de autenticación por minuto desde una IP la bloquean un minuto.
Si tu clave es anterior a api2 aparece en tu panel de comercio como "Regenerar para usar api2": regenerá el secreto para poder firmar.