Patrones de Stripe, Twilio y SDK
Stripe y Twilio son los SDK de pago más comunes en las API B2B de Node. Esta página cubre los tiempos de espera, la idempotencia, los modos de prueba y el emparejamiento de webhooks.
Busca en todas las páginas de la documentación
Stripe y Twilio son los SDK de pago más comunes en las API B2B de Node. Esta página cubre los tiempos de espera, la idempotencia, los modos de prueba y el emparejamiento de webhooks.
Tarjeta de receta de referencia rápida: lista para copiar y pegar.
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: "2024-11-20.acacia",
timeout: 10_000,
maxNetworkRetries: 0,
});
const intent = await stripe.paymentIntents.create(
{ amount: 2500, currency: "usd", automatic_payment_methods: { enabled: true } },
{ idempotencyKey: req.header("Idempotency-Key") ?? undefined }
);Cuándo usarlo:
// src/integrations/payments-service.ts
import Stripe from "stripe";
import twilio from "twilio";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: "2024-11-20.acacia",
timeout: 10_000,
maxNetworkRetries: 0,
});
const twilioClient = twilio(process.env.TWILIO_ACCOUNT_SID!, process.env.TWILIO_AUTH_TOKEN!);
export async function createPaymentIntent(
amountCents: number,
currency: string,
idempotencyKey: string
) {
return stripe.paymentIntents.create(
{ amount: amountCents, currency, automatic_payment_methods: { enabled: true } },
{ idempotencyKey }
);
}
export async function sendOtpSms(to: string, code: string) {
return twilioClient.messages.create({
to,
from: process.env.TWILIO_FROM_NUMBER!,
body: `Your code is ${code}`,
statusCallback: `${process.env.PUBLIC_API_URL}/webhooks/twilio/sms`,
});
}
// Ruta de Express
app.post("/payments/intent", async (req, res, next) => {
try {
const key = req.header("Idempotency-Key");
if (!key) return res.status(400).json({ error: "missing_idempotency_key" });
const pi = await createPaymentIntent(req.body.amountCents, "usd", key);
res.status(201).json({ clientSecret: pi.client_secret, id: pi.id });
} catch (err) {
next(mapStripeError(err));
}
});Qué demuestra esto:
| Operación | Patrón |
|---|---|
| Cargo único | PaymentIntent |
| Facturación SaaS | Cliente + Suscripción + Precios |
| Mercado de Connect | Encabezado stripeAccount en las solicitudes |
| Reembolsos | Idempotente en la creación de refund con clave |
// Recuperar con expand - usar con moderación
const sub = await stripe.subscriptions.retrieve(id, { expand: ["customer", "latest_invoice"] });payment_intent.succeeded, invoice.paid, customer.subscription.updatedevent.id - ver Verificación de Webhook// Verificar al llamante en la entrada - webhook TwiML
app.post("/voice/inbound", express.urlencoded({ extended: false }), (req, res) => {
const twiml = new twilio.twiml.VoiceResponse();
twiml.say("Hello");
res.type("text/xml").send(twiml.toString());
});# Tarjeta de prueba de Stripe 4242 4242 4242 4242
STRIPE_SECRET_KEY=sk_test_...
# Números mágicos de Twilio para prueba de SMSidempotencyKey al habilitar maxNetworkRetries del SDKclient_secret - fuga de pago en los registros. Solución: registrar solo el ID del intento de pago.apiVersion en el código.| Alternativa | Usar cuándo | No usar cuándo |
|---|---|---|
| Paddle/Lemon Squeezy | Comerciante registrado | Mercado de Connect personalizado |
| MessageBird/Vonage | Precios/características de Twilio | Ya estandarizado en Twilio |
| Adyen/Braintree | Mezcla de pagos empresariales | El equipo conoce Stripe |
| Resend + OTP por correo electrónico | Solo códigos de correo electrónico | Se requiere entrega de SMS |
Checkout alojado más rápido en el alcance de PCI. Elements UI personalizada - sigue usando PaymentIntent en el lado del servidor.
La API de Verify maneja el ciclo de vida de OTP - menos código SMS personalizado que la API de Messages sin procesar.
API de Account Links para cuentas conectadas Express/Standard - manejadores de webhook separados.
PaymentIntent capture_method: manual para autorización y luego capturar una cantidad menor más tarde.
No asumas el orden. Usa una máquina de estados idempotente en el estado del intento de pago.
Stripe maneja el flujo 3DS en el lado del cliente; escucha los eventos requires_action.
Poner en cola los envíos de SMS; retroceso exponencial en 429; el servicio de mensajería ayuda al enrutamiento.
Buen patrón: la API encola, el worker llama a Stripe para cumplir después del webhook.
Stripe envía tipos; los tipos de Twilio incluidos - fijar versiones para consistencia.
Comunidad @nestjs/stripe o un servicio de envoltura delgado - mismas reglas de idempotencia.
Versiones de la pila: Esta página fue escrita para Node.js 24.18.0 (LTS Activo), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 y NestJS 11.
Revisado por Chris St. John·Última actualización: 16 jul 2026