Documentación de la API

Con la API REST de LisansX puede importar la lista de productos y el stock a su propio sitio, realizar pedidos y recibir los códigos de entrega al instante. A continuación encontrará la autenticación, los endpoints y ejemplos en PHP, Node.js y Python.

Las claves de API solo se otorgan a los distribuidores. Cualquiera puede consultar la documentación; para enviar solicitudes se necesita un paquete de distribuidor activo. Su clave se genera cuando se aprueba su solicitud de distribuidor.

Autenticación

Cada solicitud se firma con tres encabezados. Como la firma abarca conjuntamente la marca de tiempo, el método HTTP, la ruta y el cuerpo sin procesar, la solicitud no puede modificarse en tránsito ni reenviarse.

EncabezadoValor
X-Api-KeySu clave de API
X-TimestampSegundos Unix: debe estar dentro de ±300 s respecto a la hora del servidor
X-SignatureFirma hexadecimal generada con la fórmula siguiente
signingKey = sha256_hex(api_secret)
signature  = hmac_sha256_hex(signingKey, timestamp + "\n" + METHOD + "\n" + path + "\n" + rawBody)
  • path: la ruta y la cadena de consulta, si la hay (/api/v1/products?limit=50). Los parámetros de consulta también forman parte de la firma: firme exactamente la URL que solicita.
  • rawBody: el JSON exacto que envía; una cadena vacía en las solicitudes GET.
  • No vuelva a serializar el cuerpo después de firmarlo: la más mínima diferencia invalida la firma.

Endpoints

MétodoRutaDescripción
GET /api/v1/products Todos los productos a la venta, con sus precios de distribuidor
GET /api/v1/products/{id} Detalles de un producto y estado del stock
POST /api/v1/order Crear un pedido: si tiene éxito, devuelve los códigos de entrega
GET /api/v1/order/{order_no} Estado del pedido y códigos entregados
GET /api/v1/balance Su saldo actual

El límite de solicitudes por minuto se define para cada cuenta de distribuidor. Si se supera, se devuelve 429 rate_limited. Todas las respuestas de error tienen el formato {"success": false, "error": "...", "message": "..."}.

Ejemplos de integración

Listos para copiar y pegar

<?php
final class LisansXClient
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey,
        private string $apiSecret
    ) { $this->baseUrl = rtrim($baseUrl, '/'); }

    public function request(string $method, string $path, ?array $body = null): array
    {
        $method  = strtoupper($method);
        $bodyRaw = $body !== null ? json_encode($body, JSON_UNESCAPED_UNICODE) : '';
        $ts      = (string)time();

        // Clave de firma = digest SHA-256 en hexadecimal del secret sin procesar
        $signingKey = hash('sha256', $this->apiSecret);
        $signature  = hash_hmac('sha256', $ts . "\n" . $method . "\n" . $path . "\n" . $bodyRaw, $signingKey);

        $ch = curl_init($this->baseUrl . $path);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST  => $method,
            CURLOPT_TIMEOUT        => 30,
            CURLOPT_HTTPHEADER     => [
                'X-Api-Key: '   . $this->apiKey,
                'X-Timestamp: ' . $ts,
                'X-Signature: ' . $signature,
                'Content-Type: application/json',
            ],
        ]);
        if ($body !== null) curl_setopt($ch, CURLOPT_POSTFIELDS, $bodyRaw);

        $raw = curl_exec($ch);
        return json_decode((string)$raw, true) ?: ['success' => false, 'error' => 'invalid_response'];
    }
}

// --- Uso ---
$api = new LisansXClient('https://lisansx.net', 'SU_CLAVE_API', getenv('LISANSX_SECRET'));

$products = $api->request('GET', '/api/v1/products');
$order    = $api->request('POST', '/api/v1/order', ['product_id' => 1, 'qty' => 1]);

if (!empty($order['success'])) {
    foreach ($order['data']['codes'] as $code) {
        echo "Teslim edilen kod: $code\n";
    }
} else {
    error_log('LisansX hatasi: ' . ($order['message'] ?? 'bilinmiyor'));
}

Errores frecuentes

401 invalid_signature
Es posible que haya omitido derivar la clave de firma como sha256(secret).
401 invalid_timestamp
El reloj de su servidor está desincronizado. Sincronícelo con NTP.
403 ip_not_allowed
Hay una restricción de IP configurada y su solicitud procede de una IP que no está en la lista.
409 replayed_request
La misma solicitud POST firmada llegó por segunda vez (protección contra repetición). Firme cada solicitud con una marca de tiempo nueva; si va a realizar dos pedidos del mismo producto en el mismo segundo, añada al cuerpo un campo "nonce" único (p. ej., su propio número de pedido).
429 rate_limited
Ha superado el límite por minuto; distribuya sus solicitudes en el tiempo.
409 out_of_stock
El producto no tiene stock o no está disponible en la cantidad solicitada (el campo available indica la cantidad restante). No se crea el pedido ni se descuenta saldo. Compruebe el stock con GET /api/v1/products/{id} antes de cobrar a su propio cliente; el webhook stock.changed le avisa al instante cuando un producto se agota o vuelve a estar disponible.
409 price_changed
Si envió el campo opcional "max_unit_price" con el pedido y el precio unitario actual lo supera, no se crea el pedido; unit_price indica el precio actual.
402 delivery_failed
El pedido se creó, pero el producto no pudo entregarse (p. ej., se agotó en origen en el último momento). El importe se reembolsa automáticamente a su saldo.
Escribir por Telegram Abrir un ticket de soporte