Integrations Basics
8 examples to get you started with third-party integrations for Node.js APIs - 6 basic and 2 intermediate.
Search across all documentation pages
8 examples to get you started with third-party integrations for Node.js APIs - 6 basic and 2 intermediate.
npm install stripe got
npm install -D typescript@5.6 tsxSee Stripe, Twilio & SDK Patterns for vendor-specific detail.
// Bad: route calls SDK
app.post("/checkout", async (req, res) => {
const stripe = new Stripe(process.env.STRIPE_KEY!);
const pi = await stripe.paymentIntents.create({ amount: 1000, currency: "usd" });
res.json(pi);
});
// Good: route calls integration service
app.post("/checkout", async (req, res) => {
const result = await paymentsService.createIntent(req.body);
res.status(201).json(result);
});Related: Use Cases & Services
// src/integrations/stripe-client.ts
import Stripe from "stripe";
let stripe: Stripe | null = null;
export function getStripe() {
if (!stripe) {
stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: "2024-11-20.acacia",
timeout: 10_000,
maxNetworkRetries: 0, // you own retry policy
});
}
return stripe;
}timeout - SDK defaults may be too long for HTTP request budgetexport async function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
const ac = new AbortController();
const timer = setTimeout(() => ac.abort(), ms);
try {
return await Promise.race([
promise,
new Promise<T>((_, reject) => {
ac.signal.addEventListener("abort", () => reject(new Error("timeout")));
}),
]);
} finally {
clearTimeout(timer);
}
}export function mapStripeError(err: unknown): AppError {
if (err instanceof Stripe.errors.StripeCardError) {
return new AppError("card_declined", 402, { code: err.code });
}
if (err instanceof Stripe.errors.StripeAPIError) {
return new AppError("payment_provider_unavailable", 503);
}
return new AppError("internal", 500);
}logger.info({
msg: "stripe_request",
requestId: req.headers["x-request-id"],
operation: "paymentIntents.create",
idempotencyKey: key,
});const key = process.env.NODE_ENV === "production"
? process.env.STRIPE_LIVE_KEY!
: process.env.STRIPE_TEST_KEY!;import got from "got";
const client = got.extend({
prefixUrl: "https://api.partner.com/v1/",
timeout: { request: 8_000 },
headers: { Authorization: `Bearer ${process.env.PARTNER_TOKEN}` },
});
export async function fetchPartnerStatus(id: string) {
return client.get(`status/${id}`).json<PartnerStatus>();
}got retries and hooks documented in Retry & Outbound ResilienceOutbound: your API -> Stripe API (create payment)
Inbound: Stripe -> your webhook (payment succeeded)
Official SDK when available (Stripe, Twilio, AWS). Raw HTTP for small REST partners with OpenAPI client generation.
Service module tests with HTTP mock (nock, MSW) or vendor test mode.
Yes for hard dependencies in request path - see Circuit Breakers.
Prefer async queue when user does not need synchronous result (email, PDF gen).
Stripe Connect or per-tenant API key map - never global key for connected accounts without design.
Wrap in injectable service; same timeout and error mapping rules.
Pin major SDK versions; read vendor changelog before bump.
Redact authorization headers in Pino serializers.
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.
Reviewed by Chris St. John·Last updated Jul 16, 2026