Python
HTTP client in Python using requests. Reuses a Session to keep the headers and the connection pool. Also includes a webhook receiver with Flask and HMAC verification.
Setup
pip install requestsComplete client
# lxs_client.py
import os, uuid, hmac, hashlib
from typing import Optional
import requests
class LxsClient:
def __init__(self, api_key: str, base_url: str = "https://api.pos.lxsyscr.com"):
self.base_url = base_url
self.session = requests.Session()
self.session.headers.update({
"X-Api-Key": api_key,
"Content-Type": "application/json",
"Accept": "application/json"
})
self.session.timeout = 30
def emitir(self, data: dict, idempotency_key: Optional[str] = None) -> dict:
key = idempotency_key or str(uuid.uuid4())
r = self.session.post(
f"{self.base_url}/api/v1/facturas",
json=data,
headers={"Idempotency-Key": key}
)
r.raise_for_status()
return r.json()
def consultar(self, clave: str) -> dict:
r = self.session.get(f"{self.base_url}/api/v1/facturas/{clave}")
r.raise_for_status()
return r.json()
def descargar_pdf(self, clave: str) -> bytes:
r = self.session.get(f"{self.base_url}/api/v1/facturas/{clave}/pdf")
r.raise_for_status()
return r.content
def descargar_xml(self, clave: str) -> str:
r = self.session.get(f"{self.base_url}/api/v1/facturas/{clave}/xml")
r.raise_for_status()
return r.text
def reenviar_email(self, clave: str) -> dict:
r = self.session.post(f"{self.base_url}/api/v1/facturas/{clave}/email")
r.raise_for_status()
return r.json()
def anular(self, clave: str) -> None:
r = self.session.delete(f"{self.base_url}/api/v1/facturas/{clave}")
r.raise_for_status()
def proximo_consecutivo(self, tipo: str) -> int:
r = self.session.get(f"{self.base_url}/api/v1/consecutivos/proximo", params={"tipo": tipo})
r.raise_for_status()
return r.json()["proximo"]
# Usage:
client = LxsClient(os.environ["LXS_API_KEY"])
factura = client.emitir({
"tipo": "FacturaElectronica",
"idUsuario": 7,
"cliente": {"idCliente": 42},
"condicionVenta": "01",
"medioPago": "01",
"moneda": "CRC",
"lineas": [{"idProducto": 100, "cantidad": 2}]
})
print(f"Key: {factura['clave']}")Webhook receiver (Flask)
You must use request.get_data() to get the body as bytes before computing the HMAC. If get_json() is called first and then serialized again, the signature will not match.
# webhook_server.py
import os, hmac, hashlib, json
from flask import Flask, request, abort
app = Flask(__name__)
WEBHOOK_SECRET = os.environ["LXS_WEBHOOK_SECRET"]
@app.post("/webhooks/lxs")
def webhook():
signature = (request.headers.get("X-Lxs-Signature") or "").replace("sha256=", "")
expected = hmac.new(WEBHOOK_SECRET.encode(), request.get_data(), hashlib.sha256).hexdigest()
if not hmac.compare_digest(signature, expected):
abort(401)
evento = request.get_json()
procesar_evento(evento)
return "", 200
def procesar_evento(evento: dict):
# Dedup by nonce
# Update DB
pass
if __name__ == "__main__":
app.run(port=3000)