Gateway de acciones (reembolsos de Stripe)
Un agente de soporte que puede reembolsar a clientes es útil hasta que un mensaje en un ticket lo convence de reembolsar a alguien que nunca pagó. El gateway de acciones de Burnbound pone los reembolsos bajo la política de gasto del agente. Es un servicio pequeño que corres tú, junto a tus agentes, con tu clave de Stripe. El agente le pide un reembolso; el gateway lee el cargo real en Stripe, pregunta a Burnbound si la política del agente lo permite, reembolsa solo si lo permite y comunica el resultado. Burnbound nunca guarda tu clave de Stripe.
Cómo se decide un reembolso
- El agente llama a la herramienta MCP
stripe_refundcon un cargo (ch_…) o un payment intent (pi_…) y, para un reembolso parcial, un importe en unidades menores (céntimos). - El MCP lo envía a tu gateway con la clave de Burnbound del propio agente.
- El gateway lee el cargo en Stripe. La moneda, el cliente y lo que queda por reembolsar salen de Stripe, nunca del agente. Un importe mayor que lo reembolsable se rechaza.
- Burnbound decide con la política del agente, como en cualquier pago: método permitido, máximo por pago, tope diario, presupuestos de subequipo, tus reglas propias y el umbral de aprobación. Un reembolso es dinero que sale de la empresa, así que cuenta como gasto.
- Permitido: el gateway crea el reembolso en Stripe, con la clave de idempotencia de Stripe
bb_<id del intent>, y lo comunica. Denegado: no se reembolsa nada y el agente recibe el motivo. Por encima del umbral de aprobación: espera a una persona.
La misma idempotencyKey nunca reembolsa dos veces, aunque el agente lo pida otra vez después de hecho el reembolso.
Qué necesitas
- Una cuenta de Stripe. Empieza en modo de prueba, con un cargo de prueba que reembolsar.
- Un agente en Burnbound con su clave (
bb_agent_…) y@burnbound/mcp0.10.0 o posterior en tu cliente MCP:stripe_refundllega en la 0.10.0 y una versión anterior no tiene la herramienta. - Docker en la máquina que corre el gateway. El gateway se publica como imagen pública para amd64 y arm64; no necesitas el código de Burnbound.
Paso 1: Crea una clave restringida de Stripe
En Stripe, abre Desarrolladores → Claves de API → Crear clave restringida y dale solo:
| Recurso | Permiso |
|---|---|
| Charges | Lectura |
| Customers | Lectura |
| PaymentIntents | Lectura |
| Refunds | Escritura |
La lectura de Customers deja que las reglas usen la antigüedad del cliente. Sin ella, el gateway avisa una vez de que no puede leer clientes, y una regla sobre la antigüedad del cliente la trata como desconocida en cada reembolso.
Usa primero la clave del modo de prueba (rk_test_…). El gateway rechaza una clave live (sk_live_, rk_live_) salvo que pongas GATEWAY_ALLOW_LIVE=1. Una clave secreta completa funciona, pero no se recomienda. Guarda la clave en un fichero que solo pueda leer el gateway, por ejemplo stripe.key.
Paso 2: Crea la credencial del gateway en Burnbound
El gateway demuestra a Burnbound que es tu gateway. En el panel, en Organización, crea un gateway de acciones. Burnbound muestra su id y un secreto que empieza por bbgw_, una sola vez: copia los dos. El gateway firma cada llamada a Burnbound con ese secreto, así que una petición que no viene de tu gateway se rechaza aunque lleve una clave de agente válida. Guarda el secreto como una contraseña. Rotar da un secreto nuevo y deja el anterior válido 24 horas, para que cambies el gateway sin que falle ningún reembolso. Eso no basta si el secreto se filtra, porque el filtrado seguiría sirviendo esas 24 horas: usa Rotar sin periodo de gracia (el anterior deja de valer al momento y el gateway falla hasta que le pongas el nuevo), o Revocar el gateway y crea otro.
Paso 3: Arranca el gateway
Desde la carpeta donde está stripe.key:
docker run --rm -p <loopback address>:8787:8787 \
-v "$PWD/stripe.key:/run/secrets/stripe:ro" \
-e STRIPE_SECRET_KEY_FILE=/run/secrets/stripe \
-e BURNBOUND_GATEWAY_ID=<gateway id> \
-e BURNBOUND_GATEWAY_SECRET=bbgw_… \
ghcr.io/martinvarelaa/burnbound-action-gateway:0.1.0
Fija una versión, como arriba, en lugar de latest, para que una actualización llegue cuando tú decidas. <loopback address> es la dirección IPv4 de loopback de la propia máquina: así Docker publica el puerto solo para los procesos de esa máquina. El contenedor corre con un usuario sin privilegios y solo lleva un fichero empaquetado: ni código fuente ni node_modules. Dentro del contenedor escucha en el puerto 8787 (GATEWAY_PORT). Habla con https://app.burnbound.dev (BURNBOUND_API). Si apuntas BURNBOUND_API a una URL con ruta, como https://host/api, pon delante de la API un proxy que quite esa ruta y define GATEWAY_API_PATH_PREFIX_STRIPPED=1; sin eso el gateway no arranca. Déjalo en loopback o en una red privada: cualquiera que llegue a él con una de tus claves de agente puede pedir reembolsos. GET /healthz responde { "status": "ok" }. Sus logs llevan ids y códigos, nunca una clave.
Paso 4: Permite los reembolsos en el agente
En la página del agente en Burnbound:
- En Métodos de pago, activa Stripe · refund. Está apagado por defecto, en todos los agentes.
- Añade
stripe-refund.actiona los hosts permitidos: es el host de todos los reembolsos. - Fija el máximo por pago, el tope diario y, para los reembolsos que deba mirar una persona, el umbral de aprobación. Los reembolsos cuentan para ellos en USD; EUR, GBP y las demás monedas se convierten con el tipo diario del BCE, redondeando hacia arriba.
Paso 5: Apunta el MCP al gateway
Añade BURNBOUND_GATEWAY_URL al entorno del servidor MCP, junto a la clave del agente. En Claude Code:
claude mcp add burnbound --scope user -e BURNBOUND_KEY=bb_agent_… \
-e BURNBOUND_GATEWAY_URL=<gateway URL> -- npx -y @burnbound/mcp@latest
En una configuración MCP en JSON (Cursor, Claude Desktop):
{
"mcpServers": {
"burnbound": {
"command": "npx",
"args": ["-y", "@burnbound/mcp@latest"],
"env": {
"BURNBOUND_KEY": "bb_agent_…",
"BURNBOUND_GATEWAY_URL": "<gateway URL>"
}
}
}
}
<gateway URL> es donde escucha el gateway: http:// con la dirección de loopback y el puerto 8787 si corre en la misma máquina, https:// en cualquier otro caso; el MCP rechaza http:// hacia cualquier otro host. Sin ella, stripe_refund responde que el gateway no está configurado y no reembolsa nada. Después pídeselo al agente, por ejemplo: «Reembolsa 3 euros del cargo ch_… al cliente».
Cómo funcionan las aprobaciones
Un reembolso en el umbral de aprobación del agente o por encima no se ejecuta. stripe_refund devuelve pending_approval con un approvalId y una idempotencyKey, Burnbound te avisa (bandeja del panel, y Slack o email si los configuraste) y nada llega a Stripe. Una persona abre el reembolso en la bandeja de aprobaciones del panel y lo aprueba o lo deniega; el agente no puede aprobar su propio reembolso. Una vez aprobado, el agente llama otra vez a stripe_refund con los mismos argumentos y la misma idempotencyKey, y el gateway reembolsa una vez. Una aprobación denegada o caducada no se reintenta. Los plazos son los de las aprobaciones humanas.
Divisas
- USD siempre funciona. EUR, GBP y el resto de monedas que publica el Banco Central Europeo se convierten con su tipo del día (se actualiza cada hora y redondea hacia arriba). El reembolso de un cargo en una moneda sin tipo (por ejemplo KWD, salvo que el servidor fije uno en
FIAT_USD_RATES) se deniega concurrency_not_supportedy nada llega a Stripe. - Los decimales son los de Stripe, no los de ISO 4217:
amountMinorva en unidades menores de la moneda del cargo. 12,50 EUR es1250, 500 JPY es500, 1,500 KWD es1500(milésimas) y 5 ISK es500(Stripe cuenta ISK y UGX con dos decimales).stripe_refundresponde con lacurrency, losdecimalsy elamounten texto (12.50 EUR). - Las conversiones redondean hacia arriba al micro-dólar, para que un reembolso nunca parezca más pequeño ante los topes.
Límites conocidos
- Un reembolso cuyo resultado nunca llegó a Burnbound se queda en
submitted. Si Stripe hizo el reembolso pero el gateway no pudo comunicarlo (la API no respondía en ese momento),stripe_refundresponde igualmenterefundedconreported: false, y el intent se quedasubmitteden Burnbound: su importe sigue contando como gasto y no aparece como liquidado. Busca el reembolso en Stripe por su metadatoburnbound_intent. - Una sola acción por ahora: reembolsos de Stripe. Las siguientes usarán el mismo gateway y la misma política.
- Lo corres tú. Burnbound no aloja el gateway: tu clave de Stripe se queda en tu máquina.
- Tipos de cambio diarios. Las otras monedas usan el tipo de referencia del día del Banco Central Europeo, no el del mercado al minuto (ver Divisas, arriba).
Burnbound se configura en la guía de inicio. La misma política cubre la tarjeta de Stripe Issuing del agente y sus pagos x402 a las APIs del catálogo; todos los controles están en Cómo limitar el gasto de un agente de IA.