Overview
The Bulk API processes many Amazon inputs asynchronously. You submit one POST request with groups of inputs, Easyparser processes each input in the background, notifies your callback_url, and you fetch the parsed results from the Data Service.
How it works
Submit a bulk job
Send a POST request to the Bulk Service with a JSON array of groups. Each group sets the
platform,operation,domain,callback_urland apayloadwith the input values (for exampleasins,keywordsorurls).Store the result IDs
The response returns immediately. For every accepted input value it contains a result
idindata.accepted[].results[]. Processing continues in the background.Receive the webhook
When a query finishes, Easyparser sends a POST request to the group's
callback_url. The body is the query record with alinksarray that points to the parsed result. It does not contain the parsed data.Fetch the results
Call the Data Service with each result
id(or follow the result link from the webhook) to get the parsed JSON. You can also open each result in the web app: on the Bulk Requests page, open the job and select the result icon of an item.
When to use the Bulk API
- Collect data for thousands of ASINs, keywords or sellers in one submission.
- Run scheduled jobs such as daily price, offer or ranking snapshots.
- Process inputs where you do not need the answer in the same HTTP response.
To get data immediately in a single synchronous call, use the Real-Time API.
Endpoints and authentication
| Service | Method and URL | Purpose |
|---|---|---|
| Bulk Service | POST https://bulk.easyparser.com/v1/bulk | Submit a bulk job |
| Data Service | GET https://data.easyparser.com/v1/queries/{id} | Get the query record, including its status |
| Data Service | GET https://data.easyparser.com/v1/queries/{id}/results?format=json | Get the query record with the parsed JSON result (no raw HTML) |
Both services authenticate with your API key in the api-key header. The Authorization: Bearer header is not supported. Send Content-Type: application/json when you submit a job.
You find your API key in the web app under Account > Plan at https://app.easyparser.com/account/plan. New accounts get 100 free credits per month, with no credit card required. For a visual walkthrough, see Getting Started.
Identifiers
A bulk job returns three kinds of IDs. Only the result id is used to fetch data.
| Identifier | Where it appears | What it identifies |
|---|---|---|
bulk_request_id | meta_data.bulk_request_id | The whole submission. Use it to find the job on the Bulk Requests page of the web app. |
group_id | data.accepted[].group_id | One group (one object in the request array). |
id | data.accepted[].results[].id | One query (one input value). Pass it to the Data Service. |
Example flow
Submit the job
This request runs the Search operation (SEARCH) on .ca for two search result URLs.
curl --location 'https://bulk.easyparser.com/v1/bulk' \--header 'api-key: YOUR_API_KEY' \--header 'Content-Type: application/json' \--data '[ { "platform": "AMZ", "operation": "SEARCH", "domain": ".ca", "callback_url": "https://example.com/webhook", "payload": { "urls": [ "https://www.amazon.ca/s?k=mouse", "https://www.amazon.ca/s?k=table+tennis" ] } }]'Read the result IDs
The response lists one result id per accepted input value (abbreviated):
{ "success": true, "meta_data": { "bulk_request_id": "01a0341d-c6a8-722b-9189-2f2ee09608ef", "total_count": 2, "accepted_count": 2, "invalid_count": 0, "insufficient_credit_count": 0, "failed_count": 0, "rate_limit_exceeded_count": 0 }, "data": { "accepted": [ { "platform": "AMZ", "operation": "SEARCH", "domain": ".ca", "callback_url": "https://example.com/webhook", "group_id": "01a0341d-c6be-7ccb-b916-49e17627b560", "results": [ { "url": "https://www.amazon.ca/s?k=mouse", "id": "250f8e2a-7614-40b3-9a40-def192b74810", "credit": 1 }, { "url": "https://www.amazon.ca/s?k=table+tennis", "id": "cd4b5677-c8a7-47e1-91a1-966bc448e0e8", "credit": 1 } ] } ] }}Wait for the webhook
Easyparser sends a webhook to https://example.com/webhook for each query when it finishes. See Webhooks.
Fetch each result
curl --location 'https://data.easyparser.com/v1/queries/250f8e2a-7614-40b3-9a40-def192b74810/results?format=json' \--header 'api-key: YOUR_API_KEY'format supports only json. To check whether a query is still pending or has ended as success or failure, call GET https://data.easyparser.com/v1/queries/{id} instead. The result structure for each operation is described in Data Service Response.
Webhooks
Delivery and retries
- Easyparser sends one webhook per query (result
id), not one per job, to thecallback_urlof the query's group. - The body is the query record. Its
linksarray contains the URL of the parsed result, so you can follow that link instead of building the URL from theid. - Your endpoint must respond with HTTP
200within 3 seconds. Otherwise the delivery is retried once, 5 minutes later. If the second attempt also fails, Easyparser stops trying. In the webhook logs the second attempt showsretry_count2. - If 10 or more deliveries fail within one hour, Easyparser notifies you by e-mail so you can check that your endpoint is reachable.
- You can resend failed webhooks, one at a time or all failed ones of a job, from the job's webhook logs on the Bulk Requests page of the web app. A manual resend is a single attempt with no automatic retry.
The webhook is a notification only. Queries are processed whether or not the webhook is delivered, so you can always fetch results with the IDs from the submit response.
Verify the signature
Each webhook includes an X-Easyparser-Signature header: a hex-encoded HMAC-SHA256 of the raw request body, keyed with your API key. Verification is optional, but recommended for production endpoints.
- Take the raw request body exactly as received.
- Compute an HMAC-SHA256 of it with your API key as the secret, as a hex string.
- Compare the result with the
X-Easyparser-Signatureheader using a constant-time comparison. If they match, the request came from Easyparser.
import hmacimport hashlib
def verify_signature(raw_body: bytes, signature_header: str, api_key: str) -> bool: # raw_body must be the exact bytes received, not a re-serialized dict expected = hmac.new( api_key.encode("utf-8"), raw_body, hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, signature_header or "")const crypto = require("crypto");
function verifySignature(rawBody, signatureHeader, apiKey) { // rawBody must be the exact Buffer or string received, not a re-serialized object const expected = Buffer.from( crypto.createHmac("sha256", apiKey).update(rawBody).digest("hex") ); const received = Buffer.from(signatureHeader || "");
// timingSafeEqual throws if the lengths differ return expected.length === received.length && crypto.timingSafeEqual(expected, received);}Limits and data retention
- A single bulk request accepts up to 5,000 input values, counted across all groups. If you send more, the values that fit are processed and the rest are returned in
data.invalid. - Each query has a processing timeout of 5 minutes. A query that does not finish in time ends with status
failure. - Inputs count against your plan's Bulk API per-minute limit, measured in credits (
minutely_bulk_credit_limitin the Account API). Inputs above the limit are not accepted and are returned indata.rate_limit_exceeded; the rest of the request is still accepted. - Only supported platforms and operations are accepted. Input values that fail validation are returned in
data.invalidwith amessage. See Bulk Service Response. - Data Service retrieval is limited to your plan's per-minute Bulk limit plus 20% (for example, a 1,000 per minute Bulk limit allows 1,200 result retrievals per minute).
Credits
Each input value is charged with the same rules as the matching Real-Time API request, and only accepted inputs are charged. The Bulk API uses a single page per input value instead of min_page and max_page, so SEARCH, SELLER_PRODUCTS and SELLER_FEEDBACK inputs cost 1 credit per input value. Each accepted result carries its cost in credit. When your credits run out, inputs are accepted in order until the balance is used up and the rest are returned in data.insufficient_credit. See Credit Consumption.
Related
- Bulk Service Request: request body, payload fields per operation and examples
- Bulk Service Response: accepted, invalid and rejected items
- Data Service Request: fetching results by
id - Data Service Response: query record and result structure
- Credit Consumption