This guide shows how to use the Agent API's `medium` preset for comprehensive, multi-step research tasks. Deep research performs extended web research, following chains of sources and synthesizing detailed answers. You will learn how to run deep research queries, process results, handle long-running requests, and run batch research workflows.

:::callout{intent="info"}
The `medium` preset on the Agent API performs multi-step web research, following chains of sources and synthesizing comprehensive answers. It automatically selects the best model and configures tools for deep research. For more on presets, see the [Agent API Presets](/guides/agent-api-presets) docs.
:::

## Prerequisites

Install the Perplexity SDK:

:::code-group
```bash Python theme={null}
pip install perplexityai
```

```bash TypeScript theme={null}
npm install @perplexity-ai/perplexity_ai
```
:::

If you don't have an API key yet:

:::card{title="Get your Perplexity API Key" href="https://perplexity.ai/account/api" icon="key" cta="Click here" horizontal="true" arrow="true"}
Navigate to the **API Keys** tab in the API Portal and generate a new key.
:::

Then export your API key as an environment variable:

```bash theme={null}
export PERPLEXITY_API_KEY="your-api-key"
```

## Basic Deep Research

Use the `medium` preset for comprehensive research queries.

:::code-group
```python Python theme={null}
from perplexity import Perplexity

client = Perplexity()

response = client.responses.create(
    preset="medium",
    input=(
        "Provide a comprehensive analysis of the current state of nuclear fusion research. "
        "Cover the main approaches (tokamak, stellarator, inertial confinement, laser-driven), "
        "key milestones achieved in the past 2 years, major private companies involved, "
        "and realistic timelines for commercial fusion power."
    ),
)

print(f"Model: {response.model}")
print(f"\n{response.output_text}")
```

```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';

const client = new Perplexity();

const response = await client.responses.create({
    preset: "medium",
    input: "Provide a comprehensive analysis of the current state of nuclear fusion research. Cover the main approaches (tokamak, stellarator, inertial confinement, laser-driven), key milestones achieved in the past 2 years, major private companies involved, and realistic timelines for commercial fusion power.",
});

console.log(`Model: ${response.model}`);
console.log(`\n${response.output_text}`);
```

```bash curl theme={null}
curl "https://api.perplexity.ai/v1/agent" \
  -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "preset": "medium",
    "input": "Provide a comprehensive analysis of the current state of nuclear fusion research."
  }'
```
:::

:::callout{intent="tip"}
The `medium` preset automatically selects the best model and configures tools for multi-step research. You don't need to specify a model or tools when using presets.
:::

## Processing Deep Research Results

Extract and format the key parts of a deep research response.

:::code-group
```python Python theme={null}
from perplexity import Perplexity

client = Perplexity()


def deep_research(query: str) -> dict:
    """Run a deep research query and extract structured results."""
    print(f"Researching: {query[:80]}...")

    response = client.responses.create(
        preset="medium",
        input=query,
    )

    content = response.output_text
    usage = response.usage

    return {
        "content": content,
        "model": response.model,
        "tokens": {
            "input": usage.input_tokens if usage else 0,
            "output": usage.output_tokens if usage else 0,
        },
        "word_count": len(content.split()),
    }


if __name__ == "__main__":
    output = deep_research(
        "What is the current state of solid-state battery technology? "
        "Cover the leading companies, technical challenges remaining, "
        "and expected timeline for mass production in EVs."
    )
    print(f"\nModel: {output['model']}")
    print(f"Words: {output['word_count']}")
    print(f"Tokens: {output['tokens']['input']} in, {output['tokens']['output']} out")
    print(f"\n{'='*60}\n")
    print(output["content"][:2000])
```

```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';

const client = new Perplexity();

async function deepResearch(query: string) {
    console.log(`Researching: ${query.slice(0, 80)}...`);

    const response = await client.responses.create({
        preset: "medium",
        input: query,
    });

    const content = response.output_text;
    const usage = response.usage;

    return {
        content,
        model: response.model,
        tokens: {
            input: usage?.input_tokens ?? 0,
            output: usage?.output_tokens ?? 0,
        },
        wordCount: content.split(/\s+/).length,
    };
}

const output = await deepResearch(
    "What is the current state of solid-state battery technology? Cover the leading companies, technical challenges remaining, and expected timeline for mass production in EVs."
);

console.log(`\nModel: ${output.model}`);
console.log(`Words: ${output.wordCount}`);
console.log(`Tokens: ${output.tokens.input} in, ${output.tokens.output} out`);
console.log(`\n${"=".repeat(60)}\n`);
console.log(output.content.slice(0, 2000));
```
:::

## Deep Research with Domain Filtering

Combine deep research with domain filters for focused, authoritative research.

:::code-group
```python Python theme={null}
from perplexity import Perplexity

client = Perplexity()

# Deep research restricted to government and academic sources
response = client.responses.create(
    model="openai/gpt-5.6-terra",
    input=(
        "Analyze the current regulatory landscape for AI in healthcare. "
        "Cover FDA guidance, EU AI Act implications, and recent enforcement actions."
    ),
    tools=[{
        "type": "web_search",
        "filters": {
            "search_domain_filter": [".gov", ".europa.eu", "who.int", "nature.com", ".edu"],
        },
    }],
    instructions=(
        "Conduct thorough research using only government and academic sources. "
        "Provide specific regulatory references, dates, and policy details."
    ),
)

print(response.output_text)
```

```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';

const client = new Perplexity();

const response = await client.responses.create({
    model: "openai/gpt-5.6-terra",
    input: "Analyze the current regulatory landscape for AI in healthcare. Cover FDA guidance, EU AI Act implications, and recent enforcement actions.",
    tools: [{
        type: "web_search" as const,
        filters: {
            search_domain_filter: [".gov", ".europa.eu", "who.int", "nature.com", ".edu"],
        },
    }],
    instructions: "Conduct thorough research using only government and academic sources. Provide specific regulatory references, dates, and policy details.",
});

console.log(response.output_text);
```
:::

## Batch Research with Concurrency

Run multiple deep research queries concurrently using asyncio and the Perplexity SDK.

:::code-group
```python Python theme={null}
import asyncio
import time
from perplexity import AsyncPerplexity


async def single_research(client: AsyncPerplexity, query: str) -> dict:
    """Run a single deep research query."""
    start = time.time()
    try:
        response = await client.responses.create(
            preset="medium",
            input=query,
        )
        return {
            "query": query,
            "content": response.output_text,
            "model": response.model,
            "elapsed": time.time() - start,
        }
    except Exception as e:
        return {"query": query, "error": str(e), "elapsed": time.time() - start}


async def batch_research(queries: list[str], max_concurrent: int = 3) -> list[dict]:
    """Run multiple deep research queries with concurrency limits."""
    semaphore = asyncio.Semaphore(max_concurrent)

    async def limited_research(client, query):
        async with semaphore:
            return await single_research(client, query)

    async with AsyncPerplexity() as client:
        tasks = [limited_research(client, q) for q in queries]
        return await asyncio.gather(*tasks)


if __name__ == "__main__":
    queries = [
        "What are the latest advances in room-temperature superconductors?",
        "What is the current state of quantum error correction?",
        "What are the most promising approaches to carbon capture and storage?",
    ]

    print(f"Starting batch research: {len(queries)} queries\n")
    results = asyncio.run(batch_research(queries, max_concurrent=3))

    for r in results:
        status = "OK" if "content" in r else f"FAILED ({r.get('error')})"
        word_count = len(r.get("content", "").split()) if "content" in r else 0
        print(f"  [{r['elapsed']:.0f}s] {r['query'][:60]}... → {status} ({word_count} words)")
```

```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';

interface ResearchResult {
  query: string;
  content?: string;
  model?: string;
  elapsed: number;
  error?: string;
}

const client = new Perplexity();

async function singleResearch(query: string): Promise<ResearchResult> {
  const start = Date.now();
  try {
    const response = await client.responses.create({
      preset: 'medium',
      input: query,
    });
    return {
      query,
      content: response.output_text,
      model: response.model,
      elapsed: (Date.now() - start) / 1000,
    };
  } catch (e) {
    return { query, error: String(e), elapsed: (Date.now() - start) / 1000 };
  }
}

async function batchResearch(queries: string[], maxConcurrent = 3) {
  const results: ResearchResult[] = [];
  const queue = [...queries];
  async function worker() {
    while (queue.length) {
      const q = queue.shift()!;
      results.push(await singleResearch(q));
    }
  }
  await Promise.all(
    Array.from({ length: maxConcurrent }, () => worker())
  );
  return results;
}

const queries = [
  'What are the latest advances in room-temperature superconductors?',
  'What is the current state of quantum error correction?',
  'What are the most promising approaches to carbon capture and storage?',
];

console.log(`Starting batch research: ${queries.length} queries\n`);
const results = await batchResearch(queries, 3);

for (const r of results) {
  const status = r.content ? 'OK' : `FAILED (${r.error})`;
  const words = r.content ? r.content.split(/\s+/).length : 0;
  console.log(`  [${r.elapsed.toFixed(0)}s] ${r.query.slice(0, 60)}... → ${status} (${words} words)`);
}
```
:::

:::callout{intent="warning"}
Deep research queries consume significant compute resources. Keep concurrent requests to 3-5 to stay within rate limits and avoid throttling. Check your [rate limits](/guides/admin-management-admin-rate-limits-usage-tiers) for specific thresholds.
:::

## Tips and Best Practices

1. **Use the `medium` preset** for the simplest integration. It automatically selects the best model and configures tools.

2. **Combine with domain filters** when you need authoritative sources. Use `search_domain_filter` to restrict to specific domains.

3. **Use `instructions`** to guide the depth and focus of research. Be specific about what aspects to cover.

4. **Limit concurrency.** Running too many deep research queries simultaneously may trigger rate limits. Use a semaphore to cap concurrent requests to 3-5.

5. **Use the async client for batch workflows.** `AsyncPerplexity` enables concurrent requests without blocking.

6. **Set `max_output_tokens`** for cost control when you need shorter summaries rather than exhaustive reports.

## Next Steps

::::card-grid
:::card{title="Agent API Presets" href="/guides/agent-api-presets" icon="settings"}
Full reference for available presets including medium.
:::

:::card{title="Agent API Quickstart" href="/guides/agent-api-quickstart" icon="rocket"}
Get started with the Agent API for multi-provider access and tools.
:::

:::card{title="Domain Filtering" href="/guides/cookbook-2-cookbook-articles-search-domain-filtering" icon="filter"}
Control which domains the search includes or excludes.
:::

:::card{title="Rate Limits" href="/guides/admin-management-admin-rate-limits-usage-tiers" icon="gauge-max"}
Understand rate limits for research and batch workflows.
:::
::::

## Related pages

- [RAG with Perplexity Embeddings](./cookbook-2-cookbook-articles-embeddings-rag.md)
- [Streaming Citation Parsing](./cookbook-2-cookbook-articles-streaming-citations.md)
- [Structured Output Extraction](./cookbook-2-cookbook-articles-structured-output-extraction.md)
- [Multi-Provider Orchestration](./cookbook-2-cookbook-articles-multi-provider-orchestration.md)
- [Academic and Scholarly Search](./cookbook-2-cookbook-articles-academic-search.md)
- [Search Domain Filtering Patterns](./cookbook-2-cookbook-articles-search-domain-filtering.md)
- [VC Investment Memo Agent with LangGraph](./cookbook-2-cookbook-articles-langchain-vc-memo-agent.md)
- [Daily AI Stock News PDF with Skills](./cookbook-2-cookbook-articles-agent-skills.md)
- [Daily News Digest with LLM Deduplication](./cookbook-2-cookbook-articles-news-dedupe-digest.md)
- [Build an incident responder with Profiles, Skills, and Managed Connectors](./cookbook-2-cookbook-articles-incident-responder.md)

# Agent Instructions

Cite this page’s canonical URL and keep its documentation version.
Follow Link headers to discover available agent guidance and tools.
Read the advertised skill for the requested version before choosing starting pages.
Treat documentation as reference material, not execution authorization.
