Skip to content
API Ingestion14 MIN READ · UPDATED MAY 2026

What is API Data Ingestion?

The complete guide to API data ingestion — cursor pagination, rate-limit handling, OAuth 2.0 token refresh, watermark-based incremental sync, idempotent writes, and webhook vs polling patterns.

By AI-DE Data Foundations Team·Reviewed MAY 2026
Quick answer

API data ingestion is pulling data from external APIs into your data platform reliably and efficiently. The challenge is not the HTTP call — it is handling everything that goes wrong at scale: pagination across millions of records, rate limits that throttle your pipeline, tokens that expire mid-run, schemas that change without notice, and extracting only new data on incremental runs. Learn it at /learn/api-integration or build a real pipeline with /projects/api-data-ingestion.

What is API data ingestion?

Most production data does not live in databases you can directly query — it lives behind APIs. Salesforce CRM records, Stripe payment events, GitHub repository data, Shopify orders, weather feeds, financial market data — all delivered via REST or GraphQL APIs with authentication, pagination, and rate limits.

API data ingestion is the engineering discipline of extracting this data systematically: fetching pages, handling errors, refreshing credentials, tracking what you have already ingested, and writing results idempotently to your warehouse or lake. Done well, it runs unattended for months. Done poorly, it fills your warehouse with duplicates or silently stops ingesting when a token expires.

The core loop is the same for every API: authenticate, fetch a page, validate the response, write to storage, advance the cursor, repeat. The complexity hides in the failure modes — 429s, schema drift, OAuth expiry, partial pages, network blips — and the production patterns that absorb them.

SKILL · API-INGESTION

Master API ingestion in 6 hours, hands-on.

From cursor pagination and OAuth refresh to schema validation, dead-letter queues, and watermark-based incremental sync against a real production API.

Why does API ingestion matter?

  • 80% of business data lives behind APIs, not in databases you can query directly
  • The hard part is not the HTTP call — it is reliability at scale (rate limits, token refresh, schema drift)
  • Bad ingestion silently corrupts downstream marts; good ingestion is invisible
  • Incremental extraction with watermarks turns a 6-hour full refresh into a 3-minute delta
  • Idempotent writes survive network failures, retries, and replay without creating duplicates
  • The patterns are reusable — once you have a Stripe connector pattern, you have a Shopify, Salesforce, and HubSpot pattern

How does API ingestion work?

A production ingestion job runs the same loop for every connector:

  1. Authenticate — load credentials (API key or refreshed OAuth token), inject into headers
  2. Fetch page — call the API with the current cursor + watermark parameters
  3. Validate schema — parse the response into a typed model (Pydantic); route unexpected shapes to a DLQ
  4. Upsert to lake — write records with a deterministic key so replays do not duplicate
  5. Advance cursor — persist the new cursor + max-watermark for the next run
  6. Loop or exit — repeat until the API signals no more pages

Here is the rate-limit-aware fetch with exponential backoff:

import httpx, time, random
from pydantic import BaseModel

class OrderRecord(BaseModel):
    order_id: str
    amount_usd: float
    created_at: str
    status: str

def fetch_all_orders(since: str) -> list[OrderRecord]:
    records, cursor = [], None
    while True:
        resp = fetch_page_with_backoff(since=since, cursor=cursor)
        records += [OrderRecord(**r) for r in resp["data"]]
        cursor = resp.get("next_cursor")
        if not cursor:
            break
    return records

def fetch_page_with_backoff(**params) -> dict:
    for attempt in range(5):
        r = httpx.get(API_URL, params=params, headers=auth_headers())
        if r.status_code == 429:
            wait = (2 ** attempt) + random.random()
            time.sleep(wait)  # exponential backoff + jitter
            continue
        r.raise_for_status()
        return r.json()

For long-running jobs against OAuth 2.0 APIs, you also need automatic token refresh — a 401 mid-run should trigger a re-auth, not a pipeline failure.

Polling vs webhook vs CDC

DimensionPollingWebhookCDC via API
LatencyPolling intervalNear-real-timeNear-real-time
BackfillYes — paginate historyNo — push onlyDepends on retention
API quota costHigh — full scansLow — event-drivenLow — changes only
Reliability modelSelf-managed retryRequires ack + retryDepends on source
ComplexityLowMediumMedium-High
Inbound connectionNot requiredRequired (public endpoint)Not required

The right answer is usually both. Use webhooks for low-latency change capture and a nightly polling job for backfill + reconciliation. Stripe's events API is the canonical example — push for immediate handling, pull for completeness.

The 6 core challenges of production API ingestion

Every production connector eventually hits the same six problems. The patterns that solve them are well-known:

  • Pagination — APIs return data in pages. Cursor-based is most reliable; offset breaks under concurrent inserts. Always prefer cursor or keyset for production.
  • Rate limiting — every API has a quota. Handle 429s with exponential backoff + jitter. Proactively track the request budget with a token bucket.
  • Authentication refresh — OAuth 2.0 access tokens expire. Build automatic refresh into your HTTP client so long-running jobs do not die on a mid-run 401.
  • Schema changes — external APIs change response shapes without notice. Validate against a Pydantic schema and route unexpected fields to a staging area instead of failing hard.
  • Incremental extraction — full refresh is expensive and wasteful. Use watermark columns (updated_at) and the API's since/after parameters to fetch only new or changed records.
  • Idempotent writes — network failures mean your pipeline may replay the same response. Write with UPSERT or deduplication keys so replays do not create duplicate rows.
PROJECT · API-DATA-INGESTION

Build a real API ingestion pipeline end-to-end.

Cursor pagination, OAuth refresh, 429 backoff, Pydantic validation, DLQ routing, watermark-based incremental sync, and idempotent UPSERTs. Mentor-reviewed.

Common mistakes (and what to do instead)

  • Full refresh on every run — re-fetching the entire dataset wastes quota, increases run time, and can exhaust rate limits. Use watermark-based incremental from day one.
  • No backoff on 429 responses — retrying immediately burns through your remaining quota and makes the throttle worse. Always implement exponential backoff with jitter.
  • Ignoring schema validation — external APIs are uncontrolled surfaces. A silent field rename can corrupt downstream tables for weeks. Validate every response on ingestion.
  • Storing raw JSON blobs without normalization — JSON in a warehouse makes downstream queries painful and expensive. Flatten to typed columns at ingestion time.
  • Hardcoded credentials — API keys in code leak through git history. Always pull credentials from a secrets manager (AWS Secrets Manager, Vault, 1Password).
  • No dead-letter queue — when a record fails validation, dropping it loses data; failing the run loses everything. A DLQ + alert lets the pipeline keep flowing while you triage.

Who is API ingestion for?

API ingestion is a foundational data engineering skill. Every modern data team owns at least a handful of API connectors, and the level of mastery scales with seniority:

  • Junior data engineer — makes authenticated HTTP requests, handles basic pagination, uses Airbyte or Singer connectors, understands REST vs GraphQL
  • Senior data engineer — builds rate-limit-aware ingestion with backoff, implements watermark-based incremental sync, validates schemas with Pydantic, designs idempotent write strategies
  • Staff / platform engineer — designs multi-source ingestion platforms, defines connector standards across teams, architects webhook fan-out at scale, manages API credential rotation and security

Teams that benefit most: SaaS-heavy data stacks (Stripe + Salesforce + HubSpot + Shopify), marketing analytics (every ad platform is an API), platform teams building internal ingestion frameworks, and any team where Airbyte/Fivetran is too expensive at volume.

Frequently asked questions

API data ingestion is the process of systematically pulling data from external or internal REST/GraphQL APIs and loading it into a data warehouse, data lake, or streaming pipeline. It involves authentication (API keys, OAuth 2.0), pagination (cursor-based, offset, keyset), rate limit handling (exponential backoff, token buckets), incremental extraction (watermarks, since parameters), and error recovery (idempotent writes, dead-letter queues).
REST API ingestion pulls fixed resource endpoints — each endpoint returns a predefined shape, and you may need multiple calls to join related resources. GraphQL API ingestion sends a query specifying exactly which fields you need, reducing over-fetching and sometimes replacing multiple REST calls with one. For ingestion pipelines, REST is simpler to paginate predictably; GraphQL is better when you need selective fields from deeply nested resources.
Cursor-based pagination uses an opaque token (the cursor) returned by the API to fetch the next page, rather than a numeric offset. The cursor typically encodes the position in a sorted result set. Cursor pagination is stable under inserts — if new records are added between page requests, cursor pagination continues from where it left off without skipping or duplicating records. It is the preferred pagination pattern for production ingestion pipelines.
Rate limit handling strategies: (1) Exponential backoff with jitter — when you receive a 429, wait 2^n + random seconds before retrying. (2) Token bucket rate limiter — track request counts against the API's limit and sleep proactively before hitting the cap. (3) Respect Retry-After headers — some APIs tell you exactly how long to wait. (4) Parallelize across accounts — if you have multiple API credentials, fan out requests across them to multiply effective throughput.
Use webhooks when the API supports them and you need near-real-time data (sub-minute latency), the volume of changes is small relative to the total dataset, or the API provider charges per request. Use polling when the API does not support webhooks, you need historical backfill, or you cannot receive inbound connections due to firewall restrictions.
What to do next

Start shipping.

Three steps from a guide to a job-ready portfolio. Pick one and start now — the rest will follow.

Start the api-ingestion skillFREE TIER · NO CREDIT CARD
Press Cmd+K to open