> ## Documentation Index
> Fetch the complete documentation index at: https://brezelscraper.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Use BrezelScraper with n8n

> Create jobs, wait for completion, and fetch results from BrezelScraper inside n8n.

<Tip>
  Start with the API-first workflow. It is easier to test and easier to debug. Add webhooks later if you want BrezelScraper to notify n8n when jobs finish.
</Tip>

## Before you start

Make sure you have:

* A BrezelScraper account with credits
* An API key from **Dashboard** > **Integrations**
* An n8n workflow you can edit and activate

## Workflow overview

```text theme={null}
Trigger --> HTTP Request (create job) --> Wait --> HTTP Request (poll status)
                                                        |
                                          +---------+---+----------+
                                          |         |              |
                                      completed   running       failed
                                          |       / pending    / cancelled
                                          v      v              v
                                  HTTP Request  loop back     stop or
                                  (get results) to Wait       handle error
```

## Step 1: create an API key

In BrezelScraper, open **Dashboard** > **Integrations** and create a new API key.

Copy the full `bscraper_...` token and store it somewhere safe. You will only see it once.

## Step 2: create a job with an HTTP Request node

Add an `HTTP Request` node with these settings:

* Method: `POST`
* URL: `https://api.brezelscraper.com/api/v1/jobs`
* Authentication: generic header auth, or add the header manually
* Header option 1: `Authorization: Bearer bscraper_your_key_here`
* Header option 2: `X-API-Key: bscraper_your_key_here`
* Body content type: JSON

Example request body:

```json theme={null}
{
  "name": "Berlin cafes",
  "keywords": ["cafes in berlin"],
  "lang": "en",
  "depth": 5,
  "max_results": 100,
  "reviews_max": 0,
  "images_max": 0,
  "max_time": 1800
}
```

| Field         | Type      | Notes                                         |
| ------------- | --------- | --------------------------------------------- |
| `name`        | string    | A label for this job (required)               |
| `keywords`    | string\[] | 1 to 5 search terms (required)                |
| `lang`        | string    | Two-letter language code (required)           |
| `depth`       | int       | Scroll depth, 1--20 (default 5)               |
| `max_results` | int       | Cap on results, 1--500                        |
| `reviews_max` | int       | Reviews per place, 0--500                     |
| `images_max`  | int       | Total images across all places, 0--40000      |
| `max_time`    | int       | Timeout in seconds, up to 3600 (default 1800) |

A successful `201 Created` response returns the new job ID:

```json theme={null}
{
  "id": "d8d8a24e-cef2-4b02-8396-abc290b6f299"
}
```

## Step 3: keep the job ID in your workflow

Store the `id` from the response in a field such as `jobId` so later nodes can reference it easily.

## Step 4: wait before polling

Add a `Wait` node after job creation so your workflow does not hit the API in a tight loop. 30 to 60 seconds is a good starting interval for most jobs.

After the wait, call:

```text theme={null}
GET https://api.brezelscraper.com/api/v1/jobs/{{ $json.jobId }}
```

The response looks like this:

```json theme={null}
{
  "id": "d8d8a24e-cef2-4b02-8396-abc290b6f299",
  "name": "Berlin cafes",
  "status": "running",
  "data": { ... },
  "result_count": 0,
  "created_at": "2026-04-10T12:00:00Z"
}
```

Check the `status` field and branch accordingly:

* `pending`, `running`, or `aborting`: wait again, then poll again
* `completed`: continue to results
* `failed` or `cancelled`: stop the workflow or route to your error handling path

You can also check `result_count` before fetching results. If it is `0`, there is nothing to download.

## Step 5: fetch results

Once the status is `completed`, fetch structured results:

```text theme={null}
GET https://api.brezelscraper.com/api/v1/jobs/{{ $json.jobId }}/results
```

Use this when you want JSON data inside n8n.

If you want the CSV file instead:

```text theme={null}
GET https://api.brezelscraper.com/api/v1/jobs/{{ $json.jobId }}/download
```

## Cancelling a job

To stop a running job from n8n (for example on a timeout), send:

```text theme={null}
POST https://api.brezelscraper.com/api/v1/jobs/{{ $json.jobId }}/cancel
```

The job status will move to `aborting` and then to `cancelled`.

## Optional: trigger n8n from BrezelScraper webhooks

Instead of polling, you can have BrezelScraper notify n8n when a job finishes.

### Set up the webhook

1. In n8n, add a `Webhook` node and copy its **Production URL**
2. In BrezelScraper, open **Dashboard** > **Integrations**
3. Create a webhook and paste the n8n production URL
4. Copy the **signing secret** and store it securely (you will only see it once)

BrezelScraper sends a POST request to your webhook URL when a job reaches a terminal state.

### Webhook payload

```json theme={null}
{
  "event_type": "job.completed",
  "job_id": "d8d8a24e-cef2-4b02-8396-abc290b6f299",
  "job_name": "Berlin cafes",
  "status": "completed",
  "result_count": 87,
  "created_at": "2026-04-10T12:00:00Z",
  "ended_at": "2026-04-10T12:05:30Z"
}
```

Possible `event_type` values: `job.completed`, `job.failed`, `job.cancelled`.

The payload contains metadata only. Fetch results through the API after receiving the webhook.

### Verify the signature

Each delivery includes an `X-Webhook-Signature` header with an HMAC-SHA256 signature of the request body. In your n8n `Code` node:

```javascript theme={null}
const crypto = require('crypto');
const sigHeader = $input.first().headers['x-webhook-signature'];
const parts = Object.fromEntries(sigHeader.split(',').map(p => p.split('=')));
const timestamp = parts.t;
const signature = parts.sha256;

const expected = crypto
  .createHmac('sha256', 'your_signing_secret')
  .update(timestamp + '.' + $input.first().body)
  .digest('hex');
const valid = crypto.timingSafeEqual(
  Buffer.from(signature),
  Buffer.from(expected)
);
```

### Delivery and retries

BrezelScraper retries failed deliveries up to 5 times with exponential backoff. Each delivery has a unique `X-Webhook-ID` header you can use for deduplication. The timestamp in the signature header is cryptographically signed, so reject deliveries where `t` is more than 5 minutes old.

## Error handling

The API returns standard HTTP status codes. Handle these in your n8n workflow with an `IF` node or error branch:

| Code  | Meaning                                     | What to do                                                             |
| ----- | ------------------------------------------- | ---------------------------------------------------------------------- |
| `201` | Job created                                 | Continue                                                               |
| `200` | Request succeeded (poll, results, download) | Continue                                                               |
| `402` | Insufficient credits                        | Stop and alert the user                                                |
| `404` | Job not found or not owned by you           | Check the job ID                                                       |
| `422` | Invalid request body                        | Check field values and types                                           |
| `429` | Rate limit hit                              | Wait and retry after the number of seconds in the `Retry-After` header |

Polling too fast is the most common cause of `429` errors. Space your `Wait` nodes at least 10 seconds apart.

## Good production habits

* Add an `Idempotency-Key` header on `POST /api/v1/jobs` if your workflow may retry on failure
* Handle `failed` and `cancelled` jobs explicitly instead of looping forever
* Keep the job ID in one field throughout the workflow so every node can reference it

## Related pages

* [Integrations](/docs/api-reference/integrations)
* [Authentication](/docs/api-reference/authentication)
* [Jobs](/docs/api-reference/jobs)
* [Results and exports](/docs/api-reference/results-and-exports)

## Official n8n docs

* [HTTP Request node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.httprequest/)
* [Webhook node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.webhook/)
* [Wait node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.wait/)
