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.
Job statuses
| Status | Meaning |
|---|
pending | The job has been accepted and is waiting to run |
running | The scraper is actively collecting data |
completed | The job finished successfully |
failed | The job did not complete successfully |
cancelled | The job was cancelled |
aborting | Cancellation is in progress |
POST /api/v1/jobs
Create a new scraping job.
Request body
| Field | Type | Required | Default | Notes |
|---|
name | string | Yes | none | 1 to 200 characters |
keywords | string[] | Yes | none | 1 to 5 keywords, each 1 to 200 characters |
lang | string | Yes | none | 2-character language code |
depth | integer | No | 5 | Min 1, max 20 |
email | boolean | No | false | Enables email scraping from business websites |
images_max | integer | No | 0 | Total image cap for the whole job, max 40000 |
reviews_max | integer | No | 0 | Review cap per place, max 500 |
max_results | integer | No | 50 | Place cap for the whole job, max 500 |
lat | string | No | empty | Latitude for geo-targeted runs |
lon | string | No | empty | Longitude for geo-targeted runs |
zoom | integer | No | 0 | Map zoom, max 21 |
radius | integer | No | 0 | Meters, max 50000 |
max_time | integer | No | 1800 | Seconds, max 3600 |
fast_mode | boolean | No | false | Faster, lighter data collection |
proxies | string[] | No | empty | Up to 100 custom proxy URLs |
There is no unlimited sentinel for cap fields. If you want the maximum allowed value, send the maximum explicitly.
Supported lang values
ar, bg, cs, da, de, el, en, es, et, fi, fr, he, hr, hu, id, it, ja, ko, lt, lv, ms, nl, no, pl, pt, ro, ru, sk, sl, sv, th, tr, uk, vi, zh
Example request
curl -X POST https://api.brezelscraper.com/api/v1/jobs \
-H "Authorization: Bearer bscraper_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Berlin cafes",
"keywords": ["cafes in berlin"],
"lang": "en",
"depth": 5,
"max_results": 100,
"reviews_max": 0,
"images_max": 0,
"max_time": 1800
}'
Success response
{
"id": "d8d8a24e-cef2-4b02-8396-abc290b6f299"
}
Common failure modes
400 Bad Request for validation failures
402 Payment Required if your credit balance is too low
409 Conflict if you reuse an idempotency key incorrectly
422 Unprocessable Entity for invalid JSON
429 Too Many Requests if you hit the concurrent job limit, with Retry-After: 60
POST /api/v1/jobs/estimates
Check how much a scraping job will cost before you create it.
Use this endpoint to show users a price preview in your UI, or to decide programmatically
whether to proceed with a job based on cost and available credits.
Why use this endpoint
- You get a cost breakdown before spending any credits.
- The response includes your current credit balance so you know if you can afford the job.
- The estimate shows a range (min to max) because Google Maps results vary by location and search term.
Request body
| Parameter | Type | Required | Default | Description |
|---|
keywords | string[] | Yes | | The search terms for your job. 1 to 5 keywords, each up to 200 characters. More keywords means more places found and higher cost. |
depth | integer | No | 5 | How far to scroll in Google Maps search results. Higher depth finds more places per keyword. Range: 1 to 20. |
include_emails | boolean | No | false | Whether to extract emails from business websites. Adds a per-place cost. |
max_images | integer | No | 0 | Total number of images to collect across all places. 0 means skip images. Maximum 40000. |
max_reviews | integer | No | (uses average) | Maximum reviews to collect per place. 0 means skip reviews. If omitted, the estimate uses a realistic average (~50 per place). Range: 0 to 500. |
max_results | integer | No | (uses depth) | Hard cap on total places returned. If omitted, the estimate is based on depth and keyword count. Range: 1 to 500. |
Language is not needed here because it does not affect cost.
Example request
{
"keywords": ["Cafe Mitte Berlin"],
"depth": 5,
"include_emails": false,
"max_reviews": 0,
"max_images": 0
}
Example response
{
"estimate": {
"object": "job_estimate",
"currency": "credits",
"places": 40,
"places_min": 20,
"places_max": 48,
"keyword_count": 1,
"places_per_keyword": 40,
"total": 0.127,
"total_min": 0.067,
"total_max": 0.151,
"breakdown": {
"job_start_cost": 0.007,
"places_cost": 0.12,
"contact_details_cost": 0,
"reviews_cost": 0,
"images_cost": 0
},
"reviews": 0,
"images": 0,
"includes_emails": false,
"unit_prices": {
"job_start": 0.007,
"place_scraped": 0.003,
"contact_details": 0.002,
"review": 0.0005,
"image": 0.0005
},
"max_results_provided": false,
"description": "Estimated ~40 places for 1 keyword at depth 5 (range: 20 to 48).",
"expires_at": 1713110460
},
"balance": {
"current": 24.99,
"sufficient": true
}
}
Response fields
estimate object containing the cost calculation:
| Field | Type | Description |
|---|
object | string | Always "job_estimate". |
currency | string | Always "credits". One credit equals one US dollar. |
places | integer | How many places the job will likely scrape. This is the primary estimate used for pricing. |
places_min | integer | Conservative lower bound on places. Sparse markets (few results for your search term) may produce this many. |
places_max | integer | Upper bound on places. Dense markets (many results) may produce this many. |
keyword_count | integer | Number of keywords in your request. |
places_per_keyword | integer | Estimated places per keyword based on the depth setting. |
total | number | Estimated total cost in credits for the primary estimate. |
total_min | number | Lowest possible cost (based on places_min). |
total_max | number | Highest possible cost (based on places_max). |
breakdown | object | Cost broken down by component: job_start_cost (flat fee per job), places_cost, contact_details_cost (emails), reviews_cost, images_cost. |
reviews | integer | Estimated total reviews to be collected. |
images | integer | Estimated total images to be collected. |
includes_emails | boolean | Whether email extraction was included in the estimate. |
unit_prices | object | The per-unit prices used for this estimate. Lets you verify the math yourself. |
max_results_provided | boolean | Whether you set a max_results cap. If false, the estimate was based on depth. |
description | string | A human-readable summary of the estimate. |
expires_at | integer | Unix timestamp. The estimate is accurate until this time. After that, pricing may have changed. |
balance object containing your account state:
| Field | Type | Description |
|---|
current | number | Your current credit balance. |
sufficient | boolean | Whether you have enough credits to run this job. Uses the conservative lower bound so you are not blocked by an optimistic estimate. |
Notes
- All costs are in credits. One credit equals one US dollar.
- The estimate uses your account’s active pricing rules at request time.
- If you set
max_results, it acts as a hard cap. The estimate will not exceed this number of places even if depth would produce more.
- The
Cache-Control: no-store header is set on responses because estimates are ephemeral and should not be cached.
GET /api/v1/jobs
List your jobs with pagination and sorting.
Query parameters
| Parameter | Type | Default | Notes |
|---|
page | integer | 1 | Must be positive |
limit | integer | 10 | Max 100 |
sort | string | created_at | Allowed: created_at, name, status, updated_at |
order | string | desc | asc or desc |
search | string | empty | Max 200 bytes |
Example response
{
"jobs": [
{
"id": "d8d8a24e-cef2-4b02-8396-abc290b6f299",
"name": "Berlin cafes",
"status": "completed",
"data": {
"keywords": ["cafes in berlin"],
"lang": "en",
"depth": 5,
"email": false,
"images_max": 0,
"reviews_max": 0,
"max_results": 100,
"max_time": 1800,
"fast_mode": false
},
"created_at": "2026-04-10T09:00:00Z",
"updated_at": "2026-04-10T09:05:00Z",
"source": "api",
"result_count": 87,
"total_cost": "12.50"
}
],
"total": 1,
"page": 1,
"limit": 10,
"has_more": false
}
Response fields
| Field | Type | Description |
|---|
id | string | Job UUID |
name | string | The name you set when creating the job |
status | string | Current status (see Job statuses) |
data | object | The configuration you submitted. data.max_time is in seconds, matching the request format. |
created_at | string | When the job was created (ISO 8601) |
updated_at | string | When the job status last changed (ISO 8601) |
source | string | "api" if created via API key, "web" if created from the dashboard |
result_count | integer | Number of places scraped so far |
total_cost | string | Credits charged for this job (6-decimal string) |
GET /api/v1/jobs/{id}
Fetch one job by UUID.
200 OK returns the same job object shape shown above
404 Not Found if the job does not belong to you or does not exist
422 Unprocessable Entity if id is not a valid UUID
POST /api/v1/jobs/{id}/cancel
Cancel a pending or active job.
Returns 204 No Content on success.
DELETE /api/v1/jobs/{id}
Delete a job you own.
Returns 204 No Content on success. Invalid UUID values return 422 Unprocessable Entity.