Expanded Limits, Across all tiers - Our Gift to you! Learn more →

AlterLab
SearchResearchPricingComparePlaygroundBlogDocsChangelog
    AlterLabAlterLab
    PricingComparePlaygroundBlogDocsChangelog
    IntroductionQuickstartInstallationYour First Request
    REST APICrawl APIMap APISearch APIResearch APINewSERP APINewExtract APIAIJob PollingAPI KeysSessions APINewEnterprise APIEnterprise
    AccountAutoAlertsAutoAuthAutoBillingAutoCrawlAutoExtractAutoIntegrationsAutoKeysAutoMapAutoMonitorsAutoOrganizationsAutoSchedulesAutoScrapeAutoSearchAutoSessionsAutoUser WebhooksAutoV1 EndpointsAutoWebhooksAuto
    OverviewPythonNode.js
    JavaScript RenderingBrowser ActionsOutput FormatsPDF & OCRCachingWebhooksJSON Schema FilteringWebSocket Real-TimeBring Your Own ProxyProSticky SessionsProAuthenticated ScrapingNewHTTP Methods & BodiesNewStructured ExtractionAIWeb SearchAgent and RAG GroundingResearch JobsSite MappingWeb CrawlingBatch ScrapingSchedulerChange DetectionCloud Storage ExportSpend LimitsOrganizations & TeamsAlerts & NotificationsExtraction ProfilesAIBYOK ExtractionAIOAuth2 Machine-to-MachineSupport & TicketsUnsupported Targets
    Structured ExtractionAIE-commerce ScrapingNews MonitoringPrice MonitoringMulti-Page CrawlingMonitoring DashboardAI Agent / MCPMCPAI Research AgentAISite CrawlingData Pipeline to Cloud
    E-commerceLead GenerationChange MonitoringRAG & AI PipelinesAIResearch
    PricingRate LimitsError CodesChangelogVersioning
    From FirecrawlFrom ApifyFrom ScrapingBee / ScraperAPIFrom Crawl4AIFrom SpiderSearch to SERPFirecrawl v0 API ReferenceLegacy
    OverviewMCP ServerAIn8n NodeLangChainAICrewAIAILlamaIndexAISupabaseChrome ExtensionSoon
    PlaygroundPricingStatus

    Up to 5,000 free requests · No credit card

    API Reference
    New

    Research API

    Start an asynchronous research job: AlterLab searches, reads sources and returns a cited answer within the budget you set. Planning and synthesis run on your own LLM key.

    Bring your own key

    Research requires an LLM key (BYOK) added in your dashboard settings. Without one, the request returns byok_key_required with HTTP 400, nothing is stored and you are not charged. Model tokens are billed by your provider, never by AlterLab.

    Overview

    • Jobs are asynchronous: POST returns 202 with a job id; poll the job, stream events, or register a webhook.
    • Every job runs under a hard budget (cost, tool calls, runtime, depth, sources). When a cap is reached the job ends as completed_partial with a coverage report.
    • Job statuses: awaiting_approval, queued, running, completed, completed_partial, failed, cancelled.
    • Responses never name the search sources behind a result. Auth uses the same X-API-Key header as every other endpoint (scope: scrape; write for create, read for fetch).

    POST /api/v1/research

    POST
    /api/v1/research

    Start a research job. Returns 202 with the job, its resolved budget and, when a webhook is set, the webhook secret (returned once).

    Parameters

    NameTypeRequiredDescription
    querystring
    Required
    Research question, 1-4000 characters.
    effortstringOptionallite, standard, deep, exhaustive or frontier. See Effort Tiers.Default: standard
    max_cost_microcentsintegerOptionalHard cap on platform spend (1 microcent = one millionth of a dollar). Lowers the effort tier cap.
    max_tool_callsintegerOptionalCap on searches plus fetches.
    max_runtime_secondsintegerOptionalWall-clock cap.
    max_depthintegerOptionalMaximum follow-up rounds, 1-10.
    max_sourcesintegerOptionalMaximum sources read, 1-500.
    outputstringOptionaljson (structured answer), report (cited prose) or both.Default: json
    citation_formatstringOptionalnumbered, mla, apa or chicago.Default: numbered
    output_lengthstringOptionalshort, standard or long.Default: standard
    criteriastring[]OptionalUp to 20 free-text criteria (1-500 characters each). The result reports each as met or unmet.
    min_sourcesintegerOptionalIndependent sources required per field, 1-10.Default: 1
    sourcesobjectOptional{ include_domains (soft boost), exclude_domains (hard), seed_urls, only_these_urls (read only the seed URLs, no discovery searches), categories (web, news, academic, code, discussions) }.
    output_schemaobjectOptionalJSON Schema (object) for the structured answer.
    filesobject[]OptionalUp to 50 caller files, { name, text }, searched as sources and cited as file:// spans. Requires tools.file_search.
    toolsobjectOptional{ file_search (default true), code_execution (default true), mcp (up to 5 remote HTTPS MCP servers, each { name, url, allowed_tools }) }. Each call is budgeted, metered and refunded if empty.
    plan_firstbooleanOptionalReturn a plan and wait for approval before any spend.Default: false
    webhookobjectOptional{ url (HTTPS), secret (optional, 16-256 chars) }. Fired on terminal status.
    providerstringOptionalBYOK provider for planning and synthesis.
    modelstringOptionalBYOK model override.

    Request Example

    Bash
    curl -X POST https://api.alterlab.io/api/v1/research \
      -H "X-API-Key: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "query": "How do vector databases handle filtered search?",
        "effort": "standard",
        "max_cost_microcents": 20000
      }'

    Response Example

    JSON
    {
      "id": "9f1c2b7e-3a5d-4c8e-9b1a-2d6f7e8a9b0c",
      "status": "queued",
      "effort": "standard",
      "budget": {
        "max_cost_microcents": 20000,
        "max_tool_calls": 40,
        "max_runtime_seconds": 120,
        "max_depth": 2,
        "max_sources": 20
      },
      "cost": { "platform_microcents": 0, "model_microcents": 0 },
      "tool_calls": 0,
      "created_at": "2026-11-04T12:00:00Z"
    }

    Unknown request fields are rejected. The create call returns 400 invalid_webhook_url when the webhook URL fails validation.

    GET /api/v1/research

    Lists your research jobs, newest first. Query parameters: limit (1-100, default 20) and cursor (the next_cursor from the previous page). The response is { "items": [...], "next_cursor": "..." | null }. A malformed cursor returns 422 invalid_cursor.

    GET /api/v1/research/{id}

    GET
    /api/v1/research/{id}

    Fetch a job. Terminal jobs include result, coverage, stop_reason and the final cost.

    Response Example

    JSON
    {
      "id": "9f1c2b7e-3a5d-4c8e-9b1a-2d6f7e8a9b0c",
      "status": "completed",
      "effort": "standard",
      "tool_calls": 31,
      "stop_reason": "answered",
      "cost": { "platform_microcents": 14300, "model_microcents": 0 },
      "result": { "...": "answer and citations" },
      "coverage": { "...": "what was and was not read" },
      "finished_at": "2026-11-04T12:01:12Z"
    }

    Unknown ids return 404 research_not_found. The result and coverage objects are free-form JSON; read them defensively.

    POST /api/v1/research/{id}/cancel

    Cancels a job that has not finished. Returns the job with status cancelled. A job that already finished returns 409 research_already_finished.

    DELETE /api/v1/research/{id}

    Permanently deletes a finished job together with its events and queued webhook deliveries. Returns 204 with no body. A job that is still active returns 409 research_active; cancel it first. Unknown ids return 404 research_not_found.

    POST /api/v1/research/{id}/rerun

    Starts a new job from the stored request of an existing one and returns it with status 202, exactly like POST /api/v1/research. The body is optional: { "overrides": { ... } } replaces top-level request fields, and a null value clears one. The stored request never holds the webhook, so pass webhook in overrides to attach one. The merged request is validated again: invalid overrides return 422 invalid_rerun_overrides. The new job is billed like any other submission.

    Bash
    curl -X POST https://api.alterlab.io/api/v1/research/JOB_ID/rerun \
      -H "X-API-Key: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"overrides": {"effort": "deep"}}'

    GET /api/v1/research/{id}/events

    Server-sent events: status, progress, thinking_summary, plan and a final research.<status> event, after which the stream closes. Each event id is monotonic per job. Reconnect with the Last-Event-ID header (or ?last_event_id=) to receive only the events you missed. Events are kept for the life of the job.

    Bash
    curl -N https://api.alterlab.io/api/v1/research/JOB_ID/events \
      -H "X-API-Key: YOUR_API_KEY" \
      -H "Last-Event-ID: 12"

    Plan Steering

    With plan_first: true the job waits in awaiting_approval and nothing is spent until you approve.

    • GET /api/v1/research/{id}/plan: read the plan.
    • PUT /api/v1/research/{id}/plan: replace it with body { "plan": { ... } }.
    • POST /api/v1/research/{id}/approve: start the job; an optional plan in the body replaces the plan first.

    Plan endpoints on a job that is not awaiting approval return 409 research_not_awaiting_approval; an approval that raced its expiry returns 409 research_plan_expired.

    Webhooks

    On terminal status AlterLab POSTs the job to your HTTPS URL with these headers: X-AlterLab-Event, X-AlterLab-Timestamp and X-AlterLab-Signature: sha256=<hex>, where the signature is HMAC-SHA256 of {timestamp}.{body} with your secret. The secret is returned once, in the create response, unless you supplied your own.

    Python
    import hashlib, hmac
    
    def verify(secret: str, timestamp: str, body: bytes, header: str) -> bool:
        expected = hmac.new(
            secret.encode(), f"{timestamp}.".encode() + body, hashlib.sha256
        ).hexdigest()
        return hmac.compare_digest(f"sha256={expected}", header)

    Effort Tiers and Budgets

    EffortSearchesPagesDepthTool callsRuntime capCost capTypical
    lite2511030 s$0.0055-30 s
    standard620240120 s$0.05030-120 s
    deep15604120600 s$0.1002-10 min
    exhaustive4020064001800 s$0.45010-30 min
    frontier1205001015007200 s$1.20030 min-2 h

    Your own max_* values can only lower a tier cap. The cost cap covers platform spend only.

    Pricing

    ActionCostNotes
    Search run by a job$0.001 per search (1,000 microcents)Same flat price as a unified search query
    Page fetch or extractionScrape tier price of the URLPriced per step; the job total is in cost.platform_microcents
    Model tokensNot billed by AlterLabRun on your own key and billed by your provider

    New accounts get up to 5,000 free requests. See pricing.

    Errors

    HTTPerrorMeaning
    400byok_key_requiredNo LLM key on the account. Nothing stored or charged.
    400invalid_webhook_urlWebhook URL failed validation.
    404research_not_foundUnknown job id for this account.
    409research_already_finishedCancel on a job that already finished.
    409research_not_awaiting_approvalPlan read, edit or approve on a job that is not awaiting approval.

    Examples

    Python
    import time
    import requests
    
    API = "https://api.alterlab.io/api/v1/research"
    HEADERS = {"X-API-Key": "YOUR_API_KEY"}
    
    job = requests.post(
        API,
        headers=HEADERS,
        json={"query": "How do vector databases handle filtered search?", "effort": "standard"},
    ).json()
    
    while job["status"] in ("awaiting_approval", "queued", "running"):
        time.sleep(3)
        job = requests.get(f"{API}/{job['id']}", headers=HEADERS).json()
    
    print(job["status"], job["cost"]["platform_microcents"])
    print(job["result"])

    Python, Node and MCP

    The SDKs wrap every endpoint above. Research runs on your own model key; without one the call returns byok_key_required and nothing is charged.

    Python
    from alterlab import AlterLab
    
    client = AlterLab(api_key="YOUR_API_KEY")
    job = await client.research(
        "Which EU countries ban fur farming?",
        effort="standard",
        max_cost_microcents=50_000,
    )
    job = await client.wait_for_research(job["id"])
    print(job["status"], job["cost"], job["result"])
    
    # plan_first jobs: client.get_research_plan(id), update_research_plan(id, plan), approve_research(id)
    # progress: await client.research_events(id, last_event_id="12")

    In the hosted MCP server, the alterlab_research tool starts a job (or fetches one with job_id), waits within the tool time budget and returns the job. A job still running is returned with its id so the model can call again; nothing is cancelled.

    ← Previous: Search APINext: Research Guide →
    Last updated: June 2026

    On this page