Research
Six asynchronous research tools that run against a provider and report back through a job id.
The Research category starts asynchronous research runs. Every tool returns
a jobId immediately and the work finishes later; nothing in this category ever
returns the answer in its first response.
Polling
Each response carries a pollWith naming how to learn what happened:
{ "jobId": "0f2c1c8e-…", "status": "running", "pollWith": "GET /research/jobs/{jobId}" }That is a REST path, not a tool name. There is deliberately no
research_job_status tool: a research job is read with
GET /research/jobs/{jobId} on the Putty API, and earlier documentation pointed
at a tool name that was never registered.
The tools
| Tool | What it runs |
|---|---|
research_web_search | a search actor over the web |
research_web_fetch | a single-URL fetch |
research_crawl | a crawl rooted at one URL |
research_social_profile | one social profile |
research_social_posts | a social account's posts |
research_mentions | mentions of a subject |
Cost
Each job reports costCents as the provider billed it, against the caller's own
provider account — not to Putty. Putty does not resell research and does not
mark it up; the number is there so a caller can see what their own key spent.
Authentication
Like every other authenticated tool, these need a Privy access token (a
dashboard user) or an sk- API key (a service). An unauthenticated call is
refused and starts nothing — no job row, no provider spend.
project_finish
Stop the run and report what you built. This is the only way a run ends successfully, and it is refused unless `project_verify` passed during THIS run — a verify from an earlier run does not carry over. The refusal names the verify errors that are still open, so fix the first one and verify again; after three failed attempts on the same error, stop and explain it in the summary instead of looping. Pass a two-to-five line `summary` in the user's terms: what changed and what they can do next. Returns `{ ok, runId, summary }`. Once this succeeds, call nothing further — the run is over.
research_web_search
Search the open web and return what it finds. Asynchronous: this returns a `jobId` and the answer arrives on `research_job_status`. Charged to the caller's own Apify account, so it refuses with a message telling them to connect one if there is none. A count above the cap is clamped, not refused.