Skip to main content
Everything you collect is a job: one scraper, one input. A job runs in the background, so you create it, wait for it to finish, then read its results.

Create a job

POST /api/v1/jobs/create/ with a scraper_type and its input in config:
The answer is 201 with the job. The price is locked at this moment, and the job’s credit is checked. A request is refused with 402 if the balance can’t cover its estimate, or if that estimate plus the quoted estimated_cost of the organization’s pending and running jobs exceeds 10 times the balance (Billing). A 402 creates no job, so retrying the request after backing off is safe. How config is checked:
  • A field the scraper doesn’t know is ignored, not refused. Check spelling and case: a misspelt limit runs with the default.
  • An input a scraper accepts but can’t act on with the value you sent is ignored too. Each guide lists them.
  • Either way the job still runs, and its log (GET /api/v1/jobs/{id}/logs/) gets one WARNING naming the fields, for example Input(s) limitt are not recognised for instagram and had no effect; check the spelling.
  • An empty list ("usernames": []) is refused with 400.
  • Numbers, links and dates the scraper guide gives a range for are checked, and a value outside it is refused with 400 naming the field.

Statuses

Wait on is_terminal, not on status. A job that fails while it still has automatic retries left reads "status": "failed" with "is_terminal": false and "will_auto_retry": true: it is about to run again, under the same id. is_terminal is true once the job is completed or cancelled, or failed or timed_out with no retry coming. The SDK’s call() and wait_for_finish() already wait for it. Each earlier attempt is listed in attempt_history with its status, error_message and failed_at.

error_code

A job that did not complete has an error_code, so your code can decide what to do without reading error_message:

A finished job

A real completed job, from a test run of the quickstart on a local stack. Amounts are shown as "…": rates change, so the docs leave them out.
Fields worth knowing:

Read the results

GET /api/v1/jobs/{id}/results/?offset=0&limit=100 returns a page of rows:
  • limit is 50 by default and at most 100. Page with offset until you have total rows, or a page comes back with count 0.
  • total includes $0 status rows, such as Instagram’s profile_error, so it can exceed items_scraped.
  • A running job already returns the rows delivered so far.
  • Each row is the scraper’s own record. Its fields are in the scraper’s guide.
  • Rows don’t always come back in input order. Match them to your input with the field the guide names (input, facebookUrl, search_term, …).
With the SDK, iterate_items() pages for you:
Results are deleted 5 days after collection. After that, /results/ returns total: 0. Job records (configuration, status, counts and usage) stay while your account is active. Fetch the results, or take them by webhook, within that window.

Is it complete?

completed means the job ran to its end. It does not always mean every target delivered everything: a private account, a page that shows nothing to signed-out visitors, or a platform that stopped answering partway leaves gaps. scraper_metadata says what happened, with keys that depend on the scraper: Each scraper guide lists what it reports.

Logs, cancel and retry

Lists and paging

Every list answers {"total", "offset", "limit", "count", "results"}. Page with offset and limit: 25 rows by default, at most 100. The audit log is the exception: it pages with page and page_size (100 by default) and answers {"count", "next", "previous", "results"}.