How to Cut Your API Costs in Half with Batch Processing
Most API bills have a simple shape: the number of requests times the price per request. You can't do much about the price, but you can choose how you send the requests. With DataGuru's batch processing, the same requests to the same endpoints cost 50% of the normal price, provided you don't need each answer the moment you ask for it.
This guide covers how batch pricing works, when it's worth using, and how to move an existing workload over to it with a CSV file and a few lines of code.
Why batch requests cost half as much
A live API call has to be answered right away. Capacity has to be there for every request at the moment it arrives, including the busy moments.
A batch doesn't have that constraint. You upload a CSV in which every row is one request to an endpoint. DataGuru puts the rows on a separate low-priority queue and runs them on spare capacity, oldest batch first, while live traffic keeps priority. Since your batch fills in the quiet gaps, you're charged half for each row.
What you give up is speed. Small files finish within 24 hours, with one extra day per 10,000 rows and 7 days at most. In practice rows start running as soon as there is room, and you can download partial results at any point while the batch is running.
The numbers
The discount is applied to each endpoint's normal price. Here are a few current per-request prices compared with the batch price for each row:
| Endpoint | Live price / request | Batch price / row | 10,000 requests live | 10,000 rows in a batch |
|---|---|---|---|---|
| Amazon Product Search | $0.0012 | $0.0006 | $12.00 | $6.00 |
| Walmart Product Details | $0.0018 | $0.0009 | $18.00 | $9.00 |
| Google Search | $0.0022 | $0.0011 | $22.00 | $11.00 |
| Etsy Product Details | $0.0032 | $0.0016 | $32.00 | $16.00 |
| Google Shopping | $0.0050 | $0.0025 | $50.00 | $25.00 |
| PDF to JSON | $0.02 | $0.01 | $200.00 | $100.00 |
Prices as of November 2026. Every endpoint's current price is listed on its page in the API catalogue.
Take a team that refreshes 50,000 Walmart product pages every week for price monitoring. Sent as live requests, that costs $90 a week. Sent as a weekly batch, it costs $45. Nothing changes except how the requests are submitted, and over a year the saving is $2,340.
Two more billing details work in your favour:
- Failed rows are free. You pay only for rows that succeed. The money held for a failed row goes back to your balance.
- Rows that never run are refunded. If you stop a batch, or it reaches its deadline, every row that hadn't started is refunded.
When batch is the right choice
Batch suits any job where the data is needed in hours rather than seconds. Some common cases:
- Catalogue and price refreshes: re-checking thousands of product pages on Amazon, Walmart, Target, eBay or Etsy every night or every week.
- Keyword and SERP tracking: running the same list of Google searches on a schedule.
- Lead and company enrichment: looking up a list of companies or profiles once.
- Backfills: collecting history for a new dashboard, model or research project.
- Document processing: parsing a folder of PDFs or resumes at the end of the day.
Keep live requests for anything a user is waiting on, such as a search box, a checkout flow or an agent that needs the answer before its next step. Many teams use both: live calls for the interactive part of their product and a nightly batch for everything else.
How to send a batch
1. Build the CSV
The header row lists the endpoint's parameter names, exactly as they appear in its Request Parameters table. Each row after that is one request. Optional columns can be left out or left empty, in which case the parameter's default is used.
query,limit
airpods,3
lego star wars,2
stanley cup,
A file can hold up to 100,000 rows and 25 MB. Every row is checked before anything is charged. If a row is invalid, for example a required value is missing or a column name is unknown, the whole file is rejected with the line numbers of the problems, so a typo can't cost you anything.
If you'd rather not write code, open the endpoint in the Playground, choose Upload file, and download the CSV template it generates for you.
2. Upload it
POST the file to the endpoint's normal path with ?batch=true added. Uploads always use POST, even for endpoints you normally call with GET.
curl -X POST "https://api.dataguru.cc/api/v1/target/products/search?batch=true" \
-H "Authorization: Api-Key YOUR_API_KEY" \
-F "file=@queries.csv"
The response is 202 Accepted with a batch_id, the batch price for each row, and a deadline_at by which every row will have run.
3. Wait, then download
Check the batch every few minutes, or wait for the dashboard notification that tells you it has finished. Once finished is true, download results.json. Each row in it contains the same payload a single request to that endpoint would have returned.
import time
import requests
API = "https://api.dataguru.cc/api/v1"
HEADERS = {"Authorization": "Api-Key YOUR_API_KEY"}
# Submit the file
with open("queries.csv", "rb") as f:
batch = requests.post(
f"{API}/target/products/search",
params={"batch": "true"},
headers=HEADERS,
files={"file": ("queries.csv", f, "text/csv")},
).json()
batch_id = batch["batch_id"]
print("Row price:", batch["billing"]["row_price_usd"], "deadline:", batch["deadline_at"])
# Check every five minutes until no row is pending or running
while True:
status = requests.get(f"{API}/batches/{batch_id}/", headers=HEADERS).json()
print(status["status"], status["rows"])
if status["finished"]:
break
time.sleep(300)
# One object per input row, in file order
results = requests.get(f"{API}/batches/{batch_id}/results.json", headers=HEADERS).json()
for row in results:
if row["status"] == "COMPLETED":
print(row["input"], "->", row["data"])
There are two other download formats: results.jsonl (one JSON object per line, which is easier to stream for very large batches) and results.csv (your input columns plus status, error, cost and latency for each row).
Batches larger than your balance
You don't need to top up for the whole file before you upload it. Funds are held 500 rows at a time, in file order, and an upload is accepted as long as your balance covers a single row.
If your balance runs out partway through, the batch pauses with the status WAITING_FOR_FUNDS and you get a notification. Rows that are already running finish, and the deadline stops counting down. Add funds and the batch picks up again within about a minute, with the paused time added to its deadline. You can also stop a batch at any time with POST /api/v1/batches/{batch_id}/cancel/, and every row that hasn't started is refunded.
Good to know
- Batch processing is available to accounts billed in USD.
- Each batch targets one endpoint. To cover several endpoints, upload one file for each.
- For endpoints priced per record, each row holds up to 100 records and you're charged half price for the records actually returned.
- Results are kept for 30 days after the batch deadline.
- Batches you upload through the API and through the Playground both appear on the Requests page, where you can track progress, download results and inspect individual rows.
Start saving
Look through your current usage for jobs that run on a schedule or that nobody is waiting on. Each one can be moved to a batch and its cost cut in half. Start with the Batch Processing guide for the full reference, including every status and error code, or open any endpoint in the Playground and upload your first file.