Para asociar un pago cripto al pedido correcto, crea primero el pedido en el sistema del comercio y asígnale un ID estable. Envía ese ID como contexto de una payment invoice separada y guarda el invoice ID del proveedor en el pedido. Cuando una consulta autenticada o webhook firmado informe paid, localiza el pedido mediante la referencia, confirma el estado, registra token, red, importe y tx hash y ejecuta el fulfilment de forma idempotente. La relación fiable es merchant order ID → payment invoice ID → confirmed blockchain transaction.
| Registro | Qué demuestra | Qué no demuestra por sí solo |
|---|---|---|
| Pedido del comercio | Cliente, obligación y regla de fulfilment | Que los fondos llegaron on-chain |
| Payment invoice | Token, red, importe y plazo esperados | Que el comercio entregó el producto |
| Blockchain transaction | Transferencia pública de tokens | Qué pedido comercial pretendía pagar |
| Evento firmado | Asociación de invoice, estado y transacción | Que el efecto downstream ocurrió una sola vez |
La blockchain no contiene tu pedido
Una blockchain registra movimiento de activos. El evento ERC-20 Transfer incluye sender, recipient y value; el estándar ERC-20 no contiene número de pedido, cliente, SKU ni regla de entrega. Ver 100 USDC en una wallet prueba una transferencia, pero no dice si corresponde a ORDER-4821, una invoice antigua u otra operación.
Crea la relación antes de mostrar checkout. Inferir después mediante address, amount o time convierte cada coincidencia en una investigación manual.
No uses address, amount o screenshot como clave
La receiving address puede compartirse entre pagos. Dos clientes pueden enviar el mismo importe; alguien puede reutilizar una instrucción antigua; el mismo formato 0x existe en distintas redes EVM. El importe tampoco es único: hay precios iguales, underpayment, overpayment y redondeo. Importes decimales extraños pueden reducir colisiones, pero no sustituyen foreign keys.
Cuando el importe verificado sea distinto del de la factura, usa el flujo para pagos insuficientes y excesivos y mantén el pedido fuera del fulfilment automático normal.
Timestamp y sender address solo son evidencia auxiliar. Las exchanges pueden agrupar o retrasar retiros. Un screenshot no prueba nada y un tx hash real puede indicar token, recipient o red incorrectos, o haberse utilizado en otro pedido. Consulta el checklist manual.
Conecta tres registros con identificadores explícitos
| Campo | Dónde guardarlo | Finalidad |
|---|---|---|
| Local order ID | Base del comercio y payment context | Lookup y fulfilment estables |
| Payment invoice ID | Pedido y proveedor | Consulta directa y soporte |
| Expected business amount | Pedido | Obligación comercial |
| Payable token amount | Invoice | Importe exacto del checkout |
| Token y network | Invoice y payment record | Separar rutas diferentes |
| Status e history | Payment record | Controlar la siguiente acción |
| Transaction hash | Payment record final | Localizar evidencia pública |
| Paid/expiry timestamps | Payment record | Explicar pagos tardíos |
| Event/delivery key | Webhook inbox | Evitar efectos repetidos |
Usa un database ID inmutable o UUID, no un número visible editable. No guardes secrets, private keys ni datos personales innecesarios en metadata. Al crear la invoice, guarda inmediatamente su ID en el pedido para navegar en ambas direcciones.
Crea la invoice con idempotencia
El sitio debe validar la compra, crear el local order en payment_pending, generar una idempotency key por pedido e intento, crear la payment invoice con el order ID, guardar invoice ID y checkout URL y solo entonces redirigir.
Un timeout es ambiguo: la invoice puede existir aunque la respuesta no llegara. Repetir con una clave distinta puede crear dos checkouts. En GramPayBot, la referencia se envía en payload; el mismo Idempotency-Key y parámetros devuelve la invoice original, mientras que reutilizarlo con otros parámetros produce conflict. Consulta API quickstart y API reference.
Un pedido puede tener varios intentos: order → attempt 1 expired → attempt 2 paid. No sobrescribas el anterior. Solo un attempt puede cerrar el pedido automáticamente; los demás quedan para late-payment review.
Deja la transición final al servidor
La browser return page no es autoridad. Usa API autenticada o webhook firmado server-to-server. El handler debe leer el raw body, verificar HMAC en constant time, guardar delivery y body, deduplicar por una clave estable, responder 2xx rápido y procesar después en un worker.
GramPayBot puede reintentar eventos reales hasta 17 veces durante unos cuatro días. Duplicate delivery es normal. Las prácticas oficiales de Stripe también indican registrar los event IDs procesados.
Deduplicar la entrega no basta: un webhook y un polling worker pueden observar la misma invoice pagada. Protege el efecto comercial con unique constraint o conditional transition. El pedido solo debe pasar desde payment_pending y debe existir una sola fulfilment job por order ID. El objetivo es at-least-once delivery con exactly-once business effect.
Asocia estados con acciones permitidas
| Estado | Significado | Acción automática |
|---|---|---|
active | Solicitud válida sin pago aceptado | Mantener pedido pending |
paid | Invoice cumplió la regla de confirmación | Permitir fulfilment idempotente |
expired | La ventana terminó sin match | Bloquear entrega normal y revisar late payment |
cancelled | La solicitud se cerró | No usar como intento actual |
Payment state y order state pueden diferir. Una invoice pagada puede llevar a ready_for_review si hay control de stock o compliance. Una expirada puede permitir un nuevo intento. Conserva status history, motivo y autor de cada manual override.
Mantén visibles las excepciones
Wrong token contract, wrong network, underpayment, overpayment, late payment, duplicate tx hash y paid invoice sin local order deben ir a un estado de excepción. Conserva la transacción y deja que una persona autorizada decida aceptar, pedir diferencia o devolver. En direct-to-wallet el comercio firma el refund; el monitor no revierte la blockchain.
Operational matching no sustituye la contabilidad. Finance puede necesitar fiat value, fees, conversión, documentos e historial de refunds. Compara periódicamente paid payment attempts con paid orders y busca registros huérfanos o hashes duplicados. Las transferencias de tokens aparecen en event logs de smart contracts, pero esos logs no conocen el significado comercial.
Ejemplo con GramPayBot
El SaaS crea ORDER-4821. El backend llama createInvoice con payload: "ORDER-4821" e Idempotency-Key: ORDER-4821:crypto:1, y guarda public_id y checkout URL. El cliente paga USDC en Base. GramPayBot confirma y envía invoice_paid firmado con order reference, token, red y tx hash. El endpoint verifica, persiste y responde 2xx; el worker bloquea el pedido pendiente y crea una sola activación. Los retries no activan el plan de nuevo.
La verificación automática explica la detección completa, y el caso de uso para sitios muestra su función comercial.
Antes del lanzamiento, repite invoice creation con la misma clave, entrega dos veces el mismo webhook, deja expirar una invoice y prueba un importe incorrecto sin fulfilment. La integración está lista cuando cada pedido pagado conduce a una invoice y una transacción aceptada, y cada retry produce un no-op seguro o un review item visible.
Siguiente paso
Automatiza la verificación en tu sitio
Crea una invoice por pedido, usa hosted checkout y recibe un resultado vinculado al pedido.
Ver pagos para sitios web →