Riken ScraperDocs

Jobs and export

Read a job's results page by page, or download them all as gzipped NDJSON. Free.

A large job (a walk over thousands of creators, say) has more results than you want to page through. Export them instead: one request starts the export, polling it returns download links.

Flow

POST /v1/jobs/{id}/export   -> 202, Location, Retry-After: 5   (state: pending)
GET  /v1/jobs/{id}/export   -> 202 while pending or running
GET  /v1/jobs/{id}/export   -> 200, state: done, parts[] with URLs
GET  <part url>             -> the gzipped NDJSON file (no API key)

The job must be finished first: done, failed or canceled, with finished_at set. A job still queued or running gets 409 job_not_finished.

Start an export

curl -s -X POST "https://scraper.riken.me/v1/jobs/685/export" -H "x-api-key: $RIKEN_API_KEY"
{"job_id": 685, "state": "pending", "format": "ndjson.gz", "poll_url": "/v1/jobs/685/export",
 "parts": [], "rows_total": 0, "bytes_total": 0, "credits_charged": "0", "attempts": 0}

Idempotent. POST again and you get the same export, not rebuilt and not charged. It is rebuilt only if the last export failed or the job finished again after it was built.

Poll and download

curl -s "https://scraper.riken.me/v1/jobs/685/export" -H "x-api-key: $RIKEN_API_KEY"
{"job_id": 685, "state": "done", "format": "ndjson.gz",
 "sections": {"creators": 9720, "media": 299818, "walks": 9731},
 "parts": [
   {"section": "creators", "part": 0, "rows": 9720,  "bytes": 1350211, "url": "https://..."},
   {"section": "media",    "part": 0, "rows": 50000, "bytes": 6012345, "url": "https://..."}
 ],
 "rows_total": 319269, "urls_expire_at": "2026-11-05T23:41:00Z", "credits_charged": "0"}

The URL is the credential, so send no API key with it:

curl -s -o media-0000.ndjson.gz "<url>"
gunzip -c media-0000.ndjson.gz | head -1 | jq .
fieldmeaning
statepending, running, done, failed, or stale (the job finished again after this export; POST to rebuild)
sectionsevery list this kind of job has, with its row count. Present once done.
parts[]one file each: section, part, rows, bytes (gzipped), url
urls_expire_atwhen the URLs stop working. GET the export again for fresh ones.
failure_reasonwhy an attempt failed

What is in a file

  • One section per file, up to 50,000 rows each. A section with no rows has no file.
  • One JSON object per line, identical to the object GET /v1/jobs/{id} returns in that list, so one parser reads both.
  • Stored as gzip (Content-Type: application/gzip), so your client never unzips it silently.
  • The whole export is read in one database snapshot: no row skipped or repeated, and no count changes between parts.
job kindsections
tiktok.walk, instagram.fetchcreators, media, walks
tiktok.searchcreators, media, units
tiktok.audiencecreators, media, audience

Paging instead

GET /v1/jobs/{id}?results=true pages 500 rows at a time, free.

  • Creators and media come in id order, so every page costs the same however deep you go.
  • Send sections= to read one list only, for example sections=walks with walk_cursor.
  • Page a job only after it is done. While it runs, a new row can land behind your cursor.
  • An old cursor gets 400 cursor_expired: start again without one.

Errors

statuserrorwhen
404not_foundno such job, another key's job, or no export requested yet (GET)
409job_not_finishedthe job is still running or saving results
503export_unavailableexport is switched off on this server

Only the key that submitted a job can read or export it.

On this page