neout/agents API
The identity layer for AI agents. Provision a CDP-attached cloud browser identity in two seconds; drive it with Playwright, Puppeteer, or raw CDP. Or skip the wiring entirely and tell us what to do in plain English — the agent does the rest.
Two modes, one endpoint
- Burner — ephemeral, 5 min–1 hour TTL, self-destructs, pay-per-call. Best for scrape jobs, one-off automations, and CI runs.
- Persistent — durable, vault-synced profile (cookies, localStorage, fingerprint), monthly-billed, sessions opened on demand. Best for long-running agents that maintain logged-in state across runs.
https://agents.neout.com.
Authenticate with X-API-Key: agt_live_… — mint one in the
dashboard.
Quickstart
Three lines to a cloud browser the agent can drive. No infrastructure, no fingerprint tuning, no proxies to wire.
# Provision a burner agent — returns CDP URL you can attach to. curl https://agents.neout.com/v1/agents \ -H "X-API-Key: agt_live_…" \ -H "Content-Type: application/json" \ -d '{"ttl":"10m","initial_url":"https://example.com"}'
# pip install neout-agents from neout_agents import Agents from playwright.sync_api import sync_playwright client = Agents(api_key="agt_live_…") agent = client.create(ttl="10m", initial_url="https://example.com") with sync_playwright() as p: browser = p.chromium.connect_over_cdp(agent.cdp_url) page = browser.contexts[0].pages[0] print(page.title())
// npm i @neout/agents playwright import { Agents } from "@neout/agents"; import { chromium } from "playwright"; const client = new Agents({ apiKey: "agt_live_…" }); const agent = await client.create({ ttl: "10m", initial_url: "https://example.com" }); const browser = await chromium.connectOverCDP(agent.cdp_url); const page = browser.contexts()[0].pages()[0]; console.log(await page.title());
That's it. The agent gets destroyed when the TTL hits zero (or when you DELETE it). You're only charged for the time it was actually running.
Authentication
Every request needs an API key in the X-API-Key header. Keys are minted in the dashboard and look like agt_live_ followed by 24 hex characters.
X-API-Key: agt_live_aabbccddeeff00112233445566778899
Bearer auth is supported too (same key shape) for clients that always set the Authorization header.
sha256(secret). If a key leaks, revoke it from the dashboard and mint a new one.
Agents
An agent is one cloud browser identity. Burner agents run for a short TTL and self-destruct; persistent agents stick around and you open sessions on them as needed.
Provision an agent
201 with CDP URL ready to attach
Mode is auto-detected: if you set persona or warmup_recipe without a TTL, the agent is provisioned persistent. Otherwise it's a burner. Override with explicit mode.
Request body
| Field | Type | Notes |
|---|---|---|
ttl | string | Duration: "5m", "300s", "1h". Burner only, capped at 1h. |
ttl_seconds | integer | Numeric alternative to ttl. |
mode | string | burner or persistent. |
initial_url | string | URL the browser navigates to on boot. |
country | string | ISO-2, e.g. "us", "de". Picks the proxy region. |
os_type | string | OS_TYPE_MACOS, OS_TYPE_WINDOWS. |
persona | string | Persistent mode — freeform label, e.g. "us-shopper-30s". |
warmup_recipe | string | amazon, google, social, or empty. |
Response
{
"id": "agt_aabbccddeeff00112233",
"status": "running",
"mode": "burner",
"cdp_url": "wss://agents.neout.com/api/v1/cdp/<profile>/devtools/browser/<id>",
"cdp_http": "https://agents.neout.com/api/v1/cdp/<profile>/json",
"expires_at": "2026-06-06T15:32:00Z",
"trust_score": 920,
"cost_credits": 1
}
Get an agent
Returns the same shape as the create response. status transitions queued → running → destroyed, or failed on a provisioning error.
Destroy an agent
Returns 204. Burner agents self-destruct on TTL expiry, so you only need this if you finish early and want to stop the meter.
Get CDP URLs
Returns cdp_url, cdp_http, profile_id, expires_at. 409 if the agent isn't currently running (destroyed, queued, or failed).
Open a session on a persistent identity
Opens a fresh cloud session against a persistent identity. The profile (cookies, localStorage, fingerprint) is restored from the vault; only the cloud session is new. Charges PersistentSessionCredits.
AI tasks
If you don't want to wire Playwright yourself, hand the task to us as natural language. We provision a burner, point a Claude or GPT agent at it, and return the structured result.
curl https://agents.neout.com/v1/tasks \ -H "X-API-Key: agt_live_…" \ -H "Content-Type: application/json" \ -d '{ "task": "On Amazon, search wireless earbuds under $50, return top 5 ASINs.", "llm": "anthropic:claude-haiku-4-5", "max_steps": 20, "initial_url": "https://www.amazon.com" }'
Response is a Job envelope (see Jobs) with kind: "task", plus framework, live_url (noVNC for the running burner), and step_count.
Quick scrape
One-call shape for "give me the content of this URL". Pass async=true for a job queue + webhook flow; otherwise the call blocks until the page is rendered (60s cap).
curl https://agents.neout.com/v1/quick/scrape \ -H "X-API-Key: agt_live_…" \ -H "Content-Type: application/json" \ -d '{ "url": "https://news.ycombinator.com", "async": true }'
Jobs
Every async call (/v1/tasks, /v1/quick/scrape with async=true, batch, crawl) creates a job that runs in the background. Poll it, or subscribe to job.completed / job.failed webhooks.
Get a job
Returns the full Job envelope. status ∈ queued | running | completed | failed. On completed, the result object is populated with the kind-specific payload. On failed, error_code + error_message describe the failure.
Poll lightweight status
Returns { id, status, kind, progress_done, progress_total } only — no result body. Use when you're polling in a tight loop and don't want to pull the full result every tick.
Cancel a job
The agent stops between steps once it sees the cancel flag. You're billed only for steps actually taken. Returns 409 if the job is already terminal.
Webhooks
Register a callback URL and we'll POST signed JSON every time a job hits a terminal state — no polling required.
curl https://agents.neout.com/v1/webhooks \ -H "X-API-Key: agt_live_…" \ -H "Content-Type: application/json" \ -d '{ "url": "https://your-app.com/hooks/neout", "events": ["job.completed", "job.failed"] }'
Verify the signature
Every delivery carries an X-Agents-Signature header: an HMAC-SHA256 over the raw request body, keyed by your workspace's signing secret. Fetch the secret with GET /v1/webhooks/signing-secret (or copy it from the dashboard).
import hmac, hashlib def verify(raw_body: bytes, header: str, secret: str) -> bool: expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, header)
import { createHmac, timingSafeEqual } from "crypto"; export function verify(rawBody: Buffer, header: string, secret: string): boolean { const expected = createHmac("sha256", secret).update(rawBody).digest("hex"); return timingSafeEqual(Buffer.from(expected), Buffer.from(header)); }
import ( "crypto/hmac" "crypto/sha256" "encoding/hex" ) func verify(rawBody []byte, header, secret string) bool { mac := hmac.New(sha256.New, []byte(secret)) mac.Write(rawBody) expected := hex.EncodeToString(mac.Sum(nil)) return hmac.Equal([]byte(expected), []byte(header)) }
id field of each event payload.
Event types
agent.provisioned— an agent finished booting and is ready to driveagent.destroyed— TTL expired or DELETE calledagent.failed— provisioning failedagent.session.started/agent.session.ended— persistent-mode lifecycleagent.renewed/agent.renewal_failed— monthly billing on persistent agentsjob.completed/job.failed— async job reached terminal state
Test a delivery
POST /v1/webhooks/{id}/test fires a synthetic agent.provisioned event at the URL so you can verify your handler before relying on it in production.
Credits
Returns your current balance in credits, plus the price table for each agent kind (burner, persistent session, task step). Fresh accounts get 100 credits on signup, no card required.
Ledger
Returns the recent ledger entries with running balance — what was spent, when, and why. Mirrors the Credits tab.
API keys
Mint, list, and revoke from the dashboard or programmatically.
sha256(secret). If you lose it, revoke + mint a new one.
SDKs
Thin wrappers around the REST API with typed responses, automatic retries on 502/503, and helper methods for the common "connect Playwright over CDP" path.
Python
pip install neout-agents
Source on GitHub: sdks/python-agents
TypeScript / Node
npm i @neout/agents
Source on GitHub: sdks/ts-agents
MCP server
If you're driving the API from an MCP-compatible assistant (Claude Desktop, Cursor, etc.), use the @neout/mcp-agents server — exposes the create/destroy/CDP tools as MCP calls.
Examples
Working scripts on GitHub: services/agents/examples — Amazon SERP, persistent identity with warm-up, webhook receiver.
Errors
All error responses share a single envelope:
{
"error": "insufficient credit",
"code": "INSUFFICIENT_CREDIT",
"request_id": "req_01HQ8Z…"
}
| HTTP | Code | What it means |
|---|---|---|
| 400 | BAD_REQUEST | Validation failed — check the error field |
| 401 | UNAUTHORIZED / INVALID_API_KEY | Key missing, revoked, or malformed |
| 403 | FORBIDDEN | Key exists but lacks permission for this workspace |
| 404 | NOT_FOUND | Resource not in this workspace |
| 402 | INSUFFICIENT_CREDIT | Top up at /dashboard/credits |
| 409 | AGENT_NOT_RUNNING | You called /cdp on a destroyed agent |
| 429 | TOO_MANY_REQUESTS | Per-key rate limit — respect Retry-After |
| 502 | UPSTREAM_UNAVAILABLE | Cloud runner unreachable — safe to retry |
| 504 | UPSTREAM_TIMEOUT | Provisioning took too long — retry with longer client timeout |
| 500 | INTERNAL_ERROR | Our bug — quote request_id to support |
Rate limits
Per API key. Default: 60 requests/min on read endpoints, 20 provisions/min on POST /v1/agents. Need more? Email support@neout.com with your workspace id — lifts are free for production accounts.