- lib/stripe.ts: createCheckoutSession acepta metadata; claimPaidCheckout la
recupera de la sesión Stripe y la devuelve.
- lib/paid-services.ts: config unificado con fulfill(character, meta) + extraFields.
gold -> UPDATE characters money (BD directa, no SOAP), transfer -> SOAP
.char changeaccount. Los 5 simples usan soapFulfill.
- checkout [service]: lee extraFields -> metadata, precio depende de metadata (gold),
valida precio>0. service-success llama cfg.fulfill(name, metadata).
- prices.ts: getTransferPrice, getGoldOptions/goldPriceFor (home_goldprice).
- GoldForm (personaje + cantidad) y TransferForm (personaje + destino); páginas
/gold y /transfer. Catálogos Paid.gold/transfer.
Verificado: /gold /transfer redirigen a login, checkout 401 sin sesión, home OK.
NOTA: transfer no valida aún el token de seguridad ni reglas AC (nivel>=55, DK).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- lib/stripe.ts: createCheckoutSession (crea sesión Stripe + StripeLog en
home_stripelog, success_url con {CHECKOUT_SESSION_ID}), isSessionPaid,
claimPaidCheckout (verifica pagado + no entregado, marca fulfilled -> evita
re-entregas; port de require_paid_stripe).
- lib/prices.ts: precios desde home_*price (rename/customize/race/faction/level).
- components/PaidServiceForm.tsx: selector + botón de pago -> redirige a la URL de
Checkout de Stripe (session.url, sin stripe.js).
- Rename: route /api/character/rename/checkout (guard + valida personaje + crea
checkout), página /rename (PaidServiceForm) y /rename/success (verifica pago y
ejecuta SOAP .char rename, i18n). STRIPE_* + NEXT_PUBLIC_STRIPE_PUBLIC_KEY en
.env.local. Namespace Rename.
Verificado: checkout sin sesión 401, /rename redirige a login, /rename/success con
session_id inválido no entrega el servicio (muestra error). Patrón para los demás
servicios de pago (cambiar precio + comando SOAP).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>