From c36858eddd0017c6d42379f8e7174fdb4b74aa0e Mon Sep 17 00:00:00 2001 From: Viktor Date: Sun, 10 May 2026 18:21:37 +0000 Subject: [PATCH] x402: flip gateway live with Viktor's wallet + Slack payment notifications Wires the traefik stack to read two new fields from secret/viktor: * x402_wallet_address -> 0xCc33BD250d39752e0ceaB616f8a05F72274a659f * alertmanager_slack_api_url (existing) -> reused as the per-payment notification webhook so payment events arrive in the same Slack channel as other infra alerts. Gateway now runs `wallet_set:true, dry_run:false`. Verified end-to-end: - Browser UA on all 9 sites -> 200 (passes through to Anubis) - python-requests/2.31 + scrapy + ClaudeBot UA -> 402 with PaymentRequiredResponse, payTo == Viktor's wallet, amount=10000 micro-USDC, network=base, asset=Base USDC contract - Direct Slack-webhook test from inside cluster -> HTTP 200 Image bumped to forgejo.../x402-gateway:d9b83125 with Slack-format notification payload (text=..., username=x402-gateway, icon_emoji=:moneybag:; auxiliary fields preserved for richer receivers). Notifications fire on every successful X-PAYMENT validation; failures on Slack webhook are logged at WARN, never block the request, never double-charge the bot. --- stacks/traefik/main.tf | 11 +++++++++++ stacks/traefik/modules/traefik/main.tf | 15 ++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/stacks/traefik/main.tf b/stacks/traefik/main.tf index c87cba71..7bb68f97 100644 --- a/stacks/traefik/main.tf +++ b/stacks/traefik/main.tf @@ -6,6 +6,13 @@ data "vault_kv_secret_v2" "secrets" { name = "platform" } +# x402 wallet lives under secret/viktor (Viktor's personal config) — not +# secret/platform — and is the only field this stack needs from there. +data "vault_kv_secret_v2" "viktor" { + mount = "secret" + name = "viktor" +} + module "traefik" { source = "./modules/traefik" tier = local.tiers.core @@ -13,4 +20,8 @@ module "traefik" { redis_host = var.redis_host tls_secret_name = var.tls_secret_name auth_fallback_htpasswd = data.vault_kv_secret_v2.secrets.data["auth_fallback_htpasswd"] + x402_wallet_address = lookup(data.vault_kv_secret_v2.viktor.data, "x402_wallet_address", "") + # Reuses the existing Alertmanager Slack incoming webhook — same channel as + # other infra alerts. Payment events arrive as a normal Slack message. + x402_notify_webhook_url = lookup(data.vault_kv_secret_v2.viktor.data, "alertmanager_slack_api_url", "") } diff --git a/stacks/traefik/modules/traefik/main.tf b/stacks/traefik/modules/traefik/main.tf index 8ee65407..c386ca7e 100644 --- a/stacks/traefik/modules/traefik/main.tf +++ b/stacks/traefik/modules/traefik/main.tf @@ -15,6 +15,12 @@ variable "x402_wallet_address" { default = "" description = "EVM wallet (Base mainnet, 0x…) that receives USDC from x402 payments. Empty = DRY_RUN, gateway always returns 200 to forwardAuth so traffic is unaffected." } +variable "x402_notify_webhook_url" { + type = string + default = "" + description = "Slack-compatible incoming-webhook URL the gateway POSTs to on every successful payment. Empty = no notifications." + sensitive = true +} resource "kubernetes_namespace" "traefik" { metadata { @@ -508,7 +514,7 @@ resource "kubernetes_deployment" "x402_gateway" { } container { name = "x402-gateway" - image = "forgejo.viktorbarzin.me/viktor/x402-gateway:f4804d62" + image = "forgejo.viktorbarzin.me/viktor/x402-gateway:d9b83125" port { name = "http" container_port = 8923 @@ -549,6 +555,13 @@ resource "kubernetes_deployment" "x402_gateway" { name = "FACILITATOR_URL" value = "https://x402.org/facilitator" } + # Slack incoming-webhook for real-time payment notifications. + # Reuses the existing Alertmanager channel — payment events appear + # alongside infra alerts. Reads from secret/viktor.alertmanager_slack_api_url. + env { + name = "NOTIFY_WEBHOOK_URL" + value = var.x402_notify_webhook_url + } resources { requests = { cpu = "10m"