Skip to content
Integrations

3rd-party APIs — overview

The universal pattern for calling external services from your FlareX app — Secrets, fetch, retries, rate limits, and error handling.

Updated

Most apps eventually need to talk to something else — Stripe for payments, OpenAI for AI, Google for spreadsheets, your CRM, your analytics provider. The pattern is the same regardless of which service:

  1. Get an API key from the provider's dashboard.
  2. Add it to Secrets in FlareX (encrypted at rest).
  3. Tell FlareX what to do with it.
  4. Handle failure modes (rate limits, transient errors, bad data).

This page covers steps 2–4. Steps 1 and 3 depend on the service — see the per-service walkthroughs at the bottom of this page.

Note

The phrase "3rd-party API" here means HTTP APIs — REST or RPC. SDK libraries (Stripe Node SDK, the official OpenAI client, etc.) are wrappers around these APIs and follow the same pattern.

Step 1: Add the credential to Secrets

  1. Get the credential from the provider

    Sign in to the provider's dashboard, find the API keys section, and create a new key. Copy it once — most providers only show it on creation.

    For production apps, name the key something specific so you can revoke it later: e.g., flarex-prod-2026-04-25 rather than key-1.

  2. Open Secrets in your FlareX app

    Panel → your app → Secrets.

  3. Add the secret

    Pick a clear name. Conventions:

    • STRIPE_SECRET_KEY for Stripe
    • OPENAI_API_KEY for OpenAI
    • ANTHROPIC_API_KEY for Anthropic
    • <SERVICE>_API_KEY for everything else

    Paste the value and save. The plaintext is encrypted to the workspace's encryption key and never shown again.

See Secrets for the full lifecycle — rotation, scoping, deletion.

Step 2: Tell FlareX to use it

Describe the integration in chat. FlareX writes the fetch wrapper, picks a sensible client library if one exists, and adds error handling.

Add a Stripe integration. Use STRIPE_SECRET_KEY from Secrets.
On POST /checkout, create a Checkout Session for $9.99 USD and return
the session URL.
Wire in OpenAI. Use OPENAI_API_KEY from Secrets.
Add a /summarize endpoint that takes { text: string } and returns
{ summary: string } using gpt-4o-mini.

Step 3: Handle the failure modes

Production calls to 3rd-party APIs fail. Often. Plan for it.

Transient errors → retry with backoff

Network blips, 502s, 503s, and 5xx errors are usually transient. Retry with exponential backoff and a cap:

async function fetchWithRetry(url: string, init: RequestInit, max = 3) {
  for (let attempt = 0; attempt < max; attempt++) {
    const res = await fetch(url, init);
    if (res.ok) return res;
    if (res.status >= 500 && attempt < max - 1) {
      const delay = Math.min(1000 * 2 ** attempt, 8000);
      await new Promise((r) => setTimeout(r, delay));
      continue;
    }
    return res;
  }
  throw new Error('unreachable');
}

Ask FlareX to use this pattern; it will.

Rate limits → respect the headers

Most modern APIs return Retry-After (seconds) or X-RateLimit-Reset (timestamp) when they throttle you. Sleep until then before retrying.

if (res.status === 429) {
  const after = Number(res.headers.get('retry-after') ?? 1);
  await new Promise((r) => setTimeout(r, after * 1000));
  // retry once
}

Bad data → validate at the boundary

The API claims to return JSON shaped like X. Sometimes it doesn't. Use Zod or a similar validator at the API boundary so a bad response surfaces as a clear error rather than a cannot read property 'foo' of undefined 200ms later:

const ProfileSchema = z.object({
  id: z.string(),
  email: z.string().email(),
  plan: z.enum(['free', 'pro']),
});
const profile = ProfileSchema.parse(await res.json());

Timeout

Default fetch in Node has no timeout. Always set one:

const ctrl = new AbortController();
const timeout = setTimeout(() => ctrl.abort(), 10_000);
try {
  const res = await fetch(url, { signal: ctrl.signal, ...init });
} finally {
  clearTimeout(timeout);
}

Step 4: Cache when you can

Hitting an external API on every page load is slow and counts against rate limits. Cache by the smallest sensible key:

import { LRUCache } from 'lru-cache';
const cache = new LRUCache<string, T>({ max: 500, ttl: 60_000 });

async function getProfile(userId: string) {
  const hit = cache.get(userId);
  if (hit) return hit;
  const fresh = await fetchProfile(userId);
  cache.set(userId, fresh);
  return fresh;
}

For data shared across requests, cache in Redis (auto-injected as REDIS_URL on paid plans):

const cached = await redis.get(`profile:${userId}`);
if (cached) return JSON.parse(cached);
const fresh = await fetchProfile(userId);
await redis.setex(`profile:${userId}`, 300, JSON.stringify(fresh));
return fresh;

SSRF safety

If your app calls URLs provided by users (image proxies, link previews, webhook tests), be careful: a user-supplied URL pointing at http://169.254.169.254/ or http://localhost:6379/ can read your cloud metadata or your Redis.

FlareX's shared safe-dispatcher re-verifies resolved IPs against private/loopback/link-local ranges and refuses outbound connections to them. Ask for it explicitly:

For the link-preview endpoint, fetch the user-provided URL using the
SSRF-safe dispatcher pattern — block private IPs, loopback,
link-local, and metadata endpoints. Cap the response size at 2 MB.

Per-service walkthroughs

Common integrations with worked examples:

  • Stripe — Checkout, subscriptions, webhooks
  • OpenAI/v1/chat/completions, streaming, retries
  • Google APIs — OAuth, Sheets, Calendar
  • Discord webhooks — incoming Discord webhooks (separate from bots)

If you don't see your provider, the patterns above apply to all of them. Tell FlareX the service, your auth scheme, and what you want to do.

What's next

  • OAuth — when an API requires per-user auth, not a single API key
  • Webhooks — receiving inbound calls from a 3rd party
  • Secrets — rotation, deletion, security model
3rd-party APIs — overview · FlareX