{"id":13061,"date":"2026-09-01T12:45:45","date_gmt":"2026-09-01T17:45:45","guid":{"rendered":"https:\/\/fluyez.com\/blog\/?p=13061"},"modified":"2026-09-03T15:26:30","modified_gmt":"2026-09-03T20:26:30","slug":"api-de-pagos-con-stablecoin","status":"publish","type":"post","link":"https:\/\/fluyez.com\/blog\/api-de-pagos-con-stablecoin\/","title":{"rendered":"API de pagos con stablecoin, documentaci\u00f3n y casos de uso"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_89 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Tabla de Contenidos<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/fluyez.com\/blog\/api-de-pagos-con-stablecoin\/#Arquitectura_general\" >Arquitectura general<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/fluyez.com\/blog\/api-de-pagos-con-stablecoin\/#Redes_y_stablecoins_soportadas\" >Redes y stablecoins soportadas<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/fluyez.com\/blog\/api-de-pagos-con-stablecoin\/#Endpoints_principales\" >Endpoints principales<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/fluyez.com\/blog\/api-de-pagos-con-stablecoin\/#Autenticacion_y_seguridad\" >Autenticaci\u00f3n y seguridad<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/fluyez.com\/blog\/api-de-pagos-con-stablecoin\/#Codigos_de_estado_y_manejo_de_errores\" >C\u00f3digos de estado y manejo de errores<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/fluyez.com\/blog\/api-de-pagos-con-stablecoin\/#Rate_limits\" >Rate limits<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/fluyez.com\/blog\/api-de-pagos-con-stablecoin\/#Webhooks_entrega_verificacion_y_reintentos\" >Webhooks: entrega, verificaci\u00f3n y reintentos<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/fluyez.com\/blog\/api-de-pagos-con-stablecoin\/#Eventos_de_webhook_que_necesitas_manejar\" >Eventos de webhook que necesitas manejar<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/fluyez.com\/blog\/api-de-pagos-con-stablecoin\/#SDKs_y_compatibilidad\" >SDKs y compatibilidad<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/fluyez.com\/blog\/api-de-pagos-con-stablecoin\/#Casos_de_uso_tecnicos\" >Casos de uso t\u00e9cnicos<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/fluyez.com\/blog\/api-de-pagos-con-stablecoin\/#Checklist_antes_de_pasar_a_produccion\" >Checklist antes de pasar a producci\u00f3n<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/fluyez.com\/blog\/api-de-pagos-con-stablecoin\/#Entorno_de_pruebas\" >Entorno de pruebas<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/fluyez.com\/blog\/api-de-pagos-con-stablecoin\/#Base_regulatoria_detras_de_la_infraestructura\" >Base regulatoria detr\u00e1s de la infraestructura<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/fluyez.com\/blog\/api-de-pagos-con-stablecoin\/#Preguntas_frecuentes\" >Preguntas frecuentes<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-15\" href=\"https:\/\/fluyez.com\/blog\/api-de-pagos-con-stablecoin\/#Conclusion\" >Conclusi\u00f3n<\/a><\/li><\/ul><\/nav><\/div>\n<p><strong>TL;DR:<\/strong> Una <strong>API de pagos con stablecoin<\/strong> confiable en producci\u00f3n se sostiene en tres decisiones t\u00e9cnicas: verificaci\u00f3n de firma HMAC en cada webhook, idempotencia en cada request, y reintentos con backoff exponencial en lugar de reintentos inmediatos. El resto es detalle de implementaci\u00f3n.<\/p>\n<p>Este art\u00edculo documenta c\u00f3mo est\u00e1 construida t\u00e9cnicamente una API de pagos con stablecoin, qu\u00e9 componentes debe tener para ser confiable en producci\u00f3n, y qu\u00e9 patrones de integraci\u00f3n usan los equipos que ya la implementaron sin incidentes. No es una introducci\u00f3n conceptual, es la referencia t\u00e9cnica que un desarrollador necesita antes de comprometer tiempo de sprint a la integraci\u00f3n: endpoints, formatos de request y respuesta, c\u00f3digos de error, seguridad de webhooks y checklist de testing.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Arquitectura_general\"><\/span>Arquitectura general<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Una API de pagos con stablecoin bien dise\u00f1ada separa tres responsabilidades. La creaci\u00f3n del cobro, que genera una direcci\u00f3n de pago o un link \u00fanico por transacci\u00f3n. La confirmaci\u00f3n en cadena, que escucha la blockchain hasta que el pago recibe suficientes confirmaciones para considerarse v\u00e1lido. Y la notificaci\u00f3n al backend del comercio, normalmente v\u00eda webhook, para que el sistema del negocio actualice el estado del pedido sin tener que hacer polling constante contra la API.<\/p>\n<pre style=\"background-color: #f4f4f4; border: 1px solid #dddddd; padding: 16px; overflow-x: auto; border-radius: 2px;\"><code>Cliente inicia pago\r\n    \u2193\r\nAPI genera invoice (direcci\u00f3n + monto + red)\r\n    \u2193\r\nCliente env\u00eda stablecoin desde su wallet\r\n    \u2193\r\nNodo de la red confirma la transacci\u00f3n\r\n    \u2193\r\nAPI espera N confirmaciones seg\u00fan la red\r\n    \u2193\r\nWebhook notifica al backend del comercio\r\n    \u2193\r\nBackend actualiza el estado del pedido\r\n<\/code><\/pre>\n<h2><span class=\"ez-toc-section\" id=\"Redes_y_stablecoins_soportadas\"><\/span>Redes y stablecoins soportadas<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<table style=\"border-collapse: collapse; width: 100%; margin: 20px 0;\">\n<thead>\n<tr style=\"background-color: #1f3a5f; color: #ffffff;\">\n<th style=\"padding: 10px 12px; text-align: left; border: 1px solid #1F3A5F;\">Red<\/th>\n<th style=\"padding: 10px 12px; text-align: left; border: 1px solid #1F3A5F;\">Stablecoin<\/th>\n<th style=\"padding: 10px 12px; text-align: left; border: 1px solid #1F3A5F;\">Ventaja t\u00e9cnica<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">TRON (TRC20)<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">USDT<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Fee de red m\u00e1s bajo, la m\u00e1s usada en LATAM para pagos frecuentes<\/td>\n<\/tr>\n<tr style=\"background-color: #eaf1f8;\">\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Ethereum (ERC20)<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">USDT, USDC<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Mayor liquidez y compatibilidad con exchanges institucionales<\/td>\n<\/tr>\n<tr>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Polygon<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">USDC<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Confirmaci\u00f3n r\u00e1pida y fee m\u00ednimo, \u00fatil para montos peque\u00f1os frecuentes<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>La elecci\u00f3n de red no es solo una preferencia t\u00e9cnica, cambia directamente el costo y la velocidad de cada transacci\u00f3n. Para pagos de monto bajo y alta frecuencia, una red con fee m\u00ednimo como TRON o Polygon evita que el costo de red se coma un porcentaje relevante del pago. Para transferencias de tesorer\u00eda de monto alto, la liquidez y compatibilidad de Ethereum suele pesar m\u00e1s que el costo del fee.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Endpoints_principales\"><\/span>Endpoints principales<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>M\u00e1s all\u00e1 de crear un cobro, una integraci\u00f3n real necesita consultar el estado de una transacci\u00f3n, listar operaciones para conciliaci\u00f3n, y en el caso de tesorer\u00eda o n\u00f3mina, enviar pagos salientes. Estos son los endpoints que forman el n\u00facleo de cualquier integraci\u00f3n seria.<\/p>\n<table style=\"border-collapse: collapse; width: 100%; margin: 20px 0;\">\n<thead>\n<tr style=\"background-color: #1f3a5f; color: #ffffff;\">\n<th style=\"padding: 10px 12px; text-align: left; border: 1px solid #1F3A5F;\">Endpoint<\/th>\n<th style=\"padding: 10px 12px; text-align: left; border: 1px solid #1F3A5F;\">M\u00e9todo<\/th>\n<th style=\"padding: 10px 12px; text-align: left; border: 1px solid #1F3A5F;\">Para qu\u00e9 sirve<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">\/v1\/payments<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">POST<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Crea un cobro nuevo, devuelve direcci\u00f3n o link de pago<\/td>\n<\/tr>\n<tr style=\"background-color: #eaf1f8;\">\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">\/v1\/payments\/{id}<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">GET<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Consulta el estado actual de un cobro espec\u00edfico<\/td>\n<\/tr>\n<tr>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">\/v1\/payments<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">GET<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Lista cobros con filtros por fecha, estado o referencia, para conciliaci\u00f3n<\/td>\n<\/tr>\n<tr style=\"background-color: #eaf1f8;\">\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">\/v1\/payouts<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">POST<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Env\u00eda un pago saliente a una direcci\u00f3n o cuenta, para n\u00f3mina o proveedores<\/td>\n<\/tr>\n<tr>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">\/v1\/payouts\/batch<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">POST<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Env\u00eda varios pagos salientes en una sola llamada, cada uno con su propia referencia<\/td>\n<\/tr>\n<tr style=\"background-color: #eaf1f8;\">\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">\/v1\/payouts\/{id}<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">GET<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Consulta el estado de un pago saliente espec\u00edfico<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2><span class=\"ez-toc-section\" id=\"Autenticacion_y_seguridad\"><\/span>Autenticaci\u00f3n y seguridad<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Una integraci\u00f3n de este tipo debe manejar tres capas de seguridad como m\u00ednimo. Autenticaci\u00f3n por API key, distinta para entorno de pruebas y de producci\u00f3n, para evitar que una prueba de desarrollo afecte transacciones reales. Firma de webhooks mediante HMAC-SHA256, para que el backend del comercio pueda verificar que la notificaci\u00f3n realmente proviene del proveedor y no de un tercero simulando la llamada. E idempotencia en la creaci\u00f3n de cobros, usando una clave \u00fanica por operaci\u00f3n para evitar cobros duplicados si la petici\u00f3n se reintenta por un timeout de red.<\/p>\n<pre style=\"background-color: #f4f4f4; border: 1px solid #dddddd; padding: 16px; overflow-x: auto; border-radius: 2px;\"><code>POST \/v1\/payments\r\nHeaders:\r\n  Authorization: Bearer {api_key}\r\n  Idempotency-Key: {clave_unica_por_operacion}\r\n  Content-Type: application\/json\r\n\r\nBody:\r\n{\r\n  \"amount\": \"150.00\",\r\n  \"currency\": \"USD\",\r\n  \"settlement_currency\": \"USDC\",\r\n  \"network\": \"polygon\",\r\n  \"reference\": \"pedido_10432\",\r\n  \"webhook_url\": \"https:\/\/tuapp.com\/webhooks\/pagos\"\r\n}\r\n<\/code><\/pre>\n<p>La respuesta t\u00edpica de una API bien dise\u00f1ada devuelve una direcci\u00f3n o link de pago, el estado inicial de la transacci\u00f3n, y el tiempo de expiraci\u00f3n del cobro, informaci\u00f3n que el frontend del comercio necesita para mostrar el checkout con su propio temporizador y estado.<\/p>\n<pre style=\"background-color: #f4f4f4; border: 1px solid #dddddd; padding: 16px; overflow-x: auto; border-radius: 2px;\"><code>{\r\n  \"id\": \"pay_8f3a2c\",\r\n  \"status\": \"pending\",\r\n  \"payment_address\": \"0x9F2...c41A\",\r\n  \"network\": \"polygon\",\r\n  \"amount\": \"150.00\",\r\n  \"expires_at\": \"2026-09-02T14:30:00Z\"\r\n}\r\n<\/code><\/pre>\n<h2><span class=\"ez-toc-section\" id=\"Codigos_de_estado_y_manejo_de_errores\"><\/span>C\u00f3digos de estado y manejo de errores<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Una API confiable devuelve c\u00f3digos de estado consistentes, no un 200 gen\u00e9rico para todo. Diferenciar entre error del cliente (4xx) y error del servidor (5xx) es lo que determina si tu integraci\u00f3n debe reintentar la llamada o corregir el request antes de volver a enviarlo.<\/p>\n<table style=\"border-collapse: collapse; width: 100%; margin: 20px 0;\">\n<thead>\n<tr style=\"background-color: #1f3a5f; color: #ffffff;\">\n<th style=\"padding: 10px 12px; text-align: left; border: 1px solid #1F3A5F;\">C\u00f3digo<\/th>\n<th style=\"padding: 10px 12px; text-align: left; border: 1px solid #1F3A5F;\">Significado<\/th>\n<th style=\"padding: 10px 12px; text-align: left; border: 1px solid #1F3A5F;\">Qu\u00e9 hacer<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">400<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Request mal formado, campo faltante o inv\u00e1lido<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Corregir el payload, no reintentar sin cambios<\/td>\n<\/tr>\n<tr style=\"background-color: #eaf1f8;\">\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">401<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">API key inv\u00e1lida o ausente<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Verificar credenciales, no reintentar<\/td>\n<\/tr>\n<tr>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">409<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Conflicto de idempotencia, la clave ya fue usada con otro payload<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Usar una clave de idempotencia distinta para una operaci\u00f3n nueva<\/td>\n<\/tr>\n<tr style=\"background-color: #eaf1f8;\">\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">422<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Red o moneda no soportada para ese tipo de operaci\u00f3n<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Revisar par\u00e1metros seg\u00fan la documentaci\u00f3n de redes soportadas<\/td>\n<\/tr>\n<tr>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">429<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">L\u00edmite de rate limit excedido<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Reintentar con backoff exponencial, respetando el header Retry-After<\/td>\n<\/tr>\n<tr style=\"background-color: #eaf1f8;\">\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">500 \/ 503<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Error interno o servicio no disponible temporalmente<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Reintentar con backoff exponencial<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>La regla general, consistente con c\u00f3mo maneja esto cualquier API de pagos madura: solo reintentar autom\u00e1ticamente errores 429 y 5xx. Un error 4xx indica un problema en el request que no se resuelve reenviando el mismo payload, reintentar sin corregirlo solo genera ruido y, en el peor caso, operaciones duplicadas.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Rate_limits\"><\/span>Rate limits<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>La mayor\u00eda de APIs de pagos aplican l\u00edmites por ventana de tiempo para proteger la infraestructura de picos de tr\u00e1fico, t\u00edpicamente expresados como un n\u00famero de requests por minuto por API key. Cuando se excede ese l\u00edmite, la respuesta es un 429 con un header <code>Retry-After<\/code> indicando cu\u00e1ntos segundos esperar antes del siguiente intento. Dise\u00f1ar tu integraci\u00f3n para respetar ese header, en lugar de reintentar de inmediato, es lo que evita que tu propia integraci\u00f3n empeore el problema durante un pico de tr\u00e1fico.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Webhooks_entrega_verificacion_y_reintentos\"><\/span>Webhooks: entrega, verificaci\u00f3n y reintentos<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Los webhooks son, por dise\u00f1o, poco confiables: la red falla, el servidor del comercio puede estar ca\u00eddo en el momento exacto del env\u00edo, y un mismo evento puede llegar duplicado. Una integraci\u00f3n madura no asume que cada webhook llega una sola vez, asume lo contrario y se protege con tres mecanismos.<\/p>\n<h3>Verificaci\u00f3n de firma HMAC<\/h3>\n<p>Cada webhook debe incluir una firma HMAC-SHA256 calculada sobre el payload con una clave secreta compartida. El backend del comercio recalcula esa firma y la compara con la recibida, usando una comparaci\u00f3n de tiempo constante para evitar ataques de timing.<\/p>\n<pre style=\"background-color: #f4f4f4; border: 1px solid #dddddd; padding: 16px; overflow-x: auto; border-radius: 2px;\"><code>\/\/ Node.js\r\nconst crypto = require('crypto');\r\n\r\nfunction verificarWebhook(payload, firmaRecibida, secreto) {\r\n  const firmaCalculada = crypto\r\n    .createHmac('sha256', secreto)\r\n    .update(payload)\r\n    .digest('hex');\r\n\r\n  return crypto.timingSafeEqual(\r\n    Buffer.from(firmaCalculada),\r\n    Buffer.from(firmaRecibida)\r\n  );\r\n}\r\n<\/code><\/pre>\n<p>Nunca proceses un webhook sin verificar la firma primero. Sin esa verificaci\u00f3n, cualquiera que descubra tu URL de webhook podr\u00eda enviar eventos falsos y hacer que tu sistema marque pedidos como pagados sin que exista una transacci\u00f3n real.<\/p>\n<h3>Reintentos con backoff exponencial<\/h3>\n<p>Si tu endpoint responde con un c\u00f3digo distinto de 2xx, o no responde dentro del timeout, el proveedor debe reintentar la entrega con intervalos crecientes en lugar de reintentos inmediatos, t\u00edpicamente entre 5 y 10 intentos distribuidos a lo largo de varias horas o d\u00edas antes de marcar el endpoint como fallido. Tu backend, del lado receptor, debe responder 200 lo antes posible, apenas verificada la firma, y procesar la l\u00f3gica de negocio de forma as\u00edncrona en una cola. Un endpoint que tarda demasiado en responder porque procesa todo de forma s\u00edncrona es la causa m\u00e1s com\u00fan de reintentos innecesarios.<\/p>\n<h3>Idempotencia en el procesamiento<\/h3>\n<p>Como el mismo evento puede llegar m\u00e1s de una vez, tu sistema debe guardar el ID de cada evento procesado y descartar duplicados antes de ejecutar cualquier cambio de estado. Sin esto, un reintento leg\u00edtimo del proveedor puede terminar marcando un pedido como pagado dos veces, o disparando una notificaci\u00f3n duplicada al cliente.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Eventos_de_webhook_que_necesitas_manejar\"><\/span>Eventos de webhook que necesitas manejar<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<table style=\"border-collapse: collapse; width: 100%; margin: 20px 0;\">\n<thead>\n<tr style=\"background-color: #1f3a5f; color: #ffffff;\">\n<th style=\"padding: 10px 12px; text-align: left; border: 1px solid #1F3A5F;\">Evento<\/th>\n<th style=\"padding: 10px 12px; text-align: left; border: 1px solid #1F3A5F;\">Cu\u00e1ndo se dispara<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">payment.pending<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">El cobro fue creado y espera el pago del cliente<\/td>\n<\/tr>\n<tr style=\"background-color: #eaf1f8;\">\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">payment.confirming<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">La transacci\u00f3n lleg\u00f3 a la red y est\u00e1 acumulando confirmaciones<\/td>\n<\/tr>\n<tr>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">payment.completed<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">El pago alcanz\u00f3 las confirmaciones necesarias y es definitivo<\/td>\n<\/tr>\n<tr style=\"background-color: #eaf1f8;\">\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">payment.expired<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">El cliente no complet\u00f3 el pago dentro del tiempo definido<\/td>\n<\/tr>\n<tr>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">payout.sent<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Un pago saliente fue transmitido a la red<\/td>\n<\/tr>\n<tr style=\"background-color: #eaf1f8;\">\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">payout.failed<\/td>\n<td style=\"padding: 10px 12px; border: 1px solid #dddddd;\">Un pago saliente no pudo completarse, por ejemplo por direcci\u00f3n inv\u00e1lida<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>El punto que m\u00e1s equipos subestiman al integrar por primera vez es el estado intermedio, <code>payment.confirming<\/code>. Marcar un pedido como pagado apenas se detecta la transacci\u00f3n en la red, sin esperar las confirmaciones necesarias, expone al negocio a fraude si la transacci\u00f3n llegara a revertirse antes de confirmarse por completo. El n\u00famero de confirmaciones necesarias var\u00eda por red: menos en redes r\u00e1pidas como Polygon, m\u00e1s en Ethereum para montos altos.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"SDKs_y_compatibilidad\"><\/span>SDKs y compatibilidad<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Una API RESTful bien documentada, con JSON como formato est\u00e1ndar de request y respuesta, no obliga a usar un SDK espec\u00edfico. Sin embargo, la mayor\u00eda de equipos prefieren un cliente oficial para los lenguajes m\u00e1s comunes en fintech, Node.js, Python, PHP y Java, porque maneja autom\u00e1ticamente la firma de requests, el reintento con backoff y el parseo de errores, en lugar de reimplementar esa l\u00f3gica desde cero. Si tu stack usa un lenguaje sin SDK oficial, la integraci\u00f3n directa v\u00eda HTTP sigue siendo viable, simplemente exige implementar t\u00fa mismo la verificaci\u00f3n de firma y el manejo de reintentos descritos arriba.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Casos_de_uso_tecnicos\"><\/span>Casos de uso t\u00e9cnicos<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<h3>Checkout de ecommerce<\/h3>\n<p>Se genera un cobro por cada carrito al momento del pago, con expiraci\u00f3n corta, t\u00edpicamente 15 a 30 minutos, y el frontend escucha el webhook <code>payment.completed<\/code> para redirigir al cliente a la confirmaci\u00f3n del pedido sin que tenga que refrescar la p\u00e1gina manualmente.<\/p>\n<h3>Facturaci\u00f3n recurrente para SaaS<\/h3>\n<p>En lugar de un cobro \u00fanico, se genera una direcci\u00f3n de pago reutilizable o un cobro programado por ciclo de facturaci\u00f3n, con reconciliaci\u00f3n autom\u00e1tica contra el ID de cliente en el sistema de suscripciones.<\/p>\n<h3>Dispersi\u00f3n de pagos a proveedores o freelancers<\/h3>\n<p>Aqu\u00ed el flujo se invierte: en lugar de recibir pagos, la API se usa para enviar, v\u00eda <code>\/v1\/payouts\/batch<\/code>. Un lote de pagos permite despachar varias transferencias en una sola llamada, cada una con su propia referencia, \u00fatil para n\u00f3mina o pagos a un lote de proveedores el mismo d\u00eda.<\/p>\n<h3>Marketplaces con split de pagos<\/h3>\n<p>Un cobro \u00fanico se distribuye autom\u00e1ticamente entre la plataforma y el vendedor seg\u00fan un porcentaje configurado, evitando que el marketplace tenga que operar una segunda transferencia manual despu\u00e9s de cada venta.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Checklist_antes_de_pasar_a_produccion\"><\/span>Checklist antes de pasar a producci\u00f3n<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<ul>\n<li>La verificaci\u00f3n de firma HMAC est\u00e1 implementada y probada con una firma inv\u00e1lida a prop\u00f3sito, para confirmar que se rechaza.<\/li>\n<li>El endpoint de webhook responde 200 en menos de 5 segundos, y el procesamiento pesado corre de forma as\u00edncrona en una cola.<\/li>\n<li>Los IDs de evento procesados se guardan en base de datos, para descartar duplicados antes de mutar estado.<\/li>\n<li>El manejo de reintentos en tu propio c\u00f3digo distingue entre errores 4xx, que no se reintentan, y errores 429 o 5xx, que s\u00ed.<\/li>\n<li>El estado <code>payment.confirming<\/code> est\u00e1 manejado expl\u00edcitamente, sin dar el pago por v\u00e1lido antes de <code>payment.completed<\/code>.<\/li>\n<li>Existe un endpoint o proceso de reconciliaci\u00f3n que compara peri\u00f3dicamente el estado local contra <code>GET \/v1\/payments<\/code>, por si alg\u00fan webhook se perdiera.<\/li>\n<li>Las claves de API de producci\u00f3n y de entorno de pruebas est\u00e1n separadas y ninguna est\u00e1 expuesta en el frontend ni en el control de versiones.<\/li>\n<\/ul>\n<h2><span class=\"ez-toc-section\" id=\"Entorno_de_pruebas\"><\/span>Entorno de pruebas<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Antes de integrar en producci\u00f3n, cualquier equipo debe poder probar el flujo completo en un entorno sandbox, con una red de pruebas que simula confirmaciones sin mover fondos reales. Esto permite validar el manejo de cada evento de webhook, incluyendo los casos l\u00edmite como expiraci\u00f3n o montos insuficientes, sin arriesgar capital real durante el desarrollo.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Base_regulatoria_detras_de_la_infraestructura\"><\/span>Base regulatoria detr\u00e1s de la infraestructura<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Una API de pagos con stablecoin no opera en zona gris si el proveedor detr\u00e1s est\u00e1 correctamente registrado. En Per\u00fa, eso significa estar inscrito como <strong>Proveedor de Servicios de Activos Virtuales (PSAV)<\/strong> ante la SBS, bajo el Decreto Supremo N.\u00b0006-2023-JUS. Fluyez opera bajo ese registro, con seis a\u00f1os de operaci\u00f3n en el mercado peruano y presencia en cinco pa\u00edses de la regi\u00f3n, lo que da a cualquier integraci\u00f3n t\u00e9cnica una base verificable antes de mover dinero real.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Preguntas_frecuentes\"><\/span>Preguntas frecuentes<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<h3>\u00bfQu\u00e9 red conviene usar para pagos frecuentes de monto bajo?<\/h3>\n<p>TRON o Polygon, por su fee de red m\u00ednimo comparado con Ethereum, donde el costo de gas puede ser desproporcionado frente a transacciones peque\u00f1as.<\/p>\n<h3>\u00bfC\u00f3mo evito procesar un pago que despu\u00e9s se revierte?<\/h3>\n<p>Esperando el n\u00famero de confirmaciones que la red recomienda antes de marcar la transacci\u00f3n como definitiva, y manejando el estado intermedio <code>payment.confirming<\/code> en tu backend en lugar de dar por v\u00e1lido el pago apenas se detecta en la red.<\/p>\n<h3>\u00bfQu\u00e9 errores debo reintentar autom\u00e1ticamente?<\/h3>\n<p>Solo 429 (rate limit) y errores 5xx, siempre con backoff exponencial. Los errores 4xx indican un problema en el request que reintentar sin corregir no resuelve, y puede generar operaciones duplicadas.<\/p>\n<h3>\u00bfC\u00f3mo evito procesar el mismo webhook dos veces?<\/h3>\n<p>Guardando el ID de cada evento procesado en base de datos y descartando cualquier evento con un ID ya registrado antes de ejecutar cambios de estado, independientemente de cu\u00e1ntas veces llegue.<\/p>\n<h3>\u00bfPuedo probar la integraci\u00f3n sin usar fondos reales?<\/h3>\n<p>S\u00ed, un entorno sandbox con red de pruebas permite validar todo el flujo, incluida la firma de webhooks y los casos de expiraci\u00f3n, antes de pasar a producci\u00f3n.<\/p>\n<h3>\u00bfLa API sirve tambi\u00e9n para enviar pagos, no solo para recibir?<\/h3>\n<p>S\u00ed, mediante <code>\/v1\/payouts<\/code> y <code>\/v1\/payouts\/batch<\/code> para dispersi\u00f3n de pagos, n\u00f3mina internacional o pagos a proveedores en lote.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Conclusion\"><\/span>Conclusi\u00f3n<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>La diferencia entre una integraci\u00f3n de pagos con stablecoin que funciona bien en producci\u00f3n y una que genera incidentes no est\u00e1 en qu\u00e9 tan r\u00e1pido se implementa, est\u00e1 en tres decisiones concretas: verificar la firma de cada webhook antes de confiar en \u00e9l, tratar cada evento como potencialmente duplicado, y reintentar solo los errores que tiene sentido reintentar. La arquitectura descrita aqu\u00ed, creaci\u00f3n del cobro, confirmaci\u00f3n en cadena y notificaci\u00f3n as\u00edncrona con reintentos controlados, es el patr\u00f3n que sostiene la mayor\u00eda de integraciones de pago confiables en producci\u00f3n hoy, no solo en cripto.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>TL;DR: Una API de pagos con stablecoin confiable en producci\u00f3n se sostiene en tres decisiones t\u00e9cnicas: verificaci\u00f3n de firma HMAC [&hellip;]<\/p>\n","protected":false},"author":10,"featured_media":13062,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"rank_math_title":"API de pagos con stablecoin: documentaci\u00f3n y casos de uso","rank_math_description":"Arquitectura, endpoints, c\u00f3digos de error, HMAC, reintentos de webhook y patrones de integraci\u00f3n de una API de pagos con stablecoin.","rank_math_focus_keyword":"API de pagos con stablecoin:","option_page_subtitle":"","option_page_pilar":"0","footnotes":""},"categories":[83,81],"tags":[],"class_list":["post-13061","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cripto-activos","category-guias-cripto"],"acf":[],"_links":{"self":[{"href":"https:\/\/fluyez.com\/blog\/wp-json\/wp\/v2\/posts\/13061","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fluyez.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fluyez.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fluyez.com\/blog\/wp-json\/wp\/v2\/users\/10"}],"replies":[{"embeddable":true,"href":"https:\/\/fluyez.com\/blog\/wp-json\/wp\/v2\/comments?post=13061"}],"version-history":[{"count":1,"href":"https:\/\/fluyez.com\/blog\/wp-json\/wp\/v2\/posts\/13061\/revisions"}],"predecessor-version":[{"id":13063,"href":"https:\/\/fluyez.com\/blog\/wp-json\/wp\/v2\/posts\/13061\/revisions\/13063"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/fluyez.com\/blog\/wp-json\/wp\/v2\/media\/13062"}],"wp:attachment":[{"href":"https:\/\/fluyez.com\/blog\/wp-json\/wp\/v2\/media?parent=13061"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fluyez.com\/blog\/wp-json\/wp\/v2\/categories?post=13061"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fluyez.com\/blog\/wp-json\/wp\/v2\/tags?post=13061"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}