Skip to main content
Insyrge - Zoho CRM & Business Automation Consulting
← Back to All ArticlesAI & Business Automation

Zoho CRM Bulk Read API: Export Large Modules

How Bulk Read jobs work, their documented limits and how to size the pipeline that loads exported CSV files into your database.

•Manav Sharma
Zoho CRM Bulk Read API: Export Large Modules

Use the Zoho CRM Bulk Read API to export large modules in a few calls. Learn its limits, when to use it and a worked Contacts-to-PostgreSQL load.

Exporting a large Zoho CRM module through the standard Get Records API means thousands of calls, careful pagination and a steady drain on your API credits. For backups, analytics loads, migrations and periodic reconciliations, there is a better tool. The Zoho CRM Bulk Read API runs an export as a background job and hands you a compressed CSV file when it is done, so a few calls can replace thousands. This guide explains how the Bulk Read API works, its documented limits, when to use it instead of other options, how to size the infrastructure that processes its output, and a worked example that streams an export into PostgreSQL.

How the Zoho CRM Bulk Read API works

Zoho's Bulk Read overview describes a three-step process:

  1. Create a bulk read job by posting the module, the fields you want and optional filter criteria. The response contains a job ID.
  2. Wait for the job to finish. Either provide a callback URL that Zoho notifies when the job completes, or poll the job status.
  3. Download the result from the download URL in the completed job's response. It is a ZIP file containing a CSV, or an ICS file for the Events module.

Because the work happens asynchronously on Zoho's side, your system is not tied up waiting on long-running requests.

Documented limits worth knowing

According to Zoho's Bulk Read limitations page and related documentation:

LimitValueRecords per export jobUp to 200,000Fetching beyond 200,000Set page to 2, 3 and so on, or use the next_page_token from the job status responseMaximum page value500Result formatZIP containing a CSV, or ICS for EventsCredits to create a job50, according to Zoho's API limits documentation

Limits change over time, so check the current documentation when designing a job.

When to use Bulk Read, and when not to

NeedBest optionWhyA handful of records, or one record by IDGet RecordsSimple and immediateFiltered queries up to tens of thousands of recordsCOQLFlexible criteria and joins through lookups; supports pagination up to 100,000 records per criteriaFull or large exports for backup, analytics or migrationBulk ReadOne job per 200,000 records, delivered as a fileChanges since the last syncGet Records with If-Modified-Since, or COQL on Modified_TimeSmaller and more frequent than a full export

A common pattern combines them: a weekly or nightly Bulk Read for a full snapshot, and frequent delta syncs in between.

Sizing the infrastructure around Bulk Read

The export is the easy part. Processing it reliably needs some planning:

  • Storage: keep downloaded ZIP files in object storage with a retention policy, so you can reload or audit a snapshot
  • Processing: stream CSV rows rather than loading the whole file into memory, especially for wide modules
  • Database loading: use bulk loading methods such as PostgreSQL's COPY into a staging table, then merge into the main tables
  • Scheduling: stagger jobs across modules and run them outside business hours, so large exports do not compete with live integrations for credits
  • Callbacks: if you use callbacks, expose an endpoint that verifies the request and queues the job ID for processing; if not, poll at a sensible interval

Worked example: export Contacts and load them into PostgreSQL

The illustrative script below creates a Bulk Read job for Contacts, polls until it completes, downloads the ZIP and streams the CSV into a PostgreSQL staging table with COPY. The token function and connection details are placeholders.

import io, time, zipfile, requests, psycopg

API = "https://www.zohoapis.com"            # use the api_domain from your token response
HEADERS = lambda: {"Authorization": f"Zoho-oauthtoken {get_access_token()}"}

def create_job(module, fields):
    body = {"query": {"module": {"api_name": module}, "fields": fields, "page": 1}}
    r = requests.post(f"{API}/crm/bulk/v8/read", json=body, headers=HEADERS(), timeout=60)
    r.raise_for_status()
    return r.json()["data"][0]["details"]["id"]

def wait_for(job_id, interval=30, max_wait=3600):
    waited = 0
    while waited < max_wait:
        r = requests.get(f"{API}/crm/bulk/v8/read/{job_id}", headers=HEADERS(), timeout=60)
        job = r.json()["data"][0]
        if job["state"] == "COMPLETED":
            return job["result"]
        if job["state"] not in ("ADDED", "IN PROGRESS"):
            raise RuntimeError(f"Bulk read {job_id} ended in state {job['state']}")
        time.sleep(interval); waited += interval
    raise TimeoutError(job_id)

def load(job_id, conn):
    r = requests.get(f"{API}/crm/bulk/v8/read/{job_id}/result", headers=HEADERS(), timeout=300)
    r.raise_for_status()
    with zipfile.ZipFile(io.BytesIO(r.content)) as z, conn.cursor() as cur:
        name = z.namelist()[0]
        with z.open(name) as f, cur.copy("COPY stage_contacts FROM STDIN WITH (FORMAT csv, HEADER true)") as cp:
            for chunk in iter(lambda: f.read(1 << 20), b""):
                cp.write(chunk)
    conn.commit()

job = create_job("Contacts", ["Last_Name", "First_Name", "Email", "Account_Name", "Modified_Time"])
result = wait_for(job)
with psycopg.connect("dbname=crm_mirror") as conn:
    load(job, conn)
print("Loaded page", result["page"], "more records:", result.get("more_records"))

The staging table's columns must match the exported fields in order, with an id column first, because Zoho adds the record ID to every export. Check the response structure against the current documentation; this sketch omits retries, logging and the follow-up job when more_records is true.

Handling large modules

For modules with more than 200,000 records, read more_records and next_page_token from the completed job and create the next job with the page token. Process each page as it arrives rather than waiting for all of them. Record which pages have loaded, so an interrupted run can resume without starting over.

Data quality checks after each load

  • Compare the record count in the file with the count reported by the job
  • Check for unexpected empty columns, which often signal a renamed or removed field
  • Confirm date-time values parse correctly; Zoho exports them in ISO 8601 format
  • Merge from staging into main tables in a transaction, so a failed load leaves the previous data intact

Choosing fields deliberately

Exporting every field is tempting but makes files larger and loads slower, and it copies data you may not need into another system. List the fields each downstream use actually requires, include Modified_Time for change tracking, and review the list when the CRM layout changes.

Security considerations

Exports contain your customer data in a portable file. Use a dedicated integration user with read access only to the modules needed, store files encrypted with restricted access, delete them when the retention period ends, and log every export job. Treat the download URL and the access token as sensitive.

Cost and credit planning

Bulk Read is efficient, but each job still costs credits. Combine fields into one job per module rather than several narrow jobs, schedule full exports only as often as the use case needs, and use delta syncs for frequent updates. Watch overall credit consumption after adding new export jobs, because credits are shared with every other integration in your organisation.

Monitoring export jobs

Record each job's ID, module, start and finish times, record count and outcome. Alert when a job fails, takes much longer than usual or returns far fewer records than the previous run. A sudden drop in exported records often means a filter changed or permissions were altered, and catching it early prevents downstream reports from silently going wrong.

Bulk Read is one part of managing credits wisely; our guide to Zoho CRM API limits covers the wider picture. For the write side, our guide to Zoho CRM mass update compares the options for large updates.

Frequently Asked Questions

How many records can the Zoho CRM Bulk Read API export?

Up to 200,000 records per job, according to Zoho's documentation. Larger modules are exported over several jobs using the page value or a page token.

Is Bulk Read faster than Get Records?

For large exports, yes, in terms of calls and credits. The job runs asynchronously, so it suits backups and data loads rather than real-time lookups.

What format does Bulk Read return?

A ZIP file containing a CSV, or an ICS file for the Events module.

Can we export only changed records with Bulk Read?

You can add criteria, such as a modified-time filter, to a job. For frequent small updates, Get Records with If-Modified-Since or COQL is usually more efficient.

Plan your data exports with us

We design export and sync pipelines around the Zoho CRM Bulk Read API, sized for your data and credit budget. See our CRM and API integration services, or talk to us about your data pipeline.

About the Author

Manav Sharma is the founder of Insyrge and a CRM solutions architect. He works across Zoho, Salesforce, HubSpot, Odoo and more, designing the CRM setups, integrations and automations that keep sales and operations teams working from the same data.

Need Help Implementing This in Your Business?

Our certified Zoho consultants and automation experts can help you design and deploy custom workflows tailored to your operations.

Book Free Consultation