SERO Pay
Desde cero
Intégralo con un asistente de IA, sin saber programar.
Archivo/Pagar con SERO/Protocolo
Especificación abierta
Todo lo necesario para crear órdenes, reconocer pagos y verificarlos en BNB Smart Chain desde cualquier lenguaje, sin depender de nuestro código. Si puedes calcular un keccak-256 y hablar JSON-RPC, puedes integrarlo.
El principio
Una orden SERO es un documento autocontenido. De ella se deriva una huella de 24 bytes que la app de quien paga graba dentro del pago. Cualquiera que tenga la orden puede encontrar su pago en la red y comprobarlo, sin cuentas, sin claves y sin preguntarle a nadie.
1. La orden
Estos campos, en este orden exacto, sin espacios, codificados en UTF-8:
{"v":1,"id":"A-1043","number":1043,"status":"enProceso","total":"27.25","currency":"USDT",
"merchantAddress":"0x7a3c…6f81","products":[{"id":"p1","name":"Café de altura, 250 g",
"price":"9.50","quantity":2,"subtotal":"19.00"}, …]}
total es la suma exacta de los subtotal.merchantAddress en minúsculas. Nombres de hasta 40 caracteres, hasta 100 líneas.id es la referencia del comercio: la misma referencia con los mismos datos produce la misma orden.canonico = "SERO-ORDER-V1." + base64url(json) # sin relleno "="
suma = keccak256(canonico)[0:10] en mayúsculas
token = canonico + "." + suma
huella = keccak256("SERO-ORDEN-HUELLA-V1|" + token)[0:48] # 24 bytes en hexadecimal
keccak-256 es el de Ethereum (relleno 0x01), no SHA3-256.
2. El pago
La app de quien paga usa como clientTxId la huella seguida de 8 bytes al azar. El contrato SERO 0xc872fcbc4Df48187454798Ebc94176A258832F4D (cadena 56) emite:
PaymentExecuted(bytes32 indexed clientTxId, address indexed user, address indexed recipient,
uint256 amount, uint256 fee, uint256 nonce, address relayer, address treasury)
topic0 = 0x101bbd0b71609893cf7095fdbebe9b6e9e097866134ccb8d28e9ce3d309b14e4
Un pago corresponde a una orden cuando la transacción tiene estado 0x1, el log viene de ese contrato con ese topic0, los bytes 1 a 24 de topic1 son la huella, topic3 es la dirección del comercio y amount es exactamente total × 10¹⁸. amount es lo que recibe el comercio; la comisión va aparte.
3. En otro lenguaje
Una implementación completa en 50 líneas, con pycryptodome y requests. Produce el mismo token y la misma huella que sero-pay.js, byte a byte.
import base64
import json
import requests
from Crypto.Hash import keccak
CONTRATO = "0xc872fcbc4df48187454798ebc94176a258832f4d"
TEMA_PAGO = "0x101bbd0b71609893cf7095fdbebe9b6e9e097866134ccb8d28e9ce3d309b14e4"
RPC = "https://bsc-dataseed.bnbchain.org"
def keccak256(texto: str) -> str:
h = keccak.new(digest_bits=256)
h.update(texto.encode("utf-8"))
return h.hexdigest()
def crear_orden(orden_id: str, numero: int, direccion: str, productos: list) -> dict:
lineas, total = [], 0
for i, (nombre, precio_centavos, cantidad) in enumerate(productos, start=1):
subtotal = precio_centavos * cantidad
total += subtotal
lineas.append({"id": f"p{i}", "name": nombre, "price": f"{precio_centavos / 100:.2f}",
"quantity": cantidad, "subtotal": f"{subtotal / 100:.2f}"})
datos = {"v": 1, "id": orden_id, "number": numero, "status": "enProceso",
"total": f"{total / 100:.2f}", "currency": "USDT",
"merchantAddress": direccion.lower(), "products": lineas}
json_orden = json.dumps(datos, ensure_ascii=False, separators=(",", ":"))
canonico = "SERO-ORDER-V1." + base64.urlsafe_b64encode(json_orden.encode("utf-8")).decode().rstrip("=")
token = f"{canonico}.{keccak256(canonico)[:10].upper()}"
return {"token": token, "huella": keccak256(f"SERO-ORDEN-HUELLA-V1|{token}")[:48],
"direccion": direccion.lower(), "total_centavos": total}
def verificar_pago(orden: dict, referencia: str) -> bool:
respuesta = requests.post(RPC, json={"jsonrpc": "2.0", "id": 1, "method": "eth_getTransactionReceipt",
"params": [referencia]}, timeout=10).json()
recibo = respuesta.get("result")
if not recibo or recibo["status"] != "0x1":
return False
for log in recibo["logs"]:
temas = [t.lower() for t in log["topics"]]
if (log["address"].lower() == CONTRATO and len(temas) >= 4 and temas[0] == TEMA_PAGO
and temas[1][2:50] == orden["huella"]
and temas[3][-40:] == orden["direccion"][2:]
and int(log["data"][2:66], 16) == orden["total_centavos"] * 10**16):
return True
return False
Para encontrar el pago sin tener su número de referencia, pregunta a la pasarela por la huella (POST /api/pagos/estado) o busca PaymentExecuted con topic3 igual a tu dirección en los bloques recientes. Siempre confirma con el recibo, como arriba.
4. La pasarela de mensajes
Base https://gate-latam.sero.foundation, JSON, CORS abierto, sin credenciales. Solo transporta mensajes; la validez de un pago se decide siempre en la red.
| Ruta | Para qué |
|---|---|
POST /api/orders | Enlace corto de la orden para el QR: { order: token } → { id, url }. |
POST /api/pagos/estado | Pagos anotados por huella: { huellas: [...] }. |
POST /api/cobros | Envía la orden como notificación a una billetera. |
POST /api/cobros/estado | Estado del cobro: activo, pagado, cancelado, rechazado o vencido. |
POST /api/cobros/cancelar | Cancela un cobro pendiente. |
La referencia completa, con errores, límites y tiempos, está en texto plano.
Sigue leyendo
SERO Pay
Intégralo con un asistente de IA, sin saber programar.
SERO Pay
Cobros mensuales en dólares, sin tarjeta, con permiso cada vez.
SERO Pay
Un bloque de HTML personalizado y listo para cobrar.
SERO Pay
Cursos, ebooks y mentorías con entrega automática.
SERO Pay
Por qué regalamos esto y de qué vive SERO.
Preguntas frecuentes
Lee el recibo de la transacción con eth_getTransactionReceipt en cualquier nodo de BNB Smart Chain y comprueba el evento PaymentExecuted del contrato SERO: estado 0x1, huella en topic1, tu dirección en topic3 y el monto exacto en amount.
Los primeros 24 bytes de keccak256("SERO-ORDEN-HUELLA-V1|" + token). La app de quien paga la graba en el clientTxId del pago, por eso cada pago se puede asociar a su orden.
No para verificar. La pasarela solo transporta mensajes; la prueba de un pago está en la red y cualquiera puede comprobarla.