> For the complete documentation index, see [llms.txt](https://easyparser.gitbook.io/easyparser-documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://easyparser.gitbook.io/easyparser-documentation/bulk-integration/overview.md).

# Overview

The Bulk API is designed for processing multiple Amazon operations in a single request. Whether you need to run a search, fetch product details, or retrieve offers across different marketplaces, the Bulk API lets you submit batch jobs asynchronously and at scale.

This workflow is ideal for:

* Running **multi-product or multi-operation tasks** in a single API call
* Automating large-scale jobs such as **daily data collection, analytics, or product monitoring**
* **Reducing latency** and minimizing API overhead for heavy workloads

{% hint style="info" %}
A single bulk request can contain up to **5,000 items** and has a processing timeout of **5 minutes**.
{% endhint %}

{% hint style="info" %}

#### API Authentication

To use Easyparser features, you need a private **API key** to authenticate your requests.

You can quickly find your key under the **Account > Plan** section in your [Easyparser Dashboard](https://app.easyparser.com/account/plan). New accounts instantly receive 100 free credits upon signing up.

*If you need a step-by-step visual guide on how to locate and copy your token, please follow our* [*Getting Started Guide.*](/easyparser-documentation/getting-started.md)
{% endhint %}

### How the Bulk Flow Works

{% stepper %}
{% step %}
**Create a Bulk Job**

You send a JSON request containing your operations (e.g., `SEARCH`, `DETAIL`, `OFFER`) along with parameters like marketplace domain and product URLs/ASINs. You must also provide a `callback_url`, which Easyparser uses to notify you once your results are ready to retrieve.
{% endstep %}

{% step %}
**The job is processed asynchronously**

Once accepted, each input line generates a unique result ID. These IDs are returned to you immediately in the response, and the system processes the data in the background.
{% endstep %}

{% step %}
**You receive a webhook notification**

When processing is complete, Easyparser sends a webhook POST request to your `callback_url`. This notification confirms that the result IDs are ready to be retrieved, but it does not contain the full parsed data.

{% hint style="info" %}
The webhook does **not** contain the parsed data. It delivers the query record, including a `links` entry pointing to the parsed result. Use that link (or the result ID) to fetch the data from the Data Service.
{% endhint %}
{% endstep %}

{% step %}
**You fetch the final results**

Using the returned IDs, you can query the **Data Service API** to retrieve detailed structured data (in JSON or raw format) for each processed item.
{% endstep %}
{% endstepper %}

### Verifying and Receiving Webhooks

When a bulk job finishes, Easyparser notifies your `callback_url` with a webhook so you know the result IDs are ready to retrieve. Your endpoint must respond with HTTP `200` within **3 seconds** to confirm receipt. If it does not, the delivery is retried up to **2 more times at 5-minute intervals**. If 10 or more delivery failures occur within one hour, we notify you by email so you can check that your webhook server is reachable.

The webhook is a convenience notification, not the only way to get your results. The queries are processed regardless of webhook delivery, so you can always retrieve them with their IDs from the bulk response by polling the Data Service.

The webhook body is the query record, and its links array already contains the URL of the parsed result, so you can follow that link instead of building the results URL from the id.

**Verifying the Signature**

Each webhook is signed so you can confirm it came from Easyparser. The request includes an `X-Easyparser-Signature` header containing an HMAC-SHA256 signature of the raw request body, signed with your `api_key`.

Signature verification is optional. It lets you confirm a webhook genuinely came from Easyparser, which is recommended for production endpoints, but it is not required to use the results. If you skip it, the rest of the flow works exactly the same.

To verify it:

1. Take the **raw** request body exactly as received (do not re-serialize it).
2. Compute an HMAC-SHA256 of that raw body, using your `api_key` as the secret, with **hex** output.
3. Compare your result with the `X-Easyparser-Signature` header. If they match, the request is authentic.

{% hint style="warning" %}
Always use the raw, unparsed request body. Re-serializing the JSON (even without changing any values) can change the bytes and cause the signature to mismatch.
{% endhint %}

{% tabs %}
{% tab title="Python" %}
{% code overflow="wrap" %}

```python
import hmac
import 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)
```

{% endcode %}
{% endtab %}

{% tab title="Node.js" %}
{% code overflow="wrap" %}

```javascript
const crypto = require("crypto");

function verifySignature(rawBody, signatureHeader, apiKey) {
  // rawBody must be the exact bytes/string received, not a re-serialized object
  const expected = crypto
    .createHmac("sha256", apiKey)
    .update(rawBody)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signatureHeader)
  );
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Key Concepts

| Concept          | Description                                                                                                                                 |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `callback_url`   | Your endpoint that receives the query record when a result is ready. It does not include the parsed data, but it does include a link to it. |
| result ID        | A unique identifier for each processed item. Use it to fetch the parsed result from the Data Service.                                       |
| Data Service API | The endpoint you call with a result ID to retrieve the final structured Amazon data.                                                        |

### Example Flow

{% stepper %}
{% step %}
`POST https://bulk.easyparser.com/v1/bulk`  with:

{% code overflow="wrap" %}

```json
{
  "platform": "AMZ",
  "operation": "SEARCH",
  "domain": ".ca",
  "payload": {
    "urls": [
    "https://www.amazon.ca/s?k=mouse", "https://www.amazon.ca/s?k=table+tennis"
    ]
  },
  "callback_url": "https://yourdomain.com/webhook"
}

```

{% endcode %}
{% endstep %}

{% step %}
Response contains result `IDs`:

{% code overflow="wrap" %}

```json
{
  "data": {
    "accepted": [
      {
        "results": [
          { "link": "...", "id": "250f..." },
          { "link": "...", "id": "cd4b..." }
        ]
      }
    ]
  }
}
```

{% endcode %}
{% endstep %}

{% step %}
&#x20;Webhook hits your `callback_url` once the job is complete.

{% endstep %}

{% step %}
&#x20;Use each `id` to get results via:
{% endstep %}
{% endstepper %}

{% hint style="success" %}

> This structure fully decouples job creation from result consumption, which makes it ideal for asynchronous, large-scale data operations. The webhook only signals readiness, as the parsed data is always retrieved separately from the Data Service.

> For full details on the request/response format, see **Bulk Service** and **Data Service**.
> {% endhint %}

### Fetching Results

You can retrieve each result using the `id` via the Data Service:

{% code overflow="wrap" %}

```bash
curl --location 'https://data.easyparser.com/v1/queries/{id}/results?format=json' \
--header 'api-key: YOUR_API_KEY'
```

{% endcode %}

{% hint style="warning" %}
**Data Availability**

Completed bulk results are stored temporarily and can be retrieved for up to a maximum of **24 hours**. In some cases data may be removed earlier due to system operations or storage limits. We recommend retrieving and storing your results on your side as soon as they become available, as availability beyond this window cannot be guaranteed.
{% endhint %}

### Notes

* Each `id` corresponds to a single unit of work.
* Only supported operations and platforms will be accepted.
* Ensure your `callback_url` is reachable and returns HTTP `200 OK` for successful delivery.
