Menu

Topic 7 of 8

Integrating Third Party APIs

Learn Integrating Third Party APIs for free with explanations, exercises, and a quick test (for Backend Engineer).

Published: January 20, 2026 | Updated: January 20, 2026

Who this is for

Backend and platform engineers building services that call external providers (payments, messaging, maps, auth, data) from microservices or monoliths.

Prerequisites

  • Comfortable with HTTP/HTTPS, JSON, and REST concepts
  • Basic experience with an HTTP client in your language (e.g., fetch/requests/HttpClient)
  • Familiar with environment variables and secure secret storage

Why this matters

Real teams rely on third-party APIs to move faster: payments, email/SMS, identity, search, maps, and analytics. Your service must call these APIs safely and reliably. You will be asked to:

  • Design a resilient API client with timeouts, retries, and backoff
  • Handle rate limiting, idempotency, and pagination
  • Verify and process webhooks
  • Securely store and rotate API keys/OAuth tokens
  • Observe and debug integrations using logs, metrics, and correlation IDs

Concept explained simply

Integrating a third-party API means your service acts as a polite, careful caller to someone else’s system. You send requests, handle their responses and errors, and protect your users and your system from surprises.

Mental model

Think of it as driving on someone else’s road:

  • Speed limits: rate limits and quotas
  • Traffic rules: authentication and request formats
  • Road conditions: failures and latency spikes
  • Maps: documentation and versioning

Your job is to drive defensively: plan for detours (retries), don’t tailgate (timeouts), keep a log of the trip (observability), and avoid doing the same trip twice by mistake (idempotency).

Key building blocks

1) Authentication

  • API keys: Send in header; store securely; rotate regularly.
  • OAuth2 Client Credentials: Obtain token, cache until expiry, refresh when needed. Never expose secrets to clients.
  • Signing: Some APIs require HMAC signatures of the request. Compute using shared secret and include provided headers.

2) Requests that fail safely

  • Timeouts: Set a strict connect and read timeout. Keep them lower than your upstream SLA and lower than your own client-facing timeout.
  • Retries with exponential backoff + jitter: Retry only idempotent operations or POSTs with idempotency keys. Respect Retry-After headers.
  • Circuit breaker: Temporarily stop calls after consecutive failures; probe periodically to recover.

3) Pagination and filtering

  • Cursor-based pagination is safer than offsets when data changes during pagination.
  • Always bound page size; stop when next cursor is empty.

4) Idempotency

  • Idempotency key: A unique key per logical operation (e.g., create charge). Reuse the key on retry so the provider creates at most one resource.
  • Store mapping of key to outcome to ensure consistent local behavior.

5) Rate limiting

  • Detect 429 or specific headers (e.g., X-RateLimit-Remaining).
  • Back off until window resets; honor Retry-After when present.
  • Use client-side token bucket to smooth bursts.

6) Webhooks and event handling

  • Verify signatures using shared secret; reject if invalid.
  • Respond 2xx quickly; enqueue heavy work asynchronously.
  • Handle duplicates and out-of-order events; design idempotent handlers.

7) Caching

  • Cache stable reads (e.g., geocoding) by normalized key with TTL.
  • Invalidate or bypass cache when correctness matters more than speed.

8) Observability

  • Log: correlation ID, method, path (no sensitive data), status, latency, attempt number.
  • Metrics: success/error rate, p95 latency, rate-limit hits, token refreshes.
  • Traces: include external span with service.name and endpoint attributes.

9) Security checklist

  • Store secrets in a secure vault; never in code or client apps.
  • Rotate credentials; use least privilege scopes.
  • Validate and sanitize all inputs/outputs; limit logged data.

Worked examples

Example 1: Create a payment charge with idempotency and retries

  1. Generate an idempotency key per checkout (e.g., UUID linked to order).
  2. POST /charges with key in header; set 2s connect, 5s read timeout.
  3. On 5xx or network error: retry up to 3 times with exponential backoff + jitter; reuse the same idempotency key.
  4. On 409/duplicate: treat as success; fetch the charge by idempotency key reference if needed.
  5. On 429: honor Retry-After; back off and retry if within business SLA.
Minimal pseudocode
function createCharge(orderId, amountCents, cardToken) {
  const idemKey = getOrCreateIdemKey(orderId)
  const req = { amount: amountCents, source: cardToken, currency: "USD" }
  return retryWithBackoff({max:3, baseMs:200, jitter:true}, (attempt) =>
    http.post("/charges", req, {
      headers: { "Idempotency-Key": idemKey, "Authorization": token() },
      timeout: { connect: 2000, read: 5000 }
    }).then(res => {
      if (res.status === 201) return res.json
      if (res.status === 409) return fetchByIdemKey(idemKey)
      if (res.status === 429) throw retryAfterError(res.headers["retry-after"]) 
      if (res.status >= 500) throw transientError()
      throw fatalError(res)
    })
  )
}

Example 2: Geocode addresses with read-through cache

  1. Normalize address string (trim, casefold, collapse whitespace).
  2. Check cache by normalized key; return if hit.
  3. GET /geocode?q=... with small timeout; retry only on timeouts/5xx.
  4. Cache success result with TTL 7 days; include provider version in cache key to avoid stale formats.
Minimal pseudocode
function geocode(address) {
  const key = cacheKey(normalize(address))
  const cached = cache.get(key)
  if (cached) return cached
  const res = retryTransient(() => http.get("/geocode", { q: address }, { timeoutMs: 3000 }))
  if (res.status === 200) {
    cache.set(key, res.json, { ttlSec: 604800 })
    return res.json
  }
  if (res.status === 404) return null
  throw mapError(res)
}

Example 3: Verify and process webhooks safely

  1. Read signature header and timestamp.
  2. Compute HMAC of timestamp + payload using shared secret; compare using constant-time equality.
  3. Return 2xx quickly and enqueue job for processing.
  4. Ensure handler is idempotent (e.g., ignore if eventId seen before).
Minimal pseudocode
function webhookHandler(req) {
  const sig = req.headers["X-Signature"]
  const ts = req.headers["X-Timestamp"]
  if (!verifyHmac(ts, req.rawBody, sig, secret())) return respond(400)
  enqueue({ id: req.body.id, type: req.body.type, data: req.body })
  return respond(200)
}

function processJob(job) {
  if (seen(job.id)) return
  switch (job.type) {
    case "charge.succeeded": markPaid(job.data.orderId); break
    default: log("Unhandled", job.type)
  }
  remember(job.id)
}

Exercises and practice tasks

Do these hands-on tasks. They mirror the exercises below and include quick checks.

  • Exercise 1: Build a resilient GET wrapper with timeouts, retries, and jittered backoff. Return standardized errors.
  • Exercise 2: Implement an idempotent POST client for creating orders with an Idempotency-Key header and duplicate-safe handling.

Readiness checklist

  • I set connect/read timeouts and know why they differ.
  • I retry only safe operations or use idempotency keys for unsafe ones.
  • I back off on 429 and respect Retry-After.
  • I can verify webhooks and process them idempotently.
  • I log correlation IDs and avoid sensitive data in logs.

Common mistakes and how to self-check

  • No timeouts: Risk of thread/connection exhaustion. Self-check: Intentionally blackhole the endpoint; does your call return quickly with a clear error?
  • Retrying unsafe POSTs: Can create duplicates. Self-check: Disconnect network after sending request; on retry, is only one resource created?
  • Ignoring rate limits: Leads to bans or cascading failures. Self-check: Simulate burst traffic; do you back off and recover gracefully?
  • Not verifying webhooks: Anyone could spoof events. Self-check: Send a request with invalid signature; is it rejected?
  • Logging secrets/PII: Security risk. Self-check: Search logs for tokens, emails, card data; none should appear.

Practical projects

Project 1: Email sender microservice
  • POST /send-email -> calls provider with API key
  • Timeouts: connect 1s, read 3s; retry 3x on 5xx/timeout
  • Log correlation-id, status, latency; no email bodies
  • Expose /health including circuit state
Project 2: Address verifier with cache
  • GET /verify?address=...
  • Normalize, cache read-through (TTL 7d)
  • Cursor pagination for bulk verify job
  • Metrics: cache hit rate, upstream latency
Project 3: Payment webhook consumer
  • Verify HMAC signature
  • Idempotent event handling with event store
  • Async processing; respond 200 within 200ms
  • Dead letter queue on repeated failures

Learning path

  • Before this: HTTP fundamentals, secure secret management.
  • Now: Third-party API integration patterns (you are here).
  • Next: Service-to-service communication, message queues, and saga patterns for multi-step workflows.

Next steps

  • Harden your client: add circuit breaker metrics and dashboards.
  • Document your retry/timeout policy and share it with your team.
  • Implement a sandbox vs production switch with separate credentials and safe defaults.

Mini challenge

Your service imports 1M records from a partner API with a limit of 100 requests/min and cursor pagination. Design a fetcher that:

  • Uses cursor pagination and page size 500
  • Honors 429 with Retry-After
  • Persists last successful cursor to resume after restart
  • Logs progress every 10k records and exposes a metric
Hint

Implement a loop: fetch -> process -> persist cursor; throttle using a token bucket and sleep until window reset when 429 occurs.

Quick test

Take the quick test to check your understanding. Available to everyone; only logged-in users have progress saved.

Practice Exercises

2 exercises to complete

Instructions

Create a function getJson(url, params) that:

  • Sets connect timeout 1s and read timeout 3s
  • Retries up to 3 times on timeouts, 5xx, and network errors
  • Uses exponential backoff with jitter (base 200ms)
  • Returns a standardized result: { ok: true, data } or { ok: false, code, message }
  • Never retries on 4xx (except 408)

Mini task: Add a correlationId parameter that is logged on each attempt.

Expected Output
Calling an unreliable endpoint sometimes returns ok: true with JSON data after 1–3 attempts, and on persistent failure returns ok: false with a clear error code (e.g., ECONN, ETIMEDOUT, HTTP_502). Logs show attempt number, correlationId, status, and latency.

Integrating Third Party APIs — Quick Test

Test your knowledge with 8 questions. Pass with 70% or higher.

8 questions70% to pass

Have questions about Integrating Third Party APIs?

AI Assistant

Ask questions about this tool