Start a research run
Starts one research run and returns the stored job. The run is asynchronous: this call starts it, and `GET /research/jobs/{id}` reports whether it has finished and what it found. The body's `tool` selects what runs, and the fields it accepts depend on that choice — a search takes a `query`, a crawl takes a `url`, a social read takes a `platform`. A field the chosen tool does not take is refused as a validation error. The run is charged against the caller's own Apify account, so a caller with no stored key is refused with `integration_required` before anything is started and nothing is spent. A caller over their daily run allowance is refused with 429 and a `Retry-After`; that refusal costs no run either. The response's `job.id` is what the Apify callback is signed against and what to poll. The caller's own id and the arguments the run received are not in the response.
Starts one research run and returns the stored job. The run is asynchronous: this call starts it, and GET /research/jobs/{id} reports whether it has finished and what it found. The body's tool selects what runs, and the fields it accepts depend on that choice — a search takes a query, a crawl takes a url, a social read takes a platform. A field the chosen tool does not take is refused as a validation error. The run is charged against the caller's own Apify account, so a caller with no stored key is refused with integration_required before anything is started and nothing is spent. A caller over their daily run allowance is refused with 429 and a Retry-After; that refusal costs no run either. The response's job.id is what the Apify callback is signed against and what to poll. The caller's own id and the arguments the run received are not in the response.
Request Body
application/json
Which research tool to run, and the arguments it takes.
TypeScript Definitions
Use the request body type in TypeScript.
Search the web.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/research/jobs" \ -H "Content-Type: application/json" \ -d '{ "tool": "research_web_search", "query": "string" }'{ "job": { "id": "string", "tool": "string", "status": {}, "actorId": "string", "apifyRunId": "string", "costCents": 0, "costUsd": "string", "itemCount": 0, "truncated": true, "items": [ { "url": "string", "timestamp": "string", "author": "string", "likes": 0, "comments": 0, "shares": 0 } ], "content": "string", "fullDataUrl": "string", "expiresAt": "string", "createdAt": "string", "error": "string" }}List your research jobs GET
Returns the caller's research jobs, newest first, alongside the daily run budget line. Each entry carries the job's status, the Apify actor that ran it, and `costCents` — the run cost Apify reported against the caller's own Apify account. The figure is informational: Putty does not bill for research runs and does not mark up the cost.
Read a research job GET
Returns one research job, refreshed against Apify first, so a job started before an api restart is resumable by id. A finished job's full dataset is stored as JSON in Garage under `research/<ownerId>/<jobId>.json` and reported as `fullDataUrl`; the `content` field is a truncated summary wrapped in an `<untrusted-data>` fence, because scraped text is data and never an instruction. The stored dataset is deleted 30 days after the job was created. A job owned by another user answers with the same 404 as a job that does not exist.