Skip to content

Get data

Requires a valid JWT unless noted. See Authentication.

Set a shell variable for examples:

export API_BASE="https://api.azscraper.com"
export TOKEN="<paste accessToken>"

Projects

List projects

GET /projects — Query: optional archived (true | false).

curl -sS "$API_BASE/projects?archived=false" \
  -H "Authorization: Bearer $TOKEN"
const r = await fetch(`${process.env.API_BASE}/projects?archived=false`, {
  headers: { Authorization: `Bearer ${process.env.TOKEN}` },
});
console.log(await r.json());
import os, httpx
r = httpx.get(
    f"{os.environ['API_BASE']}/projects",
    params={"archived": "false"},
    headers={"Authorization": f"Bearer {os.environ['TOKEN']}"},
)
r.raise_for_status()
print(r.json())

Success

{
  "data": [
    {
      "id": "67d1...",
      "name": "My project",
      "organizationId": "67c...",
      "archived": false,
      "createdAt": "2025-03-01T12:00:00.000Z",
      "updatedAt": "2025-03-01T12:00:00.000Z"
    }
  ]
}

Create project

POST /projects — Body: { "name": string }.

curl -sS -X POST "$API_BASE/projects" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"EU keywords"}'
const r = await fetch(`${process.env.API_BASE}/projects`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ name: "EU keywords" }),
});
const body = await r.json();
if (!r.ok) console.error(body);
else console.log(body.data.id);
import os, httpx
r = httpx.post(
    f"{os.environ['API_BASE']}/projects",
    headers={"Authorization": f"Bearer {os.environ['TOKEN']}"},
    json={"name": "EU keywords"},
)
r.raise_for_status()
print(r.json()["data"]["id"])

Success

{
  "data": {
    "id": "67d2ab...",
    "name": "EU keywords",
    "organizationId": "67c...",
    "archived": false,
    "createdAt": "2025-03-20T10:00:00.000Z",
    "updatedAt": "2025-03-20T10:00:00.000Z"
  }
}

Error (validation, HTTP 400)

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "...",
    "details": []
  }
}

Update project

PATCH /projects/:id — Body: optional name, archived.

curl -sS -X PATCH "$API_BASE/projects/67d2ab..." \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"archived":true}'

Crawl jobs

Create job

POST /projects/:projectId/jobs

Body:

Field Type Notes
type "search" | "details" Search uses keywords; details uses ASINs or /dp/ASIN URLs.
targets string[] Non-empty. For details, each target must resolve to a 10-char ASIN.
config object (optional) e.g. { "lang": "en-US" }; extra keys allowed.
curl -sS -X POST "$API_BASE/projects/$PROJECT_ID/jobs" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"type":"search","targets":["wireless earbuds"],"config":{"lang":"en-US"}}'
const projectId = process.env.PROJECT_ID;
const r = await fetch(`${process.env.API_BASE}/projects/${projectId}/jobs`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    type: "search",
    targets: ["wireless earbuds"],
    config: { lang: "en-US" },
  }),
});
console.log(await r.json());
import os, httpx
r = httpx.post(
    f"{os.environ['API_BASE']}/projects/{os.environ['PROJECT_ID']}/jobs",
    headers={"Authorization": f"Bearer {os.environ['TOKEN']}"},
    json={
        "type": "search",
        "targets": ["wireless earbuds"],
        "config": {"lang": "en-US"},
    },
)
print(r.json())

Success

{
  "data": {
    "id": "67e3...",
    "projectId": "67d2ab...",
    "organizationId": "67c...",
    "type": "search",
    "status": "queued",
    "targets": [{ "value": "wireless earbuds", "status": "pending" }],
    "config": { "lang": "en-US" },
    "createdAt": "2025-03-20T10:05:00.000Z",
    "updatedAt": "2025-03-20T10:05:00.000Z",
    "bullJobId": "67e3..."
  }
}

Error (quota, HTTP 403)

{
  "success": false,
  "error": {
    "code": "FORBIDDEN",
    "message": "Job limit reached for this month",
    "details": []
  }
}

List jobs for a project

GET /projects/:projectId/jobs

Query:

Param Default Notes
status Filter by job status string.
limit 20 Capped at 100 in the repository.
offset 0 Pagination offset.
curl -sS "$API_BASE/projects/$PROJECT_ID/jobs?limit=10&offset=0&status=completed" \
  -H "Authorization: Bearer $TOKEN"

Success

{
  "data": [ { "id": "67e3...", "status": "completed", "type": "search" } ],
  "meta": { "total": 42 }
}

Get job by id

GET /jobs/:id

curl -sS "$API_BASE/jobs/$JOB_ID" \
  -H "Authorization: Bearer $TOKEN"
const r = await fetch(`${process.env.API_BASE}/jobs/${process.env.JOB_ID}`, {
  headers: { Authorization: `Bearer ${process.env.TOKEN}` },
});
console.log(await r.json());
import os, httpx
r = httpx.get(
    f"{os.environ['API_BASE']}/jobs/{os.environ['JOB_ID']}",
    headers={"Authorization": f"Bearer {os.environ['TOKEN']}"},
)
print(r.json())

Success

{
  "data": {
    "id": "67e3...",
    "projectId": "67d2ab...",
    "organizationId": "67c...",
    "type": "search",
    "status": "completed",
    "targets": [{ "value": "wireless earbuds", "status": "success" }],
    "config": { "lang": "en-US" },
    "resultSetId": "67e4...",
    "createdAt": "...",
    "updatedAt": "...",
    "completedAt": "..."
  }
}

status is one of: queued, running, completed, failed, cancelled.

Not found (HTTP 404)

{
  "success": false,
  "error": { "code": "NOT_FOUND", "message": "Job not found", "details": [] }
}

Get results

GET /jobs/:id/results — Returns stored result rows for the job (items array shape depends on crawl output).

curl -sS "$API_BASE/jobs/$JOB_ID/results" \
  -H "Authorization: Bearer $TOKEN"
const r = await fetch(`${process.env.API_BASE}/jobs/${process.env.JOB_ID}/results`, {
  headers: { Authorization: `Bearer ${process.env.TOKEN}` },
});
console.log(await r.json());
import os, httpx
r = httpx.get(
    f"{os.environ['API_BASE']}/jobs/{os.environ['JOB_ID']}/results",
    headers={"Authorization": f"Bearer {os.environ['TOKEN']}"},
)
print(r.json())

Success

{
  "data": [
    { "asin": "B08N5WRWNW", "title": "Example product" }
  ],
  "meta": { "total": 1 }
}

The objects inside data are whatever the crawler persisted for that job type; treat them as opaque JSON until you standardize on a schema in your integration.


Export job results

GET /jobs/:id/export — Query: format = json (default) or csv. Response is a file download (Content-Disposition: attachment), not a JSON envelope.

curl -sS -L "$API_BASE/jobs/$JOB_ID/export?format=csv" \
  -H "Authorization: Bearer $TOKEN" \
  -o "job-${JOB_ID}.csv"
const r = await fetch(
  `${process.env.API_BASE}/jobs/${process.env.JOB_ID}/export?format=json`,
  { headers: { Authorization: `Bearer ${process.env.TOKEN}` } },
);
if (!r.ok) {
  console.error(await r.json());
} else {
  const buf = Buffer.from(await r.arrayBuffer());
  console.log(buf.toString("utf8").slice(0, 200));
}
import os
import httpx

r = httpx.get(
    f"{os.environ['API_BASE']}/jobs/{os.environ['JOB_ID']}/export",
    params={"format": "json"},
    headers={"Authorization": f"Bearer {os.environ['TOKEN']}"},
)
r.raise_for_status()
open("export.json", "wb").write(r.content)

Error (HTTP 4xx/5xx) — JSON error envelope from the filter when the use case throws (e.g. not found).


Retry job

POST /jobs/:id/retry

curl -sS -X POST "$API_BASE/jobs/$JOB_ID/retry" \
  -H "Authorization: Bearer $TOKEN"

Response: { "data": { ...job } } — a new queued job copying the original type, config, and target values (targets reset to pending).


Cancel job

POST /jobs/:id/cancel

curl -sS -X POST "$API_BASE/jobs/$JOB_ID/cancel" \
  -H "Authorization: Bearer $TOKEN"

Schedules

Method Path Body / notes
POST /projects/:projectId/schedules { "cron": "<cron string>", "crawlConfig": { "type", "targets", "config?" } }
GET /projects/:projectId/schedules List schedules for the project.
PATCH /schedules/:id Optional enabled, cron, crawlConfig.

Cron handling in the service targets daily-style expressions; validate in your environment before relying on edge cases.


Usage

GET /usage — Monthly limits vs usage for the JWT’s organization.

{
  "data": {
    "limits": { "jobsPerMonth": 10, "targetsPerMonth": 100, "exportsPerMonth": 20 },
    "used": { "jobsThisMonth": 3, "targetsThisMonth": 40, "exportsThisMonth": 2 },
    "remaining": { "jobsPerMonth": 7, "targetsPerMonth": 60, "exportsPerMonth": 18 }
  }
}

Health (no auth)

GET /health

curl -sS "$API_BASE/health"
{ "status": "ok" }

Quick reference

Endpoint Method Auth
/health GET N
/auth/register POST N
/auth/login POST N
/auth/login-handoff POST N
/auth/verify-handoff POST N
/auth/logout POST N (Bearer optional; stateless JWT)
/projects GET Y
/projects POST Y
/projects/:id PATCH Y
/projects/:projectId/jobs POST Y
/projects/:projectId/jobs GET Y
/jobs/:id GET Y
/jobs/:id/results GET Y
/jobs/:id/export GET Y
/jobs/:id/retry POST Y
/jobs/:id/cancel POST Y
/projects/:projectId/schedules POST, GET Y
/schedules/:id PATCH Y
/usage GET Y
/audit GET Y
/referral/* various see Referral API
/admin/* various Admin JWT

See also Webhooks and Authentication.