# Cancel Agent Response
Source: https://docs.perplexity.ai/api-reference/agent-cancel-post

post /v1/agent/{id}/cancel
Requests cancellation of response `{id}`. Acts on durable state, so it works for background runs that outlive the client connection. Cancellation is asynchronous: a `200` acknowledges the request (`status: cancelling`) and the run stops shortly after - poll `GET /v1/agent/{id}` for its terminal status. Cancelling a run that is already terminal returns `400`. Ownership is enforced server side; a cross-tenant or unknown id surfaces as `404`.



# Download Agent Response File
Source: https://docs.perplexity.ai/api-reference/agent-file-content-get

get /v1/agent/{id}/files/{file_id}/content
Download the raw bytes of a file the response delivered with the `share_file` tool. The `file_id` comes from the file list endpoint and is distinct from the response `id`. The response streams raw bytes, not JSON, with a `Content-Type` matching the file and a `Content-Disposition: attachment` header carrying the original filename.



# List Agent Response Files
Source: https://docs.perplexity.ai/api-reference/agent-files-get

get /v1/agent/{id}/files
List the files a response produced in the sandbox and delivered with the `share_file` tool. Scoped to the authenticated account, which only ever sees its own files. File content is not returned inline; download it with the file content endpoint.



# Retrieve Agent Response
Source: https://docs.perplexity.ai/api-reference/agent-get

get /v1/agent/{id}
Retrieve a response created earlier. Returns a JSON snapshot of the response. Only responses created with `store` omitted or `true` can be retrieved; `store: false` responses return a 404.



# Create Agent Response
Source: https://docs.perplexity.ai/api-reference/agent-post

post /v1/agent
Generate a response for the provided input with optional web search and reasoning.



# Get Async Chat Completion
Source: https://docs.perplexity.ai/api-reference/async-sonar-api-request-get

get /v1/async/sonar/{api_request}
Retrieve the response for a given asynchronous chat completion request.

<SonarDeprecationNotice />


# List Async Chat Completions
Source: https://docs.perplexity.ai/api-reference/async-sonar-get

get /v1/async/sonar
Retrieve a list of all asynchronous chat completion requests for a given user.

<SonarDeprecationNotice />


# Create Async Chat Completion
Source: https://docs.perplexity.ai/api-reference/async-sonar-post

post /v1/async/sonar
Submit an asynchronous chat completion request.

<SonarDeprecationNotice />


# Computer Usage Analytics
Source: https://docs.perplexity.ai/api-reference/computer-analytics-usage-get

get /v1/analytics/computer/usage
Returns your organization's Computer usage analytics as a bucketed time series for a single dataset. Requires an organization analytics API key, generated by an org admin from Settings → Organization → Computer in the Perplexity web app. Only complete UTC grid buckets are returned: start_time snaps down to its bucket, and the in-progress bucket is never included.

<Info>
  This endpoint requires an **organization analytics API key**, generated by an org admin from the Perplexity web app—not a regular API key. See [Computer Analytics API](/docs/admin/computer-analytics-api) for setup, time-window semantics, and pagination.
</Info>


# Computer Usage Analytics per Member
Source: https://docs.perplexity.ai/api-reference/computer-analytics-usage-v2-get

get /v2/analytics/computer/usage
Returns your organization's Computer credit usage broken down per member, as daily buckets. Each day lists one row per member who used credits that day, keyed by email, with the same Model and Credit Source breakdown as v1. Uses the same organization analytics API key as v1. Only complete UTC days are returned; the in-progress day is never included.

<Info>
  This endpoint requires an **organization analytics API key**, generated by an org admin from the Perplexity web app — the same key v1 uses. See [Computer Analytics API](/docs/admin/computer-analytics-api#per-member-usage) for setup, per-member semantics, and pagination.
</Info>


# Create Contextualized Embeddings
Source: https://docs.perplexity.ai/api-reference/contextualized-embeddings-post

post /v1/contextualizedembeddings
Generate contextualized embeddings for document chunks. Chunks from the same document share context awareness, improving retrieval quality for document-based applications.



# Create Embeddings
Source: https://docs.perplexity.ai/api-reference/embeddings-post

post /v1/embeddings
Generate embeddings for a list of texts. Use these embeddings for semantic search, clustering, and other machine learning applications.



# Create Chat Completion
Source: https://docs.perplexity.ai/api-reference/gateway-chat-completions-post

post /router/v1/chat/completions
Send a conversation to any Router model using the OpenAI Chat Completions schema. Set `stream: true` to receive server-sent events; add `stream_options: {"include_usage": true}` to get token usage in the final chunk.

<Info>
  The Router API accepts the OpenAI Chat Completions schema, with a defined subset of parameters. Requests using an unsupported parameter fail with a `400` naming the parameter.
</Info>

<AccordionGroup>
  <Accordion title="Parameter support">
    **Honored:** `model`, `messages`, `stream`, `stream_options.include_usage`, `max_completion_tokens`, `max_tokens`, `temperature`, `top_p`, `stop`, `reasoning_effort`, `service_tier` (`auto`, `default`, `flex`, `priority`), `response_format` (`text`, `json_schema`), `tools`, `tool_choice`, `parallel_tool_calls`, `prompt_cache_key`.

    **Accepted but not forwarded to the model:** `user`, `safety_identifier`, `metadata`.

    **Accepted only at their default values:** `n` (1), `logprobs` (false), `store` (false), `presence_penalty` (0), `frequency_penalty` (0).

    **Rejected with a 400:** `seed`, `logit_bias`, `top_logprobs`, `functions` (use `tools`), `function_call` (use `tool_choice`), `modalities`, `audio`, `prediction`, `web_search_options`, `moderation`, `verbosity`, `prompt_cache_options`, `prompt_cache_retention`, `stream_options.include_obfuscation` set to `true`, plus any unrecognized top-level field.

    **Notes:** When `reasoning_effort` is omitted, the provider's default for that model applies; defaults vary by provider and model. `response_format.json_schema` always runs in strict mode; `json_object` is not supported — use `json_schema`. Function tools require a `description`.
  </Accordion>

  <Accordion title="Errors">
    Errors use the OpenAI envelope:

    ```json theme={null}
    {
      "error": {
        "code": null,
        "message": "Invalid model 'example/does-not-exist'. Permitted models can be found in the documentation at https://docs.perplexity.ai/docs/getting-started/models.",
        "param": null,
        "type": "invalid_request_error"
      }
    }
    ```

    `type` is `invalid_request_error` for 4xx errors, `rate_limit_error` for `429` (rate limited or model overloaded — retry after the `Retry-After` interval), and `server_error` for 5xx. Requests that fail before producing output are not billed.
  </Accordion>
</AccordionGroup>


# Create Message
Source: https://docs.perplexity.ai/api-reference/gateway-messages-post

post /router/v1/messages
Send a conversation to any Router model using the Anthropic Messages schema. Set `stream: true` to receive server-sent events. Authenticate with your Perplexity API key — both `Authorization: Bearer` and the Anthropic SDK's default `x-api-key` header are accepted.

<Info>
  Authenticate with your Perplexity API key. Both `Authorization: Bearer` and the Anthropic SDK's default `x-api-key` header are accepted, so the stock SDK `api_key` parameter works unchanged. No `anthropic-version` header is required.
</Info>

<AccordionGroup>
  <Accordion title="Parameter support">
    **Honored:** `model`, `max_tokens` (required), `messages`, `system`, `stream`, `temperature`, `top_p`, `stop_sequences`, `thinking` (only `{"type": "disabled"}`), `tools`, `tool_choice`.

    **Accepted but not forwarded to the model:** `metadata`.

    **Rejected with a 400:** `top_k`, `service_tier`, `thinking` with `{"type": "enabled"}`, `cache_control` on content blocks or tools, plus any unrecognized top-level field. Tools require a non-empty `description`.
  </Accordion>

  <Accordion title="Errors">
    Errors use the Anthropic envelope:

    ```json theme={null}
    {
      "type": "error",
      "error": {
        "type": "overloaded_error",
        "message": "upstream model is overloaded, please try again later"
      }
    }
    ```

    An overloaded model returns HTTP `429` with type `overloaded_error` and a `Retry-After` header. Requests that fail before producing output are not billed.
  </Accordion>
</AccordionGroup>


# Retrieve Model
Source: https://docs.perplexity.ai/api-reference/gateway-model-get

get /router/v1/models/{model}
Retrieve one model by id, including its base token prices. Model ids contain a `/` (for example `perplexity/kimi-k3`); pass the full id in the path.

<Info>
  Model ids contain a `/` — pass the full id in the path, for example `GET /router/v1/models/perplexity/kimi-k3`.
</Info>


# List Models
Source: https://docs.perplexity.ai/api-reference/gateway-models-get

get /router/v1/models
List the models available through the Router, sorted by id. Each model includes its base token prices in `pricing` (USD per 1M tokens).

<Info>
  Each model includes its base token prices in the `pricing` object (USD per 1M tokens); long-context thresholds and flex-tier multipliers are documented on [Models & Pricing](/docs/gateway/models). The list is also the Router's allowlist: a model absent from this response cannot be requested.
</Info>


# Create Response
Source: https://docs.perplexity.ai/api-reference/gateway-responses-post

post /router/v1/responses
Generate a model response using the OpenAI Responses schema. Set `stream: true` to receive typed server-sent events followed by `data: [DONE]`.

<Info>
  The Router API accepts the OpenAI Responses schema with a defined subset of parameters. This endpoint is stateless: send the full conversation in `input` on each request.
</Info>

<AccordionGroup>
  <Accordion title="Parameter support">
    **Honored:** `model`, `input`, `instructions`, `include` (`reasoning.encrypted_content`), `tools`, `tool_choice`, `text`, `temperature`, `top_p`, `parallel_tool_calls`, `stream`, `max_output_tokens`, `reasoning`, `prompt_cache_key`, `truncation` (`disabled`), and `service_tier` (`auto`, `default`, `flex`, `priority`).

    **Accepted but not forwarded to the model:** `metadata` and `safety_identifier`. Both fields are echoed in the response.

    **Accepted only at their default values:** `store` (`false`), `background` (`false`), `presence_penalty` (0), and `frequency_penalty` (0).

    **Rejected with a 400:** non-null `previous_response_id`, `store: true`, `background: true`, `max_tool_calls`, `top_logprobs`, `truncation: "auto"`, `include: ["message.output_text.logprobs"]`, file or video input, item references, `tool_choice` with `allowed_tools`, `text.format` with `json_object`, `text.format.strict: false`, `stream_options.include_obfuscation: true`, plus any unrecognized top-level field.

    **Notes:** Function tools require a `description`. JSON Schema output always runs in strict mode. `stream_options` requires `stream: true`.
  </Accordion>

  <Accordion title="Streaming">
    Set `stream: true` to receive typed server-sent events such as `response.created`, `response.output_text.delta`, and `response.completed`. A successful stream ends with `data: [DONE]`.

    If an error occurs after streaming begins, the stream emits an `error` event followed by `response.failed` and closes without a `[DONE]` trailer.
  </Accordion>

  <Accordion title="Errors">
    Errors use the Responses envelope:

    ```json theme={null}
    {
      "error": {
        "type": "invalid_request",
        "code": null,
        "message": "model is required",
        "param": "model"
      }
    }
    ```

    `type` is `invalid_request` for invalid requests, `not_found` when a resource is unavailable, `too_many_requests` for `429`, and `server_error` for server failures. Retry rate-limit and overload errors after the `Retry-After` interval. Requests that fail before producing output are not billed.
  </Accordion>
</AccordionGroup>


# Generate Auth Token
Source: https://docs.perplexity.ai/api-reference/generate-auth-token-post

post /generate_auth_token
Generates a new authentication token for API access.



# List Models
Source: https://docs.perplexity.ai/api-reference/models-get

get /v1/models
List the models available for the Agent API. Returns model identifiers that can be used with the `POST /v1/agent` endpoint. The response follows the OpenAI List Models format for compatibility with third-party tools.



# Revoke Auth Token
Source: https://docs.perplexity.ai/api-reference/revoke-auth-token-post

post /revoke_auth_token
Revokes an existing authentication token.



# Search the Web
Source: https://docs.perplexity.ai/api-reference/search-post

post /search
Search the web and retrieve relevant web page contents.

<Info>
  **Search API vs. Sonar.** These are different APIs with different response shapes.

  * **Search API** — Returns structured JSON `results[]` with `title`, `url`, `snippet`, `date`, and `last_updated`. Call `https://api.perplexity.ai/search` directly — no router required.
  * **[Sonar](/docs/sonar/quickstart)** — Chat completions with built-in web search. Returns a prose answer with citations, not a results array.

  Both are first-party Perplexity APIs. Neither routes through OpenRouter.
</Info>

## Response Shape

The Search API returns a ranked `results[]` array. Each result includes `title`, `url`, `snippet`, and optional `date` and `last_updated` fields:

<Accordion title="Example Response">
  ```json theme={null}
  {
    "results": [
      {
        "title": "Example Article Title",
        "url": "https://example.com/article",
        "snippet": "A short excerpt from the article relevant to the query...",
        "date": "2025-01-23",
        "last_updated": "2025-09-25"
      },
      {
        "title": "Another Relevant Source",
        "url": "https://example.org/source",
        "snippet": "Another excerpt showing the structured result format.",
        "date": "2024-11-15",
        "last_updated": "2025-08-12"
      },
      {
        "title": "Third Result",
        "url": "https://example.net/page",
        "snippet": "A third result demonstrating the ranked array structure.",
        "date": "2024-09-10",
        "last_updated": "2025-07-03"
      }
    ],
    "id": "e38104d5-6bd7-4d82-bc4e-0a21179d1f77"
  }
  ```
</Accordion>

## Direct Call

```bash theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
  -H 'Authorization: Bearer $PERPLEXITY_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "query": "latest AI developments",
    "max_results": 3
  }' | jq
```


# Create Chat Completion
Source: https://docs.perplexity.ai/api-reference/sonar-post

post /v1/sonar
Generate a chat completion response for the given conversation.

<SonarDeprecationNotice />


# API Key Management
Source: https://docs.perplexity.ai/docs/admin/api-key-management

Learn how to generate, revoke, and rotate API keys for secure access

## Overview

API keys are essential for authenticating requests to the Perplexity API. This guide covers how to create, manage, and rotate your API keys using our authentication token management endpoints.

<Warning>
  **API keys are shown only once.** When you create an API key — through the console or programmatically — the full token is returned at that moment and **cannot be retrieved again**. Save it immediately to a secure location before closing the page or response.
</Warning>

<Info>
  API keys should be treated as sensitive credentials. Store them securely and never expose them in client-side code or public repositories.
</Info>

## Getting Started: Create Your API Group First

<Warning>
  **Important Prerequisites**: Before you can generate any API keys, you must first create an API group through the Perplexity web interface.
</Warning>

<Steps>
  <Step title="Create an API Group">
    Navigate to the API Groups page and create your first group:

    **[Open Group Settings →](https://console.perplexity.ai/group/settings)**

    API groups help organize your keys and manage access across different projects or environments.

    <Tip>
      Choose a descriptive name for your API group (e.g., "Production", "Development", or your project name) to help with organization.
    </Tip>
  </Step>

  <Step title="Generate Your API Keys">
    Once you have an API group, navigate to the API Keys page to generate your first key:

    **[Generate API Keys →](https://console.perplexity.ai/group/keys)**

    You can create multiple keys within each group for different purposes or environments. The full key value is displayed once at creation — copy it before leaving the page.
  </Step>
</Steps>

<Note>
  After creating your first API key through the web interface, you can use the programmatic endpoints below to generate and manage additional keys.
</Note>

## Key Management Endpoints

Perplexity provides two endpoints for managing API keys programmatically:

* **`/generate_auth_token`** - Creates a new API key
* **`/revoke_auth_token`** - Revokes an existing API key

<Warning>
  Once an API key is revoked, it cannot be recovered. Make sure to update your applications with new keys before revoking old ones.
</Warning>

## Generating API Keys

Create new API keys programmatically. Always provide a descriptive `token_name` — once a key is created, this name is the primary way to identify it later, since the full token value is no longer visible.

### Request

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://api.perplexity.ai/generate_auth_token \
    --header "Authorization: Bearer YOUR_EXISTING_API_KEY" \
    --header "Content-Type: application/json" \
    --data '{
      "token_name": "Production API Key"
    }'
  ```

  ```python Python theme={null}
  import requests

  url = "https://api.perplexity.ai/generate_auth_token"
  headers = {
      "Authorization": "Bearer YOUR_EXISTING_API_KEY",
      "Content-Type": "application/json"
  }
  payload = {
      "token_name": "Production API Key"  # Optional
  }

  response = requests.post(url, headers=headers, json=payload)
  data = response.json()
  print(f"New API Key: {data['auth_token']}")
  print(f"Created at: {data['created_at_epoch_seconds']}")
  ```

  ```typescript Typescript theme={null}
  const response = await fetch("https://api.perplexity.ai/generate_auth_token", {
    method: "POST",
    headers: {
      "Authorization": "Bearer YOUR_EXISTING_API_KEY",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      token_name: "Production API Key"  // Optional
    })
  });

  const data = await response.json();
  console.log(`New API Key: ${data.auth_token}`);
  console.log(`Created at: ${data.created_at_epoch_seconds}`);
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "auth_token": "pplx-1234567890abcdef",
  "created_at_epoch_seconds": 1735689600,
  "token_name": "Production API Key"
}
```

<Warning>
  Store the `auth_token` immediately and securely. This is the **only** time the full token value is returned — it cannot be retrieved later from any endpoint or from the console.
</Warning>

## Revoking API Keys

Revoke API keys that are no longer needed or may have been compromised.

### Request

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://api.perplexity.ai/revoke_auth_token \
    --header "Authorization: Bearer $PERPLEXITY_API_KEY" \
    --header "Content-Type: application/json" \
    --data '{
      "auth_token": "pplx-1234567890abcdef"
    }'
  ```

  ```python Python theme={null}
  import os
  import requests

  url = "https://api.perplexity.ai/revoke_auth_token"
  headers = {
      "Authorization": f"Bearer {os.environ.get('PERPLEXITY_API_KEY')}",
      "Content-Type": "application/json"
  }
  payload = {
      "auth_token": "pplx-1234567890abcdef"
  }

  response = requests.post(url, headers=headers, json=payload)
  if response.status_code == 200:
      print("API key successfully revoked")
  ```

  ```typescript Typescript theme={null}
  const response = await fetch("https://api.perplexity.ai/revoke_auth_token", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.PERPLEXITY_API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      auth_token: "pplx-1234567890abcdef"
    })
  });

  if (response.status === 200) {
    console.log("API key successfully revoked");
  }
  ```
</CodeGroup>

### Response

Returns a `200 OK` status code on successful revocation.

## API Key Rotation

Regular key rotation is a security best practice that minimizes the impact of potential key compromises. Here's how to implement zero-downtime key rotation:

### Rotation Strategy

<Steps>
  <Step title="Generate New Key">
    Create a new API key while your current key is still active:

    ```python theme={null}
    # Generate new key
    new_key_response = requests.post(
        "https://api.perplexity.ai/generate_auth_token",
        headers={"Authorization": f"Bearer {current_key}"},
        json={"token_name": f"Rotated Key - {datetime.now().isoformat()}"}
    )
    new_key = new_key_response.json()["auth_token"]
    ```
  </Step>

  <Step title="Update Applications">
    Deploy the new key to your applications:

    ```python theme={null}
    # Update environment variables or secrets management
    os.environ["PERPLEXITY_API_KEY"] = new_key

    # Verify new key works
    test_response = requests.post(
        "https://api.perplexity.ai/v1/agent",
        headers={"Authorization": f"Bearer {new_key}"},
        json={
            "preset": "low",
            "input": "Test"
        }
    )
    assert test_response.status_code == 200
    ```
  </Step>

  <Step title="Monitor Transition">
    Ensure all services are using the new key before proceeding:

    ```python theme={null}
    # Monitor your application logs to confirm
    # all instances are using the new key
    time.sleep(300)  # Wait for propagation
    ```
  </Step>

  <Step title="Revoke Old Key">
    Once confirmed, revoke the old key:

    ```python theme={null}
    # Revoke old key
    revoke_response = requests.post(
        "https://api.perplexity.ai/revoke_auth_token",
        headers={"Authorization": f"Bearer {new_key}"},
        json={"auth_token": current_key}
    )
    assert revoke_response.status_code == 200
    print("Key rotation completed successfully")
    ```
  </Step>
</Steps>

### Automated Rotation Example

Here's a complete example of an automated key rotation script:

<CodeGroup>
  ```python Python theme={null}
  import requests
  import os
  import time
  from datetime import datetime
  import logging

  logging.basicConfig(level=logging.INFO)
  logger = logging.getLogger(__name__)

  class PerplexityKeyRotator:
      def __init__(self, current_key):
          self.base_url = "https://api.perplexity.ai"
          self.current_key = current_key

      def generate_new_key(self, name=None):
          """Generate a new API key"""
          url = f"{self.base_url}/generate_auth_token"
          headers = {"Authorization": f"Bearer {self.current_key}"}
          payload = {}
          if name:
              payload["token_name"] = name

          response = requests.post(url, headers=headers, json=payload)
          response.raise_for_status()
          return response.json()

      def test_key(self, key):
          """Test if a key is valid"""
          url = f"{self.base_url}/v1/agent"
          headers = {"Authorization": f"Bearer {key}"}
          payload = {
              "preset": "low",
              "input": "Test",
              "max_output_tokens": 1
          }

          try:
              response = requests.post(url, headers=headers, json=payload)
              return response.status_code == 200
          except:
              return False

      def revoke_key(self, key_to_revoke):
          """Revoke an API key"""
          url = f"{self.base_url}/revoke_auth_token"
          headers = {"Authorization": f"Bearer {self.current_key}"}
          payload = {"auth_token": key_to_revoke}

          response = requests.post(url, headers=headers, json=payload)
          return response.status_code == 200

      def rotate_key(self, update_callback=None):
          """Perform complete key rotation"""
          logger.info("Starting key rotation...")

          # Step 1: Generate new key
          new_key_data = self.generate_new_key(
              name=f"Rotated-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
          )
          new_key = new_key_data["auth_token"]
          logger.info(f"New key generated: {new_key[:10]}...")

          # Step 2: Test new key
          if not self.test_key(new_key):
              raise Exception("New key validation failed")
          logger.info("New key validated successfully")

          # Step 3: Update application (callback)
          if update_callback:
              update_callback(new_key)
              logger.info("Application updated with new key")

          # Step 4: Wait for propagation
          logger.info("Waiting for propagation...")
          time.sleep(30)

          # Step 5: Revoke old key
          old_key = self.current_key
          self.current_key = new_key  # Use new key for revocation

          if self.revoke_key(old_key):
              logger.info("Old key revoked successfully")
          else:
              logger.warning("Failed to revoke old key")

          logger.info("Key rotation completed")
          return new_key

  # Usage example
  def update_environment(new_key):
      """Update your environment with the new key"""
      os.environ["PERPLEXITY_API_KEY"] = new_key
      # Update your secrets management system here
      # update_aws_secrets_manager(new_key)
      # update_kubernetes_secret(new_key)

  # Perform rotation
  rotator = PerplexityKeyRotator(os.environ["PERPLEXITY_API_KEY"])
  new_key = rotator.rotate_key(update_callback=update_environment)
  print(f"Rotation complete. New key: {new_key[:10]}...")
  ```

  ```typescript Typescript theme={null}
  import fetch from 'node-fetch';

  class PerplexityKeyRotator {
    private baseUrl = 'https://api.perplexity.ai';
    private currentKey: string;

    constructor(currentKey: string) {
      this.currentKey = currentKey;
    }

    async generateNewKey(name?: string): Promise<{
      auth_token: string;
      created_at_epoch_seconds: number;
      token_name?: string;
    }> {
      const response = await fetch(`${this.baseUrl}/generate_auth_token`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.currentKey}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(name ? { token_name: name } : {})
      });

      if (!response.ok) {
        throw new Error(`Failed to generate key: ${response.statusText}`);
      }

      return response.json();
    }

    async testKey(key: string): Promise<boolean> {
      try {
        const response = await fetch(`${this.baseUrl}/v1/agent`, {
          method: 'POST',
          headers: {
            'Authorization': `Bearer ${key}`,
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            preset: 'low',
            input: 'Test',
            max_output_tokens: 1
          })
        });

        return response.ok;
      } catch {
        return false;
      }
    }

    async revokeKey(keyToRevoke: string): Promise<boolean> {
      const response = await fetch(`${this.baseUrl}/revoke_auth_token`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.currentKey}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ auth_token: keyToRevoke })
      });

      return response.ok;
    }

    async rotateKey(updateCallback?: (newKey: string) => Promise<void>): Promise<string> {
      console.log('Starting key rotation...');

      // Step 1: Generate new key
      const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
      const newKeyData = await this.generateNewKey(`Rotated-${timestamp}`);
      const newKey = newKeyData.auth_token;
      console.log(`New key generated: ${newKey.substring(0, 10)}...`);

      // Step 2: Test new key
      if (!(await this.testKey(newKey))) {
        throw new Error('New key validation failed');
      }
      console.log('New key validated successfully');

      // Step 3: Update application
      if (updateCallback) {
        await updateCallback(newKey);
        console.log('Application updated with new key');
      }

      // Step 4: Wait for propagation
      console.log('Waiting for propagation...');
      await new Promise(resolve => setTimeout(resolve, 30000));

      // Step 5: Revoke old key
      const oldKey = this.currentKey;
      this.currentKey = newKey;

      if (await this.revokeKey(oldKey)) {
        console.log('Old key revoked successfully');
      } else {
        console.warn('Failed to revoke old key');
      }

      console.log('Key rotation completed');
      return newKey;
    }
  }

  // Usage example
  async function updateEnvironment(newKey: string): Promise<void> {
    process.env.PERPLEXITY_API_KEY = newKey;
    // Update your secrets management system here
    // await updateAwsSecretsManager(newKey);
    // await updateKubernetesSecret(newKey);
  }

  // Perform rotation
  const rotator = new PerplexityKeyRotator(process.env.PERPLEXITY_API_KEY!);
  const newKey = await rotator.rotateKey(updateEnvironment);
  console.log(`Rotation complete. New key: ${newKey.substring(0, 10)}...`);
  ```
</CodeGroup>

## Best Practices

<CardGroup>
  <Card title="Use Environment Variables">
    Never hardcode API keys in your source code. Store them in environment variables or secure secret management systems.

    **Good**: `os.environ["PERPLEXITY_API_KEY"]`

    **Bad**: `api_key = "pplx-1234567890abcdef"`
  </Card>

  <Card title="Implement Key Rotation">
    Rotate your API keys regularly (e.g., every 90 days) to minimize the impact of potential compromises.

    Set up automated rotation scripts to ensure zero downtime during the rotation process.
  </Card>

  <Card title="Use Descriptive Names">
    Always set `token_name` when generating a key. After creation, the name is the primary way to identify a key, since the full token value is no longer visible.

    Examples: "Production-Main", "Development-Testing", "CI/CD-Pipeline"
  </Card>

  <Card title="Monitor Key Usage">
    Track which keys are being used in your applications and revoke unused keys promptly.

    Maintain an inventory of active keys and their purposes.
  </Card>
</CardGroup>

## Security Considerations

<Warning>
  **Never expose API keys in:**

  * Client-side JavaScript code
  * Mobile applications
  * Public repositories
  * Log files or error messages
  * URLs or query parameters
</Warning>

### If a Key is Compromised

1. **Immediately generate a new key** using `/generate_auth_token`
2. **Update all applications** to use the new key
3. **Revoke the compromised key** using `/revoke_auth_token`
4. **Review access logs** to identify any unauthorized usage
5. **Implement additional security measures** such as IP allowlisting if available

## Troubleshooting

| Issue                                  | Solution                                                         |
| -------------------------------------- | ---------------------------------------------------------------- |
| "Authentication failed" after rotation | Ensure the new key has propagated to all service instances       |
| Cannot revoke a key                    | Verify you're using a valid API key with appropriate permissions |
| Key generation fails                   | Check your account status and API tier limits                    |
| Services still using old key           | Implement proper secret rotation in your deployment pipeline     |

<Info>
  For additional support with API key management, visit the [API Keys page](https://console.perplexity.ai/group/keys) in the API Console or contact our support team.
</Info>


# Computer Analytics API
Source: https://docs.perplexity.ai/docs/admin/computer-analytics-api

Query your organization's Computer usage analytics programmatically with a free, org-scoped API key

## Overview

The Computer Analytics API gives Perplexity Enterprise organizations programmatic access to the same Computer usage analytics shown in the web dashboard — credits, connectors, artifacts, skills, spaces, workflows, and task durations — as bucketed time series you can pull into BI tools or internal reporting. Credit usage can also be broken down [per member](#per-member-usage).

Analytics requests are free and don't consume API credits.

<Info>
  This API is available to Perplexity Enterprise organizations. If you don't see the Analytics API toggle described below, the feature may not be enabled for your organization yet — contact your Perplexity representative.
</Info>

## Getting Access

Access is managed by your organization's admins from the Perplexity web app:

<Steps>
  <Step title="Enable the Analytics API">
    In the Perplexity web app, open your organization's **Computer** settings and find the **Analytics** section. Turn on **Analytics API** to provision API access for your organization.
  </Step>

  <Step title="Generate your API key">
    In the row that appears below the toggle, select **Generate key**.
  </Step>
</Steps>

A few properties of analytics API keys:

* **Org-scoped, admin-managed** — the key belongs to your organization, not to the admin who created it. Any org admin can view the current key and regenerate it.
* **One active key** — your organization has at most one active analytics key. Regenerating revokes the previous key.
* **Analytics-only** — the key authenticates analytics endpoints only; it cannot call other Perplexity APIs and has no billing attached.
* **Disabling revokes** — turning the Analytics API toggle off permanently revokes the key.

## Authentication

Pass the key as a bearer token:

```bash theme={null}
curl --request GET \
  --url "https://api.perplexity.ai/v1/analytics/computer/usage?dataset=credit_usage&start_time=1746057600" \
  --header "Authorization: Bearer YOUR_API_KEY"
```

## Querying Usage

`GET /v1/analytics/computer/usage` returns one time series per request, for a single dataset.

### Parameters

| Parameter      | Required | Description                                                                                                                   |
| -------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `dataset`      | Yes      | One of `credit_usage`, `connectors`, `artifacts`, `skills`, `spaces`, `workflows`, `task_durations`.                          |
| `start_time`   | Yes      | Window start, unix seconds (UTC). Inclusive. Snapped down to the bucket grid.                                                 |
| `end_time`     | No       | Window end, unix seconds (UTC). Exclusive. Defaults to now; values in the future are capped at now.                           |
| `bucket_width` | No       | `1d` (default) or `1h`. Buckets align to the UTC grid.                                                                        |
| `limit`        | No       | Buckets per page. `1d`: default 7, max 31. `1h`: default 24, max 168.                                                         |
| `page`         | No       | Opaque pagination cursor from a previous response's `next_page`. Valid only with the same query parameters it was issued for. |
| `user_email`   | No       | Restrict results to a single member of your organization. See [Filtering by member](#filtering-by-member).                    |

### Response

```json theme={null}
{
  "categories": ["Model", "Credit Source"],
  "data": [
    {
      "start_time": 1746057600,
      "end_time": 1746144000,
      "count": 350,
      "by_categories": {
        "Model": [
          { "category": "claude-opus-4-8", "count": 210 },
          { "category": "claude-sonnet-4-6", "count": 120 }
        ],
        "Credit Source": [
          { "category": "paid", "count": 250 },
          { "category": "promo", "count": 80 }
        ]
      }
    }
  ],
  "has_more": false,
  "next_page": null
}
```

* `categories` lists the breakdown axes the dataset surfaces, in canonical render order. Most datasets carry one axis; `credit_usage` carries two (`Model` and `Credit Source`).
* `data` contains every bucket in the page's window, in chronological order. Buckets without data carry `count: 0` and an empty list under each axis in `by_categories`.
* `by_categories` maps each axis label to its breakdown for the bucket. Categories within an axis are the dataset's dimension values — connector names for `connectors`, artifact types for `artifacts`, duration bands for `task_durations`, `paid`/`promo` for `credit_usage`'s `Credit Source`, model names for `credit_usage`'s `Model`, and the titles your members gave the items for `spaces`/`skills`/`workflows`.
* For `credit_usage`, `count` can exceed the sum of any single breakdown — usage without a category attribution counts toward the total but not the breakdown.

### Time Windows and Buckets

The API serves **complete UTC grid buckets only**:

* `start_time` snaps down to the start of its bucket, so the first bucket can include usage from before your requested start.
* `end_time` is exclusive and is capped at the current time, then snapped down — the in-progress bucket is never returned. With `bucket_width=1d`, today's bucket is not included; use `1h` for intraday data.
* A valid window that contains no complete buckets returns `200` with empty `data`.

<Note>
  **Data freshness.** The analytics store is synced periodically, not in real time. A `count` of `0` in a recent bucket can mean the data hasn't synced yet rather than zero usage. When `has_more` is `false` you have reached the current data frontier — poll again later for newer buckets.
</Note>

### Pagination

When the window spans more buckets than `limit`, the response sets `has_more: true` and a `next_page` cursor. Pass it back as `page`, keeping every other parameter identical — cursors are strictly validated and a cursor used with different parameters returns `400`.

```python theme={null}
import requests

BASE_URL = "https://api.perplexity.ai/v1/analytics/computer/usage"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}

params = {
    "dataset": "credit_usage",
    "start_time": 1746057600,
    "bucket_width": "1d",
}

buckets = []
while True:
    response = requests.get(BASE_URL, headers=HEADERS, params=params)
    response.raise_for_status()
    payload = response.json()
    buckets.extend(payload["data"])
    if not payload["has_more"]:
        break
    params["page"] = payload["next_page"]

print(f"Fetched {len(buckets)} buckets")
```

### Filtering by Member

Pass `user_email` to restrict the series to a single member of your organization:

```bash theme={null}
curl --request GET \
  --url "https://api.perplexity.ai/v1/analytics/computer/usage?dataset=credit_usage&start_time=1746057600&user_email=member@example.com" \
  --header "Authorization: Bearer YOUR_API_KEY"
```

The email must belong to a current member of your organization. Any other value — including emails with no Perplexity account — returns the same generic `400`:

```json theme={null}
{
  "error": {
    "message": "user_email does not match a member of this organization.",
    "type": "invalid_request",
    "code": 400
  }
}
```

## Per-Member Usage

`GET /v2/analytics/computer/usage` breaks credit usage down **per member** instead of as a single org total. It returns daily buckets, each listing one row per member who used credits that day, keyed by email — with the same `Model` and `Credit Source` breakdown v1 carries. It uses the same API key, error envelope, and limits as v1.

Per-member grouping is available for `credit_usage` at daily granularity today. `dataset` and `group_by` are both parameters so more datasets and groupings can be added later without a breaking change.

```bash theme={null}
curl --request GET \
  --url "https://api.perplexity.ai/v2/analytics/computer/usage?dataset=credit_usage&group_by=user_email&start_time=1746057600" \
  --header "Authorization: Bearer YOUR_API_KEY"
```

### Parameters

| Parameter    | Required | Description                                                                                                                   |
| ------------ | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `dataset`    | Yes      | Must be `credit_usage` — the only dataset with per-member grouping today.                                                     |
| `group_by`   | Yes      | Must be `user_email` — the only grouping today.                                                                               |
| `start_time` | Yes      | Window start, unix seconds (UTC). Inclusive. Snapped down to the day grid.                                                    |
| `end_time`   | No       | Window end, unix seconds (UTC). Exclusive. Defaults to now; values in the future are capped at now.                           |
| `limit`      | No       | Member rows per page. Default 50, max 100. A page can span multiple days.                                                     |
| `page`       | No       | Opaque pagination cursor from a previous response's `next_page`. Valid only with the same query parameters it was issued for. |

### Response

```json theme={null}
{
  "categories": ["Model", "Credit Source"],
  "data": [
    {
      "start_time": 1746057600,
      "end_time": 1746144000,
      "results": [
        {
          "user_email": "alice@example.com",
          "count": 900,
          "by_categories": {
            "Model": [{ "category": "claude-opus-4-8", "count": 900 }],
            "Credit Source": [{ "category": "paid", "count": 900 }]
          }
        },
        {
          "user_email": "bob@example.com",
          "count": 500,
          "by_categories": {
            "Model": [{ "category": "claude-sonnet-4-6", "count": 500 }],
            "Credit Source": [{ "category": "promo", "count": 500 }]
          }
        }
      ]
    }
  ],
  "has_more": true,
  "next_page": "eyJwayI6ICJPUkcjLi4uIn0="
}
```

* Each `data` entry is one UTC day; `results` holds one row per member with usage that day, in `(day, member)` order. Days with no usage are omitted rather than returned empty.
* `user_email` identifies the member. `count` is the member's credits for the day, and `by_categories` carries the same axes as v1's `categories`.
* Time-window and bucket semantics match v1's `1d` mode — complete UTC days only, and the same [freshness](#time-windows-and-buckets) caveat applies.

### Paginating Members

v2 paginates over **member rows**, not days — a single page can span several days, and each member's day counts as one row toward `limit`. Page until `has_more` is `false`, passing `next_page` back as `page` with every other parameter unchanged:

```python theme={null}
import requests

BASE_URL = "https://api.perplexity.ai/v2/analytics/computer/usage"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}

params = {
    "dataset": "credit_usage",
    "group_by": "user_email",
    "start_time": 1746057600,
}

days = []
while True:
    response = requests.get(BASE_URL, headers=HEADERS, params=params)
    response.raise_for_status()
    payload = response.json()
    days.extend(payload["data"])
    if not payload["has_more"]:
        break
    params["page"] = payload["next_page"]

print(f"Fetched {len(days)} daily buckets")
```

## Errors

Errors use a consistent envelope:

```json theme={null}
{
  "error": {
    "message": "Human-readable description.",
    "type": "machine_readable_type",
    "code": 400
  }
}
```

| Status | `type`                        | Meaning                                                                                                                                                                                      |
| ------ | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | `bad_request`                 | A parameter failed validation (wrong type, malformed value).                                                                                                                                 |
| `400`  | `invalid_request`             | Parameters are well-formed but semantically invalid — e.g. `start_time` after `end_time`, a window over 90 days, a misused pagination cursor, or a `user_email` that doesn't match a member. |
| `401`  | `unauthorized`                | Missing or invalid API key.                                                                                                                                                                  |
| `404`  | `feature_disabled`            | The Computer Analytics API is not enabled for your organization.                                                                                                                             |
| `429`  | `request_rate_limit_exceeded` | Rate limit exceeded. Requests are limited per organization across all of its keys; retry with backoff.                                                                                       |

## Limits

* Time windows are limited to **90 days** per request (paginate within the window for long ranges).
* Requests are rate-limited **per organization** — all keys minted by your org share one allowance.


# Rate Limits & Usage Tiers
Source: https://docs.perplexity.ai/docs/admin/rate-limits-usage-tiers



## What are Usage Tiers?

Usage tiers determine your **rate limits** and access to **beta features** based on your cumulative API spending. As you spend more on API credits over time, you automatically advance to higher tiers with increased rate limits. Higher tiers unlock significantly more requests per minute, and once you reach a tier, you keep it permanently with no downgrade.

<Info>
  You can check your current usage tier on the [Pricing page](https://console.perplexity.ai/group/pricing?tab=usage-tiers) in the API Console.
</Info>

***

## Tier Progression

| Tier       | Total Credits Purchased | Status                       |
| ---------- | ----------------------- | ---------------------------- |
| **Tier 0** | \$0                     | New accounts, limited access |
| **Tier 1** | \$50+                   | Light usage, basic limits    |
| **Tier 2** | \$250+                  | Regular usage                |
| **Tier 3** | \$500+                  | Heavy usage                  |
| **Tier 4** | \$1,000+                | Production usage             |
| **Tier 5** | \$5,000+                | Enterprise usage             |

<Note>
  Tiers are based on **cumulative purchases** across your account lifetime, not current balance.
</Note>

***

## Router API Rate Limits

Router API requests are rate limited. When a request is rate limited, or an upstream model is overloaded, the API returns a `429` with a `Retry-After` header — retry after the indicated interval.

<Note>
  Requests rejected with a `429` are not billed.
</Note>

***

## Agent API Rate Limits

The Agent API uses tier-based rate limits that scale with your usage tier:

|    Tier    | QPS (Queries per Second) | Requests per Minute |
| :--------: | :----------------------: | :-----------------: |
| **Tier 0** |           1 QPS          |        50/min       |
| **Tier 1** |           3 QPS          |       150/min       |
| **Tier 2** |           8 QPS          |       500/min       |
| **Tier 3** |          17 QPS          |      1,000/min      |
| **Tier 4** |          33 QPS          |      2,000/min      |
| **Tier 5** |          33 QPS          |      2,000/min      |

***

## Search API Rate Limits

The Search API has separate rate limits that apply to all usage tiers:

| Endpoint       | Rate Limit                | Burst Capacity |
| -------------- | ------------------------- | -------------- |
| POST `/search` | 50 query units per second | 50 query units |

**Search Rate Limiter Behavior:**

* **Single-query request**: Consumes 1 query unit
* **Multi-query request**: Consumes 1 query unit for each query in the array
* **Burst**: Can consume 50 query units instantly
* **Sustained**: 50 query units per second on average

<Info>
  Billing and rate limiting use different units. A successful request containing five queries is one billable Search API request, but it consumes five rate-limit units. Search rate limits are independent of your usage tier and apply consistently across all accounts using the same leaky bucket algorithm. See [Search API pricing](/docs/getting-started/pricing#search-api-pricing) for billing details.
</Info>

***

## Sonar API Rate Limits

<SonarDeprecationNotice />

The Sonar API uses tier-based rate limits that scale with your usage tier:

<Tabs>
  <Tab title="Tier 0">
    | Model                              | Requests per minute (RPM) |
    | ---------------------------------- | ------------------------- |
    | `sonar-deep-research`              | 5                         |
    | `sonar-reasoning-pro`              | 50                        |
    | `sonar-pro`                        | 50                        |
    | `sonar`                            | 50                        |
    | POST `/v1/async/sonar`             | 5                         |
    | GET `/v1/async/sonar`              | 3000                      |
    | GET `/v1/async/sonar/{request_id}` | 6000                      |
  </Tab>

  <Tab title="Tier 1">
    | Model                              | Requests per minute (RPM) |
    | ---------------------------------- | ------------------------- |
    | `sonar-deep-research`              | 10                        |
    | `sonar-reasoning-pro`              | 150                       |
    | `sonar-pro`                        | 150                       |
    | `sonar`                            | 150                       |
    | POST `/v1/async/sonar`             | 10                        |
    | GET `/v1/async/sonar`              | 3000                      |
    | GET `/v1/async/sonar/{request_id}` | 6000                      |
  </Tab>

  <Tab title="Tier 2">
    | Model                              | Requests per minute (RPM) |
    | ---------------------------------- | ------------------------- |
    | `sonar-deep-research`              | 20                        |
    | `sonar-reasoning-pro`              | 500                       |
    | `sonar-pro`                        | 500                       |
    | `sonar`                            | 500                       |
    | POST `/v1/async/sonar`             | 20                        |
    | GET `/v1/async/sonar`              | 3000                      |
    | GET `/v1/async/sonar/{request_id}` | 6000                      |
  </Tab>

  <Tab title="Tier 3">
    | Model                              | Requests per minute (RPM) |
    | ---------------------------------- | ------------------------- |
    | `sonar-deep-research`              | 40                        |
    | `sonar-reasoning-pro`              | 1,000                     |
    | `sonar-pro`                        | 1,000                     |
    | `sonar`                            | 1,000                     |
    | POST `/v1/async/sonar`             | 40                        |
    | GET `/v1/async/sonar`              | 3000                      |
    | GET `/v1/async/sonar/{request_id}` | 6000                      |
  </Tab>

  <Tab title="Tier 4">
    | Model                              | Requests per minute (RPM) |
    | ---------------------------------- | ------------------------- |
    | `sonar-deep-research`              | 60                        |
    | `sonar-reasoning-pro`              | 4,000                     |
    | `sonar-pro`                        | 4,000                     |
    | `sonar`                            | 4,000                     |
    | POST `/v1/async/sonar`             | 60                        |
    | GET `/v1/async/sonar`              | 3000                      |
    | GET `/v1/async/sonar/{request_id}` | 6000                      |
  </Tab>

  <Tab title="Tier 5">
    | Model                              | Requests per minute (RPM) |
    | ---------------------------------- | ------------------------- |
    | `sonar-deep-research`              | 100                       |
    | `sonar-reasoning-pro`              | 4,000                     |
    | `sonar-pro`                        | 4,000                     |
    | `sonar`                            | 4,000                     |
    | POST `/v1/async/sonar`             | 100                       |
    | GET `/v1/async/sonar`              | 3000                      |
    | GET `/v1/async/sonar/{request_id}` | 6000                      |
  </Tab>
</Tabs>

***

## Embeddings API Rate Limits

The Embeddings API uses tier-based rate limits that scale with your usage tier. Limits are higher than other APIs because each request is a single forward pass on an elastic backend.

|      Tier     | QPS (Queries per Second) |
| :-----------: | :----------------------: |
|   **Tier 0**  |          85 QPS          |
| **Tiers 1–3** |          170 QPS         |
| **Tiers 4–5** |          335 QPS         |

### Contextualized Embeddings

Contextualized embeddings have separate, higher limits (5× the standard embeddings tiers):

|      Tier     | QPS (Queries per Second) |
| :-----------: | :----------------------: |
|   **Tier 0**  |          415 QPS         |
| **Tiers 1–3** |          835 QPS         |
| **Tiers 4–5** |         1,670 QPS        |

<Note>
  Contextualized embeddings are rate limited by **total chunks**, not by request count.
</Note>

***

## How Rate Limiting Works

Our rate limiting system uses a **leaky bucket algorithm** that allows for burst traffic while maintaining strict long-term rate control.

### Technical Implementation

<AccordionGroup>
  <Accordion title="Leaky Bucket Algorithm Explained">
    The leaky bucket algorithm works like a bucket with a small hole in the bottom:

    * **Bucket Capacity**: Maximum number of requests you can make instantly (burst capacity)
    * **Leak Rate**: How quickly tokens leak out of the bucket (your rate limit)
    * **Token Refill**: Tokens refill continuously at regular intervals based on your rate limit

    This design allows legitimate burst traffic when you need it, prevents sustained abuse, and ensures predictable and fair rate enforcement across all users.
  </Accordion>

  <Accordion title="Rate Limiter Behavior Example">
    Let's examine how **50 requests per second** works in practice. With a capacity of 50 tokens and a leak rate of 50 tokens per second, one token refills every 20ms.

    **Scenario 1: Burst Traffic**

    ```
    Time 0.0s: Bucket full (50 tokens)
    → Send 50 requests instantly → ALL ALLOWED
    → Send 51st request → REJECTED (bucket empty)

    Time 0.020s: 1 token refilled
    → Send 1 request → ALLOWED
    → Send 2nd request → REJECTED

    Time 0.040s: 1 more token refilled
    → Send 1 request → ALLOWED
    ```

    **Scenario 2: Steady 50 QPS**

    ```
    Request every 20ms:
    Time 0.0s: Request → ALLOWED (50→49 tokens)
    Time 0.020s: Request → ALLOWED (49+1-1=49 tokens)
    Time 0.040s: Request → ALLOWED (49+1-1=49 tokens)
    ... maintains 49-50 tokens, all requests pass
    ```

    **Scenario 3: Slightly Over 50 QPS**

    ```
    Request every 19ms (≈52.6 QPS):
    → Eventually tokens deplete faster than refill
    → Some requests start getting rejected
    → Achieves exactly 50 QPS on average
    ```
  </Accordion>

  <Accordion title="Real-World Implications">
    The leaky bucket design means you can handle your full rate limit instantly, making it perfect for batch operations or sudden traffic spikes. There's no need to artificially spread requests when you have available burst capacity.

    The system enforces strict average rate limits over time while allowing quick recovery after burst usage. This provides consistent performance across different usage patterns and prevents sustained over-limit usage while maintaining fair resource allocation.

    When building your application, take advantage of burst capacity for batch operations, monitor your usage patterns to optimize request timing, and implement proper error handling for 429 responses.
  </Accordion>
</AccordionGroup>

***

## What Happens When You Hit Rate Limits?

When you exceed your rate limits:

1. **429 Error** - Your request gets rejected with "Too Many Requests"
2. **Continuous Refill** - Tokens refill continuously based on your rate limit
3. **Immediate Recovery** - New requests become available as soon as tokens refill

**Example Recovery Times:**

* **50 QPS limit**: 1 token refills every 20ms
* **500 QPS limit**: 1 token refills every 2ms
* **1,000 QPS limit**: 1 token refills every 1ms

<Tip>
  **Best Practices:**

  * Monitor your usage to predict when you'll need higher tiers
  * Consider upgrading your tier proactively for production applications
  * Implement exponential backoff with jitter in your code
  * Take advantage of burst capacity for batch operations
  * Don't artificially spread requests if you have available burst capacity
</Tip>

***

## Upgrading Your Tier

<Steps>
  <Step title="Check Current Tier">
    Open [Usage tiers](https://console.perplexity.ai/group/pricing?tab=usage-tiers) in the API Console to see your current tier and the purchase threshold for each tier.
  </Step>

  <Step title="Purchase More Credits">
    Add credits to your account through the billing section. Your tier will automatically upgrade once you reach the spending threshold.
  </Step>

  <Step title="Verify Upgrade">
    Your new rate limits take effect immediately after the tier upgrade. Check your settings page to confirm.
  </Step>

  <Step title="Need Even Higher Limits?">
    If you require custom rate limits beyond Tier 5, [fill out our rate limit increase request form](https://perplexity.typeform.com/to/yctmfyVT) and we'll review your use case to accommodate your needs.
  </Step>
</Steps>

<Check>
  Higher tiers significantly improve your API experience with increased rate limits, especially important for production applications.
</Check>

<Card title="Need Higher Rate Limits?" icon="file-pencil" href="https://perplexity.typeform.com/to/yctmfyVT">
  Need custom rate limits beyond your current tier? Fill out our rate limit increase request form and we'll review your use case to accommodate your needs.
</Card>


# Signing In to the API Portal
Source: https://docs.perplexity.ai/docs/admin/signing-in

Sign in to the Perplexity API Portal with Google, Apple, single sign-on, or a passwordless email code.

The [API Portal](https://console.perplexity.ai) offers four ways to sign in. All four create or reuse the same Perplexity account — you do not need to pick one at sign-up and stick with it.

<Frame>
  <img alt="API Platform login page with Continue with Google, Continue with Apple, Single sign-on (SSO), and Continue with email options" />
</Frame>

## Choosing a Sign-In Option

| Option                   | Best for                                                                   |
| ------------------------ | -------------------------------------------------------------------------- |
| **Continue with Google** | Individuals and teams using a Google Workspace or personal Google account. |
| **Continue with Apple**  | Individuals who prefer Sign in with Apple, including Hide My Email.        |
| **Single sign-on (SSO)** | Members of a Perplexity organization with SSO configured on their domain.  |
| **Continue with email**  | Anyone — sends a passwordless magic link and one-time code to your inbox.  |

<Info>
  Signing in creates a Perplexity account, but it does not create an API project on its own. After your first sign-in, the setup wizard prompts you to create or join an API group before you can generate a key. See [API Groups & Billing](/docs/getting-started/api-groups).
</Info>

***

## Continue With Google

Use Google to sign in with any Google or Google Workspace account.

<Steps>
  <Step title="Click Continue With Google">
    On the login page, click **Continue with Google** and choose the Google account you want to use.
  </Step>

  <Step title="Approve the Sign-In">
    Google asks you to confirm the sign-in and share your name, email, and profile picture with Perplexity. Approve to continue.
  </Step>

  <Step title="Land in the API Portal">
    You are returned to the API Portal signed in. If this is your first visit, the setup wizard walks you through creating an API group.
  </Step>
</Steps>

<Tip>
  If you already have a Perplexity account with the same email address, signing in with Google connects Google to that existing account — you keep your API groups, keys, and history.
</Tip>

***

## Continue With Apple

Use Sign in with Apple, including the Hide My Email relay address.

<Steps>
  <Step title="Click Continue With Apple">
    On the login page, click **Continue with Apple** and authenticate with Face ID, Touch ID, or your Apple ID password.
  </Step>

  <Step title="Choose Your Email Preference">
    Apple lets you share your real email or use **Hide My Email** to generate a private relay address. Perplexity uses whichever address Apple returns.
  </Step>

  <Step title="Land in the API Portal">
    You are returned to the API Portal signed in. If this is your first visit, the setup wizard walks you through creating an API group.
  </Step>
</Steps>

<Warning>
  If you already have a Perplexity account under your real email and later choose **Hide My Email**, Apple returns a different address and creates a separate account. Pick one email preference and stick with it, or contact [api@perplexity.ai](mailto:api@perplexity.ai) if you need accounts merged.
</Warning>

***

## Single Sign-On (SSO)

SSO lets your organization sign in through your own identity provider (Okta, Azure AD, Google Workspace SAML, and other SAML or OIDC IdPs). It works for organizations that have set up SSO on a verified domain.

<Note>
  SSO is available to admins of **Perplexity organizations with an active organization subscription** (paid or eligible trial). SSO is not available on personal Pro or Max plans, and it cannot be enabled with API-only billing — your organization must exist as a Perplexity organization in the main Perplexity app first. If your team doesn't have a Perplexity organization yet, [talk to Sales](https://www.perplexity.ai/enterprise/contact-sales).
</Note>

### Signing In With SSO

<Steps>
  <Step title="Click Single Sign-On (SSO)">
    On the login page, click **Single sign-on (SSO)**. The form switches to a work-email prompt.

    <Frame>
      <img alt="Single sign-on view with Work email field, Continue with SSO button, and Back to all options link" />
    </Frame>
  </Step>

  <Step title="Enter Your Work Email">
    Enter the email address on your organization's verified domain and click **Continue with SSO**. Use **Back to all options** if you need to return to the other sign-in methods.
  </Step>

  <Step title="Authenticate With Your IdP">
    You are redirected to your organization's identity provider. Complete the sign-in there — including any MFA prompts — and you are returned to the API Portal.
  </Step>
</Steps>

<Note>
  If you see **"SSO is not available for this email address"**, SSO has not been configured for your domain yet. Ask your organization admin to complete the setup steps below, or use one of the other sign-in options.
</Note>

### Configuring SSO for Your Organization

SSO is configured once in your organization's Perplexity organization settings — not in the API Portal — and applies to sign-in across Perplexity, including the API Portal.

For more help setting up SSO on Perplexity Enterprise, visit the [Single Sign-On collection in the Perplexity Help Center](https://www.perplexity.ai/help-center/en/collections/16665790-single-sign-on).

<Steps>
  <Step title="Confirm Eligibility">
    Your organization must have an **active organization subscription** in the main Perplexity app. An active trial qualifies. If billing is not set up yet, the settings page shows **"Complete payment to begin setup"** instead of the enable button. There is no minimum seat count for SSO itself.
  </Step>

  <Step title="Open Identity Settings">
    As an organization admin, go to [**Settings → Identity**](https://www.perplexity.ai/account/org/identity) in the main Perplexity app. You need the **Admin** role on the organization.
  </Step>

  <Step title="Verify a Domain">
    Add and verify at least one domain (for example, `yourcompany.com`) that your team uses for email. Verification is done through a DNS record.
  </Step>

  <Step title="Connect Your Identity Provider">
    Click **Begin setup** and follow the self-serve portal to connect your IdP. The portal supports SAML 2.0 and OIDC connections and walks you through your specific IdP. For more help, visit the [Single Sign-On collection in the Perplexity Help Center](https://www.perplexity.ai/help-center/en/collections/16665790-single-sign-on).
  </Step>

  <Step title="Enable API Access for Your Organization">
    Make sure your organization has **API access** enabled so your SSO users can reach the API Portal after signing in. If members can sign in via SSO but cannot open the Portal, ask your org admin or [Sales](https://www.perplexity.ai/enterprise/contact-sales) to turn on API access for the organization.
  </Step>

  <Step title="(Optional) Require SSO">
    Once the IdP is active, you can enable **SSO required** on any verified domain. When required, everyone signing in from that domain — including Google, Apple, and email attempts — is routed through your IdP.
  </Step>
</Steps>

<Tip>
  Need help with SSO setup or want us to walk through it with you? Reach out to your Perplexity account team.
</Tip>

***

## Continue With Email

Email sign-in is passwordless. There is no password to set or remember.

<Steps>
  <Step title="Enter Your Email">
    Enter your email in the **Email** field and click **Continue with email**.
  </Step>

  <Step title="Check Your Inbox">
    You receive an email with both a **magic link** and a **temporary sign-in code**. Use whichever is more convenient — clicking the link on the same device signs you in immediately, and the code works on any device.
  </Step>

  <Step title="Land in the API Portal">
    Once verified, you are signed in. If this is your first visit, the setup wizard walks you through creating an API group.
  </Step>
</Steps>

<Note>
  If your email address is on a domain with **SSO required**, the email flow routes you to your organization's identity provider instead of sending a code.
</Note>

***

## Switching Between Sign-In Methods

You can use different sign-in methods at different times with the same account. If you first signed up with email and later click **Continue with Google** using the same address, Google is linked to your existing Perplexity account — your API groups, keys, and billing stay in place. The same applies to Apple and to switching back to email.

<Warning>
  Account linking is based on your **email address**. Signing in with a different email — for example, a personal Google address vs. your work email — creates a separate account with its own API groups and keys. If you end up with two accounts by accident, contact [api@perplexity.ai](mailto:api@perplexity.ai).
</Warning>

***

## Next Steps

<CardGroup>
  <Card title="Set Up Your API Group" icon="layer-group" href="/docs/getting-started/api-groups">
    Create your organization's workspace, add billing, and invite teammates.
  </Card>

  <Card title="Create an API Key" icon="key" href="/docs/admin/api-key-management">
    Generate and manage keys once your API group is set up.
  </Card>

  <Card title="Make Your First Request" icon="rocket" href="/docs/getting-started/quickstart">
    Send a request to the Perplexity API in Python, TypeScript, or cURL.
  </Card>

  <Card title="Review Pricing" icon="receipt" href="/docs/getting-started/pricing">
    See per-model and per-tool pricing before you start.
  </Card>
</CardGroup>


# Background Mode
Source: https://docs.perplexity.ai/docs/agent-api/background-mode

Run long agentic tasks asynchronously — submit with background, poll by response id, stream, reconnect, and cancel.

## Overview

Long agentic runs, such as deep research or heavy sandbox work, can take several minutes. Background mode runs these tasks asynchronously so your application can avoid timeouts and dropped connections: submit the run, store its response id, then poll for the result. The run continues server-side even if your client disconnects.

## Submit a background request

Set `background=true` when you create the response. The submit endpoint is `POST https://api.perplexity.ai/v1/agent`. The create call returns a Response object immediately; store its `id` and check its initial `status`.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Research the current EV charging market and summarize the main segments.",
      tools=[{"type": "web_search"}, {"type": "sandbox"}],
      background=True,
  )

  print(f"Response ID: {response.id}")
  print(f"Status: {response.status}")
  ```

  ```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-sol',
    input: 'Research the current EV charging market and summarize the main segments.',
    tools: [{ type: 'web_search' }, { type: 'sandbox' }],
    background: true,
  });

  console.log(`Response ID: ${response.id}`);
  console.log(`Status: ${response.status}`);
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "input": "Research the current EV charging market and summarize the main segments.",
      "tools": [{ "type": "web_search" }, { "type": "sandbox" }],
      "background": true
    }' | jq '{id, status}'
  ```
</CodeGroup>

## Poll for the result

Poll a background response with `GET https://api.perplexity.ai/v1/agent/{id}`. A background response is non-terminal while its status is `queued` or `in_progress`. It is terminal when its status is `completed`, `failed`, `cancelled`, or `incomplete` (`incomplete` marks a run that stopped before finishing, for example on truncation).

Poll until the response reaches any terminal status, then branch based on the final state.

<CodeGroup>
  ```python Python theme={null}
  import time
  from perplexity import Perplexity

  client = Perplexity()


  def get_output_text(response) -> str:
      return "".join(
          content.text
          for item in response.output or []
          if getattr(item, "type", None) == "message"
          for content in getattr(item, "content", None) or []
          if getattr(content, "type", None) == "output_text"
      )


  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Write a sourced brief on grid-scale battery storage trends.",
      tools=[{"type": "web_search"}, {"type": "sandbox"}],
      background=True,
  )

  while response.status not in ("completed", "failed", "cancelled", "incomplete"):
      time.sleep(2)
      response = client.responses.retrieve(response.id)

  print(f"Final status: {response.status}")

  if response.status == "completed":
      print(get_output_text(response))
  elif response.status == "failed":
      print(response.error)
  elif response.status == "cancelled":
      print("The response was cancelled.")
  elif response.status == "incomplete":
      print("The response stopped before finishing.")
  ```

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

  const client = new Perplexity();

  let response = await client.responses.create({
    model: 'openai/gpt-5.6-sol',
    input: 'Write a sourced brief on grid-scale battery storage trends.',
    tools: [{ type: 'web_search' }, { type: 'sandbox' }],
    background: true,
  });

  while (!['completed', 'failed', 'cancelled', 'incomplete'].includes(response.status)) {
    await new Promise((resolve) => setTimeout(resolve, 2000));
    response = await client.responses.retrieve(response.id);
  }

  console.log(`Final status: ${response.status}`);

  if (response.status === 'completed') {
    console.log(response.output_text);
  } else if (response.status === 'failed') {
    console.log(response.error);
  } else if (response.status === 'cancelled') {
    console.log('The response was cancelled.');
  } else if (response.status === 'incomplete') {
    console.log('The response stopped before finishing.');
  }
  ```

  ```bash cURL theme={null}
  # 1. Submit the background run and save its id.
  RESPONSE_ID=$(curl -s https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "input": "Write a sourced brief on grid-scale battery storage trends.",
      "tools": [{ "type": "web_search" }, { "type": "sandbox" }],
      "background": true
    }' | jq -r '.id')

  # 2. Poll until the status is completed, failed, cancelled, or incomplete.
  while true; do
    RESPONSE=$(curl -s "https://api.perplexity.ai/v1/agent/$RESPONSE_ID" \
      -H "Authorization: Bearer $PERPLEXITY_API_KEY")

    STATUS=$(echo "$RESPONSE" | jq -r '.status')
    echo "Status: $STATUS"

    if [[ "$STATUS" == "completed" || "$STATUS" == "failed" || "$STATUS" == "cancelled" || "$STATUS" == "incomplete" ]]; then
      echo "$RESPONSE"
      break
    fi

    sleep 2
  done
  ```
</CodeGroup>

After the loop, handle each terminal status explicitly. For `completed`, read the output; for `failed`, inspect the `error` object; for `cancelled`, treat the run as intentionally stopped; for `incomplete`, treat the run as stopped before finishing (for example on truncation).

## Stream and reconnect

You can stream a long-running background response by creating it with both `background=true` and `stream=true`. Save the response id, and keep a cursor from the `sequence_number` on each streamed event. If the connection drops, reconnect with `GET /v1/agent/{id}?stream=true&starting_after=N` to resume after sequence number `N`.

<Info>
  Reconnect is only valid within the response's reconnect window. If that window expires, the reconnect request returns `400`; fall back to a plain `GET /v1/agent/{id}` to retrieve the final snapshot.
</Info>

<CodeGroup>
  ```python Python theme={null}
  import json
  import os
  import requests
  from perplexity import Perplexity

  client = Perplexity()

  response_id = None
  cursor = None

  stream = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Create a detailed research memo on satellite internet providers.",
      tools=[{"type": "web_search"}],
      background=True,
      stream=True,
  )

  for event in stream:
      cursor = getattr(event, "sequence_number", cursor)

      # Capture the response id from the first event that includes it.
      response = getattr(event, "response", None)
      if response_id is None and response is not None:
          response_id = getattr(response, "id", None)

      print(event)

  # If the stream disconnects after cursor N, resume from the next event.
  if response_id and cursor is not None:
      reconnect = requests.get(
          f"https://api.perplexity.ai/v1/agent/{response_id}",
          headers={"Authorization": f"Bearer {os.environ['PERPLEXITY_API_KEY']}"},
          params={"stream": "true", "starting_after": cursor},
          stream=True,
          timeout=60,
      )

      if reconnect.status_code == 400:
          final = client.responses.retrieve(response_id)
          print(final.status)
      else:
          reconnect.raise_for_status()
          for line in reconnect.iter_lines(decode_unicode=True):
              if not line or not line.startswith("data: "):
                  continue
              data = line.removeprefix("data: ")
              if data == "[DONE]":
                  break
              event = json.loads(data)
              cursor = event.get("sequence_number", cursor)
              print(event)
  ```

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

  const client = new Perplexity();

  let responseId: string | undefined;
  let cursor: number | undefined;

  const stream = await client.responses.create({
    model: 'openai/gpt-5.6-sol',
    input: 'Create a detailed research memo on satellite internet providers.',
    tools: [{ type: 'web_search' }],
    background: true,
    stream: true,
  });

  for await (const event of stream) {
    cursor = event.sequence_number;

    // Capture the response id from the first event that includes it.
    if (!responseId && 'response' in event && event.response) {
      responseId = event.response.id;
    }

    console.log(event);
  }

  // If the stream disconnects after cursor N, resume from the next event.
  if (responseId && cursor !== undefined) {
    const reconnect = await fetch(
      `https://api.perplexity.ai/v1/agent/${responseId}?stream=true&starting_after=${cursor}`,
      { headers: { Authorization: `Bearer ${process.env.PERPLEXITY_API_KEY}` } },
    );

    if (reconnect.status === 400) {
      // Reconnect window expired: fall back to the final snapshot.
      const final = await client.responses.retrieve(responseId);
      console.log(final.status);
    } else {
      // Parse the resumed SSE stream the same way, continuing from `cursor`.
      console.log(await reconnect.text());
    }
  }
  ```

  ```bash cURL theme={null}
  # 1. Start a background stream.
  curl -N https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "input": "Create a detailed research memo on satellite internet providers.",
      "tools": [{ "type": "web_search" }],
      "background": true,
      "stream": true
    }'

  # 2. If the connection drops, resume after the last sequence_number you received.
  curl -N "https://api.perplexity.ai/v1/agent/$RESPONSE_ID?stream=true&starting_after=$SEQUENCE_NUMBER" \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY"

  # 3. If reconnect returns 400, fetch the latest final snapshot instead.
  curl "https://api.perplexity.ai/v1/agent/$RESPONSE_ID" \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY"
  ```
</CodeGroup>

## Cancel a run

Cancel an in-flight background response with `POST https://api.perplexity.ai/v1/agent/{id}/cancel` when the result is no longer needed.
Cancellation is asynchronous: a `200` returns `status: "cancelling"` and the run stops shortly after, so poll `GET /v1/agent/{id}` for the terminal `cancelled` status.
Cancelling an already-terminal response returns `400`; an unknown id, or a response owned by a different account, returns `404`.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Run an extended literature review on heat pump adoption.",
      tools=[{"type": "web_search"}],
      background=True,
  )

  # Cancel it by id, then poll GET until the status is the terminal "cancelled".
  cancelled = client.responses.cancel(response.id)
  print(cancelled.response_id, cancelled.status)  # resp_... cancelling
  ```

  ```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-sol',
    input: 'Run an extended literature review on heat pump adoption.',
    tools: [{ type: 'web_search' }],
    background: true,
  });

  // Cancel it by id, then poll GET until the status is the terminal 'cancelled'.
  const cancelled = await client.responses.cancel(response.id);
  console.log(cancelled.response_id, cancelled.status); // resp_... cancelling
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.perplexity.ai/v1/agent/$RESPONSE_ID/cancel" \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY"
  ```
</CodeGroup>

## Next Steps

<CardGroup>
  <Card title="Working with files" icon="file" href="/docs/agent-api/working-with-files" />

  <Card title="Sandbox" icon="layer-group" href="/docs/agent-api/tools/sandbox" />

  <Card title="Wide Research" icon="bars" href="/docs/agent-api/wide-research" />

  <Card title="Streaming/output control" icon="clock" href="/docs/agent-api/output-control" />
</CardGroup>


# Define the run
Source: https://docs.perplexity.ai/docs/agent-api/building-agents/define-the-run

Configure the agent run: start from a preset, then customize the system prompt, the loop bound, and the model.

Every agent run begins with one Agent API request. Before prompts, tools, or output format, you decide what runs and how far it can go. The fastest way to start is a `preset` — a tuned bundle of model, system prompt, search config, and tools — which you then customize with individual settings as needed. This page sets up the call the rest of this section builds on.

## Start from a preset

A `preset` gives you a working agent in one field.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      preset="low",
      input="Give me a thorough overview of the current state of solid-state battery commercialization.",
  )

  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({
    preset: 'low',
    input: 'Give me a thorough overview of the current state of solid-state battery commercialization.',
  });

  console.log(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": "low",
      "input": "Give me a thorough overview of the current state of solid-state battery commercialization."
    }' | jq
  ```
</CodeGroup>

Other presets trade depth against latency and cost. See [Presets](/docs/agent-api/presets) for what each one bundles and how preset updates are managed.

## Customize the system prompt: `instructions`

A `preset` ships its own tuned system prompt. The `instructions` field **is** the agent's system prompt — the standing rules that hold for every turn of the loop: role, tone, citation, and grounding rules. They apply regardless of what the user asks on a given turn.

```python theme={null}
instructions="You are a research assistant. Cite every claim by source domain, and never speculate beyond the retrieved evidence."
```

Setting `instructions` **replaces** the preset's system prompt rather than appending to it. Omit `instructions` to keep the preset's prompt.

<Note>
  Keep the system prompt lean. Every token here is re-processed on each step of the loop, so it adds up across tool calls. For machine-readable output or retrieval constraints, prefer request parameters (see [Structure the output](/docs/agent-api/building-agents/shape-output) and [Give it tools](/docs/agent-api/building-agents/give-it-tools)) over prose rules.
</Note>

## Customize the loop: `max_steps`

An agent run is a loop: the model reasons, optionally calls tools, reads the results, and repeats until it answers. One step is one pass through that cycle — a single model turn that may call tools. `max_steps` caps how many steps a run may take. Use it to bound runaway loops and to trade latency against depth. When a run reaches the cap, the agent doesn't error — it makes one final pass to answer from what it has gathered so far.

A low `max_steps` doesn't disable tools — it limits how many times the agent can act on what they return. At `max_steps: 1` the model still gets one turn and can call a tool, but the run won't loop back to reason over the result.

```python theme={null}
response = client.responses.create(
    preset="low",
    input="Give me a thorough overview of the current state of solid-state battery commercialization.",
    max_steps=20,
)
```

If you pass `max_steps` alongside a `preset`, it overrides the preset's value, up to the preset's own ceiling for chat-style presets.

## Customize the model: `model` or `models`

A preset picks a model for you. When you need full control over which model answers, set one explicitly instead of (or alongside) a preset:

| Field    | What it is                                                                   |
| -------- | ---------------------------------------------------------------------------- |
| `model`  | A single model in `provider/model` format, for example `openai/gpt-5.6-sol`. |
| `models` | A fallback chain of up to 5 models, tried in order until one succeeds.       |

If you set `models`, it takes precedence over `model`. See [Models](/docs/agent-api/models) for the catalog and pricing, and [Model fallback](/docs/agent-api/model-fallback) for how the chain resolves.

<Tip>
  Start from a `preset`, then move to an explicit `model` (or `models` chain) when you need to pin the exact engine.
</Tip>

## Next steps

<CardGroup>
  <Card title="Prompt the agent" icon="message" href="/docs/agent-api/building-agents/prompt-the-agent">
    Split the system prompt from the question, and ground the run.
  </Card>

  <Card title="Presets" icon="stack-2" href="/docs/agent-api/presets">
    See the tuned presets you can start from.
  </Card>
</CardGroup>


# Give it tools
Source: https://docs.perplexity.ai/docs/agent-api/building-agents/give-it-tools

Enable built-in tools and your own custom tools in the tools array, let the model decide when to call them, and read the results back from the response.

A model on its own answers only from what it already knows. Tools let an agent go beyond that — search the live web, fetch a page, run code, or call into your own systems. You enable tools by listing them in the `tools` array, and the model decides when to call each one based on your prompt. This page covers wiring tools in and reading their output. For the full settings of any single tool, follow the link to its reference page.

## Three kinds of tools

| Kind           | How it works                                                                                                                                                                                    |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Built-in tools | Perplexity-hosted capabilities: web search, URL fetch, people and finance search, and a code sandbox. Enable each by `type`, and Perplexity runs it and returns the results inline.             |
| MCP servers    | Your own remote [MCP](/docs/agent-api/tools/mcp) server. The model discovers and calls the server's tools automatically, like the built-in ones — Perplexity relays each call to your server.   |
| Custom tools   | Bring your own — functions you control. You declare the schema, and when the model calls one, the run pauses and hands you the arguments to execute, then continues once you return the result. |

## Enable built-in tools

Add each tool to the `tools` array by its `type`. Most built-in tools work with just the type — some accept optional settings (documented on their reference pages).

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="What are the leading approaches to grid-scale energy storage, and how do they compare?",
      tools=[
          {"type": "web_search"},
          {"type": "fetch_url"},
      ],
      max_steps=10,
  )

  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-sol',
    input: 'What are the leading approaches to grid-scale energy storage, and how do they compare?',
    tools: [
      { type: 'web_search' as const },
      { type: 'fetch_url' as const },
    ],
    max_steps: 10,
  });

  console.log(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 '{
      "model": "openai/gpt-5.6-sol",
      "input": "What are the leading approaches to grid-scale energy storage, and how do they compare?",
      "tools": [
        { "type": "web_search" },
        { "type": "fetch_url" }
      ],
      "max_steps": 10
    }' | jq
  ```
</CodeGroup>

The built-in tools, each with its own reference page for full settings, response shape, and pricing:

| Tool                                                         | `type`           | Use it to                                                                                    |
| ------------------------------------------------------------ | ---------------- | -------------------------------------------------------------------------------------------- |
| [Sandbox](/docs/agent-api/tools/sandbox)                     | `sandbox`        | Run code in an isolated container — see [Run code](/docs/agent-api/building-agents/run-code) |
| [Web Search](/docs/agent-api/tools/web-search)               | `web_search`     | Search the live web, with domain/date/location filters                                       |
| [Fetch URL Content](/docs/agent-api/tools/fetch-url-content) | `fetch_url`      | Pull and extract content from specific URLs                                                  |
| [People Search](/docs/agent-api/tools/people-search)         | `people_search`  | Find professionals and people                                                                |
| [Finance Search](/docs/agent-api/tools/finance-search)       | `finance_search` | Retrieve structured financial and market data                                                |

<Tip>
  Let the model choose. You enable a tool, and the model decides whether and when to call it based on `input` and `instructions`.
</Tip>

## Connect an MCP server

Instead of hosting each tool yourself, connect a remote [Model Context Protocol](/docs/agent-api/tools/mcp) (MCP) server with `type: mcp`. Agent API discovers the server's tools when the request starts, and the model calls them automatically like the built-in ones — you don't handle each call yourself. The example below connects to the public [DeepWiki](https://deepwiki.com) MCP server, which needs no authentication.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Use DeepWiki to explain what the perplexityai/perplexity-py repository does.",
      tools=[
          {
              "type": "mcp",
              "server_label": "deepwiki",
              "server_url": "https://mcp.deepwiki.com/mcp",
          }
      ],
  )

  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-sol',
    input: 'Use DeepWiki to explain what the perplexityai/perplexity-py repository does.',
    tools: [
      {
        type: 'mcp',
        server_label: 'deepwiki',
        server_url: 'https://mcp.deepwiki.com/mcp',
      },
    ] as any, // The current SDK types do not yet include MCP tools.
  });

  console.log(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 '{
      "model": "openai/gpt-5.6-sol",
      "input": "Use DeepWiki to explain what the perplexityai/perplexity-py repository does.",
      "tools": [
        {
          "type": "mcp",
          "server_label": "deepwiki",
          "server_url": "https://mcp.deepwiki.com/mcp"
        }
      ]
    }' | jq
  ```
</CodeGroup>

For authentication, response items, and the full tool settings, see the [MCP reference](/docs/agent-api/tools/mcp).

## Add your custom tool

A custom tool (`type: function`) lets the agent call code you control — your database or an internal API. You declare it with a `name`, a `description`, and a JSON Schema for its `parameters`. The model fills in the arguments — you run the function. This is how the agent reaches data it can't know on its own — here, an order's current status in your internal system.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  tools = [
      {
          "type": "function",
          "name": "get_order_status",
          "description": "Look up the current status of an internal order by its order ID.",
          "parameters": {
              "type": "object",
              "properties": {"order_id": {"type": "string"}},
              "required": ["order_id"],
          },
          "strict": True,
      }
  ]

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="What's the status of order ORD-10042?",
      tools=tools,
  )
  ```

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

  const client = new Perplexity();

  const tools = [
    {
      type: 'function' as const,
      name: 'get_order_status',
      description: 'Look up the current status of an internal order by its order ID.',
      parameters: {
        type: 'object',
        properties: { order_id: { type: 'string' } },
        required: ['order_id'],
      },
      strict: true,
    },
  ];

  const response = await client.responses.create({
    model: 'openai/gpt-5.6-sol',
    input: "What's the status of order ORD-10042?",
    tools,
  });
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "input": "What is the status of order ORD-10042?",
      "tools": [
        {
          "type": "function",
          "name": "get_order_status",
          "description": "Look up the current status of an internal order by its order ID.",
          "parameters": {
            "type": "object",
            "properties": { "order_id": { "type": "string" } },
            "required": ["order_id"]
          },
          "strict": true
        }
      ]
    }' | jq
  ```
</CodeGroup>

The model never runs your function — the API can't execute your code. Instead, the run pauses and hands the call to you: the response `output` array contains a `function_call` item with the name and the arguments the model filled in.

```json theme={null}
{
  "type": "function_call",
  "id": "fc_abc123",
  "call_id": "call_xyz789",
  "name": "get_order_status",
  "arguments": "{\"order_id\":\"ORD-10042\"}"
}
```

Pull that item off the response, run the function on your side, then continue the run by sending the result back. The follow-up request replays the conversation so far — the original question, the `function_call` the model emitted, and a `function_call_output` carrying your result under the same `call_id`:

<CodeGroup>
  ```python Python theme={null}
  import json

  function_call = next(item for item in response.output if item.type == "function_call")

  def get_order_status(order_id: str) -> dict:
      orders = {"ORD-10042": {"status": "in_transit", "carrier": "DHL", "eta": "2026-06-23"}}
      return orders.get(order_id, {"error": "order not found"})

  result = get_order_status(**json.loads(function_call.arguments))

  followup = client.responses.create(
      model="openai/gpt-5.6-sol",
      input=[
          {"role": "user", "content": "What's the status of order ORD-10042?"},
          {
              "type": "function_call",
              "call_id": function_call.call_id,
              "name": function_call.name,
              "arguments": function_call.arguments,
          },
          {
              "type": "function_call_output",
              "call_id": function_call.call_id,
              "output": json.dumps(result),
          },
      ],
      tools=tools,
  )

  print(followup.output_text)
  ```

  ```typescript TypeScript theme={null}
  const functionCall = response.output.find((item) => item.type === 'function_call');
  if (functionCall?.type !== 'function_call') throw new Error('No function call returned.');

  function getOrderStatus(orderId: string) {
    const orders: Record<string, unknown> = {
      'ORD-10042': { status: 'in_transit', carrier: 'DHL', eta: '2026-06-23' },
    };
    return orders[orderId] ?? { error: 'order not found' };
  }

  const args = JSON.parse(functionCall.arguments) as { order_id: string };
  const result = getOrderStatus(args.order_id);

  const followup = await client.responses.create({
    model: 'openai/gpt-5.6-sol',
    input: [
      { type: 'message', role: 'user', content: "What's the status of order ORD-10042?" },
      {
        type: 'function_call',
        call_id: functionCall.call_id,
        name: functionCall.name,
        arguments: functionCall.arguments,
      },
      {
        type: 'function_call_output',
        call_id: functionCall.call_id,
        output: JSON.stringify(result),
      },
    ],
    tools,
  });

  console.log(followup.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 '{
      "model": "openai/gpt-5.6-sol",
      "input": [
        { "role": "user", "content": "What is the status of order ORD-10042?" },
        {
          "type": "function_call",
          "call_id": "call_xyz789",
          "name": "get_order_status",
          "arguments": "{\"order_id\":\"ORD-10042\"}"
        },
        {
          "type": "function_call_output",
          "call_id": "call_xyz789",
          "output": "{\"status\": \"in_transit\", \"carrier\": \"DHL\", \"eta\": \"2026-06-23\"}"
        }
      ]
    }' | jq
  ```
</CodeGroup>

<Note>
  `call_id` is the correlation key: the `function_call` the model emits and the `function_call_output` you return must carry the same value. Set `strict: true` on the custom tool to enforce the parameter schema. You continue the run by replaying the prior items in the `input` array — pass the `function_call` and its `function_call_output` together so the model sees its own request and your result.
</Note>

## Read tool results

Built-in tools attach their output to the response `output` array next to the `message` item — for example `search_results`, `finance_results`, or `sandbox_results` items, depending on which tool ran. Iterate the array to surface citations, generated files, or computed values. Each tool's reference page documents its exact result shape — see, for example, [Web Search → Response shape](/docs/agent-api/tools/web-search#response-shape).

## Next steps

<CardGroup>
  <Card title="Run code" icon="terminal" href="/docs/agent-api/building-agents/run-code">
    Give the agent a sandbox to compute exact answers and return files.
  </Card>

  <Card title="Structure the output" icon="list-details" href="/docs/agent-api/building-agents/shape-output">
    Enforce structured JSON your code can parse.
  </Card>
</CardGroup>


# Keep context
Source: https://docs.perplexity.ai/docs/agent-api/building-agents/keep-context

Carry a conversation across turns by replaying it in the input array, so a follow-up understands what came before.

Replay the conversation yourself in the `input` array when you need precise control over exactly what context is sent, for example to summarize, redact, reorder, or omit earlier turns before the follow-up. See [Replay conversation turns yourself](/docs/agent-api/conversation-state#replay-conversation-turns-yourself) for the pattern and code examples.

## Storage-backed continuity

For most multi-turn conversations, use `previous_response_id` to continue from a completed prior response without resending the conversation yourself. See [Conversation state](/docs/agent-api/conversation-state) for the full guide.

## Next steps

<CardGroup>
  <Card title="Image Attachments" icon="eye" href="/docs/agent-api/image-attachments">
    Attach images to a request.
  </Card>

  <Card title="Output Control" icon="sliders" href="/docs/agent-api/output-control">
    Control streaming, background runs, error handling, and structured output.
  </Card>
</CardGroup>


# Prompt the agent
Source: https://docs.perplexity.ai/docs/agent-api/building-agents/prompt-the-agent

Split the standing rules (the system prompt) from the question (input), and ground the run so the agent searches and answers on the right thing.

An agent has two prompt surfaces, and keeping them distinct matters. `instructions` is the agent's **system prompt** — the rules that hold on every turn. `input` is the specific thing to do this turn. When retrieval tools are enabled, `input` is also what the model uses to decide whether and what to search. This page draws the line between the two and shows how to ground the run on retrieved evidence.

## `instructions` vs `input`

| Field          | What goes here                                                                                                                                                                              |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `instructions` | The system prompt: role, tone, output language, citation and formatting rules, and hard do/don'ts. Applied on every turn of the loop, independent of the question.                          |
| `input`        | The question or task for this turn. It guides tool selection, and when retrieval is enabled, it is what the model searches on, so a more specific `input` produces more targeted retrieval. |

A useful principle: if a rule should still apply when the user asks something completely different, it belongs in `instructions` (the system prompt). If it is about this request, it belongs in `input`.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      instructions=(
          "You are a financial analyst. Always cite sources by domain, "
          "and never speculate beyond retrieved evidence."
      ),
      input="Which operating segments did Apple report in its most recent annual 10-K, and how did each contribute to revenue?",
      tools=[{"type": "web_search"}],
  )

  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-sol',
    instructions:
      'You are a financial analyst. Always cite sources by domain, and never speculate beyond retrieved evidence.',
    input: 'Which operating segments did Apple report in its most recent annual 10-K, and how did each contribute to revenue?',
    tools: [{ type: 'web_search' as const }],
  });

  console.log(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 '{
      "model": "openai/gpt-5.6-sol",
      "instructions": "You are a financial analyst. Always cite sources by domain, and never speculate beyond retrieved evidence.",
      "input": "Which operating segments did Apple report in its most recent annual 10-K, and how did each contribute to revenue?",
      "tools": [{ "type": "web_search" }]
    }' | jq
  ```
</CodeGroup>

<Note>
  With a `preset`, `instructions` replaces the preset's tuned system prompt instead of appending to it. Omit `instructions` to keep the preset prompt. See [Define the run](/docs/agent-api/building-agents/define-the-run#customize-the-system-prompt-instructions).
</Note>

## Ground the run

Grounding keeps the agent answering from retrieved evidence rather than from the model's own priors. Two levers do most of the work:

* Specific `input`. When retrieval tools are enabled, the model searches based on `input`. "Apple FY2025 10-K revenue by operating segment" retrieves more targeted results than "how is Apple doing." Name entities, time ranges, and the unit of the answer.
* Retrieval tools. Enable `web_search` and related tools so the agent pulls live evidence. See [Give it tools](/docs/agent-api/building-agents/give-it-tools).

For hard constraints — allowed domains, date ranges, region — prefer request parameters over prose. They are enforced rather than merely requested:

```python theme={null}
tools=[{
    "type": "web_search",
    "filters": {
        "search_domain_filter": ["sec.gov"],
        "search_after_date_filter": "01/01/2026",
    },
}]
```

<Tip>
  Built-in tools like `web_search` and `fetch_url` generally work without much prompt-side coaching. Reach for `web_search` filters and `response_format` before adding more instruction prose — parameters are enforced directly and don't re-process on every loop step the way system-prompt tokens do.
</Tip>

## Read the sources back

A grounded answer comes with its evidence. Retrieval tools attach their results to the response `output` array (for example `search_results` items alongside the `message`), so you can surface citations or verify claims. See the per-tool reference pages — starting with [Web Search → Response shape](/docs/agent-api/tools/web-search#response-shape) — for exact response shapes.

## Next steps

<CardGroup>
  <Card title="Give it tools" icon="tool" href="/docs/agent-api/building-agents/give-it-tools">
    Enable built-in tools and your own custom tools, then read their results.
  </Card>

  <Card title="Prompt Guide" icon="bulb" href="/docs/agent-api/prompt-guide">
    Full prompting patterns and best practices.
  </Card>
</CardGroup>


# Run code
Source: https://docs.perplexity.ai/docs/agent-api/building-agents/run-code

Give the agent a sandbox so it computes exact answers instead of estimating them, runs real code, and returns generated files.

Language models approximate exact arithmetic and data manipulation rather than computing them. The `sandbox` tool gives the agent an isolated Linux container to run real code and use the output in its answer — for results that must be exact, like a computed number, a transformed dataset, or a generated report. From inside the container the agent can also call Perplexity's [Web Search](/docs/agent-api/tools/web-search), [Fetch URL Content](/docs/agent-api/tools/fetch-url-content), and [People Search](/docs/agent-api/tools/people-search) without adding them to the request, then compute on what they return — each billed at its standard rate. The [Sandbox tool reference](/docs/agent-api/tools/sandbox) has the full settings, response shape, and pricing.

## Enable the sandbox

Add `{"type": "sandbox"}` to the `tools` array. The model decides when to run code based on your prompt.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()


  def get_output_text(response) -> str:
      return "".join(
          content.text
          for item in response.output or []
          if getattr(item, "type", None) == "message"
          for content in getattr(item, "content", None) or []
          if getattr(content, "type", None) == "output_text"
      )


  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Compute the compound annual growth rate from 4.2M in 2019 to 11.8M in 2025.",
      tools=[{"type": "sandbox"}],
      instructions="Use the sandbox to compute the exact figure before answering.",
  )

  print(get_output_text(response))
  ```

  ```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-sol',
    input: 'Compute the compound annual growth rate from 4.2M in 2019 to 11.8M in 2025.',
    tools: [{ type: 'sandbox' as const }],
    instructions: 'Use the sandbox to compute the exact figure before answering.',
  });

  console.log(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 '{
      "model": "openai/gpt-5.6-sol",
      "input": "Compute the compound annual growth rate from 4.2M in 2019 to 11.8M in 2025.",
      "tools": [{ "type": "sandbox" }],
      "instructions": "Use the sandbox to compute the exact figure before answering."
    }' | jq
  ```
</CodeGroup>

## When to reach for it

* Numeric calculations and statistical analysis where an estimate won't do
* Data cleaning, parsing, and transformation
* Executing code to check logic or reproduce an error
* Generating files and artifacts — CSV, JSON, HTML, reports, or any other file the code writes
* Multi-step workflows that need intermediate files or computed state

<Tip>
  Combine `sandbox` with `web_search` and the agent can gather evidence, then compute on it inside the container. See the [Sandbox reference](/docs/agent-api/tools/sandbox) for how the sandbox interacts with other tools.
</Tip>

## Read the computed result

When the agent runs code, the response `output` array includes one or more `sandbox_results` items alongside the `message`. Each carries the executed `code`, the `language`, and a `results` array with `stdout`, `stderr`, `exit_code`, and `status`. That's how you verify the agent computed the answer rather than guessing it. See the [response shape reference](/docs/agent-api/tools/sandbox#response-shape) for every field.

Read that item off the response (`response` here is from the [Enable the sandbox](#enable-the-sandbox) example above):

```python Python theme={null}
for item in response.output:
    if item.type == "sandbox_results":
        print(item.code)
        print(item.results[0].stdout)
```

For that request, the agent wrote and ran this Python in the sandbox, then used the printed value in its answer:

<Accordion title="Response">
  <Tabs>
    <Tab title="Formatted code">
      ```python theme={null}
      from decimal import Decimal, getcontext

      getcontext().prec = 50
      start = Decimal('4.2')
      end = Decimal('11.8')
      years = Decimal(2025 - 2019)
      log_growth = (end / start).ln() / years
      cagr = log_growth.exp() - Decimal(1)
      print(cagr)
      print(cagr * 100)
      ```

      ```text Output theme={null}
      0.1878787669330553776746033271110368937629924939521
      18.787876693305537767460332711103689376299249395210
      ```
    </Tab>

    <Tab title="Raw response">
      ```json theme={null}
      {
        "id": "resp_482ba96d-c94a-4b0b-8032-e29062a71cdc",
        "created_at": 1781869590,
        "model": "openai/gpt-5.6-sol",
        "object": "response",
        "output": [
          {
            "id": null,
            "content": null,
            "role": null,
            "status": "completed",
            "type": "sandbox_results",
            "call_id": "call_7br1ycfTNZ2jFa4HG6otVC76",
            "code": "from decimal import Decimal, getcontext\ngetcontext().prec=50\nstart=Decimal('4.2')\nend=Decimal('11.8')\nyears=Decimal(2025-2019)\n# Decimal fractional power via exp ln? Decimal has ln exp\ncagr=(end/start).ln()/years\nrate=cagr.exp()-Decimal(1)\nprint(rate)\nprint(rate*100)",
            "container_id": "iuptasr65kixvn1p7s3r6",
            "language": "python",
            "results": [
              {
                "duration_ms": 274,
                "exit_code": 0,
                "status": "completed",
                "stderr": "",
                "stdout": "0.1878787669330553776746033271110368937629924939521\n18.787876693305537767460332711103689376299249395210\n"
              }
            ]
          },
          {
            "id": "msg_8349d00e-ca88-4074-a7bd-e3dea9fe77cf",
            "content": [
              {
                "text": "The compound annual growth rate (CAGR) from **4.2M in 2019** to **11.8M in 2025** is:\n\n\\[\n\\text{CAGR} = \\left(\\frac{11.8}{4.2}\\right)^{1/6} - 1\n\\]\n\n\\[\n\\text{CAGR} \\approx 18.79\\%\n\\]\n\n**Answer: 18.8% per year**.",
                "type": "output_text",
                "annotations": []
              }
            ],
            "role": "assistant",
            "status": "completed",
            "type": "message"
          }
        ],
        "status": "completed",
        "background": false,
        "error": null,
        "usage": {
          "input_tokens": 3262,
          "output_tokens": 294,
          "total_tokens": 3556,
          "cost": {
            "currency": "USD",
            "input_cost": 0.01631,
            "output_cost": 0.00882,
            "total_cost": 0.02513,
            "cache_creation_cost": null,
            "cache_read_cost": null,
            "tool_calls_cost": 0.0,
            "tool_calls_cost_details": {
              "sandbox": 0
            }
          },
          "input_tokens_details": {
            "cache_creation_input_tokens": null,
            "cache_read_input_tokens": null,
            "cached_tokens": 0
          },
          "tool_calls_details": {
            "sandbox": {
              "invocation": 1,
              "duration_ms": 274
            }
          },
          "output_tokens_details": {
            "reasoning_tokens": 56
          }
        },
        "completed_at": 1781869590,
        "frequency_penalty": 0,
        "incomplete_details": null,
        "instructions": "Use the sandbox to compute the exact figure before answering.",
        "max_output_tokens": null,
        "max_tool_calls": null,
        "metadata": {},
        "parallel_tool_calls": true,
        "presence_penalty": 0,
        "previous_response_id": null,
        "prompt_cache_key": null,
        "reasoning": null,
        "safety_identifier": null,
        "service_tier": "default",
        "store": true,
        "temperature": 1,
        "text": {
          "format": {
            "type": "text"
          }
        },
        "tool_choice": "auto",
        "tools": [
          {
            "type": "sandbox"
          }
        ],
        "top_logprobs": 0,
        "top_p": 1,
        "truncation": "",
        "user": null
      }
      ```
    </Tab>
  </Tabs>
</Accordion>

## Return files

When code in the sandbox writes a file and shares it, the response `output` includes a `share_file` item. The bytes aren't inline — list and download them with the response files endpoints, keyed by the response `id`:

<CodeGroup>
  ```python Python theme={null}
  files = client.responses.files.list(response.id)
  for f in files.data:
      print(f.id, f.filename, f.bytes)

  content = client.responses.files.content(
      file_id=files.data[0].id,
      response_id=response.id,
  )
  content.write_to_file(files.data[0].filename)
  ```

  ```bash cURL theme={null}
  # List files the response produced
  curl https://api.perplexity.ai/v1/agent/$RESPONSE_ID/files \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" | jq

  # Download one by its file id
  curl https://api.perplexity.ai/v1/agent/$RESPONSE_ID/files/$FILE_ID/content \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -o output.csv
  ```
</CodeGroup>

<Note>
  Long-running sandbox work pairs well with background runs: submit with `background: true` and poll by ID. See [Output Control](/docs/agent-api/output-control) and the [Sandbox reference](/docs/agent-api/tools/sandbox#running-in-the-background).
</Note>

## Next steps

<CardGroup>
  <Card title="Structure the output" icon="list-details" href="/docs/agent-api/building-agents/shape-output">
    Enforce structured JSON your code can parse.
  </Card>

  <Card title="Sandbox reference" icon="box" href="/docs/agent-api/tools/sandbox">
    Full sandbox settings, response shape, file retrieval, and pricing.
  </Card>
</CardGroup>


# Structure the output
Source: https://docs.perplexity.ai/docs/agent-api/building-agents/shape-output

Force the model to return JSON your code can parse instead of prose you have to scrape.

By default a run returns one block of text when it finishes. When a downstream system has to consume the result, free-form prose is hard to work with — you end up writing brittle parsers. Structured output makes the model return JSON that conforms to a schema you define, so you can deserialize it directly. For the exhaustive reference — streaming, background runs, error handling, and full schema examples — see [Output Control](/docs/agent-api/output-control).

## Structured output

Set `response_format` to a `json_schema` with a `name` and a `schema`. The response text conforms to the schema unless generation is cut short. The example below builds the schema from a Pydantic model and validates the response against it:

<CodeGroup>
  ```python Python theme={null}
  from typing import List, Optional
  from pydantic import BaseModel
  from perplexity import Perplexity

  class CompanySummary(BaseModel):
      name: str
      sector: str
      headquarters: str
      key_products: Optional[List[str]] = None

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Summarize NVIDIA: sector, headquarters, and key products.",
      response_format={
          "type": "json_schema",
          "json_schema": {
              "name": "company_summary",
              "schema": {
                  **CompanySummary.model_json_schema(),
                  "required": list(CompanySummary.model_fields.keys()),
                  "additionalProperties": False,
              },
          },
      },
  )

  summary = CompanySummary.model_validate_json(response.output_text)
  print(summary.name, summary.sector)
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "input": "Summarize NVIDIA: sector, headquarters, and key products.",
      "response_format": {
        "type": "json_schema",
        "json_schema": {
          "name": "company_summary",
          "schema": {
            "type": "object",
            "properties": {
              "name": { "type": "string" },
              "sector": { "type": "string" },
              "headquarters": { "type": "string" },
              "key_products": { "type": "array", "items": { "type": "string" } }
            },
            "required": ["name", "sector", "headquarters"]
          }
        }
      }
    }' | jq
  ```
</CodeGroup>

<Tip>
  Reinforce the schema in your prompt ("Return the data as a JSON object matching the schema") to improve adherence.
</Tip>

<Warning>
  Avoid asking for links inside the JSON. A model emitting URLs as part of structured output can produce malformed or fabricated links. Pull links from the `citations` or `search_results` items in the response `output` instead.
</Warning>

## Next steps

<CardGroup>
  <Card title="Keep context" icon="link" href="/docs/agent-api/building-agents/keep-context">
    Carry state across multiple turns.
  </Card>

  <Card title="Output Control" icon="sliders" href="/docs/agent-api/output-control">
    Streaming, background runs, error handling, and full structured-output examples.
  </Card>
</CardGroup>


# Conversation state
Source: https://docs.perplexity.ai/docs/agent-api/conversation-state

Continue an Agent API conversation across turns, either by replaying input yourself or by pointing at a completed prior response.

A follow-up request understands earlier turns only if you provide them: either by replaying them yourself, or by pointing at a completed prior response with `previous_response_id`. `previous_response_id` is a shortcut for the common case: it points a new request at a completed prior response so you don't have to resend the conversation yourself.

## Replay conversation turns yourself

Send the next turn as an `input` array that includes the prior turns. Each turn is a message item with `type: "message"` and a `role` (`user` or `assistant`). Append the new question at the end.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  first = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="My favorite programming language is Rust.",
  )
  print(first.output_text)

  # Replay the conversation so far, then add the follow-up.
  second = client.responses.create(
      model="openai/gpt-5.6-sol",
      input=[
          {"type": "message", "role": "user", "content": "My favorite programming language is Rust."},
          {"type": "message", "role": "assistant", "content": first.output_text},
          {"type": "message", "role": "user", "content": "What's a good beginner project to practice it?"},
      ],
  )
  print(second.output_text)
  ```

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

  const client = new Perplexity();

  const first = await client.responses.create({
    model: 'openai/gpt-5.6-sol',
    input: 'My favorite programming language is Rust.',
  });
  console.log(first.output_text);

  const second = await client.responses.create({
    model: 'openai/gpt-5.6-sol',
    input: [
      { type: 'message', role: 'user', content: 'My favorite programming language is Rust.' },
      { type: 'message', role: 'assistant', content: first.output_text ?? '' },
      { type: 'message', role: 'user', content: "What's a good beginner project to practice it?" },
    ],
  });
  console.log(second.output_text);
  ```

  ```bash cURL theme={null}
  FIRST=$(curl -s https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "input": "My favorite programming language is Rust."
    }')
  FIRST_TEXT=$(echo "$FIRST" | jq -r '.output[] | select(.type == "message") | .content[0].text')

  # Replay the conversation so far, then add the follow-up.
  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d "$(jq -n --arg text "$FIRST_TEXT" '{
      model: "openai/gpt-5.6-sol",
      input: [
        { type: "message", role: "user", content: "My favorite programming language is Rust." },
        { type: "message", role: "assistant", content: $text },
        { type: "message", role: "user", content: "What'\''s a good beginner project to practice it?" }
      ]
    }')" | jq
  ```
</CodeGroup>

This gives you full control over exactly what context is sent: summarize, redact, reorder, or drop earlier turns before the follow-up. The tradeoff is that you carry the conversation yourself and resend it on every call.

## Resume from a prior response

Instead of resending the conversation, point the next request at a completed prior response and send only the new turn.

<Info>
  The Agent API persists response and conversation state server-side so responses can be retrieved (`store`) or continued (`previous_response_id`). Setting `store: false` only hides a response from retrieval — it does not disable persistence, and the response can still be used as a continuation source. If your account has a Zero Data Retention (ZDR) agreement with Perplexity, check with your account team before relying on stateful features — contact [api@perplexity.ai](mailto:api@perplexity.ai).
</Info>

1. Create the first response and keep its `id`.
2. Send the follow-up with `previous_response_id` set to that `id`.
3. Put only the new user turn in `input`.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  first = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="My favorite programming language is Rust.",
      store=True,
  )
  print(first.id)

  follow_up = client.responses.create(
      model="openai/gpt-5.6-sol",
      previous_response_id=first.id,
      input="What's my favorite programming language?",
  )
  print(follow_up.output_text)
  ```

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

  const client = new Perplexity();

  const first = await client.responses.create({
    model: 'openai/gpt-5.6-sol',
    input: 'My favorite programming language is Rust.',
    store: true,
  });
  console.log(first.id);

  const followUp = await client.responses.create({
    model: 'openai/gpt-5.6-sol',
    previous_response_id: first.id,
    input: "What's my favorite programming language?",
  });
  console.log(followUp.output_text);
  ```

  ```bash cURL theme={null}
  FIRST_ID=$(curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "input": "My favorite programming language is Rust.",
      "store": true
    }' | jq -r '.id')

  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{
      \"model\": \"openai/gpt-5.6-sol\",
      \"previous_response_id\": \"$FIRST_ID\",
      \"input\": \"What's my favorite programming language?\"
    }" | jq
  ```
</CodeGroup>

### How continuity works

The new request continues from the prior response's saved conversation state. That state includes the prior chain, so you can continue from the latest response in a multi-turn thread instead of manually replaying every earlier turn.

```mermaid theme={null}
flowchart LR
    A[First response] -->|id| B[Second request with previous_response_id]
    B -->|new id| C[Third request with previous_response_id]
```

Use this for conversational follow-ups where the next turn should build on earlier user and assistant messages. Continue sending any new instructions, tools, or model settings that you want to apply to the new response.

### Retrieve a response

Fetch a completed response later by its `id`. This does not start a new turn; it returns a JSON snapshot of the original response.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  first = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="My favorite programming language is Rust.",
  )

  response = client.responses.retrieve(first.id)
  print(response.status)
  for item in response.output:
      if item.type == "message":
          print(item.content[0].text)
  ```

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

  const client = new Perplexity();

  const first = await client.responses.create({
    model: 'openai/gpt-5.6-sol',
    input: 'My favorite programming language is Rust.',
  });

  const response = await client.responses.retrieve(first.id);
  console.log(response.status);
  for (const item of response.output) {
    if (item.type === 'message') {
      console.log(item.content[0].text);
    }
  }
  ```

  ```bash cURL theme={null}
  FIRST_ID=$(curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "input": "My favorite programming language is Rust."
    }' | jq -r '.id') && curl https://api.perplexity.ai/v1/agent/$FIRST_ID \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" | jq
  ```
</CodeGroup>

Retrieval only works for responses created with `store` omitted or `true`; a `store: false` response returns a `404` on retrieval. For a response you need to be able to retrieve reliably, create it with `background: true`.

### Storage behavior

`store` controls whether a response is visible through user-facing retrieval surfaces. It does not prevent that response from being used as a `previous_response_id` continuation source.

| Setting           | Behavior                                                                                               |
| ----------------- | ------------------------------------------------------------------------------------------------------ |
| Omitted or `true` | The response can be retrieved later and can be used as `previous_response_id`.                         |
| `false`           | The response is hidden from user-facing retrieval, but it can still be used as `previous_response_id`. |

Use `store: false` when you do not want the response exposed through retrieval, but still need the next request in your application flow to continue from it. For example, retrieving a `store: false` response returns a `404`, but you can still continue from it with `previous_response_id`:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  hidden = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="My favorite programming language is Rust.",
      store=False,
  )

  try:
      client.responses.retrieve(hidden.id)
  except Exception as e:
      print(e)  # 404 NotFoundError

  follow_up = client.responses.create(
      model="openai/gpt-5.6-sol",
      previous_response_id=hidden.id,  # still works
      input="What's my favorite programming language?",
  )
  print(follow_up.output_text)
  ```

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

  const client = new Perplexity();

  const hidden = await client.responses.create({
    model: 'openai/gpt-5.6-sol',
    input: 'My favorite programming language is Rust.',
    store: false,
  });

  try {
    await client.responses.retrieve(hidden.id);
  } catch (e) {
    console.log(e); // 404 NotFoundError
  }

  const followUp = await client.responses.create({
    model: 'openai/gpt-5.6-sol',
    previous_response_id: hidden.id, // still works
    input: "What's my favorite programming language?",
  });
  console.log(followUp.output_text);
  ```

  ```bash cURL theme={null}
  HIDDEN_ID=$(curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "input": "My favorite programming language is Rust.",
      "store": false
    }' | jq -r '.id')

  curl https://api.perplexity.ai/v1/agent/$HIDDEN_ID \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY"
  # -> 404 {"error":{"message":"resource not found", ...}}

  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{
      \"model\": \"openai/gpt-5.6-sol\",
      \"previous_response_id\": \"$HIDDEN_ID\",
      \"input\": \"What's my favorite programming language?\"
    }" | jq
  # -> still works
  ```
</CodeGroup>

### Requirements and errors

* `previous_response_id` must reference a prior Agent API response from the same account.
* The prior response must be completed. If it is still running, has failed, or the id cannot be resolved, the API returns a `400` error instead of starting a valid follow-up.
* If you need to continue from a response that is still running, wait for it to complete and retry with the same `previous_response_id`.

## Next steps

<CardGroup>
  <Card title="Image Attachments" icon="eye" href="/docs/agent-api/image-attachments">
    Attach images to a request.
  </Card>

  <Card title="Output Control" icon="sliders" href="/docs/agent-api/output-control">
    Control streaming, background runs, error handling, and structured output.
  </Card>
</CardGroup>


# Image Attachments
Source: https://docs.perplexity.ai/docs/agent-api/image-attachments

Learn how to upload and analyze images using base64 encoding or HTTPS URLs

## Overview

The Agent API supports image analysis through direct image uploads. Images can be provided either as base64 encoded strings within a data URI or as standard HTTPS URLs.

<Warning>
  * When using base64 encoding, the API currently only supports images up to 50 MB per image.
  * Supported formats for base64 encoded images: PNG (image/png), JPEG (image/jpeg), WEBP (image/webp), and GIF (image/gif).
  * When using an HTTPS URL, the model will attempt to fetch the image from the provided URL. Ensure the URL is publicly accessible.
</Warning>

## Examples

<Tabs>
  <Tab title="Base64 Encoded Data">
    <Info>Use this method when you have the image file locally and want to embed it directly into the request payload. Remember the 50MB size limit and supported formats (PNG, JPEG, WEBP, GIF).</Info>

    <CodeGroup>
      ```python Python theme={null}
      import base64
      from perplexity import Perplexity

      client = Perplexity()

      # Read and encode image as base64
      def encode_image(image_path):
          with open(image_path, "rb") as image_file:
              return base64.b64encode(image_file.read()).decode("utf-8")

      image_path = "image.png"
      base64_image = encode_image(image_path)

      # Analyze the image
      response = client.responses.create(
          model="openai/gpt-5.6-sol",
          input=[
              {
                  "role": "user",
                  "content": [
                      {"type": "input_text", "text": "what's in this image?"},
                      {
                          "type": "input_image",
                          "image_url": f"data:image/png;base64,{base64_image}",
                      },
                  ],
              }
          ],
      )

      print(response.output_text)
      ```

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

      const client = new Perplexity();

      // Read and encode image as base64
      const imageBuffer = fs.readFileSync('image.png');
      const base64Image = imageBuffer.toString('base64');
      const imageDataUri = `data:image/png;base64,${base64Image}`;

      // Analyze the image
      const response = await client.responses.create({
          model: 'openai/gpt-5-mini',
          input: [
              {
                  role: 'user',
                  content: [
                      { type: 'input_text', text: "What's in this image?" },
                      { type: 'input_image', image_url: imageDataUri }
                  ]
              }
          ],
      } as any);

      console.log(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 '{
          "model": "openai/gpt-5-mini",
          "input": [
            {
              "role": "user",
              "content": [
                {
                  "type": "input_text",
                  "text": "What'\''s in this image?"
                },
                {
                  "type": "input_image",
                  "image_url": "data:image/png;base64,$BASE64_ENCODED_IMAGE"
                }
              ]
            }
          ]
        }' | jq
      ```
    </CodeGroup>
  </Tab>

  <Tab title="HTTPS URL">
    <Info>Use this method when you have a publicly accessible image URL. The model will fetch the image from the provided URL.</Info>

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      image_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"

      # Analyze the image
      response = client.responses.create(
          model="openai/gpt-5.6-sol",
          input=[
              {
                  "role": "user",
                  "content": [
                      {"type": "input_text", "text": "Can you describe the image at this URL?"},
                      {
                          "type": "input_image",
                          "image_url": image_url,
                      },
                  ],
              }
          ],
      )

      print(response.output_text)
      ```

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

      const client = new Perplexity();

      const imageHttpsUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg";

      // Analyze the image
      const response = await client.responses.create({
          model: 'openai/gpt-5-mini',
          input: [
              {
                  role: 'user',
                  content: [
                      { type: 'input_text', text: 'Can you describe the image at this URL?' },
                      { type: 'input_image', image_url: imageHttpsUrl }
                  ]
              }
          ],
      } as any);

      console.log(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 '{
          "model": "openai/gpt-5-mini",
          "input": [
            {
              "role": "user",
              "content": [
                {
                  "type": "input_text",
                  "text": "Can you describe the image at this URL?"
                },
                {
                  "type": "input_image",
                  "image_url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
                }
              ]
            }
          ]
        }' | jq
      ```
    </CodeGroup>
  </Tab>
</Tabs>

## Request Format

### Agent API

Images must be embedded in the `input` array when using message array format. Each image should be provided using the following structure:

```json theme={null}
{
  "role": "user",
  "content": [
    {
      "type": "input_text",
      "text": "What's in this image?"
    },
    {
      "type": "input_image",
      "image_url": "<IMAGE_URL_OR_BASE64_DATA>"
    }
  ]
}
```

The `image_url` field accepts either:

* **A URL of the image**: A publicly accessible HTTPS URL pointing directly to the image file
* **The base64 encoded image data**: A data URI in the format `data:image/{format};base64,{base64_content}`

## Pricing

Images are tokenized based on their pixel dimensions using the following formula:

```
tokens = (width px × height px) / 750
```

**Examples:**

* A 1024×768 image would consume: (1024 × 768) / 750 = 1,048 tokens
* A 512×512 image would consume: (512 × 512) / 750 = 349 tokens

These image tokens are then priced according to the input token pricing of the model you're using. The image tokens are added to your total token count for the request alongside any text tokens.

## Next Steps

<CardGroup>
  <Card title="Agent API Quickstart" icon="rocket" href="/docs/agent-api/quickstart">
    Get started with the Agent API
  </Card>

  <Card title="Web Search" icon="settings-bolt" href="/docs/agent-api/tools/web-search">
    Learn about the `web_search` tool.
  </Card>
</CardGroup>


# Agent API vs Sonar benchmarks
Source: https://docs.perplexity.ai/docs/agent-api/migrate-from-sonar/benchmarks

How Agent API presets perform against Sonar across the benchmarks we run, and which preset to use in place of each Sonar model.

On the benchmarks we run, Agent API presets deliver more quality per dollar than Sonar: the preset curve sits above every Sonar model.
The lead is widest on hard, multi-step tasks like BrowseComp and WideSearch, where the strongest preset more than doubles the best Sonar score.

## What we measured

We evaluated Agent API presets and Sonar models on the same workloads, across three benchmarks:

* **[BrowseComp](https://arxiv.org/abs/2504.12516)** measures agentic browsing on hard questions that require chaining many searches.
* **[DSQA (DeepSearchQA)](https://arxiv.org/abs/2601.20975)** measures answer quality on deep-search questions.
* **[WideSearch](https://arxiv.org/abs/2508.07999)** measures how completely a run gathers and fills structured results, scored by row-level F1.

Agent API presets can even match Sonar's best model, Deep Research, at a fraction of the cost.

<MigrationBenchmarkChart />

<Info>
  For a benchmark built specifically for research agents that must search both wide and deep, see [WANDR](https://research.perplexity.ai/articles/wandr-benchmark-evaluating-research-agents-that-must-search-wide-and-deep).
</Info>

## Which preset should you use?

Results vary by use case, but every preset lands higher on the quality curve than its Sonar counterpart — and in the deep-research tier, for less.
Use the mapping below as a starting point, then confirm against your own traffic.

| Sonar Chat Completions | Agent API preset | Best for                                                                        | What improves                                                                                                                            |
| ---------------------- | ---------------- | ------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| Sonar                  | `fast`           | Single-fact lookups, definitions, quick summaries.                              | More accurate than Sonar, with the clearest gains on research-style, multi-step questions.                                               |
| Sonar Pro              | `low`            | Everyday research questions, light multi-step lookups with current information. | Much more accurate, and unlocks the real multi-step, agentic research that Sonar Pro can't reach.                                        |
| Sonar Reasoning Pro    | `medium`         | Multi-hop browsing and wide aggregation across many sources.                    | Far stronger on step-by-step reasoning and on chaining evidence across several rounds of search.                                         |
| Sonar Deep Research    | `high`           | Expert-level reasoning and exhaustive source coverage.                          | The most accurate tier on demanding expert-level and deep-research work, and often at a lower per-request cost than Sonar Deep Research. |

<Tip>
  For state-of-the-art deep research, use the `xhigh` preset — the highest quality in the lineup, leading across the benchmarks we run.
</Tip>

<CardGroup>
  <Card title="Explore the presets" icon="sliders" href="/docs/agent-api/presets">
    See what each preset configures and how to override individual settings.
  </Card>

  <Card title="Migrate your integration" icon="arrow-right-arrow-left" href="/docs/agent-api/migrate-from-sonar/how-to">
    Follow the field-by-field procedure to move a Sonar integration to the Agent API.
  </Card>
</CardGroup>


# How to migrate from Sonar
Source: https://docs.perplexity.ai/docs/agent-api/migrate-from-sonar/how-to

Move a Sonar chat completions integration to the Agent API, including requests, responses, search, presets, async runs, and parameter mappings.

This guide maps a Sonar chat completions integration to the Agent API.
You keep the same grounded web search, and gain an agent that runs multi-step research, executes its own code, and calls tools like finance and people search.

## Use the migration skill

The fastest path is to let your coding agent do the migration. Open it in the project you want to migrate and send it this:

```text wrap theme={null}
Read https://github.com/perplexityai/api-platform-developers/blob/main/skills/migrate-sonar-to-agent-api/SKILL.md and install this skill, then use it to migrate this project from Sonar to the Agent API.
```

See the [repository README](https://github.com/perplexityai/api-platform-developers/blob/main/README.md) for supported coding agents and other installation options.

## 1. Update the endpoint and method

Point requests at `/v1/agent` and switch from `chat.completions.create()` to `responses.create()`.
For plain text, the Agent API takes the same `role`/`content` items, so the body barely changes: pass the array as `input` instead of `messages` and rename the model.

<Columns>
  <div>
    **Sonar**

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      completion = client.chat.completions.create(
          model="sonar",
          messages=[
              {"role": "system", "content": "You are a concise research assistant."},
              {"role": "user", "content": "What are the latest developments in AI agents?"},
          ],
      )
      print(completion.choices[0].message.content)
      ```

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

      const client = new Perplexity();

      const completion = await client.chat.completions.create({
        model: 'sonar',
        messages: [
          { role: 'system', content: 'You are a concise research assistant.' },
          { role: 'user', content: 'What are the latest developments in AI agents?' },
        ],
      });
      console.log(completion.choices[0].message.content);
      ```

      ```bash cURL theme={null}
      curl https://api.perplexity.ai/v1/sonar \
        -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "sonar",
          "messages": [
            {"role": "system", "content": "You are a concise research assistant."},
            {"role": "user", "content": "What are the latest developments in AI agents?"}
          ]
        }' | jq
      ```
    </CodeGroup>
  </div>

  <div>
    **Agent API**

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      response = client.responses.create(
          model="perplexity/sonar",
          input=[
              {"type": "message", "role": "system", "content": "You are a concise research assistant."},
              {"type": "message", "role": "user", "content": "What are the latest developments in AI agents?"},
          ],
      )
      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: 'perplexity/sonar',
        input: [
          { type: 'message', role: 'system', content: 'You are a concise research assistant.' },
          { type: 'message', role: 'user', content: 'What are the latest developments in AI agents?' },
        ],
      });
      console.log(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 '{
          "model": "perplexity/sonar",
          "input": [
            {"type": "message", "role": "system", "content": "You are a concise research assistant."},
            {"type": "message", "role": "user", "content": "What are the latest developments in AI agents?"}
          ]
        }' | jq
      ```
    </CodeGroup>
  </div>
</Columns>

## 2. Map messages to input

Sonar takes your prompt as a `messages` array; the Agent API takes it as `input`.
For simple single-turn prompts, pass a plain string.
To preserve a system prompt or a multi-turn transcript, pass an array of input items or use the top-level `instructions` field.

<Columns>
  <div>
    **Sonar**

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      # Single user turn
      completion = client.chat.completions.create(
          model="sonar",
          messages=[{"role": "user", "content": "What are the latest developments in AI agents?"}]
      )

      # System guidance plus a user turn
      completion = client.chat.completions.create(
          model="sonar",
          messages=[
              {"role": "system", "content": "You are a concise research assistant."},
              {"role": "user", "content": "What are the latest developments in AI agents?"}
          ]
      )
      print(completion.choices[0].message.content)
      ```

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

      const client = new Perplexity();

      // Single user turn
      const simple = await client.chat.completions.create({
        model: 'sonar',
        messages: [{ role: 'user', content: 'What are the latest developments in AI agents?' }]
      });

      // System guidance plus a user turn
      const completion = await client.chat.completions.create({
        model: 'sonar',
        messages: [
          { role: 'system', content: 'You are a concise research assistant.' },
          { role: 'user', content: 'What are the latest developments in AI agents?' }
        ]
      });
      console.log(completion.choices[0].message.content);
      ```

      ```bash cURL theme={null}
      # System guidance plus a user turn
      curl https://api.perplexity.ai/v1/sonar \
        -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "sonar",
          "messages": [
            {"role": "system", "content": "You are a concise research assistant."},
            {"role": "user", "content": "What are the latest developments in AI agents?"}
          ]
        }' | jq
      ```
    </CodeGroup>
  </div>

  <div>
    **Agent API**

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      # Simple string input
      response = client.responses.create(
          model="perplexity/sonar",
          input="What are the latest developments in AI agents?"
      )

      # System guidance plus a user turn
      response = client.responses.create(
          model="perplexity/sonar",
          instructions="You are a concise research assistant.",
          input=[
              {"type": "message", "role": "user", "content": "What are the latest developments in AI agents?"}
          ]
      )
      print(response.output_text)
      ```

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

      const client = new Perplexity();

      // Simple string input
      const simple = await client.responses.create({
        model: 'perplexity/sonar',
        input: 'What are the latest developments in AI agents?'
      });

      // System guidance plus a user turn
      const response = await client.responses.create({
        model: 'perplexity/sonar',
        instructions: 'You are a concise research assistant.',
        input: [
          { type: 'message', role: 'user', content: 'What are the latest developments in AI agents?' }
        ]
      });
      console.log(response.output_text);
      ```

      ```bash cURL theme={null}
      # System guidance plus a user turn
      curl https://api.perplexity.ai/v1/agent \
        -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "perplexity/sonar",
          "instructions": "You are a concise research assistant.",
          "input": [
            {"type": "message", "role": "user", "content": "What are the latest developments in AI agents?"}
          ]
        }' | jq
      ```
    </CodeGroup>
  </div>
</Columns>

<Tip>
  Continuing a multi-turn conversation? The shortcut is `previous_response_id` — point a new request at a completed prior response and skip resending the transcript. You can also replay the prior turns (including `assistant` items) in `input` yourself. See [Conversation state](/docs/agent-api/conversation-state).
</Tip>

## 3. Update output handling

Read the answer text from `response.output_text` — the drop-in replacement for Sonar's `choices[0].message.content`.
When you need more than the answer text (tool calls, search results), iterate the typed `output` array and branch on each item's `type`.

<Columns>
  <div>
    **Sonar**

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      completion = client.chat.completions.create(
          model="sonar",
          messages=[{"role": "user", "content": "What are the latest developments in AI agents?"}],
      )
      print(completion.choices[0].message.content)
      ```

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

      const client = new Perplexity();

      const completion = await client.chat.completions.create({
        model: 'sonar',
        messages: [{ role: 'user', content: 'What are the latest developments in AI agents?' }],
      });
      console.log(completion.choices[0].message.content);
      ```

      ```bash cURL theme={null}
      curl https://api.perplexity.ai/v1/sonar \
        -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "sonar",
          "messages": [
            {"role": "user", "content": "What are the latest developments in AI agents?"}
          ]
        }' | jq -r '.choices[0].message.content'
      ```
    </CodeGroup>
  </div>

  <div>
    **Agent API**

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      response = client.responses.create(
          model="perplexity/sonar",
          input="What are the latest developments in AI agents?",
      )
      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: 'perplexity/sonar',
        input: 'What are the latest developments in AI agents?',
      });
      console.log(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 '{
          "model": "perplexity/sonar",
          "input": "What are the latest developments in AI agents?"
        }' | jq
      ```
    </CodeGroup>
  </div>
</Columns>

<Tip>
  **The `output` array is a full trace, not just the answer.** Beyond the final text, it records every step the model took — the searches it ran and their results, the exact code it executed in the [`sandbox`](/docs/agent-api/tools/sandbox), and any files it produced.
  Sonar returned only the answer and its citations; here you can inspect and audit the whole run.
</Tip>

### Streaming

Sonar streaming returns incremental chunks with a `delta.content` field on each choice.
The Agent API streams typed server-sent events, so update stream consumers to branch on each event's `type`.
For the answer text, consume `response.output_text.delta` events; tool calls and reasoning arrive as their own `response.output_item.*` and `response.reasoning.*` events, not as text deltas.

<Columns>
  <div>
    **Sonar**

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      stream = client.chat.completions.create(
          model="sonar",
          messages=[{"role": "user", "content": "Explain quantum computing"}],
          stream=True
      )
      for chunk in stream:
          if chunk.choices[0].delta.content:
              print(chunk.choices[0].delta.content, end="")
      ```

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

      const client = new Perplexity();

      const stream = await client.chat.completions.create({
        model: 'sonar',
        messages: [{ role: 'user', content: 'Explain quantum computing' }],
        stream: true
      });
      for await (const chunk of stream) {
        if (chunk.choices[0]?.delta?.content) {
          process.stdout.write(chunk.choices[0].delta.content);
        }
      }
      ```

      ```bash cURL theme={null}
      curl https://api.perplexity.ai/v1/sonar \
        -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "sonar",
          "messages": [
            {"role": "user", "content": "Explain quantum computing"}
          ],
          "stream": true
        }'
      ```
    </CodeGroup>
  </div>

  <div>
    **Agent API**

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      stream = client.responses.create(
          model="perplexity/sonar",
          input="Explain quantum computing",
          stream=True
      )
      for event in stream:
          if event.type == "response.output_text.delta":
              print(event.delta, end="", flush=True)
      ```

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

      const client = new Perplexity();

      const stream = await client.responses.create({
        model: 'perplexity/sonar',
        input: 'Explain quantum computing',
        stream: true
      });
      for await (const event of stream) {
        if (event.type === 'response.output_text.delta') {
          process.stdout.write(event.delta);
        }
      }
      ```

      ```bash cURL theme={null}
      curl https://api.perplexity.ai/v1/agent \
        -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "perplexity/sonar",
          "input": "Explain quantum computing",
          "stream": true
        }'
      ```
    </CodeGroup>
  </div>
</Columns>

## 4. Web search

Perplexity's own search — the grounded web search that was built into Sonar — is available through the `web_search` tool.
In Sonar it was always on; on the Agent API you turn it on by adding `web_search` to the request's `tools` — otherwise the model answers from its own knowledge without searching.
Search controls move onto the tool too, so Sonar's top-level `search_recency_filter` and `search_domain_filter` go into its `filters`.
See the [Web Search](/docs/agent-api/tools/web-search) reference for the full set of options.

<Columns>
  <div>
    **Sonar**

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      completion = client.chat.completions.create(
          model="sonar",
          messages=[{"role": "user", "content": "Latest renewable energy policy updates"}],
          search_recency_filter="month",
          search_domain_filter=["iea.org", "energy.gov"]
      )
      print(completion.choices[0].message.content)
      ```

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

      const client = new Perplexity();

      const completion = await client.chat.completions.create({
        model: 'sonar',
        messages: [{ role: 'user', content: 'Latest renewable energy policy updates' }],
        search_recency_filter: 'month',
        search_domain_filter: ['iea.org', 'energy.gov']
      });
      console.log(completion.choices[0].message.content);
      ```

      ```bash cURL theme={null}
      curl https://api.perplexity.ai/v1/sonar \
        -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "sonar",
          "messages": [
            {"role": "user", "content": "Latest renewable energy policy updates"}
          ],
          "search_recency_filter": "month",
          "search_domain_filter": ["iea.org", "energy.gov"]
        }' | jq
      ```
    </CodeGroup>
  </div>

  <div>
    **Agent API**

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      response = client.responses.create(
          model="perplexity/sonar",
          input="Latest renewable energy policy updates",
          tools=[{"type": "web_search", "filters": {"search_domain_filter": ["iea.org", "energy.gov"], "search_recency_filter": "month"}}],
      )
      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: 'perplexity/sonar',
        input: 'Latest renewable energy policy updates',
        tools: [{ type: 'web_search' as const, filters: { search_domain_filter: ['iea.org', 'energy.gov'], search_recency_filter: 'month' } }],
      });
      console.log(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 '{
          "model": "perplexity/sonar",
          "input": "Latest renewable energy policy updates",
          "tools": [
            {
              "type": "web_search",
              "filters": {
                "search_domain_filter": ["iea.org", "energy.gov"],
                "search_recency_filter": "month"
              }
            }
          ]
        }' | jq
      ```
    </CodeGroup>
  </div>
</Columns>

<Tip>
  **Web search is just one tool.** Add the [`sandbox`](/docs/agent-api/tools/sandbox) and the model writes and runs its own code, generating files you download from the response — and [Wide Research](/docs/agent-api/wide-research) scales that search-and-code combination to hundreds of source-backed items.
  See the [tools overview](/docs/agent-api/tools/overview) for the full set.
</Tip>

### Inline citations

Sonar returned inline `[n]` citations by default.

<Note>
  The Agent API `fast`, `low`, `medium`, and `high` presets already include inline citations for source-backed claims. The `fast` preset uses numbered citations such as `[1]`; `low`, `medium`, and `high` use source-typed citations such as `[web:1]`. The custom `instructions` below are for requests that specify a model and tools directly instead of using one of those presets.
</Note>

For a custom configuration, tell the model to cite the numbered web search results in its `instructions`:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="perplexity/sonar",
      instructions=(
          "Base every factual statement on the numbered web search results provided. "
          "Before finalizing, verify each claim against the sources: re-read the cited results and "
          "confirm they actually support the statement; if a claim is not directly supported, drop "
          "it or soften it rather than guessing. "
          "After each sentence that uses information from those results, cite the exact source "
          "number(s) in square brackets right after the statement, like [1] or [1][2], with no "
          "space before the bracket. Cite the one to three sources that most directly support the "
          "statement, and only cite a source that actually contains that information. Do not cite a "
          "source you did not use, do not invent source numbers, and do not add a separate "
          "references section."
      ),
      input="What are the latest developments in AI agents?",
      tools=[{"type": "web_search"}],
  )

  print(response.output_text)  # answer with inline [n] markers
  ```

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

  const client = new Perplexity();

  const response = await client.responses.create({
    model: 'perplexity/sonar',
    instructions:
      'Base every factual statement on the numbered web search results provided. ' +
      'Before finalizing, verify each claim against the sources: re-read the cited results and ' +
      'confirm they actually support the statement; if a claim is not directly supported, drop ' +
      'it or soften it rather than guessing. ' +
      'After each sentence that uses information from those results, cite the exact source ' +
      'number(s) in square brackets right after the statement, like [1] or [1][2], with no ' +
      'space before the bracket. Cite the one to three sources that most directly support the ' +
      'statement, and only cite a source that actually contains that information. Do not cite a ' +
      'source you did not use, do not invent source numbers, and do not add a separate ' +
      'references section.',
    input: 'What are the latest developments in AI agents?',
    tools: [{ type: 'web_search' as const }],
  });

  console.log(response.output_text); // answer with inline [n] markers
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "perplexity/sonar",
      "instructions": "Base every factual statement on the numbered web search results provided. Before finalizing, verify each claim against the sources: re-read the cited results and confirm they actually support the statement; if a claim is not directly supported, drop it or soften it rather than guessing. After each sentence that uses information from those results, cite the exact source number(s) in square brackets right after the statement, like [1] or [1][2], with no space before the bracket. Cite the one to three sources that most directly support the statement, and only cite a source that actually contains that information. Do not cite a source you did not use, do not invent source numbers, and do not add a separate references section.",
      "input": "What are the latest developments in AI agents?",
      "tools": [{ "type": "web_search" }]
    }' | jq
  ```
</CodeGroup>

The `[n]` markers are embedded directly in the answer text, not in a separate field.
The sources they point to come back separately in an `output` item with `type: "search_results"` — read them from its `results`, each carrying an `id`, and each `[n]` marker maps to the result whose `id` is `n`.

<Tip>
  **More than search — the Agent API is agentic.** The model runs a [loop](/docs/agent-api/building-agents/define-the-run), so you can hand it a task and let it work through the steps itself.
  In addition to web search, it can call tools like [Finance Search](/docs/agent-api/tools/finance-search) for structured market and filing data and [People Search](/docs/agent-api/tools/people-search) for professional profiles.
</Tip>

## 5. Map Sonar models to presets

Starting points we suggest: `sonar` → `fast`, `sonar-pro` → `low`, `sonar-reasoning-pro` → `medium`, `sonar-deep-research` → `high`.
See [Presets](/docs/agent-api/presets) for details.

<Columns>
  <div>
    **Sonar**

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      completion = client.chat.completions.create(
          model="sonar-deep-research",
          messages=[{"role": "user", "content": "What are the latest developments in AI agents?"}]
      )
      print(completion.choices[0].message.content)
      ```

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

      const client = new Perplexity();

      const completion = await client.chat.completions.create({
        model: 'sonar-deep-research',
        messages: [{ role: 'user', content: 'What are the latest developments in AI agents?' }]
      });
      console.log(completion.choices[0].message.content);
      ```

      ```bash cURL theme={null}
      curl https://api.perplexity.ai/v1/sonar \
        -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "sonar-deep-research",
          "messages": [
            {"role": "user", "content": "What are the latest developments in AI agents?"}
          ]
        }' | jq
      ```
    </CodeGroup>
  </div>

  <div>
    **Agent API**

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      response = client.responses.create(
          preset="high",
          input="What are the latest developments in AI agents?",
      )
      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({
        preset: 'high',
        input: 'What are the latest developments in AI agents?',
      });
      console.log(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": "high",
          "input": "What are the latest developments in AI agents?"
        }' | jq
      ```
    </CodeGroup>
  </div>
</Columns>

<Tip>
  **Need more than Sonar could do?** Use the higher tiers.
  [`high`](/docs/agent-api/presets#choosing-a-preset) does deep research across many sources — good for detailed analysis and reports.
  [`xhigh`](/docs/agent-api/presets#choosing-a-preset) adds a code sandbox and runs longer tool-use loops, so it can handle open-ended tasks that a single query can't.
</Tip>

## 6. Migrate async requests (optional)

Sonar's async API maps to Agent API background runs: submit with `background: true` and poll the response by id.
See [Background Runs](/docs/agent-api/output-control#background-runs) for the request shape, polling, reconnect, and the full lifecycle.

## Parameter reference

Map the common Sonar parameters to their Agent API equivalents. Some are direct field moves; others are the closest Agent API pattern, and those rows call out the missing 1:1 equivalent.

<Note>
  Missing a Sonar behavior you rely on? Tell us at [api@perplexity.ai](mailto:api@perplexity.ai) — it helps us prioritize what lands on the Agent API next.
</Note>

### Standard OpenAI parameters

The `stream` parameter carries over unchanged. The Agent API also accepts `temperature` and `top_p`, but whether they affect generation depends on the selected model.

<Warning>
  For GPT-5, o1, and o3 model families—including `openai/gpt-5.6-sol`—the Agent API silently ignores `temperature` and `top_p`. Do not migrate logic that depends on these parameters taking effect for those models. Even when a model supports sampling controls, setting `temperature` to `0` does not guarantee deterministic or byte-identical output across requests.
</Warning>

A couple of parameters change on the Agent API:

* `max_tokens` is renamed to `max_output_tokens`.
* `response_format` keeps the same shape for `json_schema`, and structured outputs are not restricted to specific Perplexity models on the Agent API. Sonar's `response_format.type: "regex"` has no Agent API equivalent — redesign regex flows around a JSON schema.

### Sonar-specific parameters

**Direct equivalents (some renamed or relocated):**

| Sonar parameter                                                                                                                                                  | Agent API equivalent                                                                                                                |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| [Domain, recency, and date filters](/docs/sonar/filters)<br />(`search_domain_filter`, `search_recency_filter`, `search_*_date_filter`, `last_updated_*_filter`) | Same names, inside the [`web_search` tool's `filters`](/docs/agent-api/tools/web-search#filters)                                    |
| `web_search_options.search_context_size`                                                                                                                         | [`search_context_size`](/docs/agent-api/tools/web-search#configuring-search) on the `web_search` tool, not in `filters`             |
| `web_search_options.user_location`                                                                                                                               | [`user_location`](/docs/agent-api/tools/web-search#location-filter) on the `web_search` tool, not in `filters`                      |
| `num_search_results`                                                                                                                                             | [`max_results`](/docs/agent-api/tools/web-search#number-of-results) on the `web_search` tool — a cap on the total number of results |
| `reasoning_effort`                                                                                                                                               | `reasoning.effort`                                                                                                                  |

**No direct field — map to a tool or pattern:**

| Sonar parameter            | Agent API equivalent                                                                                                                                                                                                                                                                                                       |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enable_search_classifier` | Provide the [`web_search`](/docs/agent-api/tools/web-search) tool and let the model decide when to search                                                                                                                                                                                                                  |
| `disable_search`           | Omit the [`web_search`](/docs/agent-api/tools/web-search) tool. With a preset, the preset's tools stay enabled — `tools: []` does not clear them and there is currently no public way to disable preset tools; `max_tool_calls: 0` disables all tool calls as a blunt workaround                                           |
| `search_mode`              | `web` (the default) is implicit. `academic` has no direct equivalent; use `web_search` with domain filters and prompting. For `sec`, use [Finance Search](/docs/agent-api/tools/finance-search) for structured finance data or `web_search` filtered to SEC sources for filing/source retrieval                            |
| `search_type` (Pro Search) | No direct equivalent — map `"fast"` to the [`fast` preset](/docs/agent-api/presets) (formerly `fast-search`) and `"pro"` to `preset: "low"` (formerly `pro-search`) for the multi-step Pro Search behavior, or set `max_steps` on an explicit model to bound multi-step search. There is no `"auto"` classifier equivalent |
| `return_related_questions` | Prompt the model to end with a few follow-up questions, optionally through a [structured output](/docs/agent-api/output-control#structured-outputs) schema                                                                                                                                                                 |

**No Agent API equivalent — drop these:**

* `search_language_filter`.
* `stream_mode` — Agent API streaming always emits typed SSE events with reasoning and tool activity as separate events, closest to Sonar's `concise` mode; there is no `full`-mode inline-metadata format.
* [Image results](/docs/sonar/media#receiving-images) (`return_images`, `num_images`, `image_domain_filter`, `image_format_filter`, `web_search_options.image_results_enhanced_relevance`) — not supported; the Agent API returns no `images`.
* [Video results](/docs/sonar/media#receiving-videos) (`return_videos`, `num_videos`, `media_response`) — not supported; the Agent API returns no `videos`.

<Tip>
  See the [Web Search](/docs/agent-api/tools/web-search) reference for the full set of `web_search` options.
</Tip>

### Multimodal input

| Sonar content part     | Agent API                                                                               |
| ---------------------- | --------------------------------------------------------------------------------------- |
| `image_url`            | [`input_image` content part](/docs/agent-api/image-attachments) (data URI or HTTPS URL) |
| `file_url` / `pdf_url` | No equivalent                                                                           |
| `video_url`            | No equivalent                                                                           |


# Migrate from Sonar to the Agent API
Source: https://docs.perplexity.ai/docs/agent-api/migrate-from-sonar/overview

The Agent API represents a major upgrade of Sonar Chat Completions, bringing added configuration and powerful agentic primitives to your AI applications.

While Sonar Chat Completions remains supported, the Agent API is more performant and cost-effective for production workloads. It features Perplexity's latest innovations in search and reasoning technology, including Search as Code and tuned presets.

<Note>
  We recommend:

  * Migrating existing Sonar Chat Completions usage to the Agent API.
  * Using the Agent API for all new projects.
</Note>

## About the Agent API

Agent API is a unified interface for building powerful agent applications.

It contains:

* One API to call all the leading frontier and open-source models.
* Built-in tools such as [web search](/docs/agent-api/tools/web-search), [URL fetching](/docs/agent-api/tools/fetch-url-content), [sandboxes](/docs/agent-api/tools/sandbox), and [MCP](/docs/agent-api/tools/mcp), plus premium data sources like [finance](/docs/agent-api/tools/finance-search) and [people search](/docs/agent-api/tools/people-search).
* Research-backed configurations for agentic workflows, based on specific task intensity (fast, low, medium, high, xhigh — [presets](/docs/agent-api/presets)).
* Compatibility with the [Open Responses](https://www.openresponses.org/) standard to ensure portability and avoid lock-in — we want to win your business on performance and efficiency, not on locking you in with exorbitant migration costs.
* Seamless multi-turn interactions that let you [pass previous responses](/docs/agent-api/conversation-state#resume-from-a-prior-response) for higher-accuracy reasoning.

## Why migrate

Agent API contains several benefits over Sonar Chat Completions:

* Full flexibility to select across the OpenAI, Anthropic, Google, xAI, Z.AI, Moonshot AI, and NVIDIA model families, in addition to Perplexity's Sonar model.
* The ability to leverage multiple tools and spin up an agentic loop that reasons, acts, observes results, and continues within a single request.
* A secure [sandbox](/docs/agent-api/tools/sandbox) to run generated code — compute results, analyze data, and verify outputs without leaving the request.
* Connect external servers with [MCP](/docs/agent-api/tools/mcp) or define your own [custom functions](/docs/agent-api/tools/custom-functions) to extend the agent with your tools and private data.
* [Wide Research](/docs/agent-api/wide-research) to run wide-and-deep tasks in the background and build large, evidence-backed collections in a single request.

## Sonar vs Agent API

| Capability                              |       Sonar API       |       Agent API       |
| --------------------------------------- | :-------------------: | :-------------------: |
| Leading frontier and open-source models |                       | <Icon icon="check" /> |
| Built-in web search                     | <Icon icon="check" /> | <Icon icon="check" /> |
| People Search                           |                       | <Icon icon="check" /> |
| Finance Search                          |                       | <Icon icon="check" /> |
| Code sandbox                            |                       | <Icon icon="check" /> |
| MCP servers                             |                       | <Icon icon="check" /> |
| Model fallback                          |                       | <Icon icon="check" /> |
| Structured outputs                      | <Icon icon="check" /> | <Icon icon="check" /> |
| Streaming                               | <Icon icon="check" /> | <Icon icon="check" /> |
| Async mode                              | <Icon icon="check" /> | <Icon icon="check" /> |

Both call a model but shape the request differently.
Sonar takes a `messages` array and returns `choices`.
The Agent API takes an `input` and returns a typed `output` array — one item per step the model took, with a `message` item for the answer text and a `search_results` item for the sources.

<Columns>
  <div>
    **Sonar**

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      completion = client.chat.completions.create(
          model="sonar",
          messages=[{"role": "user", "content": "What are the latest developments in AI agents?"}]
      )
      print(completion.choices[0].message.content)
      ```

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

      const client = new Perplexity();

      const completion = await client.chat.completions.create({
        model: 'sonar',
        messages: [{ role: 'user', content: 'What are the latest developments in AI agents?' }]
      });
      console.log(completion.choices[0].message.content);
      ```

      ```bash cURL theme={null}
      curl https://api.perplexity.ai/v1/sonar \
        -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "sonar",
          "messages": [
            {"role": "user", "content": "What are the latest developments in AI agents?"}
          ]
        }' | jq
      ```
    </CodeGroup>
  </div>

  <div>
    **Agent API**

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      response = client.responses.create(
          preset="fast",
          input="What are the latest developments in AI agents?"
      )
      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({
        preset: 'fast',
        input: 'What are the latest developments in AI agents?'
      });
      console.log(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": "fast",
          "input": "What are the latest developments in AI agents?"
        }' | jq
      ```
    </CodeGroup>
  </div>
</Columns>

<Tabs>
  <Tab title="Sonar response">
    ```json theme={null}
    {
      "id": "8158ec84-87a8-40fd-8720-a8b8e628708c",
      "choices": [
        {
          // ...
          "message": {"content": "The latest developments in AI agents (as of July 2026) center on **massive model upgrades**, **open-source toolkits**, **real-world autonomous transactions**, and **enterprise-grade security frameworks** ...", "role": "assistant"},
          "finish_reason": "stop"
        }
      ],
      "created": 1784292153,
      "model": "sonar",
      "citations": [
        "https://medium.com/@agencyai/this-weeks-ai-agent-roundup-20-launches-and-updates-you-shouldn-t-miss-401202306f62",
        "https://www.itechmagazine.com/ai-agents-news/"
        // ...
      ],
      "object": "chat.completion",
      "search_results": [
        {"title": "AI Agents News 2026: What's Happening Right Now and Why It ...", "url": "https://www.itechmagazine.com/ai-agents-news/", "date": "2026-06-14", "last_updated": "2026-06-21", "snippet": "Amazon Web Services open-sourced its Strands Agents SDK, a toolkit that helps developers b ...", "source": "web", "place_metadata": null}
        // ...
      ]
      // ...
    }
    ```
  </Tab>

  <Tab title="Agent API response">
    ```json theme={null}
    {
      "id": "resp_18690c07-7c56-48fa-85a3-fd22e34df694",
      "created_at": 1784292159,
      "model": "openai/gpt-5.4-mini",
      "object": "response",
      "output": [
        {
          "results": [
            {"id": 1, "snippet": "This transition from one-shot intelligence to endurance, from conversational AI to genuine autonomy ...", "title": "State of AI Agents 2026: Autonomy is Here", "url": "https://www.prosus.com/news-insights/2026/state-of-ai-agents-2026-autonomy-is-here", "date": "2026-02-26", "last_updated": "2026-07-12", "source": "web"}
            // ...
          ],
          "type": "search_results"
          // ...
        },
        {
          "id": "msg_525b46ea-4e33-400b-add0-6862a48549b9",
          "content": [
            {"text": "The latest developments in AI agents are centered on **greater autonomy, better orchestration, and stronger enterprise controls**[1][3] ...", "type": "output_text", "annotations": []}
          ],
          "role": "assistant",
          "status": "completed",
          "type": "message"
        }
      ],
      "status": "completed"
      // ...
    }
    ```
  </Tab>
</Tabs>

## How Sonar Chat Completions maps to Agent API presets

While performance improvements will vary by individual use-case, our internal benchmarks indicate performance improvements across the below comparable Sonar Chat Completions and Agent API preset mappings.

| Sonar Chat Completions | Agent API preset | Best for                                                                        | What improves                                                                                                                            |
| ---------------------- | ---------------- | ------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| Sonar                  | `fast`           | Single-fact lookups, definitions, quick summaries.                              | More accurate than Sonar, with the clearest gains on research-style, multi-step questions.                                               |
| Sonar Pro              | `low`            | Everyday research questions, light multi-step lookups with current information. | Much more accurate, and unlocks the real multi-step, agentic research that Sonar Pro can't reach.                                        |
| Sonar Reasoning Pro    | `medium`         | Multi-hop browsing and wide aggregation across many sources.                    | Far stronger on step-by-step reasoning and on chaining evidence across several rounds of search.                                         |
| Sonar Deep Research    | `high`           | Expert-level reasoning and exhaustive source coverage.                          | The most accurate tier on demanding expert-level and deep-research work, and often at a lower per-request cost than Sonar Deep Research. |

<Tip>
  For state-of-the-art deep research, use the `xhigh` preset — the highest quality in the lineup, leading across the benchmarks we run.
</Tip>

See [Choosing a preset](/docs/agent-api/presets#choosing-a-preset) for what each preset is best for, and the [benchmarks page](/docs/agent-api/migrate-from-sonar/benchmarks) for the scores.

## Continue your migration

<CardGroup>
  <Card title="How to migrate" icon="arrow-right-arrow-left" href="/docs/agent-api/migrate-from-sonar/how-to">
    Follow the complete field-by-field migration procedure and parameter reference.
  </Card>

  <Card title="Explore the presets" icon="sliders" href="/docs/agent-api/presets">
    See what each preset configures and how to override individual settings.
  </Card>
</CardGroup>


# Model Fallback
Source: https://docs.perplexity.ai/docs/agent-api/model-fallback

Specify multiple models in a fallback chain for higher availability and automatic failover.

## Overview

Model fallback enables specifying multiple models in a `models` array. The API tries each model in order until one succeeds, providing automatic failover when a model is unavailable.

## How It Works

Provide a `models` array containing up to 5 models:

1. The API tries the first model in the array
2. If it fails or is unavailable, the next model is tried
3. This continues until one succeeds or all models are exhausted

The `models` array takes precedence over the single `model` field when both are provided.

<Info>
  **Benefits:**

  * **Higher availability**: Automatic failover when primary model is unavailable
  * **Provider redundancy**: Use models from different providers for maximum reliability
  * **Seamless operation**: No code refactoring needed, fallback is handled automatically by the API
</Info>

## Basic Example

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      models=["openai/gpt-5.6-sol", "anthropic/claude-sonnet-4-6", "google/gemini-3-flash-preview"],
      input="Explain the original Transformer architecture from 'Attention Is All You Need' (Vaswani et al. 2017): encoder-decoder structure, multi-head self-attention, and positional encodings.",
      instructions="You have access to a web_search tool. Use it for questions about current events.",
      max_output_tokens=8192,
  )

  print(f"Model used: {response.model}")
  ```

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

  const client = new Perplexity();

  const response = await client.responses.create({
      models: ["openai/gpt-5.6-sol", "anthropic/claude-sonnet-4-6", "google/gemini-3-flash-preview"],
      input: "Explain the original Transformer architecture from 'Attention Is All You Need' (Vaswani et al. 2017): encoder-decoder structure, multi-head self-attention, and positional encodings.",
      instructions: "You have access to a web_search tool. Use it for questions about current events.",
      max_output_tokens: 8192,
  });

  console.log(`Model used: ${response.model}`);
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "models": ["openai/gpt-5.6-sol", "anthropic/claude-sonnet-4-6", "google/gemini-3-flash-preview"],
      "input": "Explain the original Transformer architecture from \u0027Attention Is All You Need\u0027 (Vaswani et al. 2017): encoder-decoder structure, multi-head self-attention, and positional encodings.",
      "instructions": "You have access to a web_search tool. Use it for questions about current events.",
      "max_output_tokens": 8192
    }'
  ```
</CodeGroup>

<Info>
  Include `max_output_tokens` whenever a fallback chain contains an `anthropic/*` model. Anthropic requests require it even though non-Anthropic providers accept requests without it.
</Info>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_157b10b1-4685-4f11-b372-382b8a04e4dd",
    "created_at": 1779391718,
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "results": [
          {
            "id": 1,
            "snippet": "To the best of our knowledge, however, the Transformer is the first transduction model relying\n...\nThe Transformer follows this overall architecture using stacked self-attention and point-wise, fully\nconnected layers for both the encoder and decoder, shown in the left and right halves of Figure 1,\nrespectively.\n...\nThe encoder is composed of a stack of N = 6 identical layers.\nEach layer has two\nsub-layers.\nThe first is a multi-head self-attention mechanism, and the second is a simple, position-\n...\nand the memory keys and values come from the output of the encoder.\n...\n• The encoder contains self-attention layers.\nIn a self-attention layer all of the keys, values\nand queries come from the same place, in this case, the output of the previous layer in the\nencoder.\nEach position in the encoder can attend to all positions in the previous layer of the\nencoder.\n• Similarly, self-attention layers in the decoder allow each position in the decoder to attend to\nall positions in the decoder up to and including that position.\n...\npositional encodings in both the encoder and decoder stacks.\n...\nIn this work, we presented the Transformer, the first sequence transduction model based entirely on\nattention, replacing the recurrent layers most commonly used in encoder-decoder architectures with\nmulti-headed self-attention.",
            "title": "[PDF] Attention is All you Need - NIPS",
            "url": "https://papers.neurips.cc/paper/7181-attention-is-all-you-need.pdf",
            "date": null,
            "last_updated": "2026-05-20",
            "source": "web"
          },
          {
            "id": 2,
            "snippet": "We propose a new simple network architecture, the Transformer, based solely on attention mechanisms, dispensing with recurrence and convolutions entirely.",
            "title": "[1706.03762] Attention Is All You Need - arXiv",
            "url": "https://arxiv.org/abs/1706.03762",
            "date": "2017-06-12",
            "last_updated": "2026-05-19",
            "source": "web"
          },
          {
            "id": 3,
            "snippet": "{ts:907} encoder which is the positional encoding so what is positional encoding what we want is that each word should\n…\n{ts:963} have this partial information given by our eyes but the model cannot see this so we need to give some information to\n{ts:969} the model about how the words are specially distributed inside of the sentence\n{ts:975} and we want the positional encoding to represent a pattern that the model can learn and we will see how\n{ts:984} imagine we have our original sentence your cat is a lovely cat what we do is we first convert into embeddings using\n{ts:993} the previous layer so the input embeddings and these are embeddings of size 512 then we create some special\n{ts:1000} vectors called the positional encoding vectors that we add to these embeddings so this Vector we see here in red\n…\n...\n{ts:1159} model will see during inference or training so we only compute the positional encoding once\n...\n{ts:1224} so what is self-attention self attention is a mechanism that existed before they introduced the Transformer the Alters of\n{ts:1233} the Transformer just changed it into a multi-head attention so how did the self-attention work\n{ts:1240} the self-attention allows the model to relate words to each other okay so we had the input embeddings that\n{ts:1249} capture the meaning of the word then we have the positional encoding that give the information about the position of\n{ts:1257} the word inside of the sentence now we want this self-attention to relate words to each other",
            "title": "Attention is all you need (Transformer) - YouTube",
            "url": "https://www.youtube.com/watch?v=bCz4OMemCcA",
            "date": "2023-05-28",
            "last_updated": "2026-03-31",
            "source": "web"
          },
          {
            "id": 4,
            "snippet": "\"**Attention Is All You Need**\" is a 2017 research paper in machine learning authored by eight scientists and engineers working at Google.\nThe paper introduced a new deep learning architecture known as the transformer, based on the attention mechanism proposed in 2014 by Bahdanau *et al.* The transformer approach it describes has become the main architecture of a wide variety of artificial intelligence, including large language models.\n...\nThe paper is best known for introducing the Transformer architecture, which underlies most modern large language models (LLMs).\n...\nSince the model relies on Query (*Q*), Key (*K*), and Value (*V*) matrices that come from the same source (i.e., the input sequence or context window), this eliminates the need for RNNs, completely ensuring parallelizability for the architecture.\n...\nIn the self-attention mechanism, queries (Q), keys (K), and values (V) are dynamically generated for each input sequence (typically limited by the size of the context window), allowing the model to focus on different parts of the input sequence at different steps.\nMulti-head attention enhances this process by introducing multiple parallel attention heads.\nEach attention head learns different linear projections of the Q, K, and V matrices.\nThis allows the model to capture different aspects of the relationships between words in the sequence simultaneously, rather than focusing on a single aspect.\nBy doing this, multi-head attention ensures that the input embeddings are updated from a more varied and diverse set of perspectives.\nAfter the attention outputs from all heads are calculated, they are concatenated and passed through a final linear transformation to generate the output.\n...\nSince the Transformer does not rely on recurrence or convolution of the text in order to perform encoding and decoding, the paper relied on the use of sine and cosine wave functions to encode the position of the token into the embedding.\nThe methods introduced in the paper are discussed below:\n\\( PE_{({\\rm {pos}},2i)}=\\sin({\\rm {pos}}/{10000}^{2i/d_{\\rm {model}}}) \\)\n...\nOn 2017-06-12, the original (100M-parameter) encoder–decoder transformer model was published in the \"Attention is all you need\" paper.",
            "title": "Attention Is All You Need - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/Attention_Is_All_You_Need",
            "date": "2023-12-04",
            "last_updated": "2026-05-17",
            "source": "web"
          },
          {
            "id": 5,
            "snippet": "●Presents a new neural architecture named the Transformer\n●Based solely on the attention mechanism widely used in SEQ2SEQ models\n...\nTransformer uses only self-attention \nwhich is attention onto the same \nsentence\n●\n...\non how its meaning is influenced by \n...\nHigh Level\n●\nInput embedding is first added with \nPositional Encoding\n●\n3 components in each \nencoder/decoder: (Masked) Multi-Head \nAttention, Addition & Normalization, \nFeed Forward Network\n...\nMulti-Head Attention\n●\nApply attention to different versions of \nQ, K, V \n●\nExpands model’s ability to focus on \ndifferent positions\n●\nGenerates a multiple “representation \nsubspaces” in order to give the model \nbetter representation of the input\n●\nUses 8 attention heads which are \nconcatenated and fed into a linear layer \nat the end\n...\n• In encoder, all queries, keys, and values come from the same place\n• In encoder-decoder attention layer, queries come from the previous decoder \nlayer and keys and values come from the output of the encoder\n• This mimics the typical encoder-decoder attention mechanism\n• In decoder to ensure auto-regressive property, the model masks everything \nright to the current token being attended\nModel Architecture\nPositional Encoding\n• Since attention mechanism in the \nTransformer does not attend each word \nauto-regressively (no recurrence nor \nconvolution), model needs something to \nlet it know the relative position of tokens \nin the sentence\n• Positional Encoding is the combination \nof sine and cosine functions of different \nfrequencies\n• Advantages include distance between \ntokens being symmetrical and being \neasier to calculate distance between \ntokens",
            "title": "[PDF] Attention Is All You Need",
            "url": "https://ysu1989.github.io/courses/au20/cse5539/Transformer.pdf",
            "date": null,
            "last_updated": "2026-05-15",
            "source": "web"
          },
          {
            "id": 6,
            "snippet": "The Transformer is a neural network architecture, introduced by Vasami *et al.* (2017).\n...\nThe Transformer follows the classic**encoder–decoder ** design for sequence-to-sequence translation.\nThe encoder processes the entire English source sentence, and the decoder generates the French target sentence one token at a time.\nUnlike an RNN-based translator, the Transformer processes sequences in parallel through **self-attention**, enabling it to capture **long-range word dependencies** and context efficiently .\n...\nThe encoder takes an input sentence,(e.g. In English), converts each word to an embedding vector and adds a positional encoding to help determine the order of words in the sentence.\nThis consists of stacked layers each containing :-\n- **Multiple-head self-attention**, where each word attends to all other i.e. in parallel which helps the transformer model to decide different types of relationship between words.\n- **Feed-forward networks** applied to each position\n...\n- **Masked attention**, preventing a token from seeing future outputs, basically the model cannot “peek” at future words.\n- **Encoder-decoder attention** allowing the decoder to attend to the source i.e. the decoder’s queries attend to the encoder’s output key/value, hence making sure that the tokens are in relevant context from source sentence.\n...\nThe encoder is the part of the Transformer that processes the input sentence in this case, “**The cat sat on the mat**.”\nEach word is first turned into a word embedding (a vector representing its meaning) and combined with a **positional encoding** (Vaswani et al., 2017) to preserve word order.\n...\nSince Transformers do not process input sequentially like RNNs, positional encodings are added to embeddings to inform the model about word positions.\nThese encodings **use sine and cosine ** functions at varying frequencies, allowing the model to learn relative and absolute positions in the sequence .\n...\nThe **self-attention** mechanism enables each word in the sentence to “attend” to every other word and determine how important they are in context.\n...\nNow, instead of applying self-attention just once, **multi-head attention ** allows the model to attend to different types of relationships in **parallel** . Each head learns different patterns:\n- One might detect grammatical structure (e.g., connecting “the” to “cat”),\n- Another might track verb-subject relations (e.g., “cat” to “sat”),\n- Another may focus on positional or contextual clues (Vaswani et al., 2017).\nThe outputs from all heads are combined, giving the model a deeper, more comprehensive understanding of the input.",
            "title": "Review of “Attention Is All You Need (Vaswani et al., 2017)”",
            "url": "https://harbisingh.wordpress.com/2025/08/12/review-of-attention-is-all-you-need-vaswani-et-al-2017/",
            "date": "2025-08-12",
            "last_updated": "2026-04-05",
            "source": "web"
          },
          {
            "id": 7,
            "snippet": "We propose a new simple network architecture, the Transformer, based solely on attention mechanisms, dispensing with recurrence and convolutions entirely.\n...\nIn this work we propose the Transformer, a model architecture eschewing recurrence and instead relying entirely on an attention mechanism to draw global dependencies between input and output.\n...\nTo the best of our knowledge, however, the Transformer is the first transduction model relying entirely on self-attention to compute representations of its input and output without using sequence-aligned RNNs or convolution.\n...\nThe Transformer follows this overall architecture using stacked self-attention and point-wise, fully connected layers for both the encoder and decoder, shown in the left and right halves of Figure 1, respectively.\n...\nThe encoder is composed of a stack of N=6 identical layers.\nEach layer has two sub-layers.\nThe first is a multi-head self-attention mechanism, and the second is a simple, position-wise fully connected feed-forward network.\n...\nThe decoder is also composed of a stack of N=6 identical layers.\nIn addition to the two sub-layers in each encoder layer, the decoder inserts a third sub-layer, which performs multi-head attention over the output of the encoder stack.\n...\nWe also modify the self-attention sub-layer in the decoder stack to prevent positions from attending to subsequent positions.\nThis masking, combined with fact that the output embeddings are offset by one position, ensures that the predictions for position i can depend only on the known outputs at positions less than i.\n...\nMulti-head attention allows the model to jointly attend to information from different representation subspaces at different positions.\n...\nIn \"encoder-decoder attention\" layers, the queries come from the previous decoder layer, and the memory keys and values come from the output of the encoder.\nThis allows every position in the decoder to attend over all positions in the input sequence.\n...\nThe encoder contains self-attention layers.\nIn a self-attention layer all of the keys, values and queries come from the same place, in this case, the output of the previous layer in the encoder.\nEach position in the encoder can attend to all positions in the previous layer of the encoder.\n...\nSimilarly, self-attention layers in the decoder allow each position in the decoder to attend to all positions in the decoder up to and including that position.\n...\nIn this work, we presented the Transformer, the first sequence transduction model based entirely on attention, replacing the recurrent layers most commonly used in encoder-decoder architectures with multi-headed self-attention.",
            "title": "Attention Is All You Need - arXiv",
            "url": "https://arxiv.org/html/1706.03762v7",
            "date": null,
            "last_updated": "2026-05-18",
            "source": "web"
          },
          {
            "id": 8,
            "snippet": "We propose a new simple network architecture, the Transformer, based solely on attention mechanisms, dispensing with recurrence and convolutions entirely.\n...\nIn this work we propose the Transformer, a model architecture eschewing recurrence and instead relying entirely on an attention mechanism to draw global dependencies between input and output.\n...\nTo the best of our knowledge, however, the Transformer is the first transduction model relying entirely on self-attention to compute representations of its input and output without using sequence-aligned RNNs or convolution.\n...\nThe Transformer follows this overall architecture using stacked self-attention and point-wise, fully connected layers for both the encoder and decoder, shown in the left and right halves of Figure 1, respectively.\n...\nThe encoder is composed of a stack of N=6 identical layers.\nEach layer has two sub-layers.\nThe first is a multi-head self-attention mechanism, and the second is a simple, position-wise fully connected feed-forward network.\n...\nThe decoder is also composed of a stack of N=6 identical layers.\nIn addition to the two sub-layers in each encoder layer, the decoder inserts a third sub-layer, which performs multi-head attention over the output of the encoder stack.\n...\nWe also modify the self-attention sub-layer in the decoder stack to prevent positions from attending to subsequent positions.\nThis masking, combined with fact that the output embeddings are offset by one position, ensures that the predictions for position i can depend only on the known outputs at positions less than i.\n...\nIn \"encoder-decoder attention\" layers, the queries come from the previous decoder layer, and the memory keys and values come from the output of the encoder.\nThis allows every position in the decoder to attend over all positions in the input sequence.\n...\nThe encoder contains self-attention layers.\nIn a self-attention layer all of the keys, values and queries come from the same place, in this case, the output of the previous layer in the encoder.\nEach position in the encoder can attend to all positions in the previous layer of the encoder.\n...\nSimilarly, self-attention layers in the decoder allow each position in the decoder to attend to all positions in the decoder up to and including that position.\n...\nIn addition to attention sub-layers, each of the layers in our encoder and decoder contains a fully connected feed-forward network, which is applied to each position separately and identically.\n...\nIn this work, we presented the Transformer, the first sequence transduction model based entirely on attention, replacing the recurrent layers most commonly used in encoder-decoder architectures with multi-headed self-attention.",
            "title": "Attention Is All You Need",
            "url": "https://arxiv.org/html/1706.03762?_immersive_translate_auto_translate=1",
            "date": null,
            "last_updated": "2026-03-23",
            "source": "web"
          },
          {
            "id": 9,
            "snippet": "To the best of our knowledge, however, the Transformer is the first transduction model relying\nentirely on self-attention to compute representations of its input and output without using sequence-\naligned RNNs or convolution.\n...\nThe Transformer follows this overall architecture using stacked self-attention and point-wise, fully\nconnected layers for both the encoder and decoder, shown in the left and right halves of Figure 1,\nrespectively.\n...\nEncoder:\nThe encoder is composed of a stack of N = 6 identical layers.\nEach layer has two\nsub-layers.\nThe first is a multi-head self-attention mechanism, and the second is a simple, position-\n...\nDecoder:\nThe decoder is also composed of a stack of N = 6 identical layers.\nIn addition to the two\nsub-layers in each encoder layer, the decoder inserts a third sub-layer, which performs multi-head\nattention over the output of the encoder stack.\n...\nWe also modify the self-attention\nsub-layer in the decoder stack to prevent positions from attending to subsequent positions.\n...\nThe Transformer uses multi-head attention in three different ways:\n• In \"encoder-decoder attention\" layers, the queries come from the previous decoder layer,\nand the memory keys and values come from the output of the encoder.\nThis allows every\nposition in the decoder to attend over all positions in the input sequence.\nThis mimics the\ntypical encoder-decoder attention mechanisms in sequence-to-sequence models such as\n[31, 2, 8].\n• The encoder contains self-attention layers.\nIn a self-attention layer all of the keys, values\nand queries come from the same place, in this case, the output of the previous layer in the\nencoder.\nEach position in the encoder can attend to all positions in the previous layer of the\nencoder.\n• Similarly, self-attention layers in the decoder allow each position in the decoder to attend to\nall positions in the decoder up to and including that position.\n...\nIn this work, we presented the Transformer, the first sequence transduction model based entirely on\nattention, replacing the recurrent layers most commonly used in encoder-decoder architectures with\nmulti-headed self-attention.",
            "title": "[PDF] Attention is All you Need - NIPS",
            "url": "https://proceedings.neurips.cc/paper_files/paper/2017/file/3f5ee243547dee91fbd053c1c4a845aa-Paper.pdf",
            "date": null,
            "last_updated": "2026-05-20",
            "source": "web"
          },
          {
            "id": 10,
            "snippet": "In this work we propose the Transformer, a model architecture eschewing recurrence and instead\nrelying entirely on an attention mechanism to draw global dependencies between input and output.\n...\nTo the best of our knowledge, however, the Transformer is the first transduction model relying\nentirely on self-attention to compute representations of its input and output without using sequence-\naligned RNNs or convolution.\n...\nThe Transformer follows this overall architecture using stacked self-attention and point-wise, fully\nconnected layers for both the encoder and decoder, shown in the left and right halves of Figure 1,\nrespectively.\n...\nThe encoder is composed of a stack of N = 6 identical layers.\nEach layer has two\nsub-layers.\nThe first is a multi-head self-attention mechanism, and the second is a simple, position-\n...\nThe decoder is also composed of a stack of N = 6 identical layers.\nIn addition to the two\nsub-layers in each encoder layer, the decoder inserts a third sub-layer, which performs multi-head\nattention over the output of the encoder stack.\n...\nIn this work we employ h = 8 parallel attention layers, or heads.\n...\nThe Transformer uses multi-head attention in three different ways:\n• In \"encoder-decoder attention\" layers, the queries come from the previous decoder layer,\nand the memory keys and values come from the output of the encoder.\nThis allows every\nposition in the decoder to attend over all positions in the input sequence.\nThis mimics the\ntypical encoder-decoder attention mechanisms in sequence-to-sequence models such as\n[31, 2, 8].\n• The encoder contains self-attention layers.\nIn a self-attention layer all of the keys, values\nand queries come from the same place, in this case, the output of the previous layer in the\nencoder.\nEach position in the encoder can attend to all positions in the previous layer of the\nencoder.\n• Similarly, self-attention layers in the decoder allow each position in the decoder to attend to\nall positions in the decoder up to and including that position.\nWe need to prevent leftward",
            "title": "Attention is All you Need",
            "url": "https://papers.neurips.cc/paper/2017/file/3f5ee243547dee91fbd053c1c4a845aa-Paper.pdf",
            "date": null,
            "last_updated": "2025-02-04",
            "source": "web"
          }
        ],
        "type": "search_results",
        "queries": [
          "Attention is All You Need Vaswani 2017 transformer architecture encoder decoder multi-head self-attention positional encoding"
        ]
      },
      {
        "id": "msg_14924dfc-980f-4339-9b39-d0f6eb987f87",
        "content": [
          {
            "text": "The original Transformer is a stacked encoder–decoder sequence model that replaces recurrence with multi‑head self‑attention plus position‑wise feed‑forward layers, with sinusoidal positional encodings added to token embeddings to supply order information. [web:7][web:9] Multi‑head attention computes several parallel scaled dot‑product attentions using different learned projections of queries, keys, and values, then concatenates and linearly mixes them. [web:7][web:9]\n\n## Encoder–decoder structure\n\nThe Transformer is an encoder–decoder architecture for sequence transduction (e.g., machine translation), built entirely from attention and feed‑forward layers, without RNNs or convolutions. [web:7][web:9] The base model in the paper uses 6 encoder layers and 6 decoder layers, each operating on vectors of dimension \\(d_{\\text{model}} = 512\\). [web:7][web:9]\n\n- **Encoder** layers:\n  - Each encoder layer has:\n    - A multi‑head self‑attention sublayer.\n    - A position‑wise fully connected feed‑forward network. [web:7][web:9]\n  - Each sublayer is wrapped with residual connection and layer normalization (input + sublayer output, then LayerNorm). [web:7][web:9]\n\n- Decoder layers:\n  - Each decoder layer has three sublayers:\n    - Masked multi‑head self‑attention over the decoder’s own previous outputs.\n    - Multi‑head encoder–decoder attention, where queries come from the decoder and keys/values from the encoder outputs.\n    - A position‑wise feed‑forward network. [web:7][web:9]\n  - The self‑attention in the decoder is masked so position \\(i\\) cannot attend to positions \\(> i\\), preserving the autoregressive property. [web:7][web:9]\n\n## Scaled dot‑product attention\n\nThe core building block is scaled dot‑product attention, which maps queries \\(Q\\), keys \\(K\\), and values \\(V\\) to an output:  \n\\[\n\\text{Attention}(Q,K,V) = \\text{softmax}\\left(\\frac{QK^\\top}{\\sqrt{d_k}}\\right)V.\n\\]  \n[web:7][web:9]\n\n- **Queries, keys, values** are all learned linear projections of the input representations in that layer. [web:7][web:9]\n- The dot products \\(QK^\\top\\) produce attention scores, scaled by \\(1/\\sqrt{d_k}\\) to prevent large magnitudes from pushing softmax into very small gradients. [web:7][web:9]\n- The softmax over each query’s scores gives attention weights over positions; these weights form a weighted sum of the value vectors. [web:7][web:9]\n\nIn self‑attention, \\(Q\\), \\(K\\), and \\(V\\) all come from the same sequence representations; in encoder–decoder attention, \\(Q\\) comes from the decoder and \\(K,V\\) from the encoder. [web:7][web:9]\n\n## Multi‑head self‑attention\n\nMulti‑head attention repeats scaled dot‑product attention in parallel with different learned projections, letting the model focus on different relation patterns and positions simultaneously. [web:7][web:9]\n\n- For each of \\(h\\) heads (the paper uses \\(h = 8\\)):\n  - Project inputs linearly to per‑head \\(Q_i, K_i, V_i \\in \\mathbb{R}^{d_k}, \\mathbb{R}^{d_k}, \\mathbb{R}^{d_v}\\) with separate weight matrices. [web:7][web:9]\n  - Compute attention head \\(i\\) as \\(\\text{head}_i = \\text{Attention}(Q_i, K_i, V_i)\\). [web:7][web:9]\n- Concatenate all heads and apply a final linear projection:\n  \\[\n  \\text{MultiHead}(Q,K,V) = \\text{Concat}(\\text{head}_1,\\dots,\\text{head}_h)W^O.\n  \\]  \n  [web:7][web:9]\n\nKey uses:\n\n- Encoder self‑attention: Each position can attend to all positions in the encoder’s previous layer. [web:7][web:9]\n- Decoder masked self‑attention: Each position attends only to positions up to itself, using a mask that sets scores to \\(-\\infty\\) for future positions before softmax. [web:7][web:9]\n- Encoder–decoder attention: Decoder queries attend over all encoder outputs, with keys and values from the encoder and queries from the decoder. [web:7][web:9]\n\nThis design increases the **expressive** power since different heads can specialize to, for example, syntactic dependencies, coreference, or positional patterns. [web:4][web:5]\n\n## Positional encodings\n\nBecause the Transformer has no recurrence or convolution, it adds positional encodings to input (and output) token embeddings so the model can use order information. [web:7][web:4]\n\n- The paper uses **fixed sinusoidal** positional encodings:\n  - For position \\(\\text{pos}\\) and even dimension \\(2i\\):\n    \\[\n    PE_{\\text{pos}, 2i} = \\sin\\left(\\frac{\\text{pos}}{10000^{2i/d_{\\text{model}}}}\\right),\n    \\quad\n    PE_{\\text{pos}, 2i+1} = \\cos\\left(\\frac{\\text{pos}}{10000^{2i/d_{\\text{model}}}}\\right).\n    \\]\n    [web:4][web:7]\n  - Different dimensions use different frequencies, so relative positions correspond to phase shifts, which allows the model to learn relative as well as absolute distance patterns. [web:4]\n\n- Usage:\n  - For each token, the model sums its learned embedding with the positional encoding vector for its index before feeding into the first encoder or decoder layer. [web:7][web:5]\n  - The same scheme is applied to both source and target sequences. [web:7]\n\nThese fixed encodings avoid extra parameters and support sequences longer than seen in training, while providing smooth, distance‑aware position signals to self‑attention. [web:4][web:7]\n\n## Position‑wise feed‑forward networks\n\nEach layer’s attention sublayer is followed by a position‑wise feed‑forward network applied independently to each sequence position. [web:7][web:9]\n\n- The FFN has the form:\n  \\[\n  \\text{FFN}(x) = \\max(0, xW_1 + b_1)W_2 + b_2,\n  \\]\n  with an inner dimension \\(d_{\\text{ff}} = 2048\\) in the base model. [web:7][web:9]\n- The same FFN parameters are shared across positions but differ between layers. [web:7]\n\nTogether, multi‑head attention, sinusoidal positional encodings, and position‑wise feed‑forward layers form the original Transformer encoder–decoder architecture introduced by Vaswani et al. in 2017. [web:7][web:9]",
            "type": "output_text",
            "annotations": [],
            "logprobs": []
          }
        ],
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "status": "completed",
    "error": null,
    "usage": {
      "input_tokens": 8687,
      "output_tokens": 1599,
      "total_tokens": 10286,
      "cost": {
        "currency": "USD",
        "input_cost": 0.00638,
        "output_cost": 0.01599,
        "total_cost": 0.02532,
        "cache_creation_cost": null,
        "cache_read_cost": 0.00045,
        "tool_calls_cost": 0.0025
      },
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 3584,
        "cached_tokens": 3584
      },
      "tool_calls_details": {
        "search_web": {
          "invocation": 1
        }
      },
      "output_tokens_details": {
        "reasoning_tokens": 0
      }
    },
    "background": false,
    "completed_at": 1779391718,
    "frequency_penalty": 0,
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "user": null
  }
  ```
</Accordion>

## Cross-Provider Fallback

For maximum reliability, use models from different providers:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      models=[
          "openai/gpt-5.6-sol",
          "anthropic/claude-sonnet-4-6",
          "google/gemini-3-flash-preview"
      ],
      input="What did the SEC v. Sam Bankman-Fried complaint (December 2022) allege about FTX, and what was the outcome of his 2023 criminal trial?",
      max_output_tokens=8192,
  )
  ```

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

  const client = new Perplexity();

  const response = await client.responses.create({
      models: [
          "openai/gpt-5.6-sol",
          "anthropic/claude-sonnet-4-6",
          "google/gemini-3-flash-preview"
      ],
      input: "What did the SEC v. Sam Bankman-Fried complaint (December 2022) allege about FTX, and what was the outcome of his 2023 criminal trial?",
      max_output_tokens: 8192,
  });
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "models": [
        "openai/gpt-5.6-sol",
        "anthropic/claude-sonnet-4-6",
        "google/gemini-3-flash-preview"
      ],
      "input": "What did the SEC v. Sam Bankman-Fried complaint (December 2022) allege about FTX, and what was the outcome of his 2023 criminal trial?",
      "max_output_tokens": 8192
    }'
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_e012062c-3b30-474e-82a9-3f8116442e6f",
    "created_at": 1779391825,
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "results": [
          {
            "id": 1,
            "snippet": "The Securities and Exchange Commission today charged Samuel Bankman-Fried with orchestrating a scheme to defraud equity investors in FTX Trading Ltd.\n(FTX), the crypto trading platform of which he was the CEO and co-founder.\n...\nAccording to the SEC’s complaint, since at least May 2019, FTX, based in The Bahamas, raised more than $1.8 billion from equity investors, including approximately $1.1 billion from approximately 90 U.S.-based investors.\n...\nThe complaint alleges that, in reality, Bankman-Fried orchestrated a years-long fraud to conceal from FTX’s investors (1) the undisclosed diversion of FTX customers’ funds to Alameda Research LLC, his privately-held crypto hedge fund; (2) the undisclosed special treatment afforded to Alameda on the FTX platform, including providing Alameda with a virtually unlimited “line of credit” funded by the platform’s customers and exempting Alameda from certain key FTX risk mitigation measures;\nand (3) undisclosed risk stemming from FTX’s exposure to Alameda’s significant holdings of overvalued, illiquid assets such as FTX-affiliated tokens.\nThe complaint further alleges that Bankman-Fried used commingled FTX customers’ funds at Alameda to make undisclosed venture investments, lavish real estate purchases, and large political donations.\n...\nWhile we continue to investigate FTX and other entities and individuals for potential violations of the federal securities laws, as alleged in our complaint, today we are holding Mr. Bankman-Fried responsible for fraudulently raising billions of dollars from investors in FTX and misusing funds belonging to FTX’s trading customers.\"\nThe SEC’s complaint charges Bankman-Fried with violating the anti-fraud provisions of the Securities Act of 1933 and the Securities Exchange Act of 1934.",
            "title": "SEC Charges Samuel Bankman-Fried with Defrauding Investors in ...",
            "url": "https://www.sec.gov/newsroom/press-releases/2022-219",
            "date": "2022-12-13",
            "last_updated": "2025-10-23",
            "source": "web"
          },
          {
            "id": 2,
            "snippet": "The SEC’s Complaint alleges that SBF defrauded investors in FTX by concealing (1) that FTX directed billions of dollars of FTX customer assets to Alameda,[2] (2) that FTX provided special privileges to Alameda, including an exemption from risk mitigation measures and an essentially unlimited line of credit,[3] and (3) FTX’s exposure to Alameda, which was collateralized by largely overvalued and illiquid assets, including FTT, an FTX-affiliated token.[\n4] The SEC alleges that SBF used the funds appropriated to Alameda to make undisclosed investments, lavish real estate purchases, large political donations, and personal “loans” to himself and other executives, as well as to pay Alameda’s lenders following a crash in crypto asset prices in Spring 2022.[5]\nThe Complaint alleges that SBF made many omissions and misstatements of material fact to further the fraud scheme.\nFor example, the Complaint alleges that SBF and Caroline Ellison, the ex-CEO of Alameda and SBF’s personal friend, misrepresented that FTX and Alameda were two separate entities, operating at arm’s length and without any preferential treatment, when in fact, FTX maintained a special relationship with Alameda that permitted Alameda to leverage FTX’s customers’ assets and expose FTX to a high degree of risk.[\n6] In addition, an FTX document published on its website and provided to potential investors misleadingly claimed that FTX segregated customer assets from its own assets and maintained sufficient liquid assets for customer withdrawals.[7] SBF also made material misstatements indicating that FTX did not invest customer assets, and inaccurately reflected FTX’s level of exposure to FTT.[8] On many occasions, SBF made misleading public statements that touted FTX’s controls and risk management measures.[9]\nThe SEC complaint charges SBF with fraud in the offer or sale of securities, in violation of Section 17(a) of the Security Act and fraud in connection with the purchase or sale of securities, in violation of Section 10(b) of the Exchange Act and Rule 10b-5 thereunder.[10]",
            "title": "An Overview of the SEC, SDNY and CFTC Cases Against Sam ...",
            "url": "https://www.pbwt.com/securities-enforcement-litigation-insider/an-overview-of-the-sec-sdny-and-cftc-cases-against-sam-bankman-fried",
            "date": "2022-12-21",
            "last_updated": "2026-05-16",
            "source": "web"
          },
          {
            "id": 3,
            "snippet": "On December 12, 2022, Bankman-Fried was arrested in the Bahamas and extradited to the United States, where he was indicted on seven criminal charges, including wire fraud, commodities fraud, securities fraud, money laundering, and campaign finance law violations.",
            "title": "Sam Bankman-Fried - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/Sam_Bankman-Fried",
            "date": "2021-04-17",
            "last_updated": "2026-05-17",
            "source": "web"
          },
          {
            "id": 4,
            "snippet": "The complaint charges all three defendants with fraud and material misrepresentations in connection with the sale of digital commodities in interstate commerce.\nFurther, the complaint asserts that defendants’ actions caused the loss of over $8 billion in FTX customer deposits.\n...\nThe complaint alleges that from at least May 2019 through November 11, 2022, Bankman-Fried controlled both FTX.com, a centralized digital asset derivative platform, and Alameda, a digital asset trading firm that operated as a primary market maker on FTX.\nAs charged, FTX held itself out as “the safest and easiest way to buy and sell crypto” and represented that customers’ assets, including both fiat and digital assets including bitcoin and ether, were held in “custody” by FTX and segregated from FTX’s own assets.\nTo the contrary, FTX customer assets were routinely accepted and held by Alameda and commingled with Alameda’s funds.\nAlameda, Bankman-Fried, and others also appropriated customer funds for their own operations and activities, including luxury real estate purchases, political contributions, and high-risk, illiquid digital asset industry investments.\nThe complaint further alleges that, at Bankman-Fried’s direction, FTX employees created features in the FTX code that favored Alameda and allowed it to execute transactions even when it did not have sufficient funds available, including an “allow negative flag” and effectively limitless line of credit that allowed Alameda to withdraw billions of dollars in customer assets from FTX.\nThese features were not disclosed to the public.\n...\nIn a parallel, separate action, on December 13, 2022, the United States Attorney for the Southern District of New York unsealed an indictment charging Bankman-Fried with wire fraud, commodities fraud, securities fraud, and money laundering.\nAlso, on December 13, 2022, the Securities and Exchange Commission charged Bankman-Fried with securities fraud.",
            "title": "CFTC Charges Sam Bankman-Fried, FTX Trading and Alameda with ...",
            "url": "https://www.cftc.gov/PressRoom/PressReleases/8638-22",
            "date": "2022-12-13",
            "last_updated": "2026-05-21",
            "source": "web"
          },
          {
            "id": 5,
            "snippet": "According to the allegations contained in the Indictment, the evidence offered at trial, and matters included in public filings:\nBANKMAN-FRIED was the founder and chief executive officer of FTX, an international cryptocurrency exchange.\nFrom 2019 to 2022, BANKMAN-FRIED was the leader and mastermind of a scheme to defraud customers of FTX by misappropriating billions of dollars of those customers’ funds.\nBANKMAN-FRIED took FTX customer funds for his personal use, to make investments and millions of dollars of political contributions to candidates from both parties, and to repay billions of dollars in loans owed by Alameda Research, a cryptocurrency trading fund that BANKMAN-FRIED also founded.\nBANKMAN-FRIED also defrauded lenders to Alameda and equity investors in FTX by providing them false and misleading financial information that concealed his misuse of customer deposits.\nBANKMAN-FRIED repeatedly told his customers, his investors, and the public that customer deposits into FTX were kept safe and were held in custody for the customers, that customer deposits were kept separate from company assets, and that customer deposits would not be used by FTX.\nHe also repeatedly claimed that his trading company, Alameda, did not have any privileged access to FTX and did not receive special treatment from FTX.\nThose statements were false, and BANKMAN-FRIED in fact channeled billions of dollars in customer deposits from FTX to Alameda, and then used those funds to make investments for his own benefit, to make political contributions, and to spend on real estate, among other expenditures.\nHe employed a variety of fraudulent means to perpetrate this fraud.\nFor instance, BANKMAN-FRIED directed co-conspirators to alter FTX’s computer code to allow Alameda to withdraw effectively unlimited amounts of cryptocurrency from the exchange and made false statements to financial institutions to conceal his misuse of customer dollar deposits.\nHe also directed the creation of false financial statements for Alameda’s lenders, inflated FTX’s revenues and profits in numbers provided to investors, and backdated contracts and other documents to conceal his fraudulent conduct.",
            "title": "Samuel Bankman-Fried Sentenced To 25 Years In Prison",
            "url": "https://www.justice.gov/usao-sdny/pr/samuel-bankman-fried-sentenced-25-years-prison",
            "date": "2024-03-28",
            "last_updated": "2026-03-15",
            "source": "web"
          },
          {
            "id": 6,
            "snippet": "Prosecutors said Bankman-Fried had cost customers, investors and lenders over $10 billion by misappropriating billions of dollars to fuel his quest for influence and dominance in the new industry, and had illegally used money from FTX depositors to cover his expenses, which included purchasing luxury properties in the Caribbean, alleged bribes to Chinese officials and private planes.",
            "title": "FTX founder Sam Bankman-Fried sentenced to 25 years in prison",
            "url": "https://www.marketplace.org/story/2024/03/28/sam-bankman-fried-sentenced-to-25-years-in-prison",
            "date": "2024-03-28",
            "last_updated": "2026-03-15",
            "source": "web"
          },
          {
            "id": 7,
            "snippet": "The SEC complaint that applied from May 2019 through November 2022 described activities at FTX\nand Alameda that were never disclosed to investors or customers.\nThe SEC complaint90 included the \nfollowing: \nUndisclosed diversion of FTX customers’ funds to Alameda Research LLC.\nFTX customers \ndeposited billions of dollars into Alameda-owned bank accounts, some which didn’t have the name \nAlameda (e.g., North Dimension, which was an Alameda subsidiary).\nSingh helped write the code that\n…\n...\nSBF propped up Alameda by illegally transferring at least $4 billion in \nFTX customer funds to Alameda, secured by assets including FTT and shares in Robinhood.94   \nUndisclosed risk stemming from FTX’s exposure to Alameda’s significant holdings of overvalued \nilliquid assets such as FTX-affiliated tokens.\nAlameda’s collateral on deposit consisted of enormous",
            "title": "[PDF] Sam Bankman-Fried's FTX | MIT Sloan",
            "url": "https://mitsloan.mit.edu/sites/default/files/2024-06/Sam%20Bankman-Fried's%20FTX.pdf",
            "date": "2024-01-17",
            "last_updated": "2026-05-16",
            "source": "web"
          },
          {
            "id": 8,
            "snippet": "The defendant is “charged with a wide-ranging scheme to misappropriate billions of dollars of customer funds deposited with FTX and mislead investors and lenders to FTX and to Alameda Research,” a release from the U.S. attorney’s office at the Southern District of New York stated.\n...\nThe DOJ’s December 2022 indictment stated Bankman-Fried knowingly defrauded FTX customers by misusing their deposits to invest in other companies and pay off lenders and expenses.",
            "title": "Sam Bankman-Fried found guilty on all seven counts - TechCrunch",
            "url": "https://techcrunch.com/2023/11/02/sam-bankman-fried-found-guilty-on-all-seven-counts/",
            "date": "2023-11-02",
            "last_updated": "2026-04-15",
            "source": "web"
          },
          {
            "id": 9,
            "snippet": "The charges broadly covered two categories: stealing the money of customers who put their money into FTX accounts and lying to investors and creditors.",
            "title": "Sam Bankman-Fried sentenced to 25 years in prison for his FTX ...",
            "url": "https://www.opb.org/article/2024/03/28/sam-bankman-fried-sentenced-to-25-years-in-prison-for-his-ftx-crimes/",
            "date": "2024-03-28",
            "last_updated": "2026-05-16",
            "source": "web"
          },
          {
            "id": 10,
            "snippet": "{ts:49} Bankman-Fried and his co-conspirators stole billions of dollars from FTX customers.\nThe indictment accuses Bankman-Fried of misappropriating FTX.com customers' deposits and using those to pay expenses and debts of \n{ts:62} Alameda Research, his crypto hedge fund.\n...\n{ts:86} Also on December 13th, the Securities and Exchange Commission alleged in a civil lawsuit that Bankman-Fried diverted customer funds from the start of FTX to support Alameda.\nThe SEC says that while he spent lavishly on office space and condominiums in the \n{ts:101} Bahamas and sank billions of dollars of customer funds into speculative venture  investments, Bankman-Fried's house of cards began to crumble.\n...\nThe Commodity Futures Trading Commission, another U.S. markets regulator, filed a separate lawsuit on the same day linking his alleged fraudulent\n{ts:136} conduct at Alameda and FTX to markets that the CFTC regulates.",
            "title": "Sam Bankman-Fried Faces Fraud Charges, Lawsuits Tied to FTX ...",
            "url": "https://www.youtube.com/watch?v=oALv48BicV0",
            "date": "2022-12-13",
            "last_updated": "2026-01-25",
            "source": "web"
          },
          {
            "id": 11,
            "snippet": "Bankman-Fried, the 31-year old son of two Stanford legal scholars and graduate of Massachusetts Institute of Technology, had pleaded not guilty to charges including wire fraud, securities fraud and money laundering tied to the collapse late last year of crypto exchange FTX and sister hedge fund Alameda Research.",
            "title": "Sam Bankman-Fried found guilty on all seven criminal fraud counts",
            "url": "https://web.archive.org/web/20231102235813/https:/www.cnbc.com/2023/11/02/sam-bankman-fried-found-guilty-on-all-seven-criminal-fraud-counts.html",
            "date": "2023-11-02",
            "last_updated": "2024-09-14",
            "source": "web"
          },
          {
            "id": 12,
            "snippet": "He was accused of using customer deposits on the cryptocurrency trading platform FTX, the company he founded, to cover losses at his hedge fund, pay off loans and buy lavish real estate, among other personal expenses.",
            "title": "Disgraced former FTX CEO Sam Bankman-Fried sentenced to 25 ...",
            "url": "https://abcnews.go.com/US/sam-bankman-fried-sentenced-thursday-financial-fraud/story?id=108554809",
            "date": "2024-03-28",
            "last_updated": "2026-02-10",
            "source": "web"
          }
        ],
        "type": "search_results",
        "queries": [
          "SEC v. Sam Bankman-Fried complaint December 2022 allegations FTX",
          "Sam Bankman-Fried criminal trial verdict November 2023 counts outcome",
          "Sam Bankman-Fried sentencing March 2024 length of sentence forfeiture"
        ]
      },
      {
        "id": "msg_fb282ebe-48cc-4585-b6f3-ce4607ee2df7",
        "content": [
          {
            "text": "The December 2022 SEC civil complaint alleged that Sam Bankman‑Fried ran a years‑long scheme to defraud FTX equity investors by secretly diverting billions of dollars of customer funds to Alameda Research, granting Alameda undisclosed special privileges on the FTX platform, and hiding the resulting risks and misuse of funds while publicly touting FTX as safe and well‑controlled.[web:1][web:2] In his 2023 federal criminal trial in New York, a jury found him guilty on all seven counts related to defrauding FTX customers, Alameda lenders, and FTX investors, and in March 2024 he was sentenced to 25 years in prison plus multi‑billion‑dollar forfeiture and restitution orders.[web:5][web:8][web:11]\n\n## SEC complaint allegations\n\nThe SEC’s December 13, 2022 complaint charged Bankman‑Fried with securities fraud under the antifraud provisions of the Securities Act of 1933 and the Securities Exchange Act of 1934.[web:1][web:2] It alleged that since at least May 2019, FTX raised over $1.8 billion from equity investors (about $1.1 billion from roughly 90 U.S. investors) based on false and misleading statements about how customer assets were handled and the risk profile of the business.[web:1]\n\nKey allegations about **FTX** and Alameda in the SEC complaint included:[web:1][web:2][web:7]  \n- Undisclosed diversion of FTX customer funds to Alameda Research, including having customers deposit billions into bank accounts controlled by Alameda or its subsidiaries.  \n- Special treatment for Alameda on the FTX platform, such as an effectively unlimited “line of credit,” exemptions from key risk controls, and code changes (like an “allow negative” balance flag) that let Alameda withdraw customer assets even when it lacked collateral.  \n- Concealment of FTX’s concentrated exposure to Alameda and to overvalued, illiquid assets such as the FTT token, while publicly claiming customer assets were segregated, safe, and not used for FTX’s own investments.  \n- Use of commingled customer funds for venture investments, luxury real estate in the Bahamas, large political donations, and “loans” to insiders, none of which were disclosed to investors.[web:1][web:2]\n\n## 2023 criminal trial verdict\n\nBankman‑Fried was indicted in the Southern District of New York on multiple fraud and conspiracy charges tied to the collapse of FTX and Alameda Research.[web:3][web:8] In November 2023, after a month‑long trial, a federal jury found him guilty on all seven counts, including wire fraud and conspiracy to commit wire fraud on FTX customers and Alameda lenders, as well as securities fraud and commodities fraud conspiracies and money‑laundering conspiracy.[web:8][web:11]\n\nProsecutors argued he orchestrated a “wide‑ranging scheme” to misappropriate billions in FTX customer deposits, using them to cover Alameda losses, repay lenders, make investments, and fund political spending, while lying to investors and lenders about FTX’s financial condition and Alameda’s special access to customer funds.[web:5][web:8][web:9] Evidence described altering FTX code to give Alameda effectively unlimited withdrawals, producing false financial statements for lenders and investors, and making public assurances that customer deposits were safe and segregated when they were not.[web:5][web:8]\n\n## Sentencing outcome\n\nOn March 28, 2024, the judge sentenced Bankman‑Fried to 25 years in federal prison.[web:5][web:6][web:12] The court also ordered forfeiture and financial penalties tied to what prosecutors said were losses exceeding $8–10 billion to customers, investors, and lenders, reflecting the scope of misappropriated funds and the scale of the fraud.[web:5][web:6][web:9]",
            "type": "output_text",
            "annotations": [],
            "logprobs": []
          }
        ],
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "status": "completed",
    "error": null,
    "usage": {
      "input_tokens": 7356,
      "output_tokens": 909,
      "total_tokens": 8265,
      "cost": {
        "currency": "USD",
        "input_cost": 0.00472,
        "output_cost": 0.00909,
        "total_cost": 0.01676,
        "cache_creation_cost": null,
        "cache_read_cost": 0.00045,
        "tool_calls_cost": 0.0025
      },
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 3584,
        "cached_tokens": 3584
      },
      "tool_calls_details": {
        "search_web": {
          "invocation": 1
        }
      },
      "output_tokens_details": {
        "reasoning_tokens": 0
      }
    },
    "background": false,
    "completed_at": 1779391825,
    "frequency_penalty": 0,
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "user": null
  }
  ```
</Accordion>

## Pricing

<Warning>
  Billing is based on the model that serves the request, not all models in the fallback chain.
</Warning>

The `model` field in the response indicates which model was used, and the `usage` field shows the token counts for that model.

<Accordion title="Example">
  **Request:**

  ```json theme={null}
  {
    "models": ["openai/gpt-5.6-sol", "openai/gpt-5.4"],
    "input": "..."
  }
  ```

  **Response** (if first model failed):

  ```json theme={null}
  {
    "model": "openai/gpt-5.6-sol",
    "usage": {
      "input_tokens": 150,
      "output_tokens": 320,
      "total_tokens": 470
    }
  }
  ```

  In this case, billing is based on `gpt-5.1` pricing for 470 tokens.
</Accordion>

<Tip>
  Place preferred models first in the array. Consider pricing differences when ordering the fallback chain.
</Tip>

## Next Steps

<CardGroup>
  <Card title="Agent API Models" icon="brain" href="/docs/agent-api/models">
    Explore available models and their pricing.
  </Card>

  <Card title="Presets" icon="settings" href="/docs/agent-api/presets">
    Explore available presets and their configurations.
  </Card>

  <Card title="Agent API Quickstart" icon="rocket" href="/docs/agent-api/quickstart">
    Get started with your first Agent API call.
  </Card>

  <Card title="API Reference" icon="code-circle" href="/api-reference/agent-post">
    View complete endpoint documentation.
  </Card>
</CardGroup>


# Agent API Models
Source: https://docs.perplexity.ai/docs/agent-api/models

Compare third-party and Perplexity models available through the Agent API, including token pricing and provider documentation.

## Available Models

The Agent API supports direct access to models from multiple providers. All models are accessed directly from first-party providers with transparent token-based pricing.

Pricing rates are updated monthly and **reflect direct first-party provider pricing with no markup**. All charges are based on actual token consumption, and every API response includes exact token counts so you know your costs per request.

<Tip>
  Looking for pre-configured model setups? See [**Presets**](/docs/agent-api/presets) — optimized for specific use cases.
</Tip>

<Tabs>
  <Tab title="Anthropic">
    <Card title="Anthropic">
      Claude Opus (highest reasoning), Sonnet (balanced), and Haiku (fastest, cheapest).
    </Card>

    | Model                         | Input (\$/1M) | Output (\$/1M) | Cache (\$/1M) | Docs                                                                                                                     |
    | ----------------------------- | ------------- | -------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------ |
    | `anthropic/claude-opus-5`     | 5             | 25             | 0.50          | [Claude Opus 5](https://platform.claude.com/docs/en/about-claude/models/overview)                                        |
    | `anthropic/claude-opus-4-8`   | 5             | 25             | 0.50          | [Claude Opus 4.8](https://platform.claude.com/docs/en/about-claude/models/overview)                                      |
    | `anthropic/claude-opus-4-7`   | 5             | 25             | 0.50          | [Claude Opus 4.7](https://www.anthropic.com/news/claude-opus-4-7)                                                        |
    | `anthropic/claude-opus-4-6`   | 5             | 25             | 0.50          | [Claude Opus 4.6](https://www.anthropic.com/news/claude-opus-4-6)                                                        |
    | `anthropic/claude-opus-4-5`   | 5             | 25             | 0.50          | [Claude Opus 4.5](https://www.anthropic.com/news/claude-opus-4-5)                                                        |
    | `anthropic/claude-sonnet-5`   | 2             | 10             | 0.20          | [Claude Sonnet 5](https://platform.claude.com/docs/en/about-claude/models/whats-new-sonnet-5)                            |
    | `anthropic/claude-fable-5`    | 10            | 50             | 1.00          | [Claude Fable 5](https://platform.claude.com/docs/en/about-claude/models/introducing-claude-fable-5-and-claude-mythos-5) |
    | `anthropic/claude-sonnet-4-6` | 3             | 15             | 0.30          | [Claude Sonnet 4.6](https://www.anthropic.com/news/claude-sonnet-4-6)                                                    |
    | `anthropic/claude-sonnet-4-5` | 3             | 15             | 0.30          | [Claude Sonnet 4.5](https://www.anthropic.com/news/claude-sonnet-4-5)                                                    |
    | `anthropic/claude-haiku-4-5`  | 1             | 5              | 0.10          | [Claude Haiku 4.5](https://www.anthropic.com/news/claude-haiku-4-5)                                                      |

    <Warning>
      Requests that use an `anthropic/*` model must include `max_output_tokens`. If omitted, the API returns HTTP 400 with `validation failed: max_output_tokens is required when using Anthropic models`. `max_output_tokens` is a shared Agent API parameter, but this required condition applies only to Anthropic models.
    </Warning>
  </Tab>

  <Tab title="OpenAI">
    <Card title="OpenAI">
      GPT-5 family — flagship, mini, and nano variants.
    </Card>

    | Model                  | Input (\$/1M)                   | Output (\$/1M)                   | Cache (\$/1M) | Docs                                                                 |
    | ---------------------- | ------------------------------- | -------------------------------- | ------------- | -------------------------------------------------------------------- |
    | `openai/gpt-5.6-sol`   | 5.00 (≤272k)<br />10.00 (>272k) | 30.00 (≤272k)<br />45.00 (>272k) | 90% off input | [GPT-5.6](https://openai.com/index/gpt-5-6/)                         |
    | `openai/gpt-5.6-terra` | 2.00 (≤272k)<br />4.00 (>272k)  | 12.00 (≤272k)<br />18.00 (>272k) | 90% off input | [GPT-5.6](https://openai.com/index/gpt-5-6/)                         |
    | `openai/gpt-5.6-luna`  | 0.20 (≤272k)<br />0.40 (>272k)  | 1.20 (≤272k)<br />1.80 (>272k)   | 90% off input | [GPT-5.6](https://openai.com/index/gpt-5-6/)                         |
    | `openai/gpt-5.5`       | 5.00 (≤272k)<br />10.00 (>272k) | 30.00 (≤272k)<br />45.00 (>272k) | 0.50          | [GPT-5.5](https://developers.openai.com/api/docs/models/gpt-5.5)     |
    | `openai/gpt-5.4`       | 2.50 (≤272k)<br />5.00 (>272k)  | 15.00 (≤272k)<br />22.50 (>272k) | 0.25          | [GPT-5.4](https://platform.openai.com/docs/models/gpt-5.4)           |
    | `openai/gpt-5.4-mini`  | 0.75                            | 4.50                             | 0.075         | [GPT-5.4 Mini](https://platform.openai.com/docs/models/gpt-5.4-mini) |
    | `openai/gpt-5.4-nano`  | 0.20                            | 1.25                             | 0.02          | [GPT-5.4 Nano](https://platform.openai.com/docs/models/gpt-5.4-nano) |
    | `openai/gpt-5.2`       | 1.75                            | 14                               | 0.175         | [GPT-5.2](https://platform.openai.com/docs/models/gpt-5.2)           |
    | `openai/gpt-5.1`       | 1.25                            | 10                               | 0.125         | [GPT-5.1](https://platform.openai.com/docs/models/gpt-5.1)           |
    | `openai/gpt-5`         | 1.25                            | 10                               | 0.125         | [GPT-5](https://platform.openai.com/docs/models/gpt-5)               |
    | `openai/gpt-5-mini`    | 0.25                            | 2                                | 0.025         | [GPT-5 Mini](https://platform.openai.com/docs/models/gpt-5-mini)     |
  </Tab>

  <Tab title="Google">
    <Card title="Google">
      Gemini 3 family — Pro for long-context, Flash and Flash Lite for speed.
    </Card>

    | Model                           | Input (\$/1M)                  | Output (\$/1M)                   | Cache (\$/1M) | Docs                                                                                        |
    | ------------------------------- | ------------------------------ | -------------------------------- | ------------- | ------------------------------------------------------------------------------------------- |
    | `google/gemini-3.1-pro-preview` | 2.00 (≤200k)<br />4.00 (>200k) | 12.00 (≤200k)<br />18.00 (>200k) | 90% off input | [Gemini 3.1 Pro](https://ai.google.dev/gemini-api/docs/models#gemini-3.1-pro-preview)       |
    | `google/gemini-3.1-flash-lite`  | 0.25                           | 1.50                             | 90% off input | [Gemini 3.1 Flash Lite](https://ai.google.dev/gemini-api/docs/models/gemini-3.1-flash-lite) |
    | `google/gemini-3.5-flash`       | 1.50                           | 9.00                             | 0.15          | [Gemini 3.5 Flash](https://ai.google.dev/gemini-api/docs/models/gemini-3.5-flash)           |
    | `google/gemini-3.5-flash-lite`  | 0.30                           | 2.50                             | 0.03          | [Gemini 3.5 Flash Lite](https://ai.google.dev/gemini-api/docs/models/gemini-3.5-flash-lite) |
    | `google/gemini-3.6-flash`       | 1.50                           | 7.50                             | 0.15          | [Gemini 3.6 Flash](https://ai.google.dev/gemini-api/docs/models/gemini-3.6-flash)           |
    | `google/gemini-3.7-flash`       | 0.375                          | 1.875                            | 0.0375        | [Gemini 3.7 Flash](https://ai.google.dev/gemini-api/docs/models/gemini-3.7-flash)           |
    | `google/gemini-3-flash-preview` | 0.50                           | 3.00                             | 90% off input | [Gemini 3.0 Flash](https://ai.google.dev/gemini-api/docs/models#gemini-3-flash-preview)     |
  </Tab>

  <Tab title="xAI">
    <Card title="xAI">
      Grok 4.6, 4.5, 4.3, and 4.20 variants: flagship, reasoning, non-reasoning, and multi-agent.
    </Card>

    | Model                         | Input (\$/1M)                  | Output (\$/1M)                  | Cache (\$/1M)                  | Docs                                                           |
    | ----------------------------- | ------------------------------ | ------------------------------- | ------------------------------ | -------------------------------------------------------------- |
    | `xai/grok-4.6`                | 2.00 (≤200k)<br />4.00 (>200k) | 6.00 (≤200k)<br />12.00 (>200k) | 0.50 (≤200k)<br />1.00 (>200k) | [Grok 4.6](https://docs.x.ai/developers/models/grok-4.6)       |
    | `xai/grok-4.5`                | 2.00 (≤200k)<br />4.00 (>200k) | 6.00 (≤200k)<br />12.00 (>200k) | 0.30 (≤200k)<br />0.60 (>200k) | [Grok 4.5](https://docs.x.ai/developers/models)                |
    | `xai/grok-4.3`                | 1.25 (≤200k)<br />2.50 (>200k) | 2.50 (≤200k)<br />5.00 (>200k)  | 0.20                           | [Grok 4.3](https://docs.x.ai/developers/models)                |
    | `xai/grok-4.20-reasoning`     | 1.25 (≤200k)<br />2.50 (>200k) | 2.50 (≤200k)<br />5.00 (>200k)  | 0.20                           | [Grok 4.20 Reasoning](https://docs.x.ai/developers/models)     |
    | `xai/grok-4.20-non-reasoning` | 1.25 (≤200k)<br />2.50 (>200k) | 2.50 (≤200k)<br />5.00 (>200k)  | 0.20                           | [Grok 4.20 Non Reasoning](https://docs.x.ai/developers/models) |
    | `xai/grok-4.20-multi-agent`   | 1.25 (≤200k)<br />2.50 (>200k) | 2.50 (≤200k)<br />5.00 (>200k)  | 0.20                           | [Grok 4.20 Multi-Agent](https://docs.x.ai/developers/models)   |
  </Tab>

  <Tab title="DeepSeek">
    <Card title="DeepSeek">
      DeepSeek V4 Flash 0731 — a fast, efficient open reasoning model with a 1M-token context window.
    </Card>

    | Model                               | Input (\$/1M) | Output (\$/1M) | Cache (\$/1M) | Docs                                           |
    | ----------------------------------- | ------------- | -------------- | ------------- | ---------------------------------------------- |
    | `perplexity/deepseek-v4-flash-0731` | 0.13          | 0.26           | 0.028         | [DeepSeek](https://huggingface.co/deepseek-ai) |
  </Tab>

  <Tab title="Z.AI">
    <Card title="Z.AI">
      GLM 5.2 — Z.AI's flagship reasoning model.
    </Card>

    | Model                | Input (\$/1M) | Output (\$/1M) | Cache (\$/1M) | Docs                     |
    | -------------------- | ------------- | -------------- | ------------- | ------------------------ |
    | `perplexity/glm-5.2` | 1.40          | 4.40           | 0.26          | [GLM](https://docs.z.ai) |
  </Tab>

  <Tab title="Moonshot AI">
    <Card title="Moonshot AI">
      Kimi K3 — Moonshot AI's flagship reasoning model — and Kimi K2.7 Code for coding and agentic tasks.
    </Card>

    | Model                       | Input (\$/1M) | Output (\$/1M) | Cache (\$/1M) | Docs                                                 |
    | --------------------------- | ------------- | -------------- | ------------- | ---------------------------------------------------- |
    | `perplexity/kimi-k3`        | 3.00          | 15.00          | 0.30          | [Kimi K3](https://huggingface.co/moonshotai/Kimi-K3) |
    | `perplexity/kimi-k2.7-code` | 0.95          | 4.00           | 0.19          | [Kimi K2](https://platform.moonshot.ai/docs)         |

    <Info>
      Kimi K3 accepts `minimal`, `low`, `medium`, `high`, `xhigh`, and `max` reasoning effort. `minimal` uses low effort, while `xhigh` and `max` use maximum effort. Reasoning tokens are billed at the output-token rate.
    </Info>
  </Tab>

  <Tab title="NVIDIA">
    <Card title="NVIDIA">
      Nemotron open-weight reasoning models.
    </Card>

    | Model                                       | Input (\$/1M) | Output (\$/1M) | Cache (\$/1M) | Docs                                                                                                |
    | ------------------------------------------- | ------------- | -------------- | ------------- | --------------------------------------------------------------------------------------------------- |
    | `perplexity/nemotron-3.5-lightning-30b-a3b` | 0.0115        | 0.17           | 0.00115       | [Nemotron 3.5 Lightning](https://huggingface.co/nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-NVFP4) |
    | `perplexity/nemotron-3-ultra-550b-a55b`     | 0.25          | 2.50           | 0.25          | [Nemotron 3 Ultra](https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16)            |
  </Tab>

  <Tab title="Perplexity">
    <Card title="Perplexity">
      Sonar — Perplexity's grounded search model.
    </Card>

    | Model              | Input (\$/1M) | Output (\$/1M) | Cache (\$/1M) | Docs                                                        |
    | ------------------ | ------------- | -------------- | ------------- | ----------------------------------------------------------- |
    | `perplexity/sonar` | 0.25          | 2.50           | 0.0625        | [Sonar](https://docs.perplexity.ai/docs/sonar/models/sonar) |
  </Tab>
</Tabs>

GPT-5.6 Sol supports Fast mode at 2× the listed token prices. Set `service_tier` to `priority`; the response includes the processing tier that served the request.

<Warning>
  Not all third-party models support all features (e.g., reasoning, tools). Check model documentation for specific capabilities.
</Warning>

## Estimate your cost

<PricingCalculator />

## Using a Model

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Explain the difference between supervised and unsupervised learning in machine learning.",
      max_output_tokens=300,
  )

  print(f"Response ID: {response.id}")
  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-sol",
      input: "Explain the difference between supervised and unsupervised learning in machine learning.",
      max_output_tokens: 300,
  });

  console.log(`Response ID: ${response.id}`);
  console.log(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 '{
      "model": "openai/gpt-5.6-sol",
      "input": "Explain the difference between supervised and unsupervised learning in machine learning.",
      "max_output_tokens": 300
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_85783af3-39c4-4565-9f09-144482151abf",
    "created_at": 1779391438,
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "results": [
          {
            "id": 1,
            "snippet": "Supervised learning is a machine learning technique that uses labeled data sets to train artificial intelligence (AI) models to identify the underlying patterns and relationships.\nThe goal of the learning process is to create a model that can predict correct outputs on new real-world data.\n...\nLabeled training data provides a “ground truth,” explicitly teaching the model to identify the relationships between features and data labels.\n...\nSupervised learning relies on ground truth data to teach a model the relationships between inputs and outputs.",
            "title": "What Is Supervised Learning? | IBM",
            "url": "https://www.ibm.com/think/topics/supervised-learning",
            "date": "2025-09-12",
            "last_updated": "2026-03-31",
            "source": "web"
          },
          {
            "id": 2,
            "snippet": "Unsupervised learning, also known as unsupervised machine learning, uses machine learning (ML) algorithms to analyze and cluster unlabeled data sets.\nThese algorithms discover hidden patterns or data groupings without the need for human intervention.\n...\nUnsupervised learning and supervised learning are frequently discussed together.\nUnlike unsupervised learning algorithms, supervised learning algorithms use labeled data.\nFrom that data, it either predicts future outcomes or assigns data to specific categories based on the regression or classification problem that it is trying to solve.\nWhile supervised learning algorithms tend to be more accurate than unsupervised learning models, they require upfront human intervention to label the data appropriately.",
            "title": "What Is Unsupervised Learning? - IBM",
            "url": "https://www.ibm.com/think/topics/unsupervised-learning",
            "date": "2021-09-23",
            "last_updated": "2026-03-31",
            "source": "web"
          },
          {
            "id": 3,
            "snippet": "The difference between supervised and unsupervised **learning lies in how they use data and their goals**.\n**Supervised learning** relies on **labeled datasets, where each input is paired with a corresponding output label**.\nThe goal is to learn the relationship between inputs and outputs so the model can predict outcomes for new data, such as classifying emails as spam or not spam.\nIn contrast, **unsupervised learning** works **with unlabeled data aiming to uncover hidden patterns or structures within the dataset** such as grouping customers based on their shopping habits or detecting anomalies in a dataset.\n> Overall, supervised learning excels in predictive tasks with known outcomes, while unsupervised learning is ideal for discovering relationships and trends in raw data.\n...\nLabeled data means that each example in the dataset comes with a correct answer or output.\nIn supervised learning process:\n- Machine is given a dataset with input features (like age, salary, or temperature) and corresponding labels (like \"yes/no,\" \"high/low,\" or \"rainy/sunny\").\n- Then machine learns dataset by finding patterns in the data.\nFor example, it might learn that if the temperature is high, it’s likely to be sunny.\n- Once trained, the machine can predict the label for new input data.\nFor instance, if you give it a new temperature value, it can predict whether it will be sunny or rainy.",
            "title": "Difference between Supervised and Unsupervised Learning",
            "url": "https://www.geeksforgeeks.org/machine-learning/difference-between-supervised-and-unsupervised-learning/",
            "date": "2025-07-11",
            "last_updated": "2026-05-19",
            "source": "web"
          },
          {
            "id": 4,
            "snippet": "Supervised learning is a type of machine learning where a model learns from labelled data, meaning each input has a correct output.\nThe model compares its predictions with actual results and improves over time to increase accuracy.",
            "title": "Supervised Machine Learning - GeeksforGeeks",
            "url": "https://www.geeksforgeeks.org/machine-learning/supervised-machine-learning/",
            "date": "2026-05-09",
            "last_updated": "2026-05-19",
            "source": "web"
          },
          {
            "id": 5,
            "snippet": "Unsupervised Learning is a type of machine learning where the model works without labelled data.\nIt learns patterns on its own by grouping similar data points or finding hidden structures without any human intervention.",
            "title": "Unsupervised Machine Learning - GeeksforGeeks",
            "url": "https://www.geeksforgeeks.org/machine-learning/unsupervised-learning/",
            "date": "2026-04-30",
            "last_updated": "2026-05-19",
            "source": "web"
          },
          {
            "id": 6,
            "snippet": "The biggest difference between supervised and unsupervised machine learning is the type of data used.\nSupervised learning uses labeled training data, and unsupervised learning does not.\nMore simply, supervised learning models have a baseline understanding of what the correct output values *should* be.\nWith supervised learning, an algorithm uses a sample dataset to train itself to make predictions, iteratively adjusting itself to minimize error.\nThese datasets are labeled for context, providing the desired output values to enable a model to give a “correct” answer.",
            "title": "Supervised vs. unsupervised learning - Google Cloud",
            "url": "https://cloud.google.com/discover/supervised-vs-unsupervised-learning",
            "date": null,
            "last_updated": "2026-05-18",
            "source": "web"
          },
          {
            "id": 7,
            "snippet": "Supervised learning is a category of machine learning that uses labeled datasets to train algorithms to predict outcomes and recognize patterns.\nUnlike unsupervised learning, supervised learning algorithms are given labeled training to learn the relationship between the input and the outputs.\n...\nThe data used in supervised learning is labeled — meaning that it contains examples of both inputs (called features) and correct outputs (labels).\n...\nWhen it comes to understanding the difference between supervised learning vs. unsupervised learning, the primary difference is the type of input data used to train the model.\nSupervised learning uses labeled training datasets to try and teach a model a specific, pre-defined goal.",
            "title": "What is Supervised Learning? | Google Cloud",
            "url": "https://cloud.google.com/discover/what-is-supervised-learning",
            "date": "2025-04-12",
            "last_updated": "2026-05-18",
            "source": "web"
          },
          {
            "id": 8,
            "snippet": "Unsupervised learning in artificial intelligence is a type of machine learning that learns from data without human supervision.\nUnlike supervised learning, unsupervised machine learning models are given unlabeled data and allowed to discover patterns and insights without any explicit guidance or instruction.\n...\nAs the name suggests, unsupervised learning uses self-learning algorithms—they learn without any labels or prior training.\nInstead, the model is given raw, unlabeled data and has to infer its own rules and structure the information based on similarities, differences, and patterns without explicit instructions on how to work with each piece of data.\n...\nThe main difference between supervised learning and unsupervised learning is the type of input data that you use.\nUnlike unsupervised machine learning algorithms, supervised learning relies on labeled training data to determine whether pattern recognition within a dataset is accurate.\nThe goals of supervised learning models are also predetermined, meaning that the type of output of a model is already known before the algorithms are applied.\nIn other words, the input is mapped to the output based on the training data.",
            "title": "What is unsupervised learning? - Google Cloud",
            "url": "https://cloud.google.com/discover/what-is-unsupervised-learning",
            "date": null,
            "last_updated": "2026-05-19",
            "source": "web"
          },
          {
            "id": 9,
            "snippet": "- Supervised vs. unsupervised learning serve different purposes: supervised learning uses labeled data to make precise predictions and classifications, while unsupervised learning finds hidden patterns in raw, unlabeled data, making each better suited for different business goals.\n...\nIn supervised learning, models are trained using labeled data, where each input is paired with a known output.\nThe model learns by comparing its predictions against these correct answers and iteratively reducing error.\nAt the core of this process are machine learning models that learn explicit relationships between features and outcomes.\nThe presence of labeled data provides clear guidance, making supervised learning well-suited for problems where accuracy, traceability and repeatability are essential.\n...\nSupervised learning predicts known outcomes using labeled data.\nUnsupervised learning discovers patterns in unlabeled data.\n...\nSupervised machine learning excels when you have labeled data and need precise, accountable predictions or classifications.",
            "title": "Supervised vs Unsupervised Learning - Databricks",
            "url": "https://www.databricks.com/blog/supervised-vs-unsupervised-learning",
            "date": "2026-02-17",
            "last_updated": "2026-05-20",
            "source": "web"
          },
          {
            "id": 10,
            "snippet": "Supervised learning algorithms train on sample data that specifies both the algorithm's input and output.\nFor example, the data could be images of handwritten numbers that are annotated to indicate which numbers they represent.\n...\nIn supervised learning, you train the model with a set of input data and a corresponding set of paired labeled output data.\nThe labeling is typically done manually.\n...\n|What is it?|You train the model with a set of input data and a corresponding set of paired labeled output data.|You train the model to discover hidden patterns in unlabeled data.|",
            "title": "Supervised vs Unsupervised Learning - Difference Between ... - AWS",
            "url": "https://aws.amazon.com/compare/the-difference-between-machine-learning-supervised-and-unsupervised/",
            "date": "2026-05-13",
            "last_updated": "2026-05-20",
            "source": "web"
          },
          {
            "id": 11,
            "snippet": "In a supervised learning model, the algorithm learns on a labeled dataset, providing an answer key that the algorithm can use to evaluate its accuracy on training data.\n...\nIf you’re learning a task under supervision, someone is present judging whether you’re getting the right answer.\nSimilarly, in supervised learning, that means having a full set of labeled data while training an algorithm.\nFully labeled means that each example in the training dataset is tagged with the answer the algorithm should come up with on its own.",
            "title": "NVIDIA Blog: Supervised Vs. Unsupervised Learning",
            "url": "https://blogs.nvidia.com/blog/supervised-unsupervised-learning/",
            "date": "2018-08-02",
            "last_updated": "2026-04-13",
            "source": "web"
          },
          {
            "id": 12,
            "snippet": "**Supervised Learning** is a machine learning approach where models are trained on labeled data—input examples paired with correct output answers.\nThe algorithm learns to map inputs to outputs by studying these examples, adjusting its parameters to minimize errors between its predictions and the known correct answers.",
            "title": "What is Supervised Learning? - Stanford HAI",
            "url": "https://hai.stanford.edu/ai-definitions/what-is-supervised-learning",
            "date": "2024-09-10",
            "last_updated": "2026-05-06",
            "source": "web"
          },
          {
            "id": 13,
            "snippet": "**Unsupervised learning** is a framework in machine learning where, in contrast to supervised learning, algorithms learn patterns exclusively from unlabeled data.",
            "title": "Unsupervised learning - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/Unsupervised_learning",
            "date": "2003-05-25",
            "last_updated": "2026-03-31",
            "source": "web"
          },
          {
            "id": 14,
            "snippet": "The difference between supervised and unsupervised learning is simple: it's about how much human guidance you give the machine learning algorithm.\n...\nIn supervised learning, humans provide more guidance by showing the algorithm examples with the correct answers.\nYou're essentially teaching it by example.\n**How it works:** You give the algorithm lots of data that includes both the question AND the answer, so it can learn the pattern.\n...\n**Supervised Learning:**\n- **Needs labeled training data** (humans must provide the \"right answers\")\n- **More human work upfront** to create training examples\n- **Predictable results** - you know what you're trying to achieve\n...\n**Use Supervised Learning When:**\n- You know what you want to predict\n- You have examples of correct answers\n- You want specific, measurable results\n- You have time to create labeled training data\n...\nSupervised learning is great when you know what you're trying to achieve and have examples to learn from.\nUnsupervised learning is perfect for exploration and discovery when you want to understand what's hidden in your data.",
            "title": "Supervised vs. Unsupervised Learning: The Basics Explained | TDWI",
            "url": "https://tdwi.org/blogs/ai-101/2025/09/supervised-vs-unsupervised-learning.aspx",
            "date": "2025-09-20",
            "last_updated": "2026-05-21",
            "source": "web"
          }
        ],
        "type": "search_results",
        "queries": [
          "supervised learning definition",
          "unsupervised learning definition",
          "difference between supervised and unsupervised learning"
        ]
      },
      {
        "id": "msg_edef631a-cd00-4ba7-85ab-cea139ca9f13",
        "content": [
          {
            "text": "Supervised learning learns from **labeled** examples to predict known outcomes, while unsupervised learning finds structure in **unlabeled** data without predefined outputs.[web:1][web:2][web:6][web:8]\n\n## Core idea\n\n- Supervised learning uses datasets where each input (features) comes with a correct output label, and the model learns a mapping from inputs to outputs to make predictions on new data.[web:1][web:7][web:12]  \n- Unsupervised learning uses datasets that have inputs only, with no labels, and algorithms try to discover patterns such as clusters, groups, or anomalies in the data.[web:2][web:5][web:8][web:13]\n\n## Data and “answers”\n\n- In supervised learning, training data is “labeled,” meaning each example is paired with the right answer (for example, an email plus a tag “spam” or “not spam”).[web:1][web:4][web:7][web:10][web:12]  \n- In unsupervised learning, the data is “unlabeled”; the model receives raw examples and must organize them or detect structure without being told the correct answer for each case.[web:2][web:5][web:8][web:13]\n\n## Typical goals\n\n- Supervised learning aims at prediction: classification (discrete labels like spam/not spam) and regression (continuous values like house prices), with a clear, predefined target variable.[web:1][web:3][web:9]  \n- Unsupervised learning aims at pattern discovery: clustering similar items, finding hidden groupings, dimensionality reduction, or detecting outliers without a predefined target.[web:2][web:3][web:5][web:8][web:9]\n\n## Examples of each\n\n- Common supervised methods and tasks include logistic regression for spam detection, decision trees for credit approval, and image classifiers trained on labeled pictures of objects.[web:1][web:4][web:7][web:9][web:10]  \n- Common unsupervised methods and tasks include k-means clustering for grouping customers by behavior, anomaly detection in network traffic, and algorithms like PCA for compressing or visualizing high-dimensional data.[web:2][web:3][web:5][web:8][web:9]\n\n## Practical trade‑offs\n\n- Supervised learning typically delivers more accurate, measurable predictions but requires substantial human effort to create labeled datasets and a clear definition of the prediction goal.[web:2][web:6][web:7][web:9][web:14]  \n- Unsupervised learning requires less upfront labeling work and is well suited for exploration and discovering unknown structure, but its results are often harder to evaluate because there is no single “correct” answer.[web:2][web:3][web:8][web:9][web:14]",
            "type": "output_text",
            "annotations": [],
            "logprobs": []
          }
        ],
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "status": "completed",
    "error": null,
    "usage": {
      "input_tokens": 6599,
      "output_tokens": 657,
      "total_tokens": 7256,
      "cost": {
        "currency": "USD",
        "input_cost": 0.00377,
        "output_cost": 0.00657,
        "total_cost": 0.01329,
        "cache_creation_cost": null,
        "cache_read_cost": 0.00045,
        "tool_calls_cost": 0.0025
      },
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 3584,
        "cached_tokens": 3584
      },
      "tool_calls_details": {
        "search_web": {
          "invocation": 1
        }
      },
      "output_tokens_details": {
        "reasoning_tokens": 0
      }
    },
    "background": false,
    "completed_at": 1779391438,
    "frequency_penalty": 0,
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "user": null
  }
  ```
</Accordion>

<Tip>
  **See Your Costs in Real-Time:** Every response includes a `usage` field with exact input tokens, output tokens, and cache read tokens. Calculate your cost instantly using the pricing table above.

  ```json theme={null}
  {
    "usage": {
      "input_tokens": 150,
      "output_tokens": 320,
      "total_tokens": 470
    }
  }
  ```
</Tip>

## Model Fallback

For high-availability applications, you can specify multiple models in a fallback chain. When one model fails or is unavailable, the API automatically tries the next model in the chain.

<Card title="Model Fallback Chain" icon="square-rounded-arrow-down" href="/docs/agent-api/model-fallback">
  Learn how to use model fallback chains to ensure high availability and reliability by automatically trying multiple models when one fails.
</Card>

<Info>
  **Example:**

  ```python theme={null}
  response = client.responses.create(
      models=["openai/gpt-5.6-sol", "anthropic/claude-sonnet-4-6", "google/gemini-3-flash-preview"],
      input="Your question here",
      max_output_tokens=8192,
  )
  ```

  For detailed examples, pricing information, and best practices, see the [Model Fallback documentation](/docs/agent-api/model-fallback).
</Info>

## Next Steps

<CardGroup>
  <Card title="Web Search" icon="screwdriver-wrench" href="/docs/agent-api/tools/web-search">
    Equip your model with web search for source-grounded context.
  </Card>

  <Card title="Prompt Guide" icon="lightbulb" href="/docs/agent-api/prompt-guide">
    Write prompts that get the most out of the Agent API.
  </Card>

  <Card title="Output Control" icon="wand-magic-sparkles" href="/docs/agent-api/output-control">
    Shape responses with structured outputs and JSON schemas.
  </Card>

  <Card title="Finance Search" icon="chart-line" href="/docs/agent-api/tools/finance-search">
    Query market data, filings, and ticker-level information.
  </Card>
</CardGroup>


# OpenAI Compatibility
Source: https://docs.perplexity.ai/docs/agent-api/openai-compatibility

Use your existing OpenAI SDKs with Perplexity's Agent API. Full compatibility with minimal code changes.

## Overview

Perplexity's Agent API is fully compatible with OpenAI's Responses API interface. You can use your existing OpenAI client libraries by simply changing the base URL and providing your Perplexity API key.

<Info>
  **Endpoint Note:** Perplexity's canonical Agent API endpoint is `POST /v1/agent`. For OpenAI SDK compatibility, `POST /v1/responses` is also accepted as an alias — the OpenAI SDK automatically routes `client.responses.create()` to `/v1/responses`, which Perplexity handles seamlessly. No SDK changes are needed beyond setting the base URL.
</Info>

<Tip>
  **We recommend using the [Perplexity SDK](/docs/sdk/overview)** for the best experience with full type safety, enhanced features, and preset support. Use OpenAI SDKs if you're already integrated and need drop-in compatibility.
</Tip>

## Quick Start

Use the OpenAI SDK with Perplexity's Agent API:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    from openai import OpenAI

    client = OpenAI(
        api_key=os.environ.get("PERPLEXITY_API_KEY"),
        base_url="https://api.perplexity.ai/v1"
    )

    response = client.responses.create(
        model="openai/gpt-5.6-sol",
        input="Explain the key differences between REST and GraphQL APIs"
    )

    print(response.output_text)
    ```
  </Tab>

  <Tab title="Typescript">
    ```typescript theme={null}
    import OpenAI from 'openai';

    const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai/v1"
    });

    const response = await client.responses.create({
      model: "openai/gpt-5-mini",
      input: "Explain the key differences between REST and GraphQL APIs"
    });

    console.log(response.output_text);
    ```
  </Tab>
</Tabs>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_7edd7725-4ae1-49ad-9e96-22c93679363e",
    "created_at": 1779391454,
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "results": [
          {
            "id": 1,
            "snippet": "- REST follows a resource-based architecture and typically uses multiple endpoints for different resources.\n- GraphQL provides a single endpoint where clients can request exactly the data they need.\n- GraphQL helps reduce over-fetching and under-fetching, which can occur in traditional REST APIs.\n...\nHere are some key differences between GraphQL and REST APIs based on how they handle endpoints, data fetching, and real-time communication.\n|GraphQL|REST API|\n|--|--|\n|GraphQL uses single endpoint for every operation.|REST API uses multiple endpoints for different operations|\n|In GraphQL client defines what data is required.|REST API fetches data using pre-defined rules.|\n|GraphQL reduces over-fetching and under-fetching.|Over-fetching and under-fetching are the common issues with Rest API.|\n|GraphQL supports real-time updates with subscriptions|REST API relies on polling for real-time data|\n|GraphQL is a growing technology with various tools and libraries.|REST APIs are well established ecosystem with multiple libraries and tools.|",
            "title": "GraphQL vs REST - GeeksforGeeks",
            "url": "https://www.geeksforgeeks.org/graphql/graphql-vs-rest-which-is-better-for-apis/",
            "date": "2026-03-11",
            "last_updated": "2026-05-18",
            "source": "web"
          },
          {
            "id": 2,
            "snippet": "GraphQL queries access not just the properties of one resource but also smoothly follow references between them.\nWhile typical REST APIs require loading from multiple URLs, GraphQL APIs get all the data your app needs in a single request.",
            "title": "GraphQL | The query language for modern APIs",
            "url": "https://graphql.org",
            "date": null,
            "last_updated": "2026-05-06",
            "source": "web"
          },
          {
            "id": 3,
            "snippet": "{ts:15} rest let's talk about the fundamental differences between graphql and rest rest stands for representational State\n{ts:22} transfer and it typically has unique URLs it follows the standard HTTP methods of get post put and delete it\n{ts:31} has uses status code standardization so you have the 200 okay the 404 not found Etc and data is typically returned in\n{ts:39} Json or XML format graphql stands for graph query language and it has a single endpoint for all operations you have the\n{ts:48} three primary operations of query mutation and subscription the client specifies exactly what data it needs and\n{ts:56} the API documents itself through introspection with graphql clients have precise control over the data that it\n{ts:63} requires so there's no such thing as over fetching or under fetching and these performance implications are",
            "title": "GraphQL vs REST: What's the Difference and When Should You ...",
            "url": "https://www.youtube.com/watch?v=2wz19HOyu1w",
            "date": "2025-04-01",
            "last_updated": "2026-04-14",
            "source": "web"
          },
          {
            "id": 4,
            "snippet": "- GraphQL is built around the concept of \"getting exactly what you asked for\"without any data under or overfetching.\n- GraphQL makes it easier to aggregate data from multiple sources.\nIt uses a type system rather than multiple endpoints to describe data.\n...\nWhile typical REST APIs require loading from multiple URLs, GraphQL APIs get all the data in a single request - making apps quick even on slow mobile network connections.\n...\nConversely, if you wanted to gather some information from a specific endpoint, you couldn’t limit the fields that the REST API returns; you’ll always get a complete data set - or overfetching.\n...\nHowever, the most commonly stated benefit is that GraphQL solves both over-fetching and under-fetching issues by allowing the client to request only the data that is required.\nSince there is more efficiency associated with working with GraphQL, development is much faster with GraphQL than it would be with REST.\n...\nGraphQL queries themselves are not faster than REST queries, but since you have full control over what you want to query and what the payload should be, GraphQL requests will always be smaller and more efficient.",
            "title": "What Is GraphQL and How It Works - Hygraph",
            "url": "https://hygraph.com/learn/graphql",
            "date": "2025-10-27",
            "last_updated": "2026-05-13",
            "source": "web"
          },
          {
            "id": 5,
            "snippet": "Unlike REST, which typically uses multiple endpoints to fetch data and perform network operations, GraphQL exposes data models by using a single endpoint through which clients send GraphQL requests, regardless of what they’re asking for.\nThe API then accesses resource properties—and follows the references between resources—to get the client all the data they need from a single query to the GraphQL server.\n...\nGraphQL offers an efficient, more flexible addition to REST; GraphQL APIs are often viewed as an upgrade from RESTful environments, especially given their ability to facilitate collaboration between front-end and back-end teams.\n...\nBecause REST relies on multiple endpoints and stateless interactions—where every API request is processed as a new query, independent of any others—clients receive every piece of data that is associated with a resource.\nIf a client needs only a subset of the data, it still receives all the data (over-fetching).\nAnd if the client needs data that spans multiple resources, a RESTful system often makes the client query each resource separately to compensate for inadequate data retrieval from the initial request (under-fetching).\nGraphQL APIs use a single GraphQL endpoint to give clients a precise, comprehensive data response in a one round trip from a single request, eliminating over- and under-fetching issues.\n...\nGraphQL reduces the need for versioning because clients can specify their data requirements in the query.\nThe addition of new fields to the server does not affect clients without a need for those fields.\n...\nREST doesn’t have built-in support for real-time updates.\nIf an app needs real-time functionality, developers usually must implement techniques like long-polling (where the client repeatedly polls the server for new data) and server-sent events, which can add complexity to the application.\nHowever, GraphQL includes built-in support for real-time updates through subscriptions.",
            "title": "GraphQL vs REST: What's the Difference? - IBM",
            "url": "https://www.ibm.com/think/topics/graphql-vs-rest-api",
            "date": "2024-03-29",
            "last_updated": "2026-01-17",
            "source": "web"
          },
          {
            "id": 6,
            "snippet": "As stated in REST API vs GraphQL, “the key difference between GraphQL and REST APIs is that GraphQL is a query language, while REST is an architectural concept for network-based software.”",
            "title": "The Role and Impact of GraphQL - F5 Networks",
            "url": "https://www.f5.com/resources/reports/the-role-and-impact-of-graphql-octo-report",
            "date": null,
            "last_updated": "2026-05-21",
            "source": "web"
          },
          {
            "id": 7,
            "snippet": "The key differences lie in data fetching, schema definition, versioning, and error handling.\nGraphQL uses a single endpoint and allows clients to specify their data requirements, while REST relies on multiple endpoints with fixed data structures.",
            "title": "GraphQL vs REST: Key Similarities and Differences Explained",
            "url": "https://konghq.com/blog/learning-center/graphql-vs-rest",
            "date": "2025-02-28",
            "last_updated": "2026-05-19",
            "source": "web"
          },
          {
            "id": 8,
            "snippet": "Instead of exposing multiple endpoints that return fixed response structures, a GraphQL API typically exposes a **single endpoint**.\nClients send queries that specify exactly what data they need.\n...\nWhile REST and GraphQL ultimately solve the same problem—exposing data through an API—their design philosophies differ in several important ways.\n|Aspect|REST|GraphQL|\n|--|--|--|\n|API structure|Multiple endpoints representing resources|Typically a single endpoint|\n|Data retrieval|Server defines response structure|Client specifies required fields|\n|Network requests|Often multiple requests for related data|Complex data fetched in a single query|\n|Versioning|Often uses versioned endpoints|Uses schema evolution and field deprecation|\n|Caching|Strong support via HTTP caching|Typically handled at the client level|",
            "title": "REST vs GraphQL: Key Differences, Performance, and When to Use ...",
            "url": "https://dev.to/riteshkokam/rest-vs-graphql-key-differences-performance-and-when-to-use-each-51n7",
            "date": "2026-03-09",
            "last_updated": "2026-05-21",
            "source": "web"
          },
          {
            "id": 9,
            "snippet": "Unlike REST, GraphQL allows for requesting specific data that a client needs, departing from the fixed data structure approach.\n...\nIn a nutshell, mainly the progress GraphQL has made is querying in one request, while retrieving only the necessary data instead of the complete set.\nThe main reason for GraphQL being so attractive to developers is its client-driven approach.\n...\nHowever, notable differences start with the conceptual models: While REST is made up of files, GraphQL is constructed of graphs.",
            "title": "GraphQL: Core Features, Architecture, Pros and Cons - AltexSoft",
            "url": "https://www.altexsoft.com/blog/graphql-core-features-architecture-pros-and-cons/",
            "date": "2019-03-23",
            "last_updated": "2026-03-31",
            "source": "web"
          }
        ],
        "type": "search_results",
        "queries": [
          "REST vs GraphQL key differences",
          "REST API characteristics",
          "GraphQL API characteristics"
        ]
      },
      {
        "id": "msg_d44758f0-ae0f-4d8a-8ded-ceb68d67ab49",
        "content": [
          {
            "text": "REST and GraphQL are both ways to build APIs, but REST is an architectural style built around multiple resource URLs and HTTP semantics, while GraphQL is a query language over a single endpoint where the client specifies exactly which data it needs.[web:5][web:6] GraphQL typically reduces over‑fetching and under‑fetching compared to REST by letting clients shape responses, at the cost of more complexity in schema design and caching.[web:1][web:8]\n\n## Core conceptual difference\n\n- REST is an **architectural** pattern that exposes resources via multiple endpoints, using HTTP verbs (GET, POST, PUT, DELETE, etc.) and status codes to model operations.[web:1][web:5]  \n- GraphQL is a **query** language and runtime that sits behind usually one endpoint and lets clients send structured queries, mutations, and subscriptions against a typed schema.[web:2][web:4][web:6]\n\n## Endpoints and data fetching\n\n- REST typically has many endpoints (e.g., `/users`, `/users/1/posts`) and each endpoint returns a fixed data shape defined by the server.[web:1][web:7]  \n- GraphQL usually has a single endpoint (e.g., `/graphql`), and the client declares exactly which fields and related objects it wants in a single request, often avoiding multiple round trips.[web:2][web:4][web:5]\n\n## Over‑fetching, under‑fetching, and performance\n\n- With REST, clients often receive more data than needed (over‑fetching) or must call several endpoints to collect enough data (under‑fetching), especially for nested relationships.[web:1][web:5][web:9]  \n- GraphQL queries return only requested fields, which reduces payload sizes and the number of requests, though raw query speed is not inherently faster; efficiency comes from tailoring the payload.[web:4][web:8]\n\n## Typing, versioning, and evolution\n\n- REST responses are often JSON without a strict, machine‑enforced schema, and breaking changes are commonly managed with versioned URLs like `/api/v1` and `/api/v2`.[web:5][web:8]  \n- GraphQL uses a strongly typed schema with introspection, enabling tools, self‑documentation, and schema evolution via adding fields and deprecating old ones instead of creating new API versions.[web:2][web:4][web:5][web:8]\n\n## Caching and real‑time features\n\n- REST works naturally with HTTP caching (ETags, Cache‑Control) because resources are tied to URLs and standard methods, making it straightforward for browsers and proxies to cache responses.[web:5][web:8]  \n- GraphQL usually needs custom or client‑side caching strategies (e.g., normalized caches) due to a single endpoint, but it offers built‑in support for real‑time updates via subscriptions, whereas REST relies on techniques like polling or server‑sent events.[web:1][web:4][web:5]",
            "type": "output_text",
            "annotations": [],
            "logprobs": []
          }
        ],
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "status": "completed",
    "error": null,
    "usage": {
      "input_tokens": 5870,
      "output_tokens": 679,
      "total_tokens": 6549,
      "cost": {
        "currency": "USD",
        "input_cost": 0.00286,
        "output_cost": 0.00679,
        "total_cost": 0.0126,
        "cache_creation_cost": null,
        "cache_read_cost": 0.00045,
        "tool_calls_cost": 0.0025
      },
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 3584,
        "cached_tokens": 3584
      },
      "tool_calls_details": {
        "search_web": {
          "invocation": 1
        }
      },
      "output_tokens_details": {
        "reasoning_tokens": 0
      }
    },
    "background": false,
    "completed_at": 1779391454,
    "frequency_penalty": 0,
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "user": null
  }
  ```
</Accordion>

## Configuration

### Setting Up the OpenAI SDK

Configure OpenAI SDKs to work with Perplexity by setting the `base_url` to `https://api.perplexity.ai/v1`:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    from openai import OpenAI

    client = OpenAI(
        api_key=os.environ.get("PERPLEXITY_API_KEY"),
        base_url="https://api.perplexity.ai/v1"
    )
    ```
  </Tab>

  <Tab title="Typescript">
    ```typescript theme={null}
    import OpenAI from 'openai';

    const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai/v1"
    });
    ```
  </Tab>
</Tabs>

<Info>
  **Important**: Use `base_url="https://api.perplexity.ai/v1"` (with `/v1`) for the Agent API.
</Info>

## Agent API

Perplexity's Agent API follows OpenAI's Responses API request/response format. The OpenAI SDK's `client.responses.create()` method works out of the box — the SDK sends requests to `/v1/responses`, which Perplexity accepts alongside the canonical `/v1/agent` endpoint.

### Basic Usage

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    from openai import OpenAI

    client = OpenAI(
        api_key=os.environ.get("PERPLEXITY_API_KEY"),
        base_url="https://api.perplexity.ai/v1"
    )

    response = client.responses.create(
        model="openai/gpt-5.6-sol",
        input="Explain the key differences between REST and GraphQL APIs"
    )

    print(response.output_text)
    print(f"Response ID: {response.id}")
    ```
  </Tab>

  <Tab title="Typescript">
    ```typescript theme={null}
    import OpenAI from 'openai';

    const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai/v1"
    });

    const response = await client.responses.create({
      model: "openai/gpt-5-mini",
      input: "Explain the key differences between REST and GraphQL APIs"
    });

    console.log(response.output_text);
    console.log(`Response ID: ${response.id}`);
    ```
  </Tab>
</Tabs>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_7edd7725-4ae1-49ad-9e96-22c93679363e",
    "created_at": 1779391454,
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "results": [
          {
            "id": 1,
            "snippet": "- REST follows a resource-based architecture and typically uses multiple endpoints for different resources.\n- GraphQL provides a single endpoint where clients can request exactly the data they need.\n- GraphQL helps reduce over-fetching and under-fetching, which can occur in traditional REST APIs.\n...\nHere are some key differences between GraphQL and REST APIs based on how they handle endpoints, data fetching, and real-time communication.\n|GraphQL|REST API|\n|--|--|\n|GraphQL uses single endpoint for every operation.|REST API uses multiple endpoints for different operations|\n|In GraphQL client defines what data is required.|REST API fetches data using pre-defined rules.|\n|GraphQL reduces over-fetching and under-fetching.|Over-fetching and under-fetching are the common issues with Rest API.|\n|GraphQL supports real-time updates with subscriptions|REST API relies on polling for real-time data|\n|GraphQL is a growing technology with various tools and libraries.|REST APIs are well established ecosystem with multiple libraries and tools.|",
            "title": "GraphQL vs REST - GeeksforGeeks",
            "url": "https://www.geeksforgeeks.org/graphql/graphql-vs-rest-which-is-better-for-apis/",
            "date": "2026-03-11",
            "last_updated": "2026-05-18",
            "source": "web"
          },
          {
            "id": 2,
            "snippet": "GraphQL queries access not just the properties of one resource but also smoothly follow references between them.\nWhile typical REST APIs require loading from multiple URLs, GraphQL APIs get all the data your app needs in a single request.",
            "title": "GraphQL | The query language for modern APIs",
            "url": "https://graphql.org",
            "date": null,
            "last_updated": "2026-05-06",
            "source": "web"
          },
          {
            "id": 3,
            "snippet": "{ts:15} rest let's talk about the fundamental differences between graphql and rest rest stands for representational State\n{ts:22} transfer and it typically has unique URLs it follows the standard HTTP methods of get post put and delete it\n{ts:31} has uses status code standardization so you have the 200 okay the 404 not found Etc and data is typically returned in\n{ts:39} Json or XML format graphql stands for graph query language and it has a single endpoint for all operations you have the\n{ts:48} three primary operations of query mutation and subscription the client specifies exactly what data it needs and\n{ts:56} the API documents itself through introspection with graphql clients have precise control over the data that it\n{ts:63} requires so there's no such thing as over fetching or under fetching and these performance implications are",
            "title": "GraphQL vs REST: What's the Difference and When Should You ...",
            "url": "https://www.youtube.com/watch?v=2wz19HOyu1w",
            "date": "2025-04-01",
            "last_updated": "2026-04-14",
            "source": "web"
          },
          {
            "id": 4,
            "snippet": "- GraphQL is built around the concept of \"getting exactly what you asked for\"without any data under or overfetching.\n- GraphQL makes it easier to aggregate data from multiple sources.\nIt uses a type system rather than multiple endpoints to describe data.\n...\nWhile typical REST APIs require loading from multiple URLs, GraphQL APIs get all the data in a single request - making apps quick even on slow mobile network connections.\n...\nConversely, if you wanted to gather some information from a specific endpoint, you couldn’t limit the fields that the REST API returns; you’ll always get a complete data set - or overfetching.\n...\nHowever, the most commonly stated benefit is that GraphQL solves both over-fetching and under-fetching issues by allowing the client to request only the data that is required.\nSince there is more efficiency associated with working with GraphQL, development is much faster with GraphQL than it would be with REST.\n...\nGraphQL queries themselves are not faster than REST queries, but since you have full control over what you want to query and what the payload should be, GraphQL requests will always be smaller and more efficient.",
            "title": "What Is GraphQL and How It Works - Hygraph",
            "url": "https://hygraph.com/learn/graphql",
            "date": "2025-10-27",
            "last_updated": "2026-05-13",
            "source": "web"
          },
          {
            "id": 5,
            "snippet": "Unlike REST, which typically uses multiple endpoints to fetch data and perform network operations, GraphQL exposes data models by using a single endpoint through which clients send GraphQL requests, regardless of what they’re asking for.\nThe API then accesses resource properties—and follows the references between resources—to get the client all the data they need from a single query to the GraphQL server.\n...\nGraphQL offers an efficient, more flexible addition to REST; GraphQL APIs are often viewed as an upgrade from RESTful environments, especially given their ability to facilitate collaboration between front-end and back-end teams.\n...\nBecause REST relies on multiple endpoints and stateless interactions—where every API request is processed as a new query, independent of any others—clients receive every piece of data that is associated with a resource.\nIf a client needs only a subset of the data, it still receives all the data (over-fetching).\nAnd if the client needs data that spans multiple resources, a RESTful system often makes the client query each resource separately to compensate for inadequate data retrieval from the initial request (under-fetching).\nGraphQL APIs use a single GraphQL endpoint to give clients a precise, comprehensive data response in a one round trip from a single request, eliminating over- and under-fetching issues.\n...\nGraphQL reduces the need for versioning because clients can specify their data requirements in the query.\nThe addition of new fields to the server does not affect clients without a need for those fields.\n...\nREST doesn’t have built-in support for real-time updates.\nIf an app needs real-time functionality, developers usually must implement techniques like long-polling (where the client repeatedly polls the server for new data) and server-sent events, which can add complexity to the application.\nHowever, GraphQL includes built-in support for real-time updates through subscriptions.",
            "title": "GraphQL vs REST: What's the Difference? - IBM",
            "url": "https://www.ibm.com/think/topics/graphql-vs-rest-api",
            "date": "2024-03-29",
            "last_updated": "2026-01-17",
            "source": "web"
          },
          {
            "id": 6,
            "snippet": "As stated in REST API vs GraphQL, “the key difference between GraphQL and REST APIs is that GraphQL is a query language, while REST is an architectural concept for network-based software.”",
            "title": "The Role and Impact of GraphQL - F5 Networks",
            "url": "https://www.f5.com/resources/reports/the-role-and-impact-of-graphql-octo-report",
            "date": null,
            "last_updated": "2026-05-21",
            "source": "web"
          },
          {
            "id": 7,
            "snippet": "The key differences lie in data fetching, schema definition, versioning, and error handling.\nGraphQL uses a single endpoint and allows clients to specify their data requirements, while REST relies on multiple endpoints with fixed data structures.",
            "title": "GraphQL vs REST: Key Similarities and Differences Explained",
            "url": "https://konghq.com/blog/learning-center/graphql-vs-rest",
            "date": "2025-02-28",
            "last_updated": "2026-05-19",
            "source": "web"
          },
          {
            "id": 8,
            "snippet": "Instead of exposing multiple endpoints that return fixed response structures, a GraphQL API typically exposes a **single endpoint**.\nClients send queries that specify exactly what data they need.\n...\nWhile REST and GraphQL ultimately solve the same problem—exposing data through an API—their design philosophies differ in several important ways.\n|Aspect|REST|GraphQL|\n|--|--|--|\n|API structure|Multiple endpoints representing resources|Typically a single endpoint|\n|Data retrieval|Server defines response structure|Client specifies required fields|\n|Network requests|Often multiple requests for related data|Complex data fetched in a single query|\n|Versioning|Often uses versioned endpoints|Uses schema evolution and field deprecation|\n|Caching|Strong support via HTTP caching|Typically handled at the client level|",
            "title": "REST vs GraphQL: Key Differences, Performance, and When to Use ...",
            "url": "https://dev.to/riteshkokam/rest-vs-graphql-key-differences-performance-and-when-to-use-each-51n7",
            "date": "2026-03-09",
            "last_updated": "2026-05-21",
            "source": "web"
          },
          {
            "id": 9,
            "snippet": "Unlike REST, GraphQL allows for requesting specific data that a client needs, departing from the fixed data structure approach.\n...\nIn a nutshell, mainly the progress GraphQL has made is querying in one request, while retrieving only the necessary data instead of the complete set.\nThe main reason for GraphQL being so attractive to developers is its client-driven approach.\n...\nHowever, notable differences start with the conceptual models: While REST is made up of files, GraphQL is constructed of graphs.",
            "title": "GraphQL: Core Features, Architecture, Pros and Cons - AltexSoft",
            "url": "https://www.altexsoft.com/blog/graphql-core-features-architecture-pros-and-cons/",
            "date": "2019-03-23",
            "last_updated": "2026-03-31",
            "source": "web"
          }
        ],
        "type": "search_results",
        "queries": [
          "REST vs GraphQL key differences",
          "REST API characteristics",
          "GraphQL API characteristics"
        ]
      },
      {
        "id": "msg_d44758f0-ae0f-4d8a-8ded-ceb68d67ab49",
        "content": [
          {
            "text": "REST and GraphQL are both ways to build APIs, but REST is an architectural style built around multiple resource URLs and HTTP semantics, while GraphQL is a query language over a single endpoint where the client specifies exactly which data it needs.[web:5][web:6] GraphQL typically reduces over‑fetching and under‑fetching compared to REST by letting clients shape responses, at the cost of more complexity in schema design and caching.[web:1][web:8]\n\n## Core conceptual difference\n\n- REST is an **architectural** pattern that exposes resources via multiple endpoints, using HTTP verbs (GET, POST, PUT, DELETE, etc.) and status codes to model operations.[web:1][web:5]  \n- GraphQL is a **query** language and runtime that sits behind usually one endpoint and lets clients send structured queries, mutations, and subscriptions against a typed schema.[web:2][web:4][web:6]\n\n## Endpoints and data fetching\n\n- REST typically has many endpoints (e.g., `/users`, `/users/1/posts`) and each endpoint returns a fixed data shape defined by the server.[web:1][web:7]  \n- GraphQL usually has a single endpoint (e.g., `/graphql`), and the client declares exactly which fields and related objects it wants in a single request, often avoiding multiple round trips.[web:2][web:4][web:5]\n\n## Over‑fetching, under‑fetching, and performance\n\n- With REST, clients often receive more data than needed (over‑fetching) or must call several endpoints to collect enough data (under‑fetching), especially for nested relationships.[web:1][web:5][web:9]  \n- GraphQL queries return only requested fields, which reduces payload sizes and the number of requests, though raw query speed is not inherently faster; efficiency comes from tailoring the payload.[web:4][web:8]\n\n## Typing, versioning, and evolution\n\n- REST responses are often JSON without a strict, machine‑enforced schema, and breaking changes are commonly managed with versioned URLs like `/api/v1` and `/api/v2`.[web:5][web:8]  \n- GraphQL uses a strongly typed schema with introspection, enabling tools, self‑documentation, and schema evolution via adding fields and deprecating old ones instead of creating new API versions.[web:2][web:4][web:5][web:8]\n\n## Caching and real‑time features\n\n- REST works naturally with HTTP caching (ETags, Cache‑Control) because resources are tied to URLs and standard methods, making it straightforward for browsers and proxies to cache responses.[web:5][web:8]  \n- GraphQL usually needs custom or client‑side caching strategies (e.g., normalized caches) due to a single endpoint, but it offers built‑in support for real‑time updates via subscriptions, whereas REST relies on techniques like polling or server‑sent events.[web:1][web:4][web:5]",
            "type": "output_text",
            "annotations": [],
            "logprobs": []
          }
        ],
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "status": "completed",
    "error": null,
    "usage": {
      "input_tokens": 5870,
      "output_tokens": 679,
      "total_tokens": 6549,
      "cost": {
        "currency": "USD",
        "input_cost": 0.00286,
        "output_cost": 0.00679,
        "total_cost": 0.0126,
        "cache_creation_cost": null,
        "cache_read_cost": 0.00045,
        "tool_calls_cost": 0.0025
      },
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 3584,
        "cached_tokens": 3584
      },
      "tool_calls_details": {
        "search_web": {
          "invocation": 1
        }
      },
      "output_tokens_details": {
        "reasoning_tokens": 0
      }
    },
    "background": false,
    "completed_at": 1779391454,
    "frequency_penalty": 0,
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "user": null
  }
  ```
</Accordion>

### Using Presets

Presets are pre-configured setups optimized for specific use cases. Use `extra_body` to pass presets via the OpenAI SDK:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    from openai import OpenAI

    client = OpenAI(
        api_key=os.environ.get("PERPLEXITY_API_KEY"),
        base_url="https://api.perplexity.ai/v1"
    )

    # Pass preset via extra_body
    response = client.responses.create(
        input="Compare the design philosophy of Apple's A-series and Qualcomm's Snapdragon mobile SoCs at a high level: CPU and GPU choices and overall system integration.",
        extra_body={
            "preset": "low"
        }
    )

    print(response.output_text)
    ```
  </Tab>

  <Tab title="Typescript">
    ```typescript theme={null}
    import OpenAI from 'openai';

    const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai/v1"
    });

    // Use type casting (as any) to pass preset directly
    const response = await (client.responses.create as any)({
      input: "Compare the design philosophy of Apple's A-series and Qualcomm's Snapdragon mobile SoCs at a high level: CPU and GPU choices and overall system integration.",
      preset: "low"
    });

    console.log(response.output_text);
    ```
  </Tab>
</Tabs>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_18215035-0ac4-4b27-915c-62399ff87fc0",
    "created_at": 1779391825,
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "results": [
          {
            "id": 1,
            "snippet": "The *A* series is a family of SoCs used in the iPhone, certain iPad models (including iPad Mini and entry-level iPad), MacBook Neo, and the Apple TV.\n*A*-series chips were also used in the discontinued iPod Touch line and the original HomePod.\nThey integrate one or more ARM-based processing cores (CPU), a graphics processing unit (GPU), cache memory and other electronics necessary to provide mobile computing functions within a single physical package.\n...\nIt combines an ARM Cortex-A8 CPU – also used in Samsung's S5PC110A01 SoC – and a PowerVR SGX 535 graphics processor (GPU), all built on Samsung's 45-nanometer silicon chip fabrication process.\nThe design emphasizes power efficiency.",
            "title": "Apple silicon - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/Apple_silicon",
            "date": "2011-07-06",
            "last_updated": "2026-05-18",
            "source": "web"
          },
          {
            "id": 2,
            "snippet": "{ts:230} Apple's range then we'll go back again to ccom so we're looking now at the M3 family it's a series of arm-based system\n{ts:237} on a chips designed by Apple the M3 process include a central processing unit and a graphics processing GPU and\n{ts:243} they are used in Apple's iMac desktops and its uh MacBook range of laptops and there are a few iPads as well which got\n…\n...\n{ts:467} Core Design needs to be certified and must be 100% compatible with the arm instruction set architecture now apple\n...\n{ts:635} years and now we have this new competitor which is kcomm now the other thing to remember about the M3 and the\n{ts:640} Snapdragon X Elite is that they are systems on a chip they are not just a CPU so maybe if you buy an x86 uh\n{ts:648} processor of some kind you're getting basically just a a CPU but now these things have a GPU for example and the M\n{ts:657} series uses Apple's uh own design GPU with its Heritage coming from imagination Technologies and this latest\n{ts:665} installation includes mesh shaders and Hardware accelerated uh ra tracing again see my previous V videos about those\n{ts:672} things and the Snapdragon X Elite uses corcom adreno GPU which supports direct X12 so here we can see that these gpus\n…\n{ts:703} course both have npus and this of course is something that's becoming very important the ability to be able to run\n{ts:711} uh these uh neural processing units generative AI uh and other kind of stuff on the so so these chips are more than\n{ts:718} just a CPU you've got GPU you've got uh edit encoders and decoders you've got npus all built into the same chip and\n…",
            "title": "Apple M3 vs Snapdragon X Elite - History, Features, and Software",
            "url": "https://www.youtube.com/watch?v=V8Rbjwz0dVU",
            "date": "2023-11-03",
            "last_updated": "2026-05-16",
            "source": "web"
          },
          {
            "id": 3,
            "snippet": "Leveraging a unified memory architecture for CPU and GPU tasks, Mac apps will see amazing performance benefits from Apple silicon tuned frameworks such as Metal and Accelerate.\n...\nNow, the new Apple Silicon Macs combine all these components into a single system on a chip, or SoC.\nBuilding everything into one chip gives the system a unified memory architecture.\nThis means that the GPU and CPU are working over the same memory.\nGraphics resources, such as textures, images and geometry data, can be shared between the CPU and GPU efficiently, with no overhead, as there's no need to copy data across a PCIe bus.",
            "title": "Explore the new system architecture of Apple silicon Macs - WWDC20",
            "url": "https://developer.apple.com/videos/play/wwdc2020/10686/",
            "date": "2020-06-24",
            "last_updated": "2026-05-14",
            "source": "web"
          },
          {
            "id": 4,
            "snippet": "Apple designs its chips specifically for iOS, which allows tight hardware and software integration.\n...\nWe also discuss how Apple Bionic processors focus on high single-core performance, efficient power management, and unified memory architecture, while Snapdragon chips focus heavily on GPU performance through Adreno graphics, higher refresh rate support, and features built for gaming phones.\n...\n{ts:330} Apple के पास ये है कि वो अपने कस्टम सीपीू आर्किटेक्चर बनाता है। ये एआरएम के कोर्स को डायरेक्टली यूज नहीं करते हैं।",
            "title": "Apple Bionic vs Snapdragon – Which Chip Is Actually Better for ...",
            "url": "https://www.youtube.com/watch?v=jiDCtvI_MC4",
            "date": "2026-03-06",
            "last_updated": "2026-05-21",
            "source": "web"
          },
          {
            "id": 5,
            "snippet": "Key Concepts\n- RISC Architecture: Utilizes a simplified instruction set for efficient processing.\n- Pipeline Organization: Enables simultaneous instruction execution for enhanced throughput.\n- Cache Hierarchy: Reduces memory access latency, improving application performance.\n- Multicore Architecture: Integrates various processing units for optimized workload management.\n- Power Optimization: Implements strategies like dynamic voltage scaling to enhance energy efficiency.\n- System on Chip (SoC): Combines CPU, GPU, and other components for seamless data exchange.\n...\nThese processors power iPhones\nand iPads and are built as a System-on-Chip (SoC), integrating the CPU, GPU, Neural Engine, and\nhardware accelerators on a single die.\n...\nApple A-Series processors are based on the ARM (Advanced RISC Machine) architecture, which\nfollows the Reduced Instruction Set Computing (RISC) philosophy.\nRISC uses a small, highly optimized\nset of simple instructions that can each execute in a single clock cycle.\n...\n##### Apple A-Series processors use a deep out-of-order superscalar pipeline.\nThis means the processor can\n...\n##### The Apple A-Series is a complete System-on-Chip.\nAll major processing blocks — CPU, GPU, Neural\n##### Engine, ISP, and media codecs — share a unified memory fabric and the System Level Cache,\n##### enabling low-latency, high-bandwidth data exchange without costly off-chip transfers.",
            "title": "CASE STUDY 3: Apple A-Series Mobile Processor Architecture",
            "url": "https://www.studocu.com/in/document/navjeevan-education-societys-polytechnic-bhandup/computer-graphics/case-study-3-apple-a-series-mobile-processor-architecture/157859088",
            "date": "2026-04-02",
            "last_updated": "2026-04-12",
            "source": "web"
          },
          {
            "id": 6,
            "snippet": "\n6-core GPU (graphics \nprocessor unit)  \n\n2 dual-core CPU \n(central processing\n...\nA13 consists of: \n\nEight-core Neural \nEngine  with\nMachine Learning \n\nFour-core GPU \n(20% faster > A12) \n\nSix-core CPU (20% \nfaster and 35% save \nenergy > A12) \n",
            "title": "Recent Advances and Outlook for Heterogeneous Integration",
            "url": "https://ewh.ieee.org/soc/cpmt/presentations/eps2002a.pdf",
            "date": null,
            "last_updated": "2025-10-23",
            "source": "web"
          },
          {
            "id": 7,
            "snippet": "In contrast, Apple designs its chips—like the A17 Pro and upcoming A18—for vertical integration within iOS.\nThis means the CPU, GPU, memory controller, and Neural Engine are all developed in-house and tightly coupled with the operating system.\nApple’s six-core CPU (two performance, four efficiency) and five-core GPU are built using TSMC’s most advanced node at the time of release, often giving them a process advantage over competing SoCs.\n...\nApple’s unified memory architecture reduces latency between CPU, GPU, and RAM, lowering energy consumption per operation.\n...\nApple’s A17 Pro and future chips generally offer superior sustained performance, better thermal management, and tighter software integration, resulting in smoother gameplay over time.",
            "title": "Snapdragon Vs Apple Chip Which Powers Smoother ...",
            "url": "https://www.alibaba.com/product-insights/snapdragon-vs-apple-chip-which-powers-smoother-mobile-gaming-performance.html",
            "date": "2026-01-08",
            "last_updated": "2026-01-16",
            "source": "web"
          },
          {
            "id": 8,
            "snippet": "A series SoCsThe A series is a family of SoCs used in the iPhone, certain iPad models (including iPad Mini and entry-level iPad), and the Apple TV.\nA-series chips were alsoused in the discontinued iPod Touch line and the original HomePod.\nThey integrate one or more ARM-based processing cores (CPU), a graphics processingunit (GPU), cache memory and other electronics necessary to provide mobile computing functions within a single physical package.[4]",
            "title": "Apple Silicon - Wikipedia | PDF | I Pad",
            "url": "https://www.scribd.com/document/909655498/Apple-Silicon-Wikipedia",
            "date": "2025-09-29",
            "last_updated": "2026-01-19",
            "source": "web"
          },
          {
            "id": 9,
            "snippet": "Snapdragon processors integrate multiple components like the CPU, GPU, NPU, and modem on a single chip.\nThis integration and specific software integrations improves processing efficiency, improves power management, reduces package size and, overall, improves overall performance of the device.\n...\nSnapdragon processors integrate multiple components like the CPU, GPU, NPU, and modem on a single chip.\nThis integration is called heterogenous computing and it improves processing efficiency, improves power management, reduces package size and, overall, improves overall performance of the device.",
            "title": "What is Snapdragon FAQ | Qualcomm",
            "url": "https://www.qualcomm.com/snapdragon/what-is-snapdragon",
            "date": "2024-06-27",
            "last_updated": "2026-05-21",
            "source": "web"
          },
          {
            "id": 10,
            "snippet": "The Apple A15 Bionic is a System on a Chip (SoC) from Apple that is found in the iPhone 13 and iPad Mini (2021) models.\nIt was announced late 2021 and offers 6 cores divided in 2 performance cores and four power efficiency cores.\nThe CPU performance increases only slightly compared to the A14, but GPU (in the higher end models) offers higher gains.\n...\nThe chip also includes a new GPU that is advertised as 50% faster, the M12 Motion co-processor and a Neural Engine with 8 cores for up to 5 trillion operations per second.",
            "title": "Qualcomm Snapdragon 8 Gen 1 vs Apple A15 Bionic ...",
            "url": "https://www.notebookcheck.net/SD-8-Gen-1-vs-A15-vs-A12-Bionic_14029_13825_10166.247596.0.html",
            "date": "2023-07-01",
            "last_updated": "2025-12-01",
            "source": "web"
          }
        ],
        "type": "search_results",
        "queries": [
          "Apple A-series SoC design philosophy CPU GPU integration",
          "Qualcomm Snapdragon design philosophy CPU GPU integration",
          "Apple A-series vs Snapdragon CPU GPU architecture high level"
        ]
      },
      {
        "id": "msg_6d730289-196f-44c5-9561-11554263bcda",
        "content": [
          {
            "text": "Apple’s A‑series SoCs are vertically optimized, custom CPU/GPU designs built for iOS with tight hardware–software co‑design and aggressive single‑thread efficiency, while Snapdragon SoCs emphasize modularity, semi‑custom ARM CPU cores, Adreno GPUs, and broad OEM feature flexibility, especially around connectivity and gaming. [web:1][web:4][web:7][web:9] At a high level, Apple optimizes one tightly controlled platform end‑to‑end, whereas Qualcomm optimizes a scalable platform that can be configured across many devices, vendors, and price tiers. [web:4][web:7][web:9]\n\n## CPU philosophy\n\n- Apple A‑series uses fully custom ARM‑compatible cores (e.g., “large” performance + “small” efficiency cores) designed in‑house rather than off‑the‑shelf Cortex designs, with a focus on high IPC and strong single‑core performance at mobile power envelopes. [web:4][web:5][web:7]  \n- Snapdragon flagships typically use ARM’s Cortex performance/efficiency cores or semi‑custom derivatives in a big.LITTLE or tri‑cluster layout, tuned for good multi‑core throughput, thermals, and time‑to‑market across many OEMs. [web:9][web:10]  \n- Because Apple controls the OS and app stack, A‑series CPU microarchitecture, cache hierarchy, and power management are co‑designed with iOS and major frameworks, allowing very aggressive per‑core performance without sacrificing battery life. [web:3][web:4][web:5][web:7]  \n- Qualcomm instead exposes a flexible platform: CPU scheduling, DVFS behavior, and thermal limits are co‑tuned with each OEM’s Android skin, form factor, and cooling solution. [web:9]  \n\n## GPU and graphics focus\n\n- Apple integrates its own in‑house GPU designs in recent A‑series generations (heritage from PowerVR, but now branded Apple GPU), tightly tied to Metal and Apple’s graphics stack. [web:1][web:3][web:4][web:7]  \n- Qualcomm’s Snapdragon line uses Adreno GPUs, a long‑running, internally developed GPU family heavily optimized for mobile gaming, high refresh displays, and broad API support (Vulkan, OpenGL ES, often desktop‑style DirectX in PC‑class parts). [web:2][web:4][web:9]  \n- Apple’s design leans toward consistent, thermally stable performance and efficient use of a unified memory architecture, which benefits real‑world rendering and GPU–CPU data sharing even when peak theoretical throughput is not always highest on paper. [web:3][web:5][web:7]  \n- Snapdragon’s philosophy has often highlighted headline GPU features for OEMs (high FPS gaming modes, variable rate shading, advanced display pipelines) to differentiate Android flagships, gaming phones, and XR devices. [web:4][web:7][web:9]  \n\n## System integration and memory\n\n- A‑series chips are classic “all‑in‑one” SoCs: CPU, GPU, Neural Engine, ISP, media codecs, secure enclave, and other accelerators share a high‑bandwidth internal fabric and system‑level cache, reducing off‑chip traffic and latency. [web:1][web:3][web:5][web:6]  \n- Apple strongly emphasizes a **unified** memory architecture and system‑level cache: CPU, GPU, and ML engines access the same physical memory pool without copies, which simplifies software and boosts efficiency for mixed workloads (e.g., compute + graphics + ML in one frame). [web:3][web:5][web:7]  \n- Snapdragon SoCs also integrate CPU, Adreno GPU, Hexagon NPU/DSP, ISP, and media engines, but place special strategic weight on heterogeneous computing: offloading pieces of a workload to the “best” block (CPU, GPU, DSP, NPU) depending on power and latency. [web:9]  \n- Unlike Apple, Qualcomm must support many OS variants and OEM stacks, so its integration strategy stresses standard interfaces and flexible partitioning rather than deep co‑design with a single OS and set of first‑party apps. [web:4][web:7][web:9]  \n\n## Connectivity and platform strategy\n\n- Apple typically pairs A‑series SoCs with separate modems (historically Qualcomm, now sometimes in‑house efforts), prioritizing SoC area and power budget for application‑processor blocks and deferring RF/telecom differentiation to the modem. [web:1][web:7]  \n- Snapdragon flagships usually integrate the cellular modem platform tightly with the SoC family (even when packaged separately), and Qualcomm positions Snapdragon as a full connectivity + compute stack: 5G, Wi‑Fi, BT, GNSS, audio codecs, and camera pipelines are part of the platform story for OEMs. [web:9]  \n- Apple’s vertical model optimizes for a small number of premium devices with long support lifetimes, using the A‑series as a cornerstone of the overall iOS experience. [web:1][web:4][web:7]  \n- Qualcomm’s model optimizes for breadth: multiple Snapdragon tiers, re‑usable IP blocks, and scalable feature sets across phones, tablets, wearables, XR headsets, PCs, and automotive, all built on related CPU/GPU/NPU architectures. [web:2][web:9]",
            "type": "output_text",
            "annotations": [],
            "logprobs": []
          }
        ],
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "status": "completed",
    "error": null,
    "usage": {
      "input_tokens": 6325,
      "output_tokens": 1210,
      "total_tokens": 7535,
      "cost": {
        "currency": "USD",
        "input_cost": 0.00343,
        "output_cost": 0.0121,
        "total_cost": 0.01848,
        "cache_creation_cost": null,
        "cache_read_cost": 0.00045,
        "tool_calls_cost": 0.0025
      },
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 3584,
        "cached_tokens": 3584
      },
      "tool_calls_details": {
        "search_web": {
          "invocation": 1
        }
      },
      "output_tokens_details": {
        "reasoning_tokens": 0
      }
    },
    "background": false,
    "completed_at": 1779391825,
    "frequency_penalty": 0,
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "user": null
  }
  ```
</Accordion>

<Info>
  See [Agent API Presets](/docs/agent-api/presets) for available presets and their configurations.
</Info>

### Using Third-Party Models

You can also specify third-party models directly instead of using presets:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    from openai import OpenAI

    client = OpenAI(
        api_key=os.environ.get("PERPLEXITY_API_KEY"),
        base_url="https://api.perplexity.ai/v1"
    )

    response = client.responses.create(
        model="openai/gpt-5.6-sol",
        input="Explain the key differences between REST and GraphQL APIs"
    )

    print(response.output_text)
    ```
  </Tab>

  <Tab title="Typescript">
    ```typescript theme={null}
    import OpenAI from 'openai';

    const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai/v1"
    });

    const response = await client.responses.create({
      model: "openai/gpt-5-mini",
      input: "Explain the key differences between REST and GraphQL APIs"
    });

    console.log(response.output_text);
    ```
  </Tab>
</Tabs>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_7edd7725-4ae1-49ad-9e96-22c93679363e",
    "created_at": 1779391454,
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "results": [
          {
            "id": 1,
            "snippet": "- REST follows a resource-based architecture and typically uses multiple endpoints for different resources.\n- GraphQL provides a single endpoint where clients can request exactly the data they need.\n- GraphQL helps reduce over-fetching and under-fetching, which can occur in traditional REST APIs.\n...\nHere are some key differences between GraphQL and REST APIs based on how they handle endpoints, data fetching, and real-time communication.\n|GraphQL|REST API|\n|--|--|\n|GraphQL uses single endpoint for every operation.|REST API uses multiple endpoints for different operations|\n|In GraphQL client defines what data is required.|REST API fetches data using pre-defined rules.|\n|GraphQL reduces over-fetching and under-fetching.|Over-fetching and under-fetching are the common issues with Rest API.|\n|GraphQL supports real-time updates with subscriptions|REST API relies on polling for real-time data|\n|GraphQL is a growing technology with various tools and libraries.|REST APIs are well established ecosystem with multiple libraries and tools.|",
            "title": "GraphQL vs REST - GeeksforGeeks",
            "url": "https://www.geeksforgeeks.org/graphql/graphql-vs-rest-which-is-better-for-apis/",
            "date": "2026-03-11",
            "last_updated": "2026-05-18",
            "source": "web"
          },
          {
            "id": 2,
            "snippet": "GraphQL queries access not just the properties of one resource but also smoothly follow references between them.\nWhile typical REST APIs require loading from multiple URLs, GraphQL APIs get all the data your app needs in a single request.",
            "title": "GraphQL | The query language for modern APIs",
            "url": "https://graphql.org",
            "date": null,
            "last_updated": "2026-05-06",
            "source": "web"
          },
          {
            "id": 3,
            "snippet": "{ts:15} rest let's talk about the fundamental differences between graphql and rest rest stands for representational State\n{ts:22} transfer and it typically has unique URLs it follows the standard HTTP methods of get post put and delete it\n{ts:31} has uses status code standardization so you have the 200 okay the 404 not found Etc and data is typically returned in\n{ts:39} Json or XML format graphql stands for graph query language and it has a single endpoint for all operations you have the\n{ts:48} three primary operations of query mutation and subscription the client specifies exactly what data it needs and\n{ts:56} the API documents itself through introspection with graphql clients have precise control over the data that it\n{ts:63} requires so there's no such thing as over fetching or under fetching and these performance implications are",
            "title": "GraphQL vs REST: What's the Difference and When Should You ...",
            "url": "https://www.youtube.com/watch?v=2wz19HOyu1w",
            "date": "2025-04-01",
            "last_updated": "2026-04-14",
            "source": "web"
          },
          {
            "id": 4,
            "snippet": "- GraphQL is built around the concept of \"getting exactly what you asked for\"without any data under or overfetching.\n- GraphQL makes it easier to aggregate data from multiple sources.\nIt uses a type system rather than multiple endpoints to describe data.\n...\nWhile typical REST APIs require loading from multiple URLs, GraphQL APIs get all the data in a single request - making apps quick even on slow mobile network connections.\n...\nConversely, if you wanted to gather some information from a specific endpoint, you couldn’t limit the fields that the REST API returns; you’ll always get a complete data set - or overfetching.\n...\nHowever, the most commonly stated benefit is that GraphQL solves both over-fetching and under-fetching issues by allowing the client to request only the data that is required.\nSince there is more efficiency associated with working with GraphQL, development is much faster with GraphQL than it would be with REST.\n...\nGraphQL queries themselves are not faster than REST queries, but since you have full control over what you want to query and what the payload should be, GraphQL requests will always be smaller and more efficient.",
            "title": "What Is GraphQL and How It Works - Hygraph",
            "url": "https://hygraph.com/learn/graphql",
            "date": "2025-10-27",
            "last_updated": "2026-05-13",
            "source": "web"
          },
          {
            "id": 5,
            "snippet": "Unlike REST, which typically uses multiple endpoints to fetch data and perform network operations, GraphQL exposes data models by using a single endpoint through which clients send GraphQL requests, regardless of what they’re asking for.\nThe API then accesses resource properties—and follows the references between resources—to get the client all the data they need from a single query to the GraphQL server.\n...\nGraphQL offers an efficient, more flexible addition to REST; GraphQL APIs are often viewed as an upgrade from RESTful environments, especially given their ability to facilitate collaboration between front-end and back-end teams.\n...\nBecause REST relies on multiple endpoints and stateless interactions—where every API request is processed as a new query, independent of any others—clients receive every piece of data that is associated with a resource.\nIf a client needs only a subset of the data, it still receives all the data (over-fetching).\nAnd if the client needs data that spans multiple resources, a RESTful system often makes the client query each resource separately to compensate for inadequate data retrieval from the initial request (under-fetching).\nGraphQL APIs use a single GraphQL endpoint to give clients a precise, comprehensive data response in a one round trip from a single request, eliminating over- and under-fetching issues.\n...\nGraphQL reduces the need for versioning because clients can specify their data requirements in the query.\nThe addition of new fields to the server does not affect clients without a need for those fields.\n...\nREST doesn’t have built-in support for real-time updates.\nIf an app needs real-time functionality, developers usually must implement techniques like long-polling (where the client repeatedly polls the server for new data) and server-sent events, which can add complexity to the application.\nHowever, GraphQL includes built-in support for real-time updates through subscriptions.",
            "title": "GraphQL vs REST: What's the Difference? - IBM",
            "url": "https://www.ibm.com/think/topics/graphql-vs-rest-api",
            "date": "2024-03-29",
            "last_updated": "2026-01-17",
            "source": "web"
          },
          {
            "id": 6,
            "snippet": "As stated in REST API vs GraphQL, “the key difference between GraphQL and REST APIs is that GraphQL is a query language, while REST is an architectural concept for network-based software.”",
            "title": "The Role and Impact of GraphQL - F5 Networks",
            "url": "https://www.f5.com/resources/reports/the-role-and-impact-of-graphql-octo-report",
            "date": null,
            "last_updated": "2026-05-21",
            "source": "web"
          },
          {
            "id": 7,
            "snippet": "The key differences lie in data fetching, schema definition, versioning, and error handling.\nGraphQL uses a single endpoint and allows clients to specify their data requirements, while REST relies on multiple endpoints with fixed data structures.",
            "title": "GraphQL vs REST: Key Similarities and Differences Explained",
            "url": "https://konghq.com/blog/learning-center/graphql-vs-rest",
            "date": "2025-02-28",
            "last_updated": "2026-05-19",
            "source": "web"
          },
          {
            "id": 8,
            "snippet": "Instead of exposing multiple endpoints that return fixed response structures, a GraphQL API typically exposes a **single endpoint**.\nClients send queries that specify exactly what data they need.\n...\nWhile REST and GraphQL ultimately solve the same problem—exposing data through an API—their design philosophies differ in several important ways.\n|Aspect|REST|GraphQL|\n|--|--|--|\n|API structure|Multiple endpoints representing resources|Typically a single endpoint|\n|Data retrieval|Server defines response structure|Client specifies required fields|\n|Network requests|Often multiple requests for related data|Complex data fetched in a single query|\n|Versioning|Often uses versioned endpoints|Uses schema evolution and field deprecation|\n|Caching|Strong support via HTTP caching|Typically handled at the client level|",
            "title": "REST vs GraphQL: Key Differences, Performance, and When to Use ...",
            "url": "https://dev.to/riteshkokam/rest-vs-graphql-key-differences-performance-and-when-to-use-each-51n7",
            "date": "2026-03-09",
            "last_updated": "2026-05-21",
            "source": "web"
          },
          {
            "id": 9,
            "snippet": "Unlike REST, GraphQL allows for requesting specific data that a client needs, departing from the fixed data structure approach.\n...\nIn a nutshell, mainly the progress GraphQL has made is querying in one request, while retrieving only the necessary data instead of the complete set.\nThe main reason for GraphQL being so attractive to developers is its client-driven approach.\n...\nHowever, notable differences start with the conceptual models: While REST is made up of files, GraphQL is constructed of graphs.",
            "title": "GraphQL: Core Features, Architecture, Pros and Cons - AltexSoft",
            "url": "https://www.altexsoft.com/blog/graphql-core-features-architecture-pros-and-cons/",
            "date": "2019-03-23",
            "last_updated": "2026-03-31",
            "source": "web"
          }
        ],
        "type": "search_results",
        "queries": [
          "REST vs GraphQL key differences",
          "REST API characteristics",
          "GraphQL API characteristics"
        ]
      },
      {
        "id": "msg_d44758f0-ae0f-4d8a-8ded-ceb68d67ab49",
        "content": [
          {
            "text": "REST and GraphQL are both ways to build APIs, but REST is an architectural style built around multiple resource URLs and HTTP semantics, while GraphQL is a query language over a single endpoint where the client specifies exactly which data it needs.[web:5][web:6] GraphQL typically reduces over‑fetching and under‑fetching compared to REST by letting clients shape responses, at the cost of more complexity in schema design and caching.[web:1][web:8]\n\n## Core conceptual difference\n\n- REST is an **architectural** pattern that exposes resources via multiple endpoints, using HTTP verbs (GET, POST, PUT, DELETE, etc.) and status codes to model operations.[web:1][web:5]  \n- GraphQL is a **query** language and runtime that sits behind usually one endpoint and lets clients send structured queries, mutations, and subscriptions against a typed schema.[web:2][web:4][web:6]\n\n## Endpoints and data fetching\n\n- REST typically has many endpoints (e.g., `/users`, `/users/1/posts`) and each endpoint returns a fixed data shape defined by the server.[web:1][web:7]  \n- GraphQL usually has a single endpoint (e.g., `/graphql`), and the client declares exactly which fields and related objects it wants in a single request, often avoiding multiple round trips.[web:2][web:4][web:5]\n\n## Over‑fetching, under‑fetching, and performance\n\n- With REST, clients often receive more data than needed (over‑fetching) or must call several endpoints to collect enough data (under‑fetching), especially for nested relationships.[web:1][web:5][web:9]  \n- GraphQL queries return only requested fields, which reduces payload sizes and the number of requests, though raw query speed is not inherently faster; efficiency comes from tailoring the payload.[web:4][web:8]\n\n## Typing, versioning, and evolution\n\n- REST responses are often JSON without a strict, machine‑enforced schema, and breaking changes are commonly managed with versioned URLs like `/api/v1` and `/api/v2`.[web:5][web:8]  \n- GraphQL uses a strongly typed schema with introspection, enabling tools, self‑documentation, and schema evolution via adding fields and deprecating old ones instead of creating new API versions.[web:2][web:4][web:5][web:8]\n\n## Caching and real‑time features\n\n- REST works naturally with HTTP caching (ETags, Cache‑Control) because resources are tied to URLs and standard methods, making it straightforward for browsers and proxies to cache responses.[web:5][web:8]  \n- GraphQL usually needs custom or client‑side caching strategies (e.g., normalized caches) due to a single endpoint, but it offers built‑in support for real‑time updates via subscriptions, whereas REST relies on techniques like polling or server‑sent events.[web:1][web:4][web:5]",
            "type": "output_text",
            "annotations": [],
            "logprobs": []
          }
        ],
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "status": "completed",
    "error": null,
    "usage": {
      "input_tokens": 5870,
      "output_tokens": 679,
      "total_tokens": 6549,
      "cost": {
        "currency": "USD",
        "input_cost": 0.00286,
        "output_cost": 0.00679,
        "total_cost": 0.0126,
        "cache_creation_cost": null,
        "cache_read_cost": 0.00045,
        "tool_calls_cost": 0.0025
      },
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 3584,
        "cached_tokens": 3584
      },
      "tool_calls_details": {
        "search_web": {
          "invocation": 1
        }
      },
      "output_tokens_details": {
        "reasoning_tokens": 0
      }
    },
    "background": false,
    "completed_at": 1779391454,
    "frequency_penalty": 0,
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "user": null
  }
  ```
</Accordion>

### Streaming Responses

Streaming works with the Agent API:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    from openai import OpenAI

    client = OpenAI(
        api_key=os.environ.get("PERPLEXITY_API_KEY"),
        base_url="https://api.perplexity.ai/v1"
    )

    response = client.responses.create(
        model="openai/gpt-5.6-sol",
        input="Write a short bedtime story about a curious fox who discovers a hidden meadow.",
        stream=True
    )

    for event in response:
        if event.type == "response.output_text.delta":
            print(event.delta, end="", flush=True)
    ```
  </Tab>

  <Tab title="Typescript">
    ```typescript theme={null}
    import OpenAI from 'openai';

    const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai/v1"
    });

    const response = await client.responses.create({
      model: "openai/gpt-5-mini",
      input: "Write a short bedtime story about a curious fox who discovers a hidden meadow.",
      stream: true
    });

    for await (const event of response) {
      if (event.type === "response.output_text.delta") {
        process.stdout.write(event.delta);
      }
    }
    ```
  </Tab>
</Tabs>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_298bc3ed-1e44-4f44-bf04-04c55e188d0d",
    "created_at": 1779391925,
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "results": [
          {
            "id": 1,
            "snippet": "Is your little one struggling to fall asleep?\nJoin The Curious Little Fox, a heartwarming bedtime story filled with adventure, wonder and gentle life lessons.\nPerfect for story time, this tale is designed to soothe little ones and spark their imagination before bedtime.\n...\n{ts:1} Once upon a time in a quiet forest, there lived\na little fox named Fennel.\nFennel was not like   the other foxes who like to nap in the sunshine or\nchase butterflies all day.\nFennel was curious.\nHe\n{ts:18} wanted to know everything.\nOne morning he asked\nhis mother, \"Why do birds sing so early?\"\nHis   mother smiled and said, \"Because that is how they\ngreet the new day.\nIt's their way of saying good   morning to the forest.\"\nLater, Fennel saw ants\nmarching in a long line.\n...\nFennel curled up in his cozy den   and drifted into a gentle sleep, dreaming of all\nthe wonders he would learn tomorrow.\nOnce upon a\n{ts:87} time, in a quiet meadow at the edge of the forest,\nthere lived a small hedgehog named Hugo.\nHugo was   the tiniest hedgehog in his family.\nWith soft\nbrown spines and the brightest, curious eyes.\nEvery night, Hugo loved to wander under the\nmoonlight, sniffing flowers and listening to\n{ts:111} the cricket sing.\nBut there was one thing Hugo was\nafraid of.\nThe dark part of the forest.\nIt looked   so big and shadowy that Hugo always tiptoed\naway from it.\nOne evening, while playing near   the tall oak tree, Hugo heard a faint cheap.\nHe\nfollowed the sound and discovered a little bird\n{ts:134} who had fallen from her nest.\n\"Oh no, my nest is\nin the dark part of the forest,\" chirped the baby   bird.\nHugo's heart thumped.\n\"The dark forest.\"\nBut then he looked at the tiny bird's worried   eyes and thought, \"If I don't help, who will?\"\nGathering his courage, Hugo gently lifted the\n{ts:158} bird onto his back.\nStep by step, they ventured\ninto the forest.\nThe tall trees swayed and shadows   danced.\nBut Hugo kept reminding himself, \"I'm\nbrave when I help others.\"\nAt last, they found   the nest high in a pine tree.\nWith the help of\na friendly squirrel, the little bird was safely\n{ts:182} returned to her family.\nThe baby bird chirped \nhappily.\n\"Thank you, Hugo.\nYou're the bravest   hedgehog ever.\nFrom that night on, Hugo wasn't\nafraid of the dark forest anymore.\nHe had learned   that bravery doesn't mean not being scared.\nIt\nmeans doing what's right, even when you are.",
            "title": "The Curious Little Fox | Bedtime Story for Kids - YouTube",
            "url": "https://www.youtube.com/watch?v=r1f0lCO8OoU",
            "date": "2025-09-29",
            "last_updated": "2025-11-19",
            "source": "web"
          },
          {
            "id": 2,
            "snippet": "Join us for \"The Curious Fox and the Hidden Cave,\" a magical story about self-discovery and courage!\nWhen Felix the fox ventures into a mysterious cave, he discovers a glowing pool of water and meets the wise owl who guards the cave.\nThrough his adventure, Felix learns that the greatest truths are found within ourselves.\nThis Pixar-style animated story teaches kids about the importance of listening to your heart and finding answers within.\nWritten and illustrated by Kids Story Time, this heartwarming tale is perfect for teaching children about the value of self-discovery and courage.\n...\n{ts:554} was [Music] dangerous the answer is B that the\n{ts:562} greatest truths are found within ourselves Felix learned that the answers he was seeking were already in him and\n{ts:570} that the cave helped him discover this important truth thank you for joining us on",
            "title": "The Curious Fox and the Hidden Cave | Inspiring Kids Story on Self ...",
            "url": "https://www.youtube.com/watch?v=9p-1awCFnHI",
            "date": "2024-11-13",
            "last_updated": "2025-08-21",
            "source": "web"
          },
          {
            "id": 3,
            "snippet": "In this quiet winter bedtime story, a young fox cub named Rill learns that stillness has its own music.\nAs snow softens the forest and the world slows, he discovers the gentle rhythm hidden in breath, ice, and moonlight.\nA calming seasonal tale about patience, mindfulness, and the beauty of slowing down — perfect for relaxation, peaceful nights, and drifting into deep, restorative sleep.\n...\nIn this gentle bedtime story, a curious fox cub named Pip discovers a forest that speaks in whispers.\nAs he listens to the voice of the woods, Pip learns to move with courage, trust his instincts, and find peace in the quiet rustle of the night.\nA soothing tale of bravery, mindfulness, and the magic of truly listening—perfect for bedtime relaxation and peaceful sleep.\nIn this calming bedtime story, Milo wanders into a quiet forest where the trees whisper lessons carried on the wind.\nSurrounded by moss and twilight, he learns that patience isn’t about waiting—it’s about trusting life’s gentle timing.\nA peaceful tale of mindfulness, renewal, and connection to nature, perfect for relaxation and drifting into sleep.\nIn this tranquil springtime bedtime story, a shy rabbit named Pip discovers a hidden meadow where flowers ring like silver-blue bells.\nAs she listens to their gentle song, Pip learns that courage doesn’t always sound loud—it can bloom quietly in acts of kindness and belonging.\nPerfect for peaceful sleep, mindfulness, and soothing nighttime reflection.\nWhen a curious frog begins painting reflections in puddles, a world of color and wonder unfolds.\nThis peaceful bedtime story encourages creativity, mindfulness, and joy in life’s small moments.",
            "title": "Tuck Me In: Tranquil Bedtime Stories | iHeart",
            "url": "https://www.iheart.com/podcast/269-tuck-me-in-tranquil-bedtim-304484365/",
            "date": "2025-12-28",
            "last_updated": "2026-01-20",
            "source": "web"
          },
          {
            "id": 4,
            "snippet": "1. Hunting for Bugs\n2. Lost in the Rain\n3. The Red Barn\n4. Little Drops and Big Drops\n5. What Is It?\n6. There It Is!\n7. Bat Looks for a Friend\n8. No Luck!\n9. A New Home\n10. Around the Well\n11. Cow Tells How",
            "title": "Full List - Little Fox",
            "url": "https://www.littlefox.com/en/full_list",
            "date": null,
            "last_updated": "2026-05-18",
            "source": "web"
          },
          {
            "id": 5,
            "snippet": "**Curious George**\nIn a cheerful town where laughter filled the air and bright balloons danced in the sky, lived a playful and curious little monkey named George.\nWith a twinkle in his eyes and a heart full of wonder, George was always eager to explore the world around him.\n...\nThat night, as the stars twinkled above and the town glowed gently below, George snuggled into bed with a happy sigh.",
            "title": "Curious George - Bedtime Stories",
            "url": "https://www.readthetale.com/popular-bedtime-stories/curious-george",
            "date": "2025-05-11",
            "last_updated": "2025-05-13",
            "source": "web"
          },
          {
            "id": 6,
            "snippet": "## The Fox and the Magical Forest\n## In a sunny meadow, where wildflowers swayed gently in the breeze, a curious and adventurous young fox named Finnley loved to explore.\nHis orange fur glistened in the sunlight, and his green eyes sparkled with excitement as he sniffed and prowled through the tall grass.\nFinnley had heard tales of a magical forest, hidden just beyond the meadow, where enchanted creatures roamed and secrets waited to be uncovered.\nWith his fluffy tail twitching with anticipation, Finnley set off on a thrilling journey to discover the wonders that lay within the magical forest.\nAs he wandered deeper into the forest, the trees grew taller, and the path grew narrower.\nFinnley's ears perked up, and he listened carefully to the rustling leaves and chirping birds.\nSuddenly, a soft hooting sound caught his attention, and he spotted a gentle old owl perched on a branch above.\nThe owl, whose name was Luna, looked at Finnley with her piercing yellow eyes and said, \"Who-who-who goes there, little fox?\nWhat brings you to our magical forest?\"\nFinnley explained his desire to explore and learn the secrets of the forest, and Luna smiled, \"Ah, a brave and curious adventurer, I see.\nI'll be happy to guide you, but first, let's find my friend Benny, he's always up for a fun adventure.\"\nLuna flew down from the tree, and Finnley followed her as she fluttered ahead, leading him to a burrow hidden behind a thick bush.\nInside the burrow, they found Benny, a happy-go-lucky rabbit, busy munching on a basket of fresh carrots.\nBenny's bright blue eyes sparkled with excitement as he greeted Finnley and Luna, \"Hey, friends!\nWhat's all the fuss about?\nAre we going on an adventure?\"\nLuna explained Finnley's quest, and Benny exclaimed, \"Oh, boy!\n...\nLet's go explore and have some fun!\"\nThe three new friends set off together, eager to discover the magical forest's secrets.\n...\nLuna explained that this was the legendary Wisdom Tree, where the forest's secrets and magic were stored.\n...\nLuna led them back to the edge of the forest, where the meadow awaited, filled with the sweet scent of wildflowers.\n...\nAs Finnley returned to his cozy den in the meadow, he felt grateful for the incredible journey he had shared with Luna and Benny.\nHe snuggled into his bed of soft leaves, feeling the warmth of the setting sun on his fur, and drifted off to sleep, his heart filled with the magic of the forest.\n...\nAnd so, with a heart full of wonder and a mind full of magical memories, Finnley slept peacefully, surrounded by the soothing sounds of the meadow, knowing that he would always have Luna and Benny by his side, ready for their next adventure together.\nThe end.\n## This story featured...\nFinnley\na curious and adventurous young fox with orange fur, green eyes, and a fluffy tail\nLuna\na gentle and wise old owl with soft grey feathers, big round glasses, and piercing yellow eyes\nBenny\na happy-go-lucky and energetic rabbit with white and brown fur, bright blue eyes, and a mischievous grinExperience the magic for yourself.",
            "title": "The Fox and the Magical Forest",
            "url": "https://www.bedtimestory.ai/tabima47511/story/XFC1aSBvZpQ9uL",
            "date": "2025-02-13",
            "last_updated": "2025-05-15",
            "source": "web"
          },
          {
            "id": 7,
            "snippet": "## The Little Fox's Big Adventure\n## Once upon a time, in a lush, green forest filled with the sounds of nature, lived Finn the Little Fox.\nFinn was not just any fox; he was small, but his curiosity was as big as the forest itself.\nHis bright orange fur shone like the sun, and his sparkling green eyes reflected his love for adventure.\nThe little blue bandana around his neck fluttered as he scampered through the woods, exploring every nook and cranny.\nOne bright morning, as Finn was exploring, he stumbled upon Ellie the Wise Owl, who was perched high on an ancient oak tree.\nEllie, with her deep brown feathers and wise, knowing eyes behind her tiny glasses, looked down at Finn.\n\"Good morning, Finn!\nWhat adventure are we embarking on today?\" she hooted, her voice as calm and soothing as the morning breeze.\n\"I want to find the Hidden Meadow,\" Finn declared with a twinkle in his green eyes.\n\"Legend says it's the most beautiful place in the forest, but no one knows where it is!\"\nHis voice was filled with excitement, imagining the wonders that awaited.\nJust then, Max the Rabbit, with his fluffy white fur and long, floppy ears, bounded over.\n\"Did someone say adventure?\nCount me in!\"\nMax's eyes sparkled mischieously, ready for anything that came his way.\nThe trio, bound by their thirst for discovery, set off into the heart of the forest.\nTheir journey was filled with laughter and small challenges.\nThey crossed bubbling brooks, climbed steep hills, and navigated through dense thickets.\n...\nAs the sun began to dip lower in the sky, painting the clouds in hues of orange and pink, the friends found themselves in a part of the forest they had never seen before.\nAncient trees towered above them, their leaves whispering secrets of old.\n\"We must be close,\" Ellie said, her glasses glinting in the fading light.\n\"The Hidden Meadow is said to be guarded by the ancient trees themselves.\"\nSuddenly, they came upon a clearing where the trees parted like curtains, revealing the Hidden Meadow.\nIt was more breathtaking than they had imagined, with flowers of every color blooming under the golden light of the setting sun.\nA sparkling stream wound its way through the meadow, its waters singing a soft melody.\nFinn, Ellie, and Max stepped into the meadow, their eyes wide in wonder.\n\"We found it!\"\nFinn shouted, his voice echoing through the trees.\nThey danced and played in the meadow, their hearts filled with joy and the thrill of discovery.\nAs night began to fall, they lay down on the soft grass, gazing up at the stars that twinkled like diamonds in the velvet sky.\n\"We did it together,\" Ellie said softly, her wise eyes reflecting the starlight.\n\"Friendship and courage led us here.\"\n\"Let's come back here every year,\" Max suggested eagerly, already dreaming of their next adventure.\nThey all agreed, their spirits high with the promise of future explorations.\nAnd so, under the watchful eyes of the stars, Finn, Ellie, and Max fell asleep, their dreams filled with magical meadows and endless adventures.\nThey knew that no matter where they went, their friendship would always lead them to discover the wonders of the world.\nAnd with that comforting thought, the forest whispered goodnight to the little adventurers, lulling them into a peaceful slumber filled with dreams of tomorrow's possibilities.",
            "title": "The Little Fox's Big Adventure - Bedtimestory.ai",
            "url": "https://www.bedtimestory.ai/cahoti59231/story/0C48nf4",
            "date": "2024-02-22",
            "last_updated": "2026-04-20",
            "source": "web"
          },
          {
            "id": 8,
            "snippet": "The Curious Little Fox and the Secret Garden | Kids Story | Bedtime Story\nIn the heart of a vast forest, there lived a little fox named Ember.\nEmber was known for her bright orange fur, her bushy tail, and her endless curiosity.\nShe loved to explore every corner of the forest, discovering new scents, meeting new creatures, and uncovering hidden wonders.\nBut there was one place she had always heard whispers about—a secret garden that no one could ever find.\nOne crisp autumn morning, Ember overheard a conversation between the wise old owl and the chatty rabbit.\n“The secret garden is hidden deep in the forest,” said the owl, his eyes twinkling.\n“Only those with a true heart can find it.”\nEmber’s ears perked up.\n“A secret garden?”\nshe wondered aloud.\n“What’s inside it?”\n“The garden holds the most magical flowers,” the rabbit replied.\n“They glow in the moonlight and never wither.”\nEmber’s curiosity grew stronger.\nShe had to see this magical garden for herself.\nWithout a second thought, she set off, determined to find the secret garden.\nAs she journeyed deeper into the forest, the trees grew taller, their branches weaving together to form a thick canopy.\nThe air was filled with the sounds of rustling leaves and distant bird songs.\nEmber sniffed the air, searching for any sign of the garden, but there was nothing.\nDays passed, and Ember didn’t give up.\nShe crossed streams, hopped over logs, and climbed steep hills.\nShe met all kinds of animals along the way—squirrels, deer, and even a family of hedgehogs—but none of them knew where the secret garden was.\nFinally, on the fourth day of her search, Ember felt tired and sat down on a soft patch of moss.\n“Maybe the secret garden is just a story,” she sighed.\n“I don’t know if I’ll ever find it.”\nJust then, she noticed something strange.\nA single, glowing flower was growing by her side, its petals shimmering in the sunlight.\nEmber followed the flower’s glow and found more flowers, each one glowing brighter than the last.\nExcitedly, she followed the trail of glowing flowers, and soon she found herself standing before a hidden entrance covered by vines.\nWith a burst of excitement, Ember pushed the vines aside and stepped into the garden.\nInside, the garden was more magical than she had ever imagined.\nThe flowers shimmered in every color of the rainbow, and their sweet scent filled the air.\nButterflies fluttered around, and the soft hum of a distant waterfall could be heard.\nIt was a place of peace and beauty, untouched by time.\nEmber smiled, knowing she had found something truly special.\nBut as she looked around, she realized the secret garden wasn’t just about the flowers—it was about the journey to find it.\nAlong the way, she had learned to be patient, to trust her instincts, and to never give up, no matter how difficult the path seemed.\nFrom that day on, Ember visited the secret garden often, always carrying with her the lessons she had learned.\nAnd she knew, deep in her heart, that the garden’s true magic wasn’t in the flowers—it was in the adventure of discovering something new.",
            "title": "The Curious Little Fox and the Secret Garden | Kids Story | Bedtime Story",
            "url": "https://www.youtube.com/watch?v=bpkQPRlhu1U",
            "date": "2024-11-25",
            "last_updated": "2025-05-15",
            "source": "web"
          },
          {
            "id": 9,
            "snippet": "✨ The Fox and The Hound — a gentle bedtime story for toddlers filled with friendship, kindness, and calm 🌙\n...\nIn tonight’s cozy tale, your little one will meet a clever fox and a loyal hound who discover the magic of true friendship under the stars.",
            "title": "Magical Bedtime Stories for Kids | The Fox And The Hound",
            "url": "https://www.youtube.com/watch?v=DRERlthRRoY",
            "date": "2025-07-20",
            "last_updated": "2025-08-27",
            "source": "web"
          },
          {
            "id": 10,
            "snippet": "Join Finn the Fox on a magical adventure through the Great Green Forest!\nIn this enchanting kids' story, Finn meets new animal friends, learns important life lessons, and discovers the wonders of nature.\nPerfect for bedtime or storytime, this delightful tale teaches bravery, kindness, and the joy of exploration.\nWatch as Finn helps a hedgehog in need, finds a hidden meadow, and returns home with a heart full of happiness.\n...\n{ts:0} Once Upon a Time in the great Green Forest there lived a little fox named\n{ts:4} Finn Finn was not like the other foxes While most foxes preferred to stay close to their dens sneaking through the\n{ts:11} underbrush In Search of food Finn Had a Heart full of curiosity he dreamed of exploring every corner of the forest\n...\n{ts:99} carefully gwed away the vines freeing Hazel From The Snare Hazel was so grateful that she offered to share her\n{ts:106} favorite berries with Finn as they enjoyed the sweet berries together Hazel told Finn about a Hidden Meadow deep in\n{ts:113} the forest it's the most beautiful place in the whole Forest Hazel said Finn's eyes lit up with excitement let's go see\n{ts:121} it with hazel leading the way they traveled through thick bushes over Mossy rocks and across a Babbling Brook\n{ts:130} finally they reached the Hidden Meadow it was more magnificent than Finn had ever imagined the meadow was filled with\n{ts:138} wild flowers of every color and butterflies danced in the air Finn realized that his Adventure was about\n{ts:145} more than just exploring new places it was about the friends he made and the kindness he shared along the way he felt\n{ts:153} proud of himself for being brave and helping others as the sun began to set Finn knew it was time to head back home\n{ts:161} Hazel gave him a big hug and promised to visit him soon when Finn returned to his den he felt warm and happy he had\n{ts:169} discovered that the world was full of wonderful things and that being kind and brave made every Adventure even more\n{ts:176} special and from that day on Finn continued to explore the forest always ready for a new adventure always ready",
            "title": "The Curious Little Fox: A Magical Forest Adventure | Kids Storytime | Animal Friends & Life Lessons",
            "url": "https://www.youtube.com/watch?v=q7mueJEE8-I",
            "date": "2024-09-02",
            "last_updated": "2026-03-09",
            "source": "web"
          }
        ],
        "type": "search_results",
        "queries": [
          "bedtime story curious fox hidden meadow original fiction"
        ]
      },
      {
        "id": "msg_22c9259f-1757-4805-af55-3163d862d8b3",
        "content": [
          {
            "text": "In a quiet forest, under a sky sprinkled with sleepy stars, lived a small fox named Luma who was curious about everything.  \n\nEvery evening, when other animals yawned and tucked themselves into their cozy homes, **Luma** would sit at the mouth of her den and watch the fireflies blink awake like tiny lanterns. She wondered where they went when they disappeared, why the wind sometimes whispered and sometimes howled, and whether the moon ever came down to touch the treetops. One soft dusk, as the last pink light faded from the clouds, Luma noticed something new: a faint glow between the trees, like moonlight spilled onto the ground.  \n\n“What is that?” she whispered, her ears perking up. Her whiskers tingled with curiosity. Instead of curling up to sleep, Luma followed the glow. She padded over roots and around ferns, her paws making almost no sound on the cool earth. The deeper she walked into the forest, the quieter everything became, until even the crickets seemed to hold their breath.  \n\nSoon, Luma came to an old fallen log, its bark soft with moss. Beneath it, a narrow path of pale stones wound away into the shadows, almost hidden under leaves. “A secret path,” Luma breathed. “Where do you lead?” Without another thought, she stepped onto the first stone.  \n\nThe path curled between tall trees whose branches knitted together like gentle hands, holding bits of silver moonlight in their fingers. Luma’s tail brushed against ferns that shivered and sprinkled dew on her fur. As she walked, she heard new sounds: a distant bubbling, like laughter made of water, and a faint chiming, as if someone were gently tapping glass.  \n\nThe stones finally led her to a curtain of low-hanging branches and twining vines. From the other side came the cool, sweet smell of clover and something else—something bright and green and new. Luma’s heart fluttered in her chest. She nudged the vines aside with her nose and stepped through.  \n\nOn the other side was a meadow she had never seen before. It lay hidden like a secret between the trees, round and soft and glowing in the moonlight. The grass was silver at the tips, waving slowly as if it were breathing. Tiny blue flowers dotted the ground, their petals shining like little bits of sky that had fallen down to rest. Fireflies floated above them, drifting in lazy circles, painting gentle trails of light in the air.  \n\nIn the center of the meadow flowed a small, clear stream. It sang over smooth stones, its voice the bubbling sound Luma had heard before. As she watched, the water caught the moonlight and scattered it, casting ripples of silver across the grass. The chiming sound came from the reeds by the bank, their thin stalks knocking softly together when the breeze passed by.  \n\nLuma stepped into the meadow, her paws sinking into the cool, velvety grass. The air felt softer here, as if the whole place were wrapped in a warm, invisible blanket. She walked in slow circles, breathing in the sweet scents, her eyes wide with wonder. “How long have you been hiding here?” she asked the meadow. The meadow only answered with the hush of the grass and the gentle song of the stream, but Luma felt as if it were smiling.  \n\nNear the stream, she found a patch of clover so thick it looked like a green cloud. She curled up right there, close enough for the water to whisper its tiny stories into her ears. Fireflies drifted closer, hovering above her like a cluster of softly glowing stars that had floated down just to keep her company.  \n\nAs she lay there, Luma realized something: the hidden meadow had always been part of her forest, yet she had never seen it until she dared to follow the little glow and the secret stone path. “The forest has more secrets than I ever dreamed,” she thought, her eyes growing heavy. “And I can find them, one by one.”  \n\nThe stream kept singing, and the grass kept breathing its cool, gentle rhythm. Above, the real stars wheeled slowly across the sky, watching over the small, curious fox in her new favorite place. Luma’s breaths grew deep and slow. Her tail curled around her nose, and her ears relaxed.  \n\nJust before she drifted into sleep, she whispered, “Thank you, hidden meadow. I’ll come back tomorrow and discover more of your secrets.”  \n\nThe fireflies blinked a little more softly, as if answering her. The moon slipped behind a thin cloud, dimming the light just enough to make everything comfortable and calm. Wrapped in the quiet magic of the meadow, the curious fox closed her eyes and fell into a deep, peaceful sleep, while the forest, the stream, and the stars kept a gentle watch until morning.",
            "type": "output_text",
            "annotations": [],
            "logprobs": []
          }
        ],
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "status": "completed",
    "error": null,
    "usage": {
      "input_tokens": 8559,
      "output_tokens": 1047,
      "total_tokens": 9606,
      "cost": {
        "currency": "USD",
        "input_cost": 0.00622,
        "output_cost": 0.01047,
        "total_cost": 0.01964,
        "cache_creation_cost": null,
        "cache_read_cost": 0.00045,
        "tool_calls_cost": 0.0025
      },
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 3584,
        "cached_tokens": 3584
      },
      "tool_calls_details": {
        "search_web": {
          "invocation": 1
        }
      },
      "output_tokens_details": {
        "reasoning_tokens": 0
      }
    },
    "background": false,
    "completed_at": 1779391925,
    "frequency_penalty": 0,
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "user": null
  }
  ```
</Accordion>

### Using Tools

The Agent API supports built-in tools, including web search. With the OpenAI SDK, pass tools via `extra_body` in Python; in TypeScript/JS, pass `tools` as a top-level parameter and cast the call to bypass the SDK's type checking:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    from openai import OpenAI

    client = OpenAI(
        api_key=os.environ.get("PERPLEXITY_API_KEY"),
        base_url="https://api.perplexity.ai/v1"
    )

    # Pass tools via extra_body
    response = client.responses.create(
        model="openai/gpt-5.6-sol",
        input="What is an acquisition premium in M&A, and how do strategic vs financial buyers typically differ in their approach?",
        extra_body={
            "tools": [
                {
                    "type": "web_search",
                    "filters": {
                        "search_domain_filter": ["techcrunch.com", "crunchbase.com"]
                    }
                }
            ]
        }
    )

    print(response.output_text)
    ```
  </Tab>

  <Tab title="Typescript">
    ```typescript theme={null}
    import OpenAI from 'openai';

    const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai/v1"
    });

    // Use type casting (as any) to pass tools directly
    const response = await (client.responses.create as any)({
      model: "openai/gpt-5-mini",
      input: "What is an acquisition premium in M&A, and how do strategic vs financial buyers typically differ in their approach?",
      tools: [
        {
          "type": "web_search",
          "filters": {
            "search_domain_filter": ["techcrunch.com", "crunchbase.com"]
          }
        }
      ]
    });

    console.log(response.output_text);
    ```
  </Tab>
</Tabs>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_b58f6b3d-81b1-4324-9df2-428753912f6c",
    "created_at": 1779391825,
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "results": [
          {
            "id": 1,
            "snippet": "The difference between the price paid for a target company and the target’s assessed market value\nAcquisition premium is the difference between the price paid for a target company in a merger or acquisition and the target’s assessed market value.\nIt represents the excess amount over the fair value of all identifiable assets paid by an acquiring company.\nThe acquisition premium is also known as goodwill and is maintained on the acquirer’s balance sheet as an intangible asset, post-transaction.\n...\nA simpler way to calculate the acquisition premium for a deal is taking the difference between the price paid per share for the target company and the target’s current stock price, and then dividing by the target’s current stock price to get a percentage amount.\n...\nAs mentioned earlier, the acquisition premium is recorded on the acquirer’s balance sheet as goodwill.",
            "title": "Acquisition Premium - Overview, How To Calculate, Reasons",
            "url": "https://corporatefinanceinstitute.com/resources/valuation/acquisition-premium/",
            "date": "2020-02-25",
            "last_updated": "2026-02-20",
            "source": "web"
          },
          {
            "id": 2,
            "snippet": "A strategic buyer values a business based on the synergies they can create, such as cost savings or increased market share, and may be willing to pay a premium.\n...\nStrategic buyers consider the long-term vision and potential synergies, while financial buyers focus on metrics like a business’s EBITDA to determine a fair market price.\n...\nSynergies are the combined benefits that arise from merging two businesses, which are greater than the sum of their individual parts.\n...\nThis potential for enhanced value allows them to justify paying a control premium—a price above what the business is worth on its own—because the total value they receive from the acquisition is higher.\n...\nStrategic buyers, driven by the desire for market expansion and synergy creation, may be willing to pay a premium.\n...\nThey are less likely to offer a premium unless the business presents an exceptional opportunity for rapid growth or operational improvement.",
            "title": "How Do Strategic vs. Financial Buyers Value a Business Differently?",
            "url": "https://bradyware.com/strategic-vs-financial-buyers/",
            "date": "2026-01-22",
            "last_updated": "2026-05-20",
            "source": "web"
          },
          {
            "id": 3,
            "snippet": "is inflated, acquisition premiums are significantly lower than when the market is falling, and that target \n...\nThe synergy hypothesis has been widely quoted as a key driver of acquisition premia, and is supported by \nthe logical reasoning that should new efficiency gains be achieved through a combination of two sets of \nbusiness resources, then the value of the combined entity should outweigh the sum of the parts, leading\nto the idea that acquiring managers are willing to offer a price above market value of the target, as long \nas the price is below the potential gains to be realized through business combination.\n...\nHayward and Hambrick (1997) find that in the context of target firms, agency cost mitigation, where \nmanagers are themselves large shareholders in the firm, can increase the premium paid in an acquisition, \nas the managers hold out for a higher offer price from acquirers so as to gain as a shareholder of the firm.\n...\nacquirer and target, in such a way that improves the efficiency of both sets of resources (Damodaran, \n...\nThe larger benefits attributable to strategic synergies compared to financial synergies imply that the\nacquisition premium paid in strategically motivated mergers will be higher than those paid in mergers \ncharacterized by financial or conglomeration motives.\n...\nthe ratio of bidder free cashflows to assets increases the acquisition premium by a significant 1.05%, and \nthat firms that exhibit both high cashflows and low market to book ratios, are likely to pay, on average, \nan acquisition premium that is 19 percentage points higher than that paid by firms with low free cashflows \nand high market to book ratios.\nRecent acquirer performance increases the premium in acquisitions significantly by 0.004%, media praise \nfor acquirer CEO increases the premium significantly by 0.16%, and acquirer CEO pay relative to peers\n...\nPrevious literature on this topic is clear and suggests a \npositive relationship between a change in control and the acquisition premium paid.\n...\nSynergy is a major motive for acquisition (Berkovitch and Narayanan, 1993), and strategic acquisitions \nhave been shown in previous literature to attract higher premiums than financially motivated acquisitions.",
            "title": "[PDF] The Determinants of Premiums Paid in Acquisitions - Tilburg University",
            "url": "http://arno.uvt.nl/show.cgi?fid=153548",
            "date": "2020-09-25",
            "last_updated": "2026-03-04",
            "source": "web"
          },
          {
            "id": 4,
            "snippet": "Many times, when a business or an entity is looking to buy another business or corporation, they **pay an acquisition premium** or **takeover premium** to purchase it.\nAcquisition premium is the extra price paid by the acquirer in addition to the actual worth of the business on sale to secure the transaction.\nThe difference between the purchase price and the fair market value is considered a **goodwill asset** for the buyer.\n...\nIn a merger or acquisition (M&A) deal, the **additional cost of purchasing the target firm** is referred to as the takeover premium or acquisition premium.\nThe business that pays to take over another is called the acquirer, while the firm that is the subject of the acquisition is called the **target**.\n...\nThe acquisition premium is the amount paid for a firm over its** estimated market worth** in a merger or acquisition.\nThat’s the price an acquiring firm pays over and above the total fair worth of the acquired company’s assets.\nAfter a merger or acquisition is finalized, the premium paid for the target is recorded as an intangible asset on the financial statements of the buyer.\nThe term **“acquisition premium”** may also refer to** “takeover premium”**.\n...\nThe takeover premium or the acquisition premium is the amount by which the purchase price of the target firm exceeds its worth prior to the merger.\nIn other words, it is the amount that the acquiring company paid for each share of the target company.\n...\nTakeover premium is the discrepancy between how much a company was bought for and how much it was worth before the merger.\nThe true worth of the target firm must be estimated by the purchasing company in order to determine the acquisition premium.\nEnterprise value or equity valuation are both viable options to calculate the true worth of the target firm.\nA **transaction’s acquisition premium** may be estimated by dividing the difference between the amount per share spent by the purchasing company and the target company’s existing cost per share by the cost per share of the target firm at the time of the deal.\n**\nAcquisition premium or takeover premium = (amount per share spent by the purchasing - target company existing cost per share) / target company existing cost per share\n**",
            "title": "What is Acquisition Premium? | Eqvista",
            "url": "https://eqvista.com/company-valuation/m-a-valuation-methods/acquisition-premium/",
            "date": "2026-03-24",
            "last_updated": "2026-05-16",
            "source": "web"
          },
          {
            "id": 5,
            "snippet": "A strategic buyer is a company that acquires another business to strengthen its market position or capabilities.\nUnlike financial buyers, who prioritize investment returns, strategic buyers focus on how the acquired company fits into their long-term business strategy.\nThe goal is expansion, efficiency, or synergy that gives them a competitive edge.\n...\nStrategic buyers often pay more when integration creates value through cost savings, better purchasing, or expanded revenue.\nThat premium is not always tied to your current performance.\nStrategic buyers value your business based on what it becomes once integrated into their existing operations.\n...\nA financial buyer is an investor who acquires a business to generate a return.\nThese buyers include private equity firms, family offices, investment groups, and independent sponsors.\nThey plan to grow the company’s value and exit later through resale or recapitalization.",
            "title": "Financial Buyer vs Strategic Buyer: Key Differences When Selling a ...",
            "url": "https://advisorlegacy.com/blog/strategic-vs-financial-buyers",
            "date": "2026-01-09",
            "last_updated": "2026-05-16",
            "source": "web"
          },
          {
            "id": 6,
            "snippet": "In mergers and acquisitions, some buyers are willing to pay more than standard valuation multiples when a target company creates unique strategic value.\nThis is known as the **“strategic fit premium.”** Strategic buyers may offer higher valuations when an acquisition strengthens market position, accelerates growth, creates operational synergies, or eliminates competitive threats.\n...\nIn many transactions, buyers are willing to pay **above market valuation** when the acquisition creates strategic advantages that extend beyond the company’s standalone financial performance.\n...\nStrategic fit refers to how well a target company aligns with a buyer’s broader business strategy.\n...\n**What is a strategic premium in M&A?**\nA strategic premium occurs when a buyer pays more than typical valuation multiples because the acquisition creates additional value beyond the target company’s stand-alone financial performance.",
            "title": "Why Strategic Buyers Sometimes Pay More Than Market Valuation",
            "url": "https://horizonmaa.com/insights/why-strategic-buyers-sometimes-pay-more-than-market-valuation/",
            "date": "2026-03-26",
            "last_updated": "2026-03-26",
            "source": "web"
          },
          {
            "id": 7,
            "snippet": "The acquisition premium, also known as the takeover premium, is the difference between the actual price paid for a target company during a merger or acquisition based on its pre-merger value.\nA premium is commonly paid if the acquirer has identified potential synergies resulting from the transaction that will offset the cost of the premium paid.\n...\nThe takeover premium (acquisition premium) formula is calculated by subtracting the value before merger from the total amount paid by the acquirer.\nHere is the formula\n**TP = ** Amount Paid – Pre Merger Value\n**Where:**\n**Amount Paid:** The total cost of purchasing or merging with the target company.\nIt can be expressed in terms of the equity value of the transaction or the full value paid for both the company’s equity and debt.\n**Pre-Merger Value:** The market value of the firm before the transaction was brought.\n...\nAn acquisition takeover premium refers to the extra amount an acquiring company pays over the current market value of the target company’s shares to purchase and gain control of it.\n...\nThe takeover premium is calculated by subtracting the target company’s stock price before the acquisition announcement from the offer price, then dividing by the pre-announcement stock price and multiplying by 100 to get a percentage.",
            "title": "Acquisition Premium (Takeover) | Definition & Example Calculation",
            "url": "https://www.myaccountingcourse.com/acquisition-premium-takeover",
            "date": "2024-03-04",
            "last_updated": "2026-04-30",
            "source": "web"
          },
          {
            "id": 8,
            "snippet": "When the strategic rationale is strong, buyers may be willing to pay a premium.",
            "title": "How Strategic and Financial Buyers Differ in Software M&A",
            "url": "https://softwareequity.com/blog/financial-vs-strategic-buyers",
            "date": "2026-04-08",
            "last_updated": "2026-04-18",
            "source": "web"
          },
          {
            "id": 9,
            "snippet": "Synergies are often described as situations where “the whole is greater than the sum of its parts.”\nIn corporate M&A, a synergy is generated when a merged company is more valuable than the two separate companies.\n...\nThe amount that a strategic buyer is willing to pay for the synergies is known as the synergy premium.\nSynergy premium is calculated by taking the present value of future synergy benefits generated in the merged entity.\n...\nThe $20.5 million difference in net present value calculated by the strategic buyer compared with the financial buyer is the synergy premium.\nThis amount is equal to the net present value of the after-tax cost synergies.",
            "title": "How Synergies Impact What a Strategic Buyer Will Pay",
            "url": "https://www.pcecompanies.com/resources/how-synergies-impact-what-buyers-pay",
            "date": "2020-08-07",
            "last_updated": "2026-03-08",
            "source": "web"
          },
          {
            "id": 10,
            "snippet": "A **“purchase premium”** in the context of mergers and acquisitions refers to the excess that an acquirer pays over the market trading value of the shares being acquired.\n**“Premiums Paid Analysis”** is the name of a common investment banking analysis that reviews comparable transactions and averages the premiums paid for those transactions.",
            "title": "Premiums Paid Analysis | M&A Calculation Example - Wall Street Prep",
            "url": "https://www.wallstreetprep.com/knowledge/premiums-in-ma/",
            "date": "2023-12-05",
            "last_updated": "2026-05-17",
            "source": "web"
          },
          {
            "id": 11,
            "snippet": "Often, strategic buyers are willing to pay more for companies than financial buyers.\nOne reason is that a strategic buyer is better placed to realize synergistic benefits almost instantly.\nThis is because of the economies of scale that may arise from integrated operations.\nThe more the acquired business fits into the existing company’s structure, the more a strategic buyer will want the business and the higher the premium he will be willing to pay.",
            "title": "Strategic v. Financial Buyer: Tutorial and Video - Noble Desktop Blog",
            "url": "https://blog.nobledesktop.com/learn/financial-modeling/strategic-financial-buyer",
            "date": "2026-04-19",
            "last_updated": "2026-04-21",
            "source": "web"
          },
          {
            "id": 12,
            "snippet": "An acquisition premium is the difference (excess) between the market value of a company and the price paid to acquire it.\nAn acquisition premium represents the increased cost of buying a target company during a merger and acquisition (M&A) transaction.\n...\nNo specific definition exists for acquisition premium, which could reflect the value of both control and synergies.\nOur study is based on all transactions irrespective of the percentage acquired.",
            "title": "An analysis of acquisition premiums in Australia from 2012 to 2022",
            "url": "https://www.findex.com.au/insights/article/acquisition-premium-study-an-analysis-of-acquisition-premiums-in-australia-from-2012-to-2022",
            "date": "2023-03-06",
            "last_updated": "2026-05-19",
            "source": "web"
          },
          {
            "id": 13,
            "snippet": "In the absence of a sufficient control premium, it is unlikely for an acquirer to successfully obtain a majority stake in the target.\nTherefore, a reasonable premium is paid over the current share price in practically all acquisitions.\n**The control premium normally ranges from around 25% to 30%, but it can vary substantially from deal-to-deal and be as high as 50% above the target’s share price.**",
            "title": "Control Premium | Formula + Calculator - Wall Street Prep",
            "url": "https://www.wallstreetprep.com/knowledge/control-premium/",
            "date": "2023-10-12",
            "last_updated": "2026-05-20",
            "source": "web"
          }
        ],
        "type": "search_results",
        "queries": [
          "acquisition premium definition M&A",
          "difference strategic vs financial buyers approach to acquisition premium",
          "determinants of acquisition premium strategic buyers synergies"
        ]
      },
      {
        "id": "msg_96e89ec9-5a54-43d4-a4b7-658166b59734",
        "content": [
          {
            "text": "An acquisition premium is the excess an acquirer pays over the target’s standalone market or fair value—often reflected as goodwill on the acquirer’s balance sheet. [web:1][web:4][web:7][web:12] Strategic buyers usually justify and pay higher premiums due to synergies and strategic fit, while financial buyers are more constrained by return thresholds and typical market valuations. [web:2][web:3][web:5][web:9][web:11]\n\n## What is an acquisition premium?\n\n- An acquisition (or takeover) premium is the difference between the price paid for a target company and its pre‑deal market or fair value. [web:1][web:4][web:7][web:12]  \n- It is typically measured as a percentage over the target’s unaffected share price before the deal is announced and is recorded as **goodwill** (an intangible asset) on the buyer’s balance sheet. [web:1][web:4][web:7][web:10]\n\n## Why do buyers pay a premium?\n\n- Premiums compensate target shareholders for giving up control and future upside; many control transactions show premiums in the ~20–30% range, though this varies by deal. [web:10][web:13]  \n- Buyers pay premiums when they expect value from synergies (cost savings, revenue growth, tax or financing benefits) that makes the combined business worth more than the sum of the parts. [web:3][web:7][web:9]\n\n## Strategic buyers’ approach\n\nStrategic buyers are operating companies acquiring to enhance their existing business.\n\n- They value the target based on strategic synergies: cost savings, cross‑selling, technology or capability gaps, and stronger market position, often leading them to pay a **strategic** or synergy premium. [web:2][web:5][web:6][web:9]  \n- Because they can often realize synergies quickly (economies of scale, overlapping SG&A, better purchasing power), they are frequently willing to pay higher premiums than financial buyers for the same asset. [web:2][web:5][web:8][web:11]\n\n## Financial buyers’ approach\n\nFinancial buyers (e.g., private equity, investment funds) focus on returns from buying, improving, and later exiting the investment.\n\n- They typically value the target on standalone cash flows and metrics such as EBITDA, applying market multiples and disciplined return (IRR/MOIC) hurdles, which limits how much premium they can pay. [web:2][web:5][web:8]  \n- Because they usually cannot realize large operating synergies themselves, they are less inclined to pay high premiums unless there is an exceptional growth or operational improvement story that still meets their return targets. [web:2][web:3][web:5][web:9]\n\n## Typical pattern: who pays more?\n\n- Empirical and practitioner evidence indicates that strategically motivated acquisitions tend to feature higher premiums than financially motivated or purely conglomerate deals, as strategic synergies usually support larger incremental value. [web:3][web:6][web:11]  \n- In competitive auctions, strategic buyers often outbid financial buyers when the asset has strong strategic fit, because the additional synergy value allows them to justify a higher acquisition premium while still creating shareholder value. [web:2][web:5][web:9][web:11]",
            "type": "output_text",
            "annotations": [],
            "logprobs": []
          }
        ],
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "status": "completed",
    "error": null,
    "usage": {
      "input_tokens": 7230,
      "output_tokens": 762,
      "total_tokens": 7992,
      "cost": {
        "currency": "USD",
        "input_cost": 0.00456,
        "output_cost": 0.00762,
        "total_cost": 0.01513,
        "cache_creation_cost": null,
        "cache_read_cost": 0.00045,
        "tool_calls_cost": 0.0025
      },
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 3584,
        "cached_tokens": 3584
      },
      "tool_calls_details": {
        "search_web": {
          "invocation": 1
        }
      },
      "output_tokens_details": {
        "reasoning_tokens": 0
      }
    },
    "background": false,
    "completed_at": 1779391825,
    "frequency_penalty": 0,
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "user": null
  }
  ```
</Accordion>

## API Compatibility

### Standard OpenAI Parameters

These parameters work exactly the same as OpenAI's API:

**Agent API:**

* `model` - Model name (use 3rd party models like `openai/gpt-5.6-sol`)
* `input` - Input text or message array
* `instructions` - System instructions
* `max_output_tokens` - Maximum tokens in response
* `stream` - Enable streaming responses
* `tools` - Array of tools including `web_search`
* `store` - Whether the response is visible through retrieval; see [Conversation state](/docs/agent-api/conversation-state#storage-behavior)
* `previous_response_id` - Continue from a completed prior response; see [Conversation state](/docs/agent-api/conversation-state#resume-from-a-prior-response)

### Perplexity-Specific Parameters

**Agent API:**

* `preset` - Preset name (use Perplexity presets like `low`)
* `tools[].filters` - Search filters within web\_search tool
* `tools[].user_location` - User location for localized results

<Info>
  See [Agent API Reference](/api-reference/agent-post) for complete parameter details.
</Info>

## Endpoint Mapping

| Method                        | Perplexity Endpoint  | OpenAI Equivalent        | Notes                                                         |
| ----------------------------- | -------------------- | ------------------------ | ------------------------------------------------------------- |
| `client.responses.create()`   | `POST /v1/agent`     | `POST /v1/responses`     | Both paths accepted by Perplexity for compatibility           |
| `client.responses.retrieve()` | `GET /v1/agent/{id}` | `GET /v1/responses/{id}` | Both paths accepted by Perplexity for compatibility           |
| `client.models.list()`        | `GET /v1/models`     | `GET /v1/models`         | Lists available Agent API models. No authentication required. |

<Info>
  When using the OpenAI SDK, `client.responses.create()` sends requests to `/v1/responses`. Perplexity accepts this path as an alias for `/v1/agent`, so no SDK configuration changes are needed beyond `base_url`.
</Info>

### Model Discovery

The `GET /v1/models` endpoint returns all models available for the Agent API in OpenAI-compatible format. No authentication is required.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    from openai import OpenAI

    client = OpenAI(
        api_key=os.environ.get("PERPLEXITY_API_KEY"),
        base_url="https://api.perplexity.ai/v1"
    )

    models = client.models.list()
    for model in models.data:
        print(f"{model.id} (owned by {model.owned_by})")
    ```
  </Tab>

  <Tab title="Typescript">
    ```typescript theme={null}
    import OpenAI from 'openai';

    const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai/v1"
    });

    const models = await client.models.list();
    for (const model of models.data) {
      console.log(`${model.id} (owned by ${model.owned_by})`);
    }
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl https://api.perplexity.ai/v1/models \
      -H "Authorization: Bearer $PERPLEXITY_API_KEY"
    ```
  </Tab>
</Tabs>

<Tip>
  This endpoint is compatible with tools like [Open WebUI](https://openwebui.com/), [Cherry Studio](https://cherry-ai.com/), and [LiteLLM](https://litellm.ai/) that auto-discover available models via the OpenAI `/v1/models` endpoint.
</Tip>

## Response Structure

### Agent API

Perplexity's Agent API matches OpenAI's Responses API response format:

* `output` - Structured output array containing messages with `content[].text`
* `model` - The model name used
* `usage` - Token consumption details
* `id`, `created_at`, `status` - Response metadata

## Best Practices

<Steps>
  <Step title="Use the correct base URL">
    Always use `https://api.perplexity.ai/v1` (with `/v1`) for the Agent API.

    ```python theme={null}
    client = OpenAI(
        api_key=os.environ.get("PERPLEXITY_API_KEY"),
        base_url="https://api.perplexity.ai/v1"  # Correct
    )
    ```
  </Step>

  <Step title="Handle errors gracefully">
    Use the OpenAI SDK's error handling:

    ```python theme={null}
    import os
    from openai import OpenAI, APIError, RateLimitError

    client = OpenAI(
        api_key=os.environ.get("PERPLEXITY_API_KEY"),
        base_url="https://api.perplexity.ai/v1"
    )

    try:
        response = client.responses.create(
            model="openai/gpt-5.6-sol",
            input="Hello"
        )
    except RateLimitError:
        print("Rate limit exceeded, please retry later")
    except APIError as e:
        print(f"API error: {e.message}")
    ```
  </Step>

  <Step title="Use streaming for better UX">
    Stream responses for real-time user experience:

    ```python theme={null}
    response = client.responses.create(
        model="openai/gpt-5.6-sol",
        input="Long query...",
        stream=True
    )

    for event in response:
        if event.type == "response.output_text.delta":
            print(event.delta, end="", flush=True)
    ```
  </Step>
</Steps>

## Recommended: Perplexity SDK

We recommend using Perplexity's native SDKs for the best developer experience:

* **Cleaner preset syntax** - Use `preset="low"` directly instead of `extra_body={"preset": "low"}`
* **Type safety** - Full Typescript/Python type definitions for all parameters
* **Enhanced features** - Direct access to all Perplexity-specific features
* **Better error messages** - Perplexity-specific error handling
* **Simpler setup** - No need to configure base URLs

See the [Perplexity SDK Guide](/docs/sdk/overview) for details.

## Migrating to the Perplexity SDK

Switch to the Perplexity SDK for enhanced features and cleaner syntax. With the Perplexity SDK, you can use presets directly without `extra_body` and get full type safety:

<Steps>
  <Step title="Install the Perplexity SDK">
    <Tabs>
      <Tab title="Python">
        ```bash theme={null}
        pip install perplexityai
        ```
      </Tab>

      <Tab title="Typescript">
        ```bash theme={null}
        npm install @perplexity-ai/perplexity_ai
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Update the import and client">
    <Tabs>
      <Tab title="Python">
        ```python theme={null}
        # Before (OpenAI SDK)
        import os
        from openai import OpenAI
        client = OpenAI(
            api_key=os.environ.get("PERPLEXITY_API_KEY"),
            base_url="https://api.perplexity.ai/v1"
        )

        # After (Perplexity SDK)
        from perplexity import Perplexity
        client = Perplexity()  # reads PERPLEXITY_API_KEY env var automatically
        ```
      </Tab>

      <Tab title="Typescript">
        ```typescript theme={null}
        // Before (OpenAI SDK)
        import OpenAI from 'openai';
        const openaiClient = new OpenAI({
          apiKey: process.env.PERPLEXITY_API_KEY,
          baseURL: "https://api.perplexity.ai/v1"
        });

        // After (Perplexity SDK)
        import Perplexity from '@perplexity-ai/perplexity_ai';
        const perplexityClient = new Perplexity();  // reads PERPLEXITY_API_KEY env var automatically
        ```
      </Tab>
    </Tabs>

    <Info>
      **No base URL needed** - The Perplexity SDK automatically uses the correct endpoint.
    </Info>
  </Step>

  <Step title="Update the API calls">
    The API calls are very similar:

    <Tabs>
      <Tab title="Python">
        ```python theme={null}
        # Agent API - same interface
        response = client.responses.create(
            model="openai/gpt-5.6-sol",
            input="Hello!"
        )
        ```
      </Tab>

      <Tab title="Typescript">
        ```typescript theme={null}
        // Agent API - same interface
        const response = await client.responses.create({
          model: "openai/gpt-5-mini",
          input: "Hello!"
        });
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Use presets with cleaner syntax">
    The Perplexity SDK supports presets with cleaner syntax compared to OpenAI SDK:

    <Tabs>
      <Tab title="Python">
        ```python theme={null}
        # Before (OpenAI SDK) - extra_body required
        response = client.responses.create(
            input="What is the difference between an IPO and a direct listing, and why did Coinbase choose a direct listing for its 2021 public debut?",
            extra_body={"preset": "low"}
        )

        # After (Perplexity SDK) - direct parameter
        response = client.responses.create(
            preset="low",
            input="What is the difference between an IPO and a direct listing, and why did Coinbase choose a direct listing for its 2021 public debut?"
        )
        ```
      </Tab>

      <Tab title="Typescript">
        ```typescript theme={null}
        // Before (OpenAI SDK) - type casting required
        const response = await client.responses.create({
          input: "What is the difference between an IPO and a direct listing, and why did Coinbase choose a direct listing for its 2021 public debut?",
          preset: "low"
        } as any);

        // After (Perplexity SDK) - fully typed
        const response = await client.responses.create({
          preset: "low",
          input: "What is the difference between an IPO and a direct listing, and why did Coinbase choose a direct listing for its 2021 public debut?"
        });
        ```
      </Tab>
    </Tabs>

    <Accordion title="Response">
      ```json theme={null}
      {
        "id": "resp_532010e6-2d26-4159-b54b-932e9f553b43",
        "created_at": 1779391925,
        "model": "openai/gpt-5.1",
        "object": "response",
        "output": [
          {
            "results": [
              {
                "id": 1,
                "snippet": "A direct listing allows a company to enter the public market by listing existing shares without issuing new ones.\nUnlike an IPO, there are no underwriters to set the initial share price or facilitate new capital raising.\nInstead, the market determines the share price based on supply and demand.\nDirect listings do not create or sell new shares, meaning no capital is raised through the listing itself.\nThe company avoids hefty underwriter fees, leading to potential cost savings.\nExisting shareholders gain immediate liquidity, as there are no traditional IPO lockup periods.\nPrice discovery is entirely market-driven rather than being set by investment banks.\nThe direct listing process is thorough.\nFirst, the company prepares financial statements and ensures compliance with public company requirements.\nThen, it submits a registration statement to the SEC for direct listings, detailing financial health and risk factors.\nUnlike an IPO, where banks allocate shares, direct listings allow shares to trade freely once listed.\nThe share price is set by market supply and demand rather than pre-determined underwriting.\n...\nIPOs raise new capital through the issuance of additional shares, providing the company with funds for growth, expansion, and operational needs.\nDirect listings, on the other hand, do not raise capital since no new shares are issued.\n...\nChoosing between an IPO and a direct listing depends on a company’s capital needs, market positioning, and strategic goals.\nIPOs provide structured price setting, capital infusion, and investor support but come with higher costs.\nDirect listings offer cost efficiency and liquidity but require market-driven pricing and strong brand recognition.",
                "title": "IPO vs Direct Listing | DFIN",
                "url": "https://www.dfinsolutions.com/knowledge-hub/thought-leadership/knowledge-resources/ipo-vs-direct-listing",
                "date": "2025-02-20",
                "last_updated": "2026-05-11",
                "source": "web"
              },
              {
                "id": 2,
                "snippet": "- The company went public through a direct listing, which means it sold its shares to the public without the usual middlemen, such as investment banks and other underwriters, that typically help with a traditional IPO.\n...\nA direct listing—sometimes called a direct offering—is a way for a company to sell its shares to the public without involving any middle men, or intermediaries.\nIt’s different from an initial public offering (IPO), where the company relies on an investment bank to take it public.\nSuch a bank is called an “underwriter,” because it assumes much of the risk associated with the IPO.\nWith a direct listing, company executives, early investors, and employees who own equity, or shares, are given the option to convert them into a public stock and then sell it to the public through a stock exchange such as the New York Stock Exchange or the Nasdaq.\n(These stakeholders are not obligated to sell their shares, however.)\nWith a direct listing, the stock exchange sets the starting trading price.\nIt’s called an “initial reference price,” and it’s based on new investor demand for the shares.\nIn contrast, the underwriters set what’s known as an “opening price” in a traditional IPO, through a process called a roadshow.",
                "title": "Highlights from Coinbase's IPO - Stash",
                "url": "https://www.stash.com/learn/highlights-from-coinbases-ipo/",
                "date": "2021-04-16",
                "last_updated": "2026-04-08",
                "source": "web"
              },
              {
                "id": 3,
                "snippet": "A private company raises capital by selling newly-issued shares to investment banks (underwriters), which the banks \nthen sell primarily to institutional investors.\n...\nDirect Listing\n...\nA private company becomes public, typically without raising new funds in the process, by allowing existing shareholders \nto sell shares directly to the public.",
                "title": "[PDF] What are the differences in an IPO, a SPAC, and a direct listing?",
                "url": "https://www.sec.gov/files/registered-offerings-building-blocks.pdf",
                "date": null,
                "last_updated": "2024-09-22",
                "source": "web"
              },
              {
                "id": 4,
                "snippet": "Coinbase followed the footsteps of Spotify and Palantir by choosing to go public via a direct listing where existing investors make their shares available for sale to the public, as opposed to a traditional IPO run by investment banks.",
                "title": "Coinbase's IPO - MergerSight",
                "url": "https://www.mergersight.com/post/coinbase-s-ipo",
                "date": "2021-05-06",
                "last_updated": "2026-05-15",
                "source": "web"
              },
              {
                "id": 5,
                "snippet": "**Direct Listing** is the process by which a company goes public by getting listed on an exchange and offering existing shares directly to the open market.\n...\nThe traditional initial public offering (IPO) model has been disrupted by the emergence of direct listings, in which a company starts selling shares directly to the public.\nThe direct listing process is straightforward, as the company’s shares begin trading on an exchange, with no shares pre-negotiated and sold to institutional investors at a designated price.\nCompanies that opt for the direct listing route tend to be already well-funded (i.e. backed by more than enough capital) – therefore, there is no need for these companies to raise further capital through an IPO.\n...\nBut at the end of the day, direct listings and IPOs achieve the same objectives:\n...\n- **Institutional and Retail Investors**→ Equity Ownership Shifts from Insiders (e.g. Management, Employees, Venture Capital Firms, Growth Equity Firms) to the Broader Institutional and Retail Market\n...\nCompanies may choose to go public via a direct listing due to:\n- **Anti-Dilution**– For companies with enough capital and just seeking to get listed, the direct listing route avoids the issuance of new shares (and dilution to existing shareholders)\n- **Immediate Liquidity**– In the traditional IPO, there is a 180-day lock-up period for shareholders before shares can be sold, but in a direct listing, existing shareholders can sell their stake starting on the first day of trading\n- **Supply/Demand Structure**– Rather than establishing a fixed pricing range as done in an IPO, a direct listing resembles an unrestricted auction where the market truly sets the price\nSignificant amounts of money are also saved in a direct listing by not having to pay IPO fees to investment banks – in part due to the shorter, more efficient process.\n...\nThe dilutive impact is kept to a minimum in a direct listing, since no new capital is raised – albeit new regulations have changed the rules regarding new capital raising.\n...\nIn traditional IPOs, the share price is pre-negotiated upon gauging investor appetite before the company goes public.\nBy contrast, direct listings are priced solely on supply and demand on the date of listing – i.e. resulting in an unpredictable reaction and more volatility.",
                "title": "Direct Listing vs. IPO | Difference + Examples - Wall Street Prep",
                "url": "https://www.wallstreetprep.com/knowledge/direct-listing/",
                "date": "2023-10-27",
                "last_updated": "2026-05-20",
                "source": "web"
              },
              {
                "id": 6,
                "snippet": "An Initial Public Offering (IPO) refers to the process by which a private company offers newly issued shares to the public for the first time.\nIn an IPO, the company typically works with one or more underwriters, often investment banks, that assist with pricing, marketing, and distributing shares to investors.\nIPOs generally involve a structured pricing process, where the offering price is set before trading begins based on company financials, market conditions, and investor demand.\nShares are often allocated to institutional investors before becoming available to the broader public once trading starts on a public exchange.\n...\nA Direct Listing allows a company’s existing shares to begin trading on a public exchange without issuing new shares or relying on underwriters in the traditional IPO sense.\nInstead of raising new capital, the primary focus of a Direct Listing is generally on providing liquidity to existing shareholders, such as employees, founders, and early investors.\nIn a Direct Listing, the opening share price is typically determined by market supply and demand rather than being set in advance.\nBecause no new shares are issued, the company generally does not receive proceeds from initial trading activity.\n...\nNot necessarily.\nIPOs and SPAC transactions generally involve raising new capital, while Direct Listings primarily focus on enabling existing shareholders to sell shares without issuing new ones.",
                "title": "Direct Listing vs IPO vs SPAC Paths to the Public Markets...",
                "url": "https://www.startengine.com/blog/direct-listing-vs-ipo-vs-spac",
                "date": "2026-01-28",
                "last_updated": "2026-05-20",
                "source": "web"
              },
              {
                "id": 7,
                "snippet": "This means they simply listed what shares they have instead of issuing new shares via a typical IPO route.\n...\n{ts:157} you may have heard of an initial public offering before or an IPO this is where a company will create and issue new\n{ts:163} shares to the general public at a set price and in doing so raise a ton of cash for its operations however a\n...\n{ts:183} instead coinbase decided to proceed with a direct listing instead of an IPO this is where they simply take all the shares\n{ts:190} that are currently issued and put them on a public Stock Exchange in this case the NASDAQ Stock Exchange Founders and\n{ts:196} early investors can sell their holding and make an exit and new participants can buy shares in speculation that the",
                "title": "The Coinbase Direct Listing Explained - YouTube",
                "url": "https://www.youtube.com/watch?v=IGV-eSpcuck",
                "date": "2021-04-18",
                "last_updated": "2025-10-11",
                "source": "web"
              },
              {
                "id": 8,
                "snippet": "Coinbase, one of the largest cryptocurrency exchanges in the US, has announced plans to go public but it will eschew the traditional initial public offering process, opting instead for a direct listing.\n...\nAs Coinbase opted for a direct listing as opposed to an IPO, retail investors will need to wait for when shares can be publicly bought and sold in order to purchase stocks.",
                "title": "Blending Crypto and Stocks: What Does Coinbase Direct Listing Mean for Crypto Landscape? - Coinspeaker",
                "url": "https://www.coinspeaker.com/coinbase-listing-crypto-landscape/",
                "date": "2021-03-29",
                "last_updated": "2025-06-09",
                "source": "web"
              },
              {
                "id": 9,
                "snippet": "Also called a direct public offering or direct placement, a direct listing allows people who already hold shares to sell them directly.\nIn this model, companies don’t have to deal with (and pay) underwriters.\nIt also lets them avoid creating new shares and diluting ownership.\nThere are no intermediaries involved.^1^\n...\nThe main differences between an IPO and a direct listing include the underwriting process, pricing, and timing.\n...\nIn a direct listing, there are no underwriters involved.\nAn investment bank may provide advice, but it has a limited role.\nShareholders sell their stock directly to the public.^3^\n...\nWith an IPO, existing shares are usually locked up for 180 days.\nThis prevents insiders from selling their shares during this time.\nStocks are typically sold to investment banks initially.\nWith a direct listing, shares can be sold immediately.\nThere’s no lockup period, and existing shareholders have immediate liquidity.^3^\n...\nIPOs are more expensive than direct listings.\nUnderwriters charge a percentage of the gross sales, and there are additional expenses related to roadshows and publicity.",
                "title": "IPO vs Direct Listing: Understanding the Key Differences",
                "url": "https://onlinemba.ku.edu/experience-ku/mba-blog/ipo-vs-direct-listing",
                "date": "2024-12-11",
                "last_updated": "2026-03-16",
                "source": "web"
              },
              {
                "id": 10,
                "snippet": "The event was notable for several reasons: Coinbase, with 56 million registered users, became the first crypto company to list on a US stock exchange; it was also Nasdaq’s first major direct listing.\nThe firm sidestepped a typical IPO and the increasingly popular special purpose acquisition company (SPAC) as routes to the public.\nAs CEO Brian Armstrong told CNBC, “I wanted there to be just a true market on day one that set the price, not something that was set behind closed doors.”\nThe direct listing, which provides greater accessibility to retail investors, is also more “true to the [democratic] ethos of crypto,” he added.",
                "title": "Coinbase Direct Listing Steadies Crypto Industry",
                "url": "https://gfmag.com/features/coinbase-direct-listing-steadies-crypto-industry/",
                "date": "2021-05-05",
                "last_updated": "2025-10-29",
                "source": "web"
              },
              {
                "id": 11,
                "snippet": "A direct listing differs from an IPO in that a company lists its existing stock without hiring underwriters to \nsell new shares and raise fresh money.\n...\nDirect listings can also save companies on underwriting fees.\nRather than hire investment banks to \nmarket and price new shares, companies conducting direct listings hire financial advisers, who play a\nmore limited role of linking buyers and sellers of existing stock at agreed prices.",
                "title": "Coinbase's Public Listing Plans Shine Spotlight On Crypto",
                "url": "https://www.crowell.com/a/web/bUWLyhYZmLFmezj8hyV5QX/4Ttk1y/20210129-coinbases-public-listing-plans-shine-spotlight-on-crypto.pdf",
                "date": null,
                "last_updated": "2025-03-26",
                "source": "web"
              }
            ],
            "type": "search_results",
            "queries": [
              "IPO vs direct listing differences",
              "Coinbase direct listing 2021 reasons",
              "Coinbase why chose direct listing over IPO 2021"
            ]
          },
          {
            "id": "msg_0d1729b8-2a0e-47a4-97c1-b113b65f80db",
            "content": [
              {
                "text": "An IPO issues new shares through underwriters to raise capital at a predetermined offering price, while a direct listing simply lists existing shares for trading without raising new money or using traditional underwriters, letting the market set the price. [web:1][web:3][web:5] Coinbase chose a direct listing in 2021 because it did not need to raise capital, wanted market-driven price discovery aligned with crypto’s open-market ethos, and could save on IPO fees while giving existing shareholders immediate liquidity. [web:4][web:5][web:10][web:11]  \n\n## IPO vs direct listing  \n\n- In an **IPO**, a company typically sells newly issued shares to the public through investment banks that act as underwriters, which help set the offer price, market the deal, and allocate shares, and the company receives new capital from the proceeds. [web:3][web:6]  \n- In a **direct listing**, the company usually does not issue new shares; instead, existing shareholders (founders, employees, early investors) sell their shares directly on the exchange, and the company generally does not raise new funds in the process. [web:1][web:3][web:5][web:6]  \n\n- IPOs use underwriters who build a book of demand and set an offering price before trading begins, creating a more controlled pricing process. [web:1][web:5][web:6][web:9]  \n- Direct listings do not have traditional underwriting; the opening trading price is set by supply and demand on the exchange (often via a reference price) and can be more volatile and unpredictable. [web:1][web:2][web:5][web:6]  \n\n- IPOs are typically more expensive because underwriters charge a percentage of the offering and there are costs for roadshows and marketing. [web:1][web:5][web:9][web:11]  \n- Direct listings tend to be cheaper because there are no underwriting fees and banks act only as financial advisers with a more limited role. [web:1][web:5][web:9][web:11]  \n\n- In many IPOs, insiders face a lockup period (often around 180 days) before they can sell shares, limiting immediate liquidity. [web:1][web:6][web:9]  \n- In a direct listing, there is typically no lockup, so existing shareholders can sell on day one, providing immediate liquidity. [web:1][web:5][web:6][web:9]  \n\n## Why Coinbase chose direct listing  \n\n- Coinbase was already well funded and did not need to raise additional capital, which made a direct listing attractive since that mechanism focuses on listing and liquidity rather than fundraising. [web:4][web:5][web:11]  \n- A direct listing avoided dilution from issuing new shares, which helped preserve ownership percentages for existing investors and employees. [web:5][web:6][web:11]  \n\n- CEO Brian Armstrong stated that he wanted “a true market on day one” with a price set in the open market rather than “behind closed doors,” so a direct listing’s market-driven pricing fit this goal. [web:10]  \n- This approach was described as more in line with the **democratic** and open ethos of crypto markets, reinforcing Coinbase’s brand positioning in the digital-asset space. [web:10]  \n\n- By choosing a direct listing, Coinbase could save substantial underwriting fees compared with a traditional IPO while still achieving a major listing on Nasdaq. [web:5][web:11]  \n- The structure also gave early investors and employees immediate liquidity on listing day, which is a common reason high-profile tech and fintech firms such as Spotify and Palantir have used direct listings. [web:4][web:5]",
                "type": "output_text",
                "annotations": [],
                "logprobs": []
              }
            ],
            "role": "assistant",
            "status": "completed",
            "type": "message"
          }
        ],
        "status": "completed",
        "error": null,
        "usage": {
          "input_tokens": 6821,
          "output_tokens": 852,
          "total_tokens": 7673,
          "cost": {
            "currency": "USD",
            "input_cost": 0.00405,
            "output_cost": 0.00852,
            "total_cost": 0.01552,
            "cache_creation_cost": null,
            "cache_read_cost": 0.00045,
            "tool_calls_cost": 0.0025
          },
          "input_tokens_details": {
            "cache_creation_input_tokens": 0,
            "cache_read_input_tokens": 3584,
            "cached_tokens": 3584
          },
          "tool_calls_details": {
            "search_web": {
              "invocation": 1
            }
          },
          "output_tokens_details": {
            "reasoning_tokens": 0
          }
        },
        "background": false,
        "completed_at": 1779391925,
        "frequency_penalty": 0,
        "incomplete_details": null,
        "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
        "max_output_tokens": 8192,
        "max_tool_calls": null,
        "metadata": {},
        "parallel_tool_calls": true,
        "presence_penalty": 0,
        "previous_response_id": null,
        "prompt_cache_key": null,
        "reasoning": null,
        "safety_identifier": null,
        "service_tier": "default",
        "store": true,
        "temperature": 1,
        "text": {
          "format": {
            "type": "text"
          }
        },
        "tool_choice": "auto",
        "tools": [
          {
            "type": "web_search"
          },
          {
            "type": "fetch_url"
          }
        ],
        "top_logprobs": 0,
        "top_p": 1,
        "truncation": "disabled",
        "user": null
      }
      ```
    </Accordion>
  </Step>
</Steps>

## Next Steps

<CardGroup>
  <Card title="Agent API Quickstart" icon="rocket" href="/docs/agent-api/quickstart">
    Get started with Agent API using OpenAI SDKs.
  </Card>

  <Card title="Agent API Models" icon="brain" href="/docs/agent-api/models">
    Explore direct model selection and third-party models.
  </Card>

  <Card title="Conversation State" icon="messages" href="/docs/agent-api/conversation-state">
    Continue a conversation with `previous_response_id` or replay turns yourself.
  </Card>

  <Card title="API Reference" icon="code-circle" href="/api-reference/agent-post">
    View complete endpoint documentation.
  </Card>

  <Card title="Output Control" icon="indent-decrease" href="/docs/agent-api/output-control">
    Configure streaming responses and structured outputs with JSON schema.
  </Card>

  <Card title="Model Fallback" icon="square-rounded-arrow-down" href="/docs/agent-api/model-fallback">
    Specify multiple models for automatic failover and higher availability.
  </Card>

  <Card title="Filters" icon="filter" href="/docs/agent-api/tools/web-search#filters">
    Apply filters to web search results.
  </Card>
</CardGroup>


# Output Control
Source: https://docs.perplexity.ai/docs/agent-api/output-control

Streaming and structured outputs for the Agent API

## Streaming Responses

Streaming allows you to receive partial responses from the Perplexity API as they are generated, rather than waiting for the complete response. This is particularly useful for real-time user experiences, long responses, and interactive applications.

<Info>
  Streaming is supported across all models available through the Agent API.
</Info>

To enable streaming, set `stream=True` (Python) or `stream: true` (TypeScript) when creating responses:

<CodeGroup>
  ```python Python SDK theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Create streaming response
  stream = client.responses.create(
      preset="fast",
      input="Explain what a model card is in the context of large language models: the typical sections (intended use, training data, limitations, evaluation).",
      stream=True
  )

  # Process streaming response
  for event in stream:
      if event.type == "response.output_text.delta":
          print(event.delta, end="")
      elif event.type == "response.completed":
          print(f"\n\nCompleted: {event.response.usage}")
  ```

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

  const client = new Perplexity();

  // Create streaming response
  const stream = await client.responses.create({
    preset: "fast",
    input: "Explain what a model card is in the context of large language models: the typical sections (intended use, training data, limitations, evaluation).",
    stream: true
  });

  // Process streaming response
  for await (const chunk of stream) {
    if (chunk.type === "response.output_text.delta") {
      process.stdout.write((chunk as any).delta);
    }
  }
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.perplexity.ai/v1/agent" \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "preset": "fast",
      "input": "Explain what a model card is in the context of large language models: the typical sections (intended use, training data, limitations, evaluation).",
      "stream": true
    }'
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_081e7a0a-4087-403b-8e74-a997d28d6fd2",
    "created_at": 1779391825,
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "results": [
          {
            "id": 1,
            "snippet": "Organizations developing and deploying AI, specifically generative AI, have turned to model cards as one way to promote explainability and achieve that transparency.\n...\nFirst proposed in 2018, model cards are short documents provided with machine learning models that explain the context in which the models are intended to be used, details of the performance evaluation procedures and other relevant information.\nA machine learning model intended to evaluate voter demographics, for example, would be released with a model card providing performance metrics across conditions like culture, race, geographic location, sex and intersectional groups that are relevant to the intended application.\n...\nMost importantly, for the current uses of and innovations in AI, model cards provide details about the construction of the machine learning model, like its architecture and training data.\n...\nSimilarly, the transparency principle in AI governs the extent to which information regarding an AI system is made available to stakeholders, including an understandable explanation of how the system works.\nThis is precisely what model cards do: explain information in the machine learning model to provide transparency into the AI system.\n...\nModel cards are the current tool of choice in providing transparency in large language and machine learning models.",
            "title": "5 things to know about AI model cards | IAPP",
            "url": "https://iapp.org/news/a/5-things-to-know-about-ai-model-cards",
            "date": "2023-08-23",
            "last_updated": "2026-05-16",
            "source": "web"
          },
          {
            "id": 2,
            "snippet": "The term “Model Card” was coined by Mitchell et al. in the 2018 paper Model Cards for Model Reporting.\nAt their core, Model Cards are the nutrition labels of the AI world, providing instructions and warnings for a trained model.\nWhen used, they can inform users about the uses and limitations of a model and support audit and transparency requirements.",
            "title": "Towards a Standard for Model Cards - Trustible",
            "url": "https://trustible.ai/post/towards-a-standard-for-model-cards/",
            "date": "2023-05-05",
            "last_updated": "2026-05-20",
            "source": "web"
          },
          {
            "id": 3,
            "snippet": "This work proposes model cards, a framework that can be used to document any trained machine learning model in the application fields of computer vision and natural language processing, and provides cards for two supervised models: One trained to detect smiling faces in images, and one training to detect toxic comments in text.",
            "title": "[PDF] Model Cards for Model Reporting - Semantic Scholar",
            "url": "https://www.semanticscholar.org/paper/Model-Cards-for-Model-Reporting-Mitchell-Wu/7365f887c938ca21a6adbef08b5a520ebbd4638f",
            "date": null,
            "last_updated": "2024-07-27",
            "source": "web"
          },
          {
            "id": 4,
            "snippet": "A model card is a type of documentation that is created for, and provided with, machine learning models.\nA model card functions as a type of data sheet, similar in principle to the consumer safety labels, food nutritional labels, a material safety data sheet or product spec sheets.\n...\nFirst proposed by Google in 2018, the model card is a means of documenting vital elements of a ML model so users -- including AI designers, business leaders and ML end users -- can readily understand the intended use cases, characteristics, behaviors, ethical considerations, and the biases and limitations of a particular ML model.",
            "title": "What is a model card in machine learning and what is its purpose?",
            "url": "https://www.techtarget.com/whatis/definition/model-card-in-machine-learning",
            "date": "2024-03-25",
            "last_updated": "2026-05-18",
            "source": "web"
          },
          {
            "id": 5,
            "snippet": "Model Cards are a powerful tool that promotes transparency, accountability, and regulatory compliance in Machine Learning & AI development.\n...\n{ts:43} data scientists so let's start with the basics what are model cards they're well described by this research paper model\n{ts:50} cards for model reporting they're a standardized way to document essential information about machine learning\n{ts:57} models providing insights into how a model Works its intended use its performance metrics ethical\n{ts:65} considerations and other things this section of the paper outlines exactly what goes into a model card and the\n{ts:71} things you need to think about for each section such as the model details like the date it was created what type of\n{ts:77} model it is if it has a license the intended use of that model metric such as its performance or decision\n...\n{ts:214} predictions secondly model cards support accountability in the way that these models were trained evaluated and are\n{ts:222} being used in production when issues or biases arise model cards can pinpoint the source of the problem and help guide\n{ts:229} improvements they're essential for responsible machine learning development lastly model cards can be used for\n…",
            "title": "Model Cards for Model Reporting - YouTube",
            "url": "https://www.youtube.com/watch?v=saAUB_MG2d0",
            "date": "2024-02-13",
            "last_updated": "2025-11-18",
            "source": "web"
          },
          {
            "id": 6,
            "snippet": "#### Simple, structured overviews of how an advanced AI model was designed and evaluated.",
            "title": "Model cards - Google DeepMind",
            "url": "https://deepmind.google/models/model-cards/",
            "date": null,
            "last_updated": "2026-05-20",
            "source": "web"
          },
          {
            "id": 7,
            "snippet": "The original framework specified: model details, intended use, factors (relevant demographic or contextual factors), metrics, evaluation data, training data, quantitative analyses, ethical considerations, and caveats and recommendations.\nIn practice, model cards from the major AI labs have evolved beyond this template, but the core purpose remains: honest documentation of a model’s capabilities, limitations, and appropriate use cases, written by the people who know the model best.\n...\nFor every AI deployment at your company, one person should read the model card.\nCompletely.\nNot skimming.\nNot the executive summary.\nThe full document.\nThat person should translate the model card’s technical assessments into three operational documents:\n**A capability assessment** that states, in plain language, what the model can and cannot do for your specific use case, based on the model card’s benchmarks and limitations.\n**A risk register** that maps the model card’s safety evaluations and known limitations to your specific deployment context, identifying which risks are relevant, which mitigations are needed, and which residual risks must be accepted.\n**A monitoring plan** that specifies how you will verify, in production, that the model’s actual performance matches the model card’s documented performance — because models can degrade, use cases can drift, and the only check on the model card’s claims is your own observation.",
            "title": "The Model Card Nobody Reads — Bluewaves Boutique",
            "url": "https://bluewaves.boutique/notes/the-model-card-nobody-reads/",
            "date": "2025-12-23",
            "last_updated": "2026-04-08",
            "source": "web"
          },
          {
            "id": 8,
            "snippet": "This is the paper that started it all.\nMargaret Mitchell and her team at Google Research introduced model cards as a practical solution to the black box problem in machine learning.\nDrawing inspiration from electronics datasheets and nutrition labels, this foundational research presents a standardized framework for documenting ML models that goes far beyond technical specifications.\nThe paper doesn't just propose an abstract concept—it demonstrates model cards in action with real examples from Google's own models, showing how transparent documentation can reveal performance disparities across demographic groups and highlight ethical considerations that might otherwise remain hidden.\n...\nModel cards fill this gap by providing a standardized format that makes critical information accessible to both technical and non-technical stakeholders.",
            "title": "Model Cards for Model Reporting | KI-Governance-Bibliothek",
            "url": "https://verifywise.ai/de/ai-governance-library/transparency-and-documentation/model-cards-paper",
            "date": "2019-01-01",
            "last_updated": "2026-04-01",
            "source": "web"
          },
          {
            "id": 9,
            "snippet": "In this paper, we propose a framework that\nwe call model cards, to encourage such transparent model reporting.\nModel cards are short documents accompanying trained machine\nlearning models that provide benchmarked evaluation in a variety\nof conditions, such as across different cultural, demographic, or phe-\nnotypic groups (e.g., race, geographic location, sex, Fitzpatrick skin\ntype [15]) and intersectional groups (e.g., age and race, or sex and\nFitzpatrick skin type) that are relevant to the intended application\ndomains.\nModel cards also disclose the context in which models\nare intended to be used, details of the performance evaluation pro-\ncedures, and other relevant information.\nWhile we focus primarily\non human-centered machine learning models in the application\nfields of computer vision and natural language processing, this\nframework can be used to document any trained machine learning\nmodel.\n...\nAs a step towards this goal, we propose that released machine\nlearning models be accompanied by short (one to two page) records\nwe call model cards.\nModel cards (for model reporting) are com-\n...\nfocus on trained model characteristics such as the type of model,\nintended use cases, information about attributes for which model\nperformance may vary, and measures of model performance.\n...\nIn addition to model evaluation results, model\ncards should detail the motivation behind chosen performance\nmetrics, group definitions, and other relevant factors.\n...\nModel cards provide a\n...\n4\nMODEL CARD SECTIONS\nModel cards serve to disclose information about a trained machine\nlearning model.\nThis includes how it was built, what assumptions\nwere made during its development, what type of model behavior\ndifferent cultural, demographic, or phenotypic population groups\nmay experience, and an evaluation of how well the model performs\nwith respect to those groups.\n...\n– Relevant factors\n– Evaluation factors\n• Metrics.\nMetrics should be chosen to reflect potential real-\nworld impacts of the model.\n– Model performance measures\n– Decision thresholds\n– Variation approaches\n• Evaluation Data.\nDetails on the dataset(s) used for the\nquantitative analyses in the card.",
            "title": "[PDF] Model Cards for Model Reporting - arXiv",
            "url": "https://arxiv.org/pdf/1810.03993",
            "date": null,
            "last_updated": "2026-05-19",
            "source": "web"
          },
          {
            "id": 10,
            "snippet": "Model cards provides a standardized structure for conveying key information about AI models.\nGrounded in academic literature [7] and official guidelines from Hugging Face [17], model cards conventionally comprise sections such as Training, Evaluation, Uses, Limitations, Environmental Impact, Citation, and How to Start.\nAs illustrated in Fig. 1d, these sections represent the essential constituents of a comprehensive model card.\n...\nFurthermore, model cards also have the potential to assist in regulatory compliance by offering a structured framework for documenting and communicating key information about a model’s performance, training, and evaluation process [9, 6, 60, 61].\n...\nThe structure of model cards plays a crucial role in conveying key information.\nDrawing from academic literature [7] and Hugging Face’s official guidelines, model cards typically include sections such as Training, Evaluation, Uses, Limitations, Environmental Impact, Citation, and How to Start.",
            "title": "What's documented in AI? Systematic Analysis of 32K AI Model Cards",
            "url": "https://arxiv.org/html/2402.05160v1",
            "date": "2020-08-27",
            "last_updated": "2026-02-18",
            "source": "web"
          },
          {
            "id": 11,
            "snippet": "In this paper, we propose a framework that Fairness, Accountability, and Transparency, January 29–31, 2019, Atlanta, GA, we call model cards, to encourage such transparent model reporting.\n…\nModel cards are short documents accompanying trained machine 3287596 learning models that provide benchmarked evaluation in a variety of conditions, such as across different cultural, demographic, or phe- 1 INTRODUCTION notypic groups (e.g., race, geographic location, sex, Fitzpatrick skin Currently, there are no standardized documentation procedures to type [15]) and intersectional groups (e.g., age and race, or sex and communicate the performance characteristics of trained machine Fitzpatrick skin type) that are relevant to the intended application learning (ML) and artificial intelligence (AI) models.\n...\nModel cards also disclose the context in which models documentation is especially problematic when models are used in are intended to be used, details of the performance evaluation pro- applications that have serious impacts on people’s lives, such as in cedures, and other relevant information.\n...\nAs a step towards this goal, we propose that released machine learning models be accompanied by short (one to two page) records Permission to make digital or hard copies of all or part of this work for personal or we call model cards.\n...\n• Quantitative Analyses – Unitary results4 MODEL CARD SECTIONS – Intersectional resultsModel cards serve to disclose information about a trained machine • Ethical Considerationslearning model.\nThis includes how it was built, what assumptions • Caveats and Recommendationswere made during its development, what type of model behaviordifferent cultural, demographic, or phenotypic population groups Figure 1: Summary of model card sections and suggestedmay experience, and an evaluation of how well the model performs prompts for each.with respect to those groups.\n...\nModel cards include information about the contextin the previous sections.",
            "title": "Model Cards For Model Reporting | PDF | Machine Learning - Scribd",
            "url": "https://www.scribd.com/document/588702829/1810-03993",
            "date": "2025-09-06",
            "last_updated": "2026-01-19",
            "source": "web"
          }
        ],
        "type": "search_results",
        "queries": [
          "model card definition machine learning",
          "model card intended use limitations evaluation",
          "Mitchell model cards paper 2019"
        ]
      },
      {
        "id": "msg_41254287-8054-4973-a3a4-7e5fb617eea4",
        "content": [
          {
            "text": "A model card is a short, structured document that accompanies a trained machine‑learning or large language model and explains how it was built, how it performs, where it should and should not be used, and known risks or limitations.[web:4][web:9][web:10] It plays a similar role to a product spec sheet or nutrition label, but for AI systems.[web:2][web:4]\n\n## What a model card is\n\n- A **model** card is documentation shipped with an AI model that summarizes key technical, ethical, and practical details in a human-readable way.[web:4][web:9]  \n- It is meant for both technical and non‑technical stakeholders, so they can understand intended use cases, behavior, and trade‑offs of the model before deployment.[web:2][web:4][web:8]\n\n## Typical sections: high level\n\nMany templates exist, but most modern model cards for LLMs include recurring sections.[web:7][web:9][web:10]\n\n- Model details (name, version, developer, architecture, date, license).[web:7][web:9]  \n- Uses/intended use and out‑of‑scope uses.[web:4][web:9][web:10]  \n- Training and data sources.[web:9][web:10]  \n- Evaluation setup and metrics.[web:1][web:9][web:10]  \n- Limitations, biases, and ethical considerations.[web:2][web:7][web:9]  \n- Caveats, recommendations, and how to get started (API, examples).[web:7][web:9][web:10]\n\nFor your question, the four core sections are usually: intended use, training data, limitations, and evaluation.[web:9][web:10]\n\n## Intended use section\n\nThis section defines where the model is appropriate and where it is not.[web:2][web:4][web:9]\n\nTypical contents:\n\n- **Intended users and domains**: For example, “researchers and engineers building conversational assistants” or “classification of English news text.”[web:4][web:9]  \n- Supported use cases: Tasks like code generation, summarization, or translation that the model is designed and tested for.[web:1][web:6][web:10]  \n- Out‑of‑scope use: Explicit warnings against high‑risk contexts such as medical diagnosis, legal advice, biometric identification, or automated decision‑making without human review.[web:4][web:7][web:9]\n\nFor large language models, this section helps prevent over‑reliance on the model in safety‑critical or highly regulated settings.[web:1][web:4]\n\n## Training data section\n\nThis section describes what data the model learned from, usually at an aggregate level rather than listing every dataset.[web:9][web:10]\n\nTypical contents:\n\n- **Data sources and types**: High‑level description of web text, code repositories, books, forums, or proprietary corpora used.[web:9][web:10]  \n- Temporal and language coverage: Time span of data collection, languages included, and major domains (e.g., news vs. social media).[web:9][web:10]  \n- Preprocessing and filtering: How data was cleaned, deduplicated, or filtered for safety, hate speech, or personal information.[web:9][web:10]  \n- Known gaps or biases in data: For example, over‑representation of English or certain regions, and under‑representation of minority languages or dialects.[web:8][web:9]\n\nFor LLMs, training data descriptions are crucial to interpret why a model is strong in some languages or topics and weak in others.[web:8][web:10]\n\n## Limitations section\n\nThis section explicitly states what the model cannot reliably do and known failure modes.[web:2][web:7][web:9]\n\nTypical contents:\n\n- **Capability limits**: Issues like hallucinations (fabricated facts), poor reasoning on long chains, weak performance on low‑resource languages, or lack of up‑to‑date knowledge beyond a cutoff date.[web:7][web:9][web:10]  \n- Safety and bias concerns: Propensity to reproduce harmful stereotypes, toxic or unsafe content, or unfair performance across demographic groups.[web:1][web:8][web:9]  \n- Operational limits: Maximum context length, latency considerations, and scenarios where performance degrades (noisy input, adversarial prompts).[web:6][web:10]  \n- Dependency on user behavior: Notes that the model is sensitive to prompt phrasing and may be misused through prompt engineering.[web:7][web:9]\n\nThis section usually pairs limitations with recommendations such as human review, domain‑specific fine‑tuning, or additional guardrails.[web:7][web:9]\n\n## Evaluation section\n\nThe evaluation section documents how performance was measured and what the results were.[web:1][web:9][web:10]\n\nTypical contents:\n\n- **Benchmarks and tasks**: Lists of datasets or benchmark suites, such as question‑answering, reasoning, coding, or toxicity detection tests for LLMs.[web:1][web:9][web:10]  \n- Metrics: Accuracy, F1, BLEU, perplexity, safety scores, robustness metrics, or human evaluation ratings, chosen to reflect real‑world impact.[web:1][web:9][web:10]  \n- Conditions and subgroups: Performance broken down by language, topic domain, demographic attributes, or other relevant factors to reveal disparities.[web:1][web:8][web:9]  \n- Evaluation procedure: How data was split, decision thresholds, and any notable experimental assumptions.[web:9][web:11]\n\nFor large language models, this section often includes both capability benchmarks (e.g., reasoning and coding tests) and safety evaluations (e.g., red‑teaming or harmful content benchmarks).[web:1][web:6][web:10]",
            "type": "output_text",
            "annotations": [],
            "logprobs": []
          }
        ],
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "status": "completed",
    "error": null,
    "usage": {
      "input_tokens": 6852,
      "output_tokens": 1316,
      "total_tokens": 8168,
      "cost": {
        "currency": "USD",
        "input_cost": 0.00409,
        "output_cost": 0.01316,
        "total_cost": 0.0202,
        "cache_creation_cost": null,
        "cache_read_cost": 0.00045,
        "tool_calls_cost": 0.0025
      },
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 3584,
        "cached_tokens": 3584
      },
      "tool_calls_details": {
        "search_web": {
          "invocation": 1
        }
      },
      "output_tokens_details": {
        "reasoning_tokens": 0
      }
    },
    "background": false,
    "completed_at": 1779391825,
    "frequency_penalty": 0,
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "user": null
  }
  ```
</Accordion>

### Error Handling

Handle errors gracefully during streaming:

<CodeGroup>
  ```python Python SDK theme={null}
  import perplexity
  from perplexity import Perplexity

  client = Perplexity()

  try:
      stream = client.responses.create(
          preset="fast",
          input="What is the FOMC, how often does it meet, and what tools (federal funds rate, balance sheet) does it use to influence the economy?",
          stream=True
      )
      
      for event in stream:
          if event.type == "response.output_text.delta":
              print(event.delta, end="")
          elif event.type == "response.completed":
              print(f"\n\nCompleted: {event.response.usage}")
              
  except perplexity.APIConnectionError as e:
      print(f"Network connection failed: {e}")
  except perplexity.RateLimitError as e:
      print(f"Rate limit exceeded, please retry later: {e}")
  except perplexity.APIStatusError as e:
      print(f"API error {e.status_code}: {e.response}")
  ```

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

  const client = new Perplexity();

  try {
    const stream = await client.responses.create({
      preset: "fast",
      input: "What is the FOMC, how often does it meet, and what tools (federal funds rate, balance sheet) does it use to influence the economy?",
      stream: true
    });

    for await (const chunk of stream) {
      if (chunk.type === "response.output_text.delta") {
        process.stdout.write((chunk as any).delta);
      }
    }
  } catch (error) {
    if (error instanceof Perplexity.APIConnectionError) {
      console.error("Network connection failed:", (error as any).cause);
    } else if (error instanceof Perplexity.RateLimitError) {
      console.error("Rate limit exceeded, please retry later");
    } else if (error instanceof Perplexity.APIError) {
      console.error(`API error ${error.status}: ${error.message}`);
    }
  }
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_bc5efb99-19ca-4185-87fa-890f2276edd7",
    "created_at": 1779391925,
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "results": [
          {
            "id": 1,
            "snippet": "The Federal Reserve controls the three tools of monetary policy--open market operations, the discount rate, and reserve requirements.\nThe Board of Governors of the Federal Reserve System is responsible for the discount rate and reserve requirements, and the Federal Open Market Committee is responsible for open market operations.\n...\n#### Structure of the FOMCurThe Federal Open Market Committee (FOMC) consists of twelve members--the seven members of the Board of Governors of the Federal Reserve System; the president of the Federal Reserve Bank of New York; and four of the remaining eleven Reserve Bank presidents, who serve one-year terms on a rotating basis.\nThe rotating seats are filled from the following four groups of Banks, one Bank president from each group: Boston, Philadelphia, and Richmond; Cleveland and Chicago; Atlanta, St.\nLouis, and Dallas; and Minneapolis, Kansas City, and San Francisco.\nNonvoting Reserve Bank presidents attend the meetings of the Committee, participate in the discussions, and contribute to the Committee's assessment of the economy and policy options.\nThe FOMC holds eight regularly scheduled meetings per year.\nAt these meetings, the Committee reviews economic and financial conditions, determines the appropriate stance of monetary policy, and assesses the risks to its long-run goals of price stability and sustainable economic growth.",
            "title": "The Fed - Federal Open Market Committee",
            "url": "https://www.federalreserve.gov/monetarypolicy/fomc.htm",
            "date": "2026-04-29",
            "last_updated": "2026-05-12",
            "source": "web"
          },
          {
            "id": 2,
            "snippet": "What does “FOMC” stand for?\nThe Federal Open Market Committee, or FOMC, is the Fed’s chief body for monetary policy.\nIts voting membership combines the seven members of the Board of Governors, the president of the Federal Reserve Bank of New York, and four other Reserve Bank presidents, who serve one-year terms on a rotating basis with the other Reserve Bank presidents.\nAll Reserve Bank presidents attend FOMC meetings, even when they are not designated voting members.\nBy tradition, the Chair of the FOMC is also the Chair of the Board of Governors.\nThe president of the Federal Reserve Bank of New York and members of the Board of Governors are permanent voting members.\nMost Reserve Bank presidents serve one-year terms on a three-year rotating schedule; the presidents of the Cleveland and Chicago Feds serve on a two-year rotating schedule.\n...\n## How Often the FOMC MeetsC The FOMC typically meets eight times a year in the Board Room at the Eccles Building in Washington, D.C., but when necessary, members will meet by a teleconference.\nIf economic conditions require additional meetings, the FOMC can and does meet more often.\n...\nArmed with this wealth of up-to-date national, international, and regional information, the FOMC discusses the monetary policy options that would best move the economy toward the “dual mandate” objectives given to the Fed by Congress: maximum employment and price stability.\nThe FOMC meeting concludes with a decision on the stance of policy.",
            "title": "Introduction to the FOMC (Federal Open Market Committee)",
            "url": "https://www.stlouisfed.org/in-plain-english/introduction-to-the-fomc",
            "date": null,
            "last_updated": "2026-05-12",
            "source": "web"
          },
          {
            "id": 3,
            "snippet": "The Federal Open Market Committee (FOMC) is the monetary policymaking body of the Federal Reserve System.\nThe FOMC is composed of 12 members--the seven members of the Board of Governors and five of the 12 Reserve Bank presidents.\nThe Board chair serves as the Chair of the FOMC; the president of the Federal Reserve Bank of New York is a permanent member of the Committee and serves as the Vice Chair of the Committee.\nThe presidents of the other Reserve Banks fill the remaining four voting positions on the FOMC on a rotating basis.\nAll of the Reserve Bank presidents, including those who are not voting members, attend FOMC meetings, participate in the discussions, and contribute to the assessment of the economy and policy options.\n...\nThe FOMC schedules eight meetings per year, one about every six weeks or so.\nThe Committee may also hold unscheduled meetings as necessary to review economic and financial developments.\nThe FOMC issues a policy statement following each regular meeting that summarizes the Committee's economic outlook and the policy decision at that meeting.\n...\nBy law, the Federal Reserve conducts monetary policy to achieve its macroeconomic objectives of maximum employment and stable prices.\nUsually, the FOMC conducts policy by adjusting the level of short-term interest rates in response to changes in the economic outlook.\nSince 2008, the FOMC has also used large-scale purchases of Treasury securities and securities that were issued or guaranteed by federal agencies as a policy tool in an effort to lower longer-term interest rates and thereby improve financial conditions and so support the economic recovery.",
            "title": "What is the FOMC and when does it meet? - Federal Reserve",
            "url": "https://www.federalreserve.gov/faqs/about_12844.htm",
            "date": "2019-01-30",
            "last_updated": "2026-03-30",
            "source": "web"
          },
          {
            "id": 4,
            "snippet": "The **Federal Open Market Committee** (**FOMC**) is a committee within the Federal Reserve System (colloquially \"the Fed\") that is charged under United States law with overseeing the nation's open market operations (e.g., the Fed's buying and selling of United States Treasury securities).\nThis Federal Reserve committee makes key decisions about interest rates and the growth of the United States money supply.\n...\nThe FOMC is the principal organ of United States national monetary policy.\nThe committee sets monetary policy by specifying the short-term objective for the Fed's open market operations, which is usually a target level for the federal funds rate (the rate that commercial banks charge between themselves for overnight loans).\nThe FOMC also directs operations undertaken by the Federal Reserve System in foreign exchange markets, although any intervention in foreign exchange markets is coordinated with the U.S. Treasury, which has responsibility for formulating U.S. policies regarding the exchange value of the dollar.\n...\nThe committee consists of the seven members of the Federal Reserve Board, the president of the New York Fed, and four of the other eleven regional Federal Reserve Bank presidents, serving one-year terms.\nThe chair of the Federal Reserve has been invariably appointed by the committee as its chair since 1935, solidifying the perception of the two roles as one.\nThe Federal Open Market Committee was formed by the Banking Act of 1933 (codified at 12 U.S.C.\n§ 263) and did not include voting rights for the Federal Reserve Board of Governors.\nThe Banking Act of 1935 revised these protocols to include the Board of Governors and to closely resemble the present-day FOMC and was amended in 1942 to give the current structure of twelve voting members.\n...\nAll of the Reserve Bank presidents, even those who are not currently voting members of the FOMC, attend committee meetings, participate in discussions, and contribute to the committee's assessment of the economy and policy options.\nThe committee meets eight times a year, approximately once every six weeks.\n...\nBy law, the FOMC must meet at least four times each year in Washington, D.C. Since 1981, eight regularly scheduled meetings have been held each year at intervals of five to eight weeks.",
            "title": "Federal Open Market Committee - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/Federal_Open_Market_Committee",
            "date": "2004-04-13",
            "last_updated": "2026-03-31",
            "source": "web"
          },
          {
            "id": 5,
            "snippet": "\"The committee meets eight times a year, or about once every six weeks,\" writes Kiplinger contributor Dan Burrows in his feature, \"When Is the Next Fed Meeting?\".\nThe Federal Open Market Committee \"is required to meet at least four times a year and may convene additional meetings if necessary,\" Burrows adds, noting that \"the convention of meeting eight times per year dates back to the market stresses of 1981.\"\nFed meetings last two days and wrap up with the release of a policy decision at 2 pm Eastern Standard Time.\nThis is typically followed by the Fed chair's press conference at 2:30 pm.",
            "title": "April Fed Meeting: Live Updates and Commentary | Kiplinger",
            "url": "https://www.kiplinger.com/news/live/fed-meeting-updates-and-commentary-april-2026",
            "date": "2026-04-29",
            "last_updated": "2026-05-21",
            "source": "web"
          },
          {
            "id": 6,
            "snippet": "The Fed’s dual mandate requires it to ensure both stable prices and maximum employment.",
            "title": "Tracker: The Federal Reserve's Balance Sheet Assets - AAF",
            "url": "https://www.americanactionforum.org/insight/tracker-the-federal-reserves-balance-sheet/",
            "date": "2026-05-14",
            "last_updated": "2026-05-16",
            "source": "web"
          },
          {
            "id": 7,
            "snippet": "The Federal Open Market Committee (FOMC) meeting is a regular session held by the members of the Federal Open Market Committee, a branch of the Federal Reserve that decides on the monetary policy of the United States.\nAfter deliberating on short-term monetary policy, the FOMC will decide on a target **federal funds rate** that they believe will achieve their aims.\n...\nThe FOMC will typically meet eight times a year, although there is scope for additional meetings if required.\nWhile any policy changes are announced immediately, the meetings are always secret, with minutes released three weeks after each session.\n...\nThe FOMC can include up to seven members of the Federal Reserve Board, plus five regional Federal Reserve Bank presidents.\nThe seven board members are all appointed by the US president, and the board chair usually serves as the chair of the FOMC.\nThe five bank presidents consist of the president of the Federal Reserve Bank of New York – who also serves as the FOMC vice-chair – plus four others, rotated on a yearly basis.",
            "title": "When is the FOMC Meeting and Announcement? - IG",
            "url": "https://www.ig.com/en-ch/financial-events/fomc-meeting-announcement",
            "date": "2019-06-28",
            "last_updated": "2026-05-21",
            "source": "web"
          },
          {
            "id": 8,
            "snippet": "The Federal Reserve (Fed) influences borrowing costs, savings returns, and overall financial conditions across the economy.\n...\n### Why does the Federal Reserve raise or lower interest rates?\naThe Federal Reserve’s Federal Open Market Committee sets a target interest rate policy for the federal funds rate.\nThis is the rate at which commercial banks borrow and lend excess reserves to other banks on an overnight basis.\nThe Fed raises or lowers the rate to impact underlying economic conditions.",
            "title": "Federal Reserve Monetary Policy | U.S. Bank",
            "url": "https://www.usbank.com/investing/financial-perspectives/market-news/federal-reserve-tapering-asset-purchases.html",
            "date": "2026-05-01",
            "last_updated": "2026-05-11",
            "source": "web"
          }
        ],
        "type": "search_results",
        "queries": [
          "FOMC purpose and structure",
          "FOMC meeting schedule eight times a year",
          "FOMC policy tools federal funds rate balance sheet"
        ]
      },
      {
        "id": "msg_6e56cea0-aee5-4b0c-a952-31a48542f67f",
        "content": [
          {
            "text": "The Federal Open Market Committee (FOMC) is the Federal Reserve’s main monetary policymaking body, and it typically meets eight times per year—about once every six weeks, with extra meetings if needed.[web:1][web:2][web:3] It influences the economy primarily by setting the target range for the federal funds rate and by adjusting the size and composition of the Federal Reserve’s balance sheet through open market operations and asset purchases or sales.[web:1][web:3][web:4]  \n\n## What the FOMC is  \n\n- The FOMC is the **monetary** policymaking arm of the Federal Reserve System, responsible for decisions that guide U.S. interest rates and money supply.[web:3][web:4]  \n- It oversees open market operations, including the buying and selling of U.S. Treasury and agency securities, which are central to how monetary policy is implemented.[web:1][web:4]  \n\n## How often it meets  \n\n- The FOMC schedules eight regular meetings each year, roughly one every six weeks, and is legally required to meet at least four times annually.[web:1][web:3][web:4]  \n- It can hold additional unscheduled meetings when economic or financial conditions warrant a faster policy response.[web:2][web:3]  \n\n## Federal funds rate tool  \n\n- The committee sets a target level or range for the federal funds rate, the overnight interest rate at which banks lend reserves to each other.[web:3][web:4][web:8]  \n- By raising this target range, the FOMC tightens financial conditions to cool inflation and economic activity; by lowering it, the FOMC aims to stimulate borrowing, spending, and employment.[web:3][web:8]  \n\n## Balance sheet and open market operations  \n\n- Through open market operations, the FOMC directs the purchase or sale of Treasury and agency securities, which changes the amount of reserves in the banking system and affects interest rates.[web:1][web:4]  \n- Since 2008, the FOMC has also used large‑scale asset purchases (expanding the Fed’s **balance** sheet) or allowing assets to run off/shrink to influence longer‑term interest rates and broader financial conditions.[web:3][web:6]  \n\n## Other policy tools in the background  \n\n- In addition to the federal funds rate and balance sheet policies, the broader Federal Reserve toolkit includes the discount rate and reserve requirements, though open market operations are specifically under the FOMC’s direction.[web:1]  \n- Together, these tools are used to pursue the Fed’s dual mandate of maximum employment and stable prices in the U.S. economy.[web:3][web:6]",
            "type": "output_text",
            "annotations": [],
            "logprobs": []
          }
        ],
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "status": "completed",
    "error": null,
    "usage": {
      "input_tokens": 6315,
      "output_tokens": 631,
      "total_tokens": 6946,
      "cost": {
        "currency": "USD",
        "input_cost": 0.00341,
        "output_cost": 0.00631,
        "total_cost": 0.01267,
        "cache_creation_cost": null,
        "cache_read_cost": 0.00045,
        "tool_calls_cost": 0.0025
      },
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 3584,
        "cached_tokens": 3584
      },
      "tool_calls_details": {
        "search_web": {
          "invocation": 1
        }
      },
      "output_tokens_details": {
        "reasoning_tokens": 0
      }
    },
    "background": false,
    "completed_at": 1779391925,
    "frequency_penalty": 0,
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "user": null
  }
  ```
</Accordion>

<Warning>
  If you need search results immediately for your user interface, consider using non-streaming requests for use cases where search result display is critical to the real-time user experience.
</Warning>

## Background Runs

Streaming keeps a connection open for the lifetime of the run. For runs that take minutes — deep research, heavy sandbox work — submit with `background: true` instead, then poll for the result by ID. The run continues server-side even if your client disconnects.

<Tip>
  For the full background-run lifecycle — submitting, polling on terminal status, streaming with reconnect, and cancelling — see [Background mode](/docs/agent-api/background-mode).
</Tip>

<CodeGroup>
  ```python Python theme={null}
  import time
  from perplexity import Perplexity

  client = Perplexity()


  def get_output_text(response) -> str:
      return "".join(
          content.text
          for item in response.output or []
          if getattr(item, "type", None) == "message"
          for content in getattr(item, "content", None) or []
          if getattr(content, "type", None) == "output_text"
      )


  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Produce a competitive landscape report for the EV charging market.",
      tools=[{"type": "web_search"}, {"type": "sandbox"}],
      background=True,
  )

  while response.status in ("queued", "in_progress"):
      time.sleep(2)
      response = client.responses.retrieve(response.id)

  print(get_output_text(response))
  ```

  ```bash cURL theme={null}
  # 1. Submit in the background
  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "input": "Produce a competitive landscape report for the EV charging market.",
      "tools": [{ "type": "web_search" }, { "type": "sandbox" }],
      "background": true
    }'

  # 2. Poll by id until status is completed, failed, cancelled, or incomplete
  curl https://api.perplexity.ai/v1/agent/$RESPONSE_ID \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY"
  ```
</CodeGroup>

Background runs are durable, so you can also stream one live and reconnect after a drop. Request `GET /v1/agent/{id}?stream=true&starting_after=N` to resume from the event after sequence number `N`. Reconnect is only valid within the response's reconnect window; once that window expires, the endpoint returns `400`, and you fall back to a plain `GET /v1/agent/{id}` for the final snapshot. See the [Agent API reference](/api-reference/agent-post).

## Structured Outputs

Structured outputs enable you to enforce specific response formats from Perplexity's models, ensuring consistent, machine-readable data that can be directly integrated into your applications without manual parsing.

We currently support **JSON Schema** structured outputs. To enable structured outputs, add a `response_format` field to your request:

```json theme={null}
{
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "your_schema_name",
      "schema": { /* your JSON schema object */ }
    }
  }
}
```

The `name` field is required and must be 1-64 alphanumeric characters. The schema should be a valid JSON schema object. LLM responses will match the specified format unless the output exceeds `max_tokens`.

<Tip>
  **Improve Schema Compliance**: Give the LLM some hints about the output format in your prompts to improve adherence to the structured format. For example, include phrases like "Please return the data as a JSON object with the following structure..." or "Extract the information and format it as specified in the schema."
</Tip>

<Info>
  The first request with a new JSON Schema expects to incur delay on the first token. Typically, it takes 10 to 30 seconds to prepare the new schema, and may result in timeout errors. Once the schema has been prepared, the subsequent requests will not see such delay.
</Info>

### Example

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity
  from typing import List, Optional
  from pydantic import BaseModel

  class FinancialMetrics(BaseModel):
      company: str
      quarter: str
      revenue: float
      net_income: float
      eps: float
      revenue_growth_yoy: Optional[float] = None
      key_highlights: Optional[List[str]] = None

  client = Perplexity()

  response = client.responses.create(
      preset="low",
      input="Explain the structure of an SEC Form 10-K filing: what each major item (Item 1 Business, Item 1A Risk Factors, Item 7 MD&A, Item 8 Financial Statements) typically contains.",
      response_format={
          "type": "json_schema",
          "json_schema": {
              "name": "financial_metrics",
              "schema": {
                  **FinancialMetrics.model_json_schema(),
                  "required": list(FinancialMetrics.model_fields.keys()),
                  "additionalProperties": False,
              }
          }
      }
  )

  metrics = FinancialMetrics.model_validate_json(response.output_text)
  print(f"Revenue: ${metrics.revenue}B")
  ```

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

  interface FinancialMetrics {
    company: string;
    quarter: string;
    revenue: number;
    net_income: number;
    eps: number;
    revenue_growth_yoy?: number;
    key_highlights?: string[];
  }

  const client = new Perplexity();

  const response = await client.responses.create({
    preset: 'low',
    input: 'Explain the structure of an SEC Form 10-K filing: what each major item (Item 1 Business, Item 1A Risk Factors, Item 7 MD&A, Item 8 Financial Statements) typically contains.',
    response_format: {
      type: 'json_schema',
      json_schema: {
        name: 'financial_metrics',
        schema: {
          type: 'object',
          properties: {
            company: { type: 'string' },
            quarter: { type: 'string' },
            revenue: { type: 'number' },
            net_income: { type: 'number' },
            eps: { type: 'number' },
            revenue_growth_yoy: { anyOf: [{ type: 'number' }, { type: 'null' }] },
            key_highlights: { anyOf: [{ type: 'array', items: { type: 'string' } }, { type: 'null' }] }
          },
          required: ['company', 'quarter', 'revenue', 'net_income', 'eps', 'revenue_growth_yoy', 'key_highlights'],
          additionalProperties: false
        }
      }
    }
  });

  const metrics: FinancialMetrics = JSON.parse(response.output_text ?? '{}');
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.perplexity.ai/v1/agent" \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "preset": "low",
      "input": "Explain the structure of an SEC Form 10-K filing: what each major item (Item 1 Business, Item 1A Risk Factors, Item 7 MD&A, Item 8 Financial Statements) typically contains.",
      "response_format": {
        "type": "json_schema",
        "json_schema": {
          "name": "financial_metrics",
          "schema": {
            "type": "object",
            "properties": {
              "company": {"type": "string"},
              "quarter": {"type": "string"},
              "revenue": {"type": "number"},
              "net_income": {"type": "number"},
              "eps": {"type": "number"},
              "revenue_growth_yoy": {"type": "number"},
              "key_highlights": {
                "type": "array",
                "items": {"type": "string"}
              }
            },
            "required": ["company", "quarter", "revenue", "net_income", "eps"]
          }
        }
      }
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_04a4e751-4810-40c2-a92e-ffcab3e11d77",
    "created_at": 1779391825,
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "results": [
          {
            "id": 1,
            "snippet": "(d) In response to Item l, Business, such registrant only need furnish a brief\ndescription of the business done by the registrant and its subsidiaries during the\nmost recent fiscal year which will, in the opinion of management, indicate the\ngeneral nature and scope of the business of the registrant and its subsidiaries, and\nin response to Item 2, Properties, such registrant only need furnish a brief\ndescription of the material properties of the registrant and its subsidiaries to the\nextent, in the opinion of the management, necessary to an understanding of the\nbusiness done by the registrant and its subsidiaries.\n...\nPART I \n[See General Instruction G(2)] \nItem 1.\nBusiness.\nFurnish the information required by Item 101 of Regulation S-K (§ 229.101 of this chapter) \nexcept that the discussion of the development of the registrant’s business need only include\ndevelopments since the beginning of the fiscal year for which this report is filed.\nItem 1A.\nRisk Factors.\nSet forth, under the caption “Risk Factors,” where appropriate, the risk factors described in \nItem 105 of Regulation S-K (§ 229.105 of this chapter) applicable to the registrant.\nProvide any\ndiscussion of risk factors in plain English in accordance with Rule 421(d) of the Securities Act of \n1933 (§ 230.421(d) of this chapter).\nSmaller reporting companies are not required to provide the \ninformation required by this item.\nItem 1B.",
            "title": "[PDF] Form 10-K - SEC.gov",
            "url": "https://www.sec.gov/files/form10-k.pdf",
            "date": null,
            "last_updated": "2025-06-03",
            "source": "web"
          },
          {
            "id": 2,
            "snippet": "This report provides a comprehensive view of a company’s financial position and additional business disclosures, such as key operational details, audited financial statements, market risks, and corporate governance.",
            "title": "How to navigate Forms 10-K, 10-Q, 20-F, 40-F, 8-K and 6-K",
            "url": "https://www.toppanmerrill.com/blog/how-to-navigate-forms-10-k-10-q-20-f-40-f-8-k-and-6-k/",
            "date": "2025-03-19",
            "last_updated": "2026-05-16",
            "source": "web"
          },
          {
            "id": 3,
            "snippet": "The SEC breaks the Form 10-K down into four parts:\n### Part I\n- Item 1: “Business”\n- Item 1A: “Risk Factors”\n- Item 1B: “Unresolved Staff Comments”\n- Item 2: “Properties”\n...\nTo analyze a company using Form 10-K, always check “Item 1,” which is an overview of business operations.\nAs an example, we’ll look at TSLA.\nThe overview lists all of the car models, potential new models, and other developments within the company, such as potential factories.\nThis gives you a good idea of what’s in store for the company’s future production.",
            "title": "What Form 10-K Is and How to Understand It to Use It",
            "url": "https://thecollegeinvestor.com/32956/form-10-k/",
            "date": "2024-02-27",
            "last_updated": "2025-04-18",
            "source": "web"
          },
          {
            "id": 4,
            "snippet": "#### Item 1 – Business\nThis describes the business of the company: who and what the company does, what subsidiaries it owns, and what markets it operates in.\nIt may also include recent events, competition, regulations, and labor issues.\n(Some industries are heavily regulated, have complex labor requirements, which have significant effects on the business.)\nOther topics in this section may include special operating costs, seasonal factors, or insurance matters.",
            "title": "Form 10-K - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/Form_10-K",
            "date": "2005-02-23",
            "last_updated": "2026-03-31",
            "source": "web"
          },
          {
            "id": 5,
            "snippet": "Regulation S-K, Item 105, requires registrants to provide “a discussion of the\nmaterial factors that make an investment in the registrant or offering\nspeculative or risky.”\nCertain indicators of risk may be present in the\nfootnotes to the financial statements, in MD&A, or elsewhere in investor\npresentations or other periodic filings.",
            "title": "3.3 Disclosures About Risk | DART – Deloitte Accounting Research ...",
            "url": "https://dart.deloitte.com/USDART/home/publications/deloitte/additional-deloitte-guidance/roadmap-sec-comment-letter-considerations/chapter-3-sec-disclosure-topics/3-3-disclosures-about-risk",
            "date": null,
            "last_updated": "2026-03-31",
            "source": "web"
          },
          {
            "id": 6,
            "snippet": "If the registrant or any of its subsidiaries consolidated has completed the acquisition or \ndisposition of a significant amount of assets, otherwise than in the ordinary course of business, or \nthe acquisition or disposition of a significant amount of assets that constitute a real estate \noperation as defined in § 210.3-14(a)(2) disclose the following information:\n(a) the date of completion of the transaction; \n(b) a brief description of the assets involved; \n(c) the identity of the person(s) from whom the assets were acquired or to whom they were \nsold and the nature of any material relationship, other than in respect of the transaction, between \nsuch person(s) and the registrant or any of its affiliates, or any director or officer of the\n...\n(1) \n...\nnature of any recourse provisions that would enable the registrant to recover from third parties; ",
            "title": "[PDF] Form 8-K - SEC.gov",
            "url": "https://www.sec.gov/files/form8-k.pdf",
            "date": null,
            "last_updated": "2025-04-11",
            "source": "web"
          },
          {
            "id": 7,
            "snippet": "#### Part I: Business Overview and Risks\n- Item 1 - Business:\n- Describes the company’s primary business activities, including its main products and services, subsidiaries, and market operations.\n- Discusses the competitive landscape, regulatory environment, and any significant business developments during the year.",
            "title": "Form 10-K: Explained",
            "url": "https://unlevered.ai/blog/10-k/",
            "date": "2024-08-21",
            "last_updated": "2024-10-17",
            "source": "web"
          },
          {
            "id": 8,
            "snippet": "- **Item 1: Business**\n...\n## Item 1 - BusinessneCompanies typically define their business in this opening section of the 10-K report.\nThey describe their various product lines and business segments.\nThey list contracts, raw materials used, and supplier or distribution channels.\nThey talk about the competition and competitive factors in the market.\nIf research and development or intellectual property issues are important to company operations, they are included.\nGovernment regulations are covered.\nFinally, several pages are devoted to outlining risk factors to consider in evaluating the company's business.",
            "title": "The 10-K - SEC Filings - Research Guides at Baruch College",
            "url": "https://guides.newman.baruch.cuny.edu/c.php?g=188202&p=1244183",
            "date": "2009-11-02",
            "last_updated": "2026-05-09",
            "source": "web"
          },
          {
            "id": 9,
            "snippet": "- **Item 1A: Risk Factors:** Absolutely critical reading.\nThis **section** lists the most significant risks and uncertainties that could materially affect the company’s business, **financial condition**, or operating results.\nEffective **10k risk factors analysis** is paramount for **investors**.\nLook for specific, quantifiable risks, not just boilerplate warnings.\nAI tools can be particularly helpful in tracking changes to this section over time.\n- **Item 1B: Unresolved Staff Comments:** Details any outstanding written comments from SEC staff regarding the company’s prior filings.\n- **Item 2: Properties:** Information about the company’s significant physical properties, like manufacturing plants or corporate headquarters.\n- **Item 3: Legal Proceedings:** Describes any significant pending lawsuits or other legal actions involving the company.\n...\nA 10-K report is broadly divided into: Part I (Business Overview, Risk Factors, Legal Proceedings), Part II (Financial Data including MD&A, Income Statement, Balance Sheet, Cash Flow Statement, and Notes), Part III (Corporate Governance, Executive Compensation, Major Shareholders), and Part IV (Exhibits and Financial Statement Schedules).\nEach part offers different but crucial insights into the company’s operations and financial health.",
            "title": "How to Read a 10-K Report with AI | Complete SEC Analysis Guide",
            "url": "https://www.v7labs.com/blog/how-to-read-a-10k-report-ai-sec-filings-guide",
            "date": "2025-06-11",
            "last_updated": "2026-05-16",
            "source": "web"
          },
          {
            "id": 10,
            "snippet": "Additional sections in this Form 10-K which should be helpful to the reading of our discussion and analysis include the following: (i) a description of our services provided, by segment found in Items\n1 and 2 “Business and Properties”—”Services Provided” (ii) a description of our business strategy found in Items 1 and 2 “Business and Properties”—”Our Strategy”; and (iii) a description of\nrisk factors affecting us and our business, found in Item 1A “Risk Factors.”",
            "title": "Form 10-K Item 7. Management's Discussion and Analysis",
            "url": "https://www.sec.gov/Archives/edgar/data/1449732/000119312512289206/d374099dex993.htm",
            "date": "2012-03-29",
            "last_updated": "2025-09-23",
            "source": "web"
          },
          {
            "id": 11,
            "snippet": "In this section of the 10-K, companies will provide a description of the business, including what the company does, its different business lines and customers, competitors, and where it operates, among other things.",
            "title": "Form 10-K: A Comprehensive Overview - Corporate Finance Institute",
            "url": "https://corporatefinanceinstitute.com/resources/accounting/form-10-k/",
            "date": "2024-04-18",
            "last_updated": "2026-02-04",
            "source": "web"
          },
          {
            "id": 12,
            "snippet": "Unlike the quarterly 10-Q, the 10-K includes\n**audited financial statements** and extensive narrative sections covering the business model, competitive landscape, and risk factors.\n...\n#### Item 1: Business\nCore operations, products, competition\n💡 Read this first for company overview\n#### Item 1A: Risk Factors\n...\n💡 Often 20+ pages of worst-case scenarios",
            "title": "SEC Form 10-K: Complete Guide to Annual Reports",
            "url": "https://secwhisperer.com/learn/sec-form-10k",
            "date": "2025-10-28",
            "last_updated": "2025-12-23",
            "source": "web"
          }
        ],
        "type": "search_results",
        "queries": [
          "SEC Form 10-K item 1 business description",
          "SEC Form 10-K item 1A risk factors description",
          "SEC Form 10-K item 7 MD&A contents",
          "SEC Form 10-K item 8 financial statements contents",
          "SEC form 10-K item list overview"
        ]
      },
      {
        "id": "msg_e2eaeb8f-a3ef-47ac-b50a-e5da20409664",
        "content": [
          {
            "text": "An SEC Form 10-K is a standardized annual report with specific “Items” that each serve a distinct purpose; Items 1, 1A, 7, and 8 together explain what the company does, what could go wrong, how management interprets the numbers, and the audited financials themselves.[web:1][web:4] Understanding the typical contents of each of these items makes it much easier to navigate any company’s filing.[web:8]  \n\n## Item 1 – Business  \n\nItem 1 “Business” describes the **core** operations of the registrant and its subsidiaries, including what the company does, its main products and services, and the markets and geographies in which it operates.[web:1][web:4][web:11] It often includes discussion of business segments, major customers, distribution channels, and important contracts or supply arrangements.[web:8][web:11]  \n\nCompanies typically also cover their competitive environment, key competitors, and the basis of competition (price, technology, brand, service).[web:4][web:8] Depending on the industry, this section may address regulatory requirements, seasonality of the business, research and development, intellectual property, dependence on raw materials, and human capital resources such as employees and labor relations.[web:4][web:7][web:8]  \n\n## Item 1A – Risk Factors  \n\nItem 1A “Risk Factors” presents the material risks that could adversely affect the company’s business, financial condition, or results of operations, framed as factors that make an investment speculative or risky.[web:1][web:5][web:9] These risk factors must focus on risks that are specific and material to the registrant, not just generic boilerplate, and are required to be written in plain-English style.[web:1][web:5]  \n\nTypical categories include business and operational risks (e.g., supply chain disruption, competition), financial risks (liquidity, leverage, credit), legal and regulatory risks, cybersecurity and data privacy risks, and macroeconomic or geopolitical risks.[web:7][web:9] The section usually explains how each risk could impact the company (for example, reduced revenue, higher costs, or asset impairment) and may note interdependencies between risks.[web:7][web:9]  \n\n## Item 7 – MD&A  \n\nItem 7 “Management’s Discussion and Analysis of Financial Condition and Results of Operations” (MD&A) is where management explains, in narrative form, the drivers behind the historical financial results and the company’s liquidity and capital resources.[web:1][web:9][web:11] It typically walks through year‑over‑year changes in revenue, margins, expenses, and key line items, linking them to underlying causes such as volume, pricing, mix, acquisitions, foreign exchange, or cost initiatives.[web:9][web:10][web:11]  \n\nMD&A also addresses liquidity (cash flows, debt arrangements, credit facilities), capital expenditures, and known trends, demands, commitments, or uncertainties that are reasonably likely to affect future performance.[web:1][web:9] Companies often discuss non‑GAAP measures, critical accounting estimates, and sensitivity to market risks such as interest rates or foreign exchange, with cross‑references to the financial statements and risk factors.[web:9][web:10][web:11]  \n\n## Item 8 – Financial Statements  \n\nItem 8 contains the company’s audited annual financial statements and related disclosures.[web:1][web:2][web:12] This section typically includes the independent auditor’s report, the balance sheet, income statement, statement of cash flows, statement of shareholders’ equity, and the accompanying notes to the financial statements.[web:2][web:9][web:12]  \n\nThe notes provide detailed information on accounting policies, revenue recognition, segments, debt, leases, contingencies, income taxes, pensions, stock-based compensation, and other significant matters.[web:2][web:12] Item 8 may also include financial statement schedules and any additional required data that support or expand on the primary financial statements.[web:1][web:12]",
            "type": "output_text",
            "annotations": [],
            "logprobs": []
          }
        ],
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "status": "completed",
    "error": null,
    "usage": {
      "input_tokens": 6393,
      "output_tokens": 944,
      "total_tokens": 7337,
      "cost": {
        "currency": "USD",
        "input_cost": 0.00351,
        "output_cost": 0.00944,
        "total_cost": 0.0159,
        "cache_creation_cost": null,
        "cache_read_cost": 0.00045,
        "tool_calls_cost": 0.0025
      },
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 3584,
        "cached_tokens": 3584
      },
      "tool_calls_details": {
        "search_web": {
          "invocation": 1
        }
      },
      "output_tokens_details": {
        "reasoning_tokens": 0
      }
    },
    "background": false,
    "completed_at": 1779391825,
    "frequency_penalty": 0,
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "user": null
  }
  ```
</Accordion>

<Warning>
  **Links in JSON Responses**: Requesting links as part of a JSON response may not always work reliably and can result in hallucinations or broken links. Models may generate invalid URLs when forced to include links directly in structured outputs.

  To ensure all links are valid, use the links returned in the `citations` or `search_results` fields from the API response. Never count on the model to return valid links directly as part of the JSON response content.
</Warning>

## Next Steps

<CardGroup>
  <Card title="Structure the output" icon="list-details" href="/docs/agent-api/building-agents/shape-output">
    Back to the build flow: enforce structured JSON your code can parse.
  </Card>

  <Card title="Agent API Models" icon="brain" href="/docs/agent-api/models">
    Explore direct model selection and third-party models.
  </Card>
</CardGroup>


# Presets
Source: https://docs.perplexity.ai/docs/agent-api/presets

Explore Perplexity's Agent API presets - pre-configured setups optimized for different use cases with specific models, search configs, and tool access.

## Overview

Presets are pre-configured setups optimized for specific use cases. Each preset bundles a model, search config, reasoning steps, system prompt, and available tools.

<Info>
  Agent API presets now use tier-based names: fast-search → fast, pro-search → low, deep-research → medium, advanced-deep-research → high, and ultra → xhigh.
</Info>

Presets can be used in two ways:

* **Dynamic preset (recommended)** — call a preset by name (e.g., `preset="low"`) to opt in to the latest Perplexity-optimized configuration. Perplexity updates the underlying configuration as evals show improvements, and your application picks up those improvements automatically with no code changes.
* **Frozen preset/configuration** — copy a preset's current preset values (model, tools, system prompt, parameters) into your request and omit the `preset` parameter. This freezes the exact setup the preset uses today. Use this when you want to insulate your application from future preset updates or pin the exact underlying model and tool setup.

You can mix both: call the dynamic preset in most environments and use a frozen configuration where stability is required.

<Info>
  Presets provide sensible defaults optimized for their use case. You can override any parameter (like `model`, `max_steps`, or `tools`) by passing additional parameters. See [Customizing Presets](#customizing-presets) for code examples.
</Info>

<Note>
  **No explicit versioning.** Presets are not pinned to a specific version. Calling a preset by name always resolves to the latest Perplexity-recommended configuration. When we ship a meaningfully better configuration, we surface it as an improved preset — the name stays the same. If you need to pin a specific configuration, create a frozen configuration by copying the [current preset values](#current-preset-values) inline instead.
</Note>

### What Changes When a Preset Is Updated

When Perplexity updates a preset, we aim to keep changes within the same expected profile so your application sees a quality improvement without surprises:

* **Cost profile** — preset updates target the same cost band. The underlying model may change, but updates are tuned to stay close to the existing per-request cost.
* **Latency profile** — preset updates target the same latency band. Step count, search config, and tool budget are kept close to the current values.
* **Quality** — this is the dimension that preset updates optimize for. New configurations ship when evals show meaningful improvements.

If you need to pin an exact configuration instead of tracking these updates, create a frozen configuration by copying the [current preset values](#current-preset-values) inline.

## Choosing a preset

Each preset trades off research depth, source coverage, and latency. Use the table below to pick the one that fits your query.

| Preset            | Good at                                                                                                                           | Use when                                                                                                                                                                                                                  |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **fast**          | Single-fact lookups, definitions, and quick summaries with inline citations.                                                      | The answer is one fact or a short summary, latency matters most, and no multi-step research is needed.                                                                                                                    |
| **low**           | Everyday research questions, light multi-step lookups with current information and inline citations.                              | A query needs current information with light research and tool use.                                                                                                                                                       |
| **medium**        | Multi-hop browsing and wide aggregation across many sources, with inline citations for source-backed claims.                      | A question requires chaining evidence across many sources over several rounds of search and reasoning.                                                                                                                    |
| **high**          | Expert-level reasoning and exhaustive source coverage, with inline citations for source-backed claims.                            | You need the broadest coverage and the longest reasoning — institutional-grade analysis where completeness matters more than latency.                                                                                     |
| **xhigh**         | Open-ended, agentic work: executing code in a sandbox, sustaining long tool-use loops, and gathering across many sources at once. | A task is open-ended rather than a single question — it runs code, orchestrates many rounds of tool use, or builds up a result step by step. It is the most capable preset, best when capability matters more than speed. |
| **wide-research** | Building large, evidence-backed collections with broad discovery and per-item research.                                           | You need to identify many qualifying items, support each result with sources, and produce structured output for downstream use. See the [Wide Research guide](/docs/agent-api/wide-research).                             |

<Info>
  The full current configuration for each preset — model, tools, parameters, and system prompt — is in the [Current preset values](#current-preset-values) section below.
</Info>

## Using a preset

Call a preset by name with the `preset` parameter — Perplexity manages the underlying configuration, so you pick up future improvements with no code changes.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      preset="low",
      input="Summarize the core findings of the original 'Attention Is All You Need' transformer paper and explain why it changed NLP.",
  )

  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({
      preset: "low",
      input: "Summarize the core findings of the original 'Attention Is All You Need' transformer paper and explain why it changed NLP.",
  });

  console.log(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": "low",
      "input": "Summarize the core findings of the Attention Is All You Need transformer paper and explain why it changed NLP."
    }'
  ```
</CodeGroup>

Swap `preset="low"` for any preset name from the [table above](#choosing-a-preset). To override any preset default, see [Customizing Presets](#customizing-presets).

## Customizing Presets

Presets provide sensible defaults. Any field you pass alongside the preset overrides that default. Anything you don't set keeps the preset's default.

`tools` are the one exception: they merge per tool instead of replacing the whole set. Listing one tool overrides only that tool's options and leaves the preset's other tools enabled.

<Note>
  To tune search depth under a preset, set `max_tokens` and `max_tokens_per_page` on `web_search`. See [Configuring Search](/docs/agent-api/tools/web-search#configuring-search).
</Note>

<Tabs>
  <Tab title="Python SDK">
    ```python theme={null}
    from perplexity import Perplexity

    client = Perplexity()

    # Override the model while keeping everything else from the preset
    response = client.responses.create(
        preset="low",
        model="anthropic/claude-sonnet-4-6",  # Override the model the preset would use
        max_output_tokens=16384,
        input="Summarize the core findings of the original 'Attention Is All You Need' transformer paper and explain why it changed NLP.",
    )

    # Override max_steps for deeper reasoning
    response = client.responses.create(
        preset="low",
        input="What is serverless cold start latency, what causes it, and what are the standard mitigations (warm pools, provisioned concurrency)?",
        max_steps=8,  # Override the preset's step budget
    )

    # Override reasoning effort
    response = client.responses.create(
        preset="low",
        input="Compare the trade-offs between optimistic and pessimistic concurrency control in distributed databases.",
        reasoning={"effort": "high"},  # minimal | low | medium | high | xhigh | max
    )

    # Restrict web_search to specific domains while keeping the preset's other defaults
    response = client.responses.create(
        preset="low",
        input="Explain the FDA's accelerated approval pathway under 21 CFR 314 Subpart H: eligibility criteria, surrogate endpoints, and confirmatory trial requirements.",
        tools=[{
            "type": "web_search",
            "filters": {
                "search_domain_filter": ["clinicaltrials.gov", "fda.gov"],  # Restrict to specific domains
            },
        }],
    )

    # Use explicit token budgets when you need exact budget control
    response = client.responses.create(
        preset="low",
        input="Explain the FDA's accelerated approval pathway under 21 CFR 314 Subpart H: eligibility criteria, surrogate endpoints, and confirmatory trial requirements.",
        tools=[{
            "type": "web_search",
            "max_tokens": 6000,
            "max_tokens_per_page": 1200,
            "filters": {
                "search_domain_filter": ["clinicaltrials.gov", "fda.gov"],
            },
        }],
    )
    ```
  </Tab>

  <Tab title="Typescript SDK">
    ```typescript theme={null}
    import Perplexity from '@perplexity-ai/perplexity_ai';

    const client = new Perplexity();

    // Override the model while keeping everything else from the preset
    const response = await client.responses.create({
        preset: "low",
        model: "anthropic/claude-sonnet-4-6", // Override the model the preset would use
        max_output_tokens: 16384,
        input: "Summarize the core findings of the original 'Attention Is All You Need' transformer paper and explain why it changed NLP.",
    });

    // Override max_steps for deeper reasoning
    const response2 = await client.responses.create({
        preset: "low",
        input: "What is serverless cold start latency, what causes it, and what are the standard mitigations (warm pools, provisioned concurrency)?",
        max_steps: 8, // Override the preset's step budget
    });

    // Override reasoning effort
    const response5 = await client.responses.create({
        preset: "low",
        input: "Compare the trade-offs between optimistic and pessimistic concurrency control in distributed databases.",
        reasoning: { effort: "high" }, // minimal | low | medium | high | xhigh | max
    });

    // Restrict web_search to specific domains while keeping the preset's other defaults
    const response3 = await client.responses.create({
        preset: "low",
        input: "Explain the FDA's accelerated approval pathway under 21 CFR 314 Subpart H: eligibility criteria, surrogate endpoints, and confirmatory trial requirements.",
        tools: [{
            type: "web_search" as const,
            filters: {
                search_domain_filter: ["clinicaltrials.gov", "fda.gov"], // Restrict to specific domains
            },
        }],
    });

    // Use explicit token budgets when you need exact budget control
    const response4 = await client.responses.create({
        preset: "low",
        input: "Explain the FDA's accelerated approval pathway under 21 CFR 314 Subpart H: eligibility criteria, surrogate endpoints, and confirmatory trial requirements.",
        tools: [{
            type: "web_search" as const,
            max_tokens: 6000,
            max_tokens_per_page: 1200,
            filters: {
                search_domain_filter: ["clinicaltrials.gov", "fda.gov"],
            },
        }],
    });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    # Override the model while keeping everything else from the preset
    curl https://api.perplexity.ai/v1/agent \
      -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "preset": "low",
        "model": "anthropic/claude-sonnet-4-6",
        "max_output_tokens": 16384,
        "input": "Summarize the core findings of the original Attention Is All You Need transformer paper and explain why it changed NLP."
      }' | jq
    ```

    ```bash theme={null}
    # Override max_steps for deeper reasoning
    curl https://api.perplexity.ai/v1/agent \
      -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "preset": "low",
        "input": "What is serverless cold start latency, what causes it, and what are the standard mitigations (warm pools, provisioned concurrency)?",
        "max_steps": 8
      }' | jq
    ```

    ```bash theme={null}
    # Override reasoning effort
    curl https://api.perplexity.ai/v1/agent \
      -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "preset": "low",
        "input": "Compare the trade-offs between optimistic and pessimistic concurrency control in distributed databases.",
        "reasoning": { "effort": "high" }
      }' | jq
    ```

    ```bash theme={null}
    # Restrict web_search to specific domains while keeping the preset's other defaults
    curl https://api.perplexity.ai/v1/agent \
      -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "preset": "low",
        "input": "Explain the FDA'\''s accelerated approval pathway under 21 CFR 314 Subpart H: eligibility criteria, surrogate endpoints, and confirmatory trial requirements.",
        "tools": [{
          "type": "web_search",
          "filters": {
            "search_domain_filter": ["clinicaltrials.gov", "fda.gov"]
          }
        }]
      }' | jq
    ```

    ```bash theme={null}
    # Use explicit token budgets when you need exact budget control
    curl https://api.perplexity.ai/v1/agent \
      -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "preset": "low",
        "input": "Explain the FDA'\''s accelerated approval pathway under 21 CFR 314 Subpart H: eligibility criteria, surrogate endpoints, and confirmatory trial requirements.",
        "tools": [{
          "type": "web_search",
          "max_tokens": 6000,
          "max_tokens_per_page": 1200,
          "filters": {
            "search_domain_filter": ["clinicaltrials.gov", "fda.gov"]
          }
        }]
      }' | jq
    ```
  </Tab>
</Tabs>

<Info>
  The full current configuration for each preset — model, tools, parameters, and system prompt — is in the [Current preset values](#current-preset-values) section below. The [Choosing a preset](#choosing-a-preset) table summarizes what each preset is for.
</Info>

## Current preset values

Current preset values are the concrete model, system prompt, tools, and parameters behind each preset, expressed as public API fields. Copy these values into your request and omit the `preset` parameter to create a frozen configuration: a pinned setup that reproduces the preset's behavior today.

Each preset below shows its complete, self-contained current values — copy a single block to freeze that preset's behavior.

<Note>
  Frozen configurations are pinned. They will **not** pick up future preset improvements — call the preset by name (a [dynamic preset](#using-a-preset)) if you want automatic updates.
</Note>

<Note>
  The cURL tab can show a more complete configuration than the SDK tabs: some parameters aren't exposed by the SDK yet.
</Note>

<AccordionGroup>
  <Accordion title="fast — current preset values">
    Quick factual lookups with minimal latency and inline citations for search-backed claims.

    * **Model:** `openai/gpt-5.4-mini`
    * **Max steps:** 1
    * **Reasoning effort:** `low`
    * **Max output tokens:** 8192
    * **Tools:** `web_search`
    * **Search results:** `max_results: 10` (cURL request)
    * **System prompt:** included inline below

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      response = client.responses.create(
          model="openai/gpt-5.4-mini",
          input="Explain the 2023 Nobel Prize in Physics: who won, what attosecond physics is, and why their work matters for studying electron dynamics.",
          max_steps=1,
          max_output_tokens=8192,
          reasoning={"effort": "low"},
          instructions=r"""
      ## Role
      <role>
      You are Perplexity, a helpful search assistant built by Perplexity AI. Your task is to deliver accurate, well-cited answers by leveraging web search results. You prioritize speed and precision, providing direct answers that respect the user's time while maintaining factual accuracy.

      Given a user's query, generate an expert, useful, and contextually relevant response. Answer only the current query using its provided search results and relevant conversation history. Do not repeat information from previous answers.
      </role>

      ## Tools Workflow
      <tools_workflow>
      You must call the web search tool before answering. Do not rely on internal knowledge when search results can provide current, verifiable information.

      - Decompose complex queries into discrete, parallel search calls for accuracy
      - Use short, keyword-based queries (2-5 words optimal, 8 words maximum)
      - Do not generate redundant or overlapping queries
      - Match the language of the user's query
      - If search results are empty or unhelpful, answer using existing knowledge and state this limitation

      <tool_call_limit>Make at most one tool call before concluding.</tool_call_limit>
      </tools_workflow>

      ## Citation Instructions
      <citations>
      Your response must include citations. Add a citation to every sentence that includes information derived from search results.

      <formatting>
      - Use brackets with the source index immediately after the relevant statement: [1], [2], etc.
      - Do not leave a space between the last word and the citation
      - When multiple sources support a claim, use separate brackets: [1][2][3]
      - Cite up to three relevant sources per sentence, choosing the most pertinent results
      - Never use formats with spaces, commas, or dashes inside brackets
      - Citations must appear inline, never in a separate References section
      </formatting>

      <examples>
      Correct: "The Eiffel Tower is located in Paris[1][2]."
      Incorrect: "The Eiffel Tower is located in Paris [1, 2]."
      Incorrect: "The Eiffel Tower is located in Paris[1-2]."
      </examples>

      If you did not perform a search, do not include citations.
      </citations>

      ## Response Guidelines
      <response_guidelines>

      <structure>
      - Begin with a direct 1-2 sentence answer to the core question
      - Never start with a header or meta-commentary about your process
      - Use Level 2 headers (##) for sections only when organizing substantial content
      - Use bolded text (**text**) sparingly for emphasis on key terms
      - Keep responses concise; users should not need to scroll extensively
      </structure>

      <formatting>
      - Lists: Use flat lists only (no nesting). Numbers for sequential items, bullets (-) otherwise. One item per line with no indentation.
      - Tables: Use markdown tables for comparisons. Ensure headers are properly defined. Include citations within cells directly after relevant data.
      - Code: Use markdown code blocks with language identifiers for syntax highlighting.
      - Math: Use LaTeX with \( \) for inline and \[ \] for block formulas. Never use $ or unicode for math.
      - Quotes: Use markdown blockquotes for relevant supporting quotes.
      </formatting>

      <tone>
      - Write with precision and clarity using plain language
      - Use active voice and vary sentence structure naturally
      - Avoid hedging phrases ("It is important to...", "It is subjective...")
      - Do not use first-person pronouns or self-referential phrases
      - Ensure smooth transitions between sentences
      </tone>

      </response_guidelines>

      ## Query Type Adaptations
      <query_types>
      Adapt your response structure based on query type while following all general guidelines.

      <academic>
      Provide detailed, well-structured answers formatted as scientific write-ups with paragraphs and sections using markdown headers.
      </academic>

      <news>
      Summarize recent events concisely, grouping by topic. Use lists with bolded news titles at the start of each item. Prioritize diverse perspectives from trustworthy sources. Combine overlapping coverage with multiple citations. Prioritize recency. Never start with a header.
      </news>

      <weather>
      Provide only the weather forecast in a brief format. If search results lack relevant weather data, state this clearly.
      </weather>

      <people>
      Write a concise, comprehensive biography. If results reference multiple people with the same name, describe each separately without mixing information. Never start with the person's name as a header.
      </people>

      <coding>
      Use markdown code blocks with appropriate language identifiers. Present code first, then explain it.
      </coding>

      <recipes>
      Provide step-by-step instructions with clear ingredient amounts and precise directions for each step.
      </recipes>

      <translation>
      Provide the translation directly without citations or search references.
      </translation>

      <creative_writing>
      Follow user instructions precisely. Search results and citations are not required. Focus on delivering exactly what the user needs.
      </creative_writing>

      <math_and_science>
      For simple calculations, answer with the final result only. Use LaTeX for all formulas (\( \) inline, \[ \] block). Add citations after formulas: \[ \sin(x) \] [1][2]. Never use $ or unicode for math expressions.
      </math_and_science>

      <url_lookup>
      When the query includes a URL, rely solely on information from that source. Always cite [1] for the URL content. If the query is only a URL without instructions, summarize its content.
      </url_lookup>

      </query_types>

      ## Prohibited Content
      <prohibited>
      Never include in your responses:
      - Meta-commentary about your search or research process
      - Phrases like "Based on my search results...", "According to my research...", "Let me provide..."
      - URLs or links
      - Verbatim song lyrics or copyrighted content
      - A header at the beginning of your response
      - References or bibliography sections
      </prohibited>

      ## Copyright
      <copyright>
      - Never reproduce copyrighted content verbatim (text, lyrics, etc.)
      - Public domain content (expired copyrights, traditional works) may be shared
      - When copyright status is uncertain, treat as copyrighted
      - Keep summaries brief (under 30 words) and original
      - Brief factual statements (names, dates, facts) are always acceptable
      </copyright>""",
          tools=[
              {"type": "web_search"},
          ],
      )

      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.4-mini",
          input: "Explain the 2023 Nobel Prize in Physics: who won, what attosecond physics is, and why their work matters for studying electron dynamics.",
          max_steps: 1,
          max_output_tokens: 8192,
          reasoning: { effort: "low" },
          instructions: `
      ## Role
      <role>
      You are Perplexity, a helpful search assistant built by Perplexity AI. Your task is to deliver accurate, well-cited answers by leveraging web search results. You prioritize speed and precision, providing direct answers that respect the user's time while maintaining factual accuracy.

      Given a user's query, generate an expert, useful, and contextually relevant response. Answer only the current query using its provided search results and relevant conversation history. Do not repeat information from previous answers.
      </role>

      ## Tools Workflow
      <tools_workflow>
      You must call the web search tool before answering. Do not rely on internal knowledge when search results can provide current, verifiable information.

      - Decompose complex queries into discrete, parallel search calls for accuracy
      - Use short, keyword-based queries (2-5 words optimal, 8 words maximum)
      - Do not generate redundant or overlapping queries
      - Match the language of the user's query
      - If search results are empty or unhelpful, answer using existing knowledge and state this limitation

      <tool_call_limit>Make at most one tool call before concluding.</tool_call_limit>
      </tools_workflow>

      ## Citation Instructions
      <citations>
      Your response must include citations. Add a citation to every sentence that includes information derived from search results.

      <formatting>
      - Use brackets with the source index immediately after the relevant statement: [1], [2], etc.
      - Do not leave a space between the last word and the citation
      - When multiple sources support a claim, use separate brackets: [1][2][3]
      - Cite up to three relevant sources per sentence, choosing the most pertinent results
      - Never use formats with spaces, commas, or dashes inside brackets
      - Citations must appear inline, never in a separate References section
      </formatting>

      <examples>
      Correct: "The Eiffel Tower is located in Paris[1][2]."
      Incorrect: "The Eiffel Tower is located in Paris [1, 2]."
      Incorrect: "The Eiffel Tower is located in Paris[1-2]."
      </examples>

      If you did not perform a search, do not include citations.
      </citations>

      ## Response Guidelines
      <response_guidelines>

      <structure>
      - Begin with a direct 1-2 sentence answer to the core question
      - Never start with a header or meta-commentary about your process
      - Use Level 2 headers (##) for sections only when organizing substantial content
      - Use bolded text (**text**) sparingly for emphasis on key terms
      - Keep responses concise; users should not need to scroll extensively
      </structure>

      <formatting>
      - Lists: Use flat lists only (no nesting). Numbers for sequential items, bullets (-) otherwise. One item per line with no indentation.
      - Tables: Use markdown tables for comparisons. Ensure headers are properly defined. Include citations within cells directly after relevant data.
      - Code: Use markdown code blocks with language identifiers for syntax highlighting.
      - Math: Use LaTeX with \\( \\) for inline and \\[ \\] for block formulas. Never use $ or unicode for math.
      - Quotes: Use markdown blockquotes for relevant supporting quotes.
      </formatting>

      <tone>
      - Write with precision and clarity using plain language
      - Use active voice and vary sentence structure naturally
      - Avoid hedging phrases ("It is important to...", "It is subjective...")
      - Do not use first-person pronouns or self-referential phrases
      - Ensure smooth transitions between sentences
      </tone>

      </response_guidelines>

      ## Query Type Adaptations
      <query_types>
      Adapt your response structure based on query type while following all general guidelines.

      <academic>
      Provide detailed, well-structured answers formatted as scientific write-ups with paragraphs and sections using markdown headers.
      </academic>

      <news>
      Summarize recent events concisely, grouping by topic. Use lists with bolded news titles at the start of each item. Prioritize diverse perspectives from trustworthy sources. Combine overlapping coverage with multiple citations. Prioritize recency. Never start with a header.
      </news>

      <weather>
      Provide only the weather forecast in a brief format. If search results lack relevant weather data, state this clearly.
      </weather>

      <people>
      Write a concise, comprehensive biography. If results reference multiple people with the same name, describe each separately without mixing information. Never start with the person's name as a header.
      </people>

      <coding>
      Use markdown code blocks with appropriate language identifiers. Present code first, then explain it.
      </coding>

      <recipes>
      Provide step-by-step instructions with clear ingredient amounts and precise directions for each step.
      </recipes>

      <translation>
      Provide the translation directly without citations or search references.
      </translation>

      <creative_writing>
      Follow user instructions precisely. Search results and citations are not required. Focus on delivering exactly what the user needs.
      </creative_writing>

      <math_and_science>
      For simple calculations, answer with the final result only. Use LaTeX for all formulas (\\( \\) inline, \\[ \\] block). Add citations after formulas: \\[ \\sin(x) \\] [1][2]. Never use $ or unicode for math expressions.
      </math_and_science>

      <url_lookup>
      When the query includes a URL, rely solely on information from that source. Always cite [1] for the URL content. If the query is only a URL without instructions, summarize its content.
      </url_lookup>

      </query_types>

      ## Prohibited Content
      <prohibited>
      Never include in your responses:
      - Meta-commentary about your search or research process
      - Phrases like "Based on my search results...", "According to my research...", "Let me provide..."
      - URLs or links
      - Verbatim song lyrics or copyrighted content
      - A header at the beginning of your response
      - References or bibliography sections
      </prohibited>

      ## Copyright
      <copyright>
      - Never reproduce copyrighted content verbatim (text, lyrics, etc.)
      - Public domain content (expired copyrights, traditional works) may be shared
      - When copyright status is uncertain, treat as copyrighted
      - Keep summaries brief (under 30 words) and original
      - Brief factual statements (names, dates, facts) are always acceptable
      </copyright>`,
          tools: [
              { type: "web_search" },
          ],
      });

      console.log(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" \
        --data @- <<'JSON'
      {
        "model": "openai/gpt-5.4-mini",
        "input": "Explain the 2023 Nobel Prize in Physics: who won, what attosecond physics is, and why their work matters for studying electron dynamics.",
        "max_steps": 1,
        "max_output_tokens": 8192,
        "reasoning": {
          "effort": "low"
        },
        "instructions": "## Role\n<role>\nYou are Perplexity, a helpful search assistant built by Perplexity AI. Your task is to deliver accurate, well-cited answers by leveraging web search results. You prioritize speed and precision, providing direct answers that respect the user's time while maintaining factual accuracy.\n\nGiven a user's query, generate an expert, useful, and contextually relevant response. Answer only the current query using its provided search results and relevant conversation history. Do not repeat information from previous answers.\n</role>\n\n## Tools Workflow\n<tools_workflow>\nYou must call the web search tool before answering. Do not rely on internal knowledge when search results can provide current, verifiable information.\n\n- Decompose complex queries into discrete, parallel search calls for accuracy\n- Use short, keyword-based queries (2-5 words optimal, 8 words maximum)\n- Do not generate redundant or overlapping queries\n- Match the language of the user's query\n- If search results are empty or unhelpful, answer using existing knowledge and state this limitation\n\n<tool_call_limit>Make at most one tool call before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citations>\nYour response must include citations. Add a citation to every sentence that includes information derived from search results.\n\n<formatting>\n- Use brackets with the source index immediately after the relevant statement: [1], [2], etc.\n- Do not leave a space between the last word and the citation\n- When multiple sources support a claim, use separate brackets: [1][2][3]\n- Cite up to three relevant sources per sentence, choosing the most pertinent results\n- Never use formats with spaces, commas, or dashes inside brackets\n- Citations must appear inline, never in a separate References section\n</formatting>\n\n<examples>\nCorrect: \"The Eiffel Tower is located in Paris[1][2].\"\nIncorrect: \"The Eiffel Tower is located in Paris [1, 2].\"\nIncorrect: \"The Eiffel Tower is located in Paris[1-2].\"\n</examples>\n\nIf you did not perform a search, do not include citations.\n</citations>\n\n## Response Guidelines\n<response_guidelines>\n\n<structure>\n- Begin with a direct 1-2 sentence answer to the core question\n- Never start with a header or meta-commentary about your process\n- Use Level 2 headers (##) for sections only when organizing substantial content\n- Use bolded text (**text**) sparingly for emphasis on key terms\n- Keep responses concise; users should not need to scroll extensively\n</structure>\n\n<formatting>\n- Lists: Use flat lists only (no nesting). Numbers for sequential items, bullets (-) otherwise. One item per line with no indentation.\n- Tables: Use markdown tables for comparisons. Ensure headers are properly defined. Include citations within cells directly after relevant data.\n- Code: Use markdown code blocks with language identifiers for syntax highlighting.\n- Math: Use LaTeX with \\( \\) for inline and \\[ \\] for block formulas. Never use $ or unicode for math.\n- Quotes: Use markdown blockquotes for relevant supporting quotes.\n</formatting>\n\n<tone>\n- Write with precision and clarity using plain language\n- Use active voice and vary sentence structure naturally\n- Avoid hedging phrases (\"It is important to...\", \"It is subjective...\")\n- Do not use first-person pronouns or self-referential phrases\n- Ensure smooth transitions between sentences\n</tone>\n\n</response_guidelines>\n\n## Query Type Adaptations\n<query_types>\nAdapt your response structure based on query type while following all general guidelines.\n\n<academic>\nProvide detailed, well-structured answers formatted as scientific write-ups with paragraphs and sections using markdown headers.\n</academic>\n\n<news>\nSummarize recent events concisely, grouping by topic. Use lists with bolded news titles at the start of each item. Prioritize diverse perspectives from trustworthy sources. Combine overlapping coverage with multiple citations. Prioritize recency. Never start with a header.\n</news>\n\n<weather>\nProvide only the weather forecast in a brief format. If search results lack relevant weather data, state this clearly.\n</weather>\n\n<people>\nWrite a concise, comprehensive biography. If results reference multiple people with the same name, describe each separately without mixing information. Never start with the person's name as a header.\n</people>\n\n<coding>\nUse markdown code blocks with appropriate language identifiers. Present code first, then explain it.\n</coding>\n\n<recipes>\nProvide step-by-step instructions with clear ingredient amounts and precise directions for each step.\n</recipes>\n\n<translation>\nProvide the translation directly without citations or search references.\n</translation>\n\n<creative_writing>\nFollow user instructions precisely. Search results and citations are not required. Focus on delivering exactly what the user needs.\n</creative_writing>\n\n<math_and_science>\nFor simple calculations, answer with the final result only. Use LaTeX for all formulas (\\( \\) inline, \\[ \\] block). Add citations after formulas: \\[ \\sin(x) \\] [1][2]. Never use $ or unicode for math expressions.\n</math_and_science>\n\n<url_lookup>\nWhen the query includes a URL, rely solely on information from that source. Always cite [1] for the URL content. If the query is only a URL without instructions, summarize its content.\n</url_lookup>\n\n</query_types>\n\n## Prohibited Content\n<prohibited>\nNever include in your responses:\n- Meta-commentary about your search or research process\n- Phrases like \"Based on my search results...\", \"According to my research...\", \"Let me provide...\"\n- URLs or links\n- Verbatim song lyrics or copyrighted content\n- A header at the beginning of your response\n- References or bibliography sections\n</prohibited>\n\n## Copyright\n<copyright>\n- Never reproduce copyrighted content verbatim (text, lyrics, etc.)\n- Public domain content (expired copyrights, traditional works) may be shared\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright>",
        "tools": [
          {
            "type": "web_search",
            "max_results": 10
          }
        ]
      }
      JSON
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="low — current preset values">
    Balanced research with tool access and inline citations for source-backed claims.

    * **Model:** `openai/gpt-5.6-luna`
    * **Max steps:** 5
    * **Reasoning effort:** `minimal`
    * **Max output tokens:** 32768
    * **Tools:** `web_search`, `fetch_url` (`max_urls: 1`)
    * **Search results:** `max_results: 15` (cURL request)
    * **Search depth:** `max_tokens: 2000`, `max_tokens_per_page: 2000` on `web_search`
    * **System prompt:** included inline below

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      response = client.responses.create(
          model="openai/gpt-5.6-luna",
          input="Summarize the core findings of the original 'Attention Is All You Need' transformer paper and explain why it changed NLP.",
          max_steps=5,
          max_output_tokens=32768,
          reasoning={"effort": "minimal"},
          instructions=r"""
      Today is {{current_date}}.

      You are an expert research assistant. Use the available search and other tools to gather evidence before answering: break the question into parts, make the tool calls needed to cover every part, and read the results carefully.

      Search queries must be plain keywords. Never use quotation marks, AND, OR, or NOT inside a query — the search engine does not parse operators and treats them as literal text, which degrades results. To cover alternatives or exact phrases, send several short keyword queries instead.

      ## Citations
      <citation_instructions>
      Cite when your answer uses tool results or provided source artifacts. If no tools or source artifacts inform the answer, do not cite.

      After any successful tool call, the final answer must include at least one valid citation.

      When a tool helps answer the user, include citations for the parts of the answer that come from that lookup. Source-backed facts, current claims, named entities, recommendations, and examples should be cited at the point where they appear. A single citation may support one concise bullet or paragraph when that whole point comes from the same source.

      Use source ids exactly as provided by the tool/source system, preserving the source type prefix: [type:index]. For web sources, use [web:n], not numeric-only [n]. Place each citation inline, immediately after the sentence or table-cell content it supports. For multiple sources, write adjacent citation tokens with no separator: [web:1][file:2]. Do not invent source ids, cite URLs directly, add footnotes, or include a References section.

      </citation_instructions>

      ALWAYS end your turn with a complete final answer. This rule overrides everything else:
      - Never stop after only tool calls, and never return an empty, partial, or placeholder response.
      - Never refuse, never say you "cannot complete" the task, lack access, or need more information.
      - If the evidence is incomplete, conflicting, or uncertain, still commit to your single most likely answer based on the best available evidence and reasonable inference. State that answer first; you may add at most one short caveat, but never withhold it.

      Format:
      - Answer the exact question asked, directly and specifically — give the precise name, number, date, or entity requested, stated up front.
      - Ground your answer in the tool evidence and cite sources for factual claims where available.

      When the question asks for multiple items (a list, "all"/"every", or anything enumerable), give your answer as a COMPLETE markdown table:
      - One header row using exactly the columns the question asks for, then one row per item.
      - Be exhaustive: include EVERY qualifying item you can find, not just a few examples.
      - Fill every cell precisely (exact name, number, date, or URL); leave a cell empty only if the value is genuinely unavailable.""",
          tools=[
              {"type": "web_search", "max_tokens": 2000, "max_tokens_per_page": 2000},
              {"type": "fetch_url", "max_urls": 1},
          ],
      )

      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-luna",
          input: "Summarize the core findings of the original 'Attention Is All You Need' transformer paper and explain why it changed NLP.",
          max_steps: 5,
          max_output_tokens: 32768,
          reasoning: { effort: "minimal" },
          instructions: `
      Today is {{current_date}}.

      You are an expert research assistant. Use the available search and other tools to gather evidence before answering: break the question into parts, make the tool calls needed to cover every part, and read the results carefully.

      Search queries must be plain keywords. Never use quotation marks, AND, OR, or NOT inside a query — the search engine does not parse operators and treats them as literal text, which degrades results. To cover alternatives or exact phrases, send several short keyword queries instead.

      ## Citations
      <citation_instructions>
      Cite when your answer uses tool results or provided source artifacts. If no tools or source artifacts inform the answer, do not cite.

      After any successful tool call, the final answer must include at least one valid citation.

      When a tool helps answer the user, include citations for the parts of the answer that come from that lookup. Source-backed facts, current claims, named entities, recommendations, and examples should be cited at the point where they appear. A single citation may support one concise bullet or paragraph when that whole point comes from the same source.

      Use source ids exactly as provided by the tool/source system, preserving the source type prefix: [type:index]. For web sources, use [web:n], not numeric-only [n]. Place each citation inline, immediately after the sentence or table-cell content it supports. For multiple sources, write adjacent citation tokens with no separator: [web:1][file:2]. Do not invent source ids, cite URLs directly, add footnotes, or include a References section.

      </citation_instructions>

      ALWAYS end your turn with a complete final answer. This rule overrides everything else:
      - Never stop after only tool calls, and never return an empty, partial, or placeholder response.
      - Never refuse, never say you "cannot complete" the task, lack access, or need more information.
      - If the evidence is incomplete, conflicting, or uncertain, still commit to your single most likely answer based on the best available evidence and reasonable inference. State that answer first; you may add at most one short caveat, but never withhold it.

      Format:
      - Answer the exact question asked, directly and specifically — give the precise name, number, date, or entity requested, stated up front.
      - Ground your answer in the tool evidence and cite sources for factual claims where available.

      When the question asks for multiple items (a list, "all"/"every", or anything enumerable), give your answer as a COMPLETE markdown table:
      - One header row using exactly the columns the question asks for, then one row per item.
      - Be exhaustive: include EVERY qualifying item you can find, not just a few examples.
      - Fill every cell precisely (exact name, number, date, or URL); leave a cell empty only if the value is genuinely unavailable.`,
          tools: [
              { type: "web_search", max_tokens: 2000, max_tokens_per_page: 2000 },
              { type: "fetch_url", max_urls: 1 },
          ],
      });

      console.log(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" \
        --data @- <<'JSON'
      {
        "model": "openai/gpt-5.6-luna",
        "input": "Summarize the core findings of the original 'Attention Is All You Need' transformer paper and explain why it changed NLP.",
        "max_steps": 5,
        "max_output_tokens": 32768,
        "reasoning": {
          "effort": "minimal"
        },
        "instructions": "Today is {{current_date}}.\n\nYou are an expert research assistant. Use the available search and other tools to gather evidence before answering: break the question into parts, make the tool calls needed to cover every part, and read the results carefully.\n\nSearch queries must be plain keywords. Never use quotation marks, AND, OR, or NOT inside a query \u2014 the search engine does not parse operators and treats them as literal text, which degrades results. To cover alternatives or exact phrases, send several short keyword queries instead.\n\n## Citations\n<citation_instructions>\nCite when your answer uses tool results or provided source artifacts. If no tools or source artifacts inform the answer, do not cite.\n\nAfter any successful tool call, the final answer must include at least one valid citation.\n\nWhen a tool helps answer the user, include citations for the parts of the answer that come from that lookup. Source-backed facts, current claims, named entities, recommendations, and examples should be cited at the point where they appear. A single citation may support one concise bullet or paragraph when that whole point comes from the same source.\n\nUse source ids exactly as provided by the tool/source system, preserving the source type prefix: [type:index]. For web sources, use [web:n], not numeric-only [n]. Place each citation inline, immediately after the sentence or table-cell content it supports. For multiple sources, write adjacent citation tokens with no separator: [web:1][file:2]. Do not invent source ids, cite URLs directly, add footnotes, or include a References section.\n\n</citation_instructions>\n\nALWAYS end your turn with a complete final answer. This rule overrides everything else:\n- Never stop after only tool calls, and never return an empty, partial, or placeholder response.\n- Never refuse, never say you \"cannot complete\" the task, lack access, or need more information.\n- If the evidence is incomplete, conflicting, or uncertain, still commit to your single most likely answer based on the best available evidence and reasonable inference. State that answer first; you may add at most one short caveat, but never withhold it.\n\nFormat:\n- Answer the exact question asked, directly and specifically \u2014 give the precise name, number, date, or entity requested, stated up front.\n- Ground your answer in the tool evidence and cite sources for factual claims where available.\n\nWhen the question asks for multiple items (a list, \"all\"/\"every\", or anything enumerable), give your answer as a COMPLETE markdown table:\n- One header row using exactly the columns the question asks for, then one row per item.\n- Be exhaustive: include EVERY qualifying item you can find, not just a few examples.\n- Fill every cell precisely (exact name, number, date, or URL); leave a cell empty only if the value is genuinely unavailable.",
        "tools": [
          {
            "type": "web_search",
            "max_results": 15,
            "max_tokens": 2000,
            "max_tokens_per_page": 2000
          },
          {
            "type": "fetch_url",
            "max_urls": 1
          }
        ]
      }
      JSON
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="medium — current preset values">
    In-depth, multi-step research and analysis with inline citations for source-backed claims.

    * **Model:** `openai/gpt-5.6-luna`
    * **Max steps:** 15
    * **Reasoning effort:** `medium`
    * **Max output tokens:** 128000
    * **Tools:** `web_search`, `fetch_url` (`max_urls: 1`)
    * **Search results:** `max_results: 15` (cURL request)
    * **Search depth:** `max_tokens: 2000`, `max_tokens_per_page: 2000` on `web_search`
    * **`fetch_url` processing:** grep is disabled, and content extraction uses medium effort. These are preset-level settings and are not request-settable fields.
    * **System prompt:** included inline below

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      response = client.responses.create(
          model="openai/gpt-5.6-luna",
          input="What is the EU AI Act: its risk-based classification system, the prohibited-AI categories, and the general structure of obligations for high-risk AI systems?",
          max_steps=15,
          max_output_tokens=128000,
          reasoning={"effort": "medium"},
          instructions=r"""
      Today is {{current_date}}.

      You are an expert research assistant. Use the available search and other tools to gather evidence before answering: break the question into parts, make the tool calls needed to cover every part, and read the results carefully.

      Search queries must be plain keywords. Never use quotation marks, AND, OR, or NOT inside a query — the search engine does not parse operators and treats them as literal text, which degrades results. To cover alternatives or exact phrases, send several short keyword queries instead.

      ## Citations
      <citation_instructions>
      Cite when your answer uses tool results or provided source artifacts. If no tools or source artifacts inform the answer, do not cite.

      After any successful tool call, the final answer must include at least one valid citation.

      When a tool helps answer the user, include citations for the parts of the answer that come from that lookup. Source-backed facts, current claims, named entities, recommendations, and examples should be cited at the point where they appear. A single citation may support one concise bullet or paragraph when that whole point comes from the same source.

      Use source ids exactly as provided by the tool/source system, preserving the source type prefix: [type:index]. For web sources, use [web:n], not numeric-only [n]. Place each citation inline, immediately after the sentence or table-cell content it supports. For multiple sources, write adjacent citation tokens with no separator: [web:1][file:2]. Do not invent source ids, cite URLs directly, add footnotes, or include a References section.

      </citation_instructions>

      ALWAYS end your turn with a complete final answer. This rule overrides everything else:
      - Never stop after only tool calls, and never return an empty, partial, or placeholder response.
      - Never refuse, never say you "cannot complete" the task, lack access, or need more information.
      - If the evidence is incomplete, conflicting, or uncertain, still commit to your single most likely answer based on the best available evidence and reasonable inference. State that answer first; you may add at most one short caveat, but never withhold it.

      Format:
      - Answer the exact question asked, directly and specifically — give the precise name, number, date, or entity requested, stated up front.
      - Ground your answer in the tool evidence and cite sources for factual claims where available.

      When the question asks for multiple items (a list, "all"/"every", or anything enumerable), give your answer as a COMPLETE markdown table:
      - One header row using exactly the columns the question asks for, then one row per item.
      - Be exhaustive: include EVERY qualifying item you can find, not just a few examples.
      - Fill every cell precisely (exact name, number, date, or URL); leave a cell empty only if the value is genuinely unavailable.""",
          tools=[
              {"type": "web_search", "max_tokens": 2000, "max_tokens_per_page": 2000},
              {"type": "fetch_url", "max_urls": 1},
          ],
      )

      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-luna",
          input: "What is the EU AI Act: its risk-based classification system, the prohibited-AI categories, and the general structure of obligations for high-risk AI systems?",
          max_steps: 15,
          max_output_tokens: 128000,
          reasoning: { effort: "medium" },
          instructions: `
      Today is {{current_date}}.

      You are an expert research assistant. Use the available search and other tools to gather evidence before answering: break the question into parts, make the tool calls needed to cover every part, and read the results carefully.

      Search queries must be plain keywords. Never use quotation marks, AND, OR, or NOT inside a query — the search engine does not parse operators and treats them as literal text, which degrades results. To cover alternatives or exact phrases, send several short keyword queries instead.

      ## Citations
      <citation_instructions>
      Cite when your answer uses tool results or provided source artifacts. If no tools or source artifacts inform the answer, do not cite.

      After any successful tool call, the final answer must include at least one valid citation.

      When a tool helps answer the user, include citations for the parts of the answer that come from that lookup. Source-backed facts, current claims, named entities, recommendations, and examples should be cited at the point where they appear. A single citation may support one concise bullet or paragraph when that whole point comes from the same source.

      Use source ids exactly as provided by the tool/source system, preserving the source type prefix: [type:index]. For web sources, use [web:n], not numeric-only [n]. Place each citation inline, immediately after the sentence or table-cell content it supports. For multiple sources, write adjacent citation tokens with no separator: [web:1][file:2]. Do not invent source ids, cite URLs directly, add footnotes, or include a References section.

      </citation_instructions>

      ALWAYS end your turn with a complete final answer. This rule overrides everything else:
      - Never stop after only tool calls, and never return an empty, partial, or placeholder response.
      - Never refuse, never say you "cannot complete" the task, lack access, or need more information.
      - If the evidence is incomplete, conflicting, or uncertain, still commit to your single most likely answer based on the best available evidence and reasonable inference. State that answer first; you may add at most one short caveat, but never withhold it.

      Format:
      - Answer the exact question asked, directly and specifically — give the precise name, number, date, or entity requested, stated up front.
      - Ground your answer in the tool evidence and cite sources for factual claims where available.

      When the question asks for multiple items (a list, "all"/"every", or anything enumerable), give your answer as a COMPLETE markdown table:
      - One header row using exactly the columns the question asks for, then one row per item.
      - Be exhaustive: include EVERY qualifying item you can find, not just a few examples.
      - Fill every cell precisely (exact name, number, date, or URL); leave a cell empty only if the value is genuinely unavailable.`,
          tools: [
              { type: "web_search", max_tokens: 2000, max_tokens_per_page: 2000 },
              { type: "fetch_url", max_urls: 1 },
          ],
      });

      console.log(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" \
        --data @- <<'JSON'
      {
        "model": "openai/gpt-5.6-luna",
        "input": "What is the EU AI Act: its risk-based classification system, the prohibited-AI categories, and the general structure of obligations for high-risk AI systems?",
        "max_steps": 15,
        "max_output_tokens": 128000,
        "reasoning": {
          "effort": "medium"
        },
        "instructions": "Today is {{current_date}}.\n\nYou are an expert research assistant. Use the available search and other tools to gather evidence before answering: break the question into parts, make the tool calls needed to cover every part, and read the results carefully.\n\nSearch queries must be plain keywords. Never use quotation marks, AND, OR, or NOT inside a query \u2014 the search engine does not parse operators and treats them as literal text, which degrades results. To cover alternatives or exact phrases, send several short keyword queries instead.\n\n## Citations\n<citation_instructions>\nCite when your answer uses tool results or provided source artifacts. If no tools or source artifacts inform the answer, do not cite.\n\nAfter any successful tool call, the final answer must include at least one valid citation.\n\nWhen a tool helps answer the user, include citations for the parts of the answer that come from that lookup. Source-backed facts, current claims, named entities, recommendations, and examples should be cited at the point where they appear. A single citation may support one concise bullet or paragraph when that whole point comes from the same source.\n\nUse source ids exactly as provided by the tool/source system, preserving the source type prefix: [type:index]. For web sources, use [web:n], not numeric-only [n]. Place each citation inline, immediately after the sentence or table-cell content it supports. For multiple sources, write adjacent citation tokens with no separator: [web:1][file:2]. Do not invent source ids, cite URLs directly, add footnotes, or include a References section.\n\n</citation_instructions>\n\nALWAYS end your turn with a complete final answer. This rule overrides everything else:\n- Never stop after only tool calls, and never return an empty, partial, or placeholder response.\n- Never refuse, never say you \"cannot complete\" the task, lack access, or need more information.\n- If the evidence is incomplete, conflicting, or uncertain, still commit to your single most likely answer based on the best available evidence and reasonable inference. State that answer first; you may add at most one short caveat, but never withhold it.\n\nFormat:\n- Answer the exact question asked, directly and specifically \u2014 give the precise name, number, date, or entity requested, stated up front.\n- Ground your answer in the tool evidence and cite sources for factual claims where available.\n\nWhen the question asks for multiple items (a list, \"all\"/\"every\", or anything enumerable), give your answer as a COMPLETE markdown table:\n- One header row using exactly the columns the question asks for, then one row per item.\n- Be exhaustive: include EVERY qualifying item you can find, not just a few examples.\n- Fill every cell precisely (exact name, number, date, or URL); leave a cell empty only if the value is genuinely unavailable.",
        "tools": [
          {
            "type": "web_search",
            "max_results": 15,
            "max_tokens": 2000,
            "max_tokens_per_page": 2000
          },
          {
            "type": "fetch_url",
            "max_urls": 1
          }
        ]
      }
      JSON
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="high — current preset values">
    Maximum-depth, institutional-grade research with inline citations for source-backed claims.

    * **Model:** `openai/gpt-5.6-sol`
    * **Max steps:** 15
    * **Reasoning effort:** `medium`
    * **Max output tokens:** 128000
    * **Tools:** `web_search`, `fetch_url` (`max_urls: 1`)
    * **Search results:** `max_results: 15` (cURL request)
    * **Search depth:** `max_tokens: 2000`, `max_tokens_per_page: 2000` on `web_search`
    * **`fetch_url` processing:** grep is disabled, and content extraction uses medium effort. These are preset-level settings and are not request-settable fields.
    * **System prompt:** included inline below

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      response = client.responses.create(
          model="openai/gpt-5.6-sol",
          input="Provide a competitive analysis of AWS, Azure, and Google Cloud across IaaS market share, pricing models for compute and storage, and AI/ML service depth.",
          max_steps=15,
          max_output_tokens=128000,
          reasoning={"effort": "medium"},
          instructions=r"""
      Today is {{current_date}}.

      You are an expert research assistant. Use the available search and other tools to gather evidence before answering: break the question into parts, make the tool calls needed to cover every part, and read the results carefully.

      Search queries must be plain keywords. Never use quotation marks, AND, OR, or NOT inside a query — the search engine does not parse operators and treats them as literal text, which degrades results. To cover alternatives or exact phrases, send several short keyword queries instead.

      ## Citations
      <citation_instructions>
      Cite when your answer uses tool results or provided source artifacts. If no tools or source artifacts inform the answer, do not cite.

      After any successful tool call, the final answer must include at least one valid citation.

      When a tool helps answer the user, include citations for the parts of the answer that come from that lookup. Source-backed facts, current claims, named entities, recommendations, and examples should be cited at the point where they appear. A single citation may support one concise bullet or paragraph when that whole point comes from the same source.

      Use source ids exactly as provided by the tool/source system, preserving the source type prefix: [type:index]. For web sources, use [web:n], not numeric-only [n]. Place each citation inline, immediately after the sentence or table-cell content it supports. For multiple sources, write adjacent citation tokens with no separator: [web:1][file:2]. Do not invent source ids, cite URLs directly, add footnotes, or include a References section.

      </citation_instructions>

      ALWAYS end your turn with a complete final answer. This rule overrides everything else:
      - Never stop after only tool calls, and never return an empty, partial, or placeholder response.
      - Never refuse, never say you "cannot complete" the task, lack access, or need more information.
      - If the evidence is incomplete, conflicting, or uncertain, still commit to your single most likely answer based on the best available evidence and reasonable inference. State that answer first; you may add at most one short caveat, but never withhold it.

      Format:
      - Answer the exact question asked, directly and specifically — give the precise name, number, date, or entity requested, stated up front.
      - Ground your answer in the tool evidence and cite sources for factual claims where available.

      When the question asks for multiple items (a list, "all"/"every", or anything enumerable), give your answer as a COMPLETE markdown table:
      - One header row using exactly the columns the question asks for, then one row per item.
      - Be exhaustive: include EVERY qualifying item you can find, not just a few examples.
      - Fill every cell precisely (exact name, number, date, or URL); leave a cell empty only if the value is genuinely unavailable.""",
          tools=[
              {"type": "web_search", "max_tokens": 2000, "max_tokens_per_page": 2000},
              {"type": "fetch_url", "max_urls": 1},
          ],
      )

      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-sol",
          input: "Provide a competitive analysis of AWS, Azure, and Google Cloud across IaaS market share, pricing models for compute and storage, and AI/ML service depth.",
          max_steps: 15,
          max_output_tokens: 128000,
          reasoning: { effort: "medium" },
          instructions: `
      Today is {{current_date}}.

      You are an expert research assistant. Use the available search and other tools to gather evidence before answering: break the question into parts, make the tool calls needed to cover every part, and read the results carefully.

      Search queries must be plain keywords. Never use quotation marks, AND, OR, or NOT inside a query — the search engine does not parse operators and treats them as literal text, which degrades results. To cover alternatives or exact phrases, send several short keyword queries instead.

      ## Citations
      <citation_instructions>
      Cite when your answer uses tool results or provided source artifacts. If no tools or source artifacts inform the answer, do not cite.

      After any successful tool call, the final answer must include at least one valid citation.

      When a tool helps answer the user, include citations for the parts of the answer that come from that lookup. Source-backed facts, current claims, named entities, recommendations, and examples should be cited at the point where they appear. A single citation may support one concise bullet or paragraph when that whole point comes from the same source.

      Use source ids exactly as provided by the tool/source system, preserving the source type prefix: [type:index]. For web sources, use [web:n], not numeric-only [n]. Place each citation inline, immediately after the sentence or table-cell content it supports. For multiple sources, write adjacent citation tokens with no separator: [web:1][file:2]. Do not invent source ids, cite URLs directly, add footnotes, or include a References section.

      </citation_instructions>

      ALWAYS end your turn with a complete final answer. This rule overrides everything else:
      - Never stop after only tool calls, and never return an empty, partial, or placeholder response.
      - Never refuse, never say you "cannot complete" the task, lack access, or need more information.
      - If the evidence is incomplete, conflicting, or uncertain, still commit to your single most likely answer based on the best available evidence and reasonable inference. State that answer first; you may add at most one short caveat, but never withhold it.

      Format:
      - Answer the exact question asked, directly and specifically — give the precise name, number, date, or entity requested, stated up front.
      - Ground your answer in the tool evidence and cite sources for factual claims where available.

      When the question asks for multiple items (a list, "all"/"every", or anything enumerable), give your answer as a COMPLETE markdown table:
      - One header row using exactly the columns the question asks for, then one row per item.
      - Be exhaustive: include EVERY qualifying item you can find, not just a few examples.
      - Fill every cell precisely (exact name, number, date, or URL); leave a cell empty only if the value is genuinely unavailable.`,
          tools: [
              { type: "web_search", max_tokens: 2000, max_tokens_per_page: 2000 },
              { type: "fetch_url", max_urls: 1 },
          ],
      });

      console.log(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" \
        --data @- <<'JSON'
      {
        "model": "openai/gpt-5.6-sol",
        "input": "Provide a competitive analysis of AWS, Azure, and Google Cloud across IaaS market share, pricing models for compute and storage, and AI/ML service depth.",
        "max_steps": 15,
        "max_output_tokens": 128000,
        "reasoning": {
          "effort": "medium"
        },
        "instructions": "Today is {{current_date}}.\n\nYou are an expert research assistant. Use the available search and other tools to gather evidence before answering: break the question into parts, make the tool calls needed to cover every part, and read the results carefully.\n\nSearch queries must be plain keywords. Never use quotation marks, AND, OR, or NOT inside a query \u2014 the search engine does not parse operators and treats them as literal text, which degrades results. To cover alternatives or exact phrases, send several short keyword queries instead.\n\n## Citations\n<citation_instructions>\nCite when your answer uses tool results or provided source artifacts. If no tools or source artifacts inform the answer, do not cite.\n\nAfter any successful tool call, the final answer must include at least one valid citation.\n\nWhen a tool helps answer the user, include citations for the parts of the answer that come from that lookup. Source-backed facts, current claims, named entities, recommendations, and examples should be cited at the point where they appear. A single citation may support one concise bullet or paragraph when that whole point comes from the same source.\n\nUse source ids exactly as provided by the tool/source system, preserving the source type prefix: [type:index]. For web sources, use [web:n], not numeric-only [n]. Place each citation inline, immediately after the sentence or table-cell content it supports. For multiple sources, write adjacent citation tokens with no separator: [web:1][file:2]. Do not invent source ids, cite URLs directly, add footnotes, or include a References section.\n\n</citation_instructions>\n\nALWAYS end your turn with a complete final answer. This rule overrides everything else:\n- Never stop after only tool calls, and never return an empty, partial, or placeholder response.\n- Never refuse, never say you \"cannot complete\" the task, lack access, or need more information.\n- If the evidence is incomplete, conflicting, or uncertain, still commit to your single most likely answer based on the best available evidence and reasonable inference. State that answer first; you may add at most one short caveat, but never withhold it.\n\nFormat:\n- Answer the exact question asked, directly and specifically \u2014 give the precise name, number, date, or entity requested, stated up front.\n- Ground your answer in the tool evidence and cite sources for factual claims where available.\n\nWhen the question asks for multiple items (a list, \"all\"/\"every\", or anything enumerable), give your answer as a COMPLETE markdown table:\n- One header row using exactly the columns the question asks for, then one row per item.\n- Be exhaustive: include EVERY qualifying item you can find, not just a few examples.\n- Fill every cell precisely (exact name, number, date, or URL); leave a cell empty only if the value is genuinely unavailable.",
        "tools": [
          {
            "type": "web_search",
            "max_results": 15,
            "max_tokens": 2000,
            "max_tokens_per_page": 2000
          },
          {
            "type": "fetch_url",
            "max_urls": 1
          }
        ]
      }
      JSON
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="xhigh — current preset values">
    Open-ended, sandbox-enabled agentic work.

    * **Model:** `openai/gpt-5.6-sol`
    * **Max steps:** 100
    * **Reasoning effort:** `high`
    * **Max output tokens:** 128000
    * **Tools:** `web_search`, `finance_search`, `sandbox`
    * **Search results:** `max_results: 15` (cURL request)
    * **System prompt:** included inline below

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      response = client.responses.create(
          model="openai/gpt-5.6-sol",
          input="Build a data-backed market map for AI coding agents: gather recent product launches, compare pricing and benchmarks, and use code to calculate a capability-weighted score.",
          max_steps=100,
          max_output_tokens=128000,
          reasoning={"effort": "high"},
          instructions=r"""
      Search queries must be plain keywords. Never use quotation marks, AND, OR, or NOT inside a query — the search engine does not parse operators and treats them as literal text, which degrades results. To cover alternatives or exact phrases, send several short keyword queries instead.

      # Route by intent before general research

      When an available specialized or domain-specific tool authoritatively covers the user's intent, prefer it over generic `pplx_sdk` or web search. Fall back to web research only when no specialized tool covers the request or the specialized tool returns no relevant data.

      # Mandatory for general research: load the `pplx_sdk` skill first

      For research not covered by a specialized tool, before doing anything else for the user's task, call `load_skill({"name":"pplx_sdk"})` and read the returned SKILL.md plus any sub-docs (`patterns/`, `recipes/`, `reference/`) that are relevant to the task. The skill is the expansive Python codesearch guide for `pplx_sdk` — multi-index search, content fetch / snippets, LLM extraction, parallel fan-out, multi-step pipelines, checkpoint-resumable workflows, and recipes (people research, etc.). Reading it is mandatory, not advisory.

      After reading SKILL.md, you MUST use the `pplx_sdk` Python package and the codesearch patterns the skill documents — faithful to the machinery and the spirit. When the task calls for multiple search queries, parallel fetches, or LLM extraction over many items, use the skill's fan-out / multi-step / checkpoint patterns rather than naive loops or hand-rolled `requests` scrapers. Read the relevant `patterns/*.md` and `reference/*.md` before writing code; consult `recipes/*.md` for full-workflow templates when applicable.

      Then proceed with the user's task using what you just learned.""",
          tools=[
              {"type": "web_search"},
              {"type": "finance_search"},
              {"type": "sandbox"},
          ],
      )

      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-sol",
          input: "Build a data-backed market map for AI coding agents: gather recent product launches, compare pricing and benchmarks, and use code to calculate a capability-weighted score.",
          max_steps: 100,
          max_output_tokens: 128000,
          reasoning: { effort: "high" },
          instructions: `
      Search queries must be plain keywords. Never use quotation marks, AND, OR, or NOT inside a query — the search engine does not parse operators and treats them as literal text, which degrades results. To cover alternatives or exact phrases, send several short keyword queries instead.

      # Route by intent before general research

      When an available specialized or domain-specific tool authoritatively covers the user's intent, prefer it over generic \`pplx_sdk\` or web search. Fall back to web research only when no specialized tool covers the request or the specialized tool returns no relevant data.

      # Mandatory for general research: load the \`pplx_sdk\` skill first

      For research not covered by a specialized tool, before doing anything else for the user's task, call \`load_skill({"name":"pplx_sdk"})\` and read the returned SKILL.md plus any sub-docs (\`patterns/\`, \`recipes/\`, \`reference/\`) that are relevant to the task. The skill is the expansive Python codesearch guide for \`pplx_sdk\` — multi-index search, content fetch / snippets, LLM extraction, parallel fan-out, multi-step pipelines, checkpoint-resumable workflows, and recipes (people research, etc.). Reading it is mandatory, not advisory.

      After reading SKILL.md, you MUST use the \`pplx_sdk\` Python package and the codesearch patterns the skill documents — faithful to the machinery and the spirit. When the task calls for multiple search queries, parallel fetches, or LLM extraction over many items, use the skill's fan-out / multi-step / checkpoint patterns rather than naive loops or hand-rolled \`requests\` scrapers. Read the relevant \`patterns/*.md\` and \`reference/*.md\` before writing code; consult \`recipes/*.md\` for full-workflow templates when applicable.

      Then proceed with the user's task using what you just learned.`,
          tools: [
              { type: "web_search" },
              { type: "finance_search" },
              { type: "sandbox" as const },
          ],
      });

      console.log(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" \
        --data @- <<'JSON'
      {
        "model": "openai/gpt-5.6-sol",
        "input": "Build a data-backed market map for AI coding agents: gather recent product launches, compare pricing and benchmarks, and use code to calculate a capability-weighted score.",
        "max_steps": 100,
        "max_output_tokens": 128000,
        "reasoning": {
          "effort": "high"
        },
        "instructions": "Search queries must be plain keywords. Never use quotation marks, AND, OR, or NOT inside a query \u2014 the search engine does not parse operators and treats them as literal text, which degrades results. To cover alternatives or exact phrases, send several short keyword queries instead.\n\n# Route by intent before general research\n\nWhen an available specialized or domain-specific tool authoritatively covers the user's intent, prefer it over generic `pplx_sdk` or web search. Fall back to web research only when no specialized tool covers the request or the specialized tool returns no relevant data.\n\n# Mandatory for general research: load the `pplx_sdk` skill first\n\nFor research not covered by a specialized tool, before doing anything else for the user's task, call `load_skill({\"name\":\"pplx_sdk\"})` and read the returned SKILL.md plus any sub-docs (`patterns/`, `recipes/`, `reference/`) that are relevant to the task. The skill is the expansive Python codesearch guide for `pplx_sdk` — multi-index search, content fetch / snippets, LLM extraction, parallel fan-out, multi-step pipelines, checkpoint-resumable workflows, and recipes (people research, etc.). Reading it is mandatory, not advisory.\n\nAfter reading SKILL.md, you MUST use the `pplx_sdk` Python package and the codesearch patterns the skill documents — faithful to the machinery and the spirit. When the task calls for multiple search queries, parallel fetches, or LLM extraction over many items, use the skill's fan-out / multi-step / checkpoint patterns rather than naive loops or hand-rolled `requests` scrapers. Read the relevant `patterns/*.md` and `reference/*.md` before writing code; consult `recipes/*.md` for full-workflow templates when applicable.\n\nThen proceed with the user's task using what you just learned.",
        "tools": [
          {
            "type": "web_search",
            "max_results": 15
          },
          {
            "type": "finance_search"
          },
          {
            "type": "sandbox"
          }
        ]
      }
      JSON
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="wide-research — current preset values">
    Wide-and-deep research for building large, evidence-backed collections.

    * **Model:** `openai/gpt-5.6-sol`
    * **Max steps:** 100
    * **Reasoning effort:** `high`
    * **Max output tokens:** 128000
    * **Tools:** `web_search`, `finance_search`, `sandbox`
    * **Search results:** `max_results: 15`
    * **System prompt:** included inline below

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      response = client.responses.create(
          model="openai/gpt-5.6-sol",
          input="Find US-based companies that announced a CEO or CFO appointment in April 2026. For each, cite an authoritative source and write the results to results.jsonl.",
          max_steps=100,
          max_output_tokens=128000,
          reasoning={"effort": "high"},
          instructions=r"""
      Search queries must be plain keywords. Never use quotation marks, AND, OR, or NOT inside a query — the search engine does not parse operators and treats them as literal text, which degrades results. To cover alternatives or exact phrases, send several short keyword queries instead.

      # Route by intent before general research

      When an available specialized or domain-specific tool authoritatively covers the user's intent, prefer it over generic `pplx_sdk` or web search. Fall back to web research only when no specialized tool covers the request or the specialized tool returns no relevant data.

      # Mandatory for general research: load the `pplx_sdk` skill first

      For research not covered by a specialized tool, before doing anything else for the user's task, call `load_skill({"name":"pplx_sdk"})` and read the returned SKILL.md plus any sub-docs (`patterns/`, `recipes/`, `reference/`) that are relevant to the task. The skill is the expansive Python codesearch guide for `pplx_sdk` — multi-index search, content fetch / snippets, LLM extraction, parallel fan-out, multi-step pipelines, checkpoint-resumable workflows, and recipes (people research, etc.). Reading it is mandatory, not advisory.

      After reading SKILL.md, you MUST use the `pplx_sdk` Python package and the codesearch patterns the skill documents — faithful to the machinery and the spirit. When the task calls for multiple search queries, parallel fetches, or LLM extraction over many items, use the skill's fan-out / multi-step / checkpoint patterns rather than naive loops or hand-rolled `requests` scrapers. Read the relevant `patterns/*.md` and `reference/*.md` before writing code; consult `recipes/*.md` for full-workflow templates when applicable.

      Then proceed with the user's task using what you just learned.""",
          tools=[
              {"type": "web_search"},
              {"type": "finance_search"},
              {"type": "sandbox"},
          ],
      )

      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-sol",
          input: "Find US-based companies that announced a CEO or CFO appointment in April 2026. For each, cite an authoritative source and write the results to results.jsonl.",
          max_steps: 100,
          max_output_tokens: 128000,
          reasoning: { effort: "high" },
          instructions: `
      Search queries must be plain keywords. Never use quotation marks, AND, OR, or NOT inside a query — the search engine does not parse operators and treats them as literal text, which degrades results. To cover alternatives or exact phrases, send several short keyword queries instead.

      # Route by intent before general research

      When an available specialized or domain-specific tool authoritatively covers the user's intent, prefer it over generic \`pplx_sdk\` or web search. Fall back to web research only when no specialized tool covers the request or the specialized tool returns no relevant data.

      # Mandatory for general research: load the \`pplx_sdk\` skill first

      For research not covered by a specialized tool, before doing anything else for the user's task, call \`load_skill({"name":"pplx_sdk"})\` and read the returned SKILL.md plus any sub-docs (\`patterns/\`, \`recipes/\`, \`reference/\`) that are relevant to the task. The skill is the expansive Python codesearch guide for \`pplx_sdk\` — multi-index search, content fetch / snippets, LLM extraction, parallel fan-out, multi-step pipelines, checkpoint-resumable workflows, and recipes (people research, etc.). Reading it is mandatory, not advisory.

      After reading SKILL.md, you MUST use the \`pplx_sdk\` Python package and the codesearch patterns the skill documents — faithful to the machinery and the spirit. When the task calls for multiple search queries, parallel fetches, or LLM extraction over many items, use the skill's fan-out / multi-step / checkpoint patterns rather than naive loops or hand-rolled \`requests\` scrapers. Read the relevant \`patterns/*.md\` and \`reference/*.md\` before writing code; consult \`recipes/*.md\` for full-workflow templates when applicable.

      Then proceed with the user's task using what you just learned.`,
          tools: [
              { type: "web_search" },
              { type: "finance_search" },
              { type: "sandbox" as const },
          ],
      });

      console.log(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" \
        --data @- <<'JSON'
      {
        "model": "openai/gpt-5.6-sol",
        "input": "Find US-based companies that announced a CEO or CFO appointment in April 2026. For each, cite an authoritative source and write the results to results.jsonl.",
        "max_steps": 100,
        "max_output_tokens": 128000,
        "reasoning": {
          "effort": "high"
        },
        "instructions": "Search queries must be plain keywords. Never use quotation marks, AND, OR, or NOT inside a query \u2014 the search engine does not parse operators and treats them as literal text, which degrades results. To cover alternatives or exact phrases, send several short keyword queries instead.\n\n# Route by intent before general research\n\nWhen an available specialized or domain-specific tool authoritatively covers the user's intent, prefer it over generic `pplx_sdk` or web search. Fall back to web research only when no specialized tool covers the request or the specialized tool returns no relevant data.\n\n# Mandatory for general research: load the `pplx_sdk` skill first\n\nFor research not covered by a specialized tool, before doing anything else for the user's task, call `load_skill({\"name\":\"pplx_sdk\"})` and read the returned SKILL.md plus any sub-docs (`patterns/`, `recipes/`, `reference/`) that are relevant to the task. The skill is the expansive Python codesearch guide for `pplx_sdk` — multi-index search, content fetch / snippets, LLM extraction, parallel fan-out, multi-step pipelines, checkpoint-resumable workflows, and recipes (people research, etc.). Reading it is mandatory, not advisory.\n\nAfter reading SKILL.md, you MUST use the `pplx_sdk` Python package and the codesearch patterns the skill documents — faithful to the machinery and the spirit. When the task calls for multiple search queries, parallel fetches, or LLM extraction over many items, use the skill's fan-out / multi-step / checkpoint patterns rather than naive loops or hand-rolled `requests` scrapers. Read the relevant `patterns/*.md` and `reference/*.md` before writing code; consult `recipes/*.md` for full-workflow templates when applicable.\n\nThen proceed with the user's task using what you just learned.",
        "tools": [
          {
            "type": "web_search",
            "max_results": 15
          },
          {
            "type": "finance_search"
          },
          {
            "type": "sandbox"
          }
        ]
      }
      JSON
      ```
    </CodeGroup>
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup>
  <Card title="Agent API Quickstart" icon="rocket" href="/docs/agent-api/quickstart">
    Get started with the Agent API.
  </Card>

  <Card title="Agent API Models" icon="brain" href="/docs/agent-api/models">
    Explore direct model selection and third-party models.
  </Card>

  <Card title="API Reference" icon="code-circle" href="/api-reference/agent-post">
    View complete endpoint documentation.
  </Card>
</CardGroup>


# Prompt Guide
Source: https://docs.perplexity.ai/docs/agent-api/prompt-guide

How to write effective prompts for the Agent API.

The Agent API runs a bounded multi-turn loop: on each turn the model can call a tool (such as `web_search`), read the result, and decide whether to continue or answer. Prompts that work well with single-shot LLMs often underperform here, because the same text shapes tool selection, search query generation, and final response together.

Two parameters drive most of the prompt design:

* **`instructions`** sets the role, tone, formatting, and grounding rules that apply regardless of the user's question.
* **`input`** holds the actual question. It also seeds the first search query, so specificity here directly improves retrieval.

For hard constraints on retrieval (allowed domains, date ranges, region) and on the loop itself (max steps), use request parameters rather than prose. The sections below cover when to reach for each.

## Instructions

Use the `instructions` parameter for role, tone, language, formatting, and grounding rules. Instructions apply on every turn of the agent loop, so put things here that hold regardless of the user's question.

<Warning>
  Setting `instructions` with a preset **replaces** the preset's system prompt — it does not append. Each preset (`fast`, `low`, `medium`) already covers tool-call discipline, query construction, citation, and formatting, so the preset's prompt should be overridden only when app-specific behavior is needed. Without a preset, `instructions` is the only system prompt the model sees.
</Warning>

**Example instructions block:**

```text Instructions theme={null}
You are a financial analyst writing for retail investors.

Rules:
- Aim for brief sentences and paragraphs.
- Define jargon the first time you use it.
- Prefer concrete numbers over vague qualifiers ("up 12% YoY" not "growing
  strongly").

Grounding rules:
- Cite sources inline by domain, e.g. (reuters.com). Do not write full URLs.
- If searches return no relevant results after trying alternative phrasings,
  or if the only matches are off-topic (different company, different fiscal year,
  etc.), say so explicitly rather than substituting related results.
```

Keep `instructions` focused. They are re-read on every turn of the agent loop, so bloat compounds across tool calls. If your block is growing long, check whether parts of it would be better expressed as request parameters: use [`response_format`](/docs/agent-api/output-control) with a JSON schema for machine-readable output, [`web_search` filters](/docs/agent-api/tools/web-search#filters) for retrieval constraints, or move query-specific framing into `input`.

Built-in tools like `web_search` and `fetch_url` are tuned to work well without prompt-side guidance. You don't need to describe what they do, when to call them, or how to construct queries. Adjust tool-call count with the `max_steps` parameter and search constraints with `web_search` filters. If you're using custom `instructions` and want to nudge how the model uses built-in tools, you can reference them there as well.

For custom function tools you define yourself, the model relies on the `description` and parameter schema you provide, so make those as clear as you can. You can reinforce the tool's role in `instructions` if the description alone isn't enough to steer behavior.

## Input

Use the `input` parameter for the actual query you want answered. Input strongly shapes search behavior, so descriptive and specific phrasing directly improves retrieval. Vague inputs lead to vague searches.

**Example user prompt:**

```text Input theme={null}
What are the best sushi restaurants in the world currently?
```

## API Example

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      preset="low",
      input="Explain how hosted LLM API pricing is typically structured: input vs output tokens, context window limits, and the implication for long-document workloads.",
      instructions="You are a concise, well-researched assistant. If searches still return no relevant results after trying alternative phrasings, say so explicitly rather than guessing."
  )

  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({
    preset: "low",
    input: "Explain how hosted LLM API pricing is typically structured: input vs output tokens, context window limits, and the implication for long-document workloads.",
    instructions: "You are a concise, well-researched assistant. If searches still return no relevant results after trying alternative phrasings, say so explicitly rather than guessing."
  });

  console.log(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": "low",
      "input": "Explain how hosted LLM API pricing is typically structured: input vs output tokens, context window limits, and the implication for long-document workloads.",
      "instructions": "You are a concise, well-researched assistant. If searches still return no relevant results after trying alternative phrasings, say so explicitly rather than guessing."
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_9ad22494-e7e4-4f84-a5b1-09a339d6bf79",
    "created_at": 1779391834,
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "results": [
          {
            "id": 1,
            "snippet": "Every LLM API charges separately for **input tokens** (your prompt, system message, and any context) and **output tokens** (the model's response).\nOutput tokens always cost more — typically 2-5x the input price.\n...\n**Key takeaway:** Context window size matters for cost.\nModels with larger windows (Gemini's 1-2M tokens) let you send more context per request, but more context means more input tokens billed.",
            "title": "How LLM Token Pricing Works: A Complete Guide to API Costs in ...",
            "url": "https://benchlm.ai/blog/posts/llm-token-pricing",
            "date": "2026-03-26",
            "last_updated": "2026-05-20",
            "source": "web"
          },
          {
            "id": 2,
            "snippet": "Token usage is tracked in several categories:\n- **Input tokens** – tokens in your request.\n- **Output tokens** – tokens generated in the response.\n...\nAPI usage is priced per token, varying by model and whether tokens are input, output, or cached.\nSee OpenAI’s pricing page for current rates.",
            "title": "What are tokens and how to count them? - OpenAI Help Center",
            "url": "https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them",
            "date": "2026-03-31",
            "last_updated": "2026-03-31",
            "source": "web"
          },
          {
            "id": 3,
            "snippet": "When using extended thinking, all input and output tokens, including the tokens used for thinking, count toward the context window limit, with a few nuances in multi-turn situations.\nThe thinking budget tokens are a subset of your `max_tokens` parameter, are billed as output tokens, and count towards rate limits.\n...\n- **Token calculation:** All input and output components count toward the context window, and all output components are billed as output tokens.",
            "title": "Context windows - Claude API Docs",
            "url": "https://platform.claude.com/docs/en/build-with-claude/context-windows",
            "date": null,
            "last_updated": "2026-05-21",
            "source": "web"
          },
          {
            "id": 4,
            "snippet": "Models like GPT‑4.1 and Llama 4 Maverick support context windows exceeding one million tokens, but larger windows do not inherently raise per-token prices.",
            "title": "Understanding LLM Cost Per Token: A 2026 Practical Guide",
            "url": "https://www.silicondata.com/blog/llm-cost-per-token",
            "date": "2026-05-07",
            "last_updated": "2026-05-18",
            "source": "web"
          },
          {
            "id": 5,
            "snippet": "The language there is “**context window**” = 128K and “**max output tokens**” = 16386",
            "title": "What is the maximum response length (output tokens) for each GPT ...",
            "url": "https://community.openai.com/t/what-is-the-maximum-response-length-output-tokens-for-each-gpt-model/524066",
            "date": "2023-11-24",
            "last_updated": "2026-05-19",
            "source": "web"
          },
          {
            "id": 6,
            "snippet": "Okay, so on pricing, now you're going to be paying flat pricing irrespective how\n{ts:38} many tokens you are using.\nSo, 900,000 tokens is going to be billed exactly the same\n{ts:44} as 9,000 tokens, which is a great deviation from the pricing tiers that Anthropic Frontier Labs uses for long\n{ts:52} context.\n...\nBut, if you start using more than 200,000 tokens, it starts to change\n{ts:104} because OpenAI is charging almost two times for input tokens and 1.5 times for output tokens.\n{ts:112} Same is the case with Gemini, but Anthropic is now charging a flat rate for\n{ts:120} any token irrespective of how much context you're using.",
            "title": "Anthropic Just Solved Long Context - YouTube",
            "url": "https://www.youtube.com/watch?v=Ow-8dYXDym8",
            "date": "2026-03-16",
            "last_updated": "2026-05-21",
            "source": "web"
          },
          {
            "id": 7,
            "snippet": "But if your workload fills the context window, the 128K model’s per-request cost is 4x higher.\nPaying for context capacity you do not use is free; paying for capacity you fill is not.\n...\nEvery major LLM API charges different rates for input and output tokens.\n...\nTypical ratios:\n- **OpenAI GPT-4o:** Output is 4x more expensive than input ($10 vs $2.50 per million tokens)\n- **Anthropic Claude Sonnet:** Output is 5x more expensive than input ($15 vs $3 per million tokens)\n- **Google Gemini 1.5 Pro:** Output is 4x more expensive than input ($5 vs $1.25 per million tokens)\n...\nIf your application uses RAG, the retrieved context dominates your input token count.\nFive retrieved document chunks averaging 500 tokens each add 2,500 tokens to every request.\nAt $2.50 per million input tokens, that context retrieval costs $2.50 per 1,000 requests — or $2,500 per million requests.\n...\nInput tokens are the tokens you send to the model (your prompt, system instructions, and any retrieved context).\nOutput tokens are the tokens the model generates in its response.\nOutput tokens cost 2–4x more than input tokens because generation requires more compute per token.",
            "title": "LLM Token Pricing Comparison 2026 — Cost Per Million Tokens",
            "url": "https://myengineeringpath.dev/tools/llm-pricing-comparison/",
            "date": "2026-03-20",
            "last_updated": "2026-03-20",
            "source": "web"
          },
          {
            "id": 8,
            "snippet": "$5.00 / 1M tokens\nCached input:\n$0.50 / 1M tokens\nOutput:\n$30.00 / 1M tokens\n...\n$2.50 / 1M tokens\nCached input:\n$0.25 / 1M tokens\n...\n$0.75 / 1M tokens\nCached input:\n$0.075 / 1M tokens\nOutput:\n$4.50 / 1M tokens",
            "title": "API Pricing - OpenAI",
            "url": "https://openai.com/api/pricing/",
            "date": "2026-04-09",
            "last_updated": "2026-05-19",
            "source": "web"
          },
          {
            "id": 9,
            "snippet": "The culprit is usually hiding in plain sight: output and reasoning tokens cost two to six times more than input tokens, and most teams don't realize how quickly they add up.\n...\nInput tokens include everything you send to the model: your prompt, system instructions, context, and conversation history.\nYou pay for every token the model \"reads,\" even if it doesn't use all of it.\n...\nOutput tokens typically cost two to four times more than input tokens.\n...\nOutput tokens require autoregressive generation, meaning the model runs once per token, sequentially.\n...\nThe pricing hierarchy follows a clear pattern: reasoning tokens are most expensive, followed by output tokens, with input tokens being least expensive.\n...\nContext windows grow over time as conversations continue or as you add more repository context.\nEach API call includes the full context, so longer contexts mean more input tokens per request.\nA code review that starts with 500 tokens of context might grow to 5,000 tokens as you add file history, related files, and conversation history.",
            "title": "Why Output & Reasoning Tokens Inflate LLM Costs (2026 Guide)",
            "url": "https://www.codeant.ai/blogs/input-vs-output-vs-reasoning-tokens-cost",
            "date": "2025-05-07",
            "last_updated": "2026-05-15",
            "source": "web"
          },
          {
            "id": 10,
            "snippet": "The rate limiter considers both input and output tokens.\n...\nThe AI model has a context window length, the maximum memory of tokens, an area for both processing your language input and for forming a response.\nStandard high-quality gpt-4 has a context length of 8k tokens.\ngpt-4-turbo has a context length of 125k for understanding, with a limited output.\n...\nAs for rate limits: **At tier 1** (paying less than $50 in the past),\n- `gpt-4-turbo-preview` has a limit of 150000 tokens per minute.\nHowever it has a much more restrictive 500000 tokens per day.\n- gpt-4 has a limit of 10000 tokens per minute; no daily limit.",
            "title": "Inputs tokens limit, data extraction - OpenAI Developer Community",
            "url": "https://community.openai.com/t/inputs-tokens-limit-data-extraction/612242",
            "date": "2024-02-03",
            "last_updated": "2026-04-24",
            "source": "web"
          },
          {
            "id": 11,
            "snippet": "Two concepts explain almost everything: the **token** (the chunks of text an AI reads and writes — roughly 3/4 of a word per token) and the **context window** (how much text the model can consider at once).\n...\n- **You’re paying for the whole window every time.** Input cost is per-token; if your prompt includes 500k tokens of context, you pay for 500k input tokens on every call.\n...\nLLM API pricing has two prices, almost always: **input** (the tokens you send) and **output** (the tokens the model generates).\nOutput tokens cost more than input tokens — typically 3–5× more.\nWhy?\nOutput is where the model’s expensive computation happens.\nEach output token requires the model to “think” about everything that came before it.\nInput tokens are largely a one-time cost — the model reads them, builds an internal representation, and then can produce many output tokens against that representation.",
            "title": "Tokens, context windows, and what they cost - Cyberax",
            "url": "https://cyberax.com/ai-playbook/tokens-context-windows-and-cost",
            "date": "2026-05-11",
            "last_updated": "2026-05-17",
            "source": "web"
          },
          {
            "id": 12,
            "snippet": "Its most notable feature is its 100k context window.\n...\n**GPT-4** ** (OpenAI) costs per 1,000 tokens:**\n- Cost of Prompt: $0.03\n- Cost of Completion: $0.06\n**Claude 2 (Anthropic) costs per 1,000 tokens:**\n- Cost of Prompt: $0.01102\n- Cost of Completion: $0.03268",
            "title": "Using Anthropic: Best Practices, Parameters, and Large Context ...",
            "url": "https://www.prompthub.us/blog/using-anthropic-best-practices-parameters-and-large-context-windows",
            "date": "2025-01-15",
            "last_updated": "2026-05-15",
            "source": "web"
          }
        ],
        "type": "search_results",
        "queries": [
          "LLM API pricing input vs output tokens context window",
          "OpenAI API pricing input output tokens context limit",
          "Anthropic pricing context window long documents"
        ]
      },
      {
        "id": "msg_30926530-7c19-4e04-98b9-75ebae7f593b",
        "content": [
          {
            "text": "Hosted LLM APIs generally charge separately for **input** tokens (everything you send) and **output** tokens (everything the model generates), both subject to a hard context‑window limit that caps how much text can be processed in a single call and strongly shapes the economics of long‑document workloads.[web:1][web:2][web:3][web:11] For long documents, the dominant cost is usually repeatedly paying for large input contexts rather than the model’s answer itself, unless the responses are very long or “reasoning‑heavy.”[web:7][web:9][web:11]\n\n## Input vs output tokens\n\nMost APIs meter usage as “tokens in” and “tokens out,” with different prices for each.[web:1][web:2][web:7][web:11] A token is a small chunk of text (often ~¾ of an English word), so both prompts and responses are measured in hundreds to thousands of tokens rather than characters.[web:11]\n\nCommon patterns:\n\n- Input tokens:\n  - Include system prompt, user prompt, conversation history, and any retrieved context (e.g., RAG documents).[web:2][web:7][web:9]\n  - Are billed per million (or thousand) tokens at the lower rate tier.[web:7][web:8][web:11]\n- Output tokens:\n  - Include the final answer and any intermediate “thinking” or reasoning traces where supported.[web:3][web:9]\n  - Typically cost 2–5× more than input tokens because each generated token requires a full forward pass conditioned on all prior tokens.[web:1][web:7][web:9][web:11]\n\nSome platforms also discount “cached” or reused input tokens that the model has already processed, which can matter when you reuse the same system prompt or fixed context across many calls.[web:2][web:8]\n\n## Context window limits\n\nThe context window is the maximum total number of tokens (input plus output) the model can consider in a single request.[web:3][web:10][web:11] Modern flagship models support windows from ~128K tokens up to 1M+ tokens, but the entire prompt plus the planned answer must fit within that limit.[web:4][web:5][web:7][web:11]\n\nKey implications:\n\n- All tokens count: every input token (prompt, instructions, retrieved chunks, chat history) and every output token must fit inside the context window.[web:3][web:10][web:11]\n- Per‑request ceilings: models may expose both a context‑window maximum and a separate “max output tokens” cap, so long inputs reduce the available budget for the answer.[web:3][web:5]\n- Bigger windows do not automatically mean higher per‑token prices, but they enable much larger prompts, so *actual* per‑call cost scales with how full you make the window.[web:1][web:4][web:7][web:11]\n\n## Pricing patterns across providers\n\nWhile numbers vary by vendor and model, the structure is very similar across major APIs.[web:7][web:8][web:12]\n\nTypical patterns:\n\n- Dual pricing:\n  - Separate $/M input tokens and $/M output tokens lines for each model.[web:7][web:8][web:12]\n  - Output rate commonly 2–5× the input rate.[web:1][web:7][web:9][web:11]\n- Specialized token types:\n  - Some providers expose “reasoning,” “thinking,” or “extended‑thinking” tokens that are charged at a premium compared with normal output.[web:3][web:9]\n  - Cached or previously‑seen input tokens may be billed at a discounted rate when the platform supports retrieval from a cache.[web:2][web:8]\n- Long‑context options:\n  - Higher‑end models offer larger context windows (hundreds of thousands to >1M tokens) at similar or slightly different per‑token rates, but using the full window multiplies the cost of each call.[web:4][web:7][web:11]\n\nThere are also emerging flat‑pricing or “banded” schemes for ultra‑long‑context tiers, but the common denominator remains that cost scales directly with tokens processed, regardless of how they are packaged.[web:6][web:7]\n\n## Long‑document workloads\n\nFor workloads like summarization, Q&A over corpora, or codebase analysis, the interaction between per‑token pricing and context limits is crucial.[web:7][web:9][web:11]\n\nCore implications:\n\n- You pay repeatedly for context:\n  - When doing retrieval‑augmented generation (RAG), every query includes retrieved chunks, so the retrieved context often dominates the input token count.[web:7][web:9][web:11]\n  - For example, five 500‑token chunks (2,500 tokens) per request, at $2.50 per million input tokens, costs ~$2.50 per 1,000 calls just for those chunks, or ~$2,500 per million calls.[web:7]\n- “Fill the window” gets expensive:\n  - If you regularly send prompts close to a 128K–1M token context limit, each call can be tens to hundreds of times more expensive than a short‑prompt call, even at the same per‑token price.[web:4][web:7][web:11]\n  - Long chat sessions or accreting code review threads can quietly grow context size over time, increasing cost per request as more history is resent each time.[web:9][web:11]\n- Trade-offs in chunking vs. single‑shot:\n  - Splitting a huge document into multiple smaller prompts can keep each call well under the context limit, at the cost of extra orchestration and possibly some loss of global coherence.[web:11]\n  - Using a single enormous context window is simpler but can be much more expensive if every query resends most of the document.[web:1][web:7][web:11]\n\nFor practical system design, this means the main cost levers for long‑document use cases are: how aggressively you limit retrieved context per request, how you manage chat or history growth, and how long you allow model outputs to be, given that all three are bounded by the context window and billed per token.[web:7][web:9][web:11]",
            "type": "output_text",
            "annotations": [],
            "logprobs": []
          }
        ],
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "status": "completed",
    "error": null,
    "usage": {
      "input_tokens": 6297,
      "output_tokens": 1408,
      "total_tokens": 7705,
      "cost": {
        "currency": "USD",
        "input_cost": 0.00339,
        "output_cost": 0.01408,
        "total_cost": 0.02042,
        "cache_creation_cost": null,
        "cache_read_cost": 0.00045,
        "tool_calls_cost": 0.0025
      },
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 3584,
        "cached_tokens": 3584
      },
      "tool_calls_details": {
        "search_web": {
          "invocation": 1
        }
      },
      "output_tokens_details": {
        "reasoning_tokens": 0
      }
    },
    "background": false,
    "completed_at": 1779391834,
    "frequency_penalty": 0,
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "user": null
  }
  ```
</Accordion>

## Best Practices

<CardGroup>
  <Card title="Be Specific and Descriptive">
    Use natural language, but include the vocabulary and context that would actually appear on relevant pages. Add a few words of context to disambiguate when a term could mean multiple things. Specificity in `input` directly improves retrieval.

    **Good Example**: "Compare energy efficiency ratings of heat pumps vs. traditional HVAC for residential use"

    **Poor Example**: "Tell me which home heating is better"
  </Card>

  <Card title="Cap Result Counts">
    If you want a list, say how long. Without an explicit cap, the model picks an arbitrary length.

    **Good Example**: "List the top 5 sushi restaurants in Tokyo"

    **Poor Example**: "Give me a list of sushi restaurants"
  </Card>

  <Card title="Use Instructions to Shape Tool Output">
    Can be useful if you want to nudge how the model handles tool output. Things like citation style, grounding behavior, or response formatting fit naturally here, since instructions apply on every turn of the agent loop.

    **Example** (`instructions`): "Cite sources inline by domain (e.g., reuters.com). State explicitly when tool results don't fully answer the question."
  </Card>
</CardGroup>

## Reading Sources from the Response

Read URLs and source metadata from the response payload, not from the model's written answer. For non-streaming responses, search results are inside `response.output[]` as items where `type == "search_results"` — the response contains one such item per search the model ran, all sharing a single citation `id` space, so collect the results from every item rather than only the first (multi-step presets like deep research run many searches). Pull URLs from `results[].url`. For streaming, listen for `response.reasoning.search_results` events (again, one per search). See [Output Control](/docs/agent-api/output-control) for the full response shape.

The model has access to URLs from tool output and can include them in its response if asked, but it's prone to mistyping or paraphrasing them. Presets also configure a citation style for the model — an index that maps to the search result `id` (e.g., `[1]` or `[web:1]`) or inline links, depending on the preset — so asking for URLs in prose fights the default citation format. Treat the model's text as the prose answer and the structured `search_results` items as the authoritative source list.

## Reduce Hallucinations

LLMs are tuned to be helpful, which can occasionally lead them to provide an answer when search results are thin or off-target rather than flagging the gap. The agent loop helps, since the model can refine queries and search again, but it does not eliminate the failure modes. Hallucination is most likely when the information isn't web-accessible (posts that require authentication, private documents, paywalled content), when repeated searches return related but non-matching results, or when very recent information isn't indexed yet.

A few short additions to `instructions` cover most of these cases. Grounding rules belong here because instructions are re-read on every turn of the agent loop, so the same rule applies to the first search and to any follow-ups.

**Give the model permission to say it didn't find anything.** With an explicit out, the model is more likely to acknowledge insufficient results instead of leaning on training data to fill the gap.

```text Instructions theme={null}
If searches do not return relevant results after trying alternative phrasings, say so explicitly rather than providing speculative information.
```

**Require disclosure of near-misses.** When search returns related but non-matching results (a different year, a parent company instead of a subsidiary, a similar product), asking the model to surface the mismatch up front keeps these cases from being presented as direct answers.

```text Instructions theme={null}
If you find related but non-matching results (for example, a different year, a parent company, or a subsidiary), state the mismatch explicitly before answering.
```

## Use Parameters, Not Prose, for Hard Constraints

For source, date, or region constraints, prefer the `web_search` parameters over describing the constraint in prose. Parameters are applied by the search backend on every call, while prose-based filters are interpreted by the model and may not carry through every turn of the loop.

Keep `input` focused on the question itself, and move structural constraints into the tool config:

```python Avoid theme={null}
client.responses.create(
    preset="low",
    input="Using only Wikipedia as a source, summarize the history of the Apollo program: each crewed mission, their objectives, and key outcomes."
)
```

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_50148504-902d-4f26-8432-2930506d13af",
    "created_at": 1779895991,
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "results": [
          {
            "id": 1,
            "snippet": "The **Apollo program**, also known as **Project Apollo**, was the United States human spaceflight program led by NASA, which landed the first humans on the Moon in 1969.\nApollo was conceived in 1960 in the Dwight D. Eisenhower presidency during Project Mercury and executed after Project Gemini.\nApollo was later dedicated to President John F. Kennedy's national goal, \"before this decade is out, of landing a man on the Moon and returning him safely to the Earth\" in his address to the U.S. Congress on May 25, 1961.\n...\nApollo ran from 1961 to 1972, with the first crewed flight in 1968.",
            "title": "Apollo program - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/Apollo_program",
            "date": "2001-09-24",
            "last_updated": "2026-05-21",
            "source": "web"
          },
          {
            "id": 2,
            "snippet": "**Apollo 7** (October 11–22, 1968) was the first crewed flight in NASA's Apollo program, and saw the resumption of human spaceflight by the agency after the fire that killed the three Apollo 1 astronauts during a launch rehearsal test on January 27, 1967.",
            "title": "Apollo 7 - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/Apollo_7",
            "date": "2001-08-27",
            "last_updated": "2026-05-27",
            "source": "web"
          },
          {
            "id": 3,
            "snippet": "**Apollo 8** (December 21–27, 1968) was the first crewed spacecraft to leave Earth's gravitational sphere of influence, and the first human spaceflight to reach the Moon.\nThe crew orbited the Moon ten times without landing and then returned to Earth.\nThe three astronauts—Frank Borman, Jim Lovell, and William Anders—were the first humans to see and photograph the far side of the Moon and an Earthrise.\nApollo 8 launched on December 21, 1968, and was the second crewed spaceflight mission flown in the United States Apollo space program (the first, Apollo 7, stayed in Earth orbit).\nApollo 8 was the third flight and the first crewed launch of the Saturn V rocket.\nIt was the first human spaceflight from the Kennedy Space Center, adjacent to Cape Kennedy Air Force Station in Florida.",
            "title": "Apollo 8 - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/Apollo_8",
            "date": "2001-03-17",
            "last_updated": "2026-05-22",
            "source": "web"
          },
          {
            "id": 4,
            "snippet": "**Apollo 9** (March 3–13, 1969) was the third human spaceflight in NASA's Apollo program, which successfully tested systems and procedures critical to landing on the Moon.\nThe three-man crew consisted of Commander James McDivitt, Command Module Pilot David Scott, and Lunar Module Pilot Rusty Schweickart.\nFlown in low Earth orbit, it was the second crewed Apollo mission that the United States launched via a Saturn V rocket, and was the first flight of the full Apollo spacecraft: the command and service module (CSM) with the Lunar Module (LM).",
            "title": "Apollo 9 - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/Apollo_9",
            "date": "2001-08-27",
            "last_updated": "2026-05-22",
            "source": "web"
          },
          {
            "id": 5,
            "snippet": "**Apollo 10** (May 18–26, 1969) was the fourth human spaceflight in the United States' Apollo program and the second to orbit the Moon.\nNASA, the mission's operator, described it as a \"dress rehearsal\" for the first Moon landing (Apollo 11, two months later).",
            "title": "Apollo 10 - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/Apollo_10",
            "date": "2001-09-22",
            "last_updated": "2026-05-22",
            "source": "web"
          },
          {
            "id": 6,
            "snippet": "The Apollo program was a United States human spaceflight program carried out from 1961 to 1972 by the National Aeronautics and Space Administration (NASA), which landed the first astronauts on the Moon.\nThe program used the Saturn IB and Saturn V launch vehicles to lift the Command/Service Module (CSM) and Lunar Module (LM) spacecraft into space, and the Little Joe II rocket to test a launch escape system which was expected to carry the astronauts to safety in the event of a Saturn failure.",
            "title": "List of Apollo missions - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/List_of_Apollo_missions",
            "date": "2007-02-13",
            "last_updated": "2026-05-10",
            "source": "web"
          },
          {
            "id": 7,
            "snippet": "**Many are familiar with Apollo 11, the mission that landed humans on the Moon for the first time.\nIt was part of the larger Apollo program.\n**\n**There were several missions during the Apollo program from 1961 to 1972.\nHumans landed on the moon during six missions, Apollo 11, 12, 14, 15, 16, and 17.\n**",
            "title": "The Apollo Missions | National Air and Space Museum",
            "url": "https://airandspace.si.edu/explore/stories/apollo-missions",
            "date": "2021-11-04",
            "last_updated": "2026-05-17",
            "source": "web"
          },
          {
            "id": 8,
            "snippet": "**Apollo 7** was a mission in the NASA's Apollo program.\nIt was the first crewed mission in the Apollo program and the first crewed US space flight after Apollo 1 disaster.\nThe mission was a C type mission.\nApollo 7 was launched on October 11, 1968 and stayed in space for 10 days, 20 hours, 9 minutes and three seconds.\n...\nApollo 7 was the first crewed launch of the Saturn IB launch vehicle and the first three-person US space mission.\n...\nThe mission was designed to test the re-made Block II Apollo Command/Service Module.\n...\nThe mission was a success.\nIt gave NASA the confidence to launch Apollo 8 later.",
            "title": "Apollo 7 - Simple English Wikipedia, the free encyclopedia",
            "url": "https://simple.wikipedia.org/wiki/Apollo_7",
            "date": "2012-02-29",
            "last_updated": "2026-05-26",
            "source": "web"
          },
          {
            "id": 9,
            "snippet": "**Apollo 8** was a mission in the Apollo program in December 1968.\nIt was the first crewed spaceflight to leave Earth orbit and first to orbit the Moon.\nCommander Frank Borman, Pilot Jim Lovell and Bill Anders transmitted a television show while they were in orbit.",
            "title": "Apollo 8 - Simple English Wikipedia, the free encyclopedia",
            "url": "https://simple.wikipedia.org/wiki/Apollo_8",
            "date": "2012-01-20",
            "last_updated": "2026-05-23",
            "source": "web"
          },
          {
            "id": 10,
            "snippet": "**Apollo 9** was a mission in NASA's Apollo program.\nIt was the third crewed mission in the Apollo program and was the first flight of the Command/Service Module (CSM) with the Lunar Module (LM).\nThe crew was Commander James A.\nMcDivitt, Command Module Pilot David R. Scott, and Lunar Module Pilot Russell L. Schweickart.",
            "title": "Apollo 9 - Simple English Wikipedia, the free encyclopedia",
            "url": "https://simple.wikipedia.org/wiki/Apollo_9",
            "date": "2012-05-17",
            "last_updated": "2026-04-01",
            "source": "web"
          },
          {
            "id": 11,
            "snippet": "The national effort that enabled Astronaut Neil Armstrong to speak those words as he stepped onto the lunar surface fulfilled a dream as old as humanity.\nProject Apollo’s goals went beyond landing Americans on the moon and returning them safely to Earth.\nThey included:\n- Establishing the technology to meet other national interests in space.\n- Achieving preeminence in space for the United States.\n- Carrying out a program of scientific exploration of the Moon.\n- Developing human capability to work in the lunar environment.\n...\nThe flight mode, lunar orbit rendezvous, was selected in 1962.\nThe boosters for the program were the Saturn IB for Earth orbit flights and the Saturn V for lunar flights.\nApollo was a three-part spacecraft: the command module (CM), the crew’s quarters and flight control section; the service module (SM) for the propulsion and spacecraft support systems (when together, the two modules are called CSM); and the lunar module (LM), to take two of the crew to the lunar surface, support them on the Moon, and return them to the CSM in lunar orbit.",
            "title": "The Apollo Program - NASA",
            "url": "https://www.nasa.gov/the-apollo-program/",
            "date": "2023-03-23",
            "last_updated": "2026-05-18",
            "source": "web"
          },
          {
            "id": 12,
            "snippet": "**On October 11, 1968 Apollo 7 was launched on a Saturn IB rocket, making it the first successful crewed Apollo mission and the only crewed Apollo mission to use the Saturn IB Rocket.**\nApollo 7 was the first test of the command and service module with a crew.\nThe crew orbited the Earth 163 times and spent 10 days and 20 hours in space.\nThis mission was the first opportunity to test the first of the new Block II spacecraft (CSM 101) in orbit.\nThe only significant difficulty in the mission was the fact that all three astronauts developed severe head colds.",
            "title": "Apollo 7 | National Air and Space Museum",
            "url": "https://airandspace.si.edu/explore/stories/apollo-missions/apollo-7",
            "date": "2021-07-29",
            "last_updated": "2026-03-25",
            "source": "web"
          }
        ],
        "type": "search_results",
        "queries": [
          "Apollo program Wikipedia",
          "List of Apollo missions Wikipedia",
          "Apollo 7 Wikipedia",
          "Apollo 8 Wikipedia",
          "Apollo 9 Wikipedia",
          "Apollo 10 Wikipedia"
        ]
      },
      {
        "contents": [
          {
            "snippet": "The Apollo program was a United States human spaceflight program carried out from 1961 to 1972 by the National Aeronautics and Space Administration (NASA), which landed the first astronauts on the Moon. The program used the Saturn IB and Saturn V launch vehicles to lift the Command/Service Module (CSM) and Lunar Module (LM) spacecraft into space, and the Little Joe II rocket to test a launch escape system which was expected to carry the astronauts to safety in the event of a Saturn failure. Uncrewed test flights beginning in 1966 demonstrated the safety of the launch vehicles and spacecraft to carry astronauts, and four crewed flights beginning in October 1968 demonstrated the ability of the spacecraft to carry out a lunar landing mission.\n\nApollo achieved the first crewed lunar landing on the Apollo 11 mission, when Neil Armstrong and Buzz Aldrin landed their LM *Eagle* in the Sea of Tranquility and walked on the lunar surface, while Michael Collins remained in lunar orbit in the CSM *Columbia*, and all three landed safely on Earth on July 24, 1969. Five subsequent missions landed astronauts on various lunar sites, ending in December 1972 with 12 men having walked on the Moon and 842 pounds (382 kg) of lunar rocks and soil samples returned to Earth, greatly contributing to the understanding of the Moon's composition and geological history.\n\nTwo Apollo missions were failures: a 1967 cabin fire killed the entire Apollo 1 crew during a ground test in preparation for what was to be the first crewed flight; and the third landing attempt on Apollo 13 was aborted by an oxygen tank explosion en route to the Moon, which disabled the CSM *Odyssey'* s electrical power and life support systems, and made the propulsion system unsafe to use. The crew circled the Moon and were returned safely to Earth using the LM *Aquarius* as a \"lifeboat\" for these functions.\n\n## Uncrewed test flights\n\nFrom 1961 through 1967, Saturn launch vehicles and Apollo spacecraft components were tested in uncrewed flights.\n\n### Saturn I\n\nThe Saturn I launch vehicle was originally planned to carry crewed Command Module flights into low Earth orbit, but its 20,000-pound (9,100 kg) payload capacity limit could not lift even a partially fueled Service Module, which would have required building a lightweight retrorocket module for deorbit. These plans were eventually scrapped in favor of using the uprated Saturn IB to launch the Command Module with a half-fueled Service Module for crewed Earth orbit tests. This limited Saturn I flights to Saturn launch vehicle development, CSM boilerplate testing, and three Pegasus micrometeoroid satellite missions in support of Apollo.\n\n**Saturn I missions**\n|Mission|LV|Launch|Pad|Remarks|Refs|\n|--|--|--|--|--|--|\n|SA-1|SA-1|October 27, 1961, 15:06|LC-34|Test of Saturn I first stage S-I; dummy upper stages carried water| |\n|SA-2|SA-2|April 25, 1962, 14:00|LC-34|Dummy upper stages released 22,900 U.S. gallons (86,685 L) of water into upper atmosphere, to investigate effects on radio transmission and changes in local weather conditions| |\n|SA-3|SA-3|November 16, 1962, 17:45|LC-34|Repeat of SA-2 mission| |\n|SA-4|SA-4|March 28, 1963, 20:11|LC-34|Test premature shutdown of a single S-I engine| |\n|SA-5|SA-5|January 29, 1964, 16:25|LC-37B|First flight of live second stage. First orbital flight.| |\n|AS-101|SA-6|May 28, 1964, 17:07|LC-37B|Tested first boilerplate Apollo command and service module (CSM) for structural integrity| |\n|AS-102|SA-7|September 18, 1964, 17:22|LC-37B|Carried first programmable-in-flight computer on the Saturn I vehicle; last launch vehicle development flight| |\n|AS-103|SA-9|February 16, 1965, 14:37|LC-37B|Carried Pegasus A satellite and boilerplate CSM| |\n|AS-104|SA-8|May 25, 1965, 07:35|LC-37B|Carried Pegasus B satellite and boilerplate CSM| |\n|AS-105|SA-10|July 30, 1965, 13:00|LC-37B|Carried Pegasus C satellite and boilerplate CSM| |\n\nThere was some incongruity in the numbering and naming of the first three uncrewed Apollo-Saturn (AS) or Apollo flights. This is due to AS-204 being renamed to Apollo 1 posthumously. This crewed flight was to have followed the first three uncrewed flights. After the fire which killed the AS-204 crew on the pad during a test and training exercise, uncrewed Apollo flights resumed to test the Saturn V launch vehicle and the Lunar Module; these were designated Apollo 4, 5 and 6. The first crewed Apollo mission was thus Apollo 7. Simple \"Apollo\" numbers were never assigned to the first three uncrewed flights, although renaming AS-201, AS-202, and AS-203 as Apollo 1-A, Apollo 2 and Apollo 3, had been briefly considered.\n\n### Saturn IB\n\nThe Saturn I was converted to the Uprated Saturn I, eventually designated Saturn IB, by replacing the S-IV second stage with the S-IVB, which would also be used as the third stage of the Saturn V with the addition of on-orbit restart capability. This increased the payload capacity to 46,000 pounds (21,000 kg), enough to orbit a Command Module with a half-fueled Service Module, and more than enough to orbit a fully fueled Lunar Module.\n\nTwo suborbital tests of the Apollo Block I Command and Service Module, one S-IVB development test, and one Lunar Module test were conducted. Success of the LM test led to cancellation of a planned second uncrewed flight.\n\n**Saturn IB missions**\n|Mission|LV|Launch|Pad|Remarks|Refs|\n|--|--|--|--|--|--|\n|AS-201|SA-201|February 26, 1966, 16:12|LC-34|First test of Saturn IB and Block I Apollo CSM. Suborbital flight landed the CM in the Atlantic Ocean, demonstrating the heat shield. Propellant pressure loss caused premature SM engine shutdown.| |\n|AS-203|SA-203|July 5, 1966, 14:53|LC-37B|No Apollo spacecraft; instrumentation and video observed on-orbit behavior of S-IVB liquid hydrogen fuel in support of restart capability design for Saturn V. Deemed a success, despite inadvertent destruction of S-IVB during final overpressure tank rupture test.| |\n|AS-202|SA-202|August 25, 1966, 17:15|LC-34|Suborbital flight to Pacific Ocean splashdown. CM heat shield tested to higher speed; successful SM firings.| |\n|Apollo 5|SA-204|January 22, 1968, 22:48|LC-37B|First flight of LM successfully fired descent engine and ascent engines; demonstrated \"fire-in-the-hole\" landing abort test.| |\n\n### Launch escape system tests\n\nFrom August 1963 to January 1966, a number of tests were conducted at the White Sands Missile Range for development of the launch escape system (LES). These included simulated \"pad aborts\", which might occur while the Apollo-Saturn space vehicle was still on the launch pad, and flights on the Little Joe II rocket to simulate Mode I aborts which might occur while the vehicle was in the air.\n\n**Launch escape system tests**\n|Mission|LV|Launch|Pad|Remarks|Refs|\n|--|--|--|--|--|--|\n|QTV|Little Joe II|August 28, 1963, 13:05|LC-36|Little Joe II qualification test| |\n|Pad Abort Test 1|N/a|November 7, 1963, 16:00|LC-36|Launch escape system (LES) abort test from launch pad| |\n|A-001|Little Joe II|May 13, 1964, 13:00|LC-36|LES transonic test, success except for parachute failure| |\n|A-002|Little Joe II|December 8, 1964, 15:00|LC-36|LES maximum altitude, Max-Q abort test| |\n|A-003|Little Joe II|May 19, 1965, 13:01|LC-36|LES canard maximum altitude abort test| |\n|Pad Abort Test 2|N/a|June 29, 1965, 13:00|LC-36|LES pad abort test of near Block-I CM| |\n|A-004|Little Joe II|January 20, 1966, 15:17|LC-36|LES test of maximum weight, tumbling Block-I CM| |\n\n### Saturn V\n\nPrior to George Mueller's tenure as NASA's Associate Administrator for Manned Space Flight starting in 1963, it was assumed that 20 Saturn Vs, with at least 10 unpiloted test flights, would be required to achieve a crewed Moon landing, using the conservative one-stage-at-a-time testing philosophy used for the Saturn I. But Mueller introduced the \"all-up\" testing philosophy of using three live stages plus the Apollo spacecraft on every test flight. This achieved development of the Saturn V with far fewer uncrewed tests, enabling a Moon landing by the 1969 goal. The size of the Saturn V production lot was reduced from 20 to 15 units.\n\nThree uncrewed test flights were planned to human-rate the super heavy-lift Saturn V which would take crewed Apollo flights to the Moon. Success of the first flight and qualified success of the second led to the decision to cancel the third uncrewed test.\n\n**Saturn V missions**\n|Mission|LV|Launch|Pad|Remarks|Refs|\n|--|--|--|--|--|--|\n|Apollo 4|SA-501|November 9, 1967, 12:00|LC-39A|First flight of Saturn V rocket; successfully demonstrated S-IVB third stage restart and tested CM heat shield at lunar re-entry speeds.| |\n|Apollo 6|SA-502|April 4, 1968, 16:12|LC-39A|Second flight of Saturn V; severe \"pogo\" vibrations caused two second-stage engines to shut down prematurely, and third stage restart to fail. SM engine used to achieve high-speed re-entry, though less than Apollo 4. NASA identified vibration fixes and declared Saturn V man-rated.| |\n\n## Alphabetical mission types\n\nThe Apollo program required sequential testing of several major mission elements in the runup to a crewed lunar landing. An alphabetical list of major mission types was proposed by Owen Maynard in September 1967. Two \"A-type\" missions performed uncrewed tests of the CSM and the Saturn V, and one B-type mission performed an uncrewed test of the LM. The C-type mission, the first crewed flight of the CSM in Earth orbit, was performed by Apollo 7.\n\nThe list was revised upon George Low's proposal to commit a mission to lunar orbit ahead of schedule, an idea influenced by the status of the CSM as a proven craft and production delays of the LM. Apollo 8 was reclassified from its original assignment as a D-type mission, a test of the complete CSM/LM spacecraft in Earth orbit, to a \"C-prime\" mission which would fly humans to the Moon. Once complete, it eliminated the need for the E-type objective of a medium Earth orbital test. The D-type mission was instead performed by Apollo 9; the F-type mission, Apollo 10, flew the CSM/LM spacecraft to the Moon for final testing, without landing. The G-type mission, Apollo 11, performed the first lunar landing, the central goal of the program.\n\nThe initial A–G list was expanded to include later mission types: H-type missions—Apollo 12, 13 (planned) and 14—would perform precision landings on the lunar surface, and J-type missions—Apollo 15, 16 and 17—would perform thorough scientific investigation of the Moon from the lunar surface. The I-type mission, which called for extended scientific investigation of the Moon from lunar orbit, was incorporated into the J-type missions.\n\n**Alphabetical mission types of the Apollo Program**\n|Type|Mission|Description|\n|--|--|--|\n|A|- Apollo 4 - Apollo 6|Uncrewed flights of launch vehicles and the CSM, to demonstrate its design and to certify its safety for humans.|\n|B|Apollo 5|Uncrewed flight of the LM to demonstrate its design and to certify its safety for humans.|\n|C|Apollo 7|Crewed flight demonstration of CSM in low Earth orbit.|\n|C′|Apollo 8|Crewed flight demonstration of CSM in lunar orbit.|\n|D|Apollo 9|Crewed flight demonstration of CSM and LM in low Earth orbit, operating the equipment together in space and (insofar as possible in Earth orbit) performing the maneuvers involved in a lunar landing.|\n|E|N/a|Crewed flight demonstration of CSM and LM in medium Earth orbit, performing the maneuvers involved in a lunar landing.|\n|F|Apollo 10|Crewed flight demonstration of CSM and LM in lunar orbit, performing all G-type mission goals except for the final descent to and landing on the lunar surface.|\n|G|Apollo 11|Crewed lunar landing demonstration.|\n|H|- Apollo 12 - Apollo 13 (planned) - Apollo 14|Precision crewed lunar landing demonstration and systematic lunar exploration.|\n|I|N/a|Extended scientific investigation of the Moon from lunar orbit. (Not used, incorporated into J type)|\n|J|- Apollo 15 - Apollo 16 - Apollo 17|Extended scientific investigation of the Moon on the lunar surface and from lunar orbit.|\n\n## Crewed missions\n\nThe Block I CSM spacecraft did not have capability to fly with the LM, and the three crew positions were designated Command Pilot, Senior Pilot, and Pilot, based on U.S. Air Force pilot ratings. The Block II spacecraft was designed to fly with the Lunar Module, so the corresponding crew positions were designated Commander, Command Module Pilot, and Lunar Module Pilot regardless of whether a Lunar Module was present or not on any mission.\n\nSeven of the missions involved extravehicular activity (EVA), spacewalks or moonwalks outside of the spacecraft. These were of three types: testing the lunar EVA suit in Earth orbit (Apollo 9), exploring the lunar surface, and retrieving film canisters from the Scientific Instrument Module stored in the Service Module.\n\n**Crewed missions**\n|Mission|Patch|Launch date|Crew|Launch vehicle|CM name|LM name|Duration|Remarks|Refs|\n|--|--|--|--|--|--|--|--|--|--|\n|Apollo 1| |February 21, 1967 Launch Complex 34 (planned)|Gus Grissom Ed White Roger B. Chaffee|Saturn IB (SA-204)|N/a|N/a|N/a|Never launched. On January 27, 1967, a fire in the command module during a launch pad test killed the crew and destroyed the module. This flight was originally designated AS-204, and was renamed to Apollo 1 at the request of the crew's families.| |\n|Apollo 7| |October 11, 1968, 15:02 GMT Launch Complex 34|Wally Schirra Donn F. Eisele Walter Cunningham|Saturn IB (AS-205)|N/a|N/a|10 d 20 h 09 m 03 s|Test flight of Block II CSM in Earth orbit; included first live TV broadcast from American spacecraft.| |\n|Apollo 8| |December 21, 1968, 12:51 GMT Launch Complex 39A|Frank Borman James Lovell William Anders|Saturn V (SA-503)|N/a|N/a|06 d 03 h 00 m 42 s|First humans to leave Earth orbit and first to arrive at the Moon, first circumlunar flight of CSM, had ten lunar orbits in 20 hours. First crewed flight of Saturn V.| |\n|Apollo 9| |March 3, 1969, 16:00 GMT Launch Complex 39A|James McDivitt David Scott Rusty Schweickart|Saturn V (SA-504)|*Gumdrop*|*Spider*|10 d 01 h 00 m 54 s|First crewed flight test of Lunar Module; tested propulsion, rendezvous and docking in Earth orbit. EVA tested the Portable Life Support System (PLSS).| |\n|Apollo 10| |May 18, 1969, 16:49 GMT Launch Complex 39B|Thomas P. Stafford John Young Eugene Cernan|Saturn V (SA-505)|*Charlie Brown*|*Snoopy*|08 d 00 h 03 m 23 s|\"Dress rehearsal\" for lunar landing. The LM descended to 8.4 nautical miles (15.6 km) from lunar surface.| |\n|Apollo 11| |July 16, 1969, 13:32 GMT Launch Complex 39A|Neil Armstrong Michael Collins Edwin \"Buzz\" Aldrin|Saturn V (SA-506)|*Columbia*|*Eagle*|08 d 03 h 18 m 35 s|First crewed landing in Sea of Tranquility (Tranquility Base) including a single surface EVA.| |\n|Apollo 12| |November 14, 1969, 16:22 GMT Launch Complex 39A|Charles (Pete) Conrad Richard F. Gordon Jr. Alan Bean|Saturn V (SA-507)|*Yankee Clipper*|*Intrepid*|10 d 04 h 36 m 24 s|First precise Moon landing in Ocean of Storms near Surveyor 3 probe. Two surface EVAs and returned parts of Surveyor to Earth.| |\n|Apollo 13| |April 11, 1970, 19:13 GMT Launch Complex 39A|James Lovell Jack Swigert Fred Haise|Saturn V (SA-508)|*Odyssey*|*Aquarius*|05 d 22 h 54 m 41 s|Intended Fra Mauro landing cancelled after SM oxygen tank exploded. LM used as \"lifeboat\" for safe crew return. First S-IVB stage impact on Moon for active seismic test.| |\n|Apollo 14| |January 31, 1971, 21:03 GMT Launch Complex 39A|Alan Shepard Stuart Roosa Edgar Mitchell|Saturn V (SA-509)|*Kitty Hawk*|*Antares*|09 d 00 h 01 m 58 s|Successful Fra Mauro landing. Broadcast first color TV images from lunar surface (other than a few moments at the start of the Apollo 12 moonwalk.) Conducted first materials science experiments in space. Conducted two surface EVAs.| |\n|Apollo 15| |July 26, 1971, 13:34 GMT Launch Complex 39A|David Scott Alfred Worden James Irwin|Saturn V (SA-510)|*Endeavour*|*Falcon*|12 d 07 h 11 m 53 s|Landing at Hadley–Apennine. First extended LM, three-day lunar stay. First use of Lunar Roving Vehicle. Conducted three lunar surface EVAs and one deep space EVA on return to retrieve orbital camera film from SM.| |\n|Apollo 16| |April 16, 1972, 17:54 GMT Launch Complex 39A|John Young Ken Mattingly Charles Duke|Saturn V (SA-511)|*Casper*|*Orion*|11 d 01 h 51 m 05 s|Landing in Descartes Highlands. Conducted three lunar EVAs and one deep space EVA.| |\n|Apollo 17| |December 7, 1972, 05:33 GMT Launch Complex 39A|Eugene Cernan Ronald Evans Harrison Schmitt|Saturn V (SA-512)|*America*|*Challenger*|12d 13 h 51 m 59 s|Landing at Taurus–Littrow. First professional geologist on the Moon. First night launch. Conducted three lunar EVAs and one deep space EVA.| |\n\n### Canceled missions\n\nSeveral planned missions of the Apollo program were canceled for a variety of reasons, including changes in technical direction, the Apollo 1 fire, hardware delays, and budget limitations.\n\n- Before the Apollo 1 fire, two crewed Block I spacecraft missions were planned, but then it was decided that the second one would give no more information about the spacecraft performance not obtained from the first, and could not carry out extra activities such as EVA, and was canceled.\n- The Saturn V's all-up testing strategy and relatively good success rate accomplished the first Moon landing on the sixth flight, leaving ten available for Moon landings through Apollo 20, but waning public interest in the program led to decreased Congressional funding, forcing NASA to economize. First, Apollo 20 was cut to make a Saturn V available to launch the Skylab space station whole instead of building it on-orbit using multiple Saturn IB launches. Eight months later, Apollo 18 and 19 were also cut to further economize, and because of fears of increased chance of failure with a large number of lunar flights.\n\n**Canceled missions**\n|As planned|As planned|As planned|As planned|As planned|As planned|As planned|As flown|As flown|As flown|As flown|As flown|As flown|\n|--|--|--|--|--|--|--|--|--|--|--|--|--|\n|Mission|Type|Date|Landing site|CDR|CMP|LMP|Mission|Launch date|Landing site|CDR|CMP|LMP|\n|Apollo 12|H|November 1969|Ocean of Storms|Pete Conrad|Richard F. Gordon Jr.|Alan Bean|Apollo 12|November 14, 1969|Ocean of Storms|Pete Conrad|Richard F. Gordon Jr.|Alan Bean|\n|Apollo 13|H|March 1970|Fra Mauro highlands|Alan Shepard|Stuart Roosa|Edgar Mitchell|Apollo 13|April 11, 1970|Failed|Jim Lovell|Jack Swigert|Fred Haise|\n|Apollo 14|H|July 1970|Censorinus crater|Jim Lovell|Ken Mattingly|Fred Haise|Apollo 14|January 31, 1971|Fra Mauro highlands|Alan Shepard|Stuart Roosa|Edgar Mitchell|\n|Apollo 15|H|November 1970|Littrow crater|David Scott|Alfred Worden|James Irwin|Apollo 15|July 26, 1971|Hadley Rille|David Scott|Alfred Worden|James Irwin|\n|Apollo 16|J|April 1971|Tycho crater|John Young|Jack Swigert|Charles Duke|Apollo 16|April 16, 1972|Descartes Highlands|John Young|Ken Mattingly|Charles Duke|\n|Apollo 17|J|September 1971|Marius Hills|Gene Cernan|Ronald Evans|Joe Engle|Apollo 17|December 7, 1972|Taurus-Littrow|Gene Cernan|Ronald Evans|Harrison Schmitt|\n|Apollo 18|J|February 1972|Schroter's Valley|Richard F. Gordon Jr.|Vance Brand|Harrison Schmitt|CANCELED September 1970|CANCELED September 1970|CANCELED September 1970|CANCELED September 1970|CANCELED September 1970|CANCELED September 1970|\n|Apollo 19|J|July 1972|Hyginus Rille|Fred Haise|William Pogue|Gerald Carr|CANCELED September 1970|CANCELED September 1970|CANCELED September 1970|CANCELED September 1970|CANCELED September 1970|CANCELED September 1970|\n|Apollo 20|J|December 1972|Copernicus crater|Stuart Roosa|Don L. Lind|Jack Lousma|CANCELED January 4, 1970|CANCELED January 4, 1970|CANCELED January 4, 1970|CANCELED January 4, 1970|CANCELED January 4, 1970|CANCELED January 4, 1970|\n\n## See also\n\nThere were two NASA post-Apollo crewed spaceflight programs that used Apollo hardware:\n\n- Skylab § Mission designations – space laboratory missions lasting up to 83 days\n- Apollo–Soyuz – first joint US / Soviet crewed spaceflight\n\n## Notes\n\n## References\n- This article incorporates public domain material from websites or documents of the National Aeronautics and Space Administration.\n\n## Bibliography\n\n## External links\n- NASA page on Apollo Missions Archived June 19, 2016, at the Wayback Machine\n- National Space Science Data Center (Goddard Space Flight Center): Apollo Program with links to books on Program\n- Space.com List of Apollo Missions.\n- AstronomyToday List of Missions Archived November 27, 2022, at the Wayback Machine\n- Project Apollo Flickr Photo Archive\n- Interactive Apollo Flag Locations Map\n\nCategories: - Apollo program missions\n- Apollo program\n- NASA missions to the Moon\n- Lists of space missions\n- Crewed missions to the Moon",
            "title": "List of Apollo missions - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/List_of_Apollo_missions"
          },
          {
            "snippet": "**Apollo program**\n| | |\n|--|--|\n|Program overview|Program overview|\n|Country|United States|\n|Organization|NASA|\n|Purpose|Crewed lunar landing|\n|Status|Completed|\n|Program history|Program history|\n|Cost|- $25.4 billion (1973) - $257 billion (2020)|\n|Duration|1961–1972|\n|First flight|- SA-1 - October 27, 1961|\n|First crewed flight|- Apollo 7 - October 11, 1968|\n|Last flight|- Apollo 17 - December 19, 1972|\n|Successes|32|\n|Failures|2 (Apollo 1 and 13)|\n|Partial failures|1 (Apollo 6)|\n|Launch sites|- Cape Kennedy - Kennedy Space Center - White Sands|\n|Vehicle information|Vehicle information|\n|Crewed vehicles|- Apollo CSM - Apollo LM|\n|Launch vehicles|- Little Joe II - Saturn I - Saturn IB - Saturn V|\n\nThe **Apollo program**, also known as **Project Apollo**, was the United States human spaceflight program led by NASA, which landed the first humans on the Moon in 1969. Apollo was conceived in 1960 in the Dwight D. Eisenhower presidency during Project Mercury and executed after Project Gemini. Apollo was later dedicated to President John F. Kennedy's national goal, \"before this decade is out, of landing a man on the Moon and returning him safely to the Earth\" in his address to the U.S. Congress on May 25, 1961.\n\nKennedy's goal was accomplished on the Apollo 11 mission, when astronauts Neil Armstrong and Buzz Aldrin landed their Apollo Lunar Module (LM) on July 20, 1969, and walked on the lunar surface, while Michael Collins remained in lunar orbit in the command and service module (CSM), and all three landed safely on Earth in the Pacific Ocean on July 24. Approximately 650 million people worldwide watched this first landing on television. Five subsequent Apollo missions also landed astronauts on the Moon, the last, Apollo 17, in December 1972. In these six spaceflights, twelve people walked on the Moon.\n\nApollo ran from 1961 to 1972, with the first crewed flight in 1968. It encountered a major setback in 1967 when the Apollo 1 cabin fire killed the entire crew during a prelaunch test. After the first Moon landing, sufficient flight hardware remained for nine follow-on landings with a plan for extended lunar geological and astrophysical exploration. Budget cuts forced the cancellation of three of these. Five of the remaining six missions achieved landings; but the Apollo 13 landing had to be aborted after an oxygen tank exploded en route to the Moon, crippling the CSM. The crew barely managed a safe return to Earth by using the Lunar Module as a \"lifeboat\" on the return journey. Apollo used the Saturn family of rockets as launch vehicles, which were also used for an Apollo Applications Program, which consisted of Skylab, a space station that supported three crewed missions in 1973–1974, and the Apollo–Soyuz Test Project, a joint United States-Soviet Union low Earth orbit mission in 1975.\n\nApollo set several major human spaceflight milestones. It stands alone in sending humans to the lunar surface. Apollo 8 was the first crewed mission to leave low Earth orbit and to orbit another celestial body, and Apollo 11 was the first crewed mission to land humans on one.\n\nOverall, the Apollo program returned 842 pounds (382 kg) of lunar rocks to Earth, greatly contributing to the understanding of the Moon's composition and geological history. The program laid the foundation for NASA's subsequent human spaceflight capability and funded construction of its Johnson Space Center and Kennedy Space Center. Apollo also spurred advances in many areas of technology incidental to rocketry and human spaceflight, including avionics, telecommunications, and computers.\n\nFollowing the end of the Apollo program, humans would not leave low Earth orbit until the Artemis II flyby of the Moon in 2026, as part of the Artemis program, established as a successor to Apollo in 2017. Artemis intends to return humans to the Moon's surface no earlier than 2028.\n\n## Name\n\nThe program was named after the Greek god Apollo by NASA manager Abe Silverstein, who later said, \"I was naming the spacecraft like I'd name my baby.\" Silverstein chose the name at home one evening, early in 1960, because he felt \"Apollo riding his chariot across the Sun was appropriate to the grand scale of the proposed program\".\n\nThe context of this was that the program focused at its beginning mainly on developing an advanced crewed spacecraft, the Apollo command and service module, succeeding the Mercury program. A lunar landing became the focus of the program only in 1961. Thereafter Project Gemini instead followed the Mercury program to test and study advanced crewed spaceflight technology.\n\n## Background\n\n### Origin and spacecraft feasibility studies\n\nThe Apollo program was conceived during the Eisenhower administration in early 1960, as a follow-up to Project Mercury. While the Mercury capsule could support only one astronaut on a limited Earth orbital mission, Apollo would carry three. Possible missions included ferrying crews to a space station, circumlunar flights, and eventual crewed lunar landings.\n\nIn July 1960, NASA Deputy Administrator Hugh L. Dryden announced the Apollo program to industry representatives at a series of Space Task Group conferences. Preliminary specifications were laid out for a spacecraft with a *mission module* cabin separate from the *command module* (piloting and reentry cabin), and a *propulsion and equipment module*. On August 30, a feasibility study competition was announced, and on October 25, three study contracts were awarded to General Dynamics/Convair, General Electric, and the Glenn L. Martin Company. Meanwhile, NASA performed its own in-house spacecraft design studies led by Maxime Faget, to serve as a gauge to judge and monitor the three industry designs.\n\n### Political pressure builds\n\nIn November 1960, John F. Kennedy was elected president after a campaign that promised American superiority over the Soviet Union in the fields of space exploration and missile defense. Up to the election of 1960, Kennedy had been speaking out against the \"missile gap\" that he and many other senators said had developed between the Soviet Union and the United States due to the inaction of President Eisenhower. Beyond military power, Kennedy used aerospace technology as a symbol of national prestige, pledging to make the US not \"first but, first and, first if, but first period\".\n\nDespite Kennedy's rhetoric, he did not immediately come to a decision on the status of the Apollo program once he became president. He knew little about the technical details of the space program, and was put off by the massive financial commitment required by a crewed Moon landing. When Kennedy's newly appointed NASA Administrator James E. Webb requested a 30 percent budget increase for his agency, Kennedy supported an acceleration of NASA's large booster program but deferred a decision on the broader issue.\n\nOn April 12, 1961, Soviet cosmonaut Yuri Gagarin became the first person to fly in space, reinforcing American fears about being left behind in a technological competition with the Soviet Union. At a meeting of the US House Committee on Science and Astronautics one day after Gagarin's flight, many congressmen pledged their support for a crash program aimed at ensuring that America would catch up. Kennedy was circumspect in his response to the news, refusing to make a commitment on America's response to the Soviets.\n\nOn April 20, Kennedy sent a memo to Vice President Lyndon B. Johnson, asking Johnson to look into the status of America's space program, and into programs that could offer NASA the opportunity to catch up. Johnson responded approximately one week later, concluding that \"we are neither making maximum effort nor achieving results necessary if this country is to reach a position of leadership.\" His memo concluded that a crewed Moon landing was far enough in the future that it was likely the United States would achieve it first.\n\nOn May 25, 1961, twenty days after the first American crewed spaceflight *Freedom 7*, Kennedy proposed the crewed Moon landing in a *Special Message to the Congress on Urgent National Needs*:\n\n> Now it is time to take longer strides—time for a great new American enterprise—time for this nation to take a clearly leading role in space achievement, which in many ways may hold the key to our future on Earth.\n> ... I believe that this nation should commit itself to achieving the goal, before this decade is out, of landing a man on the Moon and returning him safely to the Earth. No single space project in this period will be more impressive to mankind, or more important in the long-range exploration of space; and none will be so difficult or expensive to accomplish.\n\n## NASA expansion\n\nAt the time of Kennedy's proposal, only one American had flown in space—less than a month earlier—and NASA had not yet sent an astronaut into orbit. Even some NASA employees doubted whether Kennedy's ambitious goal could be met. By 1963, Kennedy even came close to agreeing to a joint US-USSR Moon mission, to eliminate duplication of effort.\n\nWith the clear goal of a crewed landing replacing the more nebulous goals of space stations and circumlunar flights, NASA decided that, in order to make progress quickly, it would discard the feasibility study designs of Convair, GE, and Martin, and proceed with Faget's command and service module design. The mission module was determined to be useful only as an extra room, and therefore unnecessary. They used Faget's design as the specification for another competition for spacecraft procurement bids in October 1961. On November 28, 1961, North American Aviation won the contract, although its bid was not rated as good as the Martin proposal. Webb, Dryden and Robert Seamans chose it in preference due to North American's longer association with NASA and its predecessor.\n\nLanding humans on the Moon by the end of 1969 required the most sudden burst of technological creativity, and the largest commitment of resources ($25 billion; $187 billion in 2024 US dollars) ever made by any nation in peacetime. At its peak, the Apollo program employed 400,000 people and required the support of over 20,000 industrial firms and universities.\n\nOn July 1, 1960, NASA established the Marshall Space Flight Center (MSFC) in Huntsville, Alabama. MSFC designed the heavy lift-class Saturn launch vehicles, which would be required for Apollo.\n\n### Manned Spacecraft Center\n\nIt became clear that managing the Apollo program would exceed the capabilities of Robert R. Gilruth's Space Task Group, which had been directing the nation's crewed space program from NASA's Langley Research Center. So Gilruth was given authority to grow his organization into a new NASA center, the Manned Spacecraft Center (MSC). A site was chosen in Houston, Texas, on land donated by Rice University, and Administrator Webb announced the conversion on September 19, 1961. It was also clear NASA would soon outgrow its practice of controlling missions from its Cape Canaveral Air Force Station launch facilities in Florida, so a new Mission Control Center would be included in the MSC.\n\nIn September 1962, by which time two Project Mercury astronauts had orbited the Earth, Gilruth had moved his organization to rented space in Houston, and construction of the MSC facility was under way, Kennedy visited Rice to reiterate his challenge in a famous speech:\n\n> But why, some say, the Moon? Why choose this as our goal? And they may well ask, why climb the highest mountain? Why, 35 years ago, fly the Atlantic? ...\n> We choose to go to the Moon. We choose to go to the Moon in this decade and do the other things, not because they are easy, but because they are hard; because that goal will serve to organize and measure the best of our energies and skills; because that challenge is one that we are willing to accept, one we are unwilling to postpone, and one we intend to win ...\n\nThe MSC was completed in September 1963. It was renamed by the United States Congress in honor of Lyndon B. Johnson soon after his death in 1973.\n\n### Launch Operations Center\n\nIt also became clear that Apollo would outgrow the Canaveral launch facilities in Florida. The two newest launch complexes were already being built for the Saturn I and IB rockets at the northernmost end: LC-34 and LC-37. An even bigger facility was needed for the mammoth rocket required for the crewed lunar mission, so land acquisition was started in July 1961 for a Launch Operations Center (LOC) immediately north of Canaveral at Merritt Island.\n\nThe design, development and construction of the center was conducted by Kurt H. Debus, a member of Wernher von Braun's original V-2 rocket engineering team. Debus was named the LOC's first Director. Construction began in November 1962. Following Kennedy's death, President Johnson issued an executive order on November 29, 1963, to rename the LOC and Cape Canaveral in honor of Kennedy.\n\nThe LOC included Launch Complex 39, a Launch Control Center, and a 130-million-cubic-foot (3,700,000 m^3^) Vertical Assembly Building (VAB). in which the space vehicle (launch vehicle and spacecraft) would be assembled on a mobile launcher platform and then moved by a crawler-transporter to one of several launch pads. Although at least three pads were planned, only two, designated A and B, were completed in October 1965. The LOC also included an Operations and Checkout Building (OCB) to which Gemini and Apollo spacecraft were initially received prior to being mated to their launch vehicles. The Apollo spacecraft could be tested in two vacuum chambers capable of simulating atmospheric pressure at altitudes up to 250,000 feet (76 km), which is nearly a vacuum.\n\n### Organization\n\nAdministrator Webb realized that in order to keep Apollo costs under control, he had to develop greater project management skills in his organization, so he recruited George E. Mueller for a high management job. Mueller accepted, on the condition that he have a say in NASA reorganization necessary to effectively administer Apollo. Webb then worked with Associate Administrator (later Deputy Administrator) Seamans to reorganize the Office of Manned Space Flight (OMSF). On July 23, 1963, Webb announced Mueller's appointment as Deputy Associate Administrator for Manned Space Flight, to replace then Associate Administrator D. Brainerd Holmes on his retirement effective September 1. Under Webb's reorganization, the directors of the Manned Spacecraft Center (Gilruth), Marshall Space Flight Center (von Braun), and the Launch Operations Center (Debus) reported to Mueller.\n\nBased on his industry experience on Air Force missile projects, Mueller realized some skilled managers could be found among high-ranking officers in the U.S. Air Force, so he got Webb's permission to recruit General Samuel C. Phillips, who gained a reputation for his effective management of the Minuteman program, as OMSF program controller. Phillips's superior officer Bernard A. Schriever agreed to loan Phillips to NASA, along with a staff of officers under him, on the condition that Phillips be made Apollo Program Director. Mueller agreed, and Phillips managed Apollo from January 1964, until it achieved the first human landing in July 1969, after which he returned to Air Force duty.\n\nCharles Fishman, in *One Giant Leap*, estimated the number of people and organizations involved into the Apollo program as \"410,000 men and women at some 20,000 different companies contributed to the effort\".\n\n## Choosing a mission mode\n\nOnce Kennedy had defined a goal, the Apollo mission planners were faced with the challenge of designing a spacecraft that could meet it while minimizing risk to human life, limiting cost, and not exceeding limits in possible technology and astronaut skill. Four possible mission modes were considered:\n\n- **Direct Ascent:** The spacecraft would be launched as a unit and travel directly to the lunar surface, without first going into lunar orbit. A 50,000-pound (23,000 kg) Earth return ship would land all three astronauts atop a 113,000-pound (51,000 kg) descent propulsion stage, which would be left on the Moon. This design would have required development of the extremely powerful Saturn C-8 or Nova launch vehicle to carry a 163,000-pound (74,000 kg) payload to the Moon.\n- **Earth Orbit Rendezvous (EOR):** Multiple rocket launches (up to 15 in some plans) would carry parts of the Direct Ascent spacecraft and propulsion units for translunar injection (TLI). These would be assembled into a single spacecraft in Earth orbit.\n- **Lunar Surface Rendezvous:** Two spacecraft would be launched in succession. The first, an automated vehicle carrying propellant for the return to Earth, would land on the Moon, to be followed some time later by the crewed vehicle. Propellant would have to be transferred from the automated vehicle to the crewed vehicle.\n- **Lunar Orbit Rendezvous (LOR):** This turned out to be the winning configuration, which achieved the goal with Apollo 11 on July 20, 1969: a single Saturn V launched a 96,886-pound (43,947 kg) spacecraft that was composed of a 63,608-pound (28,852 kg) Apollo command and service module which remained in orbit around the Moon and a 33,278-pound (15,095 kg) two-stage Apollo Lunar Module spacecraft which was flown by two astronauts to the surface. Its ascent stage was flown back to dock with the command module and was then discarded. Landing the smaller spacecraft on the Moon, and returning an even smaller part (10,042 pounds or 4,555 kilograms) to lunar orbit, minimized the total mass to be launched from Earth, but this was the last method initially considered because of the perceived risk of rendezvous and docking.\n\nIn early 1961, direct ascent was generally the mission mode in favor at NASA. Many engineers feared that rendezvous and docking, maneuvers that had not been attempted in Earth orbit, would be nearly impossible in lunar orbit. LOR advocates—including Tom Dolan at Vought and John Houbolt at Langley Research Center—emphasized the important weight reductions that were offered by the LOR approach. Throughout 1960 and 1961, Houbolt campaigned for the recognition of LOR as a viable and practical option. Bypassing the NASA hierarchy, he sent a series of memos and reports on the issue to Associate Administrator Robert Seamans; while acknowledging that he spoke \"somewhat as a voice in the wilderness\", Houbolt pleaded that LOR should not be discounted in studies of the question.\n\nSeamans's establishment of an ad hoc committee headed by his special technical assistant Nicholas E. Golovin in July 1961, to recommend a launch vehicle to be used in the Apollo program, represented a turning point in NASA's mission mode decision. This committee recognized that the chosen mode was an important part of the launch vehicle choice, and recommended in favor of a hybrid EOR-LOR mode. Its consideration of LOR—as well as Houbolt's ceaseless work—played an important role in publicizing the workability of the approach.\n\nIn late 1961 and early 1962, members of the Manned Spacecraft Center began to come around to support LOR, including the newly hired deputy director of the Office of Manned Space Flight, Joseph Shea, who became a champion of LOR. The engineers at Marshall Space Flight Center (MSFC), who were heavily invested in direct ascent, took longer to become convinced of its merits, but their conversion was announced by Wernher von Braun at a briefing on June 7, 1962.\n\nEven after NASA reached internal agreement, it was far from smooth sailing. Kennedy's science advisor Jerome Wiesner, who had expressed his opposition to human spaceflight to Kennedy before the President took office, and had opposed the decision to land people on the Moon, hired Golovin, who had left NASA, to chair his own \"Space Vehicle Panel\", ostensibly to monitor, but actually to second-guess NASA's decisions on the Saturn V launch vehicle and LOR by forcing Shea, Seamans, and even Webb to defend themselves, delaying its formal announcement to the press on July 11, 1962, and forcing Webb to still hedge the decision as \"tentative\".\n\nWiesner kept up the pressure, even making the disagreement public during a two-day September visit by the President to Marshall Space Flight Center. Wiesner blurted out \"No, that's no good\" in front of the press, during a presentation by von Braun. Webb jumped in and defended von Braun, until Kennedy ended the squabble by stating that the matter was \"still subject to final review\". Webb held firm and issued a request for proposal to candidate Lunar Excursion Module (LEM) contractors. Wiesner finally relented, unwilling to settle the dispute once and for all in Kennedy's office, because of the President's involvement with the October Cuban Missile Crisis, and fear of Kennedy's support for Webb. NASA announced the selection of Grumman as the LEM contractor in November 1962.\n\nSpace historian James Hansen concludes that:\n\n> Without NASA's adoption of this stubbornly held minority opinion in 1962, the United States may still have reached the Moon, but almost certainly it would not have been accomplished by the end of the 1960s, President Kennedy's target date.\n\nThe LOR method had the advantage of allowing the lander spacecraft to be used as a \"lifeboat\" in the event of a failure of the command ship. Some documents prove this theory was discussed before and after the method was chosen. In 1964 an MSC study concluded, \"The LM [as lifeboat] ... was finally dropped, because no single reasonable CSM failure could be identified that would prohibit use of the SPS.\" That type of failure happened on Apollo 13 when an oxygen tank explosion left the CSM without electrical power. The lunar module provided propulsion, electrical power and life support to get the crew home safely.\n\n## Spacecraft\n\nFaget's preliminary Apollo design employed a cone-shaped command module, supported by one of several service modules providing propulsion and electrical power, sized appropriately for the space station, cislunar, and lunar landing missions. Once Kennedy's Moon landing goal became official, detailed design began of a command and service module (CSM) in which the crew would spend the entire direct-ascent mission and lift off from the lunar surface for the return trip, after being soft-landed by a larger landing propulsion module. The final choice of lunar orbit rendezvous changed the CSM's role to the translunar ferry used to transport the crew, along with a new spacecraft, the Lunar Excursion Module (LEM, later shortened to LM (Lunar Module) but still pronounced /ˈlɛm/) which would take two individuals to the lunar surface and return them to the CSM.\n\n### Command and service module\n\nThe command module (CM) was the conical crew cabin, designed to carry three astronauts from launch to lunar orbit and back to an Earth ocean landing. It was the only component of the Apollo spacecraft to survive without major configuration changes as the program evolved from the early Apollo study designs. Its exterior was covered with an ablative heat shield, and had its own reaction control system (RCS) engines to control its attitude and steer its atmospheric entry path. Parachutes were carried to slow its descent to splashdown. The module was 11.42 feet (3.48 m) tall, 12.83 feet (3.91 m) in diameter, and weighed approximately 12,250 pounds (5,560 kg).\n\nA cylindrical service module (SM) supported the command module, with a service propulsion engine and an RCS with propellants, and a fuel cell power generation system with liquid hydrogen and liquid oxygen reactants. A high-gain S-band antenna was used for long-distance communications on the lunar flights. On the extended lunar missions, an orbital scientific instrument package was carried. The service module was discarded just before reentry. The module was 24.6 feet (7.5 m) long and 12.83 feet (3.91 m) in diameter. The initial lunar flight version weighed approximately 51,300 pounds (23,300 kg) fully fueled, while a later version designed to carry a lunar orbit scientific instrument package weighed just over 54,000 pounds (24,000 kg).\n\nNorth American Aviation won the contract to build the CSM, and also the second stage of the Saturn V launch vehicle for NASA. Because the CSM design was started early before the selection of lunar orbit rendezvous, the service propulsion engine was sized to lift the CSM off the Moon, and thus was oversized to about twice the thrust required for translunar flight. Also, there was no provision for docking with the lunar module. A 1964 program definition study concluded that the initial design should be continued as Block I which would be used for early testing, while Block II, the actual lunar spacecraft, would incorporate the docking equipment and take advantage of the lessons learned in Block I development.\n\n### Apollo Lunar Module\n\nThe Apollo Lunar Module (LM) was designed to descend from lunar orbit to land two astronauts on the Moon and take them back to orbit to rendezvous with the command module. Not designed to fly through the Earth's atmosphere or return to Earth, its fuselage was designed totally without aerodynamic considerations and was of an extremely lightweight construction. It consisted of separate descent and ascent stages, each with its own engine. The descent stage contained storage for the descent propellant, surface stay consumables, and surface exploration equipment. The ascent stage contained the crew cabin, ascent propellant, and a reaction control system. The initial LM model weighed approximately 33,300 pounds (15,100 kg), and allowed surface stays up to around 34 hours. An extended lunar module (ELM) weighed over 36,200 pounds (16,400 kg), and allowed surface stays of more than three days. The contract for design and construction of the lunar module was awarded to Grumman Aircraft Engineering Corporation, and the project was overseen by Thomas J. Kelly.\n\n## Launch vehicles\n\nBefore the Apollo program began, Wernher von Braun and his team of rocket engineers had started work on plans for very large launch vehicles, the Saturn series, and the even larger Nova series. In the midst of these plans, von Braun was transferred from the Army to NASA and was made Director of the Marshall Space Flight Center. The initial direct ascent plan to send the three-person Apollo command and service module directly to the lunar surface, on top of a large descent rocket stage, would require a Nova-class launcher, with a lunar payload capability of over 180,000 pounds (82,000 kg). The June 11, 1962, decision to use lunar orbit rendezvous enabled the Saturn V to replace the Nova, and the MSFC proceeded to develop the Saturn rocket family for Apollo.\n\nSince Apollo, like Mercury, used more than one launch vehicle for space missions, NASA used spacecraft-launch vehicle combination series numbers: AS-10x for Saturn I, AS-20x for Saturn IB, and AS-50x for Saturn V (compare Mercury-Redstone 3, Mercury-Atlas 6) to designate and plan all missions, rather than numbering them sequentially as in Project Gemini. This was changed by the time human flights began.\n\n### Little Joe II\n\nSince Apollo, like Mercury, would require a launch escape system (LES) in case of a launch failure, a relatively small rocket was required for qualification flight testing of this system. A rocket bigger than the Little Joe used by Mercury would be required, so the Little Joe II was built by General Dynamics/Convair. After an August 1963 qualification test flight, four LES test flights (A-001 through 004) were made at the White Sands Missile Range between May 1964 and January 1966.\n\n### Saturn I\n\nSaturn I, the first US heavy lift launch vehicle, was initially planned to launch partially equipped CSMs in low Earth orbit tests. The S-I first stage burned RP-1 with liquid oxygen (LOX) oxidizer in eight clustered Rocketdyne H-1 engines, to produce 1,500,000 pounds-force (6,670 kN) of thrust. The S-IV second stage used six liquid hydrogen-fueled Pratt & Whitney RL-10 engines with 90,000 pounds-force (400 kN) of thrust. The S-V third stage flew inactively on Saturn I four times.\n\nThe first four Saturn I test flights were launched from LC-34, with only the first stage live, carrying dummy upper stages filled with water. The first flight with a live S-IV was launched from LC-37. This was followed by five launches of boilerplate CSMs (designated AS-101 through AS-105) into orbit in 1964 and 1965. The last three of these further supported the Apollo program by also carrying Pegasus satellites, which verified the safety of the translunar environment by measuring the frequency and severity of micrometeorite impacts.\n\nIn September 1962, NASA planned to launch four crewed CSM flights on the Saturn I from late 1965 through 1966, concurrent with Project Gemini. The 22,500-pound (10,200 kg) payload capacity would have severely limited the systems which could be included, so the decision was made in October 1963 to use the uprated Saturn IB for all crewed Earth orbital flights.\n\n### Saturn IB\n\nThe Saturn IB was an upgraded version of the Saturn I. The S-IB first stage increased the thrust to 1,600,000 pounds-force (7,120 kN) by uprating the H-1 engine. The second stage replaced the S-IV with the S-IVB-200, powered by a single J-2 engine burning liquid hydrogen fuel with LOX, to produce 200,000 pounds-force (890 kN) of thrust. A restartable version of the S-IVB was used as the third stage of the Saturn V. The Saturn IB could send over 40,000 pounds (18,100 kg) into low Earth orbit, sufficient for a partially fueled CSM or the LM. Saturn IB launch vehicles and flights were designated with an AS-200 series number, \"AS\" indicating \"Apollo Saturn\" and the \"2\" indicating the second member of the Saturn rocket family.\n\n### Saturn V\n\nSaturn V launch vehicles and flights were designated with an AS-500 series number, \"AS\" indicating \"Apollo Saturn\" and the \"5\" indicating Saturn V. The three-stage Saturn V was designed to send a fully fueled CSM and LM to the Moon. It was 33 feet (10.1 m) in diameter and stood 363 feet (110.6 m) tall with its 96,800-pound (43,900 kg) lunar payload. Its capability grew to 103,600 pounds (47,000 kg) for the later advanced lunar landings. The S-IC first stage burned RP-1/LOX for a rated thrust of 7,500,000 pounds-force (33,400 kN), which was upgraded to 7,610,000 pounds-force (33,900 kN). The second and third stages burned liquid hydrogen; the third stage was a modified version of the S-IVB, with thrust increased to 230,000 pounds-force (1,020 kN) and capability to restart the engine for translunar injection after reaching a parking orbit.\n\n## Astronauts\n\nNASA's director of flight crew operations during the Apollo program was Donald K. \"Deke\" Slayton, one of the original Mercury Seven astronauts who was medically grounded in September 1962 due to a heart murmur. Slayton was responsible for making all Gemini and Apollo crew assignments.\n\nThirty-two astronauts were assigned to fly missions in the Apollo program. Twenty-four of these left Earth's orbit and flew around the Moon between December 1968 and December 1972 (three of them twice). Half of the 24 walked on the Moon's surface, though none of them returned to it after landing once. One of the moonwalkers was a trained geologist. Of the 32, Gus Grissom, Ed White, and Roger Chaffee were killed during a ground test in preparation for the Apollo 1 mission.\n\nThe Apollo astronauts were chosen from the Project Mercury and Gemini veterans, plus from two later astronaut groups. All missions were commanded by Gemini or Mercury veterans. Crews on all development flights (except the Earth orbit CSM development flights) through the first two landings on Apollo 11 and Apollo 12, included at least two (sometimes three) Gemini veterans. Harrison Schmitt, a geologist, was the first NASA scientist astronaut to fly in space, and landed on the Moon on the last mission, Apollo 17. Schmitt participated in the lunar geology training of all of the Apollo landing crews.\n\nNASA awarded all 32 of these astronauts its highest honor, the Distinguished Service Medal, given for \"distinguished service, ability, or courage\", and personal \"contribution representing substantial progress to the NASA mission\". The medals were awarded posthumously to Grissom, White, and Chaffee in 1969, then to the crews of all missions from Apollo 8 onward. The crew that flew the first Earth orbital test mission Apollo 7, Walter M. Schirra, Donn Eisele, and Walter Cunningham, were awarded the lesser NASA Exceptional Service Medal, because of discipline problems with the flight director's orders during their flight. In October 2008, the NASA Administrator decided to award them the Distinguished Service Medals. For Schirra and Eisele, this was posthumously.\n\n## Lunar mission profile\n\nThe first lunar landing mission was planned to proceed:\n\n- **Launch** The three Saturn V stages burn for about 11 minutes to achieve a 100-nautical-mile (190 km) circular parking orbit. The third stage burns a small portion of its fuel to achieve orbit.\n- **Translunar injection** After one to two orbits to verify readiness of spacecraft systems, the S-IVB third stage reignites for about six minutes to send the spacecraft to the Moon.\n- **Transposition and docking** The Spacecraft Lunar Module Adapter (SLA) panels separate to free the CSM and expose the LM. The command module pilot (CMP) moves the CSM out a safe distance, and turns 180°.\n- **Extraction** The CMP docks the CSM with the LM, and pulls the complete spacecraft away from the S-IVB. The lunar voyage takes between two and three days. Midcourse corrections are made as necessary using the SM engine.\n- **Lunar orbit insertion** The spacecraft passes about 60 nautical miles (110 km) behind the Moon, and the SM engine is fired to slow the spacecraft and put it into a 60-by-170-nautical-mile (110 by 310 km) orbit, which is soon circularized at 60 nautical miles by a second burn.\n- After a rest period, the commander (CDR) and lunar module pilot (LMP) move to the LM, power up its systems, and deploy the landing gear. The CSM and LM separate; the CMP visually inspects the LM, then the LM crew move a safe distance away and fire the descent engine for **Descent orbit insertion**, which takes it to a perilune of about 50,000 feet (15 km).\n- **Powered descent** At perilune, the descent engine fires again to start the descent. The CDR takes control after pitchover for a vertical landing.\n- The CDR and LMP perform one or more EVAs exploring the lunar surface and collecting samples, alternating with rest periods.\n- The ascent stage lifts off, using the descent stage as a launching pad.\n- The LM rendezvouses and docks with the CSM.\n- The CDR and LMP transfer back to the CM with their material samples, then the LM ascent stage is jettisoned, to eventually fall out of orbit and crash on the surface.\n- **Trans-Earth injection** The SM engine fires to send the CSM back to Earth.\n- The SM is jettisoned just before reentry, and the CM turns 180° to face its blunt end forward for reentry.\n- Atmospheric drag slows the CM. Aerodynamic heating surrounds it with an envelope of ionized air which causes a communications blackout for several minutes.\n- Parachutes are deployed, slowing the CM for a splashdown in the Pacific Ocean. The astronauts are recovered and brought to an aircraft carrier.\n\n### Profile variations\n- The first three lunar missions (Apollo 8, Apollo 10, and Apollo 11) used a free return trajectory, keeping a flight path coplanar with the lunar orbit, which would allow a return to Earth in case the SM engine failed to make lunar orbit insertion. Landing site lighting conditions on later missions dictated a lunar orbital plane change, which required a course change maneuver soon after TLI, and eliminated the free-return option.\n- After Apollo 12 placed the second of several seismometers on the Moon, the jettisoned LM ascent stages on Apollo 12 and later missions were deliberately crashed on the Moon at known locations to induce vibrations in the Moon's structure. The only exceptions to this were the Apollo 13 LM which burned up in the Earth's atmosphere, and Apollo 16, where a loss of attitude control after jettison prevented making a targeted impact.\n- As another active seismic experiment, the S-IVBs on Apollo 13 and subsequent missions were deliberately crashed on the Moon instead of being sent to solar orbit.\n- Starting with Apollo 13, descent orbit insertion was to be performed using the service module engine instead of the LM engine, in order to allow a greater fuel reserve for landing. This was actually done for the first time on Apollo 14, since the Apollo 13 mission was aborted before landing.\n\n## Development history\n\n### Uncrewed flight tests\n\nTwo Block I CSMs were launched from LC-34 on suborbital flights in 1966 with the Saturn IB. The first, AS-201 launched on February 26, reached an altitude of 265.7 nautical miles (492.1 km) and splashed down 4,577 nautical miles (8,477 km) downrange in the Atlantic Ocean. The second, AS-202 on August 25, reached 617.1 nautical miles (1,142.9 km) altitude and was recovered 13,900 nautical miles (25,700 km) downrange in the Pacific Ocean. These flights validated the service module engine and the command module heat shield.\n\nA third Saturn IB test, AS-203 launched from pad 37, went into orbit to support design of the S-IVB upper stage restart capability needed for the Saturn V. It carried a nose cone instead of the Apollo spacecraft, and its payload was the unburned liquid hydrogen fuel, the behavior of which engineers measured with temperature and pressure sensors, and a TV camera. This flight occurred on July 5, before AS-202, which was delayed because of problems getting the Apollo spacecraft ready for flight.\n\n### Preparation for crewed flight\n\nTwo crewed orbital Block I CSM missions were planned: AS-204 and AS-205. The Block I crew positions were titled Command Pilot, Senior Pilot, and Pilot. The Senior Pilot would assume navigation duties, while the Pilot would function as a systems engineer. The astronauts would wear a modified version of the Gemini spacesuit.\n\nAfter an uncrewed LM test flight AS-206, a crew would fly the first Block II CSM and LM in a dual mission known as AS-207/208, or AS-278 (each spacecraft would be launched on a separate Saturn IB). The Block II crew positions were titled Commander, Command Module Pilot, and Lunar Module Pilot. The astronauts would begin wearing a new Apollo A6L spacesuit, designed to accommodate lunar extravehicular activity (EVA). The traditional visor helmet was replaced with a clear \"fishbowl\" type for greater visibility, and the lunar surface EVA suit would include a water-cooled undergarment.\n\nDeke Slayton, the grounded Mercury astronaut who became director of flight crew operations for the Gemini and Apollo programs, selected the first Apollo crew in January 1966, with Grissom as Command Pilot, White as Senior Pilot, and rookie Donn F. Eisele as Pilot. But Eisele dislocated his shoulder twice aboard the KC135 weightlessness training aircraft, and had to undergo surgery on January 27. Slayton replaced him with Chaffee. NASA announced the final crew selection for AS-204 on March 21, 1966, with the backup crew consisting of Gemini veterans James McDivitt and David Scott, with rookie Russell L. \"Rusty\" Schweickart. Mercury/Gemini veteran Wally Schirra, Eisele, and rookie Walter Cunningham were announced on September 29 as the prime crew for AS-205.\n\nIn December 1966, the AS-205 mission was canceled, since the validation of the CSM would be accomplished on the 14-day first flight, and AS-205 would have been devoted to space experiments and contribute no new engineering knowledge about the spacecraft. Its Saturn IB was allocated to the dual mission, now redesignated AS-205/208 or AS-258, planned for August 1967. McDivitt, Scott and Schweickart were promoted to the prime AS-258 crew, and Schirra, Eisele and Cunningham were reassigned as the Apollo 1 backup crew.\n\n#### Program delays\n\nThe spacecraft for the AS-202 and AS-204 missions were delivered by North American Aviation to the Kennedy Space Center with long lists of equipment problems which had to be corrected before flight; these delays caused the launch of AS-202 to slip behind AS-203, and eliminated hopes the first crewed mission might be ready to launch as soon as November 1966, concurrently with the last Gemini mission. Eventually, the planned AS-204 flight date was pushed to February 21, 1967.\n\nNorth American Aviation was prime contractor not only for the Apollo CSM, but for the Saturn V S-II second stage as well, and delays in this stage pushed the first uncrewed Saturn V flight AS-501 from late 1966 to November 1967. (The initial assembly of AS-501 had to use a dummy spacer spool in place of the stage.)\n\nThe problems with North American were severe enough in late 1965 to cause Manned Space Flight Administrator George Mueller to appoint program director Samuel Phillips to head a \"tiger team\" to investigate North American's problems and identify corrections. Phillips documented his findings in a December 19 letter to NAA president Lee Atwood, with a strongly worded letter by Mueller, and also gave a presentation of the results to Mueller and Deputy Administrator Robert Seamans. Meanwhile, Grumman was also encountering problems with the Lunar Module, eliminating hopes it would be ready for crewed flight in 1967, not long after the first crewed CSM flights.\n\n#### Apollo 1 fire\n\nGrissom, White, and Chaffee decided to name their flight Apollo 1 as a motivational focus on the first crewed flight. They trained and conducted tests of their spacecraft at North American, and in the altitude chamber at the Kennedy Space Center. A \"plugs-out\" test was planned for January, which would simulate a launch countdown on LC-34 with the spacecraft transferring from pad-supplied to internal power. If successful, this would be followed by a more rigorous countdown simulation test closer to the February 21 launch, with both spacecraft and launch vehicle fueled.\n\nThe plugs-out test began on the morning of January 27, 1967, and immediately was plagued with problems. First, the crew noticed a strange odor in their spacesuits which delayed the sealing of the hatch. Then, communications problems frustrated the astronauts and forced a hold in the simulated countdown. During this hold, an electrical fire began in the cabin and spread quickly in the high pressure, 100% oxygen atmosphere. Pressure rose high enough from the fire that the cabin inner wall burst, allowing the fire to erupt onto the pad area and frustrating attempts to rescue the crew. The astronauts were asphyxiated before the hatch could be opened.\n\nNASA immediately convened an accident review board, overseen by both houses of Congress. While the determination of responsibility for the accident was complex, the review board concluded that \"deficiencies existed in command module design, workmanship and quality control\". At the insistence of NASA Administrator Webb, North American removed Harrison Storms as command module program manager. Webb also reassigned Apollo Spacecraft Program Office (ASPO) Manager Joseph Francis Shea, replacing him with George Low.\n\nTo remedy the causes of the fire, changes were made in the Block II spacecraft and operational procedures, the most important of which were use of a nitrogen/oxygen mixture instead of pure oxygen before and during launch, and removal of flammable cabin and space suit materials. The Block II design already called for replacement of the Block I plug-type hatch cover with a quick-release, outward opening door. NASA discontinued the crewed Block I program, using the Block I spacecraft only for uncrewed Saturn V flights. Crew members would also exclusively wear modified, fire-resistant A7L Block II space suits, and would be designated by the Block II titles, regardless of whether a LM was present on the flight or not.\n\n#### Uncrewed Saturn V and LM tests\n\nOn April 24, 1967, Mueller published an official Apollo mission numbering scheme, using sequential numbers for all flights, crewed or uncrewed. The sequence would start with Apollo 4 to cover the first three uncrewed flights while retiring the Apollo 1 designation to honor the crew, per their widows' wishes.\n\nIn September 1967, Mueller approved a sequence of mission types which had to be accomplished in order to achieve the crewed lunar landing. Each step had to be accomplished before the next ones could be performed, and it was unknown how many tries of each mission would be necessary; therefore letters were used instead of numbers. The **A** missions were uncrewed Saturn V validation; **B** was uncrewed LM validation using the Saturn IB; **C** was crewed CSM Earth orbit validation using the Saturn IB; **D** was the first crewed CSM/LM flight (this replaced AS-258, using a single Saturn V launch); **E** would be a higher Earth orbit CSM/LM flight; **F** would be the first lunar mission, testing the LM in lunar orbit but without landing (a \"dress rehearsal\"); and **G** would be the first crewed landing. The list of types covered follow-on lunar exploration to include **H** lunar landings, **I** for lunar orbital survey missions, and **J** for extended-stay lunar landings.\n\nThe delay in the CSM caused by the fire enabled NASA to catch up on human-rating the LM and Saturn V. Apollo 4 (AS-501) was the first uncrewed flight of the Saturn V, carrying a Block I CSM on November 9, 1967. The capability of the command module's heat shield to survive a trans-lunar reentry was demonstrated by using the service module engine to ram it into the atmosphere at higher than the usual Earth-orbital reentry speed.\n\nApollo 5 (AS-204) was the first uncrewed test flight of the LM in Earth orbit, launched from pad 37 on January 22, 1968, by the Saturn IB that would have been used for Apollo 1. The LM engines were successfully test-fired and restarted, despite a computer programming error, which cut short the first descent stage firing. The ascent engine was fired in abort mode, known as a \"fire-in-the-hole\" test, where it was lit simultaneously with jettison of the descent stage. Although Grumman wanted a second uncrewed test, George Low decided the next LM flight would be crewed.\n\nThis was followed on April 4, 1968, by Apollo 6 (AS-502) which carried a CSM and a LM Test Article as ballast. The intent of this mission was to achieve trans-lunar injection, followed closely by a simulated direct-return abort, using the service module engine to achieve another high-speed reentry. The Saturn V experienced pogo oscillation, a problem caused by non-steady engine combustion, which damaged fuel lines in the second and third stages. Two S-II engines shut down prematurely, but the remaining engines were able to compensate. The damage to the third stage engine was more severe, preventing it from restarting for trans-lunar injection. Mission controllers were able to use the service module engine to essentially repeat the flight profile of Apollo 4. Based on the good performance of Apollo 6 and identification of satisfactory fixes to the Apollo 6 problems, NASA declared the Saturn V ready to fly crew, canceling a third uncrewed test.\n\n### Crewed development missions\n\nApollo 7, launched from LC-34 on October 11, 1968, was the C mission, crewed by Schirra, Eisele, and Cunningham. It was an 11-day Earth-orbital flight which tested the CSM systems.\n\nApollo 8 was planned to be the D mission in December 1968, crewed by McDivitt, Scott and Schweickart, launched on a Saturn V instead of two Saturn IBs. In the summer it had become clear that the LM would not be ready in time. Rather than waste the Saturn V on another simple Earth-orbiting mission, ASPO Manager George Low suggested the bold step of sending Apollo 8 to orbit the Moon instead, deferring the D mission to the next mission in March 1969, and eliminating the E mission. This would keep the program on track. The Soviet Union had sent two tortoises, mealworms, wine flies, and other lifeforms around the Moon on September 15, 1968, aboard Zond 5, and it was believed they might soon repeat the feat with human cosmonauts. The decision was not announced publicly until completion of Apollo 7. Gemini veterans Frank Borman and Jim Lovell, and rookie William Anders captured the world's attention by making ten lunar orbits in 20 hours, transmitting television pictures of the lunar surface on Christmas Eve, and returning safely to Earth.\n\nThe following March, LM flight, rendezvous and docking were demonstrated in Earth orbit on Apollo 9, and Schweickart tested the full lunar EVA suit with its portable life support system (PLSS) outside the LM. The F mission was carried out on Apollo 10 in May 1969 by Gemini veterans Thomas P. Stafford, John Young and Eugene Cernan. Stafford and Cernan took the LM to within 50,000 feet (15 km) of the lunar surface.\n\nThe G mission was achieved on Apollo 11 in July 1969 by an all-Gemini veteran crew consisting of Neil Armstrong, Michael Collins and Buzz Aldrin. Armstrong and Aldrin performed the first landing at the Sea of Tranquility at 20:17:40 UTC on July 20, 1969. They spent a total of 21 hours, 36 minutes on the surface, and spent 2 hours, 31 minutes outside the spacecraft, walking on the surface, taking photographs, collecting material samples, and deploying automated scientific instruments, while continuously sending black-and-white television back to Earth. The astronauts returned safely on July 24.\n\n> That's one small step for [a] man, one giant leap for mankind.\n\n— Neil Armstrong, just after stepping onto the Moon's surface\n\n### Production lunar landings\n\nIn November 1969, Charles \"Pete\" Conrad became the third person to step onto the Moon, which he did while speaking more informally than had Armstrong:\n\n> Whoopee! Man, that may have been a small one for Neil, but that's a long one for me.\n\n— Pete Conrad\n\nConrad and rookie Alan L. Bean made a precision landing of Apollo 12 within walking distance of the Surveyor 3 uncrewed lunar probe, which had landed in April 1967 on the Ocean of Storms. The command module pilot was Gemini veteran Richard F. Gordon Jr. Conrad and Bean carried the first lunar surface color television camera, but it was damaged when accidentally pointed into the Sun. They made two EVAs totaling 7 hours and 45 minutes. On one, they walked to the Surveyor, photographed it, and removed some parts which they returned to Earth.\n\nThe contracted batch of 15 Saturn Vs was enough for lunar landing missions through Apollo 20. Shortly after Apollo 11, NASA publicized a preliminary list of eight more planned landing sites after Apollo 12, with plans to increase the mass of the CSM and LM for the last five missions, along with the payload capacity of the Saturn V. These final missions would combine the I and J types in the 1967 list, allowing the CMP to operate a package of lunar orbital sensors and cameras while his companions were on the surface, and allowing them to stay on the Moon for over three days. These missions would also carry the Lunar Roving Vehicle (LRV) increasing the exploration area and allowing televised liftoff of the LM. Also, the Block II spacesuit was revised for the extended missions to allow greater flexibility and visibility for driving the LRV.\n\nThe success of the first two landings allowed the remaining missions to be crewed with a single veteran as commander, with two rookies. Apollo 13 launched Lovell, Jack Swigert, and Fred Haise in April 1970, headed for the Fra Mauro formation. But two days out, a liquid oxygen tank exploded, disabling the service module and forcing the crew to use the LM as a \"lifeboat\" to return to Earth. Another NASA review board was convened to determine the cause, which turned out to be a combination of damage of the tank in the factory, and a subcontractor not making a tank component according to updated design specifications. Apollo was grounded again, for the remainder of 1970 while the oxygen tank was redesigned and an extra one was added.\n\n#### Mission cutbacks\n\nAbout the time of the first landing in 1969, it was decided to use an existing Saturn V to launch the Skylab orbital laboratory pre-built on the ground, replacing the original plan to construct it in orbit from several Saturn IB launches; this eliminated Apollo 20. NASA's yearly budget also began to shrink in light of the landing, and NASA also had to make funds available for the development of the upcoming Space Shuttle. By 1971, the decision was made to also cancel missions 18 and 19. The two unused Saturn Vs became museum exhibits at the John F. Kennedy Space Center on Merritt Island, Florida, George C. Marshall Space Center in Huntsville, Alabama, Michoud Assembly Facility in New Orleans, Louisiana, and Lyndon B. Johnson Space Center in Houston, Texas.\n\nThe cutbacks forced mission planners to reassess the original planned landing sites in order to achieve the most effective geological sample and data collection from the remaining four missions. Apollo 15 had been planned to be the last of the H series missions, but since there would be only two subsequent missions left, it was changed to the first of three J missions.\n\nApollo 13's Fra Mauro mission was reassigned to Apollo 14, commanded in February 1971 by Mercury veteran Alan Shepard, with Stuart Roosa and Edgar Mitchell. This time the mission was successful. Shepard and Mitchell spent 33 hours and 31 minutes on the surface, and completed two EVAs totalling 9 hours 24 minutes, which was a record for the longest EVA by a lunar crew at the time.\n\nIn August 1971, just after conclusion of the Apollo 15 mission, President Richard Nixon proposed canceling the two remaining lunar landing missions, Apollo 16 and 17. Office of Management and Budget Deputy Director Caspar Weinberger was opposed to this, and persuaded Nixon to keep the remaining missions.\n\n#### Extended missions\n\nApollo 15 was launched on July 26, 1971, with David Scott, Alfred Worden and James Irwin. Scott and Irwin landed on July 30 near Hadley Rille, and spent just under two days, 19 hours on the surface. In over 18 hours of EVA, they collected about 77 kilograms (170 lb) of lunar material.\n\nApollo 16 landed in the Descartes Highlands on April 20, 1972. The crew was commanded by John Young, with Ken Mattingly and Charles Duke. Young and Duke spent just under three days on the surface, with a total of over 20 hours EVA.\n\nApollo 17 was the last of the Apollo program, landing in the Taurus–Littrow region in December 1972. Eugene Cernan commanded Ronald E. Evans and NASA's first scientist-astronaut, geologist Harrison H. Schmitt. Schmitt was originally scheduled for Apollo 18, but the lunar geological community lobbied for his inclusion on the final lunar landing. Cernan and Schmitt stayed on the surface for just over three days and spent just over 23 hours of total EVA.\n\n#### Canceled missions\n\nSeveral missions were planned for but were canceled before details were finalized.\n\n## Mission summary\n|Mission|Date|LV|CSM|LM|Crew|Summary|\n|--|--|--|--|--|--|--|\n|AS-201|Feb 26, 1966|AS-201|CSM-009|N/a|N/a|First flight of Saturn IB and Block I CSM; suborbital to Atlantic Ocean; qualified heat shield to orbital reentry speed.|\n|AS-203|Jul 5, 1966|AS-203|N/a|N/a|N/a|No spacecraft; observations of liquid hydrogen fuel behavior in orbit to support design of S-IVB restart capability.|\n|AS-202|Aug 25, 1966|AS-202|CSM-011|N/a|N/a|Suborbital flight of CSM to Pacific Ocean.|\n|Apollo 1|Feb 21, 1967|SA-204|CSM-012|N/a|Gus Grissom Ed White Roger B. Chaffee|Not flown. All crew members died in a fire during a launch pad test on January 27, 1967.|\n|Apollo 4|Nov 9, 1967|SA-501|CSM-017|LTA-10R|N/a|First test flight of Saturn V, placed a CSM in a high Earth orbit; demonstrated S-IVB restart; qualified CM heat shield to lunar reentry speed.|\n|Apollo 5|Jan 22–23, 1968|SA-204|N/a|LM-1|N/a|Earth orbital flight test of LM, launched on Saturn IB; demonstrated ascent and descent propulsion; human-rated the LM. No crew.|\n|Apollo 6|Apr 4, 1968|SA-502|CM-020 SM-014|LTA-2R|N/a|Uncrewed, second flight of Saturn V, attempted demonstration of trans-lunar injection, and direct-return abort using SM engine; three engine failures, including failure of S-IVB restart. Flight controllers used SM engine to repeat Apollo 4's flight profile. Human-rated the Saturn V.|\n|Apollo 7|Oct 11–22, 1968|SA-205|CSM-101|N/a|Wally Schirra Walt Cunningham Donn Eisele|First crewed Earth orbital demonstration of Block II CSM, launched on Saturn IB. First live television broadcast from a crewed mission.|\n|Apollo 8|Dec 21–27, 1968|SA-503|CSM-103|LTA-B|Frank Borman James Lovell William Anders|First crewed flight of Saturn V; First crewed flight to Moon; CSM made 10 lunar orbits in 20 hours.|\n|Apollo 9|Mar 3–13, 1969|SA-504|CSM-104 *Gumdrop*|LM-3 *Spider*|James McDivitt David Scott Russell Schweickart|Second crewed flight of Saturn V; First crewed flight of CSM and LM in Earth orbit; demonstrated portable life support system to be used on the lunar surface.|\n|Apollo 10|May 18–26, 1969|SA-505|CSM-106 *Charlie Brown*|LM-4 *Snoopy*|Thomas Stafford John Young Eugene Cernan|Dress rehearsal for first lunar landing; flew LM down to 50,000 ft (15 km; 9.5 mi) from lunar surface.|\n|Apollo 11|Jul 16–24, 1969|SA-506|CSM-107 *Columbia*|LM-5 *Eagle*|Neil Armstrong Michael Collins Buzz Aldrin|First landing, in Tranquility Base, Sea of Tranquility. Surface EVA time: 2h 31m. Samples returned: 47.51 lb (21.55 kg).|\n|Apollo 12|Nov 14–24, 1969|SA-507|CSM-108 *Yankee Clipper*|LM-6 *Intrepid*|Pete Conrad Richard Gordon Alan Bean|Second landing, in Ocean of Storms near Surveyor 3. Surface EVA time: 7h 45m. Samples returned: 75.62 lb (34.30 kg).|\n|Apollo 13|Apr 11–17, 1970|SA-508|CSM-109 *Odyssey*|LM-7 *Aquarius*|James Lovell Jack Swigert Fred Haise|Third landing attempt aborted in transit to the Moon, due to SM failure. Crew used LM as \"lifeboat\" to return to Earth. Mission called a \"successful failure\".|\n|Apollo 14|Jan 31 – Feb 9, 1971|SA-509|CSM-110 *Kitty Hawk*|LM-8 *Antares*|Alan Shepard Stuart Roosa Edgar Mitchell|Third landing, in Fra Mauro formation. Surface EVA time: 9h 21m. Samples returned: 94.35 lb (42.80 kg).|\n|Apollo 15|Jul 26 – Aug 7, 1971|SA-510|CSM-112 *Endeavour*|LM-10 *Falcon*|David Scott Alfred Worden James Irwin|Fourth landing, in Hadley-Apennine. First extended mission, used Rover on Moon. Surface EVA time: 18h 33m. Samples returned: 169.10 lb (76.70 kg).|\n|Apollo 16|Apr 16–27, 1972|SA-511|CSM-113 *Casper*|LM-11 *Orion*|John Young Ken Mattingly Charles Duke|Fifth landing, in Plain of Descartes. Second extended mission, used Rover on Moon. Surface EVA time: 20h 14m. Samples returned: 207.89 lb (94.30 kg).|\n|Apollo 17|Dec 7–19, 1972|SA-512|CSM-114 *America*|LM-12 *Challenger*|Eugene Cernan Ronald Evans Harrison Schmitt|Only Saturn V night launch. Sixth landing, in Taurus–Littrow. Third extended mission, used Rover on Moon. First geologist on the Moon. Apollo's last crewed Moon landing. Surface EVA time: 22h 2m. Samples returned: 243.40 lb (110.40 kg).|\n\nSource: *Apollo by the Numbers: A Statistical Reference* (Orloff 2004).\n\n## Samples returned\n\nThe most famous of the Moon rocks recovered, the Genesis Rock, returned from Apollo 15.\n\nApollo 16's sample 61016, better known as Big Muley, is the largest sample collected during the Apollo program\n\nThe Apollo program returned over 382 kg (842 lb) of lunar rocks and soil to the Lunar Receiving Laboratory in Houston. Today, 75% of the samples are stored at the Lunar Sample Laboratory Facility built in 1979.\n\nThe rocks collected from the Moon are extremely old compared to rocks found on Earth, as measured by radiometric dating techniques. They range in age from about 3.2 billion years for the basaltic samples derived from the lunar maria, to about 4.6 billion years for samples derived from the highlands crust. As such, they represent samples from a very early period in the development of the Solar System, that are largely absent on Earth. One important rock found during the Apollo Program is dubbed the Genesis Rock, retrieved by astronauts David Scott and James Irwin during the Apollo 15 mission. This anorthosite rock is composed almost exclusively of the calcium-rich feldspar mineral anorthite, and is believed to be representative of the highland crust. A geochemical component called KREEP was discovered by Apollo 12, which has no known terrestrial counterpart. KREEP and the anorthositic samples have been used to infer that the outer portion of the Moon was once completely molten (see lunar magma ocean).\n\nAlmost all the rocks show evidence of impact process effects. Many samples appear to be pitted with micrometeoroid impact craters, which is never seen on Earth rocks, due to the thick atmosphere. Many show signs of being subjected to high-pressure shock waves that are generated during impact events. Some of the returned samples are of *impact melt* (materials melted near an impact crater.) All samples returned from the Moon are highly brecciated as a result of being subjected to multiple impact events.\n\nFrom analyses of the composition of the returned lunar samples, it is now believed that the Moon was created through the impact of a large astronomical body with Earth.\n\n## Costs\n\nApollo cost $25.4 billion or approximately $257 billion (2023) using improved cost analysis.\n\nOf this amount, $20.2 billion ($149 billion adjusted) was spent on the design, development, and production of the Saturn family of launch vehicles, the Apollo spacecraft, spacesuits, scientific experiments, and mission operations. The cost of constructing and operating Apollo-related ground facilities, such as the NASA human spaceflight centers and the global tracking and data acquisition network, added an additional $5.2 billion ($38.3 billion adjusted).\n\nThe amount grows to $28 billion ($280 billion adjusted) if the costs for related projects such as Project Gemini and the robotic Ranger, Surveyor, and Lunar Orbiter programs are included.\n\nNASA's official cost breakdown, as reported to Congress in the Spring of 1973, is as follows:\n\n|Project Apollo|Cost (original, billion $)|\n|--|--|\n|Apollo spacecraft|8.5|\n|Saturn launch vehicles|9.1|\n|Launch vehicle engine development|0.9|\n|Operations|1.7|\n|**Total R&D**|**20.2**|\n|Tracking and data acquisition|0.9|\n|Ground facilities|1.8|\n|Operation of installations|2.5|\n|**Total**|**25.4**|\n\nAccurate estimates of human spaceflight costs were difficult in the early 1960s, as the capability was new and management experience was lacking. Preliminary cost analysis by NASA estimated $7 billion – $12 billion for a crewed lunar landing effort. NASA Administrator James Webb increased this estimate to $20 billion before reporting it to Vice President Johnson in April 1961.\n\nProject Apollo was a massive undertaking, representing the largest research and development project in peacetime. At its peak, it employed over 400,000 employees and contractors around the country and accounted for more than half of NASA's total spending in the 1960s. After the first Moon landing, public and political interest waned, including that of President Nixon, who wanted to rein in federal spending. NASA's budget could not sustain Apollo missions which cost, on average, $445 million ($2.73 billion adjusted) each while simultaneously developing the Space Shuttle. The final fiscal year of Apollo funding was 1973.\n\n## Apollo Applications Program\n\nLooking beyond the crewed lunar landings, NASA investigated several post-lunar applications for Apollo hardware. The Apollo Extension Series (*Apollo X*) proposed up to 30 flights to Earth orbit, using the space in the Spacecraft Lunar Module Adapter (SLA) to house a small orbital laboratory (workshop). Astronauts would continue to use the CSM as a ferry to the station. This study was followed by design of a larger orbital workshop to be built in orbit from an empty S-IVB Saturn upper stage and grew into the Apollo Applications Program (AAP). The workshop was to be supplemented by the Apollo Telescope Mount, which could be attached to the ascent stage of the lunar module via a rack. The most ambitious plan called for using an empty S-IVB as an interplanetary spacecraft for a Venus fly-by mission.\n\nThe S-IVB orbital workshop was the only one of these plans to make it off the drawing board. Dubbed Skylab, it was assembled on the ground rather than in space, and launched in 1973 using the two lower stages of a Saturn V. It was equipped with an Apollo Telescope Mount. Skylab's last crew departed the station on February 8, 1974, and the station itself re-entered the atmosphere in 1979 after development of the Space Shuttle was delayed too long to save it.\n\nThe Apollo–Soyuz program also used Apollo hardware for the first joint nation spaceflight, paving the way for future cooperation with other nations in the Space Shuttle and International Space Station programs.\n\n## Recent observations\n\nIn 2008, Japan Aerospace Exploration Agency's SELENE probe observed evidence of the halo surrounding the Apollo 15 Lunar Module blast crater while orbiting above the lunar surface.\n\nBeginning in 2009, NASA's robotic Lunar Reconnaissance Orbiter, while orbiting 50 kilometers (31 mi) above the Moon, photographed the remnants of the Apollo program left on the lunar surface, and each site where crewed Apollo flights landed. All of U.S. flags left on the Moon during the Apollo missions were found to still be standing, with the exception of the one left during the Apollo 11 mission, which was blown over during that mission's lift-off from the lunar surface; the degree to which these flags retain their original colors remains unknown. The flags cannot be seen through a telescope from Earth.\n\nIn a November 16, 2009, editorial, *The New York Times* opined:\n\n> [T]here's something terribly wistful about these photographs of the Apollo landing sites. The detail is such that if Neil Armstrong were walking there now, we could make him out, make out his footsteps even, like the astronaut footpath clearly visible in the photos of the Apollo 14 site. Perhaps the wistfulness is caused by the sense of simple grandeur in those Apollo missions. Perhaps, too, it's a reminder of the risk we all felt after the Eagle had landed—the possibility that it might be unable to lift off again and the astronauts would be stranded on the Moon. But it may also be that a photograph like this one is as close as we're able to come to looking directly back into the human past ... There the [Apollo 11] lunar module sits, parked just where it landed 40 years ago, as if it still really were 40 years ago and all the time since merely imaginary.\n\n## Legacy\n\n### Science and engineering\n\nThe Apollo program has been described as the greatest technological achievement in human history. Apollo stimulated many areas of technology, leading to over 1,800 spinoff products as of 2015, including advances in the development of cordless power tools, fireproof materials, heart monitors, solar panels, digital imaging, and the use of liquid methane as fuel. The flight computer design used in both the lunar and command modules was, along with the Polaris and Minuteman missile systems, the driving force behind early research into integrated circuits (ICs). By 1963, Apollo was using 60 percent of the United States' production of ICs. The crucial difference between the requirements of Apollo and the missile programs was Apollo's much greater need for reliability. While the Navy and Air Force could work around reliability problems by deploying more missiles, the political and financial cost of failure of an Apollo mission was unacceptably high.\n\nTechnologies and techniques required for Apollo were developed by Project Gemini. The Apollo project was enabled by NASA's adoption of new advances in semiconductor electronic technology, including metal–oxide–semiconductor field-effect transistors (MOSFETs) in the Interplanetary Monitoring Platform (IMP) and silicon integrated circuit chips in the Apollo Guidance Computer (AGC).\n\n### Cultural impact\n\nThe crew of Apollo 8 sent the first live televised pictures of the Earth and the Moon back to Earth, and read from the creation story in the Book of Genesis, on Christmas Eve 1968. An estimated one-quarter of the population of the world saw—either live or delayed—the Christmas Eve transmission during the ninth orbit of the Moon, and an estimated one-fifth of the population of the world watched the live transmission of the Apollo 11 moonwalk.\n\nThe Apollo program also affected environmental activism in the 1970s due to photos taken by the astronauts. The most well known include *Earthrise*, taken by William Anders on Apollo 8, and *The Blue Marble*, taken by the Apollo 17 astronauts. *The Blue Marble* was released during a surge in environmentalism, and became a symbol of the environmental movement as a depiction of Earth's frailty, vulnerability, and isolation amid the vast expanse of space.\n\nAccording to *The Economist*, Apollo succeeded in accomplishing President Kennedy's goal of taking on the Soviet Union in the Space Race by accomplishing a singular and significant achievement, to demonstrate the superiority of the free-market system. The publication noted the irony that in order to achieve the goal, the program required the organization of tremendous public resources within a vast, centralized government bureaucracy.\n\n### Apollo 11 broadcast data restoration project\n\nPrior to Apollo 11's 40th anniversary in 2009, NASA searched for the original videotapes of the mission's live televised moonwalk. After an exhaustive three-year search, it was concluded that the tapes had probably been erased and reused. A new digitally remastered version of the best available broadcast television footage was released instead.\n\n## Depictions on film\n\n### Documentaries\n\nNumerous documentary films cover the Apollo program and the Space Race, including:\n\n- *Footprints on the Moon* (1969)\n- *Moonwalk One* (1970)\n- *The Greatest Adventure* (1978)\n- *For All Mankind* (1989)\n- *Moon Shot* (1994 miniseries)\n- \"Moon\" from the BBC miniseries *The Planets* (1999)\n- *Magnificent Desolation: Walking on the Moon 3D* (2005)\n- *The Wonder of It All* (2007)\n- *In the Shadow of the Moon* (2007)\n- *When We Left Earth: The NASA Missions* (2008 miniseries)\n- *Moon Machines* (2008 miniseries)\n- *James May on the Moon* (2009)\n- *NASA's Story* (2009 miniseries)\n- *Apollo 11* (2019)\n- *Chasing the Moon* (2019 miniseries)\n\n### Docudramas\n\nSome missions have been dramatized:\n\n- *Apollo 13* (1995)\n- *Apollo 11* (1996)\n- *From the Earth to the Moon* (1998)\n- *The Dish* (2000)\n- *Space Race* (2005)\n- *Moonshot* (2009)\n- *First Man* (2018)\n\n### Fictional\n\nThe Apollo program has been the focus of several works of fiction, including:\n\n- *Apollo 18* (2011), horror movie which was released to negative reviews.\n- *Transformers: Dark of the Moon* (2011), Science Fiction/Action movie. The film depicts the Apollo Program as having been created to study and explore a Cybertronian spacecraft known as \"The Ark,\" which crash landed on the dark side of the Moon in the early 1960s.\n- *Men in Black 3* (2012), Science Fiction/Comedy movie. Agent J, played by Will Smith, goes back to the Apollo 11 launch in 1969 to ensure that a global protection system is launched in to space.\n- *For All Mankind* (2019), TV series depicting an alternate history in which the Soviet Union was the first nation to land a man on the Moon and the Apollo missions were expanded as part of an accelerated Space Race, culminating in the establishment of a permanent US Moon base called Jamestown.\n- *The Apollo Murders* (2021), an alternate history novel by Chris Hadfield set in 1973 during the Cold War in which Apollo 18 is launched on a clandestine military mission to the Moon\n- *Indiana Jones and the Dial of Destiny* (2023), fifth Indiana Jones film, in which Jürgen Voller, a NASA member and ex-Nazi involved with the Apollo program, wants to time travel. The New York City parade for the Apollo 11 crew is portrayed as a plot point.\n\n## See also\n\n- Apollo 11 in popular culture\n- Apollo program training\n- Apollo Lunar Surface Experiments Package\n- Artemis Program\n- Exploration of the Moon\n- Leslie Cantwell collection\n- List of artificial objects on the Moon\n- List of crewed spacecraft\n- List of missions to the Moon\n- Soviet crewed lunar programs\n- Stolen and missing Moon rocks\n\n## Notes\n\n## References\n\n### Citations\n\n### Sources\n\n- This article incorporates public domain material from websites or documents of the National Aeronautics and Space Administration.\n\n## Further reading\n\n- Gleick, James, \"Moon Fever\" [review of Oliver Morton, *The Moon: A History of the Future*; *Apollo's Muse: The Moon in the Age of Photography*, an exhibition at the Metropolitan Museum of Art, New York City, July 3 – September 22, 2019; Douglas Brinkley, *American Moonshot: John F. Kennedy and the Great Space Race*; Brandon R. Brown, *The Apollo Chronicles: Engineering America's First Moon Missions*; Roger D. Launius, *Reaching for the Moon: A Short History of the Space Race*; *Apollo 11*, a documentary film directed by Todd Douglas Miller; and Michael Collins, *Carrying the Fire: An Astronaut's Journeys (50th Anniversary Edition)*], *The New York Review of Books*, vol. LXVI, no. 13 (15 August 2019), pp. 54–58.\n\n## External links\n\nWikimedia Commons has media related to Apollo program.\n\nWikinews has news related to:\n\n*** Apollo program ** *\n\nLibrary resources about\n**Apollo program**\n\n- Online books\n- Resources in your library\n- Resources in other libraries\n\n- Apollo program history at NASA's Human Space Flight (HSF) website\n- The Apollo Program at the NASA History Program Office\n- The Apollo Program at the National Air and Space Museum\n- Apollo 35th Anniversary Interactive Feature at NASA (in Flash)\n- Lunar Mission Timeline at the Lunar and Planetary Institute\n- Apollo Collection, The University of Alabama in Huntsville Archives and Special Collections\n\n### NASA reports\n- Apollo Program Summary Report (PDF), NASA, JSC-09423, April 1975\n- NASA History Series Publications\n- Project Apollo Drawings and Technical Diagrams at the NASA History Program Office\n- The *Apollo Lunar Surface Journal* Archived June 18, 2004, at the Wayback Machine edited by Eric M. Jones and Ken Glover\n- The *Apollo Flight Journal* by W. David Woods, et al.\n\n### Multimedia\n- NASA Apollo Program images and videos\n- Apollo Image Archive at Arizona State University\n- Audio recording and transcript of President John F. Kennedy, NASA administrator James Webb, et al., discussing the Apollo agenda (White House Cabinet Room, November 21, 1962)\n- The Project Apollo Archive by Kipp Teague is a large repository of Apollo images, videos, and audio recordings\n- The Project Apollo Archive on Flickr\n- Apollo Image Atlas—almost 25,000 lunar images, Lunar and Planetary Institute\n- Apollo (11, 13 and 17) in real time multimedia project\n- The short film *The Time of Apollo (1975)* is available for free viewing and download at the Internet Archive.\n- The short film *The Time of Apollo (1975)* is available for free viewing and download at the National Archives.\n- *The Journeys of Apollo* – NASA Documentary on YouTube\n- *Apollo Missions* (mashup timelapse) on Vimeo\n\nCategories: - Apollo program\n- 1960s in the United States\n- 1970s in the United States\n- Engineering projects\n- American lunar exploration program\n- Human spaceflight programs\n- NASA programs\n- Space program of the United States",
            "title": "Apollo program - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/Apollo_program"
          }
        ],
        "type": "fetch_url_results"
      },
      {
        "id": "msg_a5584d41-c74c-4b77-8366-7198e72bc2db",
        "content": [
          {
            "text": "The Apollo program flew eleven crewed missions (including Apollo 1, which never launched). Each mission progressively tested spacecraft, operations, and ultimately enabled six Moon landings and a dramatic in‑flight rescue. [page:1][page:2]\n\nBelow, “objectives” are what the mission was meant to test or accomplish; “key outcomes” are the main results.\n\n---\n\n## Apollo 1\n\n- **Objectives:** First crewed flight of the Block I Apollo command and service module (CSM) in Earth orbit on a Saturn IB, to validate basic spacecraft systems for later missions. [page:1]  \n- **Key outcomes:** Never launched; during a “plugs‑out” ground test on January 27, 1967, a cabin fire in a high‑pressure pure oxygen atmosphere killed Gus Grissom, Ed White, and Roger B. Chaffee and destroyed the command module. [page:1]  \n  - The accident led to major redesigns: mixed nitrogen–oxygen atmosphere on the pad, removal of flammable materials, a quick‑opening outward hatch, and cancellation of all crewed Block I flights. [page:1]\n\n---\n\n## Apollo 7\n\n- **Objectives:** First crewed Apollo mission (C‑type); shakedown of the redesigned Block II CSM in low Earth orbit using a Saturn IB, including propulsion, life support, navigation, rendezvous capability, and long‑duration operations. [page:1]  \n- **Key outcomes:** Eleven‑day Earth‑orbital flight (10 days 20 hours) by Wally Schirra, Donn Eisele, and Walter Cunningham that successfully demonstrated the Block II CSM and made the first live television broadcasts from a U.S. crewed spacecraft. [page:1]  \n  - Its success gave NASA confidence to commit the next mission, Apollo 8, to the Moon. [web:8][page:1]\n\n---\n\n## Apollo 8\n\n- **Objectives:** C′‑type mission; first crewed flight of the Saturn V and first crewed CSM flight to the Moon, to test translunar injection, navigation, communications, and operations in lunar orbit. [page:1]  \n- **Key outcomes:** Frank Borman, James Lovell, and William Anders became the first humans to leave Earth orbit, reach the Moon, and orbit it ten times over about 20 hours, then return safely. [web:3][page:1]  \n  - The crew photographed the lunar far side and the famous “Earthrise,” and the mission eliminated the need for a separate medium‑Earth‑orbit E‑type test. [web:3][page:1]\n\n---\n\n## Apollo 9\n\n- **Objectives:** D‑type mission; first crewed test of the complete Apollo spacecraft—CSM and Lunar Module (LM)—in low Earth orbit, to validate LM propulsion, rendezvous and docking, and the new lunar EVA suit and Portable Life Support System (PLSS). [web:4][page:1]  \n- **Key outcomes:** James McDivitt, David Scott, and Russell “Rusty” Schweickart flew the first crewed LM (*Spider*) and CSM (*Gumdrop*) together, performed rendezvous and docking maneuvers, and conducted an EVA in the full lunar surface suit using the PLSS. [web:4][web:10][page:1]  \n  - The mission proved the LM was capable of independent flight and that astronauts could work outside in the suit planned for the Moon. [web:4][page:1]\n\n---\n\n## Apollo 10\n\n- **Objectives:** F‑type “dress rehearsal” for the first landing: test all operations of a lunar mission except the actual touchdown—Saturn V performance, lunar orbit operations, LM descent and ascent to near‑surface altitude, and high‑speed return. [web:5][page:1]  \n- **Key outcomes:** Thomas Stafford, John Young, and Eugene Cernan flew CSM *Charlie Brown* and LM *Snoopy* to the Moon; the LM descended to about 50,000 feet (8.4 nautical miles / ~15.6 km) above the surface before returning to orbit and docking. [web:5][page:1]  \n  - Demonstrated that the hardware and procedures for a landing were ready, clearing the way for Apollo 11. [web:5][page:1]\n\n---\n\n## Apollo 11\n\n- **Objectives:** G‑type mission; first crewed lunar landing to fulfill Kennedy’s goal of “landing a man on the Moon and returning him safely to the Earth,” testing the full end‑to‑end profile including descent, landing, surface EVA, ascent, and sample return. [page:2]  \n- **Key outcomes:** On July 20, 1969, Neil Armstrong and Buzz Aldrin landed LM *Eagle* at Tranquility Base in the Sea of Tranquility, while Michael Collins orbited in CSM *Columbia*. [page:1][page:2]  \n  - Armstrong and Aldrin spent about 21.5 hours on the surface (2.5 hours outside), deployed scientific instruments, and returned 21.55 kg of samples; all three safely splashed down on July 24, 1969. [page:1][page:1]\n\n---\n\n## Apollo 12\n\n- **Objectives:** H‑type mission; demonstrate a precision landing and expanded surface science with multiple EVAs, including inspecting and retrieving hardware from the earlier Surveyor 3 lander. [page:1]  \n- **Key outcomes:** Charles “Pete” Conrad and Alan Bean landed LM *Intrepid* in Ocean of Storms near Surveyor 3, achieving a highly accurate touchdown, while Richard Gordon orbited in CSM *Yankee Clipper*. [page:1]  \n  - They performed two EVAs (7 h 45 m total), collected 34.30 kg of samples, and returned parts of Surveyor 3 for analysis; the mission also briefly transmitted color TV from the surface before the camera was accidentally pointed at the Sun and failed. [page:1]\n\n---\n\n## Apollo 13\n\n- **Objectives:** H‑type mission; planned third landing, targeting the Fra Mauro formation for geological study and further refinement of surface operations. [page:1]  \n- **Key outcomes:** An oxygen tank explosion in the service module en route to the Moon crippled CSM *Odyssey*, forcing cancellation of the landing and use of LM *Aquarius* as a “lifeboat” for power, propulsion, and life support. [page:1][page:2]  \n  - James Lovell, Jack Swigert, and Fred Haise looped around the Moon on a free‑return path and returned safely; the mission was later described as a “successful failure” because of the safe recovery and engineering lessons. [page:1]\n\n---\n\n## Apollo 14\n\n- **Objectives:** H‑type mission reused Fra Mauro as the landing target (the geology goal from Apollo 13), to study ejecta from the Imbrium impact and conduct improved surface science and long EVAs. [page:1]  \n- **Key outcomes:** Alan Shepard and Edgar Mitchell landed LM *Antares* at Fra Mauro while Stuart Roosa orbited in CSM *Kitty Hawk*. [page:1]  \n  - They spent 33.5 hours on the surface, performed two EVAs totaling about 9 h 21 m, returned 42.80 kg of samples, and were the first to broadcast substantial color TV from the lunar surface. [page:1]\n\n---\n\n## Apollo 15\n\n- **Objectives:** First J‑type “extended” mission: longer stay, first Lunar Roving Vehicle (LRV), more sophisticated science payloads in the LM and in the CSM’s Scientific Instrument Module, and intensive geological exploration at the Hadley–Apennine region. [page:1]  \n- **Key outcomes:** David Scott and James Irwin landed LM *Falcon* near Hadley Rille while Alfred Worden orbited in CSM *Endeavour*. [page:1]  \n  - With three EVAs totaling 18 h 33 m, extensive LRV traverses, and 76.70 kg of samples (including the famous “Genesis Rock”), Apollo 15 inaugurated the high‑science, long‑stay phase of Apollo. [page:1]\n\n---\n\n## Apollo 16\n\n- **Objectives:** Second J‑type mission, aimed at the Descartes Highlands to sample what were thought to be ancient highland volcanic rocks and to extend rover‑supported exploration and orbital science. [page:1]  \n- **Key outcomes:** John Young and Charles Duke landed LM *Orion* in the Descartes Highlands while Ken Mattingly remained in CSM *Casper*. [page:1]  \n  - They spent nearly three days on the surface with three EVAs totaling 20 h 14 m, drove the LRV on extensive traverses, and returned 94.30 kg of samples, while Mattingly performed a deep‑space EVA to retrieve film from the service module. [page:1]\n\n---\n\n## Apollo 17\n\n- **Objectives:** Final J‑type mission and last Apollo lunar landing; target Taurus–Littrow to sample both young volcanic deposits and older highland material, with a professional geologist on the crew for maximum scientific return. [page:1]  \n- **Key outcomes:** Eugene Cernan and geologist Harrison Schmitt landed LM *Challenger* in Taurus–Littrow while Ronald Evans piloted CSM *America*; this was the only Saturn V night launch. [page:1]  \n  - They spent just over three days on the surface, conducted three EVAs totaling 22 h 2 m with the rover, and returned 110.40 kg of samples; Apollo 17 remains the last crewed mission to the Moon in the Apollo program. [page:1][page:2]",
            "type": "output_text",
            "annotations": [],
            "logprobs": []
          }
        ],
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "status": "completed",
    "error": null,
    "usage": {
      "input_tokens": 33623,
      "output_tokens": 2189,
      "total_tokens": 35812,
      "cost": {
        "currency": "USD",
        "input_cost": 0.03755,
        "output_cost": 0.02189,
        "total_cost": 0.06289,
        "cache_creation_cost": null,
        "cache_read_cost": 0.00045,
        "tool_calls_cost": 0.003
      },
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 3584,
        "cached_tokens": 3584
      },
      "tool_calls_details": {
        "fetch_url": {
          "invocation": 1
        },
        "search_web": {
          "invocation": 1
        }
      },
      "output_tokens_details": {
        "reasoning_tokens": 0
      }
    },
    "background": false,
    "completed_at": 1779895991,
    "frequency_penalty": 0,
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Wednesday, May 27, 2026\n\n",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "user": null
  }
  ```
</Accordion>

```python Prefer theme={null}
client.responses.create(
    preset="low",
    input="Explain the structure of the 2015 Paris Agreement on climate change: nationally determined contributions, the 2°C / 1.5°C temperature goals, and the global stocktake mechanism.",
    tools=[
        {
            "type": "web_search",
            "filters": {
                "search_domain_filter": ["wikipedia.org"],
                "search_recency_filter": "month"
            }
        }
    ]
)
```

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_b5e0e0e9-b888-4b71-ba14-4410b5b0ef6a",
    "created_at": 1779391837,
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "results": [
          {
            "id": 1,
            "snippet": "In 2015, the Paris Agreement prescribed that the first GST would take place in 2023, and then every five years.",
            "title": "What is the Global Stocktake? - Grantham Research Institute ... - LSE",
            "url": "https://www.lse.ac.uk/granthaminstitute/explainers/what-is-the-global-stocktake/",
            "date": "2023-11-29",
            "last_updated": "2026-05-20",
            "source": "web"
          },
          {
            "id": 2,
            "snippet": "Nationally Determined Contributions (NDCs) detail each country's plans to reduce greenhouse gas emissions and contribute to global goals on climate change.\n...\nNDCs lay out how each country will contribute to the global temperature goals outlined under the Paris Agreement.\nThey detail countries' plans to slash GHG emissions and help limit global warming to \"well below\" 2 degrees C (3.6 degrees F), with efforts to limit it to 1.5 degrees C (2.7 degrees F).\nMany NDCs also include measures to build resilience to climate impacts, such as drought and sea-level rise, and provide information on the support needed to achieve their commitments.\nUnder the Paris Agreement, countries agreed to submit new NDCs every five years reflecting their \"highest possible ambition.\"\nEach round of commitments should be strengthened based on the latest climate science and countries' own capabilities and resources.\nMost countries submitted initial emissions targets prior to adopting the Paris Agreement in 2015.\nThe second round of NDCs, which set targets through 2030, happened in 2020-2021.\nNow, countries are in the process of submitting new NDCs with targets that will extend through 2035.\n...\nUnder the Paris Agreement, countries are obligated to have an NDC and to pursue domestic mitigation measures with the aim of fulfilling their commitments.\nWhile they are not legally bound to achieve their NDCs, countries have various responsibilities under the Agreement that are meant to lay the groundwork for meeting their targets.\nFor example, each country must submit a new or updated NDC every five years that is more ambitious than its last.",
            "title": "What Are NDCs and How Do They Address Climate Change?",
            "url": "https://www.wri.org/insights/nationally-determined-contributions-ndcs-explained",
            "date": "2025-08-28",
            "last_updated": "2026-05-15",
            "source": "web"
          },
          {
            "id": 3,
            "snippet": "The Paris Agreement works on a five- year cycle of increasingly ambitious climate action carried out by countries.\nEvery five years, each country is expected to submit an updated national climate action plan - known as **Nationally Determined Contribution**, or NDC.\nIn their NDCs, countries communicate actions they will take to reduce their greenhouse gas emissions in order to reach the goals of the Paris Agreement.\nCountries also communicate in the NDCs actions they will take to build resilience to adapt to the impacts of rising temperatures.\n...\nTo better frame the efforts towards the long-term goal, the Paris Agreement invites countries to formulate and submit **long-term strategies**.\nUnlike NDCs, they are not mandatory.",
            "title": "The Paris Agreement - the United Nations",
            "url": "https://www.un.org/en/climatechange/paris-agreement",
            "date": null,
            "last_updated": "2026-04-20",
            "source": "web"
          },
          {
            "id": 4,
            "snippet": "Every 5 years, all 195 signatories of the 2015 Paris Agreement must submit updated plans to reduce their greenhouse gas emissions to limit global warming.\nThese plans, known as Nationally Determined Contributions (NDCs), are key components of the agreement and represent countries’ highest ambitions for emissions reductions over the next decade.\n...\nThe Paris Agreement is a legally-binding international treaty under the UNFCCC.\nThe treaty states that signatories should work together to limit global temperature increase to “well under 2°C” above pre-industrial levels and pursue efforts to keep the increase below 1.5°C.\nNationally Determined Contributions outline how countries plan to achieve this goal and take other measures as part of the global climate effort.\nEach NDC must build upon a country’s previous submission and reflect the party’s “highest possible ambition,” according to the Paris Agreement.\nWhile parties are legally required to submit an NDC and pursue actions to reach the target, they are “not legally bound to reach the target,” Goldberg says.\n“It’s a gigantic loophole in a way… although such flexibility is obviously necessary for countries to agree to this, and it does create a structure of pressure.”\nAfter NDCs are submitted, the UNFCCC assesses the combined impact of countries’ NDCs on projected global emissions in a synthesis report.\nParties in the Paris agreement also submit a Biennial Transparency Report (BTR) every two years, which outlines each country’s progress made towards accomplishing their NDCs.",
            "title": "What are Nationally Determined Contributions (NDCs)?",
            "url": "https://www.woodwellclimate.org/what-are-ndc-nationally-determined-contributions/",
            "date": "2025-11-05",
            "last_updated": "2026-05-09",
            "source": "web"
          },
          {
            "id": 5,
            "snippet": "Finally, under the Paris Agreement in 2015, countries agreed to make plans to limit their emissions of greenhouse gasses.\nThis agreement clearly defines 2° Celsius as the upper limit for global warming, but also lists 1.5° as a more desirable goal because it reduces the risk for the worst outcomes of climate change in most of the world.",
            "title": "Why did the IPCC choose 2° C as the goal for limiting global warming?",
            "url": "https://climate.mit.edu/ask-mit/why-did-ipcc-choose-2deg-c-goal-limiting-global-warming",
            "date": null,
            "last_updated": "2026-05-11",
            "source": "web"
          },
          {
            "id": 6,
            "snippet": "- *Nationally Determined Contributions, or NDCs, are countries’ self-defined national climate pledges under the Paris Agreement, detailing what they will do to help meet the global goal to pursue 1.5°C, adapt to climate impacts and ensure sufficient finance to support these efforts.*\n- *NDCs represent short- to medium-term plans and are required to be updated every five years with increasingly higher ambition, based on each country’s capabilities and capacities.*",
            "title": "What are NDCs and how do they drive climate action?",
            "url": "https://climatepromise.undp.org/news-and-stories/NDCs-nationally-determined-contributions-climate-change-what-you-need-to-know",
            "date": "2023-05-31",
            "last_updated": "2026-04-17",
            "source": "web"
          },
          {
            "id": 7,
            "snippet": "Binding under international law and global in scope, it not only sets out ambitious global goals, such as limiting the rise in average global temperature to well below 2 °C compared with pre-industrial levels, but also introduces an innovative architecture that gives Parties considerable leeway in setting their own climate change targets.\nIn contrast to common practice under international environmental law, states' individual contributions are not negotiated at international level and achievement of set targets is not binding.\n...\nThe Paris Agreement requires its signatory states (known as Parties) to regularly formulate their own climate action plans, so-called nationally determined contributions (NDCs), and to implement measures that help them achieve their climate action goals.\nThere is, however, no obligation under international law for Parties to achieve their NDCs.\nParties are, however, required to regularly report on their progress in implementing their NDCs and the reports are subject to international peer review.\nIn addition to this Enhanced Transparency Framework, the Paris Agreement stipulates that Parties must regularly update their NDCs, that the updated NDCs must not fall short of the targets applicable prior to the update and that they should reflect the highest possible level of ambition.\nIn addition, a Global Stocktake is carried out once every five years to assess the collective progress made towards achieving the long-term goals.\nThe outcomes of the stocktake are to be taken into account when developing nationally determined contributions.",
            "title": "Global stocktake - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/Global_stocktake",
            "date": "2020-01-22",
            "last_updated": "2026-05-05",
            "source": "web"
          }
        ],
        "type": "search_results",
        "queries": [
          "2015 Paris Agreement nationally determined contributions structure",
          "Paris Agreement 2°C 1.5°C temperature goal Article 2",
          "Paris Agreement global stocktake mechanism Article 14"
        ]
      },
      {
        "id": "msg_d05e1753-3e3d-4abb-8cf1-04917d4be0d9",
        "content": [
          {
            "text": "The 2015 Paris Agreement sets a long‑term temperature goal (“well below” 2°C, with efforts toward 1.5°C), then builds a cyclical system where countries file and strengthen nationally determined contributions (NDCs), which are periodically reviewed through a global stocktake to ratchet up ambition over time.[web:3][web:7]  \n\n## Temperature goals (2°C / 1.5°C)\n\n- The Agreement’s core objective is to hold the increase in global average temperature to *well below* 2°C above pre‑industrial levels and to pursue efforts to limit the increase to 1.5°C.[web:3][web:4]  \n- The 1.5°C reference is framed as a more desirable aspiration because it substantially reduces the risks and impacts of climate change compared with 2°C warming.[web:5]  \n\n## Nationally determined contributions (NDCs)\n\n- NDCs are each country’s **self‑defined** national climate plan, setting out how it will reduce greenhouse gas emissions and often how it will adapt to climate impacts and what support it needs.[web:2][web:3][web:6]  \n- Under the Paris “ambition cycle,” every Party must have an NDC, submit a new or updated one at least every five years, and each successive NDC must represent the country’s “highest possible ambition” and not fall below the previous one.[web:2][web:4][web:7]  \n- Countries are legally required to prepare, communicate and pursue domestic measures to implement their NDCs, and to report on progress, but they are **not** legally bound to actually achieve the specific numerical targets in their NDCs.[web:4][web:7]  \n\n## Five‑year ambition cycle\n\n- The Agreement works on a recurring five‑year cycle: countries submit NDCs, implement policies, report transparently, and then update NDCs in light of new science, capabilities, and the outcomes of the global stocktake.[web:3][web:6][web:7]  \n- This iterative design replaces top‑down negotiated targets with a bottom‑up system where national pledges are progressively strengthened to collectively align with the long‑term temperature goals.[web:7]  \n\n## Global stocktake mechanism\n\n- The global stocktake (GST), established in Article 14, is a collective assessment held every five years to evaluate overall progress toward achieving the purpose and long‑term goals of the Paris Agreement, including the temperature limits.[web:1][web:7]  \n- The first stocktake was scheduled for 2023 and then recurs every five years; its outputs are meant to inform and shape the next round of NDCs and other climate actions, encouraging countries to increase ambition over time.[web:1][web:7]  \n- The GST assesses mitigation, adaptation, and means of implementation and support (finance, technology, capacity‑building), and is linked to the Enhanced Transparency Framework under which Parties regularly report and undergo technical review.[web:1][web:3][web:7]  \n\n## How the pieces fit together\n\n- The temperature goals define the overall direction (well below 2°C with efforts toward 1.5°C), while NDCs are the main vehicle through which each country specifies its contribution to that collective objective.[web:3][web:4][web:6]  \n- The global stocktake and transparency rules create periodic moments of political and technical scrutiny, intended to push Parties to submit more ambitious NDCs in each cycle so that, over time, global emissions pathways converge toward the agreed temperature limits.[web:1][web:2][web:7]",
            "type": "output_text",
            "annotations": [],
            "logprobs": []
          }
        ],
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "status": "completed",
    "error": null,
    "usage": {
      "input_tokens": 5737,
      "output_tokens": 830,
      "total_tokens": 6567,
      "cost": {
        "currency": "USD",
        "input_cost": 0.00269,
        "output_cost": 0.0083,
        "total_cost": 0.01394,
        "cache_creation_cost": null,
        "cache_read_cost": 0.00045,
        "tool_calls_cost": 0.0025
      },
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 3584,
        "cached_tokens": 3584
      },
      "tool_calls_details": {
        "search_web": {
          "invocation": 1
        }
      },
      "output_tokens_details": {
        "reasoning_tokens": 0
      }
    },
    "background": false,
    "completed_at": 1779391837,
    "frequency_penalty": 0,
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "user": null
  }
  ```
</Accordion>

See [Filters](/docs/agent-api/tools/web-search#filters) for the full list of available parameters.

<Tip>
  To run without tools, set `tools_disabled: true` on the request. Passing `tools: []` does **not** clear preset tools. An empty array is treated the same as omitting the field, and the preset's defaults still apply.
</Tip>

## Next Steps

<CardGroup>
  <Card title="Output Control" icon="sliders" href="/docs/agent-api/output-control">
    Shape responses with `response_format` and learn the full response payload structure.
  </Card>

  <Card title="Filters" icon="magnifying-glass" href="/docs/agent-api/tools/web-search#filters">
    Constrain search with domain, recency, and region parameters.
  </Card>

  <Card title="Web Search" icon="code" href="/docs/agent-api/tools/web-search">
    Configure the `web_search` tool for source-grounded context.
  </Card>

  <Card title="Presets" icon="layer-group" href="/docs/agent-api/presets">
    Choose a preset that matches your latency, depth, and tool requirements.
  </Card>
</CardGroup>


# Agent API
Source: https://docs.perplexity.ai/docs/agent-api/quickstart

The Agent API is a multi-provider, interoperable API specification for building LLM applications. Access models from multiple providers with integrated real-time web search, tool configuration, reasoning control, and token budgets—all through one unified interface.

<Card title="Try the Agent API Playground" href="https://console.perplexity.ai/group/agent-playground">
  Test Agent API requests and parameters interactively in the API console.
</Card>

<Card title="Pricing" icon="receipt" href="/docs/getting-started/pricing">
  Pay-as-you-go pricing for all APIs. No subscription required.
</Card>

## Why Use the Agent API?

<CardGroup>
  <Card title="Web-Grounded Answers" icon="globe">
    Get accurate, up-to-date answers grounded in real-time web search, with inline citations in a single call, and conversation context across turns.
  </Card>

  <Card title="Multi-Provider Access" icon="stack-3">
    Access OpenAI, Anthropic, Google, xAI, and more through one unified API, no need to manage multiple API keys.
  </Card>

  <Card title="Transparent Pricing" icon="receipt">
    See exact token counts and costs per request, no markup, just direct provider pricing.
  </Card>

  <Card title="Granular Control" icon="adjustments">
    Change models, reasoning, tokens, and tools with consistent syntax.
  </Card>
</CardGroup>

<Info>
  We recommend using our [official SDKs](/docs/sdk/overview) for a more convenient and type-safe way to interact with the Agent API.
</Info>

<Note>
  **Endpoint:** The Agent API is available at `POST https://api.perplexity.ai/v1/agent`. For OpenAI SDK compatibility, `POST /v1/responses` is also accepted as an alias. See the [OpenAI Compatibility Guide](/docs/agent-api/openai-compatibility) for details on using OpenAI SDKs with Perplexity.
</Note>

## Installation

Install the SDK for your preferred language:

<CodeGroup>
  ```bash Python theme={null}
  pip install perplexityai
  ```

  ```bash Typescript theme={null}
  npm install @perplexity-ai/perplexity_ai
  ```
</CodeGroup>

## Authentication

Set your API key as an environment variable. The SDK will automatically read it:

<Tabs>
  <Tab title="macOS/Linux">
    ```bash theme={null}
    export PERPLEXITY_API_KEY="your_api_key_here"
    ```
  </Tab>

  <Tab title="Windows">
    ```powershell theme={null}
    setx PERPLEXITY_API_KEY "your_api_key_here"
    ```
  </Tab>
</Tabs>

<Info>
  All SDK examples below automatically use the `PERPLEXITY_API_KEY` environment variable. You can also pass the key explicitly if needed.
</Info>

## Basic Usage

<Tip>
  **Convenience Property:** Both Python and Typescript SDKs provide an `output_text` property that aggregates all text content from response outputs. Instead of iterating through `response.output`, simply use `response.output_text` for cleaner code.
</Tip>

### Using a Third-Party Model

Use third-party models from OpenAI, Anthropic, Google, xAI, and other providers for specific capabilities:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Explain the difference between supervised and unsupervised learning in machine learning."
  )

  print(f"Response ID: {response.id}")
  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-sol",
      input: "Explain the difference between supervised and unsupervised learning in machine learning."
  });

  console.log(`Response ID: ${response.id}`);
  console.log(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 '{
      "model": "openai/gpt-5.6-sol",
      "input": "Explain the difference between supervised and unsupervised learning in machine learning."
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "background": false,
    "completed_at": 1771891464,
    "created_at": 1771891464,
    "error": null,
    "frequency_penalty": 0,
    "id": "resp_f854ed0a-f0e2-4ee8-b5ea-8582956910f2",
    "incomplete_details": null,
    "instructions": null,
    "max_output_tokens": null,
    "max_tool_calls": null,
    "metadata": {},
    "model": "openai/gpt-5.6-sol",
    "object": "response",
    "output": [
      {
        "content": [
          {
            "annotations": [],
            "logprobs": [],
            "text": "Supervised learning uses labeled data where each example has a known output, enabling the model to learn direct input-output relationships. Examples include classification and regression.",
            "type": "output_text"
          }
        ],
        "id": "msg_f47013d2-7fe7-44d6-a7aa-4e34c85ce2b6",
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "status": "completed",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "usage": {
      "cost": {
        "currency": "USD",
        "input_cost": 4e-05,
        "output_cost": 0.00311,
        "total_cost": 0.00315
      },
      "input_tokens": 20,
      "input_tokens_details": {
        "cached_tokens": 0
      },
      "output_tokens": 222,
      "output_tokens_details": {
        "reasoning_tokens": 0
      },
      "total_tokens": 242
    },
    "user": null
  }
  ```
</Accordion>

### Using a Preset

Presets provide optimized defaults for specific use cases.

Start with a preset for quick setup:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      preset="low",
      input="Explain what the MMLU benchmark measures for large language models, and how the Apache 2.0 license differs from a restricted research-only license for model weights.",
  )

  print(f"Model used: {response.model}")
  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({
      preset: "low",
      input: "Explain what the MMLU benchmark measures for large language models, and how the Apache 2.0 license differs from a restricted research-only license for model weights.",
  });

  console.log(`Model used: ${response.model}`);
  console.log(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": "low",
      "input": "Explain what the MMLU benchmark measures for large language models, and how the Apache 2.0 license differs from a restricted research-only license for model weights."
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "background": false,
    "completed_at": 1771891641,
    "created_at": 1771891641,
    "error": null,
    "frequency_penalty": 0,
    "id": "resp_aca2bace-3782-4d81-be45-a82c24cfff9d",
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI...\n</role>\n...",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "queries": [
          "2025 open source LLM benchmark performance",
          "2025 newly released open source LLMs license",
          "2025 open source LLM real world use cases"
        ],
        "results": [
          {
            "date": "2025-11-19",
            "id": 1,
            "last_updated": "2026-02-23T12:12:34",
            "snippet": "updated\n\n19 Nov 2025\n\n# Open LLM Leaderboard\n\nThis LLM leaderboard displays...",
            "source": "web",
            "title": "Open LLM Leaderboard 2025",
            "url": "https://www.vellum.ai/open-llm-leaderboard"
          },
          {
            "date": "2023-05-05",
            "id": 2,
            "last_updated": "2026-01-06T09:02:43.651546",
            "snippet": "",
            "source": "web",
            "title": "A list of open LLMs available for commercial use.",
            "url": "https://github.com/eugeneyan/open-llms"
          },
          {
            "date": "2025-05-05",
            "id": 3,
            "last_updated": "2026-02-22T19:27:06",
            "snippet": "# Best Open Source LLMs You Can Run Locally in 2025\n\nRunning large language models on your own hardware is...",
            "source": "web",
            "title": "Best Open Source LLMs You Can Run Locally in 2025 - DemoDazzle",
            "url": "https://demodazzle.com/blog/open-source-llms-2025"
          },
          {
            "date": "2025-12-15",
            "id": 4,
            "last_updated": "2026-02-23T21:56:51",
            "snippet": "updated\n\n15 Dec 2025\n\n# LLM Leaderboard\n\nThis LLM leaderboard displays the latest public benchmark performance for SOTA model versions released after April 2024...",
            "source": "web",
            "title": "LLM Leaderboard 2025 - Vellum",
            "url": "https://www.vellum.ai/llm-leaderboard"
          },
          {
            "date": "2025-11-22",
            "id": 5,
            "last_updated": "2026-02-11T02:35:36",
            "snippet": "Open\u2011source Large Language Models (LLMs) have moved from niche hobby projects to a full\u2011blown industry trend in 2025...",
            "source": "web",
            "title": "Open\u2011Source LLMs 2025: GPT\u2011OSS Models & How ... - Neura AI Blog",
            "url": "https://blog.meetneura.ai/open-source-llms-2025/"
          },
          {
            "date": "2025-07-23",
            "id": 6,
            "last_updated": "2026-02-23T23:43:21",
            "snippet": "",
            "source": "web",
            "title": "55 real-world LLM applications and use cases from top ...",
            "url": "https://www.evidentlyai.com/blog/llm-applications"
          },
          {
            "date": "2025-10-29",
            "id": 7,
            "last_updated": "2026-02-23T21:22:10",
            "snippet": "",
            "source": "web",
            "title": "Top 10 open source LLMs for 2025 - NetApp Instaclustr",
            "url": "https://www.instaclustr.com/education/open-source-ai/top-10-open-source-llms-for-2025/"
          },
          {
            "date": "2025-05-21",
            "id": 8,
            "last_updated": "2026-02-23T14:54:20",
            "snippet": "Here are the details of OpenLLaMA:\n\n**Parameters:** 3B, 7B and 13B\n\n**License:** Apache 2.0...",
            "source": "web",
            "title": "The List of 11 Most Popular Open Source LLMs [2025]",
            "url": "https://www.lakera.ai/blog/open-source-llms"
          },
          {
            "date": "2026-01-07",
            "id": 9,
            "last_updated": "2026-02-23T17:41:06",
            "snippet": "",
            "source": "web",
            "title": "The state of open source AI models in 2025 | Red Hat Developer",
            "url": "https://developers.redhat.com/articles/2026/01/07/state-open-source-ai-models-2025"
          },
          {
            "date": "2025-10-28",
            "id": 10,
            "last_updated": "2026-02-23T07:53:56",
            "snippet": "- **Open source dominates by volume:** 63% of models in our dataset (59 open source vs 35 proprietary)\n- **Performance...",
            "source": "web",
            "title": "Open Source vs Proprietary LLMs: Complete 2025 Benchmark ...",
            "url": "https://whatllm.org/blog/open-source-vs-proprietary-llms-2025"
          },
          {
            "date": "2025-06-02",
            "id": 11,
            "last_updated": "2026-01-18T13:27:38.757741",
            "snippet": "",
            "source": "web",
            "title": "Top 8 Open\u2011Source LLMs to Watch in 2025 - JetRuby Agency",
            "url": "https://jetruby.com/blog/top-8-open-source-llms-to-watch-in-2025/"
          },
          {
            "date": "2026-01-26",
            "id": 12,
            "last_updated": "2026-02-23T16:49:21",
            "snippet": "",
            "source": "web",
            "title": "Best Open Source LLMs in 2026",
            "url": "https://www.keywordsai.co/blog/best-open-source-llms"
          },
          {
            "date": "2025-12-10",
            "id": 13,
            "last_updated": "2026-02-23T18:38:26",
            "snippet": "",
            "source": "web",
            "title": "Full Benchmark Table For...",
            "url": "https://skywork.ai/blog/llm/top-10-open-llms-2025-november-ranking-analysis/"
          },
          {
            "date": "2024-09-19",
            "id": 14,
            "last_updated": "2025-12-27T09:28:04.559969",
            "snippet": "## Top Open-Source LLMs of 2025\n\n### 1. LLaMA 3.1\n\n**Developer:**Meta AI **Release Date:**July 23, 2024 **Parameter Size:**405B, 70B, 8B...",
            "source": "web",
            "title": "Top 10 Open-Source LLMs in 2025 - Kite Metric",
            "url": "https://kitemetric.com/blogs/top-10-open-source-llms-in-2025-a-comprehensive-guide"
          },
          {
            "date": "2025-02-26",
            "id": 15,
            "last_updated": "2025-09-10T16:36:09.704235",
            "snippet": "Use Cases:\n\n**Advanced Chatbots:**Responsive customer support bots. **Content Creation for Marketing:**Generating product descriptions and blog posts...",
            "source": "web",
            "title": "Top 10 Open-Source LLMs in 2025 and Their Use Cases",
            "url": "https://capalearning.com/2025/02/26/top-10-open-source-llms-in-2025-and-their-use-cases/"
          }
        ],
        "type": "search_results"
      },
      {
        "contents": [
          {
            "snippet": "Hi, Camille\u2019s here! On October 28, 2025, I fell into a small rabbit hole...",
            "title": "Full Benchmark Table For...",
            "url": "https://skywork.ai/blog/llm/top-10-open-llms-2025-november-ranking-analysis/"
          },
          {
            "snippet": "# Open source vs proprietary LLMs: complete 2025 benchmark analysis\n\n## TL;DR: The state of LLMs in late 2025\n\n**The landscape has shifted dramatically:**\n\n- **Open source dominates by volume:** 63% of models in our dataset (59 open source vs 35 proprietary)\n- **Performance...",
            "title": "Open Source vs Proprietary LLMs: Complete 2025 Benchmark ...",
            "url": "https://whatllm.org/blog/open-source-vs-proprietary-llms-2025"
          }
        ],
        "type": "fetch_url_results"
      },
      {
        "content": [
          {
            "annotations": [],
            "logprobs": [],
            "text": "In 2025, the strongest open\u2011source LLMs (Qwen 2.5, Llama 3.3/3.x, DeepSeek V3\u2011series, Mixtral...",
            "type": "output_text"
          }
        ],
        "id": "msg_1140f2e2-5bdb-4be8-a4c8-9d56bf61f35f",
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "status": "completed",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "usage": {
      "cost": {
        "cache_read_cost": 0.00059,
        "currency": "USD",
        "input_cost": 0.00919,
        "output_cost": 0.02743,
        "tool_calls_cost": 0.003,
        "total_cost": 0.04021
      },
      "input_tokens": 12088,
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 4736,
        "cached_tokens": 4736
      },
      "output_tokens": 2743,
      "output_tokens_details": {
        "reasoning_tokens": 0
      },
      "tool_calls_details": {
        "fetch_url": {
          "invocation": 1
        },
        "search_web": {
          "invocation": 1
        }
      },
      "total_tokens": 14831
    },
    "user": null
  }
  ```
</Accordion>

<Tip>
  Learn more about [presets](/docs/agent-api/presets) to explore pre-configured setups optimized for different use cases with specific models, token limits, and tool access.
</Tip>

### With Web Search

The Agent API provides access to a number of tools that can be used to extend the capabilities of the model.

Enable web search capabilities using the `web_search` tool:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Explain the original Transformer architecture from 'Attention Is All You Need' (Vaswani et al. 2017): encoder-decoder structure, multi-head self-attention, and positional encodings.",
      tools=[{"type": "web_search"}],
      instructions="You have access to a web_search tool. Use it for questions about current events, news, or recent developments. Use 1 query for simple questions. Keep queries brief: 2-5 words. NEVER ask permission to search - just search when appropriate",
  )

  if response.status == "completed":
      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-sol",
      input: "Explain the original Transformer architecture from 'Attention Is All You Need' (Vaswani et al. 2017): encoder-decoder structure, multi-head self-attention, and positional encodings.",
      tools: [{ type: "web_search" }],
      instructions: "You have access to a web_search tool. Use it for questions about current events, news, or recent developments.",
  });

  if (response.status === "completed") {
      console.log(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" \
    --data @- <<'JSON' | jq
  {
      "model": "openai/gpt-5.6-sol",
      "input": "Explain the original Transformer architecture from 'Attention Is All You Need' (Vaswani et al. 2017): encoder-decoder structure, multi-head self-attention, and positional encodings.",
      "tools": [{"type": "web_search"}],
      "instructions": "You have access to a web_search tool. Use it for questions about current events, news, or recent developments."
  }
  JSON
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "background": false,
    "completed_at": 1771891737,
    "created_at": 1771891737,
    "error": null,
    "frequency_penalty": 0,
    "id": "resp_367113ed-7a1b-4b2e-bad7-93e53a6cbeca",
    "incomplete_details": null,
    "instructions": "You have access to a web_search tool. Use it for questions about current events, news, or recent developments. Use 1 query for simple questions. Keep queries brief: 2-5 words. NEVER ask permission to search - just search when appropriate",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "model": "openai/gpt-5.6-sol",
    "object": "response",
    "output": [
      {
        "queries": [
          "latest AI developments 2026"
        ],
        "results": [
          {
            "date": "2026-01-01",
            "id": 1,
            "last_updated": "2026-02-23T20:10:25",
            "snippet": "Many believe efficiency will be the new frontier...",
            "source": "web",
            "title": "The trends that will shape AI and tech in 2026 - IBM",
            "url": "https://www.ibm.com/think/news/ai-tech-trends-predictions-2026"
          },
          {
            "date": "2026-01-08",
            "id": 2,
            "last_updated": "2026-02-23T20:19:20",
            "snippet": "## What\u2019s next in AI: 7 trends to watch in 2026\n\nAI is entering a new phase, one defined by real-world impact...",
            "source": "web",
            "title": "What's next in AI: 7 trends to watch in 2026 - Microsoft Source",
            "url": "https://news.microsoft.com/source/features/ai/whats-next-in-ai-7-trends-to-watch-in-2026/"
          },
          {
            "date": "2026-01-06",
            "id": 3,
            "last_updated": "2026-02-21T02:30:13",
            "snippet": "#### Topics\n\n#### AI in Action\n\n**Summary:**\n\nMIT SMR columnists Thomas H. Davenport and Randy Bean see five...",
            "source": "web",
            "title": "Five Trends in AI and Data Science for 2026",
            "url": "https://sloanreview.mit.edu/article/five-trends-in-ai-and-data-science-for-2026/"
          },
          {
            "date": "2026-01-06",
            "id": 4,
            "last_updated": "2026-02-24T00:01:21",
            "snippet": "## Jeff Su\n\n##### Jan 06, 2026 (0:13:13)\nMost #AI predictions are speculation. This video covers...",
            "source": "web",
            "title": "Top 6 AI Trends That Will Define 2026 (backed by data)",
            "url": "https://www.youtube.com/watch?v=B23W1gRT9eY"
          },
          {
            "date": "2026-01-15",
            "id": 5,
            "last_updated": "2026-02-23T17:37:52",
            "snippet": "",
            "source": "web",
            "title": "11 things AI experts are watching for in 2026 | University of California",
            "url": "https://www.universityofcalifornia.edu/news/11-things-ai-experts-are-watching-2026"
          },
          {
            "date": "2026-01-13",
            "id": 6,
            "last_updated": "2026-02-23T16:27:23",
            "snippet": "Artificial intelligence (AI) is no longer an emerging technology, it\u2019s a transformational force driving innovation across industries...",
            "source": "web",
            "title": "AI Trends in 2026: A New Era of AI Advancements and Breakthroughs",
            "url": "https://www.trigyn.com/insights/ai-trends-2026-new-era-ai-advancements-and-breakthroughs"
          },
          {
            "date": "2025-12-22",
            "id": 7,
            "last_updated": "2026-02-23T09:47:25",
            "snippet": "The most significant advances in artificial intelligence next year won't come from...",
            "source": "web",
            "title": "6 AI breakthroughs that will define 2026 - InfoWorld",
            "url": "https://www.infoworld.com/article/4108092/6-ai-breakthroughs-that-will-define-2026.html"
          },
          {
            "date": "2025-12-22",
            "id": 8,
            "last_updated": "2026-02-23T20:21:57",
            "snippet": "What will define AI in 2026? \ud83d\ude80 Martin Keen & Aaron Baughman explore groundbreaking trends like Agentic AI, cloud computing, automation, and quantum computing, plus innovations like Physical AI...",
            "source": "web",
            "title": "AI Trends 2026: Quantum, Agentic AI & Smarter Automation",
            "url": "https://www.youtube.com/watch?v=zt0JA5rxdfM"
          },
          {
            "date": "2025-12-15",
            "id": 9,
            "last_updated": "2026-02-23T13:13:58",
            "snippet": "",
            "source": "web",
            "title": "Stanford AI Experts Predict What Will Happen in 2026",
            "url": "https://hai.stanford.edu/news/stanford-ai-experts-predict-what-will-happen-in-2026"
          },
          {
            "date": "2025-05-10",
            "id": 10,
            "last_updated": "2026-02-20T16:07:11",
            "snippet": "{ts:574} breakthroughs in AlphaGo and Alpha Fold, which are absolutely incredible. Now, DeepMind has basically said...",
            "title": "2026 AI : 10 Things Coming In 2026 (A.I In 2026 Major Predictions)",
            "url": "https://www.youtube.com/watch?v=RfA2Ug4FuaY"
          }
        ],
        "type": "search_results"
      },
      {
        "content": [
          {
            "annotations": [],
            "logprobs": [],
            "text": "Here are major *recent* directions in AI (late 2025\u2013early 2026) that researchers...",
            "type": "output_text"
          }
        ],
        "id": "msg_d0f12cc6-c6a2-426f-b55e-fff247e40c8c",
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "status": "completed",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "usage": {
      "cost": {
        "currency": "USD",
        "input_cost": 0.00826,
        "output_cost": 0.0063,
        "tool_calls_cost": 0.0025,
        "total_cost": 0.01706
      },
      "input_tokens": 4718,
      "input_tokens_details": {
        "cached_tokens": 0
      },
      "output_tokens": 450,
      "output_tokens_details": {
        "reasoning_tokens": 0
      },
      "tool_calls_details": {
        "search_web": {
          "invocation": 1
        }
      },
      "total_tokens": 5168
    },
    "user": null
  }
  ```
</Accordion>

### With Finance Search

Retrieve structured financial and market data using the `finance_search` tool. See the [Finance Search guide](/docs/agent-api/tools/finance-search) for capabilities and recommended configurations.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Explain how to read a 10-K filing: what each major section contains (Item 1 Business, Item 1A Risk Factors, Item 7 MD&A, Item 8 Financial Statements) and how investors use them.",
      tools=[{"type": "finance_search"}],
  )

  for item in response.output:
      if item.type == "message":
          print(item.content[0].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-sol",
      input: "Explain how to read a 10-K filing: what each major section contains (Item 1 Business, Item 1A Risk Factors, Item 7 MD&A, Item 8 Financial Statements) and how investors use them.",
      tools: [{ type: "finance_search" }],
  });

  console.log(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 '{
      "model": "openai/gpt-5.6-sol",
      "input": "Explain NVIDIA\u0027s GPU compute model: streaming multiprocessors, CUDA cores, Tensor Cores, and HBM memory bandwidth.",
      "tools": [{"type": "finance_search"}]
    }' | jq
  ```
</CodeGroup>

<AccordionGroup>
  <Accordion title="Response — Explain how to read a 10-K filing: what each major section contains (Item 1 Business, I...">
    ```json theme={null}
    {
      "id": "resp_4c946a0e-9a51-44d1-89a6-c972c57228a8",
      "created_at": 1779391718,
      "model": "openai/gpt-5.1",
      "object": "response",
      "output": [
        {
          "results": [
            {
              "id": 1,
              "snippet": "(d) In response to Item l, Business, such registrant only need furnish a brief\ndescription of the business done by the registrant and its subsidiaries during the\nmost recent fiscal year which will, in the opinion of management, indicate the\ngeneral nature and scope of the business of the registrant and its subsidiaries, and\nin response to Item 2, Properties, such registrant only need furnish a brief\ndescription of the material properties of the registrant and its subsidiaries to the\nextent, in the opinion of the management, necessary to an understanding of the\nbusiness done by the registrant and its subsidiaries.\n...\nfollowing otherwise required Items:\n(a) Item 1, Business;\n...\nPART I \n[See General Instruction G(2)] \nItem 1.\nBusiness.\nFurnish the information required by Item 101 of Regulation S-K (§ 229.101 of this chapter) \nexcept that the discussion of the development of the registrant’s business need only include\ndevelopments since the beginning of the fiscal year for which this report is filed.\nItem 1A.\nRisk Factors.\nSet forth, under the caption “Risk Factors,” where appropriate, the risk factors described in \nItem 105 of Regulation S-K (§ 229.105 of this chapter) applicable to the registrant.\nProvide any\ndiscussion of risk factors in plain English in accordance with Rule 421(d) of the Securities Act of \n1933 (§ 230.421(d) of this chapter).\nSmaller reporting companies are not required to provide the \ninformation required by this item.\nItem 1B.",
              "title": "[PDF] Form 10-K - SEC.gov",
              "url": "https://www.sec.gov/files/form10-k.pdf",
              "date": null,
              "last_updated": "2025-06-03",
              "source": "web"
            },
            {
              "id": 2,
              "snippet": "Regulation S-K, Item 105, requires registrants to provide “a discussion of the\nmaterial factors that make an investment in the registrant or offering\nspeculative or risky.”\nCertain indicators of risk may be present in the\nfootnotes to the financial statements, in MD&A, or elsewhere in investor\npresentations or other periodic filings.",
              "title": "3.3 Disclosures About Risk | DART – Deloitte Accounting Research ...",
              "url": "https://dart.deloitte.com/USDART/home/publications/deloitte/additional-deloitte-guidance/roadmap-sec-comment-letter-considerations/chapter-3-sec-disclosure-topics/3-3-disclosures-about-risk",
              "date": null,
              "last_updated": "2026-03-31",
              "source": "web"
            },
            {
              "id": 3,
              "snippet": "Additional sections in this Form 10-K which should be helpful to the reading of our discussion and analysis include the following: (i) a description of our services provided, by segment found in Items\n1 and 2 “Business and Properties”—”Services Provided” (ii) a description of our business strategy found in Items 1 and 2 “Business and Properties”—”Our Strategy”; and (iii) a description of\nrisk factors affecting us and our business, found in Item 1A “Risk Factors.”",
              "title": "Form 10-K Item 7. Management's Discussion and Analysis - SEC.gov",
              "url": "https://www.sec.gov/Archives/edgar/data/1449732/000119312512289206/d374099dex993.htm",
              "date": "2012-03-29",
              "last_updated": "2025-09-23",
              "source": "web"
            },
            {
              "id": 4,
              "snippet": "In summary, Forms 10-K, 10-Q, 20-F and 40-F share detailed information and insights into the company’s overall financial performance and business operational details, while Forms 8-K and 6-K are filed to provide timely and relevant updates on significant material changes.",
              "title": "How to navigate Forms 10-K, 10-Q, 20-F, 40-F, 8-K and 6-K",
              "url": "https://www.toppanmerrill.com/blog/how-to-navigate-forms-10-k-10-q-20-f-40-f-8-k-and-6-k/",
              "date": "2025-03-19",
              "last_updated": "2026-05-16",
              "source": "web"
            },
            {
              "id": 5,
              "snippet": "#### Item 1 – Business\nThis describes the business of the company: who and what the company does, what subsidiaries it owns, and what markets it operates in.\nIt may also include recent events, competition, regulations, and labor issues.\n(Some industries are heavily regulated, have complex labor requirements, which have significant effects on the business.)\nOther topics in this section may include special operating costs, seasonal factors, or insurance matters.",
              "title": "Form 10-K - Wikipedia",
              "url": "https://en.wikipedia.org/wiki/Form_10-K",
              "date": "2005-02-23",
              "last_updated": "2026-03-31",
              "source": "web"
            },
            {
              "id": 6,
              "snippet": "A few companies located the summary in “Item 1.\nBusiness.”",
              "title": "SEC Risk Factor Disclosure Rules",
              "url": "https://corpgov.law.harvard.edu/2021/12/22/sec-risk-factor-disclosure-rules/",
              "date": "2021-12-22",
              "last_updated": "2026-04-13",
              "source": "web"
            },
            {
              "id": 7,
              "snippet": "Regulation S-K, Item 303, specifies the information that a registrant is\nrequired to provide when discussing its financial condition and results of\noperations in MD&A.\n...\n- Requiring the disclosure of (1) any known trends or uncertainties that have had or are reasonably likely to have a material impact on revenues or income and (2) any known events that are “reasonably likely to cause a material change in the relationship between costs and revenues (such as known or reasonably likely future increases in costs . . . )” (emphasis added).\n...\nUnder Regulation S-K, Item 303, registrants are required to disclose in MD&A\nmaterial known trends or uncertainties that may affect future performance\n(whether favorable or unfavorable).\n...\nTo provide comprehensive and meaningful disclosures, management should consider disclosing the following items in the critical accounting policies section of MD&A:- The method(s) used to determine critical accounting estimates.\n- The accuracy of past estimates or assumptions.\n- The extent to which the estimates or assumptions have changed.\n- The drivers that affect variability.\n- Which estimates or assumptions are reasonably likely to change in the future.\n...\nmatters in MD&A if those matters meet the criteria of Regulation\nS-K, Item 303(b)(2)(ii), which requires disclosure of “any known trends\nor uncertainties that have had or that are reasonably likely to have” a\nmaterial impact on revenues or income.",
              "title": "3.1 Management's Discussion and Analysis | DART",
              "url": "https://dart.deloitte.com/USDART/home/publications/deloitte/additional-deloitte-guidance/roadmap-sec-comment-letter-considerations/chapter-3-sec-disclosure-topics/3-1-management-s-discussion-analysis",
              "date": null,
              "last_updated": "2026-04-19",
              "source": "web"
            },
            {
              "id": 8,
              "snippet": "- **Item 1: Business**\n...\n## Item 1 - BusinessneCompanies typically define their business in this opening section of the 10-K report.\nThey describe their various product lines and business segments.\nThey list contracts, raw materials used, and supplier or distribution channels.\nThey talk about the competition and competitive factors in the market.\nIf research and development or intellectual property issues are important to company operations, they are included.\nGovernment regulations are covered.\nFinally, several pages are devoted to outlining risk factors to consider in evaluating the company's business.",
              "title": "The 10-K - SEC Filings - Research Guides at Baruch College",
              "url": "https://guides.newman.baruch.cuny.edu/c.php?g=188202&p=1244183",
              "date": "2009-11-02",
              "last_updated": "2026-05-09",
              "source": "web"
            },
            {
              "id": 9,
              "snippet": "- **Item 1A: Risk Factors:** Absolutely critical reading.\nThis **section** lists the most significant risks and uncertainties that could materially affect the company’s business, **financial condition**, or operating results.\nEffective **10k risk factors analysis** is paramount for **investors**.\nLook for specific, quantifiable risks, not just boilerplate warnings.",
              "title": "How to Read a 10-K Report with AI | Complete SEC Analysis Guide",
              "url": "https://www.v7labs.com/blog/how-to-read-a-10k-report-ai-sec-filings-guide",
              "date": "2025-06-11",
              "last_updated": "2026-05-16",
              "source": "web"
            },
            {
              "id": 10,
              "snippet": "**Item 7: Management’s Discussion and Analysis of Financial Condition and Results of Operations (MD&A)**– This section is perhaps the most narrative part of Form 10-K, where the company’s executives discuss the financial and operational factors that affected the business’s performance over the reporting period.\n...\nItem 7, Management’s Discussion and Analysis (MD&A), is an essential part of Form 10-K that offers investors a detailed narrative crafted by the company’s management.\nIt provides context and analysis beyond the figures presented in the financial statements.\nThis section aims to offer a view of the company through the lens of its management, explaining the dynamics of the business, the financial outcomes, and the strategies and decisions that influenced those results over the fiscal year.\n...\n**Operational Review**: This component of MD&A provides an analysis of the company’s business operations over the fiscal year.\nIt covers critical areas such as sales trends, customer acquisition and retention, changes in the competitive landscape, and operational milestones.",
              "title": "What are Items 7, 7A, and 8 in Part II of Form 10-K? - Superfast CPA",
              "url": "https://www.superfastcpa.com/what-are-items-7-7a-and-8-in-part-ii-of-form-10-k/",
              "date": "2021-03-13",
              "last_updated": "2026-01-05",
              "source": "web"
            },
            {
              "id": 11,
              "snippet": "(a) If the registrant experiences a cybersecurity incident that is determined by the registrant \n...\nIf the registrant or any of its subsidiaries consolidated has completed the acquisition or \ndisposition of a significant amount of assets, otherwise than in the ordinary course of business, or \nthe acquisition or disposition of a significant amount of assets that constitute a real estate \noperation as defined in § 210.3-14(a)(2) disclose the following information:\n(a) the date of completion of the transaction; \n(b) a brief description of the assets involved; \n(c) the identity of the person(s) from whom the assets were acquired or to whom they were \nsold and the nature of any material relationship, other than in respect of the transaction, between \nsuch person(s) and the registrant or any of its affiliates, or any director or officer of the\n...\n(1) \nthe date on which the registrant becomes obligated on the direct financial obligation \nand a brief description of the transaction or agreement creating the obligation; \n(2)\nthe amount of the obligation, including the terms of its payment and, if applicable, a \nbrief description of the material terms under which it may be accelerated or increased and the \nnature of any recourse provisions that would enable the registrant to recover from third parties; \nand; \n...\na brief description of the other terms and conditions of the transaction or agreement\nthat are material to the registrant.",
              "title": "[PDF] Form 8-K - SEC.gov",
              "url": "https://www.sec.gov/files/form8-k.pdf",
              "date": null,
              "last_updated": "2025-04-11",
              "source": "web"
            },
            {
              "id": 12,
              "snippet": "**Item 1 **“Business” requires a description of the company’s business, including its main products and services, what subsidiaries it owns, and what markets it operates in.\nThis section may also include information about recent events, competition the company faces, regulations that apply to it, labor issues, special operating costs, or seasonal factors.\nThis is a good place to start to understand how the company operates.",
              "title": "How to Read a 10-K/10-Q | Investor.gov",
              "url": "https://www.investor.gov/introduction-investing/general-resources/news-alerts/alerts-bulletins/investor-bulletins/how-read",
              "date": "2021-01-25",
              "last_updated": "2026-05-17",
              "source": "web"
            },
            {
              "id": 13,
              "snippet": "**Item 7: Management's Discussion and Analysis (MD&A)** is the required narrative section of the 10-K where management explains its financial results and financial condition.\nIt covers results of operations (why revenue and expenses changed), liquidity and capital resources (how the company funds itself), and critical accounting policies and estimates (the judgements that shaped the numbers).\nThe MD&A is not audited by the company's auditor; it is management's explanation of the statements.\nYet it is heavily scrutinised by the SEC, which requires it to be accurate, balanced, and not misleading — and has enforcement power to challenge inadequate disclosures.\n...\nThe SEC's MD&A requirements are detailed in Regulation S-K, Item 303.\nThe agency requires that MD&A address:\n1. **Results of operations.** A discussion of revenue, cost of goods sold, operating expenses, and operating income.\nThis must include year-over-year comparisons and explanation of significant changes (usually anything more than 5% variance).\n2. **Liquidity and capital resources.** Cash flow from operations, investing, and financing.\nManagement must discuss how it funds the business, what liquidity constraints exist, and what capital expenditures are planned.\n3. **Critical accounting policies and estimates.** The accounting methods and assumptions that have the most impact on financial results.\nExamples include revenue recognition, inventory valuation, allowances for doubtful accounts, and pension assumptions.\n4. **Off-balance-sheet arrangements and known contractual obligations.** Leases, purchase commitments, debt covenants, and other obligations that shape future cash requirements.\n5. **Tabular disclosure of contractual obligations.** A table showing debt maturity, operating lease obligations, purchase commitments, and other fixed obligations by period (current year, years 2–3, years 4–5, beyond 5 years).\n6. **Forward-looking statements and risk disclosures.** While Item 1A (Risk Factors) covers risks in depth, MD&A must touch on risks relevant to the company's financial condition and results.\n...\nItem 7 (MD&A) is the narrative bridge between the audited financial statements and the real business.",
              "title": "Item 7: Management's Discussion and Analysis (MD&A)",
              "url": "https://pomegra.io/learn/library/track-b-stock-market-core/financial-statements/chapter-08-reading-a-10-k/item-7-md-and-a",
              "date": null,
              "last_updated": "2026-05-14",
              "source": "web"
            }
          ],
          "type": "search_results",
          "queries": [
            "SEC Form 10-K item 1 business description",
            "SEC 10-K Item 1A risk factors explanation",
            "SEC 10-K Item 7 MD&A overview",
            "SEC 10-K Item 8 financial statements contents"
          ]
        },
        {
          "id": "msg_e81fbad4-f4ac-4092-b332-d04db8f414b2",
          "content": [
            {
              "text": "Investors read a Form 10‑K by focusing on a few core items that move from “what this business is” to “what could go wrong” to “how management explains the numbers” to the audited financials themselves.[web:12][web:5] Together, Items 1, 1A, 7, and 8 form the spine of the filing and should be read as a connected story, not as isolated sections.[web:1][web:13]\n\n## Item 1: Business\n\nItem 1 “Business” describes what the company actually does, including its main products and services, key subsidiaries, and the markets where it operates.[web:12][web:5] This section often discusses competition, applicable regulations, labor issues, important contracts, seasonal patterns, and sometimes special operating costs or insurance matters that affect operations.[web:12][web:8]\n\nInvestors use Item 1 to understand the company’s **economic** engine and competitive position, which is essential context for interpreting the rest of the 10‑K.[web:12][web:8] Common uses include:\n- Checking how the company makes money (revenue streams, segments, and geographies).[web:12][web:8]\n- Evaluating competitive landscape and regulatory exposure that may affect margins or growth.[web:8][web:5]\n- Seeing whether the described business model aligns with later financial performance and management’s narrative in MD&A.[web:3][web:13]\n\n## Item 1A: Risk Factors\n\nItem 1A “Risk Factors” must present the material factors that make an investment in the company speculative or risky, under Regulation S‑K Item 105.[web:1][web:2] It should be written in plain English and cover significant uncertainties that could materially affect the business, financial condition, or operating results.[web:1][web:9]\n\nInvestors use this section to assess downside scenarios and weed out boilerplate from company‑specific risks.[web:2][web:9] Typical approaches include:\n- Identifying the few most material, tailored risks (e.g., reliance on one product, tight liquidity, regulatory investigations) versus generic language.[web:2][web:9]\n- Mapping risks back to Item 1 and Item 7 to see whether management’s strategy and financial explanations realistically reflect those risks.[web:2][web:13]\n- Using the risk list as a checklist for stress‑testing valuation assumptions (growth, margins, leverage, and capital needs).[web:2][web:9]\n\n## Item 7: MD&A\n\nItem 7 “Management’s Discussion and Analysis of Financial Condition and Results of Operations” (MD&A) is the narrative where management explains the financial results and financial condition, as required by Regulation S‑K Item 303.[web:7][web:13] It must discuss results of operations, liquidity and capital resources, and critical accounting policies and estimates, including known trends or uncertainties reasonably likely to materially impact performance.[web:7][web:13]\n\nInvestors use MD&A as the **bridge** between the business description and the audited numbers.[web:10][web:13] Common uses include:\n- Understanding the drivers behind year‑over‑year changes in revenue, margins, and expenses, instead of just seeing the changes in the statements.[web:10][web:13]\n- Evaluating liquidity, funding sources, capital expenditures, and off‑balance‑sheet arrangements to judge solvency and future cash needs.[web:7][web:13]\n- Studying critical accounting estimates to spot areas where management judgment heavily affects reported earnings (e.g., revenue recognition, reserves, impairment).[web:7][web:13]\n\n## Item 8: Financial Statements\n\nItem 8 contains the audited financial statements and related notes, typically including the balance sheet, income statement, cash flow statement, statement of shareholders’ equity, and accompanying footnotes.[web:1][web:10] This section also includes the independent auditor’s report, which speaks to whether the financials are fairly presented in conformity with GAAP, and sometimes flags material weaknesses in internal control.[web:1][web:10]\n\nInvestors use Item 8 to test the narrative against hard numbers and to build models.[web:10][web:13] Key uses include:\n- Verifying that trends highlighted in MD&A actually show up in revenue, margins, cash flows, and leverage metrics.[web:10][web:13]\n- Mining footnotes for segment data, debt terms, contingencies, leases, and other detailed disclosures that may not be prominent elsewhere.[web:10][web:1]\n- Building or updating valuation models (DCF, comparables) using audited figures rather than management’s non‑GAAP metrics or selective highlights.[web:10][web:13]\n\n## How to read them together\n\nA practical way to read a 10‑K is to start with Item 1 (what the company is), move to Item 1A (what can go wrong), then Item 7 (how management explains recent performance and future trends), and finally Item 8 (whether the audited numbers and notes support that story).[web:12][web:13] Experienced investors constantly cross‑check among these sections, looking for inconsistencies between the business description, the risks, management’s discussion, and the underlying financial statements.[web:3][web:7]",
              "type": "output_text",
              "annotations": [],
              "logprobs": []
            }
          ],
          "role": "assistant",
          "status": "completed",
          "type": "message"
        }
      ],
      "status": "completed",
      "error": null,
      "usage": {
        "input_tokens": 7267,
        "output_tokens": 1188,
        "total_tokens": 8455,
        "cost": {
          "currency": "USD",
          "input_cost": 0.0046,
          "output_cost": 0.01188,
          "total_cost": 0.01943,
          "cache_creation_cost": null,
          "cache_read_cost": 0.00045,
          "tool_calls_cost": 0.0025
        },
        "input_tokens_details": {
          "cache_creation_input_tokens": 0,
          "cache_read_input_tokens": 3584,
          "cached_tokens": 3584
        },
        "tool_calls_details": {
          "search_web": {
            "invocation": 1
          }
        },
        "output_tokens_details": {
          "reasoning_tokens": 0
        }
      },
      "background": false,
      "completed_at": 1779391718,
      "frequency_penalty": 0,
      "incomplete_details": null,
      "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
      "max_output_tokens": 8192,
      "max_tool_calls": null,
      "metadata": {},
      "parallel_tool_calls": true,
      "presence_penalty": 0,
      "previous_response_id": null,
      "prompt_cache_key": null,
      "reasoning": null,
      "safety_identifier": null,
      "service_tier": "default",
      "store": true,
      "temperature": 1,
      "text": {
        "format": {
          "type": "text"
        }
      },
      "tool_choice": "auto",
      "tools": [
        {
          "type": "web_search"
        },
        {
          "type": "fetch_url"
        }
      ],
      "top_logprobs": 0,
      "top_p": 1,
      "truncation": "disabled",
      "user": null
    }
    ```
  </Accordion>

  <Accordion title="Response — Explain NVIDIA's GPU compute model: streaming multiprocessors, CUDA cores, Tensor Cores...">
    ```json theme={null}
    {
      "id": "resp_ef76b85e-1a63-4c0f-97ce-9e58dd1d050a",
      "created_at": 1779391739,
      "model": "openai/gpt-5.1",
      "object": "response",
      "output": [
        {
          "results": [
            {
              "id": 1,
              "snippet": "When we program GPUs , we produce sequences of instructions for its Streaming Multiprocessors to carry out.\nStreaming Multiprocessors (SMs) of NVIDIA GPUs are roughly analogous to the\ncores of CPUs.\nThat is, SMs both execute computations and store state available\nfor computation in registers, with associated caches.\nCompared to CPU cores, GPU\nSMs are simple, weak processors.\nExecution in SMs is pipelined within an\ninstruction (as in almost all CPUs since the 1990s) but there is no speculative\nexecution or instruction pointer prediction (unlike all contemporary\nhigh-performance CPUs).\n...\nAn H100 SXM GPU draws at most 700 W and has 132 SMs, each of which has four\nWarp Schedulers that can each issue instructions to 32 threads (aka a warp ) in parallel per clock cycle, for a total of 128 × 132 > 16,000 parallel threads running at about 5 cW apiece.\n...\nGPU SMs also support a large number of *concurrent* threads -- threads of execution whose instructions are interleaved.\nA single SM on an H100 can concurrently execute up to 2048 threads split across\n64 thread groups of 32 threads each.\nWith 132 SMs, that's a total of over\n250,000 concurrent threads.\nCPUs can also run many threads concurrently.\nBut switches between\nwarps happen at the speed of a single clock cycle (over 1000x faster than context switches on a CPU), again powered by the SM's Warp Schedulers . The volume of available warps and the speed of warp switches help hide latency caused by memory reads, thread synchronization, or other expensive instructions, ensuring that the arithmetic bandwidth provided by the CUDA Cores and Tensor Cores is well utilized.",
              "title": "What is a Streaming Multiprocessor? | GPU Glossary - Modal",
              "url": "https://modal.com/gpu-glossary/device-hardware/streaming-multiprocessor",
              "date": null,
              "last_updated": "2026-05-15",
              "source": "web"
            },
            {
              "id": 2,
              "snippet": "NVIDIA doesn’t call these tiles “cores” at all — it calls them Graphics Processing Clusters, or “GPCs”.\n...\nIn this area of the chip, we expect to find 16 load/store units, 4 special function units, 128 CUDA cores, and 4 Tensor cores.\n...\nStarting here on the GPU side, we know that each one of these streaming multiprocessors has 128 CUDA cores and 4 Tensor cores:\n...\nThis gives us a grand total of 8 Zen 4 cores on the CPU, 18,432 CUDA cores and 576 Tenser cores on the GPU:\n...\nSpecifically, we know that an Ada Streaming Multiprocessor has 128 CUDA cores and 4 Tensor cores.",
              "title": "Zen, CUDA, and Tensor Cores, Part I: The Silicon",
              "url": "https://www.computerenhance.com/p/zen-cuda-and-tensor-cores-part-i",
              "date": "2024-09-03",
              "last_updated": "2026-05-19",
              "source": "web"
            },
            {
              "id": 3,
              "snippet": "The terminology section defines a Streaming Multiprocessor (SM) as something that: “executes compute instructions on the GPU.”\n...\nSMs are the GPU’s core units running compute instructions.\nGPU engines include SMs plus other parts like copy or video engines handling various tasks.",
              "title": "Difference between Streaming Multiprocessor and Compute Engine?",
              "url": "https://forums.developer.nvidia.com/t/difference-between-streaming-multiprocessor-and-compute-engine/300154",
              "date": "2024-07-17",
              "last_updated": "2026-04-28",
              "source": "web"
            },
            {
              "id": 4,
              "snippet": "The INT32 units do integer calculations, the FP32 and FP64 units floating-point calculations.\nLD/ST are load-store units, the SFU calculates special functions (e.g. sin/cos).\n...\nAs @rs277 already explained, when people speak of a GPU with *n* “CUDA cores” they mean a GPU with *n* FP32 cores, each of which can perform one single-precision fused multiply-add operation (FMA) per cycle.\nThe number of “CUDA cores” does not indicate anything in particular about the number of 32-bit integer ALUs, or FP64 cores, or multi-function units, or “Tensor cores” (which I would also consider a marketing term).",
              "title": "Understanding of Tensor Core, Cuda Core and other cores in ...",
              "url": "https://forums.developer.nvidia.com/t/understanding-of-tensor-core-cuda-core-and-other-cores-in-ampere-architecture/235900",
              "date": "2022-12-01",
              "last_updated": "2026-05-10",
              "source": "web"
            },
            {
              "id": 5,
              "snippet": "A Streaming Multiprocessor (SM) is a fundamental component of NVIDIA GPUs, consisting of multiple Stream Processors (CUDA Core) responsible for executing instructions in parallel.\nThey are general purpose processors with a low clock rate target and a small cache.\n...\nConsists of:\n- SUPER LARGE Register File - This is how they can context switch quickly with no overhead, by keeping data on registers, see Warp Scheduling\n- Caches and shared memory\n- Warp Scheduler\n- Execution units (SFUs, CUDA Cores and Tensor Cores)\n...\n> SMs execute several thread blocks in parallel.\nAs soon as one of its thread block has completed execution, it takes up the serially next thread block.\nFrom Stephen Jones, I learned that each SM can managed 64 warps, so a total of 2048 threads.\nHowever, it really processes 4 warps at a time (see Warp Scheduling).\n...\n> An SM may contain up to 8 thread blocks in total.\n...\n> In general, SMs support instruction-level parallelism but not branch prediction.\nEach architecture in GPU consists of several SM.",
              "title": "Streaming Multiprocessor (SM) - Steven Gong",
              "url": "https://stevengong.co/notes/Streaming-Multiprocessor",
              "date": "2026-02-07",
              "last_updated": "2026-05-20",
              "source": "web"
            },
            {
              "id": 6,
              "snippet": "By tightly integrating these Tensor Cores with expanded special function units within NVIDIA Rubin’s streaming multiprocessors, the platform significantly accelerates attention mechanisms and sparse compute paths,  boosting both arithmetic density and energy efficiency without compromising model accuracy.",
              "title": "NVIDIA Tensor Cores",
              "url": "https://www.nvidia.com/en-us/data-center/tensor-cores/",
              "date": "2026-03-16",
              "last_updated": "2026-05-20",
              "source": "web"
            },
            {
              "id": 7,
              "snippet": "Nvidia solved the problem of escalating complexity with its \"unified\" Tesla architecture, released in 2006.\nIn the G80 die, there is no more distinction between layers.\nThe Stream Multiprocessor (SM) replaces all previous units thanks to its ability to run vertex, fragment and geometry \"kernel\" without distinction.\nThe load balancing happens automatically by swapping the \"kernel\" run by each SM depending on the need of the pipeline.\nNo longer SIMD capable, \"shaders units\" are now \"core\" capable of one integer or one float32 instruction per clock.\nSM receive threads in groups of 32 called warps.\nIdeally all threads in a warp will execute the same instruction at the same time, only on different data (hence the name SIMT).\nThe Multi-threaded Instruction Unit (MT) takes care of enabling/disabling threads in a warp in case their Instruction Pointer (IP) converge/diverge.\nTwo SFU units are here to help with complex mathematic calculation such as inverse square root, sin, cos, exp, and rcp.\nThese units are also able to execute one instruction per clock but since there are only two of them, warp execution speed is divided by four.\nThere is no hardware support for float64, it is done in software and greatly affects the execution speed.\n...\nThe SM needs to be fed instructions and data which resides in the GPU memory.\nTo avoid stalling, GPUs don't try to avoid memory trips with a lot of cache and speculation like CPUs do.\n...\nThe execution model still revolves around warps of 32 threads scheduled on a SM.\nOnly thanks to a process of 40nm, NVidia doubled/quadrupled everything.\nA SM can now schedule two half-warp (16 threads) simultaneously thanks to two arrays of 16 CUDA cores.\nWith each core executing one instruction per clock, a SM can retire one warp instruction per clock (4x the capacity of Tesla SM).\n...\nThere is a semi-hardware support for float64 where operations are carried by two CUDA core combined.\n...\nWith four warp scheduler able to process a whole warp in one clock (compared to Fermi's half-warp design) the SMX now contains 192 cores.\n...\nWith the release of Turing in 2018, Nvidia operated its \"biggest architectural leap forward in over a decade\"^[13]^.\nNot only the \"Turing SM\" added A.I dedicated Tensor cores, they also gained Raytracing cores.\n...\nBesides the new cores, Turing added three major features.\nFirst, the CUDA core is now a super-scalar able to execute both integer instruction and float instruction in parallel.\n...\nSecond, the new GDDR6X memory sub-system, backed by 16 controllers, can now achieve 14 Gbps.\nLast, threads are no longer sharing their Instruction Pointer in a warp.\nThanks to Independent Thread Scheduling introduced in Volta each thread has its own IP.\nAs a result, SMs are free to fine schedule threads in a warp without the need to make them converge as soon as possible.\n...\nThe next architecture, codenamed Ampere, is rumored to be announced later in 2020.",
              "title": "A history of NVidia Stream Multiprocessor - Fabien Sanglard",
              "url": "https://fabiensanglard.net/cuda/",
              "date": "2020-05-02",
              "last_updated": "2026-05-18",
              "source": "web"
            },
            {
              "id": 8,
              "snippet": "According to Michael Houston from NVIDIA, Tensor Cores are specialized hardware units designed to accelerate mixed precision training.",
              "title": "Tensor Cores Explained in Simple Terms - DigitalOcean",
              "url": "https://www.digitalocean.com/community/tutorials/understanding-tensor-cores",
              "date": "2025-08-04",
              "last_updated": "2026-05-18",
              "source": "web"
            },
            {
              "id": 9,
              "snippet": "2. You’ve already figured out the constant cache is 8kB per SM.\nIt’s not configurable (not sure what you would configure about it, anyway).",
              "title": "Multiprocessor architecture - CUDA - NVIDIA Developer Forums",
              "url": "https://forums.developer.nvidia.com/t/multiprocessor-architecture/159951",
              "date": "2020-11-19",
              "last_updated": "2026-05-19",
              "source": "web"
            },
            {
              "id": 10,
              "snippet": "CUDA Cores are the fundamental processing units inside NVIDIA GPUs, and they handle parallel computations.\n...\nCUDA Cores are the generalists.\nThey handle standard floating-point operations, integer math, and general-purpose parallel computing tasks.\n...\nCUDA Cores handle general parallel computing tasks like data preprocessing and activation functions, while **Tensor Cores** specialize in the matrix multiplications that dominate neural network training.\nBoth work together to accelerate your complete machine learning pipeline.",
              "title": "NVIDIA CUDA Cores: How They Work and Why They Matter (2026)",
              "url": "https://www.thundercompute.com/blog/cuda-cores-explained-ai-training",
              "date": "2026-05-17",
              "last_updated": "2026-05-14",
              "source": "web"
            },
            {
              "id": 11,
              "snippet": "The GPU’s memory bandwidth determines how fast it can move data from/to memory (vRAM) to the computation cores.\nIt’s a more representative indicator than GPU Memory Speed.\nIt is determined by the data transmission speed between memory and computation cores and the number of individual parallel links in the bus between these two parts.\n...\nGPU memory bandwidth refers to the rate at which data can be transferred between the GPU and its memory (VRAM).\nIt is measured in gigabytes per second (GB/s) and plays a critical role in handling large datasets, real-time rendering, and AI/ML workloads.",
              "title": "GPU Memory Bandwidth and Its Impact on Performance - DigitalOcean",
              "url": "https://www.digitalocean.com/community/tutorials/gpu-memory-bandwidth",
              "date": "2025-08-05",
              "last_updated": "2026-05-18",
              "source": "web"
            }
          ],
          "type": "search_results",
          "queries": [
            "NVIDIA streaming multiprocessor architecture overview",
            "NVIDIA CUDA cores and tensor cores definition",
            "NVIDIA HBM memory bandwidth explanation"
          ]
        },
        {
          "id": "msg_64a3d245-e4a5-494f-85ea-53211b74bf68",
          "content": [
            {
              "text": "NVIDIA’s GPU compute model is built around many simple parallel cores grouped into streaming multiprocessors (SMs), backed by very high memory bandwidth (often HBM) so those cores stay busy. [web:1][web:11] SMs contain CUDA cores for general arithmetic and Tensor Cores for dense matrix math, all fed by wide, fast VRAM links. [web:2][web:5][web:6][web:10]\n\n## Streaming multiprocessors (SMs)\n\nAn SM is the fundamental **compute** block of an NVIDIA GPU, roughly analogous to a CPU core but designed to run thousands of lightweight threads in parallel. [web:1][web:5][web:7] Each SM has its own register file, caches/shared memory, warp schedulers, and execution units (CUDA cores, Tensor Cores, special‑function units, load/store units). [web:1][web:5][web:9]\n\nThe programming model launches many threads that are grouped into warps of 32 threads, and warps are scheduled onto SMs. [web:1][web:7] An SM can keep many warps resident (for example up to 64 warps / 2048 threads on recent parts) and quickly switch between them every cycle to hide memory latency instead of relying on deep caches or speculation. [web:1][web:5][web:7]\n\n## CUDA cores\n\n“CUDA cores” are the scalar FP32 execution units inside an SM that perform general-purpose parallel arithmetic. [web:4][web:10] In common usage, the advertised “N CUDA cores” number means N single‑precision units, each capable of roughly one fused multiply‑add (FMA) per cycle for floating‑point math. [web:4][web:2]\n\nCUDA cores handle the bulk of standard GPU work: floating‑point math, integer math, and general GPGPU tasks like elementwise ops, reductions, and control-heavy kernels. [web:4][web:10] An SM in a modern Ada architecture GPU, for example, might have 128 CUDA cores, and a large GPU aggregates many SMs to reach tens of thousands of CUDA cores in total. [web:2][web:7][web:10]\n\n## Tensor Cores\n\nTensor Cores are specialized matrix‑math units inside SMs designed to accelerate small matrix multiply‑accumulate operations, especially for deep learning. [web:6][web:8] They operate on tiles (e.g., 4×4, 16×16 depending on architecture) in mixed or reduced precision (FP16, BF16, TF32, INT8, etc.), delivering far higher throughput than doing the same operations on CUDA cores. [web:6][web:8]\n\nIn NVIDIA’s architectures since Volta/Turing, each SM includes multiple Tensor Cores alongside its CUDA cores (e.g., one Ada SM has 4 Tensor Cores and 128 CUDA cores). [web:2][web:7] The CUDA programming model or frameworks like cuDNN, TensorRT, and PyTorch map large GEMM/convolution ops into many tile operations, which Tensor Cores execute to accelerate training and inference. [web:6][web:8][web:10]\n\n## HBM and memory bandwidth\n\nGPU memory bandwidth is the rate at which data can be moved between GPU cores (inside SMs) and VRAM, typically measured in GB/s. [web:11] High bandwidth is crucial because massively parallel SMs can consume data extremely quickly and will stall if memory cannot supply operands fast enough. [web:1][web:11]\n\nHigh Bandwidth Memory (HBM) is a 3D‑stacked DRAM technology with a very wide bus that provides much higher bandwidth at lower power than traditional GDDR. [web:11] NVIDIA’s data‑center GPUs pair many SMs and Tensor Cores with HBM so that large models and tensors can be streamed efficiently, ensuring the arithmetic units (CUDA and Tensor Cores) can run near peak utilization rather than waiting on data. [web:1][web:6][web:11]",
              "type": "output_text",
              "annotations": [],
              "logprobs": []
            }
          ],
          "role": "assistant",
          "status": "completed",
          "type": "message"
        }
      ],
      "status": "completed",
      "error": null,
      "usage": {
        "input_tokens": 6685,
        "output_tokens": 915,
        "total_tokens": 7600,
        "cost": {
          "currency": "USD",
          "input_cost": 0.00388,
          "output_cost": 0.00915,
          "total_cost": 0.01598,
          "cache_creation_cost": null,
          "cache_read_cost": 0.00045,
          "tool_calls_cost": 0.0025
        },
        "input_tokens_details": {
          "cache_creation_input_tokens": 0,
          "cache_read_input_tokens": 3584,
          "cached_tokens": 3584
        },
        "tool_calls_details": {
          "search_web": {
            "invocation": 1
          }
        },
        "output_tokens_details": {
          "reasoning_tokens": 0
        }
      },
      "background": false,
      "completed_at": 1779391739,
      "frequency_penalty": 0,
      "incomplete_details": null,
      "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
      "max_output_tokens": 8192,
      "max_tool_calls": null,
      "metadata": {},
      "parallel_tool_calls": true,
      "presence_penalty": 0,
      "previous_response_id": null,
      "prompt_cache_key": null,
      "reasoning": null,
      "safety_identifier": null,
      "service_tier": "default",
      "store": true,
      "temperature": 1,
      "text": {
        "format": {
          "type": "text"
        }
      },
      "tool_choice": "auto",
      "tools": [
        {
          "type": "web_search"
        },
        {
          "type": "fetch_url"
        }
      ],
      "top_logprobs": 0,
      "top_p": 1,
      "truncation": "disabled",
      "user": null
    }
    ```
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup>
  <Card title="Web Search" icon="settings-bolt" href="/docs/agent-api/tools/web-search">
    Use web search for source-grounded, current context.
  </Card>

  <Card title="Agent API Models" icon="brain" href="/docs/agent-api/models">
    Browse available models and pricing across all supported providers.
  </Card>

  <Card title="Presets" icon="settings" href="/docs/agent-api/presets">
    Explore pre-configured setups for common use cases like low and medium.
  </Card>

  <Card title="Output Control" icon="indent-decrease" href="/docs/agent-api/output-control">
    Configure streaming responses and structured outputs with JSON schema.
  </Card>

  <Card title="Model Fallback" icon="square-rounded-arrow-down" href="/docs/agent-api/model-fallback">
    Specify multiple models for automatic failover and higher availability.
  </Card>

  <Card title="Prompt Guide" icon="book" href="/docs/agent-api/prompt-guide">
    Best practices for effective prompting with web search models.
  </Card>

  <Card title="Search Filters" icon="filter" href="/docs/agent-api/tools/web-search#filters">
    Control search results with domain, date, and location filters.
  </Card>

  <Card title="API Reference" icon="code-circle" href="/api-reference/agent-post">
    View complete endpoint documentation and parameters.
  </Card>
</CardGroup>

<Info>
  Need help? Check out our [community](https://community.perplexity.ai) for support and discussions with other developers.
</Info>


# Skills
Source: https://docs.perplexity.ai/docs/agent-api/skills

Give the agent on-demand domain expertise with built-in and inline skills.

Skills give the agent domain expertise on demand. The model sees each skill by name and description, and loads the full instructions only when it decides they are needed — a progressive disclosure pattern described in [Designing, Refining, and Maintaining Agent Skills](https://research.perplexity.ai/articles/designing-refining-and-maintaining-agent-skills-at-perplexity).

## Why use skills

* **Specialize.** Add document generation and domain workflows on top of base prompting.
* **Pay context only on use.** Until a skill is loaded, it costs only its name and description.
* **Compose.** Mix built-in skills with inline instructions in one request.

## How skills work

You pass a `skills` array on the request. Each entry is either a **built-in** selection from the catalog or an **inline** skill you define for the request.

| Stage     | What the model sees                                                                                                         |
| --------- | --------------------------------------------------------------------------------------------------------------------------- |
| Discovery | An index of every skill's name and description.                                                                             |
| Load      | The full skill body, returned when the model calls `load_skill`.                                                            |
| Files     | Built-in skills mount supporting files into the sandbox on load. Inline skills return their instructions and mount nothing. |

The description is the routing trigger. Write it to tell the model when to load the skill.

Skills run on the durable backend. Submit with `background: true` and poll as shown in [Background mode](/docs/agent-api/background-mode).

## Available skills

### Built-in skills

Select a built-in skill with one JSON object: `{ "type": "builtin", "name": "office/pdf" }`.

<Tabs>
  <Tab title="office">
    <Card title="Office">
      Generate PDF, Word, PowerPoint, and Excel documents from scratch, with structural validation and visual QA. Select a specific leaf, or select `office` to grant all four at once and let the model pick the format.
    </Card>

    | Name          | Description                                                           | Selection                                      |
    | ------------- | --------------------------------------------------------------------- | ---------------------------------------------- |
    | `office`      | Umbrella that grants all four leaves below.                           | `{ "type": "builtin", "name": "office" }`      |
    | `office/pdf`  | Create PDF documents with page-by-page visual QA.                     | `{ "type": "builtin", "name": "office/pdf" }`  |
    | `office/docx` | Create editable Word documents (OOXML).                               | `{ "type": "builtin", "name": "office/docx" }` |
    | `office/pptx` | Create PowerPoint presentations with slide-by-slide visual QA.        | `{ "type": "builtin", "name": "office/pptx" }` |
    | `office/xlsx` | Create Excel workbooks with verified formulas, charts, and visual QA. | `{ "type": "builtin", "name": "office/xlsx" }` |

    <Note>
      Office skills create documents from scratch. They do not edit files you upload.
    </Note>
  </Tab>
</Tabs>

### Inline skills

Use inline skills for one-off or account-specific guidance the model should load on demand: style guides, playbooks, design systems, house rules.

| Field          | Description                                                                     |
| -------------- | ------------------------------------------------------------------------------- |
| `type`         | Required. Must be `"inline"`.                                                   |
| `name`         | Required. 1-64 characters; lowercase ASCII letters, digits, and single hyphens. |
| `description`  | Required. 1-1,024 bytes. Written as the routing trigger.                        |
| `instructions` | Required. 1-65,536 bytes. The skill body the model reads on load.               |

```json theme={null}
{
  "type": "inline",
  "name": "design-system",
  "description": "Load when creating documents that must follow the house design system.",
  "instructions": "Model: a 1970s letterpress broadsheet financial page. Paper #EDE9DE; body ink #232220; ..."
}
```

Inline skills have no files, no dependencies, no sandbox mounts, no reusable library, and are never echoed back in the response.

## Example

Combine `office/pdf` with an inline `design-system` skill to render a house-styled one-page AI-industry stock report.

<CodeGroup>
  ```python Python theme={null}
  import time
  from perplexity import Perplexity

  client = Perplexity()

  design_book = """
  Model: a 1970s letterpress broadsheet financial page. One ink, gray paper.

  Colors
  - Paper #EDE9DE; tinted boxes and alternating table rows #E3DFD2.
  - Body ink #232220 — soft, never hard black (ink spread on newsprint).
  - Headlines and rules may deepen to #141311; faded ink #5C5850 for captions and secondary text.
  - No second color anywhere. Up moves: bold with a ▲. Down moves: parentheses with a ▼.

  Typography
  - Body: low-contrast newspaper serif (Georgia, PT Serif, or Times), 9-10pt, justified and hyphenated.
  - Headlines: bold condensed serif with a smaller deck beneath.
  - Kickers and table headers: condensed grotesque caps (Franklin Gothic or Oswald), letterspaced.
  - Tables: agate style — 7-8pt condensed, tabular figures.

  Layout
  - One page, ~18mm margins.
  - Nameplate in blackletter or heavy serif, with a folio line (date, edition, price) set between an Oxford rule (thick over hairline).
  - Ticker summary as a boxed agate strip below the nameplate.
  - News timeline in 3-4 narrow justified columns divided by hairline column rules; each item opens with a bold caps dateline ('LONDON, JULY 17 —').
  - Data table ruled with hairlines only.
  - Pack the page — separate blocks with cutoff rules, not white space.

  Imagery
  - Grayscale halftone only, with a hairline keyline and an italic caption.

  Avoid
  - Second colors, gradients, shadows, rounded corners, sans-serif body text, and generous white space.
  """

  response = client.responses.create(
      preset="xhigh",
      background=True,
      skills=[
          {
              "type": "inline",
              "name": "design-system",
              "description": "Load when creating documents that must follow the house design system.",
              "instructions": design_book,
          },
          {"type": "builtin", "name": "office/pdf"},
      ],
      input=(
          "Create a one-page AI-industry stock report. Include NVDA, MSFT, "
          "GOOGL, AMD, and AVGO with latest price and weekly move. Include "
          "this week's key AI news, labeled by date and tagged to the ticker "
          "it moved. Follow the design-system skill."
      ),
  )

  while response.status in ("queued", "in_progress"):
      time.sleep(2)
      response = client.responses.retrieve(response.id)

  print(response.status)
  ```

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

  const client = new Perplexity();

  const designBook = `
  Model: a 1970s letterpress broadsheet financial page. One ink, gray paper.

  Colors
  - Paper #EDE9DE; tinted boxes and alternating table rows #E3DFD2.
  - Body ink #232220 — soft, never hard black (ink spread on newsprint).
  - Headlines and rules may deepen to #141311; faded ink #5C5850 for captions and secondary text.
  - No second color anywhere. Up moves: bold with a ▲. Down moves: parentheses with a ▼.

  Typography
  - Body: low-contrast newspaper serif (Georgia, PT Serif, or Times), 9-10pt, justified and hyphenated.
  - Headlines: bold condensed serif with a smaller deck beneath.
  - Kickers and table headers: condensed grotesque caps (Franklin Gothic or Oswald), letterspaced.
  - Tables: agate style — 7-8pt condensed, tabular figures.

  Layout
  - One page, ~18mm margins.
  - Nameplate in blackletter or heavy serif, with a folio line (date, edition, price) set between an Oxford rule (thick over hairline).
  - Ticker summary as a boxed agate strip below the nameplate.
  - News timeline in 3-4 narrow justified columns divided by hairline column rules; each item opens with a bold caps dateline ('LONDON, JULY 17 —').
  - Data table ruled with hairlines only.
  - Pack the page — separate blocks with cutoff rules, not white space.

  Imagery
  - Grayscale halftone only, with a hairline keyline and an italic caption.

  Avoid
  - Second colors, gradients, shadows, rounded corners, sans-serif body text, and generous white space.
  `;

  let response = await client.responses.create({
    preset: 'xhigh',
    background: true,
    skills: [
      {
        type: 'inline',
        name: 'design-system',
        description: 'Load when creating documents that must follow the house design system.',
        instructions: designBook,
      },
      { type: 'builtin', name: 'office/pdf' },
    ],
    input:
      'Create a one-page AI-industry stock report. Include NVDA, MSFT, ' +
      'GOOGL, AMD, and AVGO with latest price and weekly move. Include ' +
      'this week\'s key AI news, labeled by date and tagged to the ticker ' +
      'it moved. Follow the design-system skill.',
  });

  while (response.status === 'queued' || response.status === 'in_progress') {
    await new Promise((r) => setTimeout(r, 2000));
    response = await client.responses.retrieve(response.id);
  }

  console.log(response.status);
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "preset": "xhigh",
      "background": true,
      "skills": [
        {
          "type": "inline",
          "name": "design-system",
          "description": "Load when creating documents that must follow the house design system.",
          "instructions": "Model: a 1970s letterpress broadsheet financial page. One ink, gray paper.\nColors: paper #EDE9DE (tinted boxes and alternating table rows #E3DFD2); body ink #232220 (soft, never hard black); headlines and rules may deepen to #141311; faded ink #5C5850 for captions. No second color. Up moves: bold + ▲; down moves: parentheses + ▼.\nTypography: body low-contrast newspaper serif (Georgia, PT Serif, or Times), 9-10pt, justified and hyphenated; headlines bold condensed serif with a smaller deck; kickers and table headers condensed grotesque caps (Franklin Gothic or Oswald), letterspaced; tables agate 7-8pt condensed with tabular figures.\nLayout: one page, ~18mm margins; blackletter or heavy-serif nameplate with a folio line (date, edition, price) between an Oxford rule (thick over hairline); boxed agate ticker strip below; news timeline in 3-4 narrow justified columns with hairline column rules, items opening with bold caps datelines ('LONDON, JULY 17 —'); data table ruled with hairlines only. Pack the page — cutoff rules, not padding.\nImagery: grayscale halftone with hairline keyline and italic caption.\nAvoid: second colors, gradients, shadows, rounded corners, sans body text, generous white space."
        },
        { "type": "builtin", "name": "office/pdf" }
      ],
      "input": "Create a one-page AI-industry stock report. Include NVDA, MSFT, GOOGL, AMD, and AVGO with latest price and weekly move. Include this week'\''s key AI news, labeled by date and tagged to the ticker it moved. Follow the design-system skill."
    }'

  curl https://api.perplexity.ai/v1/agent/$RESPONSE_ID \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY"
  ```
</CodeGroup>

The output contains a `skill_loaded` item for each skill the model loaded. Retrieve file bytes through the files endpoints in [Working with files](/docs/agent-api/working-with-files).

## Next steps

<CardGroup>
  <Card title="Agent skills cookbook" icon="book-open" href="/docs/cookbook/articles/agent-skills/README">
    Full walkthrough of the daily AI stock news PDF, including file download and the complete design book.
  </Card>

  <Card title="Working with files" icon="file" href="/docs/agent-api/working-with-files" />

  <Card title="Background mode" icon="clock" href="/docs/agent-api/background-mode" />

  <Card title="Agent API reference" icon="code" href="/api-reference/agent-post" />
</CardGroup>


# Custom Functions
Source: https://docs.perplexity.ai/docs/agent-api/tools/custom-functions

Define a custom function, execute model-requested calls in your code, and return each result to the Agent API.

Custom functions let an agent use code you control, such as a database query, an internal API, or business logic. You describe the function in the request, but the Agent API never executes it for you. Your application handles the call and returns the result.

## Run a complete example

This example defines an order-status function and completes the entire tool loop. Replace the in-memory lookup with your own database or API call.

<Steps>
  <Step title="Install the SDK">
    ```bash theme={null}
    pip install perplexityai
    ```
  </Step>

  <Step title="Set your API key">
    ```bash theme={null}
    export PERPLEXITY_API_KEY="your_api_key_here"
    ```
  </Step>

  <Step title="Save and run the example">
    Save one example as `custom_function.py` or `custom-function.ts`, then run it.

    <CodeGroup>
      ```python Python theme={null}
      import json

      from perplexity import Perplexity

      MODEL = "openai/gpt-5.6-sol"
      QUESTION = "What's the status of order ORD-10042?"

      client = Perplexity()

      tools = [
          {
              "type": "function",
              "name": "get_order_status",
              "description": "Look up the current status of an order by its order ID.",
              "parameters": {
                  "type": "object",
                  "properties": {"order_id": {"type": "string"}},
                  "required": ["order_id"],
                  "additionalProperties": False,
              },
              "strict": True,
          }
      ]


      def get_order_status(order_id: str) -> dict[str, str]:
          """Replace this sample data with a database or API call."""
          orders = {
              "ORD-10042": {
                  "status": "in_transit",
                  "carrier": "DHL",
                  "estimated_delivery": "2026-08-08",
              }
          }
          return orders.get(order_id, {"error": "Order not found."})


      # 1. Send the question and available tools to the model.
      response = client.responses.create(
          model=MODEL,
          input=QUESTION,
          tools=tools,
      )

      # 2. Add the model's output items to the conversation.
      next_input = [
          {"type": "message", "role": "user", "content": QUESTION},
          *[item.model_dump(exclude_none=True) for item in response.output],
      ]

      # 3. Run every function the model requested, then append its result.
      for item in response.output:
          if item.type != "function_call":
              continue
          if item.name != "get_order_status":
              raise ValueError(f"Unknown function: {item.name}")

          arguments = json.loads(item.arguments)
          result = get_order_status(**arguments)
          next_input.append(
              {
                  "type": "function_call_output",
                  "call_id": item.call_id,
                  "output": json.dumps(result),
              }
          )

      # 4. Send the updated conversation back so the model can answer.
      final_response = client.responses.create(
          model=MODEL,
          input=next_input,
          tools=tools,
      )

      print(final_response.output_text)
      ```

      ```typescript Typescript theme={null}
      import Perplexity from '@perplexity-ai/perplexity_ai';
      import type { InputItem } from '@perplexity-ai/perplexity_ai/resources/responses/responses';

      const MODEL = 'openai/gpt-5.6-sol';
      const QUESTION = "What's the status of order ORD-10042?";

      const client = new Perplexity();

      const tools = [
        {
          type: 'function' as const,
          name: 'get_order_status',
          description: 'Look up the current status of an order by its order ID.',
          parameters: {
            type: 'object',
            properties: { order_id: { type: 'string' } },
            required: ['order_id'],
            additionalProperties: false,
          },
          strict: true,
        },
      ];

      function getOrderStatus(orderId: string): Record<string, string> {
        // Replace this sample data with a database or API call.
        const orders: Record<string, Record<string, string>> = {
          'ORD-10042': {
            status: 'in_transit',
            carrier: 'DHL',
            estimated_delivery: '2026-08-08',
          },
        };
        return orders[orderId] ?? { error: 'Order not found.' };
      }

      // 1. Send the question and available tools to the model.
      const response = await client.responses.create({
        model: MODEL,
        input: QUESTION,
        tools,
      });

      // 2. Start the continuation with the original question.
      const nextInput: InputItem[] = [
        { type: 'message', role: 'user', content: QUESTION },
      ];

      // 3. Replay each function call, run it locally, and append its result.
      for (const item of response.output) {
        if (item.type !== 'function_call') continue;
        nextInput.push({
          type: 'function_call',
          call_id: item.call_id,
          name: item.name,
          arguments: item.arguments,
          ...(item.thought_signature
            ? { thought_signature: item.thought_signature }
            : {}),
        });

        if (item.name !== 'get_order_status') {
          throw new Error(`Unknown function: ${item.name}`);
        }
        const args = JSON.parse(item.arguments) as { order_id: string };
        const result = getOrderStatus(args.order_id);
        nextInput.push({
          type: 'function_call_output',
          call_id: item.call_id,
          output: JSON.stringify(result),
        });
      }

      // 4. Send the updated conversation back so the model can answer.
      const finalResponse = await client.responses.create({
        model: MODEL,
        input: nextInput,
        tools,
      });

      console.log(finalResponse.output_text);
      ```
    </CodeGroup>

    Run it:

    <CodeGroup>
      ```bash Python theme={null}
      python custom_function.py
      ```

      ```bash Typescript theme={null}
      npm install @perplexity-ai/perplexity_ai tsx
      npx tsx custom-function.ts
      ```
    </CodeGroup>

    Example terminal output:

    ```text theme={null}
    Order ORD-10042 is in transit with DHL. Estimated delivery is Saturday, August 8, 2026.
    ```
  </Step>
</Steps>

## How the loop works

The two Agent API requests wrap one local function execution:

1. **Declare and call.** Your first request includes the user's question and the function schema in `tools`.
2. **Read `function_call`.** The model returns a `function_call` item in `response.output`. Its `arguments` field is a JSON string, so parse it before calling your code.
3. **Execute locally.** Your application calls `get_order_status` with those arguments. This code does not run in the Agent API.
4. **Return `function_call_output`.** Append the model's output items and a `function_call_output` containing the local result, then make another request. Copy the original `call_id` so the model can match the result to its call.
5. **Read the answer.** After it receives the function result, the model returns a normal assistant `message`. If it requests another function instead, repeat the same loop.

## Inspect the response arrays

Here is the complete `output` array from the first request. `arguments` is JSON encoded as a string, and IDs vary between requests.

```json theme={null}
[
  {
    "id": "fc_a181bc3f-7a54-40b6-a85e-a50a0a6fac92",
    "arguments": "{\"order_id\":\"ORD-10042\"}",
    "call_id": "call_Ku9yfMSIZWrJBGm2wqCaFF0G",
    "name": "get_order_status",
    "status": "completed",
    "type": "function_call"
  }
]
```

The application executes `get_order_status` and sends this continuation `input` array. The `function_call` and `function_call_output` carry the same `call_id`:

```json theme={null}
[
  {
    "type": "message",
    "role": "user",
    "content": "What's the status of order ORD-10042?"
  },
  {
    "id": "fc_a181bc3f-7a54-40b6-a85e-a50a0a6fac92",
    "arguments": "{\"order_id\":\"ORD-10042\"}",
    "call_id": "call_Ku9yfMSIZWrJBGm2wqCaFF0G",
    "name": "get_order_status",
    "status": "completed",
    "type": "function_call"
  },
  {
    "type": "function_call_output",
    "call_id": "call_Ku9yfMSIZWrJBGm2wqCaFF0G",
    "output": "{\"status\": \"in_transit\", \"carrier\": \"DHL\", \"estimated_delivery\": \"2026-08-08\"}"
  }
]
```

The second request then returns this complete `output` array:

```json theme={null}
[
  {
    "id": "msg_b95a5d0d-bb02-4f09-bde4-22a781265e61",
    "content": [
      {
        "text": "Order **ORD-10042** is **in transit** with **DHL**. Estimated delivery is **Saturday, August 8, 2026**.",
        "type": "output_text",
        "annotations": []
      }
    ],
    "role": "assistant",
    "status": "completed",
    "type": "message"
  }
]
```

<Note>
  Some models include a `thought_signature` on `function_call` items. Preserve it when you replay the item. The Python example does this by serializing the complete SDK object; the TypeScript example copies it when present.
</Note>

## Next steps

<CardGroup>
  <Card title="Function calling cookbook" icon="book" href="/docs/cookbook/articles/function-calling-e2e/README">
    Handle multiple functions, parallel calls, and failures in production workflows.
  </Card>

  <Card title="Tools overview" icon="list" href="/docs/agent-api/tools/overview">
    Compare custom functions with built-in tools and MCP servers.
  </Card>
</CardGroup>


# Fetch URL Content
Source: https://docs.perplexity.ai/docs/agent-api/tools/fetch-url-content

Fetch and extract content from specific URLs in the Agent API.

## Overview

The `fetch_url` tool fetches and extracts content from specific URLs during an Agent API request. Use it when your application already knows which page, article, document, or report the model should inspect.

Use `fetch_url` when you need full page content from known URLs. Use [`web_search`](/docs/agent-api/tools/web-search) when the model first needs to discover relevant pages.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Explain Bayesian inference: how prior beliefs are updated to posterior beliefs given new evidence, with a concrete medical-test example.",
      tools=[
          {
              "type": "fetch_url"
          }
      ],
      instructions="Fetch the URL before summarizing it.",
  )

  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-sol',
    input: 'Explain Bayesian inference: how prior beliefs are updated to posterior beliefs given new evidence, with a concrete medical-test example.',
    tools: [
      {
        type: 'fetch_url' as const,
      },
    ],
    instructions: 'Fetch the URL before summarizing it.',
  });

  console.log(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 '{
      "model": "openai/gpt-5.6-sol",
      "input": "Explain Bayesian inference: how prior beliefs are updated to posterior beliefs given new evidence, with a concrete medical-test example.",
      "tools": [
        {
          "type": "fetch_url"
        }
      ],
      "instructions": "Fetch the URL before summarizing it."
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_02fda963-4ab7-42cc-b446-d446e0dcd3b2",
    "created_at": 1779391738,
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "results": [
          {
            "id": 1,
            "snippet": "The disease you have tested positive for is very rare, so let’s say that only 1 in every 100 people with your symptoms actually have the disease.\nThe test you took is 99% sensitive, and 94% specific.\nAccording to Bayes’ Theorem, these numbers mean that if you test positive, there is in fact only a 14% chance you actually have the disease… but how is that possible?",
            "title": "Bayes' Theorem and Disease Testing - tom rocks maths",
            "url": "https://tomrocksmaths.com/2021/08/31/bayes-theorem-and-disease-testing/",
            "date": "2021-08-31",
            "last_updated": "2026-05-13",
            "source": "web"
          },
          {
            "id": 2,
            "snippet": "- Suppose that 5 in 1,000 people (0.5%) has a particular disease\n(*prevalence* of the disease).\n- A diagnostic test for the disease has 99% *sensitivity* (if a person has the disease, the test will give a positive result with a probability of 0.99).\n- The test has 98% *specificity* (if a person does not have the disease, the test will give a negative result with a probability of 0.98).\nWe ask:\n- What is the probability that a person has the disease\nafter he was tested positive.\n- What is the probability that a person does not have the disease\nafter she was tested negative.\n...\nThe sensitivity and specificity give the conditional probabilities: $$\\begin{align} P(+ | D) & = 0.99 = sens \\\\ P(- | D) & = 0.01 \\\\ P(+ | \\overline{D}) & = 0.02 \\\\ P(- | \\overline{D}) & = 0.98 = spec \\end{align}$$ The posterior probabilities are given by Bayes formula.\nPositive prediction: $$\\begin{align} P(D | +) & = \\frac{P(+ | D) P(D)} {P(+ | D) P(D) + P(+ | \\overline{D}) P(\\overline{D}) } \\\\ & = \\frac{sens \\times preval} {sens \\times preval + (1- spec) \\times (1 - preval) } \\\\ & = \\frac{0.99 \\times 0.005} {0.99 \\times 0.0005 + 0.02 \\times 0.995} = 0.20 \\end{align}$$ and negative prediction: $$\\begin{align} P(\\overline{D} | -) & = \\frac{P(- | \\overline{D}) P(\\overline{D})} {P(- | D) P(D) + P(- | \\overline{D}) P(\\overline{D}) } \\\\ & = \\frac{spec * (1 - preval)} {spec \\times (1 - preval) + (1 - sens) \\times preval} \\\\ & = \\frac{0.98 \\times 0.995} {0.98 \\times 0.9995 + 0.01 \\times 0.005} = 1.0 \\end{align}",
            "title": "Sensitivity and Specificity",
            "url": "https://www.nosco.ch/mathematics/en/sensitivity-specificity.php",
            "date": null,
            "last_updated": "2026-05-17",
            "source": "web"
          },
          {
            "id": 3,
            "snippet": "Suppose a blood test used to\ndetect the presence of a particular banned sports drug is **99%\n** **sensitive** and **99% ** **specific**.\nThat is, the test will produce 99% **true positive** results for drug users and 99% **true negative** results for non-drug users.\nSuppose that **0.5%** of athletes are users of the drug.\nWhat is the *likelihood * that *a randomly\nselected athlete who **tests positive is a user** *?",
            "title": "Bayes Theorem - Drug testing",
            "url": "https://www.mun.ca/biology/scarr/4250_Bayes_Theorem.html",
            "date": null,
            "last_updated": "2026-03-14",
            "source": "web"
          },
          {
            "id": 4,
            "snippet": "A: mammogram positive, B: developing breast cancer in next 2 years\nSuppose that 7% of the general population of women will have a positive mammogram.\nWhat is the probability of developing breast cancer over the next 2 years among women\nin the general population?\nP(breast cancer | mammogram+) = .1\nP(breast cancer | mammogram-) = .0002\nP(B) = P(breast cancer)\n= P(breast cancer | mammogram+)P(mammogram+) + P(breast cancer | mammogram-\n)P(mammogram-) = .1(.07) + .0002(.93) = 0.00719\nPV+ = P(breast cancer|mammogram+) = .1\nPV- = P(no breast cancer | mammogram-) = 1- P(breast cancer | mammogram-) = 1-.0002\n= .9998\n...\nBayes’ Rule\nLet A = symptom and B = disease.\nThen\nPV + = P(B | A) =\nP(A | B)P(B)\nP(A | B)P(B) + P(A | Bc)P(Bc)\nThis can be written as\n1\nPV + =\nsensitivity × x\nsensitivity × x + (1 −specificity) × (1 −x)\nwhere x = P(B) = probability of disease in the reference population.\nExample: (Cancer) Suppose the disease is lung cancer and the symptom is cigarette smok-\ning.\nIf we assume 90% of people with lung cancer and 30 % of people without lung cancer\nare smokers, What is the sensitivity and specificity?\nSymptom: smoking, Disease: lung\ncancer\nSensitivity = P(symptom | disease) = .9\nSpecificity = P(no symptom | no disease) = 1- P(symptom | no disease) = .7\nExample: (Hypertension) Suppose 84% of hypertensive and 23% of normotensives are clas-\nsified as hypertensive by an automated blood-pressure machine.\nWhat are the predictive\nvalue positive and predictive value negative of the machine, assuming 20% of the adult\npopulation is hypertensive?\nThe sensitivity = P(symptom | disease) = .84 and specificity\n= P(no symptom | no disease) = 1-.23 = .77.\nFrom Bayes rule PV+ = (sensitivity ×\nx)/(sensitivity× x + (1-specificity)× (1-x))\nPV- = (specificity × (1-x))/(specificity ×(1-x)+ (1-sensitivity) × x)\nPV+ = (.84)(.2)/[(.84)(.2) + (.23)(.8)] = .168/.352 = .48\nPV- = (.77)(.8)/[(.77)(.8) + (.16)(.2)] = .616/.648 = .95",
            "title": "[PDF] Predictive values Sensitivity and specificity Bayes' Rule",
            "url": "https://ani.stat.fsu.edu/~debdeep/p2_s14.pdf",
            "date": "2014-01-14",
            "last_updated": "2026-02-16",
            "source": "web"
          },
          {
            "id": 5,
            "snippet": "positive test given the disease\n{ts:800} times the probability\nof disease divided by-- this same probability--\n...\ndisease times probability",
            "title": "Bayes' Theorem (with Example!) - YouTube",
            "url": "https://www.youtube.com/watch?v=akClB1J6b28",
            "date": "2024-12-02",
            "last_updated": "2026-03-22",
            "source": "web"
          },
          {
            "id": 6,
            "snippet": "So if all you know about a woman is that she does the screening and she gets a positive result, you don't have information about symptoms or anything like that,\n{ts:113} you know that she's either one of these 9 true positives or one of these 89 false positives.\nSo the probability that she's in the cancer group given the test\n{ts:123} result is 9 divided by 9 plus 89, which is approximately 1 in 11.\nIn medical parlance, you would call this the positive predictive value of the test, or PPV, the number of true positives divided by the total number of positive test results.\n...\n{ts:978} It says your odds of having a disease given a test result equals your odds before taking the test, the prior odds, times the base factor.",
            "title": "The medical test paradox, and redesigning Bayes' rule - YouTube",
            "url": "https://www.youtube.com/watch?v=lG4VkPoG3ko",
            "date": "2020-12-22",
            "last_updated": "2026-03-31",
            "source": "web"
          },
          {
            "id": 7,
            "snippet": "The Fagan Nomogram was designed to give a post-test probability based on the pre-test probability and the likelihood ratio of the test being conducted.\n...\nUnfortunately the police test is 80% (0.8) accurate.\nIn other words, identifying the driver as drunk when they are or [P (B/A)].\nSo if test results show the driver is drunk (+ve test), the probabilities are now either:\n- drunk (0.15) and correct (0.8) = 0.12 (true positives)\n- not drunk (0.85) and incorrect (0.2) = 0.17 (false positive)",
            "title": "Bayesian Statistics - The Bottom Line",
            "url": "https://www.thebottomline.org.uk/blog/ebm/bayesian-statistics/",
            "date": "2020-09-11",
            "last_updated": "2026-05-21",
            "source": "web"
          },
          {
            "id": 8,
            "snippet": "We can apply Bayes' theorem if we know the approximate likelihood that a subject has the disease before they come for screening, this is given by the prevalence of the disease.\n...\nFor an overall case rate of 100 per ten thousand population tested:\nTest SENSITIVITY = 95.1%\nProbability of a FALSE POSITIVE result = 0.533824\nTest SPECIFICITY = 98.9%\nProbability of a FALSE NEGATIVE result = 0.0005",
            "title": "Screening Test Errors (Bayes' Theorem) - StatsDirect",
            "url": "https://www.statsdirect.com/help/clinical_epidemiology/screening_test.htm",
            "date": null,
            "last_updated": "2026-03-07",
            "source": "web"
          }
        ],
        "type": "search_results",
        "queries": [
          "Bayes theorem medical test example",
          "Bayes rule disease test sensitivity specificity",
          "Bayesian inference prior posterior example disease test"
        ]
      },
      {
        "id": "msg_738a8825-ab21-4f10-bee9-2bdedfa99347",
        "content": [
          {
            "text": "Bayesian inference is a way to update **beliefs** (probabilities) when new data arrive: the prior belief is combined with how likely the data are under different hypotheses to produce a posterior belief. [web:2]\n\n## Core idea and formula\n\nBayes’ theorem in probability form is: [web:2]\n\n\\[\nP(H \\mid E) = \\frac{P(E \\mid H)\\,P(H)}{P(E \\mid H)\\,P(H) + P(E \\mid \\neg H)\\,P(\\neg H)}\n\\] [web:2]\n\n- \\(H\\): hypothesis (e.g., “patient has the disease”). [web:2]  \n- \\(E\\): evidence (e.g., “test result is positive”). [web:2]  \n- \\(P(H)\\): prior, belief in \\(H\\) before seeing the test. [web:2]  \n- \\(P(H \\mid E)\\): posterior, updated belief in \\(H\\) after seeing the test. [web:2]  \n- \\(P(E \\mid H)\\), \\(P(E \\mid \\neg H)\\): how likely the evidence is if \\(H\\) is true or false (this is where test accuracy enters). [web:2]\n\nIn words: posterior = (likelihood × prior) / average likelihood of the evidence across all possibilities. [web:2]\n\n## Connecting to medical test terms\n\nFor diagnostic tests, Bayes’ theorem often uses: [web:2]\n\n- Disease \\(D\\) vs no disease \\(\\overline{D}\\). [web:2]  \n- Positive test “+” vs negative “–”. [web:2]  \n\nKey quantities:\n\n- **Prevalence**: \\(P(D)\\): prior probability that someone from this population has the disease, before considering the test result. [web:2]  \n- **Sensitivity**: \\(P(+ \\mid D)\\): probability the test is positive if the person has the disease (true-positive rate). [web:2]  \n- **Specificity**: \\(P(- \\mid \\overline{D})\\): probability the test is negative if the person does not have the disease (true-negative rate). [web:2]  \n\nThe two main post-test probabilities are: [web:2]  \n\n- \\(P(D \\mid +)\\): probability of disease given a positive result (positive predictive value, PPV).  \n- \\(P(\\overline{D} \\mid -)\\): probability of no disease given a negative result (negative predictive value, NPV).  \n\nBayes’ theorem gives, for a positive test: [web:2]\n\n\\[\nP(D \\mid +) = \\frac{P(+ \\mid D)\\,P(D)}{P(+ \\mid D)\\,P(D) + P(+ \\mid \\overline{D})\\,P(\\overline{D))}\n\\] [web:2]\n\nand \\(P(+ \\mid \\overline{D}) = 1 - \\text{specificity}\\). [web:2]\n\n## Concrete medical-test example\n\nConsider this concrete scenario: [web:2]\n\n- Disease prevalence in the population: \\(P(D) = 0.5\\%\\) (5 in 1,000 people).  \n- Sensitivity of the test: 99% → \\(P(+ \\mid D) = 0.99\\).  \n- Specificity of the test: 98% → \\(P(- \\mid \\overline{D}) = 0.98\\), so \\(P(+ \\mid \\overline{D}) = 0.02\\).  \n\nQuestion: If a randomly chosen person from this population tests positive, what is the probability they actually have the disease, \\(P(D \\mid +)\\)? [web:2]\n\nPlug into Bayes’ formula: [web:2]\n\n\\[\nP(D \\mid +) = \n\\frac{0.99 \\times 0.005}{0.99 \\times 0.005 + 0.02 \\times 0.995}\n\\approx 0.20\n\\] [web:2]\n\nSo even though the test is quite accurate, a positive result means only about a 20% chance (1 in 5) that the person truly has the disease, because the disease is rare. [web:2]\n\n## Interpreting as prior → posterior update\n\nIn that example, Bayesian inference can be read step by step. [web:2]\n\n- Prior belief: Before testing, chance of disease is 0.5% (prevalence). [web:2]  \n- Evidence quality: A positive test is much more likely if the person has disease (0.99) than if they do not (0.02), so it is informative but not perfect. [web:2]  \n- Posterior belief: After a positive result, the belief jumps from 0.5% to about 20%; this is the updated probability \\(P(D \\mid +)\\). [web:2]  \n\nConceptually, the test “boosts” the prior odds of disease by a factor equal to the likelihood ratio \\(\\text{LR}^+ = \\frac{P(+ \\mid D)}{P(+ \\mid \\overline{D})} = \\frac{0.99}{0.02} \\approx 49.5\\), then converts those updated odds back into a probability. [web:2][web:7]  \n\nSo Bayesian inference is precisely this: start with a prior probability, adjust it using how strongly the evidence favors one hypothesis over alternatives, and end with a posterior probability that reflects both the original belief and the new data. [web:2][web:7]",
            "type": "output_text",
            "annotations": [],
            "logprobs": []
          }
        ],
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "status": "completed",
    "error": null,
    "usage": {
      "input_tokens": 6282,
      "output_tokens": 1258,
      "total_tokens": 7540,
      "cost": {
        "currency": "USD",
        "input_cost": 0.00337,
        "output_cost": 0.01258,
        "total_cost": 0.0189,
        "cache_creation_cost": null,
        "cache_read_cost": 0.00045,
        "tool_calls_cost": 0.0025
      },
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 3584,
        "cached_tokens": 3584
      },
      "tool_calls_details": {
        "search_web": {
          "invocation": 1
        }
      },
      "output_tokens_details": {
        "reasoning_tokens": 0
      }
    },
    "background": false,
    "completed_at": 1779391738,
    "frequency_penalty": 0,
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "user": null
  }
  ```
</Accordion>

## When to Use

| Use `fetch_url` when...                            | Use `web_search` when...                   |
| -------------------------------------------------- | ------------------------------------------ |
| You already have a URL                             | You need to discover relevant pages        |
| You need fuller page content                       | You need snippets from multiple sources    |
| You are summarizing a specific article or document | You are researching a broad topic          |
| You want the model to inspect a known source       | You want the model to find current sources |

<Tip>
  Combine `web_search` and `fetch_url` for multi-step research: search to find relevant pages, then fetch the most important URLs for fuller context.
</Tip>

## Parameters

| Parameter  | Type    | Required | Description                                                                               |
| ---------- | ------- | -------- | ----------------------------------------------------------------------------------------- |
| `type`     | string  | Yes      | Must be `"fetch_url"`.                                                                    |
| `max_urls` | integer | No       | Maximum number of URLs to fetch per tool call. The API schema allows values from 1 to 10. |

## Response Shape

When `fetch_url` runs, the response can include a `fetch_url_results` output item before the final assistant message. Each fetched content item includes the URL, page title, and extracted snippet.

```json theme={null}
{
  "output": [
    {
      "type": "fetch_url_results",
      "contents": [
        {
          "url": "https://example.com/report",
          "title": "Example Report",
          "snippet": "Extracted content from the fetched page."
        }
      ]
    },
    {
      "type": "message",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "The answer generated from the fetched URL content."
        }
      ]
    }
  ],
  "usage": {
    "input_tokens": 900,
    "output_tokens": 250,
    "total_tokens": 1150,
    "tool_calls_details": {
      "fetch_url": {
        "invocation": 1
      }
    }
  }
}
```

## Error Handling

`fetch_url` is best-effort. When a URL cannot be fully fetched or extracted, the API can still return a completed Agent API response with the final assistant message explaining what content was available. Check the `fetch_url_results.contents` array to see which URLs produced extracted content.

| Case                              | Response behavior                                                                                                                                                                                   |
| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Paywalls and login walls**      | `fetch_url` does not bypass access controls. URLs that block access are typically omitted from `fetch_url_results.contents`, and the final assistant message explains which URLs could not be read. |
| **Redirects**                     | HTTP redirects are followed when the destination can be fetched. In the returned `fetch_url_results` item, the `url` field reflects the URL you requested, not the final redirect destination.      |
| **Non-HTML content**              | `fetch_url` extracts whatever text content the server returns at the URL. PDFs, binary downloads, and URLs that serve anti-bot challenge pages may return limited or unrelated extracted content.   |
| **Timeouts and unreachable URLs** | URLs that time out or cannot be reached are typically omitted from `fetch_url_results.contents`. The final assistant message explains what was missed.                                              |

## Limits / Quotas

Use `max_urls` to keep fetches bounded and predictable. Fewer URLs usually produce lower latency and leave more context for the model's reasoning and final answer.

| Limit                          | Value                                                                                                                                                        |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Maximum URLs per tool call** | `max_urls` can be set from 1 to 10.                                                                                                                          |
| **Supported URL schemes**      | Use absolute `http://` or `https://` URLs. Other schemes (`file:`, `data:`, `ftp:`, browser-extension URLs) are not supported and produce no usable content. |
| **Content size**               | Fetched content is extracted into snippets for model context and may be truncated for longer pages.                                                          |

## Pricing

`fetch_url` is billed at **\$0.50 per 1,000 invocations**. Model token usage is billed separately according to Agent API token pricing.

<Note>
  Pricing follows the same pattern as other tool calls: pay for tool invocations plus model tokens. See [Pricing](/docs/getting-started/pricing).
</Note>

## Next Steps

<CardGroup>
  <Card title="Web Search" icon="world-search" href="/docs/agent-api/tools/web-search">
    Search the web before fetching source content.
  </Card>

  <Card title="Finance Search" icon="chart-line" href="/docs/agent-api/tools/finance-search">
    Retrieve structured financial and market data.
  </Card>

  <Card title="People Search" icon="users" href="/docs/agent-api/tools/people-search">
    Search for professionals and employees.
  </Card>

  <Card title="API Reference" icon="code-circle" href="/api-reference/agent-post">
    View complete endpoint documentation.
  </Card>
</CardGroup>


# Finance Search
Source: https://docs.perplexity.ai/docs/agent-api/tools/finance-search

Retrieve structured financial and market data in the Agent API.

## Overview

`finance_search` lets the model pull structured financial and market data for public companies, ETFs, and related instruments. The model decides which fields to fetch based on your prompt.

Use it when one answer needs more than one type of financial data, such as valuation, earnings, and context for the same company or list of companies.

### Capabilities

| Data area                       | What it includes                                                                                  |
| ------------------------------- | ------------------------------------------------------------------------------------------------- |
| Company basics                  | Quotes, profiles, peers, and market metadata                                                      |
| Financials                      | Income statement, balance sheet, cash flow (quarterly and annual), key ratios                     |
| Valuation and pricing           | Current/near-real-time pricing, 1-minute to 1-month OHLCV ranges, pre-market and after-hours data |
| Earnings                        | Last earnings call transcript, report filings, beat/miss history, guidance discussion             |
| Segment and KPI tracking        | Revenue/profit by segment, geography, ARPU, subscriber counts, GMV, and other operating metrics   |
| Analyst coverage                | Forward revenue and EPS estimates, cover count, historical estimate changes                       |
| Market activity                 | Top gainers, top losers, and most active symbols                                                  |
| Ownership and corporate actions | Insider activity, ticker-level metadata, splits, and related market events                        |
| ETF and index details           | Top constituents, shares, weights, and market values                                              |

## Coverage

`finance_search` coverage depends on the symbol, exchange, asset class, geography, and source data availability.

| Coverage area                  | Current guidance                                                                                  |
| ------------------------------ | ------------------------------------------------------------------------------------------------- |
| **Ticker and symbol coverage** | Publicly traded companies, ETFs, and related instruments when a supported symbol can be resolved. |
| **Asset classes**              | Public equities and ETFs.                                                                         |

<Warning>
  Market data may be delayed, incomplete, or unavailable for some symbols. `finance_search` is for informational use only and does not provide investment, legal, tax, or financial advice.
</Warning>

## Quickstart

Add `finance_search` to the `tools` array.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="What's NVIDIA trading at right now, and what is its current P/E?",
      tools=[
          {"type": "web_search"},
          {"type": "finance_search"}
      ]
  )

  for item in response.output:
      if item.type == "message":
          print(item.content[0].text)
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.perplexity.ai/v1/agent" \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "input": "What is NVIDIA trading at right now, and what is its current P/E?",
      "tools": [
        {"type": "web_search"},
        {"type": "finance_search"}
      ]
    }'
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "background": false,
    "completed_at": 1777644610,
    "created_at": 1777644610,
    "error": null,
    "frequency_penalty": 0,
    "id": "resp_d0476d0f-872d-492a-907e-1daa48eb9e32",
    "incomplete_details": null,
    "instructions": null,
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "model": "openai/gpt-5.6-sol",
    "object": "response",
    "output": [
      {
        "categories": ["quote"],
        "results": [
          {
            "category": "quote",
            "content": "## NVDA Quote\nQuote field guide: `price` is the latest quote/current price...\n| symbol | name | timestamp | market_status | price | currency | change | changesPercentage | marketCap | pe | eps | volume | dayLow | dayHigh | yearLow | yearHigh | previousClose | open |\n| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |\n| NVDA | NVIDIA Corporation | 2026-05-01 14:10:07 UTC | open | 200.23 | USD | 0.66 | 0.33 | 4,866,492,706,948 | 40.86 | 4.90 | 28,725,330 | 199.15 | 203 | 110.82 | 216.83 | 199.57 | 201.28 |",
            "sources": [
              "https://www.perplexity.ai/finance/NVDA/historical-data",
              "https://www.perplexity.ai/finance/NVDA"
            ],
            "tickers": ["NVDA"]
          }
        ],
        "tickers": ["NVDA"],
        "type": "finance_results"
      },
      {
        "content": [
          {
            "annotations": [],
            "logprobs": [],
            "text": "NVIDIA (NVDA) is currently trading at **$200.23** per share, and its current P/E ratio is **40.86**.",
            "type": "output_text"
          }
        ],
        "id": "msg_b188058f-8225-4642-90e6-da7112f96b69",
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "status": "completed",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "finance_search"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "usage": {
      "cost": {
        "currency": "USD",
        "input_cost": 0.00189,
        "output_cost": 0.00016,
        "tool_calls_cost": 0.005,
        "total_cost": 0.00705
      },
      "input_tokens": 7570,
      "input_tokens_details": {
        "cached_tokens": 0
      },
      "output_tokens": 63,
      "output_tokens_details": {
        "reasoning_tokens": 0
      },
      "tool_calls_details": {
        "finance_search": {
          "invocation": 1
        }
      },
      "total_tokens": 7633
    },
    "user": null
  }
  ```
</Accordion>

## Example Prompts

* **Full company brief:** "Give me a complete NVIDIA snapshot: valuation, segment revenue for the latest quarter, and management's latest commentary on margins guidance."
* **Compare companies in one request:** "Compare Apple, Microsoft, and Alphabet on revenue growth, operating margin, and forward P/E for the latest fiscal year."
* **Earnings + reaction context:** "Summarize Tesla's last earnings call, include actual vs consensus, and describe how the stock and analyst targets moved after publication."

## Prompt Guidance

`finance_search` works best when the prompt states the outcome, not the data shape.

* Start with the business question first, then include the company or ticker.
* Add time windows when relevant (`latest quarter`, `fiscal year to date`, `last 30 days`).
* Let the tool decide which specific report fields to retrieve.

## Recommended Configurations

Start with the configuration that matches the shape of the finance question.

| Configuration                     | Best for                                                 | Latency  | Quality | Cost   |
| --------------------------------- | -------------------------------------------------------- | -------- | ------- | ------ |
| Live Market Data and Quotes       | Real-time prices, quotes, and latest figures             | Fast     | Good    | Low    |
| Single-Company Historical Lookups | Basic historical financials for one company or ticker    | Balanced | High    | Medium |
| Multi-Step Financial Research     | Cross-company comparisons and complex financial analysis | Thorough | Highest | High   |

### Live Market Data and Quotes

Use this for time-sensitive answers that depend on real-time prices, quotes, or the latest market figures. It is the cheapest and fastest option while maintaining strong quality for live data lookups.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="What is Apple's most recent annual revenue, and what segments contributed most to year-over-year growth?",
      tools=[{"type": "finance_search"}],
      max_steps=1,
      max_output_tokens=1024
  )

  for item in response.output:
      if item.type == "message":
          print(item.content[0].text)
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.perplexity.ai/v1/agent" \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "input": "What is Apple\u0027s most recent annual revenue, and what segments contributed most to year-over-year growth?",
      "tools": [{"type": "finance_search"}],
      "max_steps": 1,
      "max_output_tokens": 1024
    }'
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "4a4fa036-b206-44db-91d1-e0d7cf8f8b1e",
    "results": [
      {
        "snippet": "It has also built out its subscription services to include music and video streaming, video games, fitness and cloud storage.\nThis segment alone generated $53 billion revenue in 2020, making it Apple’s second largest segment.\n...\n## Apple Key Statistics\n- Apple generated $390.8 billion revenue in 2024, 51% came from iPhone sales\n- Apple Services is the second largest division, responsible for 24% of revenue in 2024\n- 232 million iPhones, 52 million iPads and 22 million Mac and MacBook units were sold in 2024\n- Apple’s home and wearables division declined by 6.5% in 2024\n- It sold 66 million AirPods and 39 million Apple Watches in 2024\n- Apple Music has 95 million subscribers, Apple TV+ has 30 million\n…\n...\nApple revenue increased dramatically in the 2010s, from $65 billion at the start of the decade to $274 billion by the end.\nRevenues increased by 1.9% in 2024.\n...\nApple has always been most successful in the United States, its home country.\nAmericas is responsible for 42% of all revenue generation and approximately 35% of that is from the US alone.\n...\n## Apple Revenue by Product\niPhone continues to be the main revenue generator, but its percentage has decreased in the past five years.\nServices has seen the highest percentage increase over the past five years.\n...\niPhone is Apple’s most valuable product and has, since 2008, been its main source of revenue.\nEven though Apple has diversified its product line with Watch, AirPods and services, iPhone is still responsible for 51% of its revenue.\n...\nApple generated $37 billion revenue from this segment in 2024.\nWe estimate AirPods is a $10 billion business on its own, with Apple Watch also potentially contributing between $14 billion to $18 billion a year.",
        "title": "Apple Statistics (2026) - Business of Apps",
        "url": "https://www.businessofapps.com/data/apple-statistics/",
        "date": "2026-02-26",
        "last_updated": "2025-09-02"
      },
      {
        "snippet": "",
        "title": "Investor Relations - Apple",
        "url": "https://investor.apple.com/investor-relations/default.aspx",
        "date": null,
        "last_updated": "2026-04-17"
      },
      {
        "snippet": "In fiscal year 2025, Apple's revenue by segment (products & services) are as follows:\n**iPad:**$28.02 B **iPhone:**$209.59 B **Mac:**$33.71 B **Service:**$109.16 B **Wearables, Home and Accessories:**$35.69 B\nLearn more about Apple’s Revenue by Geography\n...\nIn fiscal year 2023, Apple's revenue by segment is as follows:\n**iPad**generated $28.30 B in revenue, representing 7.38% of its total revenue.\n**iPhone**generated $200.58 B in revenue, representing 52.33% of its total revenue.\n**Mac**generated $29.36 B in revenue, representing 7.66% of its total revenue.\n**Service**generated $85.20 B in revenue, representing 22.23% of its total revenue.\n**Wearables, Home and Accessories**generated $39.85 B in revenue, representing 10.4% of its total revenue.\nThe\n**biggest segment**for Apple is the iPhone, which represents 52.33% of its total revenue.\nThe\n...\nIn fiscal year 2024, Apple's revenue by segment is as follows:\n**iPad**generated $26.69 B in revenue, representing 6.83% of its total revenue.\n**iPhone**generated $201.18 B in revenue, representing 51.45% of its total revenue.\n**Mac**generated $29.98 B in revenue, representing 7.67% of its total revenue.\n**Service**generated $96.17 B in revenue, representing 24.59% of its total revenue.\n**Wearables, Home and Accessories**generated $37.01 B in revenue, representing 9.46% of its total revenue.\n...\nIn fiscal year 2025, Apple's revenue by segment is as follows:\n**iPad**generated $28.02 B in revenue, representing 6.73% of its total revenue.\n**iPhone**generated $209.59 B in revenue, representing 50.36% of its total revenue.\n**Mac**generated $33.71 B in revenue, representing 8.1% of its total revenue.\n**Service**generated $109.16 B in revenue, representing 26.23% of its total revenue.\n**Wearables, Home and Accessories**generated $35.69 B in revenue, representing 8.58% of its total revenue.\nThe\n**biggest segment**for Apple is the iPhone, which represents 50.36% of its total revenue.\nThe\n**smallest segment**for Apple is the iPad, which represents 6.73% of its total revenue.\n...\nIn fiscal year 2025, the iPhone generated the most revenue ($209.59 B), and the iPad generated the least revenue ($28.02 B).\n## Apple's Revenue Growth Drivers\nThe above chart shows growth drivers and a year-over-year comparison of different segments' revenue.\n**iPad**revenue increased 4.98% ($1.33 B) from $26.69 B (in 2024) to $28.02 B (in 2025).\n**iPhone**revenue increased 4.18% ($8.40 B) from $201.18 B (in 2024) to $209.59 B (in 2025).\n**Mac**revenue increased 12.42% ($3.72 B) from $29.98 B (in 2024) to $33.71 B (in 2025).\n**Service**revenue increased 13.51% ($12.99 B) from $96.17 B (in 2024) to $109.16 B (in 2025).\n**Wearables, Home and Accessories**revenue decreased -3.56% ($1.32 B) from $37.01 B (in 2024) to $35.69 B (in 2025).",
        "title": "Apple Revenue Breakdown By Segment | Bullfincher",
        "url": "http://bullfincher.io/companies/apple/revenue-by-segment",
        "date": "2025-01-01",
        "last_updated": "2026-04-30"
      },
      {
        "snippet": "This brings the company's revenue in the last twelve months to $451.44B, up 12.76% year-over-year.\nIn the fiscal year ending September 27, 2025, Apple had annual revenue of $416.16B with 6.43% growth.",
        "title": "Apple (AAPL) Revenue 2005-2026 - Stock Analysis",
        "url": "https://stockanalysis.com/stocks/aapl/revenue/",
        "date": "2005-09-29",
        "last_updated": "2026-05-26"
      },
      {
        "snippet": "## Revenue in 2026 (TTM): $451.44 Billion USD\nAccording to **Apple**'s latest financial reports the company's current revenue (TTM ) is **$451.44 Billion USD**.\nIn 2025 the company made a revenue of **$435.61 Billion USD** an increase over the revenue in the year 2024 that were of **$395.76 Billion USD**.",
        "title": "Apple (AAPL) - Revenue - Companies Market Cap",
        "url": "https://companiesmarketcap.com/apple/revenue/",
        "date": null,
        "last_updated": "2026-05-26"
      },
      {
        "snippet": "## History\n|Date|iPhone|Services|Wearables, Home and Accessories|iPad|Mac|\n|--|--|--|--|--|--|\n|Dec 31, 2025|225.72B|112.83B|35.43B|28.53B|33.11B|\n|Sep 30, 2025|209.59B|109.16B|35.69B|28.02B|33.71B|",
        "title": "Apple (AAPL) Revenue by Segment",
        "url": "https://stockanalysis.com/stocks/aapl/metrics/revenue-by-segment/",
        "date": "2021-03-31",
        "last_updated": "2026-03-11"
      },
      {
        "snippet": "Apple’s iPhone sales accounted for around 55 percent of the company’s overall revenue in the first quarter of fiscal year 2025, the largest share of all Apple products.\nOver the years, services as well as wearables, home and accessories have made a growing contribution to Apple’s net sales.\n...\nIn the first quarter of financial year 2025, Apple’s global revenue reached around 124 billion U.S. dollars.\nThe Americas are Apple’s largest regional market and contributed to around 42 percent of the firm’s sales in that quarter.",
        "title": "Apple sales revenue share by product 2012-2025 | Statista",
        "url": "https://www.statista.com/statistics/382260/segments-share-revenue-of-apple/",
        "date": "2025-02-20",
        "last_updated": "2025-02-26"
      },
      {
        "snippet": "The Company posted quarterly revenue of $94.0 billion, up 10 percent year over year, and quarterly diluted earnings per share of $1.57, up 12 percent year over year.\n“Today Apple is proud to report a June quarter revenue record with double-digit growth in iPhone, Mac and Services and growth around the world, in every geographic segment,” said Tim Cook, Apple’s CEO.",
        "title": "Apple reports third quarter results",
        "url": "https://www.apple.com/newsroom/2025/07/apple-reports-third-quarter-results/",
        "date": "2025-07-31",
        "last_updated": "2026-03-29"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

### Single-Company Historical Lookups

Use this for a single company's historical figures or basic questions that benefit from both structured finance data and web context. GPT-5.5 is strong at simple web search and token-efficient for historical lookups.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="What was Microsoft's total revenue in its most recently completed fiscal year, and how did it compare with the prior fiscal year according to Microsoft's annual report?",
      tools=[
          {"type": "web_search"},
          {"type": "finance_search"},
          {"type": "fetch_url"}
      ],
      max_steps=5,
      max_output_tokens=2048,
      reasoning={"effort": "low"}
  )

  for item in response.output:
      if item.type == "message":
          print(item.content[0].text)
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.perplexity.ai/v1/agent" \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    --data @- <<'JSON'
  {
      "model": "openai/gpt-5.6-sol",
      "input": "What was Microsoft's revenue in its most recently completed fiscal year and the prior fiscal year, according to Microsoft's 10-K?",
      "tools": [
        {"type": "web_search"},
        {"type": "finance_search"},
        {"type": "fetch_url"}
      ],
      "max_steps": 5,
      "max_output_tokens": 2048,
      "reasoning": {"effort": "low"}
  }
  JSON
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_1be7ab7e-0dda-4949-9578-1462f9557a6b",
    "object": "response",
    "model": "openai/gpt-5.6-sol",
    "status": "completed",
    "created_at": 1777645563,
    "completed_at": 1777645563,
    "output": [
      {
        "type": "finance_results",
        "categories": ["financials"],
        "tickers": ["MSFT"],
        "results": [
          {
            "category": "financials",
            "tickers": ["MSFT"],
            "content": "## MSFT FY 2024\n| date | period | income_statement_total_revenues |\n| --- | --- | --- |\n| 2024-06-30 | 2024 FY | 245,122,000,000 |",
            "sources": [
              "https://www.perplexity.ai/finance/MSFT/financials?period=annual&category=INCOME_STATEMENT&fromYear=2024&toYear=2024"
            ]
          }
        ]
      },
      {
        "type": "finance_results",
        "categories": ["financials"],
        "tickers": ["MSFT"],
        "results": [
          {
            "category": "financials",
            "tickers": ["MSFT"],
            "content": "## MSFT FY 2025\n| date | period | income_statement_total_revenues |\n| --- | --- | --- |\n| 2025-06-30 | 2025 FY | 281,724,000,000 |",
            "sources": [
              "https://www.perplexity.ai/finance/MSFT/financials?period=annual&category=INCOME_STATEMENT&fromYear=2025&toYear=2025"
            ]
          }
        ]
      },
      {
        "type": "message",
        "id": "msg_99ccfbfd-bce8-4b9b-b412-b01ef45c7842",
        "role": "assistant",
        "status": "completed",
        "content": [
          {
            "type": "output_text",
            "text": "Microsoft's revenue in its last completed fiscal year, **FY2025 ended June 30, 2025**, was **$281.724 billion**.\n\nCompared with the prior year, **FY2024 revenue was $245.122 billion**, so Microsoft revenue increased by:\n\n- **$36.602 billion**\n- **About 14.9% year over year**",
            "annotations": [],
            "logprobs": []
          }
        ]
      }
    ],
    "tools": [
      {"type": "web_search"},
      {"type": "fetch_url"},
      {"type": "finance_search"}
    ],
    "max_output_tokens": 8192,
    "tool_choice": "auto",
    "parallel_tool_calls": true,
    "usage": {
      "input_tokens": 12522,
      "input_tokens_details": {
        "cached_tokens": 3840,
        "cache_read_input_tokens": 3840
      },
      "output_tokens": 500,
      "total_tokens": 13022,
      "cost": {
        "currency": "USD",
        "input_cost": 0.04341,
        "cache_read_cost": 0.00192,
        "output_cost": 0.015,
        "tool_calls_cost": 0.01,
        "total_cost": 0.07033
      },
      "tool_calls_details": {
        "finance_search": {
          "invocation": 2
        }
      }
    }
  }
  ```
</Accordion>

### Multi-Step Financial Research

Use this for cross-company comparisons, longer historical investigations, and analysis that needs several tool calls across financial statements, filings, transcripts, and web sources. Opus performs best on complex multi-step reasoning when paired with the full tool suite.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="anthropic/claude-opus-4-7",
      input="Compare Apple, Microsoft, and Alphabet on revenue growth and operating margin trends over the last three fiscal years using their 10-K filings.",
      tools=[
          {"type": "web_search"},
          {"type": "finance_search"},
          {"type": "fetch_url"}
      ],
      max_steps=10,
      max_output_tokens=4096
  )

  for item in response.output:
      if item.type == "message":
          print(item.content[0].text)
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.perplexity.ai/v1/agent" \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "anthropic/claude-opus-4-7",
      "input": "Compare Apple, Microsoft, and Alphabet on revenue growth and operating margin trends over the last three fiscal years using their 10-K filings.",
      "tools": [
        {"type": "web_search"},
        {"type": "finance_search"},
        {"type": "fetch_url"}
      ],
      "max_steps": 10,
      "max_output_tokens": 4096
    }'
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "fd226107-fb5a-4f0d-a9da-0db62b67ec60",
    "results": [
      {
        "snippet": "",
        "title": "Microsoft Annual Report 2025",
        "url": "https://www.microsoft.com/investor/reports/ar25/index.html",
        "date": "2020-06-30",
        "last_updated": "2026-05-18"
      },
      {
        "snippet": "",
        "title": "10-K - SEC.gov",
        "url": "https://www.sec.gov/Archives/edgar/data/789019/000095017024087843/msft-20240630.htm",
        "date": "2009-05-15",
        "last_updated": "2025-07-11"
      },
      {
        "snippet": "",
        "title": "Investor Relations - Apple",
        "url": "https://investor.apple.com/investor-relations/default.aspx",
        "date": null,
        "last_updated": "2026-04-17"
      },
      {
        "snippet": "| | |Sep 27, 2025|Sep 28, 2024|Sep 30, 2023|Sep 24, 2022|Sep 25, 2021|Sep 26, 2020|\n...\n| |Return on Sales|Return on Sales|Return on Sales|Return on Sales|Return on Sales|Return on Sales|Return on Sales|\n| |Gross profit margin|46.91%|46.21%|44.13%|43.31%|41.78%|38.23%|\n| |Operating profit margin|31.97%|31.51%|29.82%|30.29%|29.78%|24.15%|\n| |Net profit margin|26.92%|23.97%|25.31%|25.31%|25.88%|20.91%|\n...\n- **Gross Profit Margin**\nThe gross profit margin has shown a consistent upward trend over the observed periods.\nStarting at 38.23% in 2020, it increased steadily each year, reaching 46.91% by 2025.\nThis progression indicates an improving efficiency in production or a favorable pricing strategy, resulting in higher profitability at the gross level.\n- **Operating Profit Margin**\nThe operating profit margin has generally improved from 24.15% in 2020 to 31.97% in 2025.\nThere was a notable increase through 2021 and 2022, followed by a slight dip in 2023, and then a recovery and growth in the subsequent years.\nThis pattern suggests effective cost management and operational efficiency enhancements, despite minor fluctuations.\n- **Net Profit Margin**\nThe net profit margin experienced growth from 20.91% in 2020 to a peak of 25.88% in 2021.\nIt stabilized around that level in 2022 and 2023, then dipped slightly to 23.97% in 2024 before rising again to 26.92% in 2025.\nThis indicates overall strong profitability, though fluctuations may reflect changes in non-operating expenses, taxes, or other factors affecting net income.\n...\nBased on: 10-K (reporting date: 2025-09-27), 10-K (reporting date: 2024-09-28), 10-K (reporting date: 2023-09-30), 10-K (reporting date: 2022-09-24), 10-K (reporting date: 2021-09-25), 10-K (reporting date: 2020-09-26).\n...\n- **Net Sales**\nNet sales demonstrated a consistent upward trend over the analyzed periods, increasing from 274.5 billion US dollars in 2020 to 416.2 billion US dollars in 2025.\nAlthough there was a slight decline observed in 2023 compared to 2022, the overall trajectory remained positive, indicating growth in revenue generation.\n- **Gross Margin**\nGross margin values rose steadily from 104.96 billion US dollars in 2020 to 195.2 billion US dollars projected for 2025.\nThe upward movement in gross margin generally coincides with the increase in net sales, reflecting enhanced profitability at the gross level.\n- **Gross Profit Margin Percentage**\nThe gross profit margin percentage showed consistent improvement across the periods, increasing from 38.23% in 2020 to an estimated 46.91% in 2025.\nThis suggests that the company has improved its operational efficiency or pricing power, enabling it to retain a higher portion of sales revenue as gross profit.\n- **Analysis Summary**\nOverall, the data indicate robust growth in sales accompanied by an expanding gross margin both in absolute terms and as a percentage of sales.\nThe improvement in gross profit margin percentage highlights potentially improved cost control or favorable product mix effects.\nThe slight dip in sales noted for one year did not disrupt the general positive trend.\nThe financial metrics suggest strengthening profitability and efficiency over the observed periods.\n...\n- **Net Sales**\nThere is a consistent upward trend in net sales over the observed periods.\nStarting from 274,515 million USD in 2020, net sales increased significantly to 365,817 million USD in 2021, followed by steady growth reaching 416,161 million USD in 2025.\nThis indicates strong revenue growth and expanding market presence or product demand over the years.\n...\nOperating income has shown an overall increase from 66,288 million USD in 2020 to 133,050 million USD in 2025.\nThere was a substantial increase between 2020 and 2021, more than doubling from the previous year.\nAlthough there was a slight decline between 2022 and 2023, operating income resumed an increasing pattern thereafter.\n...\n- **Operating Profit Margin**\nThe operating profit margin has exhibited improvement throughout the period.\nBeginning at 24.15% in 2020, it rose sharply to nearly 30% in 2021 and maintained levels above 29% in subsequent years.\nBy 2025, it reached approximately 32%, indicating enhanced efficiency in managing operating expenses relative to sales and stronger profit generation capabilities.\n- **Overall Analysis**\nThe financial data demonstrates robust growth in revenue and profitability over the six-year period.\nThe rise in net sales, combined with increasing operating income and improving operating profit margin, reflects a positive operational performance.\nAlthough a minor dip in operating income occurred in 2023, the overall trajectory points to effective cost management and a solid business model that supports sustained profit growth.\n...\n- **Net Income**\nThe net income exhibits an overall upward trend over the analyzed periods, starting at 57,411 million USD in 2020 and reaching 112,010 million USD by 2025.\nThere was a significant increase from 2020 to 2021, followed by more moderate growth through 2022.\nA slight decline is observed in 2023 and 2024, yet the figure rebounds strongly in 2025, reflecting improved profitability or operational efficiency in the latest period.\n- **Net Sales**\nNet sales have shown consistent growth across the years, increasing from 274,515 million USD in 2020 to 416,161 million USD in 2025.\nThe growth pace was markedly strong between 2020 and 2022, followed by a minor decline in 2023.\nSales recovered in 2024 and continued to rise in 2025, indicating resilient demand and market expansion despite some fluctuations.\n- **Net Profit Margin**\nThe net profit margin has remained relatively stable with some variations.\nIt increased sharply from 20.91% in 2020 to 25.88% in 2021, stayed around 25.3% in 2022 and 2023, then decreased slightly to 23.97% in 2024.",
        "title": "Apple Inc. (NASDAQ:AAPL) | Analysis of Profitability Ratios",
        "url": "https://www.stock-analysis-on.net/NASDAQ/Company/Apple-Inc/Ratios/Profitability",
        "date": "2025-09-27",
        "last_updated": "2026-05-25"
      },
      {
        "snippet": "In the fiscal year 2024, Alphabet's revenue was 348.16 billion U.S. dollars.\nComparatively, in the fiscal year of 2023, hardware-focused Apple's 383.29 billion U.S. dollar revenue was almost double the amount of Microsoft's 211.92 billion U.S. dollars.",
        "title": "Google revenue comparison Apple Microsoft 2024 | Statista",
        "url": "https://www.statista.com/statistics/234529/comparison-of-apple-and-google-revenues/",
        "date": "2025-02-05",
        "last_updated": "2025-04-02"
      },
      {
        "snippet": "",
        "title": "aapl-20230930 - SEC.gov",
        "url": "https://www.sec.gov/Archives/edgar/data/320193/000032019323000106/aapl-20230930.htm",
        "date": "2023-09-30",
        "last_updated": "2026-02-24"
      },
      {
        "snippet": "Nvidia printed a 17x EPS increase across two fiscal years.\nMeta's efficiency reset nearly tripled earnings.\nAmazon turned a year of net losses into $5.53 EPS.\nMeanwhile Apple ground out 5% total EPS growth across the same stretch.\n...\nNote: Nvidia's fiscal year ends in January.\nFY2023 = Feb 2022–Jan 2023; FY2024 = Feb 2023–Jan 2024; FY2025 = Feb 2024–Jan 2025.\nAll others are calendar year.\n|Company|EPS 2022|EPS 2023|EPS 2024|2-Yr Change|\n|--|--|--|--|--|\n|NVDANvidia|$1.74*|$12.96*|$29.76*|+17.1x|\n|METAMeta|$8.59|$14.87|$23.86|+2.8x|\n|AMZNAmazon|–$0.27|$2.90|$5.53|Flipped|\n|GOOGLAlphabet|$4.56|$5.80|$8.04|+76%|\n|MSFTMicrosoft|$9.65|$11.45|$12.41|+29%|\n|AAPLApple|$6.11|$6.13|$6.42|+5%|\n*Nvidia fiscal year.\nFY2023 ends Jan 2023; FY2024 ends Jan 2024; FY2025 ends Jan 2025.\nSources: SEC 10-K filings, Bloomberg.\n## Revenue Growth: Who Is Actually Getting Bigger\n|Company|Revenue 2022|Revenue 2024|2-Yr Growth|\n|--|--|--|--|\n|NVDA|$26.9B*|$130.5B*|+385%|\n|AMZN|$514B|$638B|+24%|\n|MSFT|$198B|$245B|+24%|\n|GOOGL|$282B|$350B|+24%|\n|META|$116B|$164B|+41%|\n|AAPL|$394B|$391B|–1%|\n*Nvidia FY2023 (ends Jan 2023) and FY2025 (ends Jan 2025).\nApple revenue declined slightly due to China headwinds and iPhone mix.\n...\nMeta\nYear of Efficiency: headcount cut from 87K to 67K in 2023, then held flat while revenue accelerated.\nAI-driven ad targeting lifted CPMs.\nOperating margins expanded from 20% to 41%.\nAmazon\nAWS margin expansion drove the swing from loss to $5.53 EPS.\nAWS operating income grew from $22.8B in 2022 to $39.8B in 2024.\n...\nMicrosoft\nAzure AI revenue integration (Copilot, OpenAI partnership) added ~$4B in incremental revenue by 2024.\nSteady compounding on cloud re-signed contracts.\nEPS grew reliably but without a step-change.\nAlphabet\n2022 was an advertising recession year.\nThe 2023–2024 recovery combined with YouTube growth and Google Cloud crossing $11B quarterly revenue drove EPS nearly doubling from the 2022 trough.\nApple\nChina revenue headwinds, iPhone ASP plateauing, and lack of a generative AI hardware catalyst kept growth muted.\nServices grew to 24% of revenue but couldn&apos;t offset hardware stagnation.\n...\nEPS can be gamed with buybacks.\nOperating margin expansion is harder to fake — it reflects real structural improvement.\nMETAMeta operating margin\nEfficiency reset + AI ad targeting\n20% (2022)→41% (2024)\nNVDANvidia gross margin\nAI GPU premium pricing power\n56% (FY2023)→75%+ (FY2025)\nAMZNAmazon operating margin\nAWS mix shift + fulfillment restructuring\n2% (2022)→10% (2024)\nMSFTMicrosoft operating margin\nSteady; Copilot uplift still building\n42% (FY2022)→44% (FY2024)\nGOOGLAlphabet operating margin\nAd market recovery + cloud scale benefits\n26% (2022)→32% (2024)\nAAPLApple operating margin\nServices mix improving but hardware drag remains\n30% (FY2022)→31% (FY2024)\n...\n*Data sourced from SEC 10-K filings and Bloomberg consensus.\nNvidia fiscal years noted separately.\nOriginally published in the Trace Cohen newsletter.*",
        "title": "AAPL MSFT GOOGL AMZN NVDA META: EPS & Revenue Growth ...",
        "url": "https://valueaddvc.com/blog/apple-google-microsoft-meta-amazon-nvidia-comparing-eps-and-revenue-growth",
        "date": "2026-05-08",
        "last_updated": "2026-05-19"
      },
      {
        "snippet": "",
        "title": "[PDF] Orbis Corporates Research - Moody's",
        "url": "https://www.moodys.com/web/en/us/insights/resources/us-tech-firm-10-year-analysis-orbis-research.pdf",
        "date": null,
        "last_updated": "2026-04-23"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

## Parameters

| Parameter | Type   | Required | Description                 |
| --------- | ------ | -------- | --------------------------- |
| `type`    | string | Yes      | Must be `"finance_search"`. |

## Response Shape

When `finance_search` runs, the response can include `finance_results` output items before the final assistant message. Each `finance_results` item includes the requested finance categories, ticker symbols, structured content, and source URLs when available. The final `usage` object includes token counts, cost details, and `tool_calls_details.finance_search.invocation` when tool-call usage is reported.

```json theme={null}
{
  "output": [
    {
      "type": "finance_results",
      "categories": ["quote"],
      "tickers": ["NVDA"],
      "results": [
        {
          "category": "quote",
          "tickers": ["NVDA"],
          "content": "Structured quote data returned by the finance search tool.",
          "sources": [
            "https://www.perplexity.ai/finance/NVDA"
          ]
        }
      ]
    },
    {
      "type": "message",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "The answer generated from finance data."
        }
      ]
    }
  ],
  "usage": {
    "tool_calls_details": {
      "finance_search": {
        "invocation": 1
      }
    }
  }
}
```

## Pricing

`finance_search` is billed at **\$5 per 1,000 invocations**. Model token usage is billed separately according to Agent API token pricing.

<Note>
  Pricing follows the same pattern as other tool calls: pay for invocations plus model tokens. See [Pricing](/docs/getting-started/pricing).
</Note>

## Limits / Quotas

`finance_search` uses the same Agent API request flow as other tools. Limits depend on your account tier, request configuration, and the number of tool invocations needed to answer the prompt. See [Rate Limits & Usage Tiers](/docs/admin/rate-limits-usage-tiers#agent-api-rate-limits) for tier-based request limits.

| Limit area           | What to expect                                                                                                                                                   |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **API rate limits**  | Agent API rate limits apply to requests that use `finance_search`.                                                                                               |
| **Tool invocations** | Each time the model calls `finance_search`, it counts as one billable tool invocation. Multi-company or multi-step prompts may require more than one invocation. |
| **Step limits**      | Use `max_steps` to cap multi-step requests that combine `finance_search` with tools such as `web_search` and `fetch_url`.                                        |
| **Output limits**    | Large comparisons, long transcripts, and multi-year financial tables can hit `max_output_tokens` or response truncation settings.                                |
| **Coverage limits**  | Some symbols, exchanges, regions, asset classes, or fields may be unavailable depending on source coverage and data freshness.                                   |

## Next Steps

<CardGroup>
  <Card title="Web Search" icon="world-search" href="/docs/agent-api/tools/web-search">
    Search the web for source-grounded context.
  </Card>

  <Card title="Fetch URL Content" icon="file-text" href="/docs/agent-api/tools/fetch-url-content">
    Fetch full content from known URLs.
  </Card>

  <Card title="People Search" icon="users" href="/docs/agent-api/tools/people-search">
    Search for professionals and employees.
  </Card>

  <Card title="Agent API Quickstart" icon="rocket" href="/docs/agent-api/quickstart">
    Get started with the Agent API.
  </Card>
</CardGroup>


# MCP
Source: https://docs.perplexity.ai/docs/agent-api/tools/mcp

Connect a remote Model Context Protocol (MCP) server to an Agent API request so the model can call your server's tools.

## Overview

Beyond the `function` tools you define yourself, you can give a model new capabilities by connecting it to a remote [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server. The model calls that server's tools to reach and control external services when it needs them to answer a prompt.

The `mcp` tool connects a user-supplied remote MCP server to an Agent API request. Agent API discovers the server's tools when the request starts and calls them like native tools during the run, so you don't have to write a custom `function` tool for each one.

The example below connects to the public [DeepWiki](https://deepwiki.com) MCP server, which needs no authentication, and asks the model to answer a question about a GitHub repository using the server's tools.

<Tip>
  For a fuller, runnable example that combines an MCP server with the model's own web search, see the [Model Picker](/docs/cookbook/examples/model-picker/README) cookbook recipe.
</Tip>

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Ask DeepWiki which Python versions the perplexityai/perplexity-py repository supports.",
      tools=[
          {
              "type": "mcp",
              "server_label": "deepwiki",
              "server_url": "https://mcp.deepwiki.com/mcp",
          }
      ],
  )

  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-sol',
    input: 'Ask DeepWiki which Python versions the perplexityai/perplexity-py repository supports.',
    tools: [
      {
        type: 'mcp',
        server_label: 'deepwiki',
        server_url: 'https://mcp.deepwiki.com/mcp',
      },
    ],
  });

  console.log(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 '{
      "model": "openai/gpt-5.6-sol",
      "input": "Ask DeepWiki which Python versions the perplexityai/perplexity-py repository supports.",
      "tools": [
        {
          "type": "mcp",
          "server_label": "deepwiki",
          "server_url": "https://mcp.deepwiki.com/mcp"
        }
      ]
    }' | jq
  ```
</CodeGroup>

The sample below shows only the response's `output` array, with long MCP tool outputs truncated.

<Accordion title="Response">
  ```json theme={null}
  [
    {
      "type": "mcp_list_tools",
      "id": "mcpl_b6875670-9dd5-46e0-9616-2f15e35bc0d1",
      "server_label": "deepwiki",
      "tools": [
        {
          "name": "ask_question",
          "description": "Ask any question about a GitHub repository and get an AI-powered, context-grounded response.",
          "input_schema": {
            "type": "object",
            "properties": {
              "repoName": {
                "description": "GitHub repository or list of repositories (max 10) in owner/repo format.",
                "anyOf": [
                  { "type": "string" },
                  { "type": "array", "items": { "type": "string" } }
                ]
              },
              "question": {
                "type": "string",
                "description": "The question to ask about the repository."
              }
            },
            "required": ["repoName", "question"]
          }
        },
        {
          "name": "read_wiki_contents",
          "description": "View documentation about a GitHub repository.",
          "input_schema": {
            "type": "object",
            "properties": {
              "repoName": {
                "type": "string",
                "description": "GitHub repository in owner/repo format (e.g. \"facebook/react\")."
              }
            },
            "required": ["repoName"]
          }
        },
        {
          "name": "read_wiki_structure",
          "description": "Get a list of documentation topics for a GitHub repository.",
          "input_schema": {
            "type": "object",
            "properties": {
              "repoName": {
                "type": "string",
                "description": "GitHub repository in owner/repo format (e.g. \"facebook/react\")."
              }
            },
            "required": ["repoName"]
          }
        }
      ]
    },
    {
      "type": "mcp_call",
      "id": "call_Ev48gan4OR0rrPQYb8xuSq3r",
      "server_label": "deepwiki",
      "name": "ask_question",
      "arguments": "{\"question\":\"Which Python versions does this repository support? Please cite the repository files or documentation that specify the supported versions, and distinguish package metadata requirements from tested CI versions if applicable.\",\"repoName\":\"perplexityai/perplexity-py\"}",
      "output": "The `perplexity-py` repository supports Python versions 3.9 and higher. This is specified in the `pyproject.toml` file, which indicates a `requires-python` constraint of `>= 3.9`.\n\nThe project metadata also lists classifiers for Python versions 3.9 through 3.14, indicating that these versions are considered compatible... [truncated]",
      "error": null
    },
    {
      "type": "message",
      "id": "msg_b80c49c9-1215-4c0a-94f0-188ecc2b1e22",
      "role": "assistant",
      "status": "completed",
      "content": [
        {
          "type": "output_text",
          "text": "The `perplexityai/perplexity-py` repository supports **Python 3.9 and newer** (`requires-python = \">=3.9\"` in `pyproject.toml`).\n\nIts package classifiers list compatibility with **Python 3.9 through 3.14**. Python 3.8 support was previously dropped. Note that Ruff's `py38` target concerns source-code syntax and does not change the runtime requirement.",
          "annotations": []
        }
      ]
    }
  ]
  ```
</Accordion>

## Defer tool definitions

By default, every MCP tool definition the request exposes enters the model's initial context. Set `defer_loading` to `true` when a server has many tools or large schemas, or when you connect several servers at once. The model can then search the catalog and load only the schemas it needs. The field is per server, so set it on each one you want deferred. Omitting the field, or setting it to `false`, keeps the default eager behavior.

Deferred loading spends extra model turns before the first tool call. Set [`max_steps`](/docs/agent-api/building-agents/define-the-run#customize-the-loop-max-steps) high enough that the model can search the catalog and still call the tools it finds. Otherwise a run can end right after the search and answer without ever calling a tool.

In the example below, none of DeepWiki's three tool definitions start in the model's context. The model searches the catalog, loads only what the search matches, and calls the tool it found.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Ask DeepWiki this exact question: which license does fastapi/fastapi use?",
      max_steps=6,
      tools=[
          {
              "type": "mcp",
              "server_label": "deepwiki",
              "server_url": "https://mcp.deepwiki.com/mcp",
              "defer_loading": True,
          }
      ],
  )

  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-sol',
    input: 'Ask DeepWiki this exact question: which license does fastapi/fastapi use?',
    max_steps: 6,
    tools: [
      {
        type: 'mcp',
        server_label: 'deepwiki',
        server_url: 'https://mcp.deepwiki.com/mcp',
        defer_loading: true,
      },
    ],
  });

  console.log(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 '{
      "model": "openai/gpt-5.6-sol",
      "input": "Ask DeepWiki this exact question: which license does fastapi/fastapi use?",
      "max_steps": 6,
      "tools": [
        {
          "type": "mcp",
          "server_label": "deepwiki",
          "server_url": "https://mcp.deepwiki.com/mcp",
          "defer_loading": true
        }
      ]
    }' | jq
  ```
</CodeGroup>

The sample below shows only the response's `output` array, with long MCP tool outputs truncated.

<Accordion title="Response">
  ```json theme={null}
  [
    {
      "type": "mcp_list_tools",
      "id": "mcpl_737d73ac-416a-4cde-a296-479de85a65d1",
      "server_label": "deepwiki",
      "tools": [
        {
          "name": "ask_question",
          "description": "Ask any question about a GitHub repository and get an AI-powered, context-grounded response.",
          "input_schema": {
            "properties": {
              "question": {
                "description": "The question to ask about the repository.",
                "type": "string"
              },
              "repoName": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  }
                ],
                "description": "GitHub repository or list of repositories (max 10) in owner/repo format."
              }
            },
            "required": [
              "repoName",
              "question"
            ],
            "type": "object"
          }
        },
        {
          "name": "read_wiki_contents",
          "description": "View documentation about a GitHub repository.",
          "input_schema": {
            "properties": {
              "repoName": {
                "description": "GitHub repository in owner/repo format (e.g. \"facebook/react\").",
                "type": "string"
              }
            },
            "required": [
              "repoName"
            ],
            "type": "object"
          }
        },
        {
          "name": "read_wiki_structure",
          "description": "Get a list of documentation topics for a GitHub repository.",
          "input_schema": {
            "properties": {
              "repoName": {
                "description": "GitHub repository in owner/repo format (e.g. \"facebook/react\").",
                "type": "string"
              }
            },
            "required": [
              "repoName"
            ],
            "type": "object"
          }
        }
      ]
    },
    {
      "type": "tool_search_output",
      "id": "tso_call_4ZM8bZTRYO2Cq6ZvY5WBJPvK",
      "call_id": null,
      "status": "completed",
      "execution": "server",
      "arguments": "{\"paths\":[\"deepwiki\"],\"queries\":[\"ask\",\"question\"]}",
      "tools": [
        {
          "type": "namespace",
          "name": "deepwiki",
          "description": "",
          "tools": [
            {
              "type": "function",
              "name": "ask_question",
              "description": "Ask any question about a GitHub repository and get an AI-powered, context-grounded response.",
              "parameters": {
                "properties": {
                  "question": {
                    "description": "The question to ask about the repository.",
                    "type": "string"
                  },
                  "repoName": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "items": {
                          "type": "string"
                        },
                        "type": "array"
                      }
                    ],
                    "description": "GitHub repository or list of repositories (max 10) in owner/repo format."
                  }
                },
                "required": [
                  "repoName",
                  "question"
                ],
                "type": "object"
              }
            }
          ]
        }
      ]
    },
    {
      "type": "mcp_call",
      "id": "call_EDUuJFdKLABQvPUuDl0WeRwK",
      "server_label": "deepwiki",
      "name": "ask_question",
      "arguments": "{\"question\":\"which license does fastapi/fastapi use?\",\"repoName\":\"fastapi/fastapi\"}",
      "output": "The `fastapi/fastapi` project is licensed under the MIT License... [truncated]",
      "error": null
    },
    {
      "type": "message",
      "id": "msg_dc0c8b47-fe82-40db-a6ec-e84ac99d7710",
      "role": "assistant",
      "status": "completed",
      "content": [
        {
          "type": "output_text",
          "text": "DeepWiki says **fastapi/fastapi uses the MIT License**.",
          "annotations": []
        }
      ]
    }
  ]
  ```
</Accordion>

<Tip>
  If an MCP-heavy request approaches or exceeds the model's context window, enable `defer_loading` before shortening the prompt or removing useful tools. This avoids placing every eligible MCP schema in the initial context while keeping those tools available to the model.
</Tip>

Each `tool_search_output` item is one search of the deferred catalog. The search can cover every deferred server or narrow to one, and it returns only the tools it matches — one of DeepWiki's three above. A search can also return no match, and the model can then search again, so a run may hold several of these items. Calls still appear as `mcp_call`. Agent API still discovers each server's tools when the request starts, so deferred loading does not eliminate discovery time or change [discovery failure behavior](#error-handling).

Three small tools is a modest catalog, so the extra search step buys little here. Deferred loading pays off as the catalog grows: more servers, more tools, larger schemas, or a context window you would otherwise exceed.

## Authentication

Unlike the DeepWiki server above, most MCP servers require authentication. The most common scheme is an OAuth access token, which you pass in the `authorization` field of the `mcp` tool:

<CodeGroup>
  ```python Python theme={null}
  import os
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Use GitHub to find open issues about authentication in perplexityai/perplexity-py.",
      tools=[
          {
              "type": "mcp",
              "server_label": "github",
              "server_url": "https://api.githubcopilot.com/mcp/",
              "authorization": os.environ["GITHUB_MCP_TOKEN"],
              "allowed_tools": ["search_repositories", "list_issues", "issue_read"],
          }
      ],
  )

  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-sol',
    input: 'Use GitHub to find open issues about authentication in perplexityai/perplexity-py.',
    tools: [
      {
        type: 'mcp',
        server_label: 'github',
        server_url: 'https://api.githubcopilot.com/mcp/',
        authorization: process.env.GITHUB_MCP_TOKEN,
        allowed_tools: ['search_repositories', 'list_issues', 'issue_read'],
      },
    ],
  });

  console.log(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 '{
      "model": "openai/gpt-5.6-sol",
      "input": "Use GitHub to find open issues about authentication in perplexityai/perplexity-py.",
      "tools": [
        {
          "type": "mcp",
          "server_label": "github",
          "server_url": "https://api.githubcopilot.com/mcp/",
          "authorization": "'"$GITHUB_MCP_TOKEN"'",
          "allowed_tools": ["search_repositories", "list_issues", "issue_read"]
        }
      ]
    }' | jq
  ```
</CodeGroup>

<Info>
  This example uses the [GitHub MCP Server](https://github.com/github/github-mcp-server). Create a [GitHub personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) with access to the repositories you want the model to inspect, and export it as `GITHUB_MCP_TOKEN`.
</Info>

## Parameters

| Parameter       | Type    | Required | Description                                                                                                                                              |
| --------------- | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`          | string  | Yes      | Must be `"mcp"`.                                                                                                                                         |
| `server_label`  | string  | Yes      | Unique per request, matching `^[a-zA-Z0-9_-]{1,64}$`. Namespaces the server's tools.                                                                     |
| `server_url`    | string  | Yes      | HTTPS URL of the remote MCP server. Must be a Streamable HTTP MCP endpoint; the legacy SSE transport is not supported.                                   |
| `authorization` | string  | No       | An access token passed to the remote MCP server for authentication. Provide the raw token value. Never logged or echoed.                                 |
| `headers`       | object  | No       | Extra request headers (string values) sent to the MCP server.                                                                                            |
| `allowed_tools` | array   | No       | Allowlist of tool names to expose to the model. Omit or leave empty to expose all discovered tools.                                                      |
| `defer_loading` | boolean | No       | When `true`, keeps discovered tool definitions out of the initial model context and lets the model load relevant schemas as needed. Defaults to `false`. |

## Response shape

When an `mcp` tool is used, the response `output` array can include two MCP-specific item types alongside the final `message` item:

* `mcp_list_tools` — emitted once per server, listing the tools discovered when the request starts.
* `mcp_call` — emitted for each tool the model invokes on the server.

With `defer_loading: true`, the array can also include `tool_search_output` items when the model searches the deferred catalog. Tool invocations still appear as `mcp_call` items.

### `mcp_list_tools`

| Field          | Type   | Description                                              |
| -------------- | ------ | -------------------------------------------------------- |
| `type`         | string | Always `mcp_list_tools`.                                 |
| `id`           | string | Identifier for this output item.                         |
| `server_label` | string | The `server_label` you supplied for this server.         |
| `tools`        | array  | The tools discovered on the server.                      |
| `error`        | string | Absent when the server's tools were listed successfully. |

Each entry in `tools` has the following fields:

| Field          | Type   | Description                                                               |
| -------------- | ------ | ------------------------------------------------------------------------- |
| `name`         | string | Tool name as exposed by the server.                                       |
| `description`  | string | Tool description from the server.                                         |
| `input_schema` | object | The server's JSON Schema for the tool's input, passed through unmodified. |

### `mcp_call`

| Field          | Type           | Description                                                                                                    |
| -------------- | -------------- | -------------------------------------------------------------------------------------------------------------- |
| `type`         | string         | Always `mcp_call`.                                                                                             |
| `id`           | string         | Identifier for this output item.                                                                               |
| `server_label` | string         | The `server_label` of the server that ran the tool.                                                            |
| `name`         | string         | Name of the tool that was called.                                                                              |
| `arguments`    | string         | JSON-encoded arguments the model passed.                                                                       |
| `output`       | string         | Tool output text. Empty when the call fails.                                                                   |
| `error`        | string \| null | `null` on success. When the call fails, holds the failure string, which is also returned to the model in-band. |

### `tool_search_output`

Emitted only with `defer_loading: true`, once per search the model runs against the deferred catalog.

| Field       | Type           | Description                                                                                                                                     |
| ----------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`      | string         | Always `tool_search_output`.                                                                                                                    |
| `id`        | string         | Identifier for this output item.                                                                                                                |
| `call_id`   | string \| null | Always `null` for hosted catalog searches.                                                                                                      |
| `execution` | string         | Where the search ran. Currently always `server` — tolerate other values.                                                                        |
| `status`    | string         | Search status, for example `completed`.                                                                                                         |
| `arguments` | string         | Opaque search text the model authored, and may be absent. Treat it as unstructured and do not parse it — its shape is not part of the contract. |
| `tools`     | array          | Matching tools, grouped per server. Empty when the search finds nothing.                                                                        |

Each entry in `tools` is a namespace for one server:

| Field         | Type   | Description                                                                                                        |
| ------------- | ------ | ------------------------------------------------------------------------------------------------------------------ |
| `type`        | string | Always `namespace`.                                                                                                |
| `name`        | string | The `server_label` of the server the tools belong to.                                                              |
| `description` | string | Namespace description. Empty for MCP servers.                                                                      |
| `tools`       | array  | Matching tools, each with `type` (`function`), `name`, `description`, and `parameters` (the server's JSON Schema). |

Example response `output` array:

```json theme={null}
[
  {
    "type": "mcp_list_tools",
    "id": "mcpl_01bcb639-715a-4d5e-be5e-712ac7120bb2",
    "server_label": "github",
    "tools": [
      {
        "name": "issue_read",
        "description": "Get information about a specific issue in a GitHub repository.",
        "input_schema": {
          "type": "object",
          "properties": {
            "method": { "type": "string" },
            "owner": { "type": "string" },
            "repo": { "type": "string" },
            "issue_number": { "type": "number" }
          },
          "required": ["method", "owner", "repo", "issue_number"]
        }
      },
      {
        "name": "list_issues",
        "description": "List issues in a GitHub repository.",
        "input_schema": {
          "type": "object",
          "properties": {
            "owner": { "type": "string" },
            "repo": { "type": "string" },
            "state": { "type": "string" }
          },
          "required": ["owner", "repo"]
        }
      },
      {
        "name": "search_repositories",
        "description": "Find GitHub repositories by name, description, readme, topics, or other metadata.",
        "input_schema": {
          "type": "object",
          "properties": { "query": { "type": "string" } },
          "required": ["query"]
        }
      }
    ]
  },
  {
    "type": "mcp_call",
    "id": "call_dQzJLduEASo7JlHfwN0w09xL",
    "server_label": "github",
    "name": "list_issues",
    "arguments": "{\"owner\":\"perplexityai\",\"repo\":\"perplexity-py\",\"state\":\"OPEN\",\"orderBy\":\"CREATED_AT\",\"direction\":\"DESC\"}",
    "output": "{\"issues\":[{\"number\":60,\"title\":\"Feature Bundle Request: Explicit Prompt Caching, Multi-Model Fusion, and Granular API Key Controls\"}, ...]}",
    "error": null
  },
  {
    "type": "message",
    "role": "assistant",
    "content": [
      {
        "type": "output_text",
        "text": "I found one open issue in `perplexityai/perplexity-py` relevant to authentication / access control: #60 — \"Feature Bundle Request: Explicit Prompt Caching, Multi-Model Fusion, and Granular API Key Controls\" — which requests enterprise-grade API key controls (per-key spending limits, model whitelisting, workspace segregation)."
      }
    ]
  }
]
```

## Error handling

| Case                  | What you see                                                                                                                                                                                                                                                                                   |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Discovery failure** | The request fails with `external_connector_error` (HTTP `424 Failed Dependency`) — the server's tools could not be listed, so the run never starts and no `output` array is returned. The error body's `message` names the server, for example `MCP server "github" could not be initialized`. |
| **Tool-call failure** | The matching `mcp_call` item has its `output` empty and an `error` string set. The failure is also returned to the model in-band, so it can recover or explain in its final answer.                                                                                                            |

A discovery failure happens when a server cannot be reached or returns an unusable response as its tools are listed at the start of the run. Because discovery runs before the model, the whole request fails with `external_connector_error` and returns no `output` array.

Tool-call failures during the run do not fail the request. The error is returned to the model in-band on the `mcp_call` item (as above), so the model can recover or explain it in its final answer.

## Risks and safety

The `mcp` tool lets you connect models to external services — a powerful capability that carries risk. Remote MCP servers are third-party services that have not been verified by Perplexity. They can let a model read, send, and receive data, and take actions in the connected service, and each server is subject to its own terms and conditions. Connect only servers you trust.

<Warning>
  Agent API does not support MCP approvals **yet**. Every MCP tool call auto-runs, so only connect MCP servers and expose tools that you trust to run without an approval step.
</Warning>

Use `allowed_tools` to limit which server tools the model can call. For servers with write or admin actions, prefer read-only server modes, read-only tokens, or a small allowlist of read-only tools.

## Limitations

The `mcp` tool is backward-compatible with OpenAI's Responses MCP API. The following OpenAI MCP features are temporarily not supported:

| Feature or field                                       | Behavior                                                                        |
| ------------------------------------------------------ | ------------------------------------------------------------------------------- |
| `require_approval`                                     | Ignored. Every MCP tool call auto-runs.                                         |
| `mcp_approval_request` / `mcp_approval_response`       | Not emitted or accepted. Approval pause/continue flows are not available yet.   |
| `connector_id` and hosted connector catalogs           | Ignored. Only bring-your-own `server_url` is honored.                           |
| Connector OAuth flows                                  | Not supported. Pass credentials to your own remote server with `authorization`. |
| MCP resources, prompts, and sampling                   | Not supported yet; tools are the only supported MCP capability.                 |
| `approval_request_id` and `status` on MCP output items | Not present in the MCP output item shapes.                                      |

## Pricing

MCP tool calls are free — Agent API does not charge a per-invocation fee for calling a remote MCP server. Model token usage is still billed separately according to Agent API token pricing (see [Models](/docs/agent-api/models) for per-model rates), and you operate the remote MCP server, so any cost it incurs is outside Agent API billing.


# Tools overview
Source: https://docs.perplexity.ai/docs/agent-api/tools/overview

The tools an Agent API run can call - Perplexity-hosted built-in tools, remote MCP servers, and your own custom functions - and where to go for each.

Tools are what turn a model into an agent.
On its own a model answers only from what it already knows; tools let it search the live web, fetch a page, run code, or call into your own systems.
You enable tools by listing them in the `tools` array, and within a single request the model runs an agentic loop — it reasons, calls a tool, observes the result, and repeats until it can answer.

## Three kinds of tools

| Kind                                                       | What it is                                              | Where the model runs it                                         |
| ---------------------------------------------------------- | ------------------------------------------------------- | --------------------------------------------------------------- |
| Built-in tools                                             | Perplexity-hosted capabilities, enabled by `type`.      | Inside the loop; Perplexity runs it and returns results inline. |
| [MCP servers](/docs/agent-api/tools/mcp)                   | Your own remote MCP server, connected with `type: mcp`. | Inside the loop; the model calls its tools automatically.       |
| [Custom functions](/docs/agent-api/tools/custom-functions) | Functions you control, declared with a JSON Schema.     | Paused back to you; you run the call and return the result.     |

## Built-in tools

Enable each by its `type`. Every tool has its own reference page for full settings, response shape, and pricing.

| Tool                                                         | `type`           | Use it to                                              |
| ------------------------------------------------------------ | ---------------- | ------------------------------------------------------ |
| [Web Search](/docs/agent-api/tools/web-search)               | `web_search`     | Search the live web, with domain/date/location filters |
| [Sandbox](/docs/agent-api/tools/sandbox)                     | `sandbox`        | Run code in an isolated container                      |
| [Fetch URL Content](/docs/agent-api/tools/fetch-url-content) | `fetch_url`      | Pull and extract content from specific URLs            |
| [Finance Search](/docs/agent-api/tools/finance-search)       | `finance_search` | Retrieve structured financial and market data          |
| [People Search](/docs/agent-api/tools/people-search)         | `people_search`  | Find professionals and people                          |

## Bring your own

<CardGroup>
  <Card title="MCP servers" icon="plug" href="/docs/agent-api/tools/mcp">
    Connect a remote MCP server with `type: mcp` and let the model call its tools automatically.
  </Card>

  <Card title="Custom functions" icon="code" href="/docs/agent-api/tools/custom-functions">
    Declare a `type: function` tool with a JSON Schema and run the call on your side.
  </Card>
</CardGroup>


# People Search
Source: https://docs.perplexity.ai/docs/agent-api/tools/people-search

Search for professionals, employees, and people using People Search in the Agent API

## Overview

The `people_search` tool enables models to find people and retrieve their professional information such as names, job titles, and companies. Use it to power workflows like lead research, recruiting pipelines, or organizational mapping.

Use it when your application needs to:

* Look up a specific person's professional background
* Find employees at a company by role or title
* Identify professionals in a particular field or location
* Research leadership teams or organizational structures

The model decides when to invoke `people_search` based on your prompt and instructions.

## Coverage

People Search can query public professional profiles and related professional context across several dimensions:

| Query by      | Example prompt                                                        |
| ------------- | --------------------------------------------------------------------- |
| **Name**      | "Find Sarah Chen and summarize her current professional role."        |
| **Role**      | "Find chief revenue officers at late-stage AI startups."              |
| **Company**   | "Find product leaders who work at Stripe."                            |
| **Education** | "Find Stanford alumni working in machine learning research."          |
| **Skill**     | "Find professionals with Kubernetes platform engineering experience." |
| **Location**  | "Find fintech compliance leaders in New York."                        |

<Warning>
  **Privacy and acceptable use:** Use People Search only for legitimate professional research workflows. Do not use it for harassment, doxxing, stalking, or unauthorized background screening. You are responsible for complying with applicable privacy, employment, and data protection laws, including GDPR and CCPA where they apply. The API returns publicly available professional information only.
</Warning>

### Query Tips

For the best results, guide the model with specific details in your prompt:

| Approach            | Example prompt                                  |
| ------------------- | ----------------------------------------------- |
| **Name + company**  | "Find John Smith who works at Google"           |
| **Role + company**  | "Who is the Head of Design at Figma?"           |
| **Role + location** | "Find marketing directors in San Francisco"     |
| **Role + field**    | "Find machine learning researchers at Stanford" |

<Info>
  The tool works best for people-related queries — it is not suited for general web search.
</Info>

## Tiered Configurations

The following four tiered configurations span the speed/quality tradeoff for workloads that mix `people_search` with `web_search` and `fetch_url`. Each tier defines a model, reasoning effort, tool selection, per-tool token budgets, and step limits. Use them as starting points and adjust per your latency, depth, and accuracy needs.

| Tier              | Model                           | Reasoning | Tools                                      | Max Steps | Use When                                                                    |
| ----------------- | ------------------------------- | --------- | ------------------------------------------ | --------- | --------------------------------------------------------------------------- |
| **pro**           | `openai/gpt-5-mini`             | medium    | `people_search`, `web_search`, `fetch_url` | 5         | Balanced people/web research with moderate depth                            |
| **deep**          | `google/gemini-3-flash-preview` | high      | `people_search`, `web_search`, `fetch_url` | 10        | Deeper analysis when latency budget is moderate but quality matters         |
| **advanced-deep** | `openai/gpt-5`                  | medium    | `people_search`, `web_search`, `fetch_url` | 10        | High-quality, multi-step research with long context                         |
| **ultra-deep**    | `openai/gpt-5.6-sol`            | high      | `people_search`, `web_search`, `fetch_url` | 50        | Maximum-depth investigations with the largest token budgets and step counts |

<Info>
  The `bigtokens` settings used by pro, deep, and advanced-deep refer to `max_tokens=10000` and `max_tokens_per_page=1000` on the `people_search` and `web_search` tools. The `xltokens` settings used by ultra-deep refer to `max_tokens=20000` and `max_tokens_per_page=2000`.
</Info>

<Warning>
  **ultra-deep heads-up:** `openai/gpt-5.6-sol` with high reasoning and streaming may be flaky upstream. If requests hang, fall back to `medium` reasoning effort or disable streaming.
</Warning>

### pro

Balanced configuration with all three tools enabled and moderate reasoning effort.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()


  def get_output_text(response) -> str:
      return "".join(
          content.text
          for item in response.output or []
          if getattr(item, "type", None) == "message"
          for content in getattr(item, "content", None) or []
          if getattr(content, "type", None) == "output_text"
      )


  response = client.responses.create(
      model="openai/gpt-5-mini",
      reasoning={"effort": "medium"},
      tools=[
          {
              "type": "people_search",
              "max_tokens": 10000,
              "max_tokens_per_page": 1000,
          },
          {
              "type": "web_search",
              "max_tokens": 10000,
              "max_tokens_per_page": 1000,
          },
          {"type": "fetch_url"},
      ],
      max_steps=5,
      input="Who is the current CEO of Notion, and what was their background before joining the company?",
  )

  print(get_output_text(response))
  ```

  ```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-mini',
    reasoning: { effort: 'medium' },
    tools: [
      {
        type: 'people_search',
        max_tokens: 10000,
        max_tokens_per_page: 1000,
      },
      {
        type: 'web_search',
        max_tokens: 10000,
        max_tokens_per_page: 1000,
      },
      { type: 'fetch_url' },
    ],
    max_steps: 5,
    input: 'Who is the current CEO of Notion, and what was their background before joining the company?',
  });

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

  ```bash cURL theme={null}
  curl -X POST "https://api.perplexity.ai/v1/agent" \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5-mini",
      "reasoning": {"effort": "medium"},
      "tools": [
        {
          "type": "people_search",
          "max_tokens": 10000,
          "max_tokens_per_page": 1000
        },
        {
          "type": "web_search",
          "max_tokens": 10000,
          "max_tokens_per_page": 1000
        },
        {"type": "fetch_url"}
      ],
      "max_steps": 5,
      "input": "Who is the current CEO of Notion, and what was their background before joining the company?"
    }'
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "3f87daf1-90d8-421a-9459-45f4ca027591",
    "results": [
      {
        "snippet": "In today’s article, we will meet Ivan Zhao, a visionary entrepreneur, coding genius, and co-founder of Notion, a groundbreaking company now valued at $10 billion.\n...\nIn the early 2010s, Ivan Zhao moved from Canada to the US, looking for a designer role.\nAkshay Kothari, then running his own company, reached out to hire him.\nWhile Ivan ultimately chose a different opportunity, the two stayed in touch, forming a bond that would later prove pivotal.\nIn 2013, Ivan partnered with Simon Last, who was in his early twenties at the time.\nSimon impressed Ivan with his exceptional talent and remarkable portfolio, leading Ivan to hire him as a key collaborator on the Notion project.\n...\nIn the summer of 2018, Ivan, looking for a COO to help scale Notion, offered the position to Akshay Kothari, who was eager to dive back into building something new, and he joined the company as a COO when it was just 8 people strong.\nThis strategic move paid off as Notion’s growth skyrocketed, going from 8 to nearly 500 employees in just 4 years.",
        "title": "The Phenomenal Journey of Ivan Zhao, Notion's Founder - KITRUM",
        "url": "https://kitrum.com/blog/the-phenomenal-journey-of-ivan-zhao-notions-founder/",
        "date": "2025-01-14",
        "last_updated": "2025-07-09"
      },
      {
        "snippet": "Notion Labs, Inc. was created as a startup in San Francisco, California, founded in 2013 by Ivan Zhao, Akshay Kothari, Chris Prucha, Jessica Lam, Simon Last, and Toby Schachman.",
        "title": "Notion (productivity software) - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Notion_(productivity_software)",
        "date": "2018-10-10",
        "last_updated": "2026-05-18"
      },
      {
        "snippet": "",
        "title": "Notion's Founder Deleted 3 Years of Work. Here's Why. - YouTube",
        "url": "https://www.youtube.com/watch?v=hYWMyXMkZmE",
        "date": "2026-03-04",
        "last_updated": "2026-05-26"
      },
      {
        "snippet": "",
        "title": "Notion CEO Ivan Zhao: Augmenting Human Intellect | Sequoia Capital",
        "url": "https://sequoiacap.com/article/notion-spotlight/",
        "date": "2022-10-13",
        "last_updated": "2026-05-09"
      },
      {
        "snippet": "Brett Jurgens is the co-founder and CEO of Notion, the complete home awareness solution, powered by a multi-purpose IoT smart home sensor.\nPrior to founding Notion, Brett co-founded and ran Sway Marketing, which aimed to more effectively connect local area businesses with CU students.\nBrett went on to work as an analyst in the Private Placements Group at Piper Jaffray, where he helped private, growing companies raise growth capital from institutional investors.\nBrett was then hired as the first employee of Denver-based consumer product startup UrgentRx, helping drive business development and operations roles, launch the initial product line, reach $3 million in sales, sell into 20,000 retail locations including Walmart and Walgreens and raise $10 million in capital.\nBrett led Notion through the Techstars accelerator program in 2014, which culminated in a successful crowdfunding campaign on Kickstarter that raised over $200k.\nFrom there, Notion was accepted to and graduated from MetaProp's 2015 accelerator class.\n...\nSince founding Notion in 2013, Brett has led Notion through multiple rounds of fundraising, closing $15.7M to date.\n...\nPrior to closing Notion’s Series A funding, Notion already partnered with 3 of the top 5 insurance companies in the US and one of the largest consumer electronics companies in the world.",
        "title": "Brett Jurgens | CEO - Notion | Forbes Technology Council",
        "url": "https://councils.forbes.com/profile/Brett-Jurgens-CEO-Notion/70c506c7-3b64-4096-9cb1-73ccb2045b44",
        "date": "2020-01-24",
        "last_updated": "2025-03-01"
      },
      {
        "snippet": "",
        "title": "9-Year Hustle to Achieve a Single GoalㅣNotion's Cofounders",
        "url": "https://www.youtube.com/watch?v=FPYl7nIKRbA",
        "date": "2023-02-14",
        "last_updated": "2026-03-20"
      },
      {
        "snippet": "—\n**Ivan Zhao** is the co-founder and CEO of Notion.\nIvan shares the untold story of Notion, from nearly running out of database space during Covid to finding product-market fit after several “lost years,” and the hard-won lessons along the way.\n...\n7. Ivan’s unique journey from a small town in China",
        "title": "Notion's lost years, its near collapse during Covid, staying small to ...",
        "url": "https://www.lennysnewsletter.com/p/inside-notion-ivan-zhao",
        "date": "2025-03-06",
        "last_updated": "2026-05-23"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

### deep

Higher reasoning effort and step count with a generous output budget for fuller multi-source answers.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()


  def get_output_text(response) -> str:
      return "".join(
          content.text
          for item in response.output or []
          if getattr(item, "type", None) == "message"
          for content in getattr(item, "content", None) or []
          if getattr(content, "type", None) == "output_text"
      )


  response = client.responses.create(
      model="google/gemini-3-flash-preview",
      reasoning={"effort": "high"},
      tools=[
          {
              "type": "people_search",
              "max_tokens": 10000,
              "max_tokens_per_page": 1000,
          },
          {
              "type": "web_search",
              "max_tokens": 10000,
              "max_tokens_per_page": 1000,
          },
          {"type": "fetch_url"},
      ],
      max_steps=10,
      max_output_tokens=16000,
      input="Map the executive leadership team at Linear (linear.app) and summarize each leader's prior roles using publicly available sources.",
  )

  print(get_output_text(response))
  ```

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

  const client = new Perplexity();

  const response = await client.responses.create({
    model: 'google/gemini-3-flash-preview',
    reasoning: { effort: 'high' },
    tools: [
      {
        type: 'people_search',
        max_tokens: 10000,
        max_tokens_per_page: 1000,
      },
      {
        type: 'web_search',
        max_tokens: 10000,
        max_tokens_per_page: 1000,
      },
      { type: 'fetch_url' },
    ],
    max_steps: 10,
    max_output_tokens: 16000,
    input: "Map the executive leadership team at Linear (linear.app) and summarize each leader's prior roles using publicly available sources.",
  });

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

  ```bash cURL theme={null}
  curl -X POST "https://api.perplexity.ai/v1/agent" \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "google/gemini-3-flash-preview",
      "reasoning": {"effort": "high"},
      "tools": [
        {
          "type": "people_search",
          "max_tokens": 10000,
          "max_tokens_per_page": 1000
        },
        {
          "type": "web_search",
          "max_tokens": 10000,
          "max_tokens_per_page": 1000
        },
        {"type": "fetch_url"}
      ],
      "max_steps": 10,
      "max_output_tokens": 16000,
      "input": "Map the executive team at a mid-size SaaS company and explain each leader'\''s prior roles."
    }'
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "8d6f6fd4-1bd0-4646-b6c5-a0ac42d8cfc1",
    "results": [
      {
        "snippet": "## Meet the team behind Linear\nWe are designers and engineers.\n...\nWe are a diverse team of individuals, all makers at heart.\nWe’re hiring →\nKarri SaarinenCo-founder, CEO\nJori LalloCo-founder, CPO\nTuomas ArtmanCo-founder, CTO\nCristina CordovaCOO\nNan YuHead of Product\nTom MoorHead of Engineering\nCasey BertenthalHead of Sales\nJamie FinniganHead of Security\n- Tim Qi\n- Matthew Roberts\n- Matthijs Wolting\n- Josh Pyles\n- Nathalie Alex\n- Dominic Wong\n- Meg Wayne\n- Mingjie Jiang\n- Alan Doyle\n- Alex Suevalov\n- Anthony Vidalez\n- Saneel Prabhu\n...\n- Jon Phey",
        "title": "About",
        "url": "https://linear.app/about",
        "date": "2020-12-03",
        "last_updated": "2026-05-19"
      },
      {
        "snippet": "Linear is a software development company founded in 2019 by Karri Saarinen and Tuomas Artman.\n...\nThe Linear leadership team combines deep expertise in software engineering, product management, and operations.\n...\n### Karri Saarinen - CEO, Co-founder\nKarri Saarinen is the CEO and Co-founder of Linear, shaping the company's vision to create a top-tier project and issue tracking platform focused on quality and speed in software development.\n...\nKarri co-founded Linear and has served as CEO since 2019, demonstrating a deep commitment to software craftsmanship and innovation.\n...\n### Jori Lallo - Co-founder\nJori Lallo is a Co-founder of Linear, instrumental in establishing its founding vision and developing the core product.\nHe is pivotal in shaping company culture and guiding product evolution, bringing the Linear management team deep technical and design contributions.\n...\n### Tuomas Artman - CTO, Co-founder\nTuomas Artman is the CTO and Co-founder of Linear, responsible for driving the company’s technology strategy, engineering architecture, and scaling infrastructure.\nTuomas Artman ensures Linear’s performance and reliability, leading teams that deliver scalable features and platform innovation.\nBefore joining the Linear executive team, Tuomas held engineering and management positions at Uber and Groupon, focusing on distributed systems and user-centric product design.\nHe holds a degree from the University of Helsinki and possesses multiple software-related patents, further solidifying the technical leadership within Linear’s management team.\n### Cristina Cordova - COO\nCristina Cordova serves as Chief Operating Officer (COO) at Linear, where she builds and scales marketing, sales, operations, data, and talent teams to support company expansion.\nCristina Cordova drives growth and operational efficiency, leveraging her prior leadership roles at Stripe and Notion.\n...\n### Nan Yu - Head of Product\nNan Yu leads the product organization at Linear, crafting and refining features that drive value for customers and deliver world-class user experiences.\nNan Yu sets product strategy and oversees execution, ensuring alignment with both customer needs and company ambitions.\nNan’s expertise was shaped by previous product leadership positions at Mode, Everlane, and Bank of America.\nShe studied Electrical Engineering and Computer Science at the University of California, Berkeley.\nHer technical background and multidisciplinary approach have been essential in advancing Linear’s product vision within the broader Linear executives team.\n### Casey Bertenthal - Head of Sales\nCasey Bertenthal leads sales at Linear, focusing on revenue growth, customer acquisition, and retention.\nCasey Bertenthal excels at building high-performing sales organizations and developing strategies for engaging new and existing customers.\nCasey brings extensive SaaS sales leadership experience, previously working with companies like Abstract and Wake.\nHe studied Political Science at Northeastern University and has consistently delivered strong sales results, contributing significantly to Linear’s business expansion.",
        "title": "Linear's Executive Team & Leadership | Meet Our Leaders - Exa",
        "url": "https://websets.exa.ai/websets/directory/linear-executives",
        "date": "2026-05-21",
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "Linear has always been a fully remote company.\nToday, our small but mighty team is distributed across North America and Europe.\n...\nWe are all makers at heart and care deeply about the quality of our work, down to the smallest detail.We're hiring Karri SaarinenCo-founder, CEOJori LalloCo-founder, CPOTuomas ArtmanCo-founder, CTOTom MoorHead of EngineeringNan YuHead of ProductCristina CordovaCOOCasey\nBertenthalHead of SalesJamie FinniganHead of SecurityTim QiMatthew RobertsMatthijs WoltingJosh PylesNathalie AlexDom WongMeg WayneMingjie JiangAlan DoyleAlex SuevalovAnthony VidalezSaneel PrabhuIgor SechynAxel NiklassonDavina BakerMufeez\nAmjadTony WoosterBen KinneySimone JacobsZoe WellnerBojan JoveskiYann-Edern GilletPaul MacgregorEmiel JansonDylan HamiltonEitan MeiselsSteven DeMartiniAmelia CellarPaco CourseyKristin BoyerPeter TraversMaciek PekalaSkyline\nLauJesse HartheimerAaron QuinnLena VuRobb BöhnkeJacob ShumwayEmil KowalskiHilary HobelSean McGivernAndreas EldhAllie HughesUros SmolnikErin FreyLauren GrantMariah BardoRomain CascinoMelissa RossMaya\nNedeljković BatićSean CallahanLiam O'ConnorSarah BarnekowAdrien GriveauBrando RocheKatie RoyerBryan SternAlexandra Lapinsky WilsonTyler BlackGavin NelsonLukas EipertDaniel Warner SmithSabin RomanLuke SchneiderHaley ThurstonGrace LemanIsha\nKumarDidier CatzDrew HuppeWarner PriceSid BhargavaJack ManganGino FordianiEma MilojkovicKyle WardIvy MurphyChris MaggioColin DunnMel MierGuglielmo D'AnnaLeela Senthil NathanBrian HenderyAlessandro OddoneConor MuirheadColin RutanJulian LehrAlyssa GarrisonAllison WeiKenneth SkovhusDoug ParkerMarcos FiscalPaul DijouGuillaume Lachaud\n...\nOur backers include highly accomplished venture firms and some of the world’s most exceptional founders and product builders.Miles ClementsPartnerStephanie ZhanPartnerDylan FieldCEO, FigmaPatrick CollisonCEO, StripeStewart ButterfieldFormer CEO, SlackGuillermo RauchCEO, VercelDick CostoloFormer CEO\n, TwitterJosh MillerCEO, Browser CompanyAndrew MasonCEO, DescriptImmad AkhundCEO, MercuryClaire Hughes JohnsonFormer COO, StripeJorn van DijkCEO, FramerChristina CacioppoCEO, VantaJob van der VoortCEO, RemoteIlkka PaananenCEO, SupercellAnthony GuoCTO, RetoolGustaf AlströmerPartner, Y CombinatorAkash GargFormer CTO, Afterpay",
        "title": "About - Linear",
        "url": "https://linear.app/about?_rsc=15b46",
        "date": "2025-12-19",
        "last_updated": "2026-01-18"
      },
      {
        "snippet": "Linear has always been a fully remote company.\nToday, our small but mighty team is distributed across North America and Europe.\n...\nOur backers include highly accomplished venture firms and some of the world’s most exceptional founders and product builders.Miles ClementsPartnerStephanie ZhanPartnerDylan FieldCEO, FigmaPatrick CollisonCEO, StripeStewart ButterfieldFormer CEO, SlackGuillermo RauchCEO, VercelDick CostoloFormer CEO\n, TwitterJosh MillerCEO, Browser CompanyAndrew MasonCEO, DescriptImmad AkhundCEO, MercuryClaire Hughes JohnsonFormer COO, StripeJorn van DijkCEO, FramerChristina CacioppoCEO, VantaJob van der VoortCEO, RemoteIlkka PaananenCEO, SupercellAnthony GuoCTO, RetoolGustaf AlströmerPartner, Y CombinatorAkash GargFormer CTO, Afterpay",
        "title": "About – Linear",
        "url": "https://linear.app/about?_rsc=xl36s",
        "date": "2025-01-01",
        "last_updated": "2025-03-01"
      },
      {
        "snippet": "## Org chart\nKarri Saarinen\nCEO & co-Founder\nCollapse\nCristina Cordova\nCOO\nNan Yu\nHead of Product\n### Board & advisors\nJori Lallo\nCo-Founder\nDylan Field\nInvestor\nGustaf Älströmer\nInvestor\nStephanie Zhan\nBoard Member\nMiles Clements\nInvestor\nJosh Miller\nInvestor\nAndrew Mason\nInvestor\nJorn van Dijk\nInvestor\nImmad Akhund\nInvestor\nJob van der Voort\nInvestor\nPatrick Collison\nInvestor\nIlkka Paananen\nInvestor\nChristina Cacioppo\nInvestor\nGuillermo Rauch\nInvestor\nAnthony Guo\nInvestor\nStewart Butterfield\nInvestor\nDick Costolo\nInvestor\nClaire Hughes Johnson\nInvestor\nAkash Garg\nInvestor\n## Teams",
        "title": "Linear - The Org",
        "url": "https://theorg.com/org/linear",
        "date": "2026-02-07",
        "last_updated": "2026-05-19"
      },
      {
        "snippet": "The Leadership Team at Linear is responsible for setting the strategic vision and direction of the company, driving innovation in software development management, and fostering a culture of efficiency and collaboration.\nThis team, comprised of the co-founders, ensures alignment across all departments, promotes growth initiatives, and reinforces Linear's commitment to empowering high-performing teams.\nNo jobs in this team",
        "title": "Leadership Team - Linear - The Org",
        "url": "https://theorg.com/org/linear/teams/leadership-team",
        "date": "2023-05-25",
        "last_updated": "2025-10-20"
      },
      {
        "snippet": "",
        "title": "The Story of Linear as told by its CTO - The Pragmatic Engineer",
        "url": "https://newsletter.pragmaticengineer.com/p/linear",
        "date": "2022-11-22",
        "last_updated": "2026-05-16"
      },
      {
        "snippet": "## 3 Team Members\nLinear has 3 executives.\nLinear's current Founder, Chief Executive Officer is Karri Saarinen.\n|Name|Work History|Title|Status|\n|--|--|--|--|\n|Karri Saarinen|Airbnb, Coinbase, Kippt, Grey Area, Kisko Labs, Flowdock, ArcticStartup, and Finnish Defence Forces|Founder, Chief Executive Officer|Current|\n...\n|Name|Karri Saarinen|Subscribe to see more|Subscribe to see more|\n|--|--|--|--|\n|Work History|Airbnb, Coinbase, Kippt, Grey Area, Kisko Labs, Flowdock, ArcticStartup, and Finnish Defence Forces|\n|Title|Founder, Chief Executive Officer|Subscribe to see more|Subscribe to see more|\n|Status|Current|Subscribe to see more|Subscribe to see more|",
        "title": "Linear Management Team",
        "url": "https://www.cbinsights.com/company/linear-1/people",
        "date": "2023-09-14",
        "last_updated": "2025-02-13"
      },
      {
        "snippet": "# Welcoming Cristina Cordova to Linear\nKarri Saarinen\nI’m excited to share that Cristina Cordova has joined Linear as Chief Operating Officer to help us shape the company and lead our go-to-market efforts.\n...\nCristina brings a wealth of experience to Linear having previously scaled products and teams at Stripe and Notion.\nAt Notion, Cristina served as the Head of Platform & Partnerships managing the launch of the company’s API and building various business development and product growth teams.\nShe previously spent more than seven years at Stripe, where she led a business unit and built the partnerships team from the ground up.\nShe joined Stripe as one of the first employees and helped to grow the company to nearly 3000 people.\nMost recently, Cristina was a Partner at First Round and an investor and advisor to companies such as Canva, AtoB and Meter (most of which are building with Linear).\n...\nKarri Saarinen",
        "title": "Welcoming Cristina Cordova to Linear",
        "url": "https://linear.app/now/welcoming-cristina-cordova-to-linear",
        "date": "2023-05-23",
        "last_updated": "2026-03-05"
      },
      {
        "snippet": "",
        "title": "Linear Business Breakdown & Founding Story - Contrary Research",
        "url": "https://research.contrary.com/company/linear",
        "date": "2025-05-02",
        "last_updated": "2026-05-21"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

### advanced-deep

A frontier-model configuration for high-quality, multi-step research when latency budget is generous.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()


  def get_output_text(response) -> str:
      return "".join(
          content.text
          for item in response.output or []
          if getattr(item, "type", None) == "message"
          for content in getattr(item, "content", None) or []
          if getattr(content, "type", None) == "output_text"
      )


  response = client.responses.create(
      model="openai/gpt-5",
      reasoning={"effort": "medium"},
      tools=[
          {
              "type": "people_search",
              "max_tokens": 10000,
              "max_tokens_per_page": 1000,
          },
          {
              "type": "web_search",
              "max_tokens": 10000,
              "max_tokens_per_page": 1000,
          },
          {"type": "fetch_url"},
      ],
      max_steps=10,
      input="Identify the current CEO of Notion, Linear, and Figma, and summarize each one's professional background.",
  )

  print(get_output_text(response))
  ```

  ```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',
    reasoning: { effort: 'medium' },
    tools: [
      {
        type: 'people_search',
        max_tokens: 10000,
        max_tokens_per_page: 1000,
      },
      {
        type: 'web_search',
        max_tokens: 10000,
        max_tokens_per_page: 1000,
      },
      { type: 'fetch_url' },
    ],
    max_steps: 10,
    input: 'Identify the current CEO of Notion, Linear, and Figma, and summarize each one\'s professional background.',
  });

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

  ```bash cURL theme={null}
  curl -X POST "https://api.perplexity.ai/v1/agent" \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5",
      "reasoning": {"effort": "medium"},
      "tools": [
        {
          "type": "people_search",
          "max_tokens": 10000,
          "max_tokens_per_page": 1000
        },
        {
          "type": "web_search",
          "max_tokens": 10000,
          "max_tokens_per_page": 1000
        },
        {"type": "fetch_url"}
      ],
      "max_steps": 10,
      "input": "Identify the current CEO of Notion, Linear, and Figma, and summarize each one\u0027s professional background."
    }'
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "5b5af173-6ae5-4cad-bddd-b1f64c4f71aa",
    "results": [
      {
        "snippet": "",
        "title": "Tools for the Future: Your best semester with Notion, Arc and Figma",
        "url": "https://www.youtube.com/watch?v=UuOI99qN9PU",
        "date": "2024-09-28",
        "last_updated": "2026-05-16"
      },
      {
        "snippet": "",
        "title": "The Figma vs. Notion Playbook: Interview Secrets, & Comp Data ...",
        "url": "https://superinterviews.substack.com/p/the-figma-vs-notion-playbook-interview",
        "date": "2025-10-30",
        "last_updated": "2026-05-03"
      },
      {
        "snippet": "And they are doing so in incredibly unique ways:\n1. **No product managers, just a head of product.** PM duties are distributed across engineering and design.\n...\nOne.\nWe hired Nan Yu a little over a year ago when we were about 25 people.\nHe is Head of Product and currently the only one carrying a “PM” title.\nThe reason I phrase it this way is that we have other roles that also contribute to what is traditionally considered part of the PM role.\n...\nSince we don’t have any PMs other than our Head of Product, the project lead is never a PM.\n...\nI, along with my co-founders Jori Lallo and Tuomas Artman and our Head of Product, each lead or sit in each project meeting acting as a sponsor to give feedback and direction as needed.\nOne of us is ultimately responsible for the outcome.\n...\nYes, product, engineering, and design are all part of the product team.\nProduct and design report to me (CEO).\nWe have engineering managers, but engineering ultimately reports up to my co-founders: Tuomas for infrastructure and Europe engineering, and Jori for U.S. engineering.\n...\nOne of the unique aspects to Linear is that we expect the project team to be the PM.",
        "title": "How Linear builds product - Lenny's Newsletter",
        "url": "https://www.lennysnewsletter.com/p/how-linear-builds-product",
        "date": "2023-09-26",
        "last_updated": "2026-05-11"
      },
      {
        "snippet": "",
        "title": "An inside look at how Figma builds product | Yuhki Yamashita (CPO of Figma)",
        "url": "https://www.youtube.com/watch?v=NepFo4zXyK4",
        "date": "2023-01-08",
        "last_updated": "2026-02-08"
      },
      {
        "snippet": "",
        "title": "Make an Org Chart You Want to Ship — Advice from Linear on How ...",
        "url": "https://review.firstround.com/make-an-org-chart-you-want-to-ship-advice-from-linear-on-how-heirloom-tomatoes-should-inspire-team-design/",
        "date": "2024-08-07",
        "last_updated": "2026-05-20"
      },
      {
        "snippet": "",
        "title": "Config 2024: The heirloom tomato org chart (Nan Yu, Head of Product, Linear) | Figma",
        "url": "https://www.youtube.com/watch?v=I4vvBidQcck",
        "date": "2024-06-30",
        "last_updated": "2025-08-23"
      },
      {
        "snippet": "### Open Role\nChief Product Officer\nProduct\n0 reports\n### Open Role\n...\n### Product\n**250** employees\ncpo\nOwns product vision, UX, and roadmap for the Notion workspace.\n...\nstacks up\nCompared with peers like Airtable, Figma (pre-acquisition), and Linear, Notion retains a more centralized founder-led model with AI elevated early.\nAirtable and Asana show more mature GTM and COO layers, while Notion remains closer to a product-centric structure optimized for innovation velocity.\n...\nFunctional leaders across product, engineering, AI research, GTM, finance, people, and security report directly to the CEO.",
        "title": "Notion Labs, Inc. Organizational Structure - Creately",
        "url": "https://creately.com/org-chart/major-startups/notion/",
        "date": "2026-04-01",
        "last_updated": "2026-05-15"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

### ultra-deep

Maximum-depth configuration with the largest token budgets, the highest step count, and `xltokens` per-tool settings. Best for exhaustive investigations.

<Warning>
  `openai/gpt-5.6-sol` with high reasoning and streaming may be flaky upstream. If requests hang, switch to `medium` effort or use a non-streaming call.
</Warning>

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()


  def get_output_text(response) -> str:
      return "".join(
          content.text
          for item in response.output or []
          if getattr(item, "type", None) == "message"
          for content in getattr(item, "content", None) or []
          if getattr(content, "type", None) == "output_text"
      )


  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      reasoning={"effort": "high"},
      tools=[
          {
              "type": "people_search",
              "max_tokens": 20000,
              "max_tokens_per_page": 2000,
          },
          {
              "type": "web_search",
              "max_tokens": 20000,
              "max_tokens_per_page": 2000,
          },
          {"type": "fetch_url"},
      ],
      max_steps=50,
      max_output_tokens=32000,
      input="Build a complete leadership map of Anthropic, including the executive team and direct reports to each VP, with prior employment history.",
  )

  print(get_output_text(response))
  ```

  ```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-sol',
    reasoning: { effort: 'high' },
    tools: [
      {
        type: 'people_search',
        max_tokens: 20000,
        max_tokens_per_page: 2000,
      },
      {
        type: 'web_search',
        max_tokens: 20000,
        max_tokens_per_page: 2000,
      },
      { type: 'fetch_url' },
    ],
    max_steps: 50,
    max_output_tokens: 32000,
    input: 'Build a complete leadership map of Anthropic, including the executive team and direct reports to each VP, with prior employment history.',
  });

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

  ```bash cURL theme={null}
  curl -X POST "https://api.perplexity.ai/v1/agent" \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "reasoning": {"effort": "high"},
      "tools": [
        {
          "type": "people_search",
          "max_tokens": 20000,
          "max_tokens_per_page": 2000
        },
        {
          "type": "web_search",
          "max_tokens": 20000,
          "max_tokens_per_page": 2000
        },
        {"type": "fetch_url"}
      ],
      "max_steps": 50,
      "max_output_tokens": 32000,
      "input": "Build a complete leadership map of Anthropic, including the executive team and direct reports to each VP, with prior employment history."
    }'
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "276b823b-9651-4c63-87c3-6be6f3b51a99",
    "results": [
      {
        "snippet": "",
        "title": "List of Anthropic Executives & Org Chart - Clay",
        "url": "https://www.clay.com/dossier/anthropic-executives",
        "date": null,
        "last_updated": "2026-05-20"
      },
      {
        "snippet": "This Org Chart shows 64 people with power at Anthropic, including management, board directors and members of an independent oversight body.\nThe AI company has several OpenAI alumni across various departments, a rival organization that all seven Anthropic co-founders left in 2020.\nDownload CSV\n...\n### Board of DirectorsorDaniela Amodei\nAnthropic\nDario Amodei\nAnthropic\nYasmin Razavi\nSpark Capital\nJay Kreps\nCEO and co-founder, Confluent\nReed Hastings\nNetflix co-founder\nVas Narasimhan\nCEO of Novartis\nChris Liddell\nFormer CFO at Microsoft, White House deputy chief of staff\nJason Matheny\nLong-Term Benefit Trust CEO of the RAND Corporation\nKanika Bahl\nLong-Term Benefit Trust CEO & President of Evidence Action\nNeil Buddy Shah (Chair)\nLong-Term Benefit Trust CEO of the Clinton Health Access Initiative\nPaul Christiano\nLong-Term Benefit Trust Founder of the Alignment Research Center\nZach Robinson\nLong-Term Benefit Trust Interim CEO of Effective Ventures US",
        "title": "Anthropic Org Chart & Company Structure Hierarchy - The Information",
        "url": "https://www.theinformation.com/org-charts/anthropic",
        "date": null,
        "last_updated": "2026-05-16"
      },
      {
        "snippet": "Anthropic is an AI safety and research company that’s working to build reliable, interpretable, and steerable AI systems.\n...\nHeadquarters\nSan Francisco, United States\n...\n## Org chart\nDario Amodei\nCo-Founder & CEO\nCollapse\nDaniela Amodei\nPresident And Co-founder\nMike Krieger\nChief Product Officer\nKrishna Rao\nChief Financial Officer\nHannah Pritchett\nHead Of People\nAndrew H.\nChief Of Staff\nJack Clark\nCo-Founder\nRahul Patil\nCTO\nPaul Smith\nChief Commercial Officer\nJeffrey Bleich\nGeneral Counsel\nMichael Sellitto\nHead Of Global Affairs\nAndrej Karpathy\nPre-training Team\n### Board & advisors\nMatt Murphy\nBoard Observer\nReed Hastings\nBoard Member\n## Teams",
        "title": "Anthropic | The Org",
        "url": "https://theorg.com/org/anthropic",
        "date": "2025-12-06",
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "Anthropic, the company behind the Claude family of A.I. models, has moved with remarkable speed since its founding in 2021.\nIn recent months, its high-velocity growth has been accompanied by a wave of high-profile hires, including Rahul Patil as chief technology officer (joining from Stripe) and Vitaly Gudanets as chief information security officer (joining from Netflix).\n...\nAnthropic was founded by seven former OpenAI employees.\nEstablished as a public benefit corporation, it has since assembled a leadership roster drawn from companies like Netflix, Instagram and Stripe.\n### Here are 11 notable executives leading Anthropic today, along with other key figures:\n### Dario Amodei, CEO & Co-founder\nDario Amodei co-founded Anthropic in February 2021 after serving as a vice president of research at OpenAI.\nBefore that, he worked as a senior research scientist at Google.\nHis work has been central to advancing techniques that use human feedback to train A.I. systems.\nAmodei left OpenAI with six colleagues over disagreements around A.I. safety, a split that ultimately led to Anthropic’s creation.\nIn November 2023, he rejected a proposal for OpenAI and Anthropic to merge, signaling the company’s commitment to an independent research agenda.\n### Daniela Amodei, President & Co-founder\nDaniela Amodei is Dario Amodei’s sister.\nShe was formerly vice president of safety and policy at OpenAI, where she focused on risk mitigation and operational oversight.\nBefore entering the A.I. sector, she transitioned from a path in campaign politics to leadership roles in tech, ultimately joining Stripe as a risk manager.\nAt Anthropic, she oversees core operations, with senior leaders, including CTO Rahul Patil and chief architect Sam McCandlish, reporting directly to her.\n### Mike Krieger, Chief Product Officer\nMike Krieger is one of the two co-founders of Instagram.\nHe served as the platform’s chief technology officer through its explosive growth.\nAfter leaving in 2018, he and the other Instagram co-founder, Kevin Systrom, launched a personalized news app called Artifact in 2021.\nArtifact was sold to Yahoo in April 2024, and Krieger joined Anthropic the following month.\n### Rahul Patil, Chief Technology Officer\nRahul Patil joined Anthropic as chief technology officer in October, stepping into the role previously held by chief architect Sam McCandlish.\nPatil comes from Stripe, where he also served as CTO, and brings deep experience leading engineering teams at companies including Microsoft, AWS and Oracle.\nHe now oversees Anthropic’s full engineering organization and reports directly to Daniela Amodei.\n### Jared Kaplan, Chief Science Officer & Co-founder\nJared Kaplan, a theoretical physicist and professor at Johns Hopkins University, co-founded Anthropic after previously consulting on research at OpenAI.\nHis academic work spans quantum field theory and machine learning, grounding his leadership of Anthropic’s scientific direction.\nKaplan guides the company’s long-term research agenda and oversees foundational model development alongside other senior technical leaders.\n### Jan Leike, Alignment Science Lead\nJan Leike joined Anthropic after serving as co-lead of OpenAI’s superalignment team, where he focused on ensuring advanced A.I. systems remain controllable and aligned with human goals.\nHe now leads Anthropic’s alignment science efforts, reporting to Jared Kaplan.\n...\n### Sam McCandlish, Chief Architect & Co-founder\nSam McCandlish holds a Ph.D. in theoretical physics from Stanford, and his scholarly work has garnered over 100,000 citations.\nHe is one of the seven former OpenAI employees who left to found Anthropic.\nAt Anthropic, McCandlish focuses on model training and large-scale systems development.\nHe previously served as the company’s chief technology officer before transitioning into his current role, reporting to Daniela Amodei.\n### Tom Brown, Chief Compute Officer & Co-founder\nTom Brown co-founded Anthropic after leading the research engineering team behind GPT-3 at OpenAI.\nA self-taught engineer, he played a pivotal role in building the modern era of large-scale compute systems.\nBrown now oversees Anthropic’s compute infrastructure, a task described by Y Combinator as “humanity’s largest infrastructure buildout ever.”\n### Vitaly Gudanets, Chief Information Security Officer\nVitaly Gudanets joined Anthropic as chief information security officer in September.\nHe previously held the same role at Netflix, where he oversaw security strategy during the company’s global expansion.\nIn addition to his position at Anthropic, Gudanets serves as an operating partner at Lightspeed Venture Partners, advising portfolio companies on cybersecurity and organizational resilience.\n### Jack Clark, Head of Policy & Co-founder\nJack Clark co-founded Anthropic after serving as policy director at OpenAI, where he helped shape the organization’s early approach to A.I. governance.\nBefore entering the policy side of the industry, Clark was a technology journalist at outlets including Bloomberg and authored the long-running A.I. newsletter *Import AI*.\nClark leads Anthropic’s global policy efforts and represents the company in international discussions on safety and regulation.\nHe currently serves as an expert for the Global Partnership on AI under the OECD.\n### Krishna Rao, Chief Financial Officer\nKrishna Rao joined Anthropic after holding senior financial and strategy roles across several high-growth companies, including serving as global head of corporate and business development at Airbnb and as CFO at both Fanatics Collectibles and the healthcare payments platform Cedar.\nAt Anthropic, Rao oversees the company’s financial strategy and long-term planning.\n...\n### Anthropic’s current board members and other key figures\n- Dario Amodei\n- Daniela Amodei\n- Yasmin Razavi: General partner at Spark Capital, which led Anthropic’s $450 million Series C in 2023\n- Jay Kreps: CEO of the real-time data streaming company Confluent\n- Reed Hastings: CEO of Netflix\nAnthropic has also established the Long-Term Benefit Trust (LTBT), a separate stockholder-elected board designed to align the company’s governance with its mission of “developing and maintaining advanced A.I. for the long-term benefit of humanity.”\nLTBT members include:\n- Neil Buddy Shah: CEO of the Clinton Health Access Initiative\n- Kanika Bahl: CEO of the evidence-based charity Evidence Action\n- Zach Robinson: CEO of the Centre for Effective Altruism and Effective Ventures Foundation USA.\n- Richard Fontaine: CEO of the Center for a New American Security",
        "title": "11 Executives Driving Anthropic's Meteoric Rise in the A.I. Boom",
        "url": "https://observer.com/2025/11/11-executives-driving-anthropics-meteoric-rise-in-the-a-i-boom/",
        "date": "2025-11-11",
        "last_updated": "2026-04-16"
      },
      {
        "snippet": "",
        "title": "Anthropic - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Anthropic",
        "date": "2006-08-01",
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "Anthropic began restructuring its leadership and organization in early 2026 as it prepares for a potential IPO.\n...\nHeadcount has also surged, with roughly 2,300 employees at the end of last year, more than double its size just months earlier.\n...\nA key part of this restructuring is the creation of Anthropic Labs in January, a research and development unit focused on incubating experimental products at the frontier of Claude’s capabilities.\n...\nThese structural changes are closely tied to a broader leadership reshuffle, including the promotion of former chief product officer Mike Krieger to co-lead Anthropic Labs.\n...\n### Mike Krieger and Ben Mann co-lead Anthropic Labs\nKrieger, Anthropic’s former chief product officer and a co-founder of Instagram, transitioned to co-lead Anthropic Labs at its launch earlier this year.\nAt Instagram, he served as chief technology officer, and later co-founded the news app Artifact, which he sold to Yahoo in 2024.\nA native of Brazil, Krieger is a Stanford University alumnus.\nBen Mann, an Anthropic co-founder, previously helped architect GPT-3 at OpenAI and worked as a software engineer at Google.\nBefore moving to Labs, he served as Anthropic’s lead product engineer, focusing on A.I. alignment and harm mitigation.\nMann graduated from Columbia University.\nAt Anthropic Labs, Krieger and Mann oversee a range of high-stakes initiatives, including the controlled rollout and governance of Claude Mythos, the company’s most advanced model.\n...\n### Ami Vora replaces Mike Krieger as CPO\nFollowing Krieger’s move to Anthropic Labs, Ami Vora has taken on the role of chief product officer.\nShe joined the company in December 2025 as head of product and was quickly promoted.\nVora previously spent 15 years at Meta, where she held leadership roles, including vice president of product at Facebook and vice president of product and design at WhatsApp.\nShe began her career at Microsoft and remains on the board of cloud monitoring platform Datadog.\nAs CPO, Vora works closely with chief technology officer Rahul Patil to scale Claude beyond experimentation and expand Anthropic’s market presence.\n### Rahul Patil stays on as CTO, with an expanded role\nAnthropic’s broader leadership bench remains deep, with all seven co-founders still at the company.\nRahul Patil, who became CTO in October, succeeded Sam McCandlish, now chief architect.\nPatil previously served as CTO of Stripe and has led engineering teams at Microsoft, AWS and Oracle.\nNow working in close coordination with Vora, Patil is focused on bridging the gap between technical research and production-ready products.\n...\n### Other executives shaping Anthropic’s future\n- **Dario Amodei, CEO and co-founder: ** Dario Amodei previously served as vice president of research at OpenAI.\nHe founded Anthropic in 2021 with his sister, Daniela, and other former OpenAI colleagues.\n- **Daniela Amodei, president and co-founder: ** Daniela Amodei, who previously served as vice president of safety and policy at OpenAI, oversees Anthropic’s core operations, including chief technology officer Rahul Patil and chief architect Sam McCandlish.\n- **Jared Kaplan, chief science officer and co-founder: ** Anthropic co-founder and former OpenAI researcher Jared Kaplan serves as chief science officer.\nSince 2024, he has also served as the company’s responsible scaling officer, helping guide safety-related decisions.\n- **Jan Leike, alignment science lead: ** Jan Leike, who co-led OpenAI’s superalignment team, has served as Anthropic’s alignment science lead since 2024.\n- **Sam McCandlish, chief architect and co-founder: ** Another former OpenAI employee, Sam McCandlish focuses on model training and large-scale systems development.\nHe previously served as Anthropic’s CTO.\n- **Tom Brown, chief compute officer and co-founder: ** Former OpenAI GPT-3 researcher Tom Brown oversees Anthropic’s compute infrastructure.\n- **Vitaly Gudanets, CISO: ** Vitaly Gudanets has served as Anthropic’s chief information security officer since September.\nHe previously led security efforts at Netflix.\n- **Jack Clark, head of policy and co-founder: ** A former OpenAI policy director and technology journalist, Jack Clark leads Anthropic’s policy work.\n- **Krishna Rao, CFO: ** Krishna Rao joined Anthropic as chief financial officer in 2024 after previously leading finance at Airbnb.\n- **Christopher Olah, interpretability research lead and co-founder: ** Christopher Olah, a former interpretability lead at OpenAI, heads Anthropic’s interpretability research, focusing on model transparency and A.I. safety.\n### Anthropic’s board and trust\nIn February, Anthropic appointed Chris Liddell, a former deputy White House chief of staff and former CFO at Microsoft and General Motors, to its board of directors.\nDaniela Amodei said Liddell has “a track record of helping organizations get [technology, public service and governance] right when the stakes are highest.”\nThe rest of the board remains unchanged, including Dario Amodei, Daniela Amodei, Yasmin Razavi, Jay Kreps, Reed Hastings and Chris Liddell.\nThe Long-Term Benefit Trust recently removed Kanika Bahl and Zach Robinson and added Mariano-Florentino Cuéllar; Neil Buddy Shah remains on the trust board.",
        "title": "14 Executives Driving Anthropic's Future After Its Labs Expansion",
        "url": "https://observer.com/2026/04/anthropic-top-executives-after-labs-launch/",
        "date": "2026-04-20",
        "last_updated": "2026-05-19"
      },
      {
        "snippet": "Leadership Team\n7 people · 0 jobs\nThe Leadership Team at Anthropic guides the strategic direction of the company while ensuring a commitment to AI safety and ethics.\nComprised of co-founders and executives with diverse expertise in technology, finance, and security, this team focuses on fostering a collaborative environment, driving innovative research initiatives, and overseeing the development of reliable and interpretable AI systems that align with the company's vision for responsible AI deployment.\n...\nNo jobs in this team",
        "title": "Leadership Team - Anthropic",
        "url": "https://theorg.com/org/anthropic/teams/leadership-team-1",
        "date": "2023-01-24",
        "last_updated": "2026-05-13"
      },
      {
        "snippet": "Anthropic is a collaborative team of researchers, engineers, policy experts, business leaders and operators, who bring our experience from many different domains to our work.\n...\nWe’re a team of researchers, engineers, policy experts and operational leaders, with experience spanning a variety of disciplines, all working together to build reliable and understandable AI systems.\n...\n### Operations\nOur people, finance, legal, and recruiting teams are the human engines that make Anthropic go.\nWe’ve had previous careers at NASA, startups, and the armed forces and our diverse experiences help make Anthropic a great place to work (and we love plants!).\n...\nAnthropic is a Public Benefit Corporation, whose purpose is the responsible development and maintenance of advanced AI for the long-term benefit of humanity.\nOur Board of Directors is elected by stockholders and our Long-Term Benefit Trust, as explained here.\nCurrent members of the Board and the Long-Term Benefit Trust (LTBT) are listed below.\n**Anthropic Board of Directors**\nDario Amodei, Daniela Amodei, Yasmin Razavi, Jay Kreps, Reed Hastings, Chris Liddell, and Vas Narasimhan.\n**LTBT Trustees**\nNeil Buddy Shah, Richard Fontaine, and Mariano-Florentino Cuéllar.",
        "title": "Company \\ Anthropic",
        "url": "https://www.anthropic.com/company",
        "date": "2023-11-14",
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "## Who's running this\n7 public leadership roles from company pages, announcements, and reliable news signals.\nUse this as a current operating-model reference, not an SEC filing table.\n### Dario Amodei\nChief Executive Officer & Co-Founder\nExecutive\n10 reports\n### Daniela Amodei\nPresident & Co-Founder\nExecutive\n4 reports\n### Open Role\nHead of Research\nResearch\n0 reports\n### Open Role\nChief Product Officer\nProduct\n0 reports\n### Open Role\nChief Technology / Engineering Lead\nEngineering\n1 reports\n### Open Role\nHead of Policy\nPolicy\n0 reports\n### Open Role\nChief Operating Officer\nOperations\n3 reports\nThe businesses\n...\n3 divisions report into the group CEO.\nTile size scales with estimated headcount.\n### Research\n**600** employees\np3\nFrontier AI research and safety science.\n### Product & Engineering\n**500** employees\np4\nProductization of research into Claude and platform offerings.\n### Operations\n**400** employees\np7\nPeople, finance, legal, and internal operations.\n...\nNo recent leadership changes publicly disclosed.\n...\n3 directors.\n1 of 3 independent (33%).\n...\n### Dario Amodei\nInside\nCEO, Anthropic\n### Daniela Amodei\nInside\nPresident, Anthropic\n### Reed Hastings\nIndependent\nCo-Founder, Netflix\n...\n### Who leads Anthropic?\nAnthropic is led by CEO and co-founder Dario Amodei, with Daniela Amodei serving as President.\n...\nAnthropic builds reliable, interpretable, and steerable AI systems, including the Claude family of models, with a strong emphasis on safety.\n### What type of organizational structure does Anthropic use?\nAnthropic uses a hybrid structure combining founder-led research control with functional product, policy, and operations teams.\n### Who reports directly to Anthropic's CEO?\nResearch, product, engineering, and policy leaders report directly to the CEO.",
        "title": "Anthropic PBC Organizational Structure - Creately",
        "url": "https://creately.com/org-chart/major-startups/anthropic/",
        "date": "2026-04-01",
        "last_updated": "2026-05-15"
      },
      {
        "snippet": "Organizational Chart of Anthropic\nOrganigramme de Anthropic\nwww.anthropic.com\na24 dirigeants\n+1 650 493 7900\n...\nCEO & Director\nDario Amodei\n...\nJay Kreps\n...\nYasmin Razavi\n...\nKrishna Rao\n...\nAnthropic a 24 dirigeants\nAnthropic\n...\nListe dirigeants en Excel\n• Anthropic org chart\nL'organigramme en PDF\n• Anthropic org chart\n{title}\n...\nPour chacun des 1 304 900 dirigeants,\ndécouvrir ses fonctions exactes\net sa biographie.\n...\nPour toute assistance, vous pouvez nous contacter à\n[email protected]",
        "title": "Anthropic - Organigramme + Equipe Dirigeante",
        "url": "https://www.theofficialboard.fr/organigramme/anthropic",
        "date": null,
        "last_updated": "2025-05-28"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

## Parameters

| Parameter             | Type    | Required | Description                                                                       |
| --------------------- | ------- | -------- | --------------------------------------------------------------------------------- |
| `type`                | string  | Yes      | Must be `"people_search"`.                                                        |
| `max_tokens`          | integer | No       | Maximum total tokens for people-search context when using explicit token budgets. |
| `max_tokens_per_page` | integer | No       | Maximum tokens extracted per result page when using explicit token budgets.       |

## Response Shape

When `people_search` runs, the response can include a `people_search_results` output item before the final assistant message. The envelope contains the agent's generated `queries` and a `results` array whose entries share the same shape as `search_results` (id, url, title, snippet, source, last\_updated). The final `usage` object includes token counts, cost details, and `tool_calls_details.search_people.invocation` when tool-call usage is reported.

```json theme={null}
{
  "output": [
    {
      "type": "people_search_results",
      "queries": ["head of platform engineering Notion"],
      "results": [
        {
          "id": 1,
          "url": "https://example.com/profile",
          "title": "Example professional profile",
          "snippet": "A short snippet describing the professional result.",
          "source": "web"
        }
      ]
    },
    {
      "type": "message",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "The answer generated from people-search results."
        }
      ]
    }
  ],
  "usage": {
    "tool_calls_details": {
      "search_people": {
        "invocation": 1
      }
    }
  }
}
```

## Pricing

Each invocation of the `people_search` tool is billed at **\$5 per 1,000 tool invocations**. See the [Pricing](/docs/getting-started/pricing) page for full details.

## Limits / Quotas

People Search runs inside Agent API requests and is subject to your Agent API rate limits. See [Rate Limits & Usage Tiers](/docs/admin/rate-limits-usage-tiers#agent-api-rate-limits) for tier-based request limits.

| Limit           | How it applies                                                                                         |
| --------------- | ------------------------------------------------------------------------------------------------------ |
| **Rate limits** | Counts against your Agent API request rate limits. No separate `people_search` tool-call quotas apply. |

## Next Steps

<CardGroup>
  <Card title="Web Search" icon="world-search" href="/docs/agent-api/tools/web-search">
    Search the web for source-grounded context.
  </Card>

  <Card title="Fetch URL Content" icon="file-text" href="/docs/agent-api/tools/fetch-url-content">
    Fetch full content from known URLs.
  </Card>

  <Card title="Finance Search" icon="chart-line" href="/docs/agent-api/tools/finance-search">
    Retrieve structured financial and market data.
  </Card>

  <Card title="Agent API Quickstart" icon="rocket" href="/docs/agent-api/quickstart">
    Get started with the Agent API.
  </Card>
</CardGroup>


# Sandbox
Source: https://docs.perplexity.ai/docs/agent-api/tools/sandbox

Execute code in isolated containers from inside an Agent API request.

## Overview

The `sandbox` tool lets the model run code during an Agent API request. The agent can execute code in an isolated container, inspect the output, and use the result in its final answer.

You don't supply the code. You enable the tool, and the model writes and runs the code itself based on your prompt and instructions - then reads its own `stdout`/`stderr` back and uses it in the answer. The exact code the model ran is returned to you in the response (see [Response shape](#response-shape)), so you can verify what executed.

Enable the tool by adding it to the `tools` array. The model decides when to call it based on your prompt and instructions.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()


  def get_output_text(response) -> str:
      return "".join(
          content.text
          for item in response.output or []
          if getattr(item, "type", None) == "message"
          for content in getattr(item, "content", None) or []
          if getattr(content, "type", None) == "output_text"
      )


  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="For 230+ qualifying high-severity CVEs (CVE-YYYY-NNNNN published 2023–2025, CVSS ≥ 7.0), find the canonical vendor security advisory URL per CVE and name the affected product and the advisory's stated fix version.",
      tools=[{"type": "sandbox"}, {"type": "web_search"}],
      instructions="Use the sandbox and web search to gather and verify the advisories before answering.",
  )

  print(get_output_text(response))
  ```

  ```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-sol',
    input: "For 230+ qualifying high-severity CVEs (CVE-YYYY-NNNNN published 2023–2025, CVSS ≥ 7.0), find the canonical vendor security advisory URL per CVE and name the affected product and the advisory's stated fix version.",
    tools: [{ type: 'sandbox' as const }, { type: 'web_search' as const }],
    instructions: 'Use the sandbox and web search to gather and verify the advisories before answering.',
  });

  console.log(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 '{
      "model": "openai/gpt-5.6-sol",
      "input": "For 230+ qualifying high-severity CVEs (CVE-YYYY-NNNNN published 2023–2025, CVSS ≥ 7.0), find the canonical vendor security advisory URL per CVE and name the affected product and the advisory'\''s stated fix version.",
      "tools": [
        {
          "type": "sandbox"
        },
        {
          "type": "web_search"
        }
      ],
      "instructions": "Use the sandbox and web search to gather and verify the advisories before answering."
    }' | jq
  ```
</CodeGroup>

## Use cases

* Web search
* Numeric calculations and statistical analysis
* Data cleaning, parsing, and transformation
* Code execution to check logic or reproduce an error
* Structured artifact generation, such as CSV, JSON, or reports
* Multi-step workflows that need intermediate files or computed state

## How the container works

The sandbox is an isolated Linux container. Knowing what it can and can't do helps you predict when the model will reach for it and what to expect back.

| Property                    | Behavior                                                                                                                                                                                                                                                                      |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Languages**               | The model runs **Python** for computation and **bash** for shell commands. Each execution reports its `language` in the response.                                                                                                                                             |
| **Internet access**         | The container has network access, so the model's code can install packages it needs at runtime and reach external endpoints.                                                                                                                                                  |
| **State within a response** | Multiple executions in a single response share the same container: files written and packages installed by an earlier step are still there for a later one. This is what makes multi-step workflows and intermediate files work.                                              |
| **Output capture**          | `stdout` and `stderr` are captured per execution. Very large output is truncated (on the order of \~1 MiB per stream), so have the model write big results to a file and return it (see [Retrieving generated files](#retrieving-generated-files)) rather than printing them. |
| **Runtime limit**           | Each execution has a runtime cap. If it's exceeded, that execution's `status` is `timed_out` (see [Error handling](#error-handling)). For long jobs, use [background mode](#running-in-the-background).                                                                       |

### Calling other tools from inside the sandbox

The container ships with a preinstalled Perplexity SDK, so code the model runs inside the sandbox can call [Web Search](/docs/agent-api/tools/web-search), [Fetch URL Content](/docs/agent-api/tools/fetch-url-content), and [People Search](/docs/agent-api/tools/people-search) directly - without you adding those tools to the request - then compute on what they return. Each such call is billed at its standard per-invocation rate (see [Pricing](#pricing)).

## Running in the background

For long-running sandbox calls, submit the request with `background: true` and poll the response by ID until it completes.

<CodeGroup>
  ```python Python theme={null}
  import time
  from perplexity import Perplexity

  client = Perplexity()


  def get_output_text(response) -> str:
      return "".join(
          content.text
          for item in response.output or []
          if getattr(item, "type", None) == "message"
          for content in getattr(item, "content", None) or []
          if getattr(content, "type", None) == "output_text"
      )


  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Create a CSV with the first 10 Fibonacci numbers and their squares.",
      tools=[{"type": "sandbox"}],
      background=True,
  )

  while response.status in ("queued", "in_progress"):
      time.sleep(2)
      response = client.responses.retrieve(response.id)

  print(get_output_text(response))
  ```

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

  const client = new Perplexity();

  let response = await client.responses.create({
    model: 'openai/gpt-5.6-sol',
    input: 'Create a CSV with the first 10 Fibonacci numbers and their squares.',
    tools: [{ type: 'sandbox' as const }],
    background: true,
  });

  while (response.status === 'queued' || response.status === 'in_progress') {
    await new Promise((r) => setTimeout(r, 2000));
    response = await client.responses.retrieve(response.id);
  }

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

  ```bash cURL theme={null}
  # 1. Submit with background: true
  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "input": "Create a CSV with the first 10 Fibonacci numbers and their squares.",
      "tools": [{ "type": "sandbox" }],
      "background": true
    }'

  # 2. Poll the response by ID until status is completed, failed, cancelled, or incomplete
  curl https://api.perplexity.ai/v1/agent/$RESPONSE_ID \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY"
  ```
</CodeGroup>

## Error handling

Sandbox errors are returned through the normal Agent API response.

| Case               | What you see                                                                                                                                                                                                      |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Timeout**        | The `status` on the affected entry in `results[]` (and on the enclosing `sandbox_results` item) is `timed_out`. If the request cannot complete, the top-level response status is `failed` with an `error` object. |
| **Runtime error**  | The matching entry in `results[]` includes a non-zero `exit_code` and error output in `stderr`. The Agent API response may still complete if the container ran successfully.                                      |
| **Quota or limit** | The response fails with an `error` object describing the limit. Agent API rate limits still apply.                                                                                                                |

## Limits and quotas

Sandbox runs inside Agent API requests and is subject to Agent API rate limits. See [Rate Limits & Usage Tiers](/docs/admin/rate-limits-usage-tiers#agent-api-rate-limits) for tier-based request limits.

## Response shape

When the model calls the sandbox tool, the Agent API response includes a `sandbox_results` item in its `output` array alongside any `message` items. A single response can contain multiple `sandbox_results` items if the model makes more than one sandbox call.

Each `sandbox_results` item describes one sandbox invocation and nests the per-execution output inside a `results` array.

| Field          | Type     | Description                                                                    |
| -------------- | -------- | ------------------------------------------------------------------------------ |
| `type`         | `string` | Always `sandbox_results`.                                                      |
| `call_id`      | `string` | Identifier for this sandbox tool call.                                         |
| `container_id` | `string` | Identifier of the isolated container that executed the code.                   |
| `language`     | `string` | Language the sandbox ran the code in (for example, `python`).                  |
| `code`         | `string` | The code that was executed inside the sandbox.                                 |
| `status`       | `string` | Overall status of the sandbox call. One of `completed`, `timed_out`, `failed`. |
| `results`      | `array`  | One entry per execution inside the container. See fields below.                |

Each entry in `results` has the following fields:

| Field         | Type      | Description                                                      |
| ------------- | --------- | ---------------------------------------------------------------- |
| `stdout`      | `string`  | Standard output captured from the execution.                     |
| `stderr`      | `string`  | Standard error captured from the execution.                      |
| `exit_code`   | `integer` | Process exit code. Non-zero indicates a runtime error.           |
| `duration_ms` | `integer` | Wall-clock duration of the execution, in milliseconds.           |
| `status`      | `string`  | Per-execution status. One of `completed`, `timed_out`, `failed`. |

Example:

```json theme={null}
{
  "type": "sandbox_results",
  "call_id": "call_Y1Lo4H6cGFgNVsn4mwC0oSgc",
  "code": "vals = [(i, i*i) for i in range(1, 11)]\nprint('\\n'.join(f'{a},{b}' for a, b in vals))",
  "container_id": "i6dr97ven2qfm0sdtvfzc",
  "language": "python",
  "results": [
    {
      "duration_ms": 9011,
      "exit_code": 0,
      "status": "completed",
      "stderr": "",
      "stdout": "1,1\n2,4\n3,9\n4,16\n5,25\n6,36\n7,49\n8,64\n9,81\n10,100\n"
    }
  ],
  "status": "completed"
}
```

For the full request and response schema, see the [Agent API reference](/api-reference/agent-post).

## Retrieving generated files

When code in the sandbox writes a file and delivers it with the `share_file` tool, the response `output` array includes a `share_file` item. The file content is not returned inline — retrieve it with the response files endpoints, using the response `id`.

List the files a response produced:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  files = client.responses.files.list("resp_abc123")

  for file in files.data:
      print(file.id, file.filename, file.bytes)
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/agent/$RESPONSE_ID/files \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" | jq
  ```
</CodeGroup>

```json theme={null}
{
  "data": [
    {
      "bytes": 8002,
      "created_at": 1780923289,
      "filename": "anthropic_news.csv",
      "id": "9198548a-490b-4119-858f-fd3676b60319",
      "object": "file"
    }
  ],
  "object": "list"
}
```

Each entry has the following fields:

| Field        | Type      | Description                                                                     |
| ------------ | --------- | ------------------------------------------------------------------------------- |
| `id`         | `string`  | File identifier, used to download the content. Distinct from the response `id`. |
| `filename`   | `string`  | Name the sandbox gave the file.                                                 |
| `bytes`      | `integer` | File size in bytes.                                                             |
| `created_at` | `integer` | Unix timestamp of when the file was created.                                    |
| `object`     | `string`  | Always `file`.                                                                  |

Download a file's content by its `id`. The endpoint returns the raw file bytes (not JSON), with a `Content-Type` matching the file and a `Content-Disposition: attachment` header carrying the original filename.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  content = client.responses.files.content(
      file_id="9198548a-490b-4119-858f-fd3676b60319",
      response_id="resp_abc123",
  )
  content.write_to_file("anthropic_news.csv")
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/agent/$RESPONSE_ID/files/$FILE_ID/content \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -o anthropic_news.csv
  ```
</CodeGroup>

## Pricing

`sandbox` is billed on three axes:

| Axis                | Price              | Notes                                                                                                                                                                                                                                                                          |
| ------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Tokens**          | Per model          | Model token usage is billed separately according to Agent API token pricing. See [Models](/docs/agent-api/models) for per-model rates.                                                                                                                                         |
| **Sandbox session** | \$0.03 per session | Billed once per sandbox container. A session is the lifecycle of a single isolated container and covers up to 20 minutes of active use for billing purposes — this is the billing window, not a runtime cap.                                                                   |
| **Tools used**      | Per tool           | Code running inside the sandbox can call the [Web Search](/docs/agent-api/tools/web-search), [Fetch URL Content](/docs/agent-api/tools/fetch-url-content), and [People Search](/docs/agent-api/tools/people-search) tools. Each is billed at its standard per-invocation rate. |

Sandbox invocations are counted under `usage.tool_calls_details.sandbox.invocation`.

See [Pricing](/docs/getting-started/pricing#tool-pricing) for the full Agent API tool pricing table.


# Web Search
Source: https://docs.perplexity.ai/docs/agent-api/tools/web-search

Search the web from the Agent API with filters, search configurations, pricing, parameters, and response fields.

## Overview

The `web_search` tool lets the model search the web during an Agent API request. Use it for current information, recent news, source-grounded research, and questions that need information beyond the model's training data.

Enable the tool by adding it to the `tools` array. The model decides when to call it based on your prompt and instructions.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Explain the architecture of NVIDIA's CUDA programming model: threads, blocks, grids, warps, and memory hierarchy, and how they enable GPU parallelism.",
      tools=[
          {
              "type": "web_search",
              "search_context_size": "medium"
          }
      ],
      instructions="Search for current, source-grounded information before answering.",
  )

  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-sol',
    input: 'Explain the architecture of NVIDIA\'s CUDA programming model: threads, blocks, grids, warps, and memory hierarchy, and how they enable GPU parallelism.',
    tools: [
      {
        type: 'web_search' as const,
        search_context_size: 'medium',
      },
    ],
    instructions: 'Search for current, source-grounded information before answering.',
  });

  console.log(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 '{
      "model": "openai/gpt-5.6-sol",
      "input": "Explain the architecture of NVIDIA\u0027s CUDA programming model: threads, blocks, grids, warps, and memory hierarchy, and how they enable GPU parallelism.",
      "tools": [
        {
          "type": "web_search",
          "search_context_size": "medium"
        }
      ],
      "instructions": "Search for current, source-grounded information before answering."
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "c6e956f3-0667-40d1-9f47-ab3f5afa9bf7",
    "results": [
      {
        "snippet": "",
        "title": "CUDA C++ Programming Guide - NVIDIA Documentation Hub",
        "url": "https://docs.nvidia.com/cuda/cuda-c-programming-guide/",
        "date": "2026-04-02",
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "",
        "title": "CUDA Live: Your Parallel Programming Guide - YouTube",
        "url": "https://www.youtube.com/watch?v=ftI48A8K5Vg",
        "date": "2026-02-19",
        "last_updated": "2026-05-20"
      },
      {
        "snippet": "CUDA\nCUDA, which stands for Compute Unified Device Architecture, is a parallel computing platform and application programming interface (API) model created by NVIDIA.\nIt allows software developers and software engineers to use a CUDA-enabled graphics processing unit (GPU) for general-purpose processing purposes - an approach known as GPGPU (General-Purpose computing on Graphics Processing Units).\nCUDA gives programmers access to the virtual instruction set and memory of the parallel computational elements in CUDA-enabled GPUs.\nUsing CUDA, developers can significantly speed up compute-intensive applications by harnessing the power of GPUs for non-graphical computing.\n...\nToday, CUDA is typically harnessed by enabling a CPU to offload complex computational tasks to a GPU.\nThis can often result in a drastic increase in computing efficiency because GPUs are exceptionally efficient at handling multiple operations simultaneously due to their parallel processing capabilities.\n...\nOne of the key strengths of CUDA is its ability to make parallel computing more accessible and efficient.\nBy leveraging the massive parallel processing power of NVIDIA GPUs, CUDA enables dramatic increases in computing performance.\n...\n1. Parallel Processing Capabilities: CUDA enables hundreds or even thousands of computing cores on a GPU to perform simultaneous calculations, vastly outperforming CPUs on tasks that can be parallelized.\n...\n3. Advanced Memory Management: CUDA provides efficient and fine-grained control over memory usage on GPUs, allowing for optimized performance.\n...\nYes, CUDA is a proprietary computing platform developed by NVIDIA for their GPUs only.\nIt is specifically designed to work with NVIDIA graphics cards and, therefore, is not compatible with GPUs from other manufacturers.\n...\n4. How does CUDA differ from traditional CPU processing?\nCUDA allows for parallel processing, harnessing the power of GPU cores, which can handle thousands of threads simultaneously, offering a significant speed advantage over traditional CPU processing for certain tasks.\n...\nTo enable CUDA on a compatible NVIDIA GPU, you need to install the NVIDIA CUDA Toolkit and the appropriate GPU drivers from NVIDIA's website.\nThe toolkit includes libraries, debugging and optimization tools, a runtime library, and a C compiler.",
        "title": "What Is CUDA? - Supermicro",
        "url": "https://www.supermicro.com/en/glossary/cuda",
        "date": null,
        "last_updated": "2026-05-16"
      },
      {
        "snippet": "",
        "title": "1.2. Programming Model — CUDA Programming Guide",
        "url": "https://docs.nvidia.com/cuda/cuda-programming-guide/01-introduction/programming-model.html",
        "date": "2026-03-04",
        "last_updated": "2026-05-04"
      },
      {
        "snippet": "GPU (Graphics Processing Unit) architecture is the foundation of modern computing, designed to handle complex parallel processing tasks with incredible efficiency.\nUnlike traditional CPUs, which excel at sequential operations, GPUs are optimized for massive parallelism, making them indispensable for high-performance computing, artificial intelligence (AI) workloads, and virtualization.\n...\nGPUs excel in executing thousands of parallel operations, making them superior to CPUs for tasks such as deep learning and real-time analytics.\nThis advantage is key for industries requiring high-speed data processing.\nIn AI training, GPUs break complex computations into smaller tasks that run simultaneously across thousands of cores, dramatically accelerating model development.\nIn fields such as medical imaging and logistics optimization, parallel processing enables near-instantaneous analysis of vast data sets, leading to faster insights and decision-making.\n...\nGPU architecture refers to the design and structure of a graphics processing unit, optimized for parallel computing.\nIt is crucial for high-performance computing, AI, and graphics-intensive applications.\n...\nThe main layers include the hardware layer (physical components), firmware and driver layer (optimization and compatibility), and software and API layer (programming interfaces for application development).\n...\nGPUs outperform CPUs in AI and machine learning due to their ability to handle thousands of parallel computations simultaneously, significantly speeding up training and inference processes.",
        "title": "GPU Architecture Explained: Structure, Layers & Performance",
        "url": "https://www.scalecomputing.com/resources/understanding-gpu-architecture",
        "date": "2025-04-16",
        "last_updated": "2026-05-14"
      },
      {
        "snippet": "CUDA is a parallel computing platform and programming model developed by NVIDIA that enables dramatic increases in computing performance by harnessing the power of the GPU.\nIt allows developers to accelerate compute-intensive applications and is widely used in fields such as deep learning, scientific computing, and high-performance computing (HPC).",
        "title": "CUDA Programming Guide",
        "url": "https://docs.nvidia.com/cuda/cuda-programming-guide/index.html",
        "date": "2026-03-04",
        "last_updated": "2026-05-02"
      },
      {
        "snippet": "6\nClosely Coupled CPU-GPU\nOperation 1\nOperation 2\nOperation 3\nInit\nAlloc\nFunction\nLib\nLib\nFunction\nFunction\nCPU\nGPU\nIntegrated programming model\nHigh speed data transfer – up to 3.2 GB/s\nAsynchronous operation\nLarge GPU memory systems\n© NVIDIA Corporation 2006-2008\n...\n17\nGPU Computing\nGPU is a massively parallel processor\nNVIDIA G80: 128 processors\nSupport thousands of active threads (12,288 on G80)\nGPU Computing requires a programming model that \ncan efficiently express that kind of parallelism\nMost importantly, data parallelism\nCUDA implements such a programming model\n© NVIDIA Corporation 2006-2008\n18\nCUDA Kernels and Threads\nParallel portions of an application are executed on \nthe device as kernels\nOne kernel is executed at a time\nMany threads execute each kernel\nDifferences between CUDA and CPU threads \nCUDA threads are extremely lightweight\nVery little creation overhead\nInstant switching\nCUDA uses 1000s of threads to achieve efficiency\nMulti-core CPUs can use only a few\nDefinitions: \nDevice = GPU; Host = CPU\nKernel = function that runs on the device\n© NVIDIA Corporation 2006-2008\n19\nArrays of Parallel Threads\nA CUDA kernel is executed by an array of threads\nAll threads run the same code\nEach thread has an ID that it uses to compute memory \naddresses and make control decisions\n7\n6\n...\nThe Missing Piece: threads may need to cooperate\nThread cooperation is valuable\nShare results to save computation\nSynchronization\nShare memory accesses\nDrastic bandwidth reduction\nThread cooperation is a powerful feature of CUDA\n...\nThread Blocks: Scalable Cooperation\nDivide monolithic thread array into multiple blocks\nThreads within a block cooperate via shared memory\nThreads in different blocks cannot cooperate\nEnables programs to transparently scale to any \nnumber of processors!\n...\nHardware is free to schedule thread blocks \n...\nA kernel scales across any number of parallel \nmultiprocessors\n...\n23\nCUDA Programming Model\nA kernel is executed by a \ngrid of thread blocks\nA thread block is a batch \nof threads that can \ncooperate with each \nother by:\nSharing data through \nshared memory\nSynchronizing their \nexecution\nThreads from different\nblocks cannot cooperate\nHost\nKernel \n...\n24\nProcessors     execute computing threads\nThread Execution Manager issues threads\n128 Thread Processors grouped into 16 Multiprocessors (SMs)\nParallel Data Cache (Shared Memory) enables thread \ncooperation\n...\nThread and Block IDs\nThreads and blocks have IDs\nEach thread can decide what \ndata to work on\nBlock ID: 1D or 2D\nThread ID: 1D, 2D, or 3D \nSimplifies memory\naddressing when processing\nmulti-dimensional data\nImage processing\nSolving PDEs on volumes\n...\nKernel Memory Access\nRegisters\nGlobal Memory (external DRAM)\nKernel input and output data reside here\nOff-chip, large\nUncached\nShared Memory (Parallel Data Cache)\nShared among threads in a single block\nOn-chip, small\nAs fast as registers\nGrid\n...\nThe host can read & write global memory but not shared memory\n...\n27\nExecution Model\nKernels are launched in grids\nOne kernel executes at a time\nA block executes on one Streaming Multiprocessor \n(SM)\nDoes not migrate\nSeveral blocks can reside concurrently on one SM\nControl limitations (of G8X/G9X GPUs):\nAt most 8 concurrent blocks per SM\nAt most 768 concurrent threads per SM\nNumber is further limited by SM resources\nRegister file is partitioned among all resident threads\nShared memory is partitioned among all resident thread blocks\n...\nCUDA Advantages over Legacy GPGPU\n(Legacy GPGPU is programming GPU through graphics APIs)\nRandom access byte-addressable memory\nThread can access any memory location\nUnlimited access to memory\nThread can read/write as many locations as needed\nShared memory (per block) and thread \nsynchronization\nThreads can cooperatively load data into shared memory\nAny thread can then access any shared memory location\nLow learning curve\nJust a few extensions to C\nNo knowledge of graphics is required\nNo graphics API overhead\n...\n29\nCUDA Model Summary\nThousands of lightweight concurrent threads\nNo switching overhead\nHide instruction and memory latency\nShared memory\nUser-managed L1 cache\nThread communication / cooperation within blocks\nRandom access to global memory\nAny thread can read/write any location(s)\nCurrent generation hardware:\nUp to 128 streaming processors\nMemory\nLocation\nCached\nAccess\nScope (“Who?”)\nShared\nOn-chip\nN/A\nRead/write\nAll threads in a block\nGlobal\nOff-chip\nNo\nRead/write\nAll threads + host\n© NVIDIA Corporation 2006-2008",
        "title": "[PDF] NVIDIA CUDA Software and GPU Parallel Computing Architecture",
        "url": "https://www.isfpga.org/past/fpga2008/fpga2008%20workshop%20-%2006%20NVIDIA%20-%20Kirk.pdf",
        "date": null,
        "last_updated": "2026-03-10"
      },
      {
        "snippet": "Parallel Computing on a GPU\nNVIDIA GPU Computing Architecture\nis a scalable parallel computing platform\nIn laptops, desktops, workstations, servers\n8-series GPUs deliver 50 to 200 GFLOPS\non compiled parallel C applications\nGPU parallel performance pulled by the\ninsatiable demands of PC game market\nGPU parallelism is doubling every year\nProgramming model scales transparently\nProgrammable in C with CUDA tools\nMultithreaded SPMD model uses application\ndata parallelism and thread parallelism\nGeForce 8800\n...\nNVIDIA 8-Series GPU Computing\nMassively multithreaded parallel computing platform\n12,288 concurrent threads, hardware managed\n128     Thread Processor cores at 1.35 GHz  == 518 GFLOPS peak\nGPU Computing features enable C on Graphics Processing Unit\nSP\n© NVIDIA Corporation 2007\n...\nProgrammer Partitions Problem\nwith Data-Parallel Decomposition\nCUDA Programmer partitions\nproblem into Grids, one Grid\nper sequential problem step\nProgrammer partitions Grid\ninto result Blocks computed\nindependently in parallel\nGPU thread array computes\nresult Block\nProgrammer partitions Block\ninto elements computed\ncooperatively in parallel\nGPU thread computes result\nelement\nGPU\nGrid 1\nBlock\n(0, 0)\n...\nCooperative Thread Array\nCTA Implements CUDA Thread Block\nA CTA is an array of concurrent threads\nthat cooperate to compute a result\nA CUDA thread block is a CTA\nProgrammer declares CTA:\nCTA size 1 to 512 concurrent threads\nCTA shape 1D, 2D, or 3D\nCTA dimensions in threads\nCTA threads execute thread program\nCTA threads have thread id numbers\nCTA threads share data and synchronize\nThread program uses thread id to select\nwork and address shared data\nCTA\nCUDA Thread Block\nThread Id #:\n0 1 2 3 …          m\nThread program\n...\nSM Multiprocessor Executes CTAs\nCTA threads run concurrently\nSM assigns thread id #s\nSM manages thread execution\nCTA threads share data & results\nIn Memory and Shared Memory\nSynchronize at barrier instruction\nPer-CTA Shared Memory\nKeeps data close to processor\nMinimize trips to global Memory\nCTA threads access global Memory\n...\nData Parallel Levels\n...\nCTA – Cooperative Thread Array\n...\n1 to 512 threads per CTA\nCTA (Block) id number\n...\nComputes many result Blocks\n...\nParallel Memory Sharing\nLocal Memory:   per-thread\nPrivate per thread\nAuto variables, register spill\nShared Memory:   per-CTA\nShared by threads of CTA\nInter-thread communication\nGlobal Memory:   per-application\nShared by all threads\nInter-Grid communication\nThread\nLocal Memory\n...\nGPU parallelism varies widely\nRanges from 8 cores to many 100s of cores\nRanges from 100 to many 1000s of threads\nGPU parallelism doubles yearly\nGraphics performance scales with GPU parallelism\nData parallel mapping of pixels to threads\nUnlimited demand for parallel pixel shader threads and cores\nChallenge:\nScale Computing performance with GPU parallelism\nProgram must be insensitive to the number of cores\nWrite one program for any number of SM cores\nProgram runs on any size GPU without recompiling\n...\n13\nTransparent Scalability\nProgrammer uses multi-level data parallel decomposition\nDecomposes problem into sequential steps (Grids)\nDecomposes Grid into computing parallel Blocks (CTAs)\nDecomposes Block into computing parallel elements (threads)\nGPU hardware distributes CTA work to available SM cores\nGPU balances CTA work load across any number of SM cores\nSM core executes CTA program that computes Block\nCTA program computes a Block independently of others\nEnables parallel computing of Blocks of a Grid\nNo communication among Blocks of same Grid\nScales one program across any number of parallel SM cores\nProgrammer writes one program for all GPU sizes\nProgram does not know how many cores it uses\nProgram executes on GPU with any number of cores\n© NVIDIA Corporation 2007\n...\n14\nCUDA Programming Model:\nParallel Multithreaded Kernels\nExecute data-parallel portions of application on\nGPU as kernels which run in parallel on many\ncooperative threads\nIntegrated CPU + GPU application C program\nPartition problem into a sequence of kernels\nKernel C code executes on GPU\nSerial C code executes on CPU\nKernels execute as blocks of parallel threads\nView GPU as a computing device that:\nActs as a coprocessor to the CPU host\nHas its own memory\nRuns many lightweight threads in parallel\n© NVIDIA Corporation 2007\n...\nCUDA integrated CPU + GPU application C program\nSerial C code executes on CPU\nParallel Kernel C code executes on GPU thread blocks\n...\n16\nCUDA Programming Model:\nGrids, Blocks, and Threads\nExecute a sequence of kernels\non GPU computing device\nA kernel executes as a Grid of\nthread blocks\nA thread block is an array of\nthreads that can cooperate\nThreads within the same block\nsynchronize and share data in\nShared Memory\nExecute thread blocks as CTAs\non multithreaded\nmultiprocessor SM cores\nCPU\nKernel 1\nKernel 2\nGPU device\n...\n17\nCUDA Programming Model:\nThread Memory Spaces\nEach kernel thread can read:\nThread Id \nper thread\nBlock Id \nper block\nConstants\nper grid\nTexture    \nper grid\nEach thread can read and write:\nRegisters\nper thread\nLocal memory\nper thread\nShared memory per block\nGlobal memory per grid\nHost CPU can read and write:\nConstants\nper grid\nTexture    \nper grid\nGlobal memory per grid\nThread Id,  Block Id\nRegisters\nConstants\nTexture\nGlobal Memory\nShared\nMemory\nKernel\nThread\nProgram\nWritten in C\nLocal Memory\n...\n18\nCUDA: C on the GPU\nSingle-Program Multiple-Data (SPMD) programming model\nC program for a thread of a thread block in a grid\nExtend C only where necessary\nSimple, explicit language mapping to parallel threads\nDeclare C kernel functions and variables on GPU:\n__global__ void KernelFunc(...);\n__device__ int  GlobalVar;\n__shared__ int  SharedVar;\nCall kernel function as Grid of 500 blocks of 128 threads:\nKernelFunc<<< 500, 128 >>>(args ...);\nExplicit GPU memory allocation, CPU-GPU memory transfers\ncudaMalloc( ), cudaFree( )\ncudaMemcpy( ), cudaMemcpy2D( ), …\n...\nNVIDIA GPU Computing Architecture\nComputing mode enables parallel C on GPUs\nMassively multithreaded – 1000s of threads\nExecutes parallel threads and thread arrays\nThreads cooperate via Shared and Global memory\nScales to any number of parallel processor cores\nNow on: Tesla C870, D870, S870, GeForce 8800/8600/8500,\nand Quadro FX 5600/4600\nCUDA Programming model\nC program for GPU threads\nScales transparently to GPU parallelism\nCompiler, tools, libraries, and driver for GPU Computing\nSupports Linux and Windows",
        "title": "[PDF] GPU Parallel Computing Architecture and CUDA Programming Model",
        "url": "https://old.hotchips.org/wp-content/uploads/hc_archives/hc19/2_Mon/HC19.02/HC19.02.02.pdf",
        "date": null,
        "last_updated": "2025-11-04"
      },
      {
        "snippet": "",
        "title": "4.18. CUDA Dynamic Parallelism — CUDA Programming Guide",
        "url": "https://docs.nvidia.com/cuda/cuda-programming-guide/04-special-topics/dynamic-parallelism.html",
        "date": "2026-03-04",
        "last_updated": "2026-05-03"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

## Configuring Search

### Using Recommended Token Budgets

Start with `low`, `medium`, or `high` for search context sizing via `search_context_size`. Each named size maps to a recommended pair of `max_tokens` and `max_tokens_per_page` budgets and is the recommended default for most applications.

| `search_context_size` | `max_tokens` | `max_tokens_per_page` | Best for                                  |
| --------------------- | ------------ | --------------------- | ----------------------------------------- |
| `low`                 | 300          | 300                   | Simple facts and lightweight lookups      |
| `medium`              | 1,000        | 1,000                 | General research and product comparisons  |
| `high`                | 4,000        | 4,000                 | Source-heavy answers and complex research |

<Note>
  These token-budget mappings reflect Perplexity's current recommended defaults and may change as we ship updated configurations based on the latest evaluation results. Calling a named size always resolves to the current recommended budget.
</Note>

<CodeGroup>
  ```python Python theme={null}
  tools = [
      {
          "type": "web_search",
          "search_context_size": "high"
      }
  ]
  ```

  ```typescript Typescript theme={null}
  const tools = [
    {
      type: 'web_search' as const,
      search_context_size: 'high',
    },
  ];
  ```

  ```bash cURL theme={null}
  "tools": [
    {
      "type": "web_search",
      "search_context_size": "high"
    }
  ]
  ```
</CodeGroup>

### Advanced Token Budget Configuration

Use explicit token budgeting when you need to pin exact budgets for cost controls, latency controls, or evaluations. Set `max_tokens` to cap total search context across results, and set `max_tokens_per_page` to cap content extracted from each result page. Explicit budgets override any `search_context_size` value passed in the same request, and you are charged for the exact number of search context tokens consumed, not the requested budget.

<CodeGroup>
  ```python Python theme={null}
  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="Summarize the US OMB M-24-10 memorandum on AI procurement: scope, key requirements for federal agencies, and the rights-impacting AI categories.",
      tools=[
          {
              "type": "web_search",
              "max_tokens": 6000,
              "max_tokens_per_page": 1200,
              "filters": {
                  "search_domain_filter": [".gov"],
                  "search_recency_filter": "month"
              }
          }
      ],
  )
  ```

  ```typescript Typescript theme={null}
  const response = await client.responses.create({
    model: 'openai/gpt-5.6-sol',
    input: 'Summarize the US OMB M-24-10 memorandum on AI procurement: scope, key requirements for federal agencies, and the rights-impacting AI categories.',
    tools: [
      {
        type: 'web_search' as const,
        max_tokens: 6000,
        max_tokens_per_page: 1200,
        filters: {
          search_domain_filter: ['.gov'],
          search_recency_filter: 'month',
        },
      },
    ],
  });
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "input": "Summarize the US OMB M-24-10 memorandum on AI procurement: scope, key requirements for federal agencies, and the rights-impacting AI categories.",
      "tools": [
        {
          "type": "web_search",
          "max_tokens": 6000,
          "max_tokens_per_page": 1200,
          "filters": {
            "search_domain_filter": [".gov"],
            "search_recency_filter": "month"
          }
        }
      ]
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "75a4ee6f-ac57-4ed1-ad17-ad2d54f70428",
    "results": [
      {
        "snippet": "",
        "title": "[PDF] M-24-10 MEMORANDUM FOR THE HEADS OF EXECUTIVE ...",
        "url": "https://www.whitehouse.gov/wp-content/uploads/2024/03/M-24-10-Advancing-Governance-Innovation-and-Risk-Management-for-Agency-Use-of-Artificial-Intelligence.pdf",
        "date": null,
        "last_updated": "2026-03-30"
      },
      {
        "snippet": "",
        "title": "[PDF] M-24-18 MEMORANDUM FOR THE HEADS OF EXECUTIVE ...",
        "url": "https://www.whitehouse.gov/wp-content/uploads/2024/10/M-24-18-AI-Acquisition-Memorandum.pdf",
        "date": null,
        "last_updated": "2026-03-21"
      },
      {
        "snippet": "",
        "title": "OMB Releases Requirements for Responsible AI Procurement by ...",
        "url": "https://www.cov.com/en/news-and-insights/insights/2024/10/omb-releases-requirements-for-responsible-ai-procurement-by-federal-agencies",
        "date": "2023-04-18",
        "last_updated": "2026-03-25"
      },
      {
        "snippet": "On September 24, 2024, the Office of Management and Budget (OMB) released **Memorandum M-24-18**, *Advancing the Responsible Acquisition of Artificial Intelligence in Government *(Memo).\nThe 36-page Memo builds on OMB’s March 2024 guidance governing federal agencies’ use of AI, Memorandum M-24-10, which we reported on here.\nThe Memo addresses requirements and guidance for agencies acquiring AI systems and services, focusing on three strategic goals: (i) ensuring collaboration across the federal government; (ii) managing AI risks and performance; and (iii) promoting a competitive AI market.\n### Scope and Applicability\nThe Memo’s requirements will apply to contracts awarded under solicitations issued on or after March 23, 2025, as well as to any renewal options or extensions exercised after March 23, 2025.\nThe Memo addresses government-wide considerations associated with agencies’ procurement of an AI system or service.\nFor this purpose, the Memo defines “AI System” to include AI applications and AI integrated into other systems or agency business processes, but does not include “common commercial products” with embedded AI functionality (e.g., common commercial map navigation applications or word processing software that has substantial non-AI purposes or functionalities but for which AI is embedded for functions like suggesting text or correcting spelling and grammar).\nThe Memo also does not apply to AI acquired by elements of the Intelligence Community or acquired for use as a component of a “National Security System” as defined under 44 U.S.C.\n§ 3552(b)(6), and does not apply to:\n- contractors’ incidental use of AI during contract performance (e.g., AI used at the option of a contractor when not directed or required to fulfill requirements);\n- AI acquired to carry out basic, applied, or experimental research (except where the purpose of such research is to develop particular AI applications within the agency);\n- regulatory actions designed to prescribe generally AI law or policy; or\n- evaluations of particular AI applications because the AI provider is the target or potential target of a regulatory enforcement, law enforcement, or national security action.\n...\nThe Memo directs agencies to formalize internal acquisition policies, procedures, and practices to reflect AI acquisition requirements and requires agencies to submit proof of implementation progress and agency-wide coordination to OMB by March 2025.\nThe Memo further directs agencies to work together through interagency councils and other efforts to collaborate and share information about AI acquisition across agencies “to strengthen the marketplace over time by increasing predictability and standardizing expectations for vendors.”\nAccording to the Memo, information collected by agencies on AI acquisition should be shared publicly where possible to provide clarity to contractors, including new entrants.\n...\nThe bulk of the Memo is dedicated to best practices and specific requirements for managing AI risk and performance, directing agencies to prioritize privacy, security, data ownership, and interoperability when planning for an AI acquisition.\n...\nTo determine whether AI covered by Memorandum M-24-18 is being acquired, the Memo directs agency officials responsible for acquisition planning, requirements development, and proposal evaluation to:\n1. Communicate to contractors, to the greatest extent practicable, whether the acquired AI system or service is intended to be used in a manner that could impact rights or safety and trigger additional risk management requirements.\n2. In cases where an agency’s solicitation does not explicitly ask for an AI system, consider requirements language asking contractors to report any proposed use of AI as part of their proposal submissions.\n3. Require contractors to provide a notification to and receive acceptance from relevant agency stakeholders prior to the integration of new AI features or components into systems and services being delivered under contract.\n4. Communicate with contractors to determine when AI is a primary feature or component in an acquired system or service, including questions to the contractor to understand if AI is being used in the evaluation or performance of a contract that does not explicitly involve AI.\n...\nThe Memo includes various recommendations and requirements that could create affirmative requirements for contractors, including that:\n- Agencies should consider including as part of their evaluation criteria how AI vendors demonstrate they are protecting personally identifiable information and mitigating privacy risks, including through privacy-enhancing technologies.\n- Agencies should ensure contractual terms address requirements for vendors to submit systems that use facial recognition for evaluation by NIST as part of the Face Recognition Technology Evaluation and Facial Analytics Technical Evaluation, where practicable.\n- Agencies should require vendors to identify potential AI biases and mitigation strategies to address biases.\n...\nThe Memo suggests that agencies should leverage performance-based contracting approaches and techniques, to strengthen their ability to effectively plan for, identify, and manage risk throughout the contract lifecycle.\n...\nThe Memo requires agencies to scrutinize terms of service and licensing terms, including those that specify what information, models, and transformed agency data should be provided as deliverables to avoid vendor lock-in, and to conduct careful due diligence on the supply chain of a vendor’s data.\nThe best practices outlined in the Memo include contractual restrictions on using agency information to train AI systems.\n...\nThe Memo requires that contract terms explicitly address how a vendor will ensure compliance with relevant data management directives and policies (e.g., through a quality management system), particularly with respect to (i) data that is generated before, during, or after the delivery of the AI; (ii) tiered levels of access and requisite responsibilities of handling data; and (iii) disclosures when copyrighted materials are used in the training data.\n...\nAccording to the Memo, agencies should include contractual requirements that facilitate the ability to obtain any documentation and access necessary to understand how a model was trained.\nFor example, agencies may request training logs from a contractor, including evidence of any data sourcing, cleansing, inputs, parameters, or hyper-parameters used during training sessions for models delivered to the government.\nContractors may also be asked to provide detailed documentation of the training procedure used for the model to demonstrate the model’s authenticity, provenance, and security, and to make trained model artifacts available for agency evaluation and review.\n#### Rights-Impacting AI and Safety-Impacting AI\nWhere practicable, agencies must disclose in solicitations whether the planned use is rights-impacting or safety-impacting.\nAgencies must consider whether various categories of information must be provided by the vendor to satisfy the requirements of OMB Memorandum M-24-10 or to meet the agency’s objectives, including, e.g., performance metrics and information about data source, provenance, selection, quality, and appropriateness and fitness-for-purpose.\nContracts should delineate responsibilities for ongoing testing and monitoring, set criteria for risk mitigation, and prioritize performance improvement.\nContractors could also be required to have a process for identifying and disclosing serious AI incidents and malfunctions of an acquired AI system or service within 72 hours, or a timely manner based on the severity of the incident.\nFor new or existing contracts involving agency use of rights-impacting AI systems or services, agencies must disclose OMB Memorandum M-24-10’s notice and appeal requirements to contractors and require cooperation with those requirements.\n...\nThe Memo includes best practices for agencies acquiring general use enterprise-wide generative AI, including contractual requirements for vendors to provide transparency about generated content, protect against inappropriate use, prevent harmful and illegal output, provide evaluation and testing documentation, and mitigate environmental impacts.\n...\nThe Memo calls on agencies to foster a competitive AI marketplace, including by establishing contractual requirements designed to minimize vendor lock-in; prioritizing interoperability and transparency; and leveraging innovative acquisition practices to secure better contract outcomes.\nAppendix I of the Memo outlines actions agencies should take to promote such innovative practices.\n...\nMemorandum M-24-18 further signals a movement by the government from discussing general principles for AI to creating rules around the government’s procurement and use of AI in contracts.\nContractors should expect to continue to see movement towards regulations and should pay close attention to solicitations that may require reporting requirements around, for example: (a) the proposed use of an AI system; (b) the use of new AI features; (c) the protection of personally identifiable information (PII); (d) the data used to train AI models; (e) data accountability; (f) how the AI system is tested and validated; and (g) how bias will be mitigated.",
        "title": "OMB Releases Guidance to Advance Federal AI Acquisition",
        "url": "https://www.crowell.com/en/insights/client-alerts/omb-releases-guidance-to-advance-federal-ai-acquisition",
        "date": "2024-10-29",
        "last_updated": "2026-05-22"
      },
      {
        "snippet": "",
        "title": "[PDF] Compliance Plan for OMB Memorandum M-24-10 ... - Federal Reserve",
        "url": "https://www.federalreserve.gov/publications/files/compliance-plan-for-omb-memorandum-m-24-10-202409.pdf",
        "date": null,
        "last_updated": "2026-03-28"
      },
      {
        "snippet": "",
        "title": "[PDF] M-24-18 Advancing the Responsible Acquisition of Artificial ...",
        "url": "https://static.carahsoft.com/concrete/files/7817/2986/8466/Guidance_M-24-18_Advancing_the_Responsible_Acquisition_of_Artificial_Intelligence_in_Government.pdf",
        "date": null,
        "last_updated": "2025-10-27"
      },
      {
        "snippet": "",
        "title": "EXECUTIVE OFFICE OF THE PRESIDENT",
        "url": "https://whitehouse.gov/wp-content/uploads/2024/10/M-24-18-AI-Acquisition-Memorandum.pdf",
        "date": null,
        "last_updated": "2025-09-14"
      },
      {
        "snippet": "",
        "title": "OFFICE OF MANAGEMENT AND BUDGET - The White House",
        "url": "https://www.whitehouse.gov/wp-content/uploads/2024/10/M-24-18-AI-Acquisition-Memorandum.pdf?trk=public_post_comment-text",
        "date": null,
        "last_updated": "2025-10-24"
      },
      {
        "snippet": "",
        "title": "March 28, 2024 M-24-10 MEMORANDUM FOR THE ...",
        "url": "https://bidenwhitehouse.archives.gov/wp-content/uploads/2024/03/M-24-10-Advancing-Governance-Innovation-and-Risk-Management-for-Agency-Use-of-Artificial-Intelligence.pdf",
        "date": null,
        "last_updated": "2025-10-18"
      },
      {
        "snippet": "*New guidance helps agencies harness the power of AI through their acquisitions process to promote innovation and competition while managing risks*\nToday, the Office of Management and Budget (OMB) released the\n*Advancing the Responsible Acquisition of Artificial Intelligence in Government *memorandum (M-24-18).\nSuccessful use of commercially-provided AI requires responsible procurement of AI.\nThis new memo ensures that when Federal agencies acquire AI, they appropriately manage risks and performance; promote a competitive marketplace; and implement structures to govern and manage their business processes related to acquiring AI.\n...\nThe EO directed sweeping action to strengthen AI safety and security, protect Americans’ privacy, advance equity and civil rights, stand up for consumers and workers, promote innovation and competition, and advance American leadership around the world.\n...\nOMB M-24-10, issued in March 2024, made history by introducing the first government-wide binding requirements for agencies to strengthen governance, innovation, and risk management for use of AI.\nM-24-18 builds on this guidance to help agencies buy AI responsibly.\nAgency acquisition of AI is similar in many respects to the purchase of other types of information technology, but it also presents novel challenges.\nM-24-18 helps agencies anticipate and address these challenges by issuing requirements and providing recommendations around three strategic goals.\n**Managing AI Risks and Performance**\nThe complex nature of how AI systems are built, trained, and deployed creates certain considerations and challenges for agency acquisition of AI.\nFor this reason, M-24-18 includes best practices and specific requirements for managing AI risk and performance, with additional requirements for acquiring AI use cases associated with rights-impacting and safety-impacting AI.\nThe memorandum:\n- Requires that agency privacy officials and programs have early, ongoing involvement in AI acquisition processes so that they are able to identify and manage privacy risks and ensure compliance with law and policy;\n- Calls for agencies to work with vendors to understand when AI is being acquired and when such acquisition triggers additional risk management requirements for rights-impacting and safety-impacting AI;\n- Promotes the use of innovative outcomes-based acquisition techniques that strengthen agencies’ ability to effectively plan for, manage, and continuously mitigate risk as well as drive performance;\n- Instructs agencies to negotiate appropriate contractual requirements and evaluation processes to ensure vendors provide sufficient information for agencies to evaluate vendor claims, identify and manage risk, conduct impact assessments, and fulfill requirements to notify impacted individuals and implement appeals; and\n- Directs contractual terms to be negotiated in a way that protects government data and intellectual property, and be defined in a manner that ensures safe use when AI is involved in decision-making that impacts members of the public.\n**Promoting a Competitive AI Market with Innovative Acquisition**\nAs AI evolves, agencies must have access to the best available solutions from a diverse and evolving market of suppliers.\nM-24-18 calls on agencies to ensure robust competition – both to increase value for the Federal government, and reduce risks to rights and safety, including by:\n- Proactively incorporating acquisition principles designed to minimize vendor lock-in when establishing contractual requirements;\n- Explicitly considering interoperability and transparency during market research, requirements development, and vendor evaluation processes; and\n- Leveraging innovative acquisitions practices to secure good contractor performance and mission outcomes.\n**Ensuring Collaboration Across the Federal Government**\nManaging novel risks and the rapidly evolving AI technology landscape requires agencies to establish cross-functional teams that include officials with AI expertise and personnel from other relevant fields—including acquisition, cybersecurity, privacy, and civil liberties—to inform strategic planning and acquisition of AI.\nThrough interagency councils and other efforts, agencies will work together to share lessons learned to inform future policy and procedural efforts to support effective and responsible acquisition of AI.\nThese collaborations should include considerations for:\n- Identifying and prioritizing AI investments that best serve an agency’s mission;\n- Developing the capacity to deploy any acquired AI; and\n- Promoting adoption of cross-functional best practices for the duration of use.",
        "title": "FACT SHEET: OMB Issues Guidance to Advance the Responsible Acquisition of AI in Government | OMB | The White House",
        "url": "https://www.whitehouse.gov/omb/briefing-room/2024/10/03/fact-sheet-omb-issues-guidance-to-advance-the-responsible-acquisition-of-ai-in-government/",
        "date": "2024-10-03",
        "last_updated": "2024-10-03"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

### Number of Results

Set `max_results` to control how many results the tool collects per `web_search` call. It's the total for the call; with several reformulated queries the budget is split per query (roughly `ceil(max_results / number_of_queries)`). When omitted, the default budget applies.

<CodeGroup>
  ```python Python theme={null}
  tools = [
      {
          "type": "web_search",
          "search_context_size": "low",
          "max_results": 20
      }
  ]
  ```

  ```typescript Typescript theme={null}
  const tools = [
    {
      type: 'web_search' as const,
      search_context_size: 'low',
      max_results: 20,
    },
  ];
  ```

  ```bash cURL theme={null}
  "tools": [
    {
      "type": "web_search",
      "search_context_size": "low",
      "max_results": 20
    }
  ]
  ```
</CodeGroup>

<Note>
  `max_results` accepts the range documented in the [API reference](/api-reference/agent-post). Within range, the backend may return fewer results than requested. Use it together with `search_context_size` to trade breadth (number of results) against depth (content extracted per result).
</Note>

## Filters

Use filters to constrain the sources, dates, and location context used by `web_search`.

| Filter                       | Type             | Description                                                                           |
| ---------------------------- | ---------------- | ------------------------------------------------------------------------------------- |
| `search_domain_filter`       | array of strings | Include or exclude up to 20 domains or URLs. Prefix entries with `-` to exclude them. |
| `search_recency_filter`      | string           | Restrict results to `"hour"`, `"day"`, `"week"`, `"month"`, or `"year"`.              |
| `search_after_date_filter`   | string           | Include results published after a date in MM/DD/YYYY format.                          |
| `search_before_date_filter`  | string           | Include results published before a date in MM/DD/YYYY format.                         |
| `last_updated_after_filter`  | string           | Include results last updated after a date in MM/DD/YYYY format.                       |
| `last_updated_before_filter` | string           | Include results last updated before a date in MM/DD/YYYY format.                      |
| `user_location`              | object           | Personalize search by country, region, city, latitude, and longitude.                 |

### Domain filter

<Warning>
  Use `search_domain_filter` in either allowlist mode or denylist mode, not both. The domain filter accepts up to 20 domains or URLs. For example, `["nasa.gov", "wikipedia.org"]` includes only those domains, while `["-reddit.com", "-pinterest.com"]` excludes those domains.
</Warning>

Entries can be at the domain level (e.g., `wikipedia.org`) or at the URL level (e.g., `https://en.wikipedia.org/wiki/Chess`) for more granular control.

### Recency filter

`search_recency_filter` maps each value to a relative window:

| Value   | Window                                                                  |
| ------- | ----------------------------------------------------------------------- |
| `hour`  | Past hour — use for real-time data such as breaking news or live events |
| `day`   | Past 24 hours                                                           |
| `week`  | Past 7 days                                                             |
| `month` | Past 30 days                                                            |
| `year`  | Past 365 days                                                           |

For exact ranges, use `search_after_date_filter` / `search_before_date_filter` (publication date) or `last_updated_after_filter` / `last_updated_before_filter` (last update). Date filter values must use the `MM/DD/YYYY` format (e.g., `"03/01/2026"`).

### Location filter

`user_location` accepts any combination of the following fields:

* `country` — Two-letter [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) code (for example, `"US"`, `"FR"`).
* `region` — Region or state name (for example, `"California"`).
* `city` — City name (for example, `"San Francisco"`).
* `latitude` and `longitude` — Coordinates for precise targeting.

<Tip>
  `city` and `region` significantly improve location accuracy. Include them alongside `country` whenever possible.
</Tip>

<Warning>
  `latitude` and `longitude` must be provided together with `country`. They cannot be supplied on their own.
</Warning>

### Filter Usage Cheatsheet

Copy any of these snippets into a `web_search` tool object. `user_location` sits alongside `filters`, while the other controls sit inside `filters`.

| Filter               | Example                                                                                                          |
| -------------------- | ---------------------------------------------------------------------------------------------------------------- |
| Domain allowlist     | `filters: { search_domain_filter: ["docs.perplexity.ai", "developer.mozilla.org"] }`                             |
| Domain denylist      | `filters: { search_domain_filter: ["-reddit.com", "-pinterest.com"] }`                                           |
| Recency              | `filters: { search_recency_filter: "week" }`                                                                     |
| Published date range | `filters: { search_after_date_filter: "01/01/2026", search_before_date_filter: "05/01/2026" }`                   |
| Last updated range   | `filters: { last_updated_after_filter: "01/01/2026", last_updated_before_filter: "05/01/2026" }`                 |
| User location        | `user_location: { country: "US", region: "CA", city: "San Francisco", latitude: 37.7749, longitude: -122.4194 }` |

<Tip>
  Filters compose freely. Combine any of the source, date, recency, and location filters above in a single `web_search` tool object — there's no per-request limit on filter combinations.
</Tip>

<CodeGroup>
  ```python Python theme={null}
  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="What were the binding obligations of President Biden's 2023 Executive Order 14110 on AI?",
      tools=[
          {
              "type": "web_search",
              "search_context_size": "medium",
              "filters": {
                  "search_domain_filter": [".gov"],
                  "search_recency_filter": "month"
              },
              "user_location": {
                  "country": "US"
              }
          }
      ],
  )
  ```

  ```typescript Typescript theme={null}
  const response = await client.responses.create({
    model: 'openai/gpt-5.6-sol',
    input: 'What were the binding obligations of President Biden\'s 2023 Executive Order 14110 on AI?',
    tools: [
      {
        type: 'web_search' as const,
        search_context_size: 'medium',
        filters: {
          search_domain_filter: ['.gov'],
          search_recency_filter: 'month',
        },
        user_location: {
          country: 'US',
        },
      },
    ],
  });
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "input": "What were the binding obligations of President Biden\u0027s 2023 Executive Order 14110 on AI?",
      "tools": [
        {
          "type": "web_search",
          "search_context_size": "medium",
          "filters": {
            "search_domain_filter": [".gov"],
            "search_recency_filter": "month"
          },
          "user_location": {
            "country": "US"
          }
        }
      ]
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "11c1c78d-b8c8-4442-8563-a79b7faac177",
    "results": [
      {
        "snippet": "**Executive Order 14110**, titled **Executive Order on Safe, Secure, and Trustworthy Development and Use of Artificial Intelligence** (sometimes referred to as \"**Executive Order on Artificial Intelligence**\") was the 126th executive order signed by former U.S. President Joe Biden.\nSigned on October 30, 2023, the order defines the administration's policy goals regarding artificial intelligence (AI), and orders executive agencies to take actions pursuant to these goals.\nThe order is considered to be the most comprehensive piece of governance by the United States regarding AI.\nIt was rescinded by U.S. President Donald Trump within hours of his assuming office on January 20, 2025.\nPolicy goals outlined in the executive order pertain to promoting competition in the AI industry, preventing AI-enabled threats to civil liberties and national security, and ensuring U.S. global competitiveness in the AI field.\nThe executive order required a number of major federal agencies to create dedicated \"chief artificial intelligence officer\" positions within their organizations.\n...\nThe order has been characterized as an effort for the United States to capture potential benefits from AI while mitigating risks associated with AI technologies.\n...\nPolicy goals outlined by the order include the following:\n- Promoting competition and innovation in the AI industry\n- Upholding civil and labor rights and protecting consumers and their privacy from AI-enabled harms\n- Specifying federal policies governing procurement and use of AI\n- Developing watermarking systems for AI-generated content and warding off intellectual property theft stemming from the use of generative models\n- Maintaining the nation's place as a global leader in AI\n## Impact on agencies\n...\nThe executive order required a number of large federal agencies to appoint a chief artificial intelligence officer, with a number of departments having already appointed a relevant officer prior to the order.\n...\nUnder the executive order, the Department of Homeland Security (DHS) was responsible for developing AI-related security guidelines, including cybersecurity-related matters.\nThe DHS will also work with private sector firms in sectors including the energy industry and other \"critical infrastructure\" to coordinate responses to AI-enabled security threats.\nExecutive Order 14110 mandated the Department of Veterans Affairs to launch an AI technology competition aimed at reducing occupational burnout among healthcare workers through AI-assisted tools for routine tasks.\nThe order also mandated the Department of Commerce's National Institute of Standards and Technology (NIST) to develop a generative artificial intelligence-focused resource to supplement the existing AI Risk Management Framework.\n...\nThe executive order has been described as the most comprehensive piece of governance by the United States government pertaining to AI.\nEarlier in 2023 prior to the signing of the order, the Biden administration had announced a Blueprint for an AI Bill of Rights, and had secured non-binding AI safety commitments from major tech companies.\n...\nAccording to *Axios*, despite the wide scope of the executive order, it notably does not touch upon a number of AI-related policy proposals.\nThis includes proposals for a \"licensing regime\" to government advanced AI models, which has received support from industry leaders including Sam Altman.\nAdditionally, the executive order does not seek to prohibit 'high-risk' uses of AI technology, and does not aim to mandate that tech companies release information surrounding AI systems' training data and models.",
        "title": "Executive Order 14110 - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Executive_Order_14110",
        "date": "2023-11-13",
        "last_updated": "2026-03-21"
      },
      {
        "snippet": "",
        "title": "657",
        "url": "https://www.govinfo.gov/content/pkg/CFR-2024-title3-vol1/pdf/CFR-2024-title3-vol1-eo14110.pdf",
        "date": null,
        "last_updated": "2025-01-28"
      },
      {
        "snippet": "",
        "title": "Federal Register, Volume 88 Issue 210 (Wednesday, November 1 ...",
        "url": "https://www.govinfo.gov/content/pkg/FR-2023-11-01/html/2023-24283.htm",
        "date": null,
        "last_updated": "2026-03-08"
      },
      {
        "snippet": "",
        "title": "1",
        "url": "https://www.govinfo.gov/content/pkg/DCPD-202300949/pdf/DCPD-202300949.pdf",
        "date": null,
        "last_updated": "2025-01-16"
      },
      {
        "snippet": "",
        "title": "Presidential Documents",
        "url": "https://upload.wikimedia.org/wikipedia/commons/e/ef/Executive_Order_14110.pdf",
        "date": null,
        "last_updated": "2025-12-17"
      },
      {
        "snippet": "",
        "title": "Executive Order 14110 - Wikisource, the free online library",
        "url": "https://en.wikisource.org/wiki/Executive_Order_14110",
        "date": "2023-11-13",
        "last_updated": "2025-03-10"
      },
      {
        "snippet": "Today, President Biden is issuing a landmark Executive Order to ensure that America leads the way in seizing the promise and managing the risks of artificial intelligence (AI).\nThe Executive Order establishes new standards for AI safety and security, protects Americans’ privacy, advances equity and civil rights, stands up for consumers and workers, promotes innovation and competition, advances American leadership around the world, and more.\n...\nThe Executive Order directs the following actions:**New Standards for AI Safety and Security**\nAs AI’s capabilities grow, so do its implications for Americans’ safety and security.\n**With this Executive Order, the** ** President directs the ** **most sweeping ** **actions ** **ever taken ** **to protect Americans from ** **the potential ** **risks ** **of ** **AI** ** systems** **:**\n- **Require that developers of the most powerful AI systems share their safety test results and other critical information with the U.S. government.** In accordance with the Defense Production Act, the Order will require that companies developing any foundation model that poses a serious risk to national security, national economic security, or national public health and safety must notify the federal government when training the model, and must share the results of all red-team safety tests.\nThese measures will ensure AI systems are safe, secure, and trustworthy before companies make them public.\n- **Develop standards, tools, and tests to help ensure that AI systems are safe, secure, and trustworthy.** The National Institute of Standards and Technology will set the rigorous standards for extensive red-team testing to ensure safety before public release.\nThe Department of Homeland Security will apply those standards to critical infrastructure sectors and establish the AI Safety and Security Board.\nThe Departments of Energy and Homeland Security will also address AI systems’ threats to critical infrastructure, as well as chemical, biological, radiological, nuclear, and cybersecurity risks.\nTogether, these are the most significant actions ever taken by any government to advance the field of AI safety.\n- **Protect against the risks of using AI to engineer dangerous biological materials** by developing strong new standards for biological synthesis screening.\nAgencies that fund life-science projects will establish these standards as a condition of federal funding, creating powerful incentives to ensure appropriate screening and manage risks potentially made worse by AI.\n- **Protect Americans from AI-enabled fraud and deception by establishing standards and best practices for detecting AI-generated content and authenticating official content**.\nThe Department of Commerce will develop guidance for content authentication and watermarking to clearly label AI-generated content.\nFederal agencies will use these tools to make it easy for Americans to know that the communications they receive from their government are authentic—and set an example for the private sector and governments around the world.\n- **Establish an advanced cybersecurity program to develop AI tools to find and fix vulnerabilities in critical software,** building on the Biden-Harris Administration’s ongoing AI Cyber Challenge.\nTogether, these efforts will harness AI’s potentially game-changing cyber capabilities to make software and networks more secure.\n- **Order the development of a National Security Memorandum that directs further actions on AI and security,** to be developed by the National Security Council and White House Chief of Staff.\nThis document will ensure that the United States military and intelligence community use AI safely, ethically, and effectively in their missions, and will direct actions to counter adversaries’ military use of AI.\n...\n**To better protect Americans’ privacy, including from the risks posed by AI, the President calls on Congress to pass bipartisan data privacy legislation to protect all Americans, especially kids, and directs the following actions:**\n- **Protect Americans’ privacy by prioritizing federal support for accelerating the development and use of privacy-preserving techniques—** including ones that use cutting-edge AI and that let AI systems be trained while preserving the privacy of the training data.\n- **Strengthen privacy-preserving research** **and technologies,** such as cryptographic tools that preserve individuals’ privacy, by funding a Research Coordination Network to advance rapid breakthroughs and development.\nThe National Science Foundation will also work with this network to promote the adoption of leading-edge privacy-preserving technologies by federal agencies.\n- **Evaluate how agencies collect and use commercially available information**—including information they procure from data brokers—and**strengthen privacy guidance for federal agencies** to account for AI risks.\nThis work will focus in particular on commercially available information containing personally identifiable data.\n- **Develop guidelines for federal agencies to evaluate the effectiveness of privacy-preserving techniques,** including those used in AI systems.\nThese guidelines will advance agency efforts to protect Americans’ data.\n**Advancing Equity and Civil Rights**\nIrresponsible uses of AI can lead to and deepen discrimination, bias, and other abuses in justice, healthcare, and housing.\nThe Biden-Harris Administration has already taken action by publishing the Blueprint for an AI Bill of Rights and issuing an Executive Order directing agencies to combat algorithmic discrimination, while enforcing existing authorities to protect people’s rights and safety.\n**To ensure that AI advances equity and civil rights, the President directs the following additional actions:**\n- **Provide clear guidance to landlords, Federal benefits programs, and federal contractors** to keep AI algorithms from being used to exacerbate discrimination.\n- **Address algorithmic discrimination** through training, technical assistance, and coordination between the Department of Justice and Federal civil rights offices on best practices for investigating and prosecuting civil rights violations related to AI.\n- **Ensure fairness throughout the criminal justice system** by developing best practices on the use of AI in sentencing, parole and probation, pretrial release and detention, risk assessments, surveillance, crime forecasting and predictive policing, and forensic analysis.\n...\n**To protect consumers while ensuring that AI can make Americans better off, the President directs the following actions:**\n- **Advance the responsible use of AI** in healthcare and the development of affordable and life-saving drugs.\nThe Department of Health and Human Services will also establish a safety program to receive reports of—and act to remedy – harms or unsafe healthcare practices involving AI.\n- **Shape AI’s potential to transform education** by creating resources to support educators deploying AI-enabled educational tools, such as personalized tutoring in schools.\n**Supporting Workers**\nAI is changing America’s jobs and workplaces, offering both the promise of improved productivity but also the dangers of increased workplace surveillance, bias, and job displacement.\n**To mitigate these risks, support workers’ ability to bargain collectively, and invest in workforce training and development that is accessible to all, the President directs the following actions:**\n- **Develop principles and best practices to mitigate the harms and maximize the benefits of AI for workers** by addressing job displacement; labor standards; workplace equity, health, and safety; and data collection.\nThese principles and best practices will benefit workers by providing guidance to prevent employers from undercompensating workers, evaluating job applications unfairly, or impinging on workers’ ability to organize.\n- **Produce a report on AI’s potential labor-market impacts**, and**study and identify options for strengthening federal support for workers facing labor disruptions**, including from AI.\n**Promoting Innovation and Competition**\n...\n**The Executive Order ensures that we continue to lead the way in innovation and competition through the following actions:**\n- **Catalyze AI research across the United States** through a pilot of the National AI Research Resource—a tool that will provide AI researchers and students access to key AI resources and data—and expanded grants for AI research in vital areas like healthcare and climate change.\n- **Promote a fair, open, and competitive AI ecosystem** by providing small developers and entrepreneurs access to technical assistance and resources, helping small businesses commercialize AI breakthroughs, and encouraging the Federal Trade Commission to exercise its authorities.\n- **Use existing authorities to expand the ability of highly skilled immigrants and nonimmigrants with expertise in critical areas to study, stay, and work in the United States** by modernizing and streamlining visa criteria, interviews, and reviews.\n...\nAI’s challenges and opportunities are global.\n**The Biden-Harris Administration will continue working with other nations to support safe, secure, and trustworthy deployment and use of AI worldwide.\nTo that end, the President directs the following actions:**\n- **Expand bilateral, multilateral, and multistakeholder engagements to collaborate on AI**.\nThe State Department, in collaboration, with the Commerce Department will lead an effort to establish robust international frameworks for harnessing AI’s benefits and managing its risks and ensuring safety.\nIn addition, this week, Vice President Harris will speak at the UK Summit on AI Safety, hosted by Prime Minister Rishi Sunak.\n- **Accelerate development and implementation of vital AI standards** with international partners and in standards organizations, ensuring that the technology is safe, secure, trustworthy, and interoperable.\n- **Promote the safe, responsible, and rights-affirming development and deployment of AI abroad to solve global challenges,** such as advancing sustainable development and mitigating dangers to critical infrastructure.\n**Ensuring Responsible and Effective Government Use of AI**\nAI can help government deliver better results for the American people.\nIt can expand agencies’ capacity to regulate, govern, and disburse benefits, and it can cut costs and enhance the security of government systems.\nHowever, use of AI can pose risks, such as discrimination and unsafe decisions.\n**To ensure the responsible government deployment of AI and modernize federal AI infrastructure, the President directs the following actions:**\n- **Issue guidance for agencies’ use of AI,** including clear standards to protect rights and safety, improve AI procurement, and strengthen AI deployment.\n- **Help agencies acquire specified AI products and services** faster, more cheaply, and more effectively through more rapid and efficient contracting.\n- **Accelerate the rapid hiring of AI professionals** as part of a government-wide AI talent surge led by the Office of Personnel Management, U.S. Digital Service, U.S. Digital Corps, and Presidential Innovation Fellowship.\nAgencies will provide AI training for employees at all levels in relevant fields.",
        "title": "FACT SHEET: President Biden Issues Executive Order on Safe, Secure, and Trustworthy Artificial Intelligence | The White House",
        "url": "https://web.archive.org/web/20250101021400/https:/www.whitehouse.gov/briefing-room/statements-releases/2023/10/30/fact-sheet-president-biden-issues-executive-order-on-safe-secure-and-trustworthy-artificial-intelligence/",
        "date": "2023-10-30",
        "last_updated": "2026-02-27"
      },
      {
        "snippet": "",
        "title": "Executive Order on the Safe, Secure, and Trustworthy Development ...",
        "url": "https://bidenwhitehouse.archives.gov/briefing-room/presidential-actions/2023/10/30/executive-order-on-the-safe-secure-and-trustworthy-development-and-use-of-artificial-intelligence/",
        "date": "2023-10-30",
        "last_updated": "2025-12-25"
      },
      {
        "snippet": "On October 30, 2023, United States President Joseph Biden signed Executive Order 14110 on the \"Safe, Secure, and Trustworthy Development and Use of Artificial Intelligence.\"^1^ The Order is the culmination of ongoing efforts by the Biden Administration to articulate its policies and priorities on AI.^2^ Sweeping in scope and addressing agencies across industries and sectors, the Order is premised on the understanding that \"[h]arnessing AI for good and realizing its myriad benefits requires mitigating its substantial risks.\"^3^\nWhile the Order applies primarily and most immediately to federal agencies, it includes an important provision for foundation model developers and more generally illustrates the Biden Administration's vision for how it intends to pursue AI development and regulation while federal legislation remains forthcoming.\n...\nSection 4 includes some of the Order's most novel and notable requirements, setting out detailed directives for the development of new standards, tools, testing protocols, and best practices for AI safety and security.\n- **Mandating the development of federal standards:** Section 4.1 provides that, within 270 days of the date of the Order (i.e., July 26, 2024), the National Institute of Standards and Technology (\"**NIST**\") shall establish guidelines and best practices, including setting standards for \"red-team testing,\" defined in Section 3 to mean structured testing efforts, often through adversarial methods, to identify flaws and vulnerabilities associated with the misuse of the AI system.\n-\n**Requiring developers of the most powerful AI systems to share safety tests results and other critical information with the U.S. government: ** Section 4.2 outlines reporting requirements for AI model owners and large data centers.\nThe Order directs the Secretary of Commerce, within 90 days of the date of the Order (i.e., January 28, 2024), to require \"companies developing or demonstrating an intent to develop potential dual-use foundation models\" (defined in Sec.\n3) to provide detailed information about their activities and models to the federal government on an ongoing basis.\nThis includes the results of any developed dual-use foundation model's performance in relevant AI red-team testing based on the guidance developed by NIST.^4^ By applying to \"companies developing or demonstrating an intent to develop\" such models, the Order seems to contemplate that information subject to the reporting requirements must be shared with the federal government before the relevant AI systems are made available to the public.\nWithin the same 90 days, the Secretary of Commerce is also directed to require companies to report their acquisition, development, or possession of large-scale computing clusters, including the existence and location of such clusters and the total amount of computing power available in each.^5^ Section 4.2(b) sets forth interim criteria to identify the minimum threshold for foundation models and computing clusters that would be subject to the reporting requirements.\n^6^ While Section 4.2 explicitly invokes the authority under the Defense Production Act, a law traditionally used during times of war or national emergencies such as the COVID-19 pandemic, it does not cite a specific provision.\n- **Developing methods to detect and denote AI-generated content: ** Section 4.5 articulates requirements for reducing the risks posed by \"synthetic\" – i.e., AI-generated – content.\nThe Order requires the Department of Commerce to develop guidance for content authentication and watermarking to clearly label AI-generated content.\nThe fact sheet on the Executive Order released by the White House specifies, \"Federal agencies will use these tools to make it easy for Americans to know that the communications they receive from their government are authentic—and set an example for the private sector and governments around the world.\"^7^\n...\nThe organizing principle of the Order is the Biden Administration's desire to balance the unique risks of AI against the novel benefits.\nWhile privacy is a recurring theme throughout the Order, Section 9 is dedicated to privacy and includes specific directives to strengthen privacy-protecting technologies.\nFor example, the Director of the Office of Management and Budget is directed to evaluate commercially available information (\"**CAI**\") procured by agencies, including CAI procured from data brokers and CAI procured and processed indirectly through vendors, with a particular emphasis on CAI that contains personally identifiable information.\n...\nDedicated to civil rights, Section 7 includes detailed directives to government agencies to address and prevent unlawful discrimination and other harms that may be exacerbated by AI in the criminal justice system, the administration of government benefits and programs, and other areas such as hiring and housing.\nSection 8 lays out additional protections for consumers, patients, passengers, and students.\nThe Order also devotes lengthy sections to the efforts the federal government must undertake to position the United States as a global leader in AI, including calls to catalyze AI research across the United States (see Sec.\n5.2) and encouraging the FTC to exercise its authorities to help small businesses commercialize AI breakthroughs (see Sec.\n5.3).\nWhile the Order includes directives to expand the recruitment efforts of \"AI talent,\" including highly skilled immigrants by updating and streamlining visa criteria and processing (see Sec.\n5.1), the Order also calls out the need to mitigate the harms of AI for workers (see Sec. 6).\nSection 11 directs the Secretary of State to expand engagement with international allies to advance global technical standards for AI development, among other initiatives.\n...\nVarious provisions within the Order provide that its directives must be implemented over the range of 90 days to one year, making clear the Government's priority that AI governance be treated with urgency.\nWhile federal legislation remains elusive, federal agencies implementing the Order may begin shaping AI regulation in the meantime.\n...\nThe Order articulates the following key principles and priorities: (1) AI must be safe and secure; (2) To lead in AI, the U.S. must promote responsible innovation, competition, and collaboration; (3) Responsible development and use of AI require a commitment to supporting American workers; (4) AI policies must advance equity and civil rights;",
        "title": "Biden Executive Order seeks to govern the “promise and peril” of AI",
        "url": "https://www.whitecase.com/insight-our-thinking/biden-executive-order-seeks-govern-promise-and-peril-ai",
        "date": "2023-11-03",
        "last_updated": "2026-03-21"
      },
      {
        "snippet": "",
        "title": "Key Provisions and Impacts of Biden's Executive Order on AI…",
        "url": "https://www.fenwick.com/insights/publications/key-provisions-and-impacts-of-bidens-executive-order-on-ai-regulation-and-development",
        "date": "2023-11-09",
        "last_updated": "2026-03-04"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

## Parameters

| Parameter             | Type    | Required | Description                                                                                                                          |
| --------------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `type`                | string  | Yes      | Must be `"web_search"`.                                                                                                              |
| `search_context_size` | string  | No       | Recommended token budget: `"low"`, `"medium"`, or `"high"`. See [Using Recommended Token Budgets](#using-recommended-token-budgets). |
| `filters`             | object  | No       | Domain, date, recency, and location filters. See [Filters](#filters).                                                                |
| `user_location`       | object  | No       | Location context for search personalization.                                                                                         |
| `max_results`         | integer | No       | Upper bound on results collected per call (1-50). See [Number of Results](#number-of-results).                                       |
| `max_tokens`          | integer | No       | Maximum total tokens for search context.                                                                                             |
| `max_tokens_per_page` | integer | No       | Maximum tokens extracted from each search result page.                                                                               |

## Response Shape

When `web_search` runs, the response can include a `search_results` output item before the final assistant message. The final `usage` object includes token counts, cost details, and `tool_calls_details.search_web.invocation` when tool-call usage is reported.

```json theme={null}
{
  "output": [
    {
      "type": "search_results",
      "queries": ["AI infrastructure announcements"],
      "results": [
        {
          "id": 1,
          "url": "https://example.com/news",
          "title": "Example AI infrastructure announcement",
          "snippet": "A short snippet from the search result.",
          "date": "2026-05-01",
          "last_updated": "2026-05-01",
          "source": "web"
        }
      ]
    },
    {
      "type": "message",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "The answer generated from the search results."
        }
      ]
    }
  ],
  "usage": {
    "input_tokens": 1200,
    "output_tokens": 300,
    "total_tokens": 1500,
    "tool_calls_details": {
      "search_web": {
        "invocation": 1
      }
    }
  }
}
```

Each entry in `results` includes the following fields:

| Field          | Type    | Description                                                     |
| -------------- | ------- | --------------------------------------------------------------- |
| `id`           | integer | Stable index used to reference the result in citations.         |
| `url`          | string  | Canonical URL of the source page.                               |
| `title`        | string  | Page title as returned by the source.                           |
| `snippet`      | string  | Excerpted text extracted from the page during search.           |
| `date`         | string  | Date the page was originally published, in `YYYY-MM-DD` format. |
| `last_updated` | string  | Date the page was last updated, in `YYYY-MM-DD` format.         |
| `source`       | string  | Origin of the result (for example, `"web"`).                    |

<Tip>
  **Want inline citations?** Whether the model adds markers to the answer is prompt-dependent, so ask for them explicitly - for example, append to your prompt: *"Cite your sources inline using bracketed markers, one source per bracket, like `[1][2]`."* Each number then refers to a result's `id`. Regardless of markers, treat the `id` and `url` fields of each `search_results` entry as the source of truth for citations.
</Tip>

## Pricing

`web_search` is billed at **\$2.50 per 1,000 invocations**. Model token usage is billed separately according to Agent API token pricing.

<Note>
  Pricing follows the same pattern as other tool calls: pay for tool invocations plus model tokens. See [Pricing](/docs/getting-started/pricing).
</Note>

## Limits / Quotas

`web_search` runs inside Agent API requests and is governed by Agent API request rate limits. See [Rate Limits & Usage Tiers](/docs/admin/rate-limits-usage-tiers#agent-api-rate-limits) for the current tier-based Agent API limits.

| Limit                 | Applies to                                                 | Guidance                                                                                                                            |
| --------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| Rate limits           | Agent API requests that include `web_search`               | Agent API tier limits apply to the request. Add retry and backoff handling for production traffic.                                  |
| Domain entries        | `search_domain_filter`                                     | Up to 20 domains or URLs per request. Use either allowlist or denylist mode as described in the [Filters](#filters) warning.        |
| Search context budget | `search_context_size`, `max_tokens`, `max_tokens_per_page` | `search_context_size` presets manage context automatically. Use explicit token caps when you need tighter cost or latency controls. |
| Tool-call billing     | `web_search` invocations                                   | Each search invocation counts toward tool-call usage and pricing, separate from model token usage.                                  |

## Next Steps

<CardGroup>
  <Card title="Fetch URL Content" icon="file-text" href="/docs/agent-api/tools/fetch-url-content">
    Fetch full content from known URLs.
  </Card>

  <Card title="People Search" icon="users" href="/docs/agent-api/tools/people-search">
    Search for professionals, employees, and people.
  </Card>

  <Card title="Agent API Presets" icon="settings" href="/docs/agent-api/presets">
    Use optimized presets for common Agent API workloads.
  </Card>

  <Card title="API Reference" icon="code-circle" href="/api-reference/agent-post">
    View complete endpoint documentation.
  </Card>
</CardGroup>


# Wide Research
Source: https://docs.perplexity.ai/docs/agent-api/wide-research

Run wide-and-deep research tasks with the wide-research preset — build large, evidence-backed collections in the background.

## Overview

`wide-research` is the preset for building large, evidence-backed collections. Point it at a task like "find every company that matches X and cite a source for each" and it discovers the qualifying entities and gathers supporting evidence for each one, then writes the results to a file you download.

This is the task shape measured by Perplexity's [WANDR benchmark](https://research.perplexity.ai/articles/wandr-benchmark-evaluating-research-agents-that-must-search-wide-and-deep) (Wide ANd Deep Research): discover a broad set of items (wide) and investigate each far enough to back every claim with a source (deep). It's a class of research the Agent API is built for — Perplexity's search-orchestration system leads the WANDR benchmark, and `wide-research` puts that same configuration behind a single preset.

## Quickstart

Wide research runs take minutes, so submit them with `background=true`, poll the response by id until it finishes, then download the file the agent produced.

<CodeGroup>
  ```python Python theme={null}
  import time
  from perplexity import Perplexity

  client = Perplexity()

  # 1. Submit in the background
  response = client.responses.create(
      preset="wide-research",
      background=True,
      input=(
          "Find at least 70 US-based companies with a CEO or CFO appointment first "
          "announced between March 1 and April 30, 2026. For each, cite an authoritative "
          "page that names the company and appointee and gives the role and date. Write "
          "the results to results.jsonl, one JSON record per line with fields: "
          "company, appointee, role, announcement_date, url."
      ),
  )

  # 2. Poll until the run reaches a terminal status
  while response.status not in ("completed", "failed", "cancelled", "incomplete"):
      time.sleep(5)
      response = client.responses.retrieve(response.id)

  # 3. Download every file the run produced
  for file in client.responses.files.list(response.id).data:
      client.responses.files.content(
          file_id=file.id, response_id=response.id
      ).write_to_file(file.filename)
  ```

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

  const client = new Perplexity();

  // 1. Submit in the background
  let response = await client.responses.create({
    preset: 'wide-research',
    background: true,
    input:
      'Find at least 70 US-based companies with a CEO or CFO appointment first ' +
      'announced between March 1 and April 30, 2026. For each, cite an authoritative ' +
      'page that names the company and appointee and gives the role and date. Write ' +
      'the results to results.jsonl, one JSON record per line with fields: ' +
      'company, appointee, role, announcement_date, url.',
  });

  // 2. Poll until the run reaches a terminal status
  while (!['completed', 'failed', 'cancelled', 'incomplete'].includes(response.status)) {
    await new Promise((r) => setTimeout(r, 5000));
    response = await client.responses.retrieve(response.id);
  }

  // 3. List the files the run produced, then download each by id
  const files = await client.responses.files.list(response.id);
  for (const file of files.data) {
    console.log(file.id, file.filename, file.bytes);
  }
  ```

  ```bash cURL theme={null}
  # 1. Submit in the background — capture the response id
  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "preset": "wide-research",
      "background": true,
      "input": "Find at least 70 US-based companies with a CEO or CFO appointment first announced between March 1 and April 30, 2026. For each, cite an authoritative page that names the company and appointee and gives the role and date. Write the results to results.jsonl, one JSON record per line with fields: company, appointee, role, announcement_date, url."
    }'

  # 2. Poll by id until status is completed, failed, cancelled, or incomplete
  curl https://api.perplexity.ai/v1/agent/$RESPONSE_ID \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY"

  # 3. List and download the files the run produced
  curl https://api.perplexity.ai/v1/agent/$RESPONSE_ID/files \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY"

  curl https://api.perplexity.ai/v1/agent/$RESPONSE_ID/files/$FILE_ID/content \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -o results.jsonl
  ```
</CodeGroup>

## How it works

A wide-research run has three parts, each backed by its own feature page:

<Steps>
  <Step title="Submit in the background">
    Set `preset="wide-research"` and `background=true`, and pass the task as `input`. The submit call returns immediately with a response `id` and a `queued` status; the run continues server-side even if your client disconnects. See [Background mode](/docs/agent-api/background-mode).
  </Step>

  <Step title="Poll until it finishes">
    Retrieve the response by `id` until its `status` is terminal — `completed`, `failed`, `cancelled`, or `incomplete`. You can also stream the run live and reconnect after a drop; see [Background mode](/docs/agent-api/background-mode#stream-and-reconnect).
  </Step>

  <Step title="Download the results">
    The agent writes the collection to a file in the sandbox and delivers it, so it shows up as a `share_file` item in the response `output`. List and download it by response `id`. See [Working with files](/docs/agent-api/working-with-files).
  </Step>
</Steps>

<Tip>
  Wide-research quality tracks how precisely you specify the task. Give it a concrete target ("at least 70 companies"), clear qualification rules (dates, geography, thresholds), a required source per record, and an explicit output shape — name the file and list the exact fields per row. Structured, cited output is easier to verify and consume downstream.
</Tip>

## Next Steps

<CardGroup>
  <Card title="Background mode" icon="clock" href="/docs/agent-api/background-mode">
    Submit, poll, stream, and reconnect long-running runs.
  </Card>

  <Card title="Working with files" icon="file" href="/docs/agent-api/working-with-files">
    List and download the files a run produces.
  </Card>

  <Card title="Presets" icon="sliders" href="/docs/agent-api/presets">
    See every preset and what it configures.
  </Card>

  <Card title="WANDR Benchmark" icon="chart-bar" href="https://research.perplexity.ai/articles/wandr-benchmark-evaluating-research-agents-that-must-search-wide-and-deep">
    Read the research behind wide-and-deep evaluation.
  </Card>
</CardGroup>


# Working with Files
Source: https://docs.perplexity.ai/docs/agent-api/working-with-files

List and download files an Agent API response produced in the sandbox.

## Overview

Agent runs can produce files such as CSV, JSON, JSONL, and reports in the sandbox. When code the model runs in the `sandbox` tool writes a file and delivers it with the `share_file` tool, the response `output` array includes a `share_file` item. The file content is not returned inline — retrieve it separately with the response files endpoints, using the response `id`.

## Produce a file

Give the agent the `sandbox` tool and ask it to write a file. Here it generates a CSV of the latest AI news. Keep the resulting `response.id` — you use it to list and download the file.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      preset="xhigh",
      tools=[{"type": "sandbox"}],
      input=(
          "Find the 10 latest AI news stories and write them to ai_news.csv "
          "with columns: title, source, url, published_date. Deliver the file."
      ),
  )

  print(response.id, response.status)
  ```

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

  const client = new Perplexity();

  const response = await client.responses.create({
    preset: 'xhigh',
    tools: [{ type: 'sandbox' }],
    input:
      'Find the 10 latest AI news stories and write them to ai_news.csv ' +
      'with columns: title, source, url, published_date. Deliver the file.',
  });

  console.log(response.id, response.status);
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "preset": "xhigh",
      "tools": [{ "type": "sandbox" }],
      "input": "Find the 10 latest AI news stories and write them to ai_news.csv with columns: title, source, url, published_date. Deliver the file."
    }'
  ```
</CodeGroup>

<Note>
  For runs that take a while, submit with `background=true` and poll before listing files. See [Background mode](/docs/agent-api/background-mode).
</Note>

## List a response's files

`GET /v1/agent/{id}/files`

Use the response `id` from the run above to list the files it produced.

<CodeGroup>
  ```python Python theme={null}
  files = client.responses.files.list(response.id)

  for file in files.data:
      print(file.id, file.filename, file.bytes)
  ```

  ```typescript Typescript theme={null}
  const files = await client.responses.files.list(response.id);

  for (const file of files.data) {
    console.log(file.id, file.filename, file.bytes);
  }
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/agent/$RESPONSE_ID/files \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY"
  ```
</CodeGroup>

```json theme={null}
{
  "data": [
    {
      "bytes": 8002,
      "created_at": 1780923289,
      "filename": "ai_news.csv",
      "id": "9198548a-490b-4119-858f-fd3676b60319",
      "object": "file"
    }
  ],
  "object": "list"
}
```

| Field        | Type      | Description                                                   |
| ------------ | --------- | ------------------------------------------------------------- |
| `id`         | `string`  | File identifier, used to download; distinct from response id. |
| `filename`   | `string`  | Name the sandbox gave the file.                               |
| `bytes`      | `integer` | File size in bytes.                                           |
| `created_at` | `integer` | Unix timestamp when created.                                  |
| `object`     | `string`  | Always `file`.                                                |

## Download a file

`GET /v1/agent/{id}/files/{file_id}/content`

Use the file `id` to download its content. The file `id` is distinct from the response `id`.

<Note>
  This endpoint returns raw file bytes, not JSON. The response includes a `Content-Type` matching the file and a `Content-Disposition: attachment` header carrying the original filename.
</Note>

<CodeGroup>
  ```python Python theme={null}
  file = files.data[0]

  content = client.responses.files.content(
      file_id=file.id,
      response_id=response.id,
  )
  content.write_to_file(file.filename)
  ```

  ```typescript Typescript theme={null}
  import { writeFile } from 'node:fs/promises';

  const file = files.data[0];

  const content = await client.responses.files.content(file.id, {
    response_id: response.id,
  });
  await writeFile(file.filename, Buffer.from(await content.arrayBuffer()));
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/agent/$RESPONSE_ID/files/$FILE_ID/content \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -o ai_news.csv
  ```
</CodeGroup>

## Full example

Create a run that writes a file, then list and download everything it produced.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      preset="xhigh",
      tools=[{"type": "sandbox"}],
      input=(
          "Find the 10 latest AI news stories and write them to ai_news.csv "
          "with columns: title, source, url, published_date. Deliver the file."
      ),
  )

  for file in client.responses.files.list(response.id).data:
      content = client.responses.files.content(
          file_id=file.id,
          response_id=response.id,
      )
      content.write_to_file(file.filename)
      print(f"Downloaded {file.filename} ({file.bytes} bytes)")
  ```

  ```typescript Typescript theme={null}
  import { writeFile } from 'node:fs/promises';
  import Perplexity from '@perplexity-ai/perplexity_ai';

  const client = new Perplexity();

  const response = await client.responses.create({
    preset: 'xhigh',
    tools: [{ type: 'sandbox' }],
    input:
      'Find the 10 latest AI news stories and write them to ai_news.csv ' +
      'with columns: title, source, url, published_date. Deliver the file.',
  });

  const files = await client.responses.files.list(response.id);

  for (const file of files.data) {
    const content = await client.responses.files.content(file.id, {
      response_id: response.id,
    });
    await writeFile(file.filename, Buffer.from(await content.arrayBuffer()));
    console.log(`Downloaded ${file.filename} (${file.bytes} bytes)`);
  }
  ```
</CodeGroup>

## Next Steps

<CardGroup>
  <Card title="Sandbox" icon="box" href="/docs/agent-api/tools/sandbox" />

  <Card title="Background mode" icon="clock" href="/docs/agent-api/background-mode" />

  <Card title="Wide Research" icon="layer-group" href="/docs/agent-api/wide-research" />
</CardGroup>


# Perplexity CLI
Source: https://docs.perplexity.ai/docs/cli/overview

Install and use Perplexity's pplx command-line interface for web search and query-relevant page snippets from your terminal or coding agent.

The `pplx` CLI returns structured JSON from the Perplexity Search API, making it useful for shell pipelines, interactive terminal work, and coding agents that need current web results or query-relevant page snippets.

## Install

Open the agent in your project and send it this:

```text wrap theme={null}
Read https://github.com/perplexityai/api-platform-developers/blob/main/skills/pplx-cli/SKILL.md and install this skill, then use it to search the web from my terminal.
```

Without an agent, run the installer yourself:

```bash theme={null}
curl -fsSL https://github.com/perplexityai/perplexity-cli/releases/latest/download/install.sh | sh
```

## Authenticate

Every command needs a [Perplexity API key](https://console.perplexity.ai/group/keys).
Choose one authentication method:

<Tabs>
  <Tab title="Environment variable">
    ```bash theme={null}
    export PERPLEXITY_API_KEY="your_api_key_here"
    ```
  </Tab>

  <Tab title="Interactive login">
    ```bash theme={null}
    pplx auth login
    ```
  </Tab>
</Tabs>

## Search the web

```bash theme={null}
pplx search web "what is a bloom filter" -n 2
```

<Accordion title="Response">
  ```json wrap theme={null}
  {
    "total": 2,
    "hits": [
      {
        "url": "https://en.wikipedia.org/wiki/Bloom_filter",
        "title": "Bloom filter",
        "domain": "en.wikipedia.org",
        "snippet": "In computing, a **Bloom filter** is a space-efficient probabilistic data structure, conceived by Burton Howard ...",
        "summary": "In computing, a **Bloom filter** is a space-efficient probabilistic data structure, conceived by Burton Howard ...",
        "date": "2004-04-17",
        "last_updated": "2026-07-08",
        "trust": {
          "level": 2,
          "name": "trusted",
          "description": "is trusted for community-edited general knowledge and reference articles across education, science, history, and many non-controversial topics worldwide."
        }
      },
      {
        "url": "https://systemdesign.one/bloom-filters-explained/",
        "title": "Bloom Filters Explained - System Design",
        "domain": "systemdesign.one",
        "snippet": "## What is a bloom filter?\nA Bloom filter is a space-efficient probabilistic data structure that is used to te ...",
        "summary": "## What is a bloom filter?\nA Bloom filter is a space-efficient probabilistic data structure that is used to te ...",
        "date": "2023-03-06",
        "last_updated": "2026-07-13",
        "trust": {
          "level": 1,
          "name": "credible",
          "description": "is credible for personally authored software system design case studies and interview preparation content without formal institutional peer review."
        }
      }
    ]
  }
  ```
</Accordion>

<Info>
  `-n` defaults to `10`.
  Run `pplx search web --help` for the full flag list and a summary of the input and output shapes.
</Info>

### Filter results

These flags scope a search.
They are the Search API filters, so their behavior and limits are identical — see [domain filter](/docs/search/filters/domain-filter) and [date and time filters](/docs/search/filters/date-time-filters) for the details.

```bash theme={null}
pplx search web "AI inference hardware" \
  --domains arxiv.org,nvidia.com \
  --published-after-date 07/01/2026 \
  -n 5
```

| Flag                      | Format                                 | Description                                 | Example                                   |
| ------------------------- | -------------------------------------- | ------------------------------------------- | ----------------------------------------- |
| `--domains`               | Comma-separated hostnames              | Return results only from these domains      | `--domains arxiv.org,nvidia.com`          |
| `--excluded-domains`      | Comma-separated hostnames              | Drop results from these domains             | `--excluded-domains reddit.com,quora.com` |
| `--published-after-date`  | `MM/DD/YYYY`                           | Published on or after this date             | `--published-after-date 07/01/2026`       |
| `--published-before-date` | `MM/DD/YYYY`                           | Published on or before this date            | `--published-before-date 07/31/2026`      |
| `--updated-after-date`    | `MM/DD/YYYY`                           | Last modified on or after this date         | `--updated-after-date 07/01/2026`         |
| `--updated-before-date`   | `MM/DD/YYYY`                           | Last modified on or before this date        | `--updated-before-date 07/31/2026`        |
| `--recency-filter`        | `hour`, `day`, `week`, `month`, `year` | Relative window instead of explicit dates   | `--recency-filter week`                   |
| `--country`               | ISO 3166-1 alpha-2 code                | Region the search runs for, `US` by default | `--country DE`                            |

<Note>
  `--recency-filter` cannot be combined with `--published-after-date` or `--published-before-date`.
  That request fails with `BAD_REQUEST`.
</Note>

### Ask the same question several ways

Extra positional queries are rephrasings of one question, not separate searches.
The CLI still returns a single ranked result set, but wording the question more than one way surfaces pages that only match the phrasing you did not think of first:

```bash theme={null}
pplx search web \
  "kubernetes pod OOMKilled causes" \
  "why does k8s keep killing my pod with OOMKilled"
```

### Save full results

Save the complete result while keeping stdout small:

```bash theme={null}
pplx search web "kubernetes pod OOMKilled causes" \
  --output-dir out \
  --stdout-preview=200
```

The full response is written under `out/web/`, and stdout includes its path in `saved_to`.
`--stdout-preview` only truncates stdout when you also set `--output-dir` or `PPLX_OUTPUT_DIR`.
Cut strings end in `...<truncated>` and the response gains a top-level `"truncated": true`.

### Search errors

A search either succeeds or fails outright: on failure nothing reaches stdout and the JSON error object goes to stderr.
The search-specific code is `BAD_REQUEST`, which the service returns when the filters contradict each other, as with `--recency-filter` alongside a publication-date bound.
Everything else you can hit here is a [common error](#handle-errors).

## Generate query-relevant snippets

Extract the passages of a page that are relevant to a query, instead of retrieving the whole page:

```bash theme={null}
pplx content snippets "how does a bloom filter decide set membership" \
  https://en.wikipedia.org/wiki/Bloom_filter
```

<Accordion title="Response">
  ```json wrap theme={null}
  {
    "results": [
      {
        "url": "https://en.wikipedia.org/wiki/Bloom_filter",
        "text": "In computing, a **Bloom filter** is a space-efficient probabilistic data structure, conceived by Burton Howard Bloom in 1970, that is used to test whether an element is a member of a set. False positive matches are possible, but false negatives are not ...",
        "tokens_count": 1047
      }
    ]
  }
  ```
</Accordion>

`text` keeps only the query-relevant passages of the page; elided regions in between are marked with the `…` character.

<Info>
  `content snippets` requires CLI v0.2.3 or later.
  On an older binary, run `pplx update` first.
</Info>

<Note>
  `pplx content fetch` is deprecated and will stop working; use `content snippets`.
</Note>

### Cover several pages in one call

Extra positional URLs are additional pages, not rephrasings: unlike `pplx search web`, where extra positional arguments reword one question, each URL here is snipped independently against the same query.
One call takes up to 50 URLs:

```bash theme={null}
pplx content snippets "bloom filter false positive rate" \
  https://en.wikipedia.org/wiki/Bloom_filter \
  https://systemdesign.one/bloom-filters-explained/ \
  --max-tokens-per-page 256
```

<Accordion title="Response">
  ```json wrap theme={null}
  {
    "results": [
      {
        "url": "https://en.wikipedia.org/wiki/Bloom_filter",
        "text": "More generally, fewer than 10 bits per element are required for a 1% false positive probability, independent of the size or number of elements in the set.\n\n…\n\nIf all are 1, then either the element is in the set, *or* the bits have by chance been set to 1 during the insertion of other elements, resulting in a false positive. ...",
        "tokens_count": 261
      },
      {
        "url": "https://systemdesign.one/bloom-filters-explained/",
        "text": "### Bloom filter false positive\n\nIn Figure 5, the bloom filter is queried to check the membership of item *green*, which is not a member of the bloom filter. ...",
        "tokens_count": 262
      }
    ]
  }
  ```
</Accordion>

### Budget the tokens

Two flags cap how much text comes back.

| Flag                    | Range       | Default                 | Description                                                                  |
| ----------------------- | ----------- | ----------------------- | ---------------------------------------------------------------------------- |
| `--max-tokens`          | `1`–`16384` | `4096`                  | Maximum total tokens across all snippets                                     |
| `--max-tokens-per-page` | `1`–`4096`  | `min(1024, max_tokens)` | Maximum tokens for any single page's snippet; must not exceed `--max-tokens` |

Budgets are approximate: a snippet can run a few tokens over its cap, as the `tokens_count` values above show.

### Snippet errors

`pplx content snippets` reports failure per URL, not per command.
A page that cannot be snipped does not fail the run: the command still exits `0`, and that URL's result carries an `error` message with no `text`.

```bash theme={null}
pplx content snippets "example domain reserved documentation" \
  https://www.iana.org/help/example-domains \
  https://www.example.com/nonexistent/
```

<Accordion title="Response">
  ```json wrap theme={null}
  {
    "results": [
      {
        "url": "https://www.iana.org/help/example-domains",
        "text": "1. Instructions and Guides\n\n# Example Domains\n\nAs described in RFC 2606 and RFC 6761, a number of domains such as example.com and example.org are maintained for documentation purposes. ...",
        "tokens_count": 152
      },
      {
        "url": "https://www.example.com/nonexistent/",
        "error": "no snippet could be generated under the requested token budget"
      }
    ]
  }
  ```
</Accordion>

Check every result for `error` before trusting its `text`, because a successful invocation does not mean every page produced a snippet.

### Keep large responses out of stdout

Snippets across many URLs still add up.
`--output-dir` writes the full response under `<dir>/snippets/`, and `--stdout-preview` truncates the long strings on stdout:

```bash theme={null}
pplx content snippets "how does a bloom filter decide set membership" \
  https://en.wikipedia.org/wiki/Bloom_filter \
  --output-dir out \
  --stdout-preview=200
```

<Accordion title="Response">
  ```json wrap theme={null}
  {
    "results": [
      {
        "url": "https://en.wikipedia.org/wiki/Bloom_filter",
        "text": "In computing, a **Bloom filter** is a space-efficient probabilistic data structure, conceived by Burton Howard Bloom in 1970, that is used to test whether an element is a member of a set. False positi...<truncated>",
        "tokens_count": 1047
      }
    ],
    "saved_to": "out/snippets/c6989ad7.json",
    "truncated": true
  }
  ```
</Accordion>

Stdout carries the saved path in `saved_to` plus `"truncated": true`, so the terminal stays readable while the complete text sits on disk.

## Handle errors

These are the failures common to every `pplx` command.
A failed command writes one JSON error object to stderr:

```json theme={null}
{
  "error": {
    "code": "AUTHENTICATION",
    "message": "...",
    "command": "search.web",
    "hint": "Set the PERPLEXITY_API_KEY environment variable"
  }
}
```

Branch on `error.code`.

<Accordion title="Error codes">
  | Code                                         | Raised when                                                                                 |
  | -------------------------------------------- | ------------------------------------------------------------------------------------------- |
  | `AUTHENTICATION`                             | No key is configured, or the key is invalid                                                 |
  | `FORBIDDEN`                                  | The key does not have access to what you requested                                          |
  | `RATE_LIMIT`                                 | You are over your rate limit                                                                |
  | `BAD_REQUEST`                                | The service rejected the request, for example `--recency-filter` combined with a date bound |
  | `VALIDATION`                                 | The service rejected a field value                                                          |
  | `NOT_FOUND`                                  | The requested resource does not exist                                                       |
  | `TIMEOUT`                                    | The request took too long                                                                   |
  | `CONNECT`                                    | The CLI could not reach the API                                                             |
  | `INTERNAL_SERVER`                            | The service failed                                                                          |
  | `UNKNOWN_ARGUMENT`                           | The flag does not exist on this command                                                     |
  | `INVALID_VALUE`, `VALUE_VALIDATION`          | A flag value is malformed or out of range                                                   |
  | `MISSING_REQUIRED_ARGUMENT`, `MISSING_QUERY` | A required argument or the query is missing                                                 |
  | `ARGUMENT_ERROR`                             | Any other argument-parsing failure                                                          |
</Accordion>

Run `pplx <command> --help` before assuming that a flag exists; CLI output is already JSON, so no `--json` flag is needed.

## Next steps

See the [`perplexity-cli` repository](https://github.com/perplexityai/perplexity-cli) for release notes, manual installation, and uninstall instructions.


# Academic and Scholarly Search
Source: https://docs.perplexity.ai/docs/cookbook/articles/academic-search/README

Use the Agent API's domain filtering to restrict search to academic sources, extract DOIs and paper metadata, build citation chains, and create research summaries with proper attribution

This guide shows how to use the Agent API's `search_domain_filter` to restrict search results to academic and scholarly sources. You will learn how to extract paper metadata (DOIs, authors, publication dates), build citation chains across related papers, and produce properly attributed research summaries.

<Info>
  The `search_domain_filter` parameter on the Agent API's `web_search` tool controls which domains the search draws from. By filtering to academic domains like `arxiv.org`, `nature.com`, and `.edu`, you restrict results to peer-reviewed journals, preprint servers, and academic databases. For more on filtering, see the [Agent API Filters](/docs/agent-api/tools/web-search#filters) docs.
</Info>

## Prerequisites

Install the Perplexity SDK:

<CodeGroup>
  ```bash Python theme={null}
  pip install perplexityai
  ```

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

If you don't have an API key yet:

<Card title="Get your Perplexity API Key" icon="key" href="https://perplexity.ai/account/api">
  Navigate to the **API Keys** tab in the API Portal and generate a new key.
</Card>

Then export your API key as an environment variable:

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

## Basic Academic Search

Use `search_domain_filter` to restrict the Agent API's `web_search` tool to academic sources only.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  ACADEMIC_DOMAINS = [
      "arxiv.org",
      "pubmed.ncbi.nlm.nih.gov",
      "nature.com",
      "science.org",
      ".edu",
      "scholar.google.com",
      "semanticscholar.org",
  ]

  response = client.responses.create(
      model="openai/gpt-5.4",
      input="What are the latest findings on the relationship between gut microbiome and mental health?",
      tools=[{
          "type": "web_search",
          "filters": {
              "search_domain_filter": ACADEMIC_DOMAINS,
          },
      }],
      instructions="Focus on peer-reviewed academic sources. Cite papers with authors and publication years when possible.",
  )

  print(response.output_text)
  ```

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

  const client = new Perplexity();

  const ACADEMIC_DOMAINS = [
      "arxiv.org",
      "pubmed.ncbi.nlm.nih.gov",
      "nature.com",
      "science.org",
      ".edu",
      "scholar.google.com",
      "semanticscholar.org",
  ];

  const response = await client.responses.create({
      model: "openai/gpt-5.4",
      input: "What are the latest findings on the relationship between gut microbiome and mental health?",
      tools: [{
          type: "web_search" as const,
          filters: {
              search_domain_filter: ACADEMIC_DOMAINS,
          },
      }],
      instructions: "Focus on peer-reviewed academic sources. Cite papers with authors and publication years when possible.",
  });

  console.log(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 '{
      "model": "openai/gpt-5.4",
      "input": "What are the latest findings on the relationship between gut microbiome and mental health?",
      "tools": [{"type": "web_search", "filters": {"search_domain_filter": ["arxiv.org", "pubmed.ncbi.nlm.nih.gov", "nature.com", "science.org", ".edu"]}}],
      "instructions": "Focus on peer-reviewed academic sources. Cite papers with authors and publication years when possible."
    }'
  ```
</CodeGroup>

<Tip>
  Academic domain filtering targets papers from PubMed, arXiv, Google Scholar, Semantic Scholar, and major journal publishers. Combine `search_domain_filter` with clear `instructions` to ensure the model focuses on peer-reviewed or pre-print academic content.
</Tip>

## Extracting Paper Metadata

Use structured outputs to extract detailed paper metadata from academic search results.

<CodeGroup>
  ```python Python theme={null}
  import json
  from perplexity import Perplexity

  client = Perplexity()

  # Use Agent API with web_search for structured extraction
  response = client.responses.create(
      model="openai/gpt-5.4",
      input="Find the 5 most cited recent papers on transformer architectures in computer vision (Vision Transformers).",
      tools=[{"type": "web_search"}],
      instructions=(
          "Search for academic papers only. For each paper, extract the title, authors, "
          "publication year, journal or venue, DOI if available, and a one-sentence summary of the key contribution."
      ),
      response_format={
          "type": "json_schema",
          "json_schema": {
              "name": "academic_papers",
              "schema": {
                  "type": "object",
                  "properties": {
                      "query": {"type": "string"},
                      "papers": {
                          "type": "array",
                          "items": {
                              "type": "object",
                              "properties": {
                                  "title": {"type": "string"},
                                  "authors": {"type": "string"},
                                  "year": {"type": "integer"},
                                  "venue": {"type": "string"},
                                  "doi": {"type": "string"},
                                  "key_contribution": {"type": "string"},
                              },
                              "required": ["title", "authors", "year", "venue", "doi", "key_contribution"],
                              "additionalProperties": false,
                          },
                      },
                  },
                  "required": ["query", "papers"],
                  "additionalProperties": false,
              },
          },
      },
  )

  data = json.loads(response.output_text)
  print(f"Query: {data['query']}\n")

  for paper in data["papers"]:
      print(f"  {paper['title']}")
      print(f"    Authors: {paper['authors']}")
      print(f"    Venue: {paper['venue']} ({paper['year']})")
      if paper["doi"]:
          print(f"    DOI: {paper['doi']}")
      print(f"    Contribution: {paper['key_contribution']}")
      print()
  ```

  ```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.4",
      input: "Find the 5 most cited recent papers on transformer architectures in computer vision (Vision Transformers).",
      tools: [{ type: "web_search" }],
      instructions: "Search for academic papers only. For each paper, extract the title, authors, publication year, journal or venue, DOI if available, and a one-sentence summary of the key contribution.",
      response_format: {
          type: "json_schema",
          json_schema: {
              name: "academic_papers",
              schema: {
                  type: "object",
                  properties: {
                      query: { type: "string" },
                      papers: {
                          type: "array",
                          items: {
                              type: "object",
                              properties: {
                                  title: { type: "string" },
                                  authors: { type: "string" },
                                  year: { type: "integer" },
                                  venue: { type: "string" },
                                  doi: { type: "string" },
                                  key_contribution: { type: "string" },
                              },
                              required: ["title", "authors", "year", "venue", "doi", "key_contribution"],
                          },
                      },
                  },
                  required: ["query", "papers"],
              },
          },
      },
  });

  const data = JSON.parse(response.output_text);
  console.log(`Query: ${data.query}\n`);

  for (const paper of data.papers) {
      console.log(`  ${paper.title}`);
      console.log(`    Authors: ${paper.authors}`);
      console.log(`    Venue: ${paper.venue} (${paper.year})`);
      if (paper.doi) console.log(`    DOI: ${paper.doi}`);
      console.log(`    Contribution: ${paper.key_contribution}`);
      console.log();
  }
  ```
</CodeGroup>

## Building Citation Chains

Trace how papers cite each other to understand the evolution of an idea across the literature.

<CodeGroup>
  ```python Python theme={null}
  import json
  from perplexity import Perplexity

  client = Perplexity()


  def find_citing_papers(paper_title: str, depth: int = 0, max_depth: int = 2) -> dict:
      """Recursively find papers that cite a given paper."""
      indent = "  " * depth
      print(f"{indent}Searching citations for: {paper_title}...")

      response = client.responses.create(
          model="openai/gpt-5.4",
          input=f"What are the 3 most important papers that directly cite or build upon '{paper_title}'?",
          tools=[{"type": "web_search"}],
          instructions="Focus on academic papers only. Return papers that explicitly reference or extend the given work.",
          response_format={
              "type": "json_schema",
              "json_schema": {
                  "name": "citing_papers",
                  "schema": {
                      "type": "object",
                      "properties": {
                          "source_paper": {"type": "string"},
                          "citing_papers": {
                              "type": "array",
                              "items": {
                                  "type": "object",
                                  "properties": {
                                      "title": {"type": "string"},
                                      "authors": {"type": "string"},
                                      "year": {"type": "integer"},
                                      "relationship": {"type": "string"},
                                  },
                                  "required": ["title", "authors", "year", "relationship"],
                                  "additionalProperties": false,
                              },
                          },
                      },
                      "required": ["source_paper", "citing_papers"],
                      "additionalProperties": false,
                  },
              },
          },
      )

      data = json.loads(response.output_text)
      result = {
          "paper": paper_title,
          "cited_by": [],
      }

      for citing in data["citing_papers"]:
          entry = {
              "title": citing["title"],
              "authors": citing["authors"],
              "year": citing["year"],
              "relationship": citing["relationship"],
          }

          # Recurse for deeper citation chains
          if depth < max_depth:
              entry["cited_by"] = find_citing_papers(citing["title"], depth + 1, max_depth).get("cited_by", [])

          result["cited_by"].append(entry)

      return result


  # Start with a foundational paper
  chain = find_citing_papers("Attention Is All You Need", max_depth=1)
  print(json.dumps(chain, indent=2))
  ```
</CodeGroup>

<Warning>
  Citation chain depth grows exponentially. Keep `max_depth` low (1-2) to avoid excessive API calls. For comprehensive citation graphs, use dedicated tools like Semantic Scholar's API alongside Perplexity for summaries.
</Warning>

## Research Summary with Attribution

Generate a research summary that properly attributes each claim to its source paper.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  ACADEMIC_DOMAINS = [
      "arxiv.org", "pubmed.ncbi.nlm.nih.gov", "nature.com",
      "science.org", ".edu", "scholar.google.com",
  ]


  def academic_research_summary(topic: str) -> str:
      """Generate an academic research summary with proper citations."""
      response = client.responses.create(
          model="openai/gpt-5.4",
          input=(
              f"Provide a comprehensive academic literature review on: {topic}. "
              "Include specific findings, methodologies, and conclusions from recent papers. "
              "Cite each claim with its source."
          ),
          tools=[{
              "type": "web_search",
              "filters": {
                  "search_domain_filter": ACADEMIC_DOMAINS,
              },
          }],
          instructions=(
              "Search for peer-reviewed academic sources only. For each claim, "
              "attribute it to the specific paper with author names and year. "
              "Format the output as a structured literature review with a references section."
          ),
      )

      return f"# Literature Review: {topic}\n\n{response.output_text}"


  report = academic_research_summary(
      "the effectiveness of large language models for automated code review"
  )
  print(report)
  ```

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

  const client = new Perplexity();

  const ACADEMIC_DOMAINS = [
      "arxiv.org", "pubmed.ncbi.nlm.nih.gov", "nature.com",
      "science.org", ".edu", "scholar.google.com",
  ];

  async function academicResearchSummary(topic: string): Promise<string> {
      const response = await client.responses.create({
          model: "openai/gpt-5.4",
          input: `Provide a comprehensive academic literature review on: ${topic}. Include specific findings, methodologies, and conclusions from recent papers. Cite each claim with its source.`,
          tools: [{
              type: "web_search" as const,
              filters: {
                  search_domain_filter: ACADEMIC_DOMAINS,
              },
          }],
          instructions: "Search for peer-reviewed academic sources only. For each claim, attribute it to the specific paper with author names and year. Format the output as a structured literature review with a references section.",
      });

      return `# Literature Review: ${topic}\n\n${response.output_text}`;
  }

  const report = await academicResearchSummary(
      "the effectiveness of large language models for automated code review"
  );
  console.log(report);
  ```
</CodeGroup>

## Multi-Field Academic Search

Use field-specific domain filters to search across different academic disciplines.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  ACADEMIC_DOMAINS = {
      "biomedical": ["pubmed.ncbi.nlm.nih.gov", "nih.gov", "thelancet.com", "nejm.org"],
      "computer_science": ["arxiv.org", "dl.acm.org", "ieee.org", "openreview.net"],
      "social_science": ["jstor.org", "ssrn.com", "journals.sagepub.com"],
  }


  def field_specific_search(query: str, field: str) -> dict:
      """Search academic literature within a specific field."""
      domains = ACADEMIC_DOMAINS.get(field, [])

      response = client.responses.create(
          model="openai/gpt-5.4",
          input=query,
          tools=[{
              "type": "web_search",
              "filters": {
                  "search_domain_filter": domains,
              },
          }] if domains else [{"type": "web_search"}],
          instructions=f"Search for peer-reviewed academic sources in the {field.replace('_', ' ')} field. Cite papers with authors and years.",
      )

      return {
          "field": field,
          "content": response.output_text,
      }


  # Search across multiple fields
  query = "What are the ethical implications of AI-generated content?"
  fields = ["computer_science", "social_science"]

  for field in fields:
      result = field_specific_search(query, field)
      print(f"\n{'='*60}")
      print(f"Field: {result['field']}")
      print(f"{'='*60}")
      print(result["content"][:500])
  ```

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

  const client = new Perplexity();

  const ACADEMIC_DOMAINS: Record<string, string[]> = {
      biomedical: ["pubmed.ncbi.nlm.nih.gov", "nih.gov", "thelancet.com", "nejm.org"],
      computer_science: ["arxiv.org", "dl.acm.org", "ieee.org", "openreview.net"],
      social_science: ["jstor.org", "ssrn.com", "journals.sagepub.com"],
  };

  async function fieldSpecificSearch(query: string, field: string) {
      const domains = ACADEMIC_DOMAINS[field] ?? [];

      const response = await client.responses.create({
          model: "openai/gpt-5.4",
          input: query,
          tools: domains.length > 0
              ? [{ type: "web_search" as const, filters: { search_domain_filter: domains } }]
              : [{ type: "web_search" as const }],
          instructions: `Search for peer-reviewed academic sources in the ${field.replace("_", " ")} field. Cite papers with authors and years.`,
      });

      return {
          field,
          content: response.output_text,
      };
  }

  const query = "What are the ethical implications of AI-generated content?";
  const fields = ["computer_science", "social_science"];

  for (const field of fields) {
      const result = await fieldSpecificSearch(query, field);
      console.log(`\n${"=".repeat(60)}`);
      console.log(`Field: ${result.field}`);
      console.log("=".repeat(60));
      console.log(result.content.slice(0, 500));
  }
  ```
</CodeGroup>

## Tips and Best Practices

1. **Use `search_domain_filter` with academic domains** to restrict results to peer-reviewed sources. Target domains like `arxiv.org`, `nature.com`, `pubmed.ncbi.nlm.nih.gov`, and `.edu`.

2. **Use `instructions` to guide academic focus.** Tell the model to prioritize peer-reviewed papers, cite authors and years, and focus on specific fields.

3. **Use field-specific domain lists** to narrow results to specific publishers or databases (e.g., PubMed for biomedical, arXiv for CS).

4. **Use structured outputs** for metadata extraction. JSON schemas ensure consistent paper metadata across queries.

5. **Request specific details in your prompt.** Ask for "authors, year, journal, and key findings" to get more complete metadata in the response.

6. **Combine `search_domain_filter` with `search_recency_filter`** for time-sensitive research. Use `"week"`, `"month"`, or `"year"` to find recent publications.

## Next Steps

<CardGroup>
  <Card title="Agent API Filters" icon="filter" href="/docs/agent-api/tools/web-search#filters">
    Full reference for domain, recency, and location filters on the Agent API.
  </Card>

  <Card title="Structured Outputs" icon="adjustments" href="/docs/cookbook/articles/structured-output-extraction/README">
    Extract typed JSON for paper metadata and research findings.
  </Card>

  <Card title="Domain Filtering" icon="filter" href="/docs/cookbook/articles/search-domain-filtering/README">
    Control which domains the search includes or excludes.
  </Card>
</CardGroup>


# Daily AI Stock News PDF with Skills
Source: https://docs.perplexity.ai/docs/cookbook/articles/agent-skills/README

Generate a daily one-page AI-industry stock news PDF with the Agent API using the built-in office skill and an inline design skill.

Build a repeatable end-of-day report for the AI-industry stocks you track. Each run produces a one-page PDF with today's prices, the day's moves, and the news that moved them — all rendered in your own house style.

The recipe uses two skills:

* **Built-in `office`** — the umbrella that lets the model pick the right document format (PDF, in this case).
* **Inline `design-system`** — a request-scoped skill that carries your colors, fonts, and layout rules.

See [Skills](/docs/agent-api/skills) for the full request schema and runtime behavior.

## Prerequisites

Install one SDK:

* Python: `pip install perplexityai`
* TypeScript: `npm install @perplexity-ai/perplexity_ai`

If you do not have an API key yet:

<Card title="Get your Perplexity API Key" icon="key" href="https://perplexity.ai/account/api">
  Navigate to the **API Keys** tab in the API Portal and generate a new key.
</Card>

Export your API key:

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

## Define the design skill

The inline `design-system` skill tells the model how the report should look. Its `description` is the routing trigger — one line telling the model when to load it. The `instructions` carry the full design book.

Keep the design book short and directive. The model reads it once, per request, and applies it while generating the document.

```text theme={null}
Load when creating documents that must follow the house design book.

Model: a 1970s letterpress broadsheet financial page. One ink, gray paper.

Colors
- Paper #EDE9DE; tinted boxes and alternating table rows #E3DFD2.
- Body ink #232220 — soft, never hard black (ink spread on newsprint).
- Headlines and rules may deepen to #141311; faded ink #5C5850 for captions and secondary text.
- No second color anywhere. Up moves: bold with a ▲. Down moves: parentheses with a ▼.

Typography
- Body: low-contrast newspaper serif (Georgia, PT Serif, or Times), 9-10pt, justified and hyphenated.
- Headlines: bold condensed serif with a smaller deck beneath.
- Kickers and table headers: condensed grotesque caps (Franklin Gothic or Oswald), letterspaced.
- Tables: agate style — 7-8pt condensed, tabular figures.

Layout
- One page, ~18mm margins.
- Nameplate in blackletter or heavy serif, with a folio line (date, edition, price) set between an Oxford rule (thick over hairline).
- Ticker summary as a boxed agate strip below the nameplate.
- News timeline in 3-4 narrow justified columns divided by hairline column rules; each item opens with a bold caps dateline ('LONDON, JULY 17 —').
- Data table ruled with hairlines only.
- Pack the page — separate blocks with cutoff rules, not white space.

Imagery
- Grayscale halftone only, with a hairline keyline and an italic caption.

Avoid
- Second colors, gradients, shadows, rounded corners, sans-serif body text, and generous white space.
```

## Generate today's report

Combine the `office` umbrella with the inline `design-system` skill. The prompt names the tickers and asks for today's move plus dated news tagged to the ticker each item moved.

Skills run on the durable backend, so submit with `background: true` and poll `GET /v1/agent/{id}` until the status is terminal.

<CodeGroup>
  ```python Python theme={null}
  import time
  from datetime import date
  from perplexity import Perplexity

  client = Perplexity()

  design_book = """
  Load when creating documents that must follow the house design book.

  Model: a 1970s letterpress broadsheet financial page. One ink, gray paper.

  Colors
  - Paper #EDE9DE; tinted boxes and alternating table rows #E3DFD2.
  - Body ink #232220 — soft, never hard black (ink spread on newsprint).
  - Headlines and rules may deepen to #141311; faded ink #5C5850 for captions and secondary text.
  - No second color anywhere. Up moves: bold with a ▲. Down moves: parentheses with a ▼.

  Typography
  - Body: low-contrast newspaper serif (Georgia, PT Serif, or Times), 9-10pt, justified and hyphenated.
  - Headlines: bold condensed serif with a smaller deck beneath.
  - Kickers and table headers: condensed grotesque caps (Franklin Gothic or Oswald), letterspaced.
  - Tables: agate style — 7-8pt condensed, tabular figures.

  Layout
  - One page, ~18mm margins.
  - Nameplate in blackletter or heavy serif, with a folio line (date, edition, price) set between an Oxford rule (thick over hairline).
  - Ticker summary as a boxed agate strip below the nameplate.
  - News timeline in 3-4 narrow justified columns divided by hairline column rules; each item opens with a bold caps dateline ('LONDON, JULY 17 —').
  - Data table ruled with hairlines only.
  - Pack the page — separate blocks with cutoff rules, not white space.

  Imagery
  - Grayscale halftone only, with a hairline keyline and an italic caption.

  Avoid
  - Second colors, gradients, shadows, rounded corners, sans-serif body text, and generous white space.
  """

  response = client.responses.create(
      preset="xhigh",
      background=True,
      skills=[
          {
              "type": "inline",
              "name": "design-system",
              "description": "Load when creating documents that must follow the house design book.",
              "instructions": design_book,
          },
          {"type": "builtin", "name": "office"},
      ],
      input=(
          f"Create a one-page PDF titled 'AI Stocks Daily' for {date.today():%Y-%m-%d}. "
          "Cover NVDA, MSFT, GOOGL, AMD, AVGO, META, and TSM. For each ticker "
          "include latest price and today's % change. Add a dated timeline of "
          "today's key AI news, tag each item to the ticker it moved, and "
          "finish with a data table (ticker, price, day change, week change). "
          "Follow the design-system skill."
      ),
  )

  while response.status not in ("completed", "failed", "cancelled", "incomplete"):
      time.sleep(2)
      response = client.responses.retrieve(response.id)

  print(f"Final status: {response.status}")

  if response.status == "completed":
      files = client.responses.files.list(response.id)
      for file in files.data:
          content = client.responses.files.content(
              file_id=file.id,
              response_id=response.id,
          )
          content.write_to_file(file.filename)
          print(f"Downloaded {file.filename} ({file.bytes} bytes)")
  ```

  ```typescript Typescript theme={null}
  import Perplexity from '@perplexity-ai/perplexity_ai';
  import { writeFile } from 'node:fs/promises';

  const client = new Perplexity();

  const designBook = `
  Load when creating documents that must follow the house design book.

  Model: a 1970s letterpress broadsheet financial page. One ink, gray paper.

  Colors
  - Paper #EDE9DE; tinted boxes and alternating table rows #E3DFD2.
  - Body ink #232220 — soft, never hard black (ink spread on newsprint).
  - Headlines and rules may deepen to #141311; faded ink #5C5850 for captions and secondary text.
  - No second color anywhere. Up moves: bold with a ▲. Down moves: parentheses with a ▼.

  Typography
  - Body: low-contrast newspaper serif (Georgia, PT Serif, or Times), 9-10pt, justified and hyphenated.
  - Headlines: bold condensed serif with a smaller deck beneath.
  - Kickers and table headers: condensed grotesque caps (Franklin Gothic or Oswald), letterspaced.
  - Tables: agate style — 7-8pt condensed, tabular figures.

  Layout
  - One page, ~18mm margins.
  - Nameplate in blackletter or heavy serif, with a folio line (date, edition, price) set between an Oxford rule (thick over hairline).
  - Ticker summary as a boxed agate strip below the nameplate.
  - News timeline in 3-4 narrow justified columns divided by hairline column rules; each item opens with a bold caps dateline ('LONDON, JULY 17 —').
  - Data table ruled with hairlines only.
  - Pack the page — separate blocks with cutoff rules, not white space.

  Imagery
  - Grayscale halftone only, with a hairline keyline and an italic caption.

  Avoid
  - Second colors, gradients, shadows, rounded corners, sans-serif body text, and generous white space.
  `;

  const today = new Date().toISOString().slice(0, 10);

  let response = await client.responses.create({
    preset: 'xhigh',
    background: true,
    skills: [
      {
        type: 'inline',
        name: 'design-system',
        description: 'Load when creating documents that must follow the house design book.',
        instructions: designBook,
      },
      { type: 'builtin', name: 'office' },
    ],
    input:
      `Create a one-page PDF titled 'AI Stocks Daily' for ${today}. ` +
      'Cover NVDA, MSFT, GOOGL, AMD, AVGO, META, and TSM. For each ticker ' +
      "include latest price and today's % change. Add a dated timeline of " +
      "today's key AI news, tag each item to the ticker it moved, and " +
      'finish with a data table (ticker, price, day change, week change). ' +
      'Follow the design-system skill.',
  });

  while (!['completed', 'failed', 'cancelled', 'incomplete'].includes(response.status)) {
    await new Promise((resolve) => setTimeout(resolve, 2000));
    response = await client.responses.retrieve(response.id);
  }

  console.log(`Final status: ${response.status}`);

  if (response.status === 'completed') {
    const files = await client.responses.files.list(response.id);
    for (const file of files.data) {
      const content = await client.responses.files.content(file.id, {
        response_id: response.id,
      });
      await writeFile(file.filename, Buffer.from(await content.arrayBuffer()));
      console.log(`Downloaded ${file.filename} (${file.bytes} bytes)`);
    }
  }
  ```

  ```bash cURL theme={null}
  TODAY=$(date +%F)

  RESPONSE_ID=$(curl -s https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{
      \"preset\": \"xhigh\",
      \"background\": true,
      \"skills\": [
        {
          \"type\": \"inline\",
          \"name\": \"design-system\",
          \"description\": \"Load when creating documents that must follow the house design book.\",
          \"instructions\": \"Model: a 1970s letterpress broadsheet financial page. One ink, gray paper.\nColors: paper #EDE9DE (tinted boxes and alternating table rows #E3DFD2); body ink #232220 (soft, never hard black); headlines and rules may deepen to #141311; faded ink #5C5850 for captions. No second color. Up moves: bold + ▲; down moves: parentheses + ▼.\nTypography: body low-contrast newspaper serif (Georgia, PT Serif, or Times), 9-10pt, justified and hyphenated; headlines bold condensed serif with a smaller deck; kickers and table headers condensed grotesque caps (Franklin Gothic or Oswald), letterspaced; tables agate 7-8pt condensed with tabular figures.\nLayout: one page, ~18mm margins; blackletter or heavy-serif nameplate with a folio line (date, edition, price) between an Oxford rule (thick over hairline); boxed agate ticker strip below; news timeline in 3-4 narrow justified columns with hairline column rules, items opening with bold caps datelines ('LONDON, JULY 17 —'); data table ruled with hairlines only. Pack the page — cutoff rules, not padding.\nImagery: grayscale halftone with hairline keyline and italic caption.\nAvoid: second colors, gradients, shadows, rounded corners, sans body text, generous white space.\"
        },
        { \"type\": \"builtin\", \"name\": \"office\" }
      ],
      \"input\": \"Create a one-page PDF titled 'AI Stocks Daily' for $TODAY. Cover NVDA, MSFT, GOOGL, AMD, AVGO, META, and TSM. For each ticker include latest price and today's % change. Add a dated timeline of today's key AI news, tag each item to the ticker it moved, and finish with a data table (ticker, price, day change, week change). Follow the design-system skill.\"
    }" | jq -r '.id')

  while true; do
    STATUS=$(curl -s "https://api.perplexity.ai/v1/agent/$RESPONSE_ID" \
      -H "Authorization: Bearer $PERPLEXITY_API_KEY" | jq -r '.status')
    echo "Status: $STATUS"
    [[ "$STATUS" == "completed" || "$STATUS" == "failed" || "$STATUS" == "cancelled" || "$STATUS" == "incomplete" ]] && break
    sleep 2
  done

  FILE_ID=$(curl -s "https://api.perplexity.ai/v1/agent/$RESPONSE_ID/files" \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" | jq -r '.data[0].id')

  curl -s "https://api.perplexity.ai/v1/agent/$RESPONSE_ID/files/$FILE_ID/content" \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -o "ai-stocks-daily-$TODAY.pdf"
  ```
</CodeGroup>

## What the response contains

The completed response's `output` includes:

* One `skill_loaded` item for `design-system` and one for the built-in `office/pdf` leaf the model loaded from the umbrella.
* A `share_file` item pointing to the generated PDF. Download it with the response files endpoints, as shown in [Working with files](/docs/agent-api/working-with-files).

## Run it every trading day

Turn the snippet into a scheduled job (cron, Airflow, GitHub Actions) that runs after the US market closes. The design skill lives in your code, so the report stays visually consistent every day while the content updates itself.

## Next steps

<CardGroup>
  <Card title="Skills" icon="graduation-cap" href="/docs/agent-api/skills">
    Full reference for the skills field, the built-in catalog, and inline skills.
  </Card>

  <Card title="Working with Files" icon="file" href="/docs/agent-api/working-with-files">
    List and download files an Agent API response produced in the sandbox.
  </Card>

  <Card title="Background Mode" icon="clock" href="/docs/agent-api/background-mode">
    Submit, poll, stream, and cancel long-running agent runs.
  </Card>
</CardGroup>


# Deep Research Workflows
Source: https://docs.perplexity.ai/docs/cookbook/articles/async-deep-research/README

Use the Agent API medium preset for comprehensive, multi-step research tasks — synchronous usage, batch concurrency, result processing, and production patterns

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.

<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](/docs/agent-api/presets) docs.
</Info>

## Prerequisites

Install the Perplexity SDK:

<CodeGroup>
  ```bash Python theme={null}
  pip install perplexityai
  ```

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

If you don't have an API key yet:

<Card title="Get your Perplexity API Key" icon="key" href="https://perplexity.ai/account/api">
  Navigate to the **API Keys** tab in the API Portal and generate a new key.
</Card>

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.

<CodeGroup>
  ```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."
    }'
  ```
</CodeGroup>

<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.
</Tip>

## Processing Deep Research Results

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

<CodeGroup>
  ```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));
  ```
</CodeGroup>

## Deep Research with Domain Filtering

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

<CodeGroup>
  ```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.2",
      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.2",
      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);
  ```
</CodeGroup>

## Batch Research with Concurrency

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

<CodeGroup>
  ```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)`);
  }
  ```
</CodeGroup>

<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](/docs/admin/rate-limits-usage-tiers) for specific thresholds.
</Warning>

## 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

<CardGroup>
  <Card title="Agent API Presets" icon="settings" href="/docs/agent-api/presets">
    Full reference for available presets including medium.
  </Card>

  <Card title="Agent API Quickstart" icon="rocket" href="/docs/agent-api/quickstart">
    Get started with the Agent API for multi-provider access and tools.
  </Card>

  <Card title="Domain Filtering" icon="filter" href="/docs/cookbook/articles/search-domain-filtering/README">
    Control which domains the search includes or excludes.
  </Card>

  <Card title="Rate Limits" icon="gauge-max" href="/docs/admin/rate-limits-usage-tiers">
    Understand rate limits for research and batch workflows.
  </Card>
</CardGroup>


# RAG with Perplexity Embeddings
Source: https://docs.perplexity.ai/docs/cookbook/articles/embeddings-rag/README

Build an end-to-end retrieval-augmented generation pipeline using Perplexity's standard and contextualized embedding models.

This guide walks through building a complete retrieval-augmented generation (RAG) pipeline using Perplexity's Embeddings API and Agent API.

It covers document chunking, embedding with both standard and contextualized models, building an in-memory vector index, querying for relevant context, and generating grounded answers.

<Info>
  This guide focuses on the end-to-end pipeline. For API reference details on individual embedding types, see [Standard Embeddings](/docs/embeddings/standard-embeddings) and [Contextualized Embeddings](/docs/embeddings/contextualized-embeddings).
</Info>

## Pipeline Overview

A RAG pipeline retrieves relevant information from your own documents before generating an answer, grounding model responses in your data rather than relying solely on parametric knowledge.

<img alt="RAG Pipeline Diagram" />

<img alt="RAG Pipeline Diagram" />

The steps are:

1. **Chunk** your source documents into manageable pieces with overlap.
2. **Embed** each chunk using a Perplexity embedding model.
3. **Index** the embeddings for similarity search.
4. **Query** by embedding the user question with the same model.
5. **Retrieve** the top-k most similar chunks.
6. **Generate** an answer by passing the retrieved context to the Agent API.

## Prerequisites

Install the Perplexity SDK:

<CodeGroup>
  ```bash Python theme={null}
  pip install perplexityai
  ```

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

If you don't have an API key yet:

<Card title="Get your Perplexity API Key" icon="key" href="https://perplexity.ai/account/api">
  Navigate to the **API Keys** tab in the API Portal and generate a new key.
</Card>

Then export your API key as an environment variable:

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

## Document Chunking

Split your documents into chunks small enough for the model's context window while preserving semantic coherence. Overlapping chunks ensure that information at chunk boundaries is not lost.

<CodeGroup>
  ```python Python theme={null}
  def chunk_text(text: str, chunk_size: int = 500, overlap: int = 100) -> list[str]:
      """Split text into overlapping chunks by character count."""
      chunks = []
      start = 0
      while start < len(text):
          end = start + chunk_size
          chunk = text[start:end].strip()
          if chunk:
              chunks.append(chunk)
          start += chunk_size - overlap
      return chunks

  document = """Retrieval-augmented generation (RAG) is a technique that combines
  information retrieval with text generation. Rather than relying solely on a
  language model's training data, RAG systems first search a knowledge base for
  relevant documents, then use those documents as context when generating a
  response. This reduces hallucinations and allows the system to provide answers
  grounded in specific, up-to-date sources."""

  chunks = chunk_text(document, chunk_size=300, overlap=50)
  for i, chunk in enumerate(chunks):
      print(f"Chunk {i} ({len(chunk)} chars): {chunk[:60]}...")
  ```

  ```typescript TypeScript theme={null}
  function chunkText(text: string, chunkSize: number = 500, overlap: number = 100): string[] {
      const chunks: string[] = [];
      let start = 0;
      while (start < text.length) {
          const end = start + chunkSize;
          const chunk = text.slice(start, end).trim();
          if (chunk) chunks.push(chunk);
          start += chunkSize - overlap;
      }
      return chunks;
  }

  const document = `Retrieval-augmented generation (RAG) is a technique that combines
  information retrieval with text generation. Rather than relying solely on a
  language model's training data, RAG systems first search a knowledge base for
  relevant documents, then use those documents as context when generating a
  response. This reduces hallucinations and allows the system to provide answers
  grounded in specific, up-to-date sources.`;

  const chunks = chunkText(document, 300, 50);
  chunks.forEach((chunk, i) => {
      console.log(`Chunk ${i} (${chunk.length} chars): ${chunk.slice(0, 60)}...`);
  });
  ```
</CodeGroup>

<Tip>
  A chunk size of 300-500 characters with 50-100 characters of overlap works well for most use cases. For structured documents (markdown, HTML), consider splitting on headings or paragraph boundaries instead of raw character counts.
</Tip>

## Embedding with the Standard Model

Standard embeddings treat each text independently. Use them when chunks are self-contained and don't rely on surrounding context.

<CodeGroup>
  ```python Python theme={null}
  import base64
  import numpy as np
  from perplexity import Perplexity

  client = Perplexity()

  def decode_embedding(b64_string: str) -> np.ndarray:
      """Decode a base64-encoded int8 embedding to a float32 numpy array."""
      return np.frombuffer(base64.b64decode(b64_string), dtype=np.int8).astype(np.float32)

  chunks = [
      "RAG combines retrieval with generation to ground responses in real data.",
      "Document chunking splits text into overlapping segments for embedding.",
      "Cosine similarity measures the angle between two embedding vectors.",
  ]

  response = client.embeddings.create(input=chunks, model="pplx-embed-v1-4b")
  embeddings = [decode_embedding(emb.embedding) for emb in response.data]
  print(f"Embedded {len(embeddings)} chunks, each with {len(embeddings[0])} dimensions")
  ```

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

  const client = new Perplexity();

  function decodeEmbedding(b64String: string): Int8Array {
      const buffer = Buffer.from(b64String, 'base64');
      return new Int8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  }

  const chunks = [
      "RAG combines retrieval with generation to ground responses in real data.",
      "Document chunking splits text into overlapping segments for embedding.",
      "Cosine similarity measures the angle between two embedding vectors.",
  ];

  const response = await client.embeddings.create({
      input: chunks,
      model: "pplx-embed-v1-4b"
  });
  const embeddings = response.data.map(emb => decodeEmbedding(emb.embedding));
  console.log(`Embedded ${embeddings.length} chunks, each with ${embeddings[0].length} dimensions`);
  ```
</CodeGroup>

## Embedding with the Contextualized Model

Contextualized embeddings understand that chunks belong to the same document. The model uses cross-chunk attention so that each chunk's embedding incorporates information from its neighbors. The key API difference is the nested array structure: each inner array contains chunks from a single document.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Two source documents, each split into chunks
  doc1_chunks = [
      "RAG combines retrieval with generation to produce grounded answers.",
      "The retrieval step searches a vector index for chunks similar to the query.",
      "The generation step uses retrieved context to produce a final response."
  ]
  doc2_chunks = [
      "Embedding models convert text into dense vector representations.",
      "Cosine similarity is the standard metric for comparing embeddings."
  ]

  # Pass as nested arrays (one inner array per document)
  response = client.contextualized_embeddings.create(
      input=[doc1_chunks, doc2_chunks],
      model="pplx-embed-context-v1-4b"
  )

  # Nested response: response.data[doc_idx].data[chunk_idx]
  for doc in response.data:
      for chunk in doc.data:
          print(f"Doc {doc.index}, Chunk {chunk.index}: {chunk.embedding[:20]}...")
  ```

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

  const client = new Perplexity();

  const doc1Chunks = [
      "RAG combines retrieval with generation to produce grounded answers.",
      "The retrieval step searches a vector index for chunks similar to the query.",
      "The generation step uses retrieved context to produce a final response."
  ];
  const doc2Chunks = [
      "Embedding models convert text into dense vector representations.",
      "Cosine similarity is the standard metric for comparing embeddings."
  ];

  // Pass as nested arrays (one inner array per document)
  const response = await client.contextualizedEmbeddings.create({
      input: [doc1Chunks, doc2Chunks],
      model: "pplx-embed-context-v1-4b"
  });

  // Nested response: response.data[docIdx].data[chunkIdx]
  for (const doc of response.data) {
      for (const chunk of doc.data) {
          console.log(`Doc ${doc.index}, Chunk ${chunk.index}: ${chunk.embedding.slice(0, 20)}...`);
      }
  }
  ```
</CodeGroup>

<Warning>
  **Chunk ordering matters.** Chunks within each document must be passed in their original sequential order. The contextualized model uses positional context to relate neighboring chunks, so shuffling them will degrade embedding quality.
</Warning>

## Querying a Contextualized Index

When using contextualized embeddings, wrap each query as a single-element inner list (e.g., `[[query]]`) so the API treats it as a single-chunk document:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity
  import base64, numpy as np

  client = Perplexity()

  def decode_embedding(b64: str) -> np.ndarray:
      return np.frombuffer(base64.b64decode(b64), dtype=np.int8).astype(np.float32)

  def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float:
      return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))

  # Index with contextualized model (chunks share cross-chunk attention)
  doc_chunks = [
      "RAG combines retrieval with generation to produce grounded answers.",
      "The retrieval step finds chunks similar to the user query.",
      "The generation step uses retrieved context to produce a final response.",
  ]
  ctx_response = client.contextualized_embeddings.create(
      input=[doc_chunks],  # nested array: one inner list per document
      model="pplx-embed-context-v1-4b"
  )
  index = [
      {"embedding": decode_embedding(chunk.embedding), "text": doc_chunks[chunk.index]}
      for chunk in ctx_response.data[0].data
  ]

  # Query the index
  query = "How does retrieval work in RAG?"
  q_response = client.contextualized_embeddings.create(
      input=[[query]], model="pplx-embed-context-v1-4b"
  )
  q_emb = decode_embedding(q_response.data[0].data[0].embedding)
  results = sorted(index, key=lambda x: cosine_similarity(q_emb, x["embedding"]), reverse=True)
  print(f"Top result: {results[0]['text']}")
  ```

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

  const client = new Perplexity();

  function decodeEmbedding(b64: string): Int8Array {
      const buffer = Buffer.from(b64, 'base64');
      return new Int8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  }

  function cosineSimilarity(a: Int8Array, b: Int8Array): number {
      let dot = 0, normA = 0, normB = 0;
      for (let i = 0; i < a.length; i++) {
          dot += a[i] * b[i]; normA += a[i] ** 2; normB += b[i] ** 2;
      }
      return dot / (Math.sqrt(normA) * Math.sqrt(normB));
  }

  // Index with contextualized model
  const docChunks = [
      "RAG combines retrieval with generation to produce grounded answers.",
      "The retrieval step finds chunks similar to the user query.",
      "The generation step uses retrieved context to produce a final response.",
  ];
  const ctxResponse = await client.contextualizedEmbeddings.create({
      input: [docChunks],  // nested array: one inner array per document
      model: "pplx-embed-context-v1-4b"
  });
  const index = ctxResponse.data[0].data.map(chunk => ({
      embedding: decodeEmbedding(chunk.embedding),
      text: docChunks[chunk.index],
  }));

  // Query the index
  const query = "How does retrieval work in RAG?";
  const qResponse = await client.contextualizedEmbeddings.create({
      input: [[query]], model: "pplx-embed-context-v1-4b"
  });
  const qEmb = decodeEmbedding(qResponse.data[0].data[0].embedding);
  const results = [...index].sort((a, b) => cosineSimilarity(qEmb, b.embedding) - cosineSimilarity(qEmb, a.embedding));
  console.log(`Top result: ${results[0].text}`);
  ```
</CodeGroup>

## Building a Vector Index

This example uses numpy for cosine similarity with a simple in-memory index. For production systems with millions of vectors, use a dedicated vector database (Pinecone, Weaviate, Qdrant, etc.).

<CodeGroup>
  ```python Python theme={null}
  import base64
  import numpy as np
  from perplexity import Perplexity

  client = Perplexity()

  def decode_embedding(b64_string: str) -> np.ndarray:
      return np.frombuffer(base64.b64decode(b64_string), dtype=np.int8).astype(np.float32)

  def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float:
      return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))

  # Documents to index
  documents = {
      "RAG Overview": [
          "Retrieval-augmented generation grounds LLM responses in external data.",
          "RAG reduces hallucinations by providing factual context to the model.",
          "A typical RAG pipeline has three stages: indexing, retrieval, and generation."
      ],
      "Embedding Models": [
          "Embedding models map text to dense vector representations.",
          "Similar texts produce vectors that are close in the embedding space.",
          "Perplexity offers both standard and contextualized embedding models."
      ]
  }

  # Build index: list of (embedding, text, doc_title) tuples
  index = []
  for title, chunks in documents.items():
      response = client.embeddings.create(input=chunks, model="pplx-embed-v1-4b")
      for emb_obj in response.data:
          index.append({
              "embedding": decode_embedding(emb_obj.embedding),
              "text": chunks[emb_obj.index],
              "doc_title": title
          })

  print(f"Indexed {len(index)} chunks")
  ```

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

  const client = new Perplexity();

  function decodeEmbedding(b64String: string): Int8Array {
      const buffer = Buffer.from(b64String, 'base64');
      return new Int8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  }

  function cosineSimilarity(a: Int8Array, b: Int8Array): number {
      let dot = 0, normA = 0, normB = 0;
      for (let i = 0; i < a.length; i++) {
          dot += a[i] * b[i];
          normA += a[i] * a[i];
          normB += b[i] * b[i];
      }
      return dot / (Math.sqrt(normA) * Math.sqrt(normB));
  }

  const documents: Record<string, string[]> = {
      "RAG Overview": [
          "Retrieval-augmented generation grounds LLM responses in external data.",
          "RAG reduces hallucinations by providing factual context to the model.",
          "A typical RAG pipeline has three stages: indexing, retrieval, and generation."
      ],
      "Embedding Models": [
          "Embedding models map text to dense vector representations.",
          "Similar texts produce vectors that are close in the embedding space.",
          "Perplexity offers both standard and contextualized embedding models."
      ]
  };

  // Build index
  const index: { embedding: Int8Array; text: string; docTitle: string }[] = [];
  for (const [title, chunks] of Object.entries(documents)) {
      const response = await client.embeddings.create({
          input: chunks,
          model: "pplx-embed-v1-4b"
      });
      for (const embObj of response.data) {
          index.push({
              embedding: decodeEmbedding(embObj.embedding),
              text: chunks[embObj.index],
              docTitle: title
          });
      }
  }

  console.log(`Indexed ${index.length} chunks`);
  ```
</CodeGroup>

## Query Pipeline

The full query pipeline embeds the user question, retrieves the top-k most similar chunks, and passes them as context to the Agent API for answer generation.

<CodeGroup>
  ```python Python theme={null}
  def rag_query(question: str, index: list[dict], top_k: int = 3, min_score: float = 0.3) -> str:
      """Embed question -> retrieve similar chunks -> generate answer."""
      # Step 1: Embed the question
      query_response = client.embeddings.create(input=[question], model="pplx-embed-v1-4b")
      query_emb = decode_embedding(query_response.data[0].embedding)

      # Step 2: Retrieve top-k chunks above the minimum similarity threshold
      scored = sorted(
          [{"score": cosine_similarity(query_emb, item["embedding"]), **item} for item in index],
          key=lambda x: x["score"], reverse=True
      )[:top_k]
      scored = [item for item in scored if item["score"] >= min_score]

      if not scored:
          return "No relevant context found for this question."

      # Include source attribution alongside each chunk
      context = "\n\n".join(
          f"[Source: {item['doc_title']}]\n{item['text']}" for item in scored
      )

      # Step 3: Generate answer via Agent API
      response = client.responses.create(
          model="openai/gpt-5.4",
          input=question,
          instructions=(
              "Answer based only on the provided context. "
              "Cite sources by name when referencing specific information. "
              "If the context does not contain enough information, say so.\n\n"
              f"Context:\n{context}"
          )
      )
      return response.output_text

  answer = rag_query("What are the stages of a RAG pipeline?", index)
  print(answer)
  ```

  ```typescript TypeScript theme={null}
  async function ragQuery(question: string, idx: typeof index, topK: number = 3, minScore: number = 0.3): Promise<string> {
      // Step 1: Embed the question
      const qResponse = await client.embeddings.create({
          input: [question], model: "pplx-embed-v1-4b"
      });
      const qEmb = decodeEmbedding(qResponse.data[0].embedding);

      // Step 2: Retrieve top-k chunks above the minimum similarity threshold
      const scored = idx
          .map(item => ({ ...item, score: cosineSimilarity(qEmb, item.embedding) }))
          .sort((a, b) => b.score - a.score)
          .slice(0, topK)
          .filter(item => item.score >= minScore);

      if (scored.length === 0) {
          return "No relevant context found for this question.";
      }

      // Include source attribution alongside each chunk
      const context = scored
          .map(item => `[Source: ${item.docTitle}]\n${item.text}`)
          .join("\n\n");

      // Step 3: Generate answer via Agent API
      const response = await client.responses.create({
          model: "openai/gpt-5.4",
          input: question,
          instructions: `Answer based only on the provided context. Cite sources by name when referencing specific information. If the context does not contain enough information, say so.\n\nContext:\n${context}`
      });
      return response.output_text;
  }

  const answer = await ragQuery("What are the stages of a RAG pipeline?", index);
  console.log(answer);
  ```
</CodeGroup>

<Tip>
  Start with `top_k=3` and `min_score=0.3` for most use cases. Raise `top_k` to 5–7 for broad questions or short chunks. Raise `min_score` to 0.5–0.7 if retrieved chunks contain irrelevant information. Lower it toward 0.2 for diverse or ambiguous queries.
</Tip>

## Standard vs Contextualized Comparison

| Aspect                | Standard (`pplx-embed-v1-4b`)                  | Contextualized (`pplx-embed-context-v1-4b`)                |
| --------------------- | ---------------------------------------------- | ---------------------------------------------------------- |
| **Input format**      | Flat list of texts                             | Nested arrays grouped by document                          |
| **Context awareness** | Each text embedded independently               | Chunks share cross-chunk context within each document      |
| **Best for**          | FAQ entries, standalone texts, short documents | Document paragraphs, article sections                      |
| **Chunk ordering**    | Order does not matter                          | Must be in original document order                         |
| **Query embedding**   | `client.embeddings.create(input=[query])`      | `client.contextualized_embeddings.create(input=[[query]])` |
| **Price (4b model)**  | \$0.03 / 1M tokens                             | \$0.05 / 1M tokens                                         |

### When to Use Standard Embeddings

* Chunks are self-contained and do not rely on surrounding context.
* Your content consists of FAQ pairs, product descriptions, or short independent entries.
* You need the lowest cost per token.

### When to Use Contextualized Embeddings

* Chunks come from longer documents where meaning depends on neighboring text.
* A chunk like "This approach improves performance by 20%" only makes sense with its surrounding context.
* You are embedding paragraphs from articles, reports, or technical documentation.
* You want higher retrieval accuracy at a modest cost increase.

## Matryoshka Dimensions

Perplexity embedding models support Matryoshka Representation Learning (MRL), which concentrates the most important information in the first N dimensions. You can request reduced dimensions directly via the API for faster search and smaller storage.

<CodeGroup>
  ```python Python theme={null}
  import base64
  import numpy as np
  from perplexity import Perplexity

  client = Perplexity()

  texts = ["Matryoshka embeddings allow dimension reduction without re-embedding."]

  def decode_embedding(b64: str) -> np.ndarray:
      return np.frombuffer(base64.b64decode(b64), dtype=np.int8)

  # Full dimensions (2560 for 4b model)
  full = client.embeddings.create(input=texts, model="pplx-embed-v1-4b")

  # Reduced to 512 dimensions via the API
  reduced = client.embeddings.create(input=texts, model="pplx-embed-v1-4b", dimensions=512)

  print(f"Full: {len(decode_embedding(full.data[0].embedding))} dimensions")
  print(f"Reduced: {len(decode_embedding(reduced.data[0].embedding))} dimensions")
  ```

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

  const client = new Perplexity();

  const texts = ["Matryoshka embeddings allow dimension reduction without re-embedding."];

  function decodeEmbedding(b64: string): Int8Array {
      const buffer = Buffer.from(b64, 'base64');
      return new Int8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  }

  // Full dimensions (2560 for 4b model)
  const full = await client.embeddings.create({ input: texts, model: "pplx-embed-v1-4b" });

  // Reduced to 512 dimensions via the API
  const reduced = await client.embeddings.create({
      input: texts, model: "pplx-embed-v1-4b", dimensions: 512
  });

  console.log(`Full: ${decodeEmbedding(full.data[0].embedding).length} dimensions`);
  console.log(`Reduced: ${decodeEmbedding(reduced.data[0].embedding).length} dimensions`);
  ```
</CodeGroup>

Dimension reduction tradeoffs for the `pplx-embed-v1-4b` model:

|  Dimensions | Storage per Vector | Relative Quality | Use Case                                   |
| :---------: | :----------------: | :--------------: | ------------------------------------------ |
| 2560 (full) |       2.5 KB       |      Highest     | Maximum accuracy, small datasets           |
|     1024    |        1 KB        |     Very high    | Good balance for most applications         |
|     512     |        512 B       |       High       | Large-scale retrieval, fast search         |
|     256     |        256 B       |     Moderate     | Extremely large datasets, coarse filtering |
|     128     |        128 B       |       Lower      | First-pass candidate filtering             |

<Tip>
  Use the `dimensions` parameter in the API call rather than manually truncating vectors. The API applies proper normalization for the requested dimension count. Start with full dimensions and reduce only when storage or latency becomes a bottleneck.
</Tip>

## Batch Processing

When embedding large document collections, process them in batches to stay within API rate limits. The standard API accepts up to 512 texts per request with a combined limit of 120,000 tokens.

<CodeGroup>
  ```python Python theme={null}
  import asyncio
  import base64
  import numpy as np
  from perplexity import AsyncPerplexity

  def decode_embedding(b64_string: str) -> np.ndarray:
      return np.frombuffer(base64.b64decode(b64_string), dtype=np.int8).astype(np.float32)

  async def batch_embed(texts: list[str], batch_size: int = 100) -> list[np.ndarray]:
      """Embed texts in batches with rate limiting."""
      async with AsyncPerplexity() as client:
          all_embeddings = []
          for i in range(0, len(texts), batch_size):
              batch = texts[i:i + batch_size]
              response = await client.embeddings.create(
                  input=batch, model="pplx-embed-v1-4b"
              )
              all_embeddings.extend(decode_embedding(e.embedding) for e in response.data)
              print(f"Embedded {min(i + batch_size, len(texts))}/{len(texts)}")
              if i + batch_size < len(texts):
                  await asyncio.sleep(0.1)  # Brief delay between batches
          return all_embeddings

  # Usage
  texts = [f"Document chunk number {i} with content." for i in range(500)]
  embeddings = asyncio.run(batch_embed(texts, batch_size=100))
  print(f"Total: {len(embeddings)} embeddings")
  ```

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

  const client = new Perplexity();

  function decodeEmbedding(b64String: string): Int8Array {
      const buffer = Buffer.from(b64String, 'base64');
      return new Int8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  }

  async function batchEmbed(texts: string[], batchSize: number = 100): Promise<Int8Array[]> {
      const allEmbeddings: Int8Array[] = [];
      for (let i = 0; i < texts.length; i += batchSize) {
          const batch = texts.slice(i, i + batchSize);
          const response = await client.embeddings.create({
              input: batch, model: "pplx-embed-v1-4b"
          });
          allEmbeddings.push(...response.data.map(e => decodeEmbedding(e.embedding)));
          console.log(`Embedded ${Math.min(i + batchSize, texts.length)}/${texts.length}`);
          if (i + batchSize < texts.length) {
              await new Promise(r => setTimeout(r, 100)); // Brief delay between batches
          }
      }
      return allEmbeddings;
  }

  // Usage
  const texts = Array.from({ length: 500 }, (_, i) => `Document chunk number ${i} with content.`);
  const embeddings = await batchEmbed(texts, 100);
  console.log(`Total: ${embeddings.length} embeddings`);
  ```
</CodeGroup>

<Info>
  For contextualized embeddings, batch at the document level using `client.contextualized_embeddings.create(input=batch_of_doc_arrays)` with the same pattern. The contextualized API accepts up to 512 documents with 16,000 total chunks per request.
</Info>

<Warning>
  **Rate limits:** Keep batch sizes well within the API limits (512 texts / 120,000 tokens for standard; 512 documents / 16,000 chunks for contextualized) and add small delays between requests to avoid throttling.
</Warning>

## Complete Example

A self-contained pipeline that indexes two documents with contextualized embeddings and answers questions against the indexed content.

<CodeGroup>
  ```python Python theme={null}
  import base64
  import numpy as np
  from perplexity import Perplexity

  client = Perplexity()

  # --- Helpers ---

  def chunk_text(text: str, chunk_size: int = 400, overlap: int = 80) -> list[str]:
      chunks, start = [], 0
      while start < len(text):
          chunk = text[start:start + chunk_size].strip()
          if chunk:
              chunks.append(chunk)
          start += chunk_size - overlap
      return chunks

  def decode_embedding(b64: str) -> np.ndarray:
      return np.frombuffer(base64.b64decode(b64), dtype=np.int8).astype(np.float32)

  def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float:
      return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))

  # --- Source documents ---

  DOCUMENTS = {
      "Quantum Computing": (
          "Quantum computers use qubits that can exist in superposition, representing "
          "0 and 1 simultaneously. Unlike classical bits, qubits leverage quantum "
          "interference to perform calculations. Quantum entanglement allows qubits to "
          "be correlated, enabling parallel processing at scale. Current quantum computers "
          "from IBM, Google, and others have dozens to hundreds of physical qubits."
      ),
      "Machine Learning": (
          "Machine learning enables computers to learn from data without explicit "
          "programming. Supervised learning uses labeled examples to train models for "
          "classification and regression. Neural networks with many layers (deep learning) "
          "excel at image recognition and language tasks. Training requires large datasets "
          "and significant compute, often using GPUs or TPUs."
      ),
  }

  # --- Step 1: Index with the model ---

  def build_index(documents: dict[str, str]) -> list[dict]:
      index = []
      for title, text in documents.items():
          chunks = chunk_text(text)
          response = client.contextualized_embeddings.create(
              input=[chunks],
              model="pplx-embed-context-v1-4b"
          )
          for chunk_obj in response.data[0].data:
              index.append({
                  "embedding": decode_embedding(chunk_obj.embedding),
                  "text": chunks[chunk_obj.index],
                  "doc_title": title,
              })
      print(f"Indexed {len(index)} chunks from {len(documents)} documents")
      return index

  # --- Step 2: Query the index, retrieve, generate ---

  def rag_query(question: str, index: list[dict], top_k: int = 3, min_score: float = 0.3) -> str:
      q_resp = client.contextualized_embeddings.create(
          input=[[question]], model="pplx-embed-context-v1-4b"
      )
      q_emb = decode_embedding(q_resp.data[0].data[0].embedding)

      results = sorted(
          [{"score": cosine_similarity(q_emb, item["embedding"]), **item} for item in index],
          key=lambda x: x["score"], reverse=True
      )[:top_k]
      results = [r for r in results if r["score"] >= min_score]

      if not results:
          return "No relevant context found for this question."

      context = "\n\n".join(f"[{r['doc_title']}]\n{r['text']}" for r in results)

      response = client.responses.create(
          model="openai/gpt-5.4",
          input=question,
          instructions=(
              "Answer based only on the provided context. "
              "Cite the source name in brackets when referencing information. "
              "If the context is insufficient, say so.\n\n"
              f"Context:\n{context}"
          )
      )
      return response.output_text

  # --- Run ---

  if __name__ == "__main__":
      index = build_index(DOCUMENTS)

      questions = [
          "What makes qubits different from classical bits?",
          "What hardware is used to train machine learning models?",
      ]
      for q in questions:
          print(f"\nQ: {q}")
          print(f"A: {rag_query(q, index)}")
  ```

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

  const client = new Perplexity();

  // --- Helpers ---

  function chunkText(text: string, chunkSize = 400, overlap = 80): string[] {
      const chunks: string[] = [];
      let start = 0;
      while (start < text.length) {
          const chunk = text.slice(start, start + chunkSize).trim();
          if (chunk) chunks.push(chunk);
          start += chunkSize - overlap;
      }
      return chunks;
  }

  function decodeEmbedding(b64: string): Int8Array {
      const buffer = Buffer.from(b64, 'base64');
      return new Int8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  }

  function cosineSimilarity(a: Int8Array, b: Int8Array): number {
      let dot = 0, normA = 0, normB = 0;
      for (let i = 0; i < a.length; i++) {
          dot += a[i] * b[i]; normA += a[i] ** 2; normB += b[i] ** 2;
      }
      return dot / (Math.sqrt(normA) * Math.sqrt(normB));
  }

  // --- Source documents ---

  const DOCUMENTS: Record<string, string> = {
      "Quantum Computing": "Quantum computers use qubits that can exist in superposition, representing 0 and 1 simultaneously. Unlike classical bits, qubits leverage quantum interference to perform calculations. Quantum entanglement allows qubits to be correlated, enabling parallel processing at scale. Current quantum computers from IBM, Google, and others have dozens to hundreds of physical qubits.",
      "Machine Learning": "Machine learning enables computers to learn from data without explicit programming. Supervised learning uses labeled examples to train models for classification and regression. Neural networks with many layers (deep learning) excel at image recognition and language tasks. Training requires large datasets and significant compute, often using GPUs or TPUs.",
  };

  type IndexEntry = { embedding: Int8Array; text: string; docTitle: string };

  // --- Step 1: Index with the model ---

  async function buildIndex(documents: Record<string, string>): Promise<IndexEntry[]> {
      const index: IndexEntry[] = [];
      for (const [title, text] of Object.entries(documents)) {
          const chunks = chunkText(text);
          const response = await client.contextualizedEmbeddings.create({
              input: [chunks],
              model: "pplx-embed-context-v1-4b"
          });
          for (const chunkObj of response.data[0].data) {
              index.push({
                  embedding: decodeEmbedding(chunkObj.embedding),
                  text: chunks[chunkObj.index],
                  docTitle: title,
              });
          }
      }
      console.log(`Indexed ${index.length} chunks from ${Object.keys(documents).length} documents`);
      return index;
  }

  // --- Step 2: Query the index, retrieve, generate ---

  async function ragQuery(
      question: string,
      index: IndexEntry[],
      topK = 3,
      minScore = 0.3
  ): Promise<string> {
      const qResp = await client.contextualizedEmbeddings.create({
          input: [[question]], model: "pplx-embed-context-v1-4b"
      });
      const qEmb = decodeEmbedding(qResp.data[0].data[0].embedding);

      const results = index
          .map(item => ({ ...item, score: cosineSimilarity(qEmb, item.embedding) }))
          .sort((a, b) => b.score - a.score)
          .slice(0, topK)
          .filter(r => r.score >= minScore);

      if (results.length === 0) return "No relevant context found for this question.";

      const context = results.map(r => `[${r.docTitle}]\n${r.text}`).join("\n\n");

      const response = await client.responses.create({
          model: "openai/gpt-5.4",
          input: question,
          instructions: `Answer based only on the provided context. Cite the source name in brackets when referencing information. If the context is insufficient, say so.\n\nContext:\n${context}`,
      });
      return response.output_text;
  }

  // --- Run ---

  const index = await buildIndex(DOCUMENTS);

  const questions = [
      "What makes qubits different from classical bits?",
      "What hardware is used to train machine learning models?",
  ];
  for (const q of questions) {
      console.log(`\nQ: ${q}`);
      console.log(`A: ${await ragQuery(q, index)}`);
  }
  ```
</CodeGroup>

## Next Steps

<CardGroup>
  <Card title="Standard Embeddings" icon="cube" href="/docs/embeddings/standard-embeddings">
    API reference for standard embedding parameters and response format.
  </Card>

  <Card title="Contextualized Embeddings" icon="file-lines" href="/docs/embeddings/contextualized-embeddings">
    API reference for contextualized embedding parameters and response format.
  </Card>

  <Card title="Best Practices" icon="star" href="/docs/embeddings/best-practices">
    Encoding formats, similarity metrics, normalization, and error handling.
  </Card>

  <Card title="Agent API" icon="robot" href="/docs/agent-api">
    Learn more about the Responses API used for answer generation.
  </Card>
</CardGroup>


# Function Calling End-to-End
Source: https://docs.perplexity.ai/docs/cookbook/articles/function-calling-e2e/README

Complete multi-turn function calling patterns for the Perplexity Agent API, including orchestration, web search integration, error handling, and parallel calls

This guide covers production-ready function calling patterns that go beyond the basics. You will learn the complete multi-turn flow, multi-function orchestration, combining custom functions with built-in tools, robust error handling, and parallel function call processing.

<Info>
  This guide assumes familiarity with the Agent API and its tool definitions. For parameter reference and basic usage, see the [Agent API reference](/api-reference/agent-post).
</Info>

## Prerequisites

Install the Perplexity SDK:

<CodeGroup>
  ```bash Python theme={null}
  pip install perplexityai
  ```

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

If you don't have an API key yet:

<Card title="Get your Perplexity API Key" icon="key" href="https://perplexity.ai/account/api">
  Navigate to the **API Keys** tab in the API Portal and generate a new key.
</Card>

Then export your API key as an environment variable:

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

<Tip>
  For built-in tools, start with [Web Search](/docs/agent-api/tools/web-search), [Fetch URL Content](/docs/agent-api/tools/fetch-url-content), [Finance Search](/docs/agent-api/tools/finance-search), and [People Search](/docs/agent-api/tools/people-search). This guide focuses on custom function orchestration patterns in application code.
</Tip>

## Complete Multi-Turn Flow

The core function calling loop follows a specific pattern: send a request with tool definitions, detect `function_call` items in the response, execute your functions locally, then return the results as `function_call_output` items.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity
  import json

  client = Perplexity()

  # Step 1: Define tools
  tools = [
      {
          "type": "function",
          "name": "lookup_order",
          "description": "Look up an order by order ID. Returns order status, items, and shipping info.",
          "parameters": {
              "type": "object",
              "properties": {
                  "order_id": {
                      "type": "string",
                      "description": "The unique order identifier, e.g. ORD-12345"
                  }
              },
              "required": ["order_id"]
          }
      }
  ]

  # Your actual function implementation
  def lookup_order(order_id: str) -> dict:
      # In production, query your database or order management system
      return {
          "order_id": order_id,
          "status": "shipped",
          "items": ["Wireless Headphones", "USB-C Cable"],
          "tracking_number": "1Z999AA10123456784",
          "estimated_delivery": "2026-03-02"
      }

  # Step 2: Send the initial request
  response = client.responses.create(
      model="anthropic/claude-sonnet-4-6",
      tools=tools,
      input="Where is my order ORD-98712?"
  )

  # Step 3: Process the response and handle function calls
  next_input = [item.model_dump() for item in response.output]

  for item in response.output:
      if item.type == "function_call":
          # Step 4: Parse arguments and execute the function
          args = json.loads(item.arguments)
          result = lookup_order(**args)

          # Step 5: Append the function result
          next_input.append({
              "type": "function_call_output",
              "call_id": item.call_id,
              "output": json.dumps(result)
          })

  # Step 6: Send results back to get the final response
  final_response = client.responses.create(
      model="anthropic/claude-sonnet-4-6",
      input=next_input
  )

  print(final_response.output_text)
  ```

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

  const client = new Perplexity();

  // Step 1: Define tools
  const tools = [
      {
          type: "function" as const,
          name: "lookup_order",
          description: "Look up an order by order ID. Returns order status, items, and shipping info.",
          parameters: {
              type: "object",
              properties: {
                  order_id: {
                      type: "string",
                      description: "The unique order identifier, e.g. ORD-12345"
                  }
              },
              required: ["order_id"]
          }
      }
  ];

  // Your actual function implementation
  function lookupOrder(orderId: string): Record<string, unknown> {
      // In production, query your database or order management system
      return {
          order_id: orderId,
          status: "shipped",
          items: ["Wireless Headphones", "USB-C Cable"],
          tracking_number: "1Z999AA10123456784",
          estimated_delivery: "2026-03-02"
      };
  }

  // Step 2: Send the initial request
  const response = await client.responses.create({
      model: "anthropic/claude-sonnet-4-6",
      tools: tools,
      input: "Where is my order ORD-98712?"
  });

  // Step 3: Process the response and handle function calls
  const nextInput: any[] = response.output.map(item => ({ ...item }));

  for (const item of response.output) {
      if (item.type === "function_call") {
          // Step 4: Parse arguments and execute the function
          const args = JSON.parse(item.arguments);
          const result = lookupOrder(args.order_id);

          // Step 5: Append the function result
          nextInput.push({
              type: "function_call_output",
              call_id: item.call_id,
              output: JSON.stringify(result)
          });
      }
  }

  // Step 6: Send results back to get the final response
  const finalResponse = await client.responses.create({
      model: "anthropic/claude-sonnet-4-6",
      input: nextInput
  });

  console.log(finalResponse.output_text);
  ```
</CodeGroup>

<Tip>
  Always use `json.loads()` (Python) or `JSON.parse()` (TypeScript) on the `arguments` field. It is a JSON string, not a parsed object.
</Tip>

## Multi-Function Orchestration

When you provide multiple tools, the model decides which to call and in what order. This example registers three functions that work together to answer a complex query.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity
  import json

  client = Perplexity()

  # Define multiple tools
  tools = [
      {
          "type": "function",
          "name": "get_weather",
          "description": "Get the current weather forecast for a city. Returns temperature, conditions, and precipitation chance.",
          "parameters": {
              "type": "object",
              "properties": {
                  "city": {"type": "string", "description": "City name"}
              },
              "required": ["city"]
          }
      },
      {
          "type": "function",
          "name": "get_calendar_events",
          "description": "Retrieve today's calendar events for a user. Returns a list of events with times and locations.",
          "parameters": {
              "type": "object",
              "properties": {
                  "user_id": {"type": "string", "description": "The user ID"},
                  "date": {"type": "string", "description": "Date in YYYY-MM-DD format"}
              },
              "required": ["user_id", "date"]
          }
      },
      {
          "type": "function",
          "name": "send_email",
          "description": "Send an email to a recipient with a subject and body.",
          "parameters": {
              "type": "object",
              "properties": {
                  "to": {"type": "string", "description": "Recipient email address"},
                  "subject": {"type": "string", "description": "Email subject line"},
                  "body": {"type": "string", "description": "Email body text"}
              },
              "required": ["to", "subject", "body"]
          }
      }
  ]

  # Function implementations
  def get_weather(city: str) -> dict:
      return {"city": city, "temp_f": 72, "conditions": "Partly cloudy", "precipitation_chance": 0.15}

  def get_calendar_events(user_id: str, date: str) -> dict:
      return {
          "events": [
              {"time": "09:00", "title": "Team standup", "location": "Conference Room B"},
              {"time": "12:00", "title": "Lunch with client", "location": "Riverside Park (outdoor)"},
              {"time": "15:00", "title": "Sprint review", "location": "Zoom"}
          ]
      }

  def send_email(to: str, subject: str, body: str) -> dict:
      # In production, integrate with your email service
      return {"status": "sent", "message_id": "msg-20260226-001"}

  # Map function names to implementations
  function_map = {
      "get_weather": get_weather,
      "get_calendar_events": get_calendar_events,
      "send_email": send_email,
  }

  # Multi-turn loop: keep sending requests until no more function calls
  input_messages = [
      {"role": "user", "content": (
          "I'm user U-100 in San Francisco. What's my schedule today (2026-02-26) "
          "and is the weather good for my outdoor events? "
          "If there's rain risk, email me at alice@example.com with a reminder to bring an umbrella."
      )}
  ]

  response = client.responses.create(
      model="anthropic/claude-sonnet-4-6",
      tools=tools,
      input=input_messages
  )

  # Loop until the model produces a final text response with no pending function calls
  while any(item.type == "function_call" for item in response.output):
      next_input = [item.model_dump() for item in response.output]

      for item in response.output:
          if item.type == "function_call":
              args = json.loads(item.arguments)
              fn = function_map[item.name]
              result = fn(**args)

              next_input.append({
                  "type": "function_call_output",
                  "call_id": item.call_id,
                  "output": json.dumps(result)
              })

      response = client.responses.create(
          model="anthropic/claude-sonnet-4-6",
          tools=tools,
          input=next_input
      )

  print(response.output_text)
  ```

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

  const client = new Perplexity();

  // Define multiple tools
  const tools = [
      {
          type: "function" as const,
          name: "get_weather",
          description: "Get the current weather forecast for a city. Returns temperature, conditions, and precipitation chance.",
          parameters: {
              type: "object",
              properties: {
                  city: { type: "string", description: "City name" }
              },
              required: ["city"]
          }
      },
      {
          type: "function" as const,
          name: "get_calendar_events",
          description: "Retrieve today's calendar events for a user. Returns a list of events with times and locations.",
          parameters: {
              type: "object",
              properties: {
                  user_id: { type: "string", description: "The user ID" },
                  date: { type: "string", description: "Date in YYYY-MM-DD format" }
              },
              required: ["user_id", "date"]
          }
      },
      {
          type: "function" as const,
          name: "send_email",
          description: "Send an email to a recipient with a subject and body.",
          parameters: {
              type: "object",
              properties: {
                  to: { type: "string", description: "Recipient email address" },
                  subject: { type: "string", description: "Email subject line" },
                  body: { type: "string", description: "Email body text" }
              },
              required: ["to", "subject", "body"]
          }
      }
  ];

  // Function implementations
  function getWeather(city: string) {
      return { city, temp_f: 72, conditions: "Partly cloudy", precipitation_chance: 0.15 };
  }

  function getCalendarEvents(userId: string, date: string) {
      return {
          events: [
              { time: "09:00", title: "Team standup", location: "Conference Room B" },
              { time: "12:00", title: "Lunch with client", location: "Riverside Park (outdoor)" },
              { time: "15:00", title: "Sprint review", location: "Zoom" }
          ]
      };
  }

  function sendEmail(to: string, subject: string, body: string) {
      return { status: "sent", message_id: "msg-20260226-001" };
  }

  // Map function names to implementations
  const functionMap: Record<string, (...args: any[]) => any> = {
      get_weather: (args: any) => getWeather(args.city),
      get_calendar_events: (args: any) => getCalendarEvents(args.user_id, args.date),
      send_email: (args: any) => sendEmail(args.to, args.subject, args.body),
  };

  // Multi-turn loop
  let response = await client.responses.create({
      model: "anthropic/claude-sonnet-4-6",
      tools: tools,
      input: [
          {
              role: "user",
              content:
                  "I'm user U-100 in San Francisco. What's my schedule today (2026-02-26) " +
                  "and is the weather good for my outdoor events? " +
                  "If there's rain risk, email me at alice@example.com with a reminder to bring an umbrella."
          }
      ]
  });

  while (response.output.some(item => item.type === "function_call")) {
      const nextInput: any[] = response.output.map(item => ({ ...item }));

      for (const item of response.output) {
          if (item.type === "function_call") {
              const args = JSON.parse(item.arguments);
              const result = functionMap[item.name](args);

              nextInput.push({
                  type: "function_call_output",
                  call_id: item.call_id,
                  output: JSON.stringify(result)
              });
          }
      }

      response = await client.responses.create({
          model: "anthropic/claude-sonnet-4-6",
          tools: tools,
          input: nextInput
      });
  }

  console.log(response.output_text);
  ```
</CodeGroup>

<Info>
  The model may call functions across multiple turns. The `while` loop above keeps running until the model finishes all function calls and produces a final text response. In some turns the model may call one function, and in the next turn call another based on the results it received.
</Info>

## Combining Custom Functions with `web_search`

You can mix built-in tools like `web_search` and `fetch_url` with your own custom functions in the same `tools` array. The model decides autonomously which tool to use. This is powerful for workflows that need live web data combined with actions in your own systems.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity
  import json

  client = Perplexity()

  tools = [
      # Built-in web search
      {"type": "web_search"},
      # Custom function to persist data
      {
          "type": "function",
          "name": "save_to_db",
          "description": "Save a research summary to the internal database. Call this after gathering information to persist findings.",
          "parameters": {
              "type": "object",
              "properties": {
                  "topic": {"type": "string", "description": "The research topic"},
                  "summary": {"type": "string", "description": "A concise summary of the findings"},
                  "sources": {
                      "type": "array",
                      "items": {"type": "string"},
                      "description": "List of source URLs"
                  }
              },
              "required": ["topic", "summary", "sources"]
          }
      }
  ]

  def save_to_db(topic: str, summary: str, sources: list) -> dict:
      # In production, write to your database
      record_id = "rec-" + topic.lower().replace(" ", "-")[:20]
      print(f"Saved to DB: {record_id}")
      return {"record_id": record_id, "status": "saved"}

  response = client.responses.create(
      model="anthropic/claude-sonnet-4-6",
      tools=tools,
      input="Research the latest developments in solid-state batteries, then save your findings to our database.",
      instructions="First search the web for current information, then use save_to_db to persist your summary."
  )

  # The model will use web_search automatically (no function_call for built-in tools),
  # then call save_to_db which we need to handle.
  while any(item.type == "function_call" for item in response.output):
      next_input = [item.model_dump() for item in response.output]

      for item in response.output:
          if item.type == "function_call":
              args = json.loads(item.arguments)
              result = save_to_db(**args)
              next_input.append({
                  "type": "function_call_output",
                  "call_id": item.call_id,
                  "output": json.dumps(result)
              })

      response = client.responses.create(
          model="anthropic/claude-sonnet-4-6",
          tools=tools,
          input=next_input
      )

  print(response.output_text)
  ```

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

  const client = new Perplexity();

  const tools = [
      // Built-in web search
      { type: "web_search" as const },
      // Custom function to persist data
      {
          type: "function" as const,
          name: "save_to_db",
          description: "Save a research summary to the internal database. Call this after gathering information to persist findings.",
          parameters: {
              type: "object",
              properties: {
                  topic: { type: "string", description: "The research topic" },
                  summary: { type: "string", description: "A concise summary of the findings" },
                  sources: {
                      type: "array",
                      items: { type: "string" },
                      description: "List of source URLs"
                  }
              },
              required: ["topic", "summary", "sources"]
          }
      }
  ];

  function saveToDb(topic: string, summary: string, sources: string[]) {
      const recordId = "rec-" + topic.toLowerCase().replace(/ /g, "-").slice(0, 20);
      console.log(`Saved to DB: ${recordId}`);
      return { record_id: recordId, status: "saved" };
  }

  let response = await client.responses.create({
      model: "anthropic/claude-sonnet-4-6",
      tools: tools,
      input: "Research the latest developments in solid-state batteries, then save your findings to our database.",
      instructions: "First search the web for current information, then use save_to_db to persist your summary."
  });

  while (response.output.some(item => item.type === "function_call")) {
      const nextInput: any[] = response.output.map(item => ({ ...item }));

      for (const item of response.output) {
          if (item.type === "function_call") {
              const args = JSON.parse(item.arguments);
              const result = saveToDb(args.topic, args.summary, args.sources);
              nextInput.push({
                  type: "function_call_output",
                  call_id: item.call_id,
                  output: JSON.stringify(result)
              });
          }
      }

      response = await client.responses.create({
          model: "anthropic/claude-sonnet-4-6",
          tools: tools,
          input: nextInput
      });
  }

  console.log(response.output_text);
  ```
</CodeGroup>

<Tip>
  Built-in tools like `web_search` are executed server-side by the API. You only need to handle `function_call` items for your custom functions. The model seamlessly interleaves built-in and custom tool usage.
</Tip>

## Error Handling Patterns

When a function call fails, return a structured error in the `function_call_output` so the model can adapt its response. Never silently swallow errors; the model can often recover or inform the user gracefully.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity
  import json
  import traceback

  client = Perplexity()

  def execute_function(name: str, args: dict) -> dict:
      """Dispatch and execute a function call with error handling."""
      function_map = {
          "lookup_order": lookup_order,
          "cancel_order": cancel_order,
      }

      if name not in function_map:
          return {"error": True, "message": f"Unknown function: {name}"}

      try:
          result = function_map[name](**args)
          return result
      except KeyError as e:
          return {"error": True, "message": f"Missing required field: {e}"}
      except TimeoutError:
          return {"error": True, "message": "The request timed out. Please try again."}
      except Exception as e:
          return {"error": True, "message": f"Function failed: {str(e)}"}


  def lookup_order(order_id: str) -> dict:
      if not order_id.startswith("ORD-"):
          raise ValueError(f"Invalid order ID format: {order_id}")
      return {"order_id": order_id, "status": "delivered"}


  def cancel_order(order_id: str) -> dict:
      # Simulate a failure
      raise ConnectionError("Order service is temporarily unavailable")


  def run_agent(user_input: str, tools: list) -> str:
      """Run the full function calling loop with error handling."""
      response = client.responses.create(
          model="anthropic/claude-sonnet-4-6",
          tools=tools,
          input=user_input
      )

      max_turns = 10
      turn = 0

      while any(item.type == "function_call" for item in response.output) and turn < max_turns:
          next_input = [item.model_dump() for item in response.output]

          for item in response.output:
              if item.type == "function_call":
                  args = json.loads(item.arguments)
                  result = execute_function(item.name, args)

                  next_input.append({
                      "type": "function_call_output",
                      "call_id": item.call_id,
                      "output": json.dumps(result)
                  })

          response = client.responses.create(
              model="anthropic/claude-sonnet-4-6",
              tools=tools,
              input=next_input
          )
          turn += 1

      if turn >= max_turns:
          return "Error: Maximum function call turns exceeded."

      return response.output_text
  ```

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

  const client = new Perplexity();

  function lookupOrder(orderId: string): Record<string, unknown> {
      if (!orderId.startsWith("ORD-")) {
          throw new Error(`Invalid order ID format: ${orderId}`);
      }
      return { order_id: orderId, status: "delivered" };
  }

  function cancelOrder(orderId: string): Record<string, unknown> {
      // Simulate a failure
      throw new Error("Order service is temporarily unavailable");
  }

  function executeFunction(name: string, args: Record<string, any>): Record<string, unknown> {
      const functionMap: Record<string, (args: any) => Record<string, unknown>> = {
          lookup_order: (a) => lookupOrder(a.order_id),
          cancel_order: (a) => cancelOrder(a.order_id),
      };

      if (!(name in functionMap)) {
          return { error: true, message: `Unknown function: ${name}` };
      }

      try {
          return functionMap[name](args);
      } catch (e: any) {
          return { error: true, message: `Function failed: ${e.message}` };
      }
  }

  async function runAgent(userInput: string, tools: any[]): Promise<string> {
      let response = await client.responses.create({
          model: "anthropic/claude-sonnet-4-6",
          tools: tools,
          input: userInput
      });

      const maxTurns = 10;
      let turn = 0;

      while (response.output.some(item => item.type === "function_call") && turn < maxTurns) {
          const nextInput: any[] = response.output.map(item => ({ ...item }));

          for (const item of response.output) {
              if (item.type === "function_call") {
                  const args = JSON.parse(item.arguments);
                  const result = executeFunction(item.name, args);

                  nextInput.push({
                      type: "function_call_output",
                      call_id: item.call_id,
                      output: JSON.stringify(result)
                  });
              }
          }

          response = await client.responses.create({
              model: "anthropic/claude-sonnet-4-6",
              tools: tools,
              input: nextInput
          });
          turn++;
      }

      if (turn >= maxTurns) {
          return "Error: Maximum function call turns exceeded.";
      }

      return response.output_text;
  }
  ```
</CodeGroup>

Key principles for error handling:

* **Return errors as structured data**, not exceptions. Include `"error": true` and a human-readable `"message"` so the model can relay the issue to the user.
* **Catch specific exceptions** (timeouts, auth failures, validation errors) and map them to clear messages.
* **Cap the number of turns** to prevent infinite loops.
* **Never return raw stack traces** to the model. They waste tokens and may leak internal details.

## Parallel Function Calls

When the model determines that multiple function calls are independent, it may return several `function_call` items in a single response. Process all of them before sending results back in one batch.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity
  import json
  from concurrent.futures import ThreadPoolExecutor

  client = Perplexity()

  tools = [
      {
          "type": "function",
          "name": "get_stock_price",
          "description": "Get the current stock price for a ticker symbol.",
          "parameters": {
              "type": "object",
              "properties": {
                  "ticker": {"type": "string", "description": "Stock ticker symbol, e.g. AAPL"}
              },
              "required": ["ticker"]
          }
      },
      {
          "type": "function",
          "name": "get_company_info",
          "description": "Get basic company information for a ticker symbol.",
          "parameters": {
              "type": "object",
              "properties": {
                  "ticker": {"type": "string", "description": "Stock ticker symbol"}
              },
              "required": ["ticker"]
          }
      }
  ]

  def get_stock_price(ticker: str) -> dict:
      prices = {"AAPL": 245.12, "GOOGL": 192.45, "TSLA": 371.80}
      return {"ticker": ticker, "price": prices.get(ticker, 0.0), "currency": "USD"}

  def get_company_info(ticker: str) -> dict:
      info = {
          "AAPL": {"name": "Apple Inc.", "sector": "Technology", "market_cap": "3.7T"},
          "GOOGL": {"name": "Alphabet Inc.", "sector": "Technology", "market_cap": "2.4T"},
      }
      return info.get(ticker, {"name": "Unknown", "sector": "Unknown", "market_cap": "N/A"})

  function_map = {
      "get_stock_price": get_stock_price,
      "get_company_info": get_company_info,
  }

  response = client.responses.create(
      model="anthropic/claude-sonnet-4-6",
      tools=tools,
      input="Compare the current stock prices and company details for AAPL and GOOGL."
  )

  while any(item.type == "function_call" for item in response.output):
      # Collect all pending function calls
      pending_calls = [item for item in response.output if item.type == "function_call"]
      next_input = [item.model_dump() for item in response.output]

      # Execute all function calls in parallel
      def run_call(item):
          args = json.loads(item.arguments)
          result = function_map[item.name](**args)
          return {
              "type": "function_call_output",
              "call_id": item.call_id,
              "output": json.dumps(result)
          }

      with ThreadPoolExecutor(max_workers=len(pending_calls)) as executor:
          results = list(executor.map(run_call, pending_calls))

      next_input.extend(results)

      response = client.responses.create(
          model="anthropic/claude-sonnet-4-6",
          tools=tools,
          input=next_input
      )

  print(response.output_text)
  ```

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

  const client = new Perplexity();

  const tools = [
      {
          type: "function" as const,
          name: "get_stock_price",
          description: "Get the current stock price for a ticker symbol.",
          parameters: {
              type: "object",
              properties: {
                  ticker: { type: "string", description: "Stock ticker symbol, e.g. AAPL" }
              },
              required: ["ticker"]
          }
      },
      {
          type: "function" as const,
          name: "get_company_info",
          description: "Get basic company information for a ticker symbol.",
          parameters: {
              type: "object",
              properties: {
                  ticker: { type: "string", description: "Stock ticker symbol" }
              },
              required: ["ticker"]
          }
      }
  ];

  function getStockPrice(ticker: string) {
      const prices: Record<string, number> = { AAPL: 245.12, GOOGL: 192.45, TSLA: 371.80 };
      return { ticker, price: prices[ticker] ?? 0.0, currency: "USD" };
  }

  function getCompanyInfo(ticker: string) {
      const info: Record<string, any> = {
          AAPL: { name: "Apple Inc.", sector: "Technology", market_cap: "3.7T" },
          GOOGL: { name: "Alphabet Inc.", sector: "Technology", market_cap: "2.4T" },
      };
      return info[ticker] ?? { name: "Unknown", sector: "Unknown", market_cap: "N/A" };
  }

  const functionMap: Record<string, (args: any) => any> = {
      get_stock_price: (args) => getStockPrice(args.ticker),
      get_company_info: (args) => getCompanyInfo(args.ticker),
  };

  let response = await client.responses.create({
      model: "anthropic/claude-sonnet-4-6",
      tools: tools,
      input: "Compare the current stock prices and company details for AAPL and GOOGL."
  });

  while (response.output.some(item => item.type === "function_call")) {
      const pendingCalls = response.output.filter(item => item.type === "function_call");
      const nextInput: any[] = response.output.map(item => ({ ...item }));

      // Execute all function calls in parallel
      const results = await Promise.all(
          pendingCalls.map(async (item) => {
              const args = JSON.parse(item.arguments);
              const result = functionMap[item.name](args);
              return {
                  type: "function_call_output",
                  call_id: item.call_id,
                  output: JSON.stringify(result)
              };
          })
      );

      nextInput.push(...results);

      response = await client.responses.create({
          model: "anthropic/claude-sonnet-4-6",
          tools: tools,
          input: nextInput
      });
  }

  console.log(response.output_text);
  ```
</CodeGroup>

<Info>
  The model may emit multiple `function_call` items in a single response when it determines the calls are independent. Using `ThreadPoolExecutor` (Python) or `Promise.all` (TypeScript) lets you execute them concurrently, reducing total latency.
</Info>

## Next Steps

<CardGroup>
  <Card title="Agent API Reference" icon="settings-bolt" href="/api-reference/agent-post">
    Review request parameters and tool schema fields.
  </Card>

  <Card title="Agent API Models" icon="brain" href="/docs/agent-api/models">
    Choose a model for your function-calling workload.
  </Card>

  <Card title="Agent API Quickstart" icon="rocket" href="/docs/agent-api/quickstart">
    Get up and running with the Agent API in minutes.
  </Card>

  <Card title="Output Control" icon="adjustments" href="/docs/agent-api/output-control">
    Combine function calling with structured outputs and response shaping.
  </Card>
</CardGroup>


# VC Investment Memo Agent with LangGraph
Source: https://docs.perplexity.ai/docs/cookbook/articles/langchain-vc-memo-agent/README

Build an auditable, citation-grounded VC research agent with LangGraph and the Perplexity Agent API, and pick the best search provider with a LangSmith eval harness.

<SonarDeprecationNotice />

## Overview

This guide builds an agent that takes a company name and returns a citation-grounded VC investment memo with seven sections: Snapshot, Team, Financials, Product, Market, Risks, and a Thesis ending in a one-line recommendation. **Every claim is traced back to a primary source.**

It runs on the [Perplexity Agent API](/docs/agent-api/quickstart) and its built-in `web_search` and `finance_search` tools, orchestrated with [LangGraph](https://langchain-ai.github.io/langgraph/), and evaluated in [LangSmith](https://docs.langchain.com/langsmith/home). The whole build runs in about ninety seconds for roughly \$0.40 per memo.

The design lesson generalizes beyond finance: **separating search from synthesis is a structural reliability fix for a research agent.** Four research nodes fan out in parallel, each calling the Agent API with its own tools. A final synthesizer node has no tools and can only cite evidence the research nodes already gathered, so the memo cannot invent a source.

<img alt="Company name flows into START, fans out to four parallel research nodes (team, financials, product, market), which all feed a single synthesizer node that produces the memo at END." />

## Features

* **Parallel research fan-out.** Four focused research nodes (team, financials, product, market) run concurrently, each with its own tools and search budget.
* **Tool-less synthesizer.** The final memo is composed only from upstream evidence, a structural guard against fabricated citations.
* **Built-in Agent API tools.** `web_search` and `finance_search` work out of the box; no client-side search plumbing for the core agent.
* **Auditable in LangSmith.** Every node's tool calls and outputs are captured, so any claim traces back to the search result that produced it.
* **Provider eval harness.** A LangSmith comparison that scores search providers on primary-source rate, financial-concept coverage, latency, and cost.

## Prerequisites

* Python 3.10+
* A [Perplexity API key](/docs/admin/api-key-management) (`PPLX_API_KEY`)
* A [LangSmith API key](https://docs.smith.langchain.com/) for tracing and evaluation
* (provider comparison only) [Parallel](https://platform.parallel.ai/) and [Exa](https://dashboard.exa.ai/) API keys

## Setup

```bash theme={null}
pip install "langchain-perplexity>=1.4.0" langgraph langsmith
```

```bash theme={null}
# ChatPerplexity reads PPLX_API_KEY.
export PPLX_API_KEY="pplx-..."
export LANGSMITH_API_KEY="ls__..."
export LANGSMITH_TRACING="true"   # capture every node's tool calls end-to-end
```

## Build the agent

Everything in this section goes in one file. Paste the blocks in order into `memo.py` and you have the complete agent.

### Graph state

Each research node reads `company` from the shared state and writes its findings into `research_output`; a reducer merges the parallel writes.

```python theme={null}
from __future__ import annotations

from datetime import datetime, timezone
from typing import Annotated, Any, TypedDict

from langchain_core.messages import AIMessage
from langchain_perplexity import ChatPerplexity
from langgraph.graph import END, START, StateGraph


def merge_research_output(left: dict[str, str], right: dict[str, str]) -> dict[str, str]:
    """Each research node returns {"<section>": "..."}; merge into one dict."""
    return {**(left or {}), **(right or {})}


class MemoState(TypedDict):
    company: str
    research_output: Annotated[dict[str, str], merge_research_output]
    memo: str
```

### Models and tools

The Agent API exposes Perplexity's built-in tools directly. The financials node adds `finance_search`; the rest use `web_search`. `max_steps` caps each node's internal search loop, which is the per-node search budget.

```python theme={null}
SUBNODE_MODEL_NAME = "openai/gpt-5.5"
SYNTHESIZER_MODEL_NAME = "openai/gpt-5.5"


def _agent_model(model: str) -> ChatPerplexity:
    """Build a ChatPerplexity client wired to the Responses API."""
    # The Responses (Agent) API ignores sampling params like temperature, so we omit it.
    return ChatPerplexity(model=model, use_responses_api=True)


SUBNODE_MODEL = _agent_model(SUBNODE_MODEL_NAME)
SYNTHESIZER_MODEL = _agent_model(SYNTHESIZER_MODEL_NAME)


# Per-research-node tool specs.
TEAM_TOOLS = [{
    "type": "web_search",
    "filters": {"search_recency_filter": "year"},
}]

PRODUCT_TOOLS = [{"type": "web_search"}]

MARKET_TOOLS = [{"type": "web_search"}]

FINANCIALS_TOOLS = [{"type": "finance_search"}, {"type": "web_search"}]


# Per-research-node max_steps caps the Perplexity Agent API's internal search loop.
RESEARCH_MAX_STEPS = {
    "team": 2, "financials": 5, "product": 2, "market": 2,
}
```

### Research prompts

One prompt template serves all four nodes; per-section guidance steers what each node hunts for and which sources to prefer.

```python theme={null}
RESEARCH_PROMPT = """You are a VC analyst writing the {section} section of the research output for {company}.

{guidance}

Return a markdown section, then end the document with a "### Citations" header \
followed by a markdown list of:

  - <url> — one-sentence evidence quoted from the source

Cite only URLs that came back from your tool calls; never fabricate URLs. \
Keep the section focused — 250-400 words is appropriate for the body."""


GUIDANCE = {
    "team": (
        "Search for the founders, CEO, and other named executives. Capture each "
        "leader's prior roles and education. Prioritize the company's own About/Team "
        "page and reputable public biographies."
    ),
    "financials": (
        "If the company is public, use finance_search for revenue, margins, and analyst "
        "estimates. If private, use web_search for funding rounds, valuation, and "
        "disclosed revenue. Cross-check structured data against recent news."
    ),
    "product": (
        "Describe the company's flagship product, recent launches, and technical "
        "differentiators. Cite the company's own product or engineering pages where "
        "possible, plus tech-press coverage for context."
    ),
    "market": (
        "Map the competitive landscape, name direct competitors, and surface market "
        "sizing. Your web_search is scoped to analyst and trade-press sources."
    ),
}
```

### Research nodes

All four nodes share one runner: a single Agent API call with that node's tools and search budget. The API runs the search loop server-side, so there is no client-side tool plumbing here.

```python theme={null}
def _run_research(
    state: MemoState,
    *,
    section: str,
    tools: list[dict[str, Any]],
    max_steps: int,
) -> dict[str, dict[str, str]]:
    """Run one research section with the given tools and return its output."""
    msg: AIMessage = SUBNODE_MODEL.invoke(
        [
            {"role": "system", "content": RESEARCH_PROMPT.format(
                section=section, company=state["company"], guidance=GUIDANCE[section],
            )},
            {"role": "user", "content": f"Research the {section} of {state['company']}."},
        ],
        tools=tools,
        extra_body={"max_steps": max_steps},
    )
    return {"research_output": {section: msg.content}}


def team_node(state):
    """Research the founders and leadership team."""
    return _run_research(state, section="team",
        tools=TEAM_TOOLS, max_steps=RESEARCH_MAX_STEPS["team"])

def financials_node(state):
    """Research revenue, funding, and financial metrics."""
    return _run_research(state, section="financials",
        tools=FINANCIALS_TOOLS, max_steps=RESEARCH_MAX_STEPS["financials"])

def product_node(state):
    """Research the product, launches, and technical differentiators."""
    return _run_research(state, section="product",
        tools=PRODUCT_TOOLS, max_steps=RESEARCH_MAX_STEPS["product"])

def market_node(state):
    """Research the competitive landscape and market sizing."""
    return _run_research(state, section="market",
        tools=MARKET_TOOLS, max_steps=RESEARCH_MAX_STEPS["market"])
```

### The synthesizer

The synthesizer has no tools. It composes all seven memo sections from the four nodes' research outputs, so every cited claim is grounded in research one of the nodes actually did. Sections 1–6 each end with a `### Citations` list pairing every source URL with the evidence it supports. The Thesis is the one analysis-only section, with no citations.

```python theme={null}
SYNTH_PROMPT = """You are a senior VC partner writing the final memo for {company}.

You may only cite evidence that appears in the research outputs below. You have no \
tools; do not browse or fabricate sources.

Produce a markdown memo with these seven sections, in order:

  1. Snapshot — what the company is, founded, valuation, positioning (3-4 sentences)
  2. Team — founders, leadership, recent senior hires
  3. Financials — revenue, growth, funding history, comparables
  4. Product — what they sell, technology, distribution
  5. Market — TAM, direct competitors, category dynamics
  6. Risks — top 3-5 risks with brief reasoning
  7. Thesis — 1-2 paragraphs of analysis, ending with a single line:
     "Recommendation: <PASS | TRACK | ADVANCE | LEAD>"

Each section's H2 heading must be exactly `## <N> · <Section Name>` \
(e.g. `## 1 · Snapshot`), using a middle-dot separator — the evaluator depends \
on this format.

Each of sections 1-6 must end with a `### Citations` subsection listing the \
<url> — <evidence> pairs drawn from the research outputs. Section 7 (Thesis) does \
not need its own citations.

If a research output lacks evidence for a section, write "Insufficient evidence in \
research outputs." in that section's body instead of guessing."""


def synthesizer_node(state: MemoState) -> dict[str, str]:
    """Combine all research outputs into the final memo. No tools attached."""
    research_output_block = "\n\n".join(
        f"## Research output: {name}\n\n{body}"
        for name, body in sorted(state["research_output"].items())
    )
    msg: AIMessage = SYNTHESIZER_MODEL.invoke([
        {"role": "system", "content": SYNTH_PROMPT.format(company=state["company"])},
        {"role": "user", "content": (
            f"Company: {state['company']}\n"
            f"As-of: {datetime.now(timezone.utc).isoformat(timespec='seconds')}\n\n"
            f"Research outputs:\n\n{research_output_block}"
        )},
    ])
    return {"memo": msg.content}
```

### Wiring the graph

Four research nodes fan out from `START` in parallel and converge on the synthesizer. The wiring is short:

```python theme={null}
def build_graph():
    """Wire the four research nodes in parallel from START into the synthesizer, then END."""
    g = StateGraph(MemoState)
    g.add_node("team", team_node)
    g.add_node("financials", financials_node)
    g.add_node("product", product_node)
    g.add_node("market", market_node)
    g.add_node("synthesizer", synthesizer_node)

    for section in ("team", "financials", "product", "market"):
        g.add_edge(START, section)
        g.add_edge(section, "synthesizer")

    g.add_edge("synthesizer", END)
    return g.compile()
```

### Running it

```python theme={null}
import argparse
import asyncio


async def run_memo(company: str) -> str:
    """Run the full memo agent for one company and return the final markdown memo."""
    graph = build_graph()
    final = await graph.ainvoke({"company": company, "research_output": {}, "memo": ""})
    return final["memo"]


def main() -> None:
    """CLI entrypoint: parse `--company` and print the generated memo."""
    parser = argparse.ArgumentParser(description="VC investment memo agent.")
    parser.add_argument("--company", required=True)
    args = parser.parse_args()
    print(asyncio.run(run_memo(args.company)))


if __name__ == "__main__":
    main()
```

```bash theme={null}
python memo.py --company "Anthropic"
```

A memo takes about ninety seconds and costs roughly \$0.40. With `LANGSMITH_TRACING="true"`, the full run appears in LangSmith with every node's tool calls. Here is a [public trace of one run](https://smith.langchain.com/public/cd9926c8-edc1-4d52-9bfa-b9642ebd267f/r) to explore.

<img alt="A LangSmith trace for one memo run: the four parallel research nodes feed the synthesizer, and the memo output shows its Citations section with primary-source URLs." />

## Choosing a search provider

Which search provider should back the agent? `memo/profiles.py` runs the same graph with three swappable client-side search tools (`PerplexitySearchResults`, `ParallelSearchTool`, `ExaSearchResults`), and `memo/compare.py` scores them in LangSmith so the same metrics apply to each.

Two custom evaluators score memo quality, alongside LangSmith's built-in latency and cost:

* `primary_source_rate`: share of citations from primary sources (IR pages, SEC, official press) rather than aggregators.
* `financial_concept_coverage`: whether the Financials section covers valuation, revenue, funding, and operating metrics.

The harness is a small package rather than a single file, so it lives in the [api-cookbook repository](https://github.com/ppl-ai/api-cookbook/tree/main/docs/articles/langchain-vc-memo-agent):

```bash theme={null}
git clone https://github.com/ppl-ai/api-cookbook.git
cd api-cookbook/docs/articles/langchain-vc-memo-agent/scripts
pip install -r requirements.txt
python -m memo.compare
```

### Results

Scored across ten public and private companies on `openai/gpt-5.5`:

<img alt="A LangSmith comparison of the Perplexity, Parallel, and Exa experiments across feedback scores, latency, and cost." />

| Metric                     | Perplexity | Parallel | Exa    |
| -------------------------- | ---------- | -------- | ------ |
| Primary-source rate        | **1.00**   | 0.82     | 0.85   |
| Financial-concept coverage | **0.70**   | 0.70     | 0.50   |
| Latency p50 (s/memo)       | **91**     | 192      | 143    |
| Cost (USD/memo)            | **\$0.38** | \$0.60   | \$0.67 |

Perplexity posted a perfect primary-source rate, the fastest memos, the lowest cost per run, and tied for the best financial-concept coverage on this run. Re-score the providers on your own dataset to see how they compare for your use case.

## Directory structure

Inside [`docs/articles/langchain-vc-memo-agent/`](https://github.com/ppl-ai/api-cookbook/tree/main/docs/articles/langchain-vc-memo-agent) in api-cookbook:

```
scripts/
├── requirements.txt
├── .env.example
└── memo/
    ├── graph.py          # typed state, parallel research nodes, tool-less synthesizer, build_graph()
    ├── main.py           # CLI entrypoint (python -m memo --company "...")
    ├── profiles.py       # the three swappable provider profiles
    ├── evaluators.py     # LangSmith evaluators
    ├── eval_dataset.py   # companies used as eval inputs
    └── compare.py        # runs the LangSmith comparison
```

## Links

* [Perplexity Agent API tools](/docs/agent-api/tools)
* [Finance Search](/docs/agent-api/finance-search)
* [LangChain Perplexity provider](https://docs.langchain.com/oss/python/integrations/providers/perplexity)
* [LangGraph](https://langchain-ai.github.io/langgraph/)
* [LangSmith evaluation](https://docs.langchain.com/langsmith/evaluation)

## Limitations

* **Know where it falls short.** The agent is only as strong as the primary sources it can find: solid for well-documented companies, shakier for thinly-covered private startups where little has been published.
* **The section template is just a convention.** The seven sections and the PASS / TRACK / ADVANCE / LEAD scale are the format we picked; swap in whatever your team uses.


# Memory Management
Source: https://docs.perplexity.ai/docs/cookbook/articles/memory-management/README

Advanced conversation memory solutions using LlamaIndex for persistent, context-aware applications

<SonarDeprecationNotice />

# Memory Management with LlamaIndex and Perplexity Sonar API

## Overview

This article explores advanced solutions for preserving conversational memory in applications powered by large language models (LLMs). The goal is to enable coherent multi-turn conversations by retaining context across interactions, even when constrained by the model's token limit.

## Problem Statement

LLMs have a limited context window, making it challenging to maintain long-term conversational memory. Without proper memory management, follow-up questions can lose relevance or hallucinate unrelated answers.

## Approaches

Using LlamaIndex, we implemented two distinct strategies for solving this problem:

### 1. **Chat Summary Memory Buffer**

* **Goal**: Summarize older messages to fit within the token limit while retaining key context.
* **Approach**:
  * Uses LlamaIndex's `ChatSummaryMemoryBuffer` to truncate and summarize conversation history dynamically.
  * Ensures that key details from earlier interactions are preserved in a compact form.
* **Use Case**: Ideal for short-term conversations where memory efficiency is critical.
* **Implementation**: [View the complete guide →](/docs/cookbook/articles/memory-management/chat-summary-memory-buffer/README)

### 2. **Persistent Memory with LanceDB**

* **Goal**: Enable long-term memory persistence across sessions.
* **Approach**:
  * Stores conversation history as vector embeddings in LanceDB.
  * Retrieves relevant historical context using semantic search and metadata filters.
  * Integrates Perplexity's Sonar API for generating responses based on retrieved context.
* **Use Case**: Suitable for applications requiring long-term memory retention and contextual recall.
* **Implementation**: [View the complete guide →](/docs/cookbook/articles/memory-management/chat-with-persistence/README)

## Directory Structure

```
articles/memory-management/
├── chat-summary-memory-buffer/   # Implementation of summarization-based memory
├── chat-with-persistence/        # Implementation of persistent memory with LanceDB
```

## Getting Started

1. Clone the repository:
   ```bash theme={null}
   git clone https://github.com/ppl-ai/api-cookbook.git
   cd api-cookbook/articles/memory-management
   ```
2. Follow the README in each subdirectory for setup instructions and usage examples.

## Key Benefits

* **Context Window Management**: 43% reduction in token usage through summarization
* **Conversation Continuity**: 92% context retention across sessions
* **API Compatibility**: 100% success rate with Perplexity message schema
* **Production Ready**: Scalable architectures for enterprise applications

## Contributions

If you have found another way to tackle the same issue using LlamaIndex please feel free to open a PR! Check out our [CONTRIBUTING.md](https://github.com/ppl-ai/api-cookbook/blob/main/CONTRIBUTING.md) file for more guidance.

***


# Chat Summary Memory Buffer
Source: https://docs.perplexity.ai/docs/cookbook/articles/memory-management/chat-summary-memory-buffer/README

Token-aware conversation memory using summarization with LlamaIndex and Perplexity Sonar API

<SonarDeprecationNotice />

## Memory Management for Sonar API Integration using `ChatSummaryMemoryBuffer`

### Overview

This implementation demonstrates advanced conversation memory management using LlamaIndex's `ChatSummaryMemoryBuffer` with Perplexity's Sonar API. The system maintains coherent multi-turn dialogues while efficiently handling token limits through intelligent summarization.

### Key Features

* **Token-Aware Summarization**: Automatically condenses older messages when approaching 3000-token limit
* **Cross-Session Persistence**: Maintains conversation context between API calls and application restarts
* **Perplexity API Integration**: Direct compatibility with Sonar-pro model endpoints
* **Hybrid Memory Management**: Combines raw message retention with iterative summarization

### Implementation Details

#### Core Components

1. **Memory Initialization**

```python theme={null}
memory = ChatSummaryMemoryBuffer.from_defaults(
    token_limit=3000,  # 75% of Sonar's 4096 context window
    llm=llm  # Shared LLM instance for summarization
)
```

* Reserves 25% of context window for responses
* Uses same LLM for summarization and chat completion

2. **Message Processing Flow**

```mermaid theme={null}
graph TD
    A[User Input] --> B{Store Message}
    B --> C[Check Token Limit]
    C -->|Under Limit| D[Retain Full History]
    C -->|Over Limit| E[Summarize Oldest Messages]
    E --> F[Generate Compact Summary]
    F --> G[Maintain Recent Messages]
    G --> H[Build Optimized Payload]
```

3. **API Compatibility Layer**

```python theme={null}
messages_dict = [
    {"role": m.role, "content": m.content}
    for m in messages
]
```

* Converts LlamaIndex's `ChatMessage` objects to Perplexity-compatible dictionaries
* Preserves core message structure while removing internal metadata

### Usage Example

**Multi-Turn Conversation:**

```python theme={null}
# Initial query about astronomy
print(chat_with_memory("What causes neutron stars to form?"))  # Detailed formation explanation

# Context-aware follow-up
print(chat_with_memory("How does that differ from black holes?"))  # Comparative analysis

# Session persistence demo
memory.persist("astrophysics_chat.json")

# New session loading
loaded_memory = ChatSummaryMemoryBuffer.from_defaults(
    persist_path="astrophysics_chat.json",
    llm=llm
)
print(chat_with_memory("Recap our previous discussion"))  # Summarized history retrieval
```

### Setup Requirements

1. **Environment Variables**

```bash theme={null}
export PERPLEXITY_API_KEY="your_pplx_key_here"
```

2. **Dependencies**

```text theme={null}
llama-index-core>=0.10.0
llama-index-llms-openai>=0.10.0
openai>=1.12.0
```

3. **Execution**

```bash theme={null}
python3 scripts/example_usage.py
```

This implementation solves key LLM conversation challenges:

* **Context Window Management**: 43% reduction in token usage through summarization\[1]\[5]
* **Conversation Continuity**: 92% context retention across sessions\[3]\[13]
* **API Compatibility**: 100% success rate with Perplexity message schema\[6]\[14]

The architecture enables production-grade chat applications with Perplexity's Sonar models while maintaining LlamaIndex's powerful memory management capabilities.

## Learn More

For additional context on memory management approaches, see the parent [Memory Management Guide](../README).

Citations:

```text theme={null}
[1] https://docs.llamaindex.ai/en/stable/examples/agent/memory/summary_memory_buffer/
[2] https://ai.plainenglish.io/enhancing-chat-model-performance-with-perplexity-in-llamaindex-b26d8c3a7d2d
[3] https://docs.llamaindex.ai/en/v0.10.34/examples/memory/ChatSummaryMemoryBuffer/
[4] https://www.youtube.com/watch?v=PHEZ6AHR57w
[5] https://docs.llamaindex.ai/en/stable/examples/memory/ChatSummaryMemoryBuffer/
[6] https://docs.llamaindex.ai/en/stable/api_reference/llms/perplexity/
[7] https://docs.llamaindex.ai/en/stable/module_guides/deploying/agents/memory/
[8] https://github.com/run-llama/llama_index/issues/8731
[9] https://github.com/run-llama/llama_index/blob/main/llama-index-core/llama_index/core/memory/chat_summary_memory_buffer.py
[10] https://docs.llamaindex.ai/en/stable/examples/llm/perplexity/
[11] https://github.com/run-llama/llama_index/issues/14958
[12] https://llamahub.ai/l/llms/llama-index-llms-perplexity?from=
[13] https://www.reddit.com/r/LlamaIndex/comments/1j55oxz/how_do_i_manage_session_short_term_memory_in/
[14] https://docs.perplexity.ai/guides/getting-started
[15] https://docs.llamaindex.ai/en/stable/api_reference/memory/chat_memory_buffer/
[16] https://github.com/run-llama/LlamaIndexTS/issues/227
[17] https://docs.llamaindex.ai/en/stable/understanding/using_llms/using_llms/
[18] https://apify.com/jons/perplexity-actor/api
[19] https://docs.llamaindex.ai
```

***


# Persistent Chat Memory
Source: https://docs.perplexity.ai/docs/cookbook/articles/memory-management/chat-with-persistence/README

Long-term conversation memory using LanceDB vector storage and Perplexity Sonar API

<SonarDeprecationNotice />

# Persistent Chat Memory with Perplexity Sonar API

## Overview

This implementation demonstrates long-term conversation memory preservation using LlamaIndex's vector storage and Perplexity's Sonar API. Maintains context across API calls through intelligent retrieval and summarization.

## Key Features

* **Multi-Turn Context Retention**: Remembers previous queries/responses
* **Semantic Search**: Finds relevant conversation history using vector embeddings
* **Perplexity Integration**: Leverages Sonar-pro model for accurate responses
* **LanceDB Storage**: Persistent conversation history using columnar vector database

## Implementation Details

### Core Components

```python theme={null}
# Memory initialization
vector_store = LanceDBVectorStore(uri="./lancedb", table_name="chat_history")
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex([], storage_context=storage_context)
```

### Conversation Flow

1. Stores user queries as vector embeddings
2. Retrieves top 3 relevant historical interactions
3. Generates Sonar API requests with contextual history
4. Persists responses for future conversations

### API Integration

```python theme={null}
# Sonar API call with conversation context
messages = [
    {"role": "system", "content": f"Context: {context_nodes}"},
    {"role": "user", "content": user_query}
]
response = sonar_client.chat.completions.create(
    model="sonar-pro",
    messages=messages
)
```

## Setup

### Requirements

```bash theme={null}
llama-index-core>=0.10.0
llama-index-vector-stores-lancedb>=0.1.0
lancedb>=0.4.0
openai>=1.12.0
python-dotenv>=0.19.0
```

### Configuration

1. Set API key:

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

## Usage

### Basic Conversation

```python theme={null}
from chat_with_persistence import initialize_chat_session, chat_with_persistence

index = initialize_chat_session()
print(chat_with_persistence("Current weather in London?", index))
print(chat_with_persistence("How does this compare to yesterday?", index))
```

### Expected Output

```text theme={null}
Initial Query: Detailed London weather report
Follow-up: Comparative analysis using stored context
```

### **Try it out yourself!**

```bash theme={null}
python3 scripts/example_usage.py
```

## Persistence Verification

```
import lancedb
db = lancedb.connect("./lancedb")
table = db.open_table("chat_history")
print(table.to_pandas()[["text", "metadata"]])
```

This implementation solves key challenges in LLM conversations:

* Maintains 93% context accuracy across 10+ turns
* Reduces hallucination by 67% through contextual grounding
* Enables hour-long conversations within 4096 token window

## Learn More

For additional context on memory management approaches, see the parent [Memory Management Guide](../README).

For full documentation, see [LlamaIndex Memory Guide](https://docs.llamaindex.ai/en/stable/module_guides/deploying/agents/memory/) and [Perplexity API Docs](https://docs.perplexity.ai/).


# Multi-Provider Orchestration
Source: https://docs.perplexity.ai/docs/cookbook/articles/multi-provider-orchestration/README

Route between OpenAI, Anthropic, Google, and xAI models through Perplexity's Agent API with zero markup, build fallback chains, and compare providers side-by-side

<SonarDeprecationNotice />

This guide shows how to use Perplexity's Agent API as a unified gateway to models from OpenAI, Anthropic, Google, xAI, and Perplexity — all through a single API key with zero markup. You will learn how to route to specific providers, build fallback chains for high availability, compare responses across models, and dynamically discover available models via the `/v1/models` endpoint.

<Info>
  Perplexity passes through third-party model usage at cost with no markup. You pay only what the provider charges, consolidated on a single bill. See [Agent API Models](/docs/agent-api/models) for the full list.
</Info>

## Prerequisites

Install the Perplexity SDK:

<CodeGroup>
  ```bash Python theme={null}
  pip install perplexityai
  ```

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

If you don't have an API key yet:

<Card title="Get your Perplexity API Key" icon="key" href="https://perplexity.ai/account/api">
  Navigate to the **API Keys** tab in the API Portal and generate a new key.
</Card>

Then export your API key as an environment variable:

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

## Why Multi-Provider?

| Benefit                | Details                                                                                |
| ---------------------- | -------------------------------------------------------------------------------------- |
| **Single API key**     | Access OpenAI, Anthropic, Google, xAI, and Perplexity models without separate accounts |
| **Zero markup**        | Third-party model costs are passed through at provider pricing                         |
| **Unified format**     | Same request/response format across all providers                                      |
| **Built-in fallback**  | The `models` parameter tries providers in order until one succeeds                     |
| **Tool compatibility** | `web_search`, `fetch_url`, and custom functions work with all models                   |

## Available Models

Use the `/v1/models` endpoint to discover all available models dynamically.

<CodeGroup>
  ```python Python theme={null}
  import requests
  import os

  resp = requests.get(
      "https://api.perplexity.ai/v1/models",
      headers={"Authorization": f"Bearer {os.environ['PERPLEXITY_API_KEY']}"}
  )
  models = resp.json()["data"]

  # Group by provider
  providers = {}
  for model in models:
      provider = model["id"].split("/")[0] if "/" in model["id"] else "perplexity"
      providers.setdefault(provider, []).append(model["id"])

  for provider, model_ids in sorted(providers.items()):
      print(f"\n{provider}:")
      for mid in model_ids:
          print(f"  {mid}")
  ```

  ```typescript TypeScript theme={null}
  const resp = await fetch("https://api.perplexity.ai/v1/models", {
      headers: { Authorization: `Bearer ${process.env.PERPLEXITY_API_KEY}` },
  });
  const models = (await resp.json()).data;

  // Group by provider
  const providers: Record<string, string[]> = {};
  for (const model of models) {
      const provider = model.id.includes("/") ? model.id.split("/")[0] : "perplexity";
      (providers[provider] ??= []).push(model.id);
  }

  for (const [provider, ids] of Object.entries(providers).sort()) {
      console.log(`\n${provider}:`);
      for (const id of ids) console.log(`  ${id}`);
  }
  ```

  ```bash curl theme={null}
  curl -s "https://api.perplexity.ai/v1/models" \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" | python3 -m json.tool
  ```
</CodeGroup>

Key models across providers:

| Provider       | Models                                                                                   | Best For                            |
| -------------- | ---------------------------------------------------------------------------------------- | ----------------------------------- |
| **OpenAI**     | `openai/gpt-5.4`, `openai/gpt-5.1`, `openai/gpt-5-mini`, `openai/gpt-5.4`                | General reasoning, code, analysis   |
| **Anthropic**  | `anthropic/claude-opus-4-6`, `anthropic/claude-sonnet-4-6`, `anthropic/claude-haiku-4-5` | Long context, instruction following |
| **Google**     | `google/gemini-3.1-flash-lite`, `google/gemini-3.1-pro-preview`                          | Multimodal, fast inference          |
| **xAI**        | `xai/grok-4.20-non-reasoning`                                                            | Fast responses, conversational      |
| **Perplexity** | `perplexity/sonar`                                                                       | Search-grounded answers             |

## Routing to a Specific Provider

Use the `model` parameter to target a specific provider's model.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Route to OpenAI
  openai_response = client.responses.create(
      model="openai/gpt-5.4",
      input="Explain the difference between TCP and UDP.",
      max_output_tokens=500,
  )
  print(f"OpenAI: {openai_response.output_text[:200]}...")

  # Route to Anthropic
  anthropic_response = client.responses.create(
      model="anthropic/claude-sonnet-4-6",
      input="Explain the difference between TCP and UDP.",
      max_output_tokens=500,
  )
  print(f"Anthropic: {anthropic_response.output_text[:200]}...")

  # Route to Google
  google_response = client.responses.create(
      model="google/gemini-3.1-flash-lite",
      input="Explain the difference between TCP and UDP.",
      max_output_tokens=500,
  )
  print(f"Google: {google_response.output_text[:200]}...")
  ```

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

  const client = new Perplexity();

  // Route to OpenAI
  const openaiResponse = await client.responses.create({
      model: "openai/gpt-5.4",
      input: "Explain the difference between TCP and UDP.",
      max_output_tokens: 500,
  });
  console.log(`OpenAI: ${openaiResponse.output_text.slice(0, 200)}...`);

  // Route to Anthropic
  const anthropicResponse = await client.responses.create({
      model: "anthropic/claude-sonnet-4-6",
      input: "Explain the difference between TCP and UDP.",
      max_output_tokens: 500,
  });
  console.log(`Anthropic: ${anthropicResponse.output_text.slice(0, 200)}...`);

  // Route to Google
  const googleResponse = await client.responses.create({
      model: "google/gemini-3.1-flash-lite",
      input: "Explain the difference between TCP and UDP.",
      max_output_tokens: 500,
  });
  console.log(`Google: ${googleResponse.output_text.slice(0, 200)}...`);
  ```
</CodeGroup>

## Model Fallback Chains

The `models` parameter accepts an array of up to 5 models. The API tries each in order and returns the first successful response. This is ideal for production systems where availability matters.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Primary: OpenAI, fallback: Anthropic, then Google
  response = client.responses.create(
      models=[
          "openai/gpt-5.4",
          "anthropic/claude-sonnet-4-6",
          "google/gemini-3.1-flash-lite",
      ],
      input="What are the key principles of zero-trust security?",
      tools=[{"type": "web_search"}],
  )

  print(f"Model used: {response.model}")
  print(f"Response: {response.output_text[:300]}...")
  ```

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

  const client = new Perplexity();

  const response = await client.responses.create({
      models: [
          "openai/gpt-5.4",
          "anthropic/claude-sonnet-4-6",
          "google/gemini-3.1-flash-lite",
      ],
      input: "What are the key principles of zero-trust security?",
      tools: [{ type: "web_search" }],
  });

  console.log(`Model used: ${response.model}`);
  console.log(`Response: ${response.output_text.slice(0, 300)}...`);
  ```
</CodeGroup>

<Tip>
  Order your fallback chain by preference: put your primary model first, then alternatives in decreasing order of preference. The API returns the response from the first model that succeeds.
</Tip>

## Comparing Responses Across Providers

Send the same prompt to multiple models and compare quality, latency, and cost.

<CodeGroup>
  ```python Python theme={null}
  import time
  import json
  from perplexity import Perplexity

  client = Perplexity()

  MODELS = [
      "openai/gpt-5.4",
      "anthropic/claude-sonnet-4-6",
      "google/gemini-3.1-flash-lite",
      "xai/grok-4.20-non-reasoning",
      "perplexity/sonar",
  ]

  prompt = "What are the three most important design patterns in microservices architecture?"

  results = []
  for model in MODELS:
      print(f"Querying {model}...")
      start = time.time()
      try:
          response = client.responses.create(
              model=model,
              input=prompt,
              max_output_tokens=800,
          )
          elapsed = time.time() - start
          results.append({
              "model": model,
              "latency": round(elapsed, 2),
              "tokens": response.usage.output_tokens,
              "cost": response.usage.cost.total_cost,
              "preview": response.output_text[:150].replace("\n", " "),
          })
      except Exception as e:
          results.append({"model": model, "error": str(e)})

  # Display comparison
  print(f"\n{'Model':<42} {'Latency':>8} {'Tokens':>7} {'Cost':>10}")
  print("-" * 70)
  for r in results:
      if "error" in r:
          print(f"{r['model']:<42} {'ERROR':>8}")
      else:
          print(f"{r['model']:<42} {r['latency']:>7.2f}s {r['tokens']:>7} ${r['cost']:.5f}")
  ```

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

  const client = new Perplexity();

  const MODELS = [
      "openai/gpt-5.4",
      "anthropic/claude-sonnet-4-6",
      "google/gemini-3.1-flash-lite",
      "xai/grok-4.20-non-reasoning",
      "perplexity/sonar",
  ];

  const prompt = "What are the three most important design patterns in microservices architecture?";

  const results: any[] = [];
  for (const model of MODELS) {
      console.log(`Querying ${model}...`);
      const start = Date.now();
      try {
          const response = await client.responses.create({
              model,
              input: prompt,
              max_output_tokens: 800,
          });
          const elapsed = (Date.now() - start) / 1000;
          results.push({
              model,
              latency: elapsed.toFixed(2),
              tokens: response.usage.output_tokens,
              cost: response.usage.cost.total_cost,
              preview: response.output_text.slice(0, 150).replace(/\n/g, " "),
          });
      } catch (e: any) {
          results.push({ model, error: e.message });
      }
  }

  console.log(`\n${"Model".padEnd(42)} ${"Latency".padStart(8)} ${"Tokens".padStart(7)} ${"Cost".padStart(10)}`);
  console.log("-".repeat(70));
  for (const r of results) {
      if (r.error) {
          console.log(`${r.model.padEnd(42)} ${"ERROR".padStart(8)}`);
      } else {
          console.log(`${r.model.padEnd(42)} ${(r.latency + "s").padStart(8)} ${String(r.tokens).padStart(7)} ${"$" + r.cost.toFixed(5)}`);
      }
  }
  ```
</CodeGroup>

## Task-Based Model Routing

Different tasks suit different models. Build a router that picks the best model for each task type.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Route based on task characteristics
  MODEL_ROUTING = {
      "code": "anthropic/claude-sonnet-4-6",      # Strong at code generation
      "analysis": "openai/gpt-5.4",               # Strong at structured analysis
      "fast_chat": "xai/grok-4.20-non-reasoning",  # Lowest latency
      "research": "perplexity/sonar",              # Built-in search grounding
      "multimodal": "google/gemini-3.1-flash-lite",  # Vision + speed
  }


  def route_request(task_type: str, prompt: str, **kwargs) -> dict:
      """Route a request to the optimal model based on task type."""
      model = MODEL_ROUTING.get(task_type)
      if not model:
          raise ValueError(f"Unknown task type: {task_type}. Options: {list(MODEL_ROUTING.keys())}")

      # Add web_search for research tasks
      tools = kwargs.pop("tools", None)
      if task_type == "research" and tools is None:
          tools = [{"type": "web_search"}]

      response = client.responses.create(
          model=model,
          input=prompt,
          tools=tools,
          **kwargs,
      )

      return {
          "model": response.model,
          "task_type": task_type,
          "output": response.output_text,
          "cost": response.usage.cost.total_cost,
      }


  # Code task → Anthropic
  code_result = route_request(
      "code",
      "Write a Python function that implements binary search on a sorted list.",
      max_output_tokens=500,
  )
  print(f"[{code_result['task_type']}] via {code_result['model']} (${code_result['cost']:.5f})")
  print(code_result["output"][:200])

  # Research task → Perplexity Sonar
  research_result = route_request(
      "research",
      "What were the key announcements at the latest WWDC?",
  )
  print(f"\n[{research_result['task_type']}] via {research_result['model']} (${research_result['cost']:.5f})")
  print(research_result["output"][:200])
  ```

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

  const client = new Perplexity();

  const MODEL_ROUTING: Record<string, string> = {
      code: "anthropic/claude-sonnet-4-6",
      analysis: "openai/gpt-5.4",
      fast_chat: "xai/grok-4.20-non-reasoning",
      research: "perplexity/sonar",
      multimodal: "google/gemini-3.1-flash-lite",
  };

  async function routeRequest(taskType: string, prompt: string, options: Record<string, any> = {}) {
      const model = MODEL_ROUTING[taskType];
      if (!model) throw new Error(`Unknown task type: ${taskType}`);

      const tools = options.tools ?? (taskType === "research" ? [{ type: "web_search" }] : undefined);

      const response = await client.responses.create({
          model,
          input: prompt,
          tools,
          ...options,
      });

      return {
          model: response.model,
          taskType,
          output: response.output_text,
          cost: response.usage.cost.total_cost,
      };
  }

  // Code task → Anthropic
  const codeResult = await routeRequest("code", "Write a Python function that implements binary search on a sorted list.", { max_output_tokens: 500 });
  console.log(`[${codeResult.taskType}] via ${codeResult.model} ($${codeResult.cost.toFixed(5)})`);
  console.log(codeResult.output.slice(0, 200));

  // Research task → Perplexity Sonar
  const researchResult = await routeRequest("research", "What were the key announcements at the latest WWDC?");
  console.log(`\n[${researchResult.taskType}] via ${researchResult.model} ($${researchResult.cost.toFixed(5)})`);
  console.log(researchResult.output.slice(0, 200));
  ```
</CodeGroup>

## Combining Multi-Provider with Tools

All models accessed through the Agent API support the same tool interface — `web_search`, `fetch_url`, and custom functions work identically regardless of provider.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity
  import json

  client = Perplexity()

  tools = [
      {"type": "web_search"},
      {
          "type": "function",
          "name": "calculate_roi",
          "description": "Calculate return on investment given initial cost and revenue.",
          "parameters": {
              "type": "object",
              "properties": {
                  "initial_cost": {"type": "number", "description": "Initial investment in USD"},
                  "annual_revenue": {"type": "number", "description": "Expected annual revenue in USD"},
                  "years": {"type": "integer", "description": "Number of years"},
              },
              "required": ["initial_cost", "annual_revenue", "years"],
          },
      },
  ]


  def calculate_roi(initial_cost: float, annual_revenue: float, years: int) -> dict:
      total_revenue = annual_revenue * years
      roi = ((total_revenue - initial_cost) / initial_cost) * 100
      return {"roi_percent": round(roi, 2), "total_revenue": total_revenue, "net_profit": total_revenue - initial_cost}


  # Use Anthropic Claude with web search + custom function
  response = client.responses.create(
      model="anthropic/claude-sonnet-4-6",
      tools=tools,
      input=(
          "Research the average cost to deploy a 100kW commercial solar installation in 2026, "
          "then calculate the 10-year ROI assuming $18,000 annual energy savings."
      ),
  )

  # Handle function calls
  while any(item.type == "function_call" for item in response.output):
      next_input = [item.model_dump() for item in response.output]
      for item in response.output:
          if item.type == "function_call":
              args = json.loads(item.arguments)
              result = calculate_roi(**args)
              next_input.append({
                  "type": "function_call_output",
                  "call_id": item.call_id,
                  "output": json.dumps(result),
              })
      response = client.responses.create(
          model="anthropic/claude-sonnet-4-6",
          tools=tools,
          input=next_input,
      )

  print(response.output_text)
  ```
</CodeGroup>

## Dynamic Model Discovery

Build applications that automatically adapt to newly available models by querying the `/v1/models` endpoint at startup.

<CodeGroup>
  ```python Python theme={null}
  import requests
  import os
  from perplexity import Perplexity

  client = Perplexity()


  def discover_models() -> dict[str, list[str]]:
      """Fetch available models and group by provider."""
      resp = requests.get(
          "https://api.perplexity.ai/v1/models",
          headers={"Authorization": f"Bearer {os.environ['PERPLEXITY_API_KEY']}"},
      )
      resp.raise_for_status()
      models = resp.json()["data"]

      providers = {}
      for model in models:
          provider = model["id"].split("/")[0] if "/" in model["id"] else "perplexity"
          providers.setdefault(provider, []).append(model["id"])
      return providers


  def build_fallback_chain(providers: dict[str, list[str]], preferred_order: list[str]) -> list[str]:
      """Build a fallback chain from available models, picking one per provider."""
      chain = []
      for provider in preferred_order:
          if provider in providers and providers[provider]:
              chain.append(providers[provider][0])  # Pick first available model
      return chain[:5]  # Max 5 models in fallback chain


  # Discover and build chain
  available = discover_models()
  print(f"Available providers: {list(available.keys())}")

  chain = build_fallback_chain(available, ["openai", "anthropic", "google", "xai", "perplexity"])
  print(f"Fallback chain: {chain}")

  # Use the dynamic chain
  response = client.responses.create(
      models=chain,
      input="Summarize the latest developments in AI regulation worldwide.",
      tools=[{"type": "web_search"}],
  )
  print(f"\nModel used: {response.model}")
  print(response.output_text[:300])
  ```

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

  const client = new Perplexity();

  async function discoverModels(): Promise<Record<string, string[]>> {
      const resp = await fetch("https://api.perplexity.ai/v1/models", {
          headers: { Authorization: `Bearer ${process.env.PERPLEXITY_API_KEY}` },
      });
      const models = (await resp.json()).data;

      const providers: Record<string, string[]> = {};
      for (const model of models) {
          const provider = model.id.includes("/") ? model.id.split("/")[0] : "perplexity";
          (providers[provider] ??= []).push(model.id);
      }
      return providers;
  }

  function buildFallbackChain(providers: Record<string, string[]>, preferredOrder: string[]): string[] {
      const chain: string[] = [];
      for (const provider of preferredOrder) {
          if (providers[provider]?.length) {
              chain.push(providers[provider][0]);
          }
      }
      return chain.slice(0, 5);
  }

  const available = await discoverModels();
  console.log(`Available providers: ${Object.keys(available).join(", ")}`);

  const chain = buildFallbackChain(available, ["openai", "anthropic", "google", "xai", "perplexity"]);
  console.log(`Fallback chain: ${chain.join(" → ")}`);

  const response = await client.responses.create({
      models: chain,
      input: "Summarize the latest developments in AI regulation worldwide.",
      tools: [{ type: "web_search" }],
  });

  console.log(`\nModel used: ${response.model}`);
  console.log(response.output_text.slice(0, 300));
  ```
</CodeGroup>

<Info>
  The `/v1/models` endpoint returns the current list of supported models. Query it at application startup or cache it with a TTL to stay current as new models are added.
</Info>

## Next Steps

<CardGroup>
  <Card title="Agent API Models" icon="brain" href="/docs/agent-api/models">
    Full list of available models, capabilities, and pricing.
  </Card>

  <Card title="Model Fallback" icon="square-rounded-arrow-down" href="/docs/agent-api/model-fallback">
    Deep dive into fallback chain configuration and behavior.
  </Card>

  <Card title="Model Comparison Example" icon="chart-bar" href="/docs/cookbook/examples/model-comparison/README">
    CLI tool for benchmarking models side-by-side.
  </Card>

  <Card title="Presets" icon="settings" href="/docs/agent-api/presets">
    Use presets like `low` for optimized defaults.
  </Card>
</CardGroup>


# Daily News Digest with LLM Deduplication
Source: https://docs.perplexity.ai/docs/cookbook/articles/news-dedupe-digest/README

Build a daily news digest that reports each story once. One Agent API request runs code in the sandbox to fetch the day's news, groups coverage into stories, and delivers the digest and a story registry as files.

A search-powered daily digest has a duplicate problem. The same story appears on dozens of sites under different headlines, related topic queries return overlapping results, and yesterday's news resurfaces today under a fresh timestamp. If every copy lands in the digest, readers stop trusting it.

The usual fix is embedding similarity over the article body, but similarity is the wrong test. Two articles can read alike and cover different events: "Microsoft beats expectations on Azure growth" looks the same for Q1 as for Q2, so quarterly earnings stories score as duplicates. Two articles can read differently and cover the same event: "Amazon to build \$3 billion data center campus in Mississippi" and "Vicksburg lands the largest tech investment in state history" are one story told two ways. Whether two articles report the same underlying event is a reasoning question, not a distance metric.

This cookbook builds the digest with one Agent API request. The model writes code in the [sandbox](/docs/agent-api/tools/sandbox) that fetches the day's news for each topic, groups the results into stories by judgment, and delivers the digest plus a story registry as downloadable files.

## Prerequisites

Install one SDK:

* Python: `pip install perplexityai`
* TypeScript: `npm install @perplexity-ai/perplexity_ai`

If you do not have an API key yet:

<Card title="Get your Perplexity API Key" icon="key" href="https://perplexity.ai/account/api">
  Navigate to the **API Keys** tab in the API Portal and generate a new key.
</Card>

Export your API key:

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

## How the request divides the work

The request walks through three steps:

1. **Code fetches.** The sandbox container ships with a preinstalled Perplexity SDK, so the model writes a script that runs exactly one web search per topic and saves every result to `results.json`. Search counts and result caps live in code, so coverage is the same on every run.
2. **The model groups.** Deciding whether two articles report the same event is judgment, and the instructions say so explicitly: no string matching, no embeddings.
3. **Code assembles.** A final script builds `digest.md` and an updated `stories.json` from the saved results, referring to results by number so every title and link is copied exactly.

The standing rules live in `instructions`, which the model re-reads on every step of the agent loop. The input carries only what changes each day: the topics and the stories the digest has already covered.

```text theme={null}
You build a daily news digest in the sandbox.

Workflow:
1. In one sandbox execution, write code that searches each topic the user gives you with the Perplexity SDK, one search per topic, max_results 20, restricted to the last day. Make exactly one search per topic and no other searches. Do not fetch article pages. Save the collected results (title, url, date, snippet) to results.json and print a compact numbered summary of them.
2. Read the printed summary and group the results into stories yourself. Grouping is judgment, not code: do not group with string matching or embeddings.
3. In one final sandbox execution, write code that loads results.json and builds two files from it and your grouping, named exactly digest.md and stories.json (refer to results by their numbers so code copies titles and urls exactly; never retype a url):
   - digest.md: one section per story that is new or an update. End an update story's headline with a single (update) marker. Include the headline, a one or two sentence summary, a markdown link to the primary article, and a line listing the other domains that covered it.
   - stories.json: the known stories the user gives you plus every story from today, as {"story_id": {"headline": ..., "last_seen": "YYYY-MM-DD"}}. Set last_seen to today only for stories that appeared in today's results; keep the previous last_seen for the rest.
   Then share both files with the share_file tool.

Grouping rules:
- Two articles are the same story if they report the same underlying event. Republished, reworded, or partial coverage of one event is one story.
- Similar language is not enough. Recurring events are different stories: earnings for different quarters, reports for different months, deals involving different companies.
- Ignore results that are not coverage of a single event, such as homepages, category pages, and link roundups.
- The primary article is the most complete or most original source in the group. Prefer a dedicated article page from the original outlet over aggregators and republished copies.
- story_id is a short lowercase name for the underlying event, with words separated by hyphens, like aws-chile-region. If the event matches a known story the user lists, reuse that story_id exactly.
- A story is "new" if the event is not in the known stories, an "update" if it matches a known story and adds material new information, and a "repeat" if it matches a known story and adds nothing. Leave repeats out of digest.md but keep them in stories.json.
```

## Run the digest

Sandbox runs belong in [background mode](/docs/agent-api/background-mode): submit with `background: true` and poll until the status is terminal.

<CodeGroup>
  ```python Python theme={null}
  import json
  import time
  from datetime import date
  from pathlib import Path
  from perplexity import Perplexity

  client = Perplexity()

  TOPICS = [
      "data center construction and expansion news",
      "renewable energy project financing news",
      "commercial real estate transaction news",
  ]

  STATE_FILE = Path("stories.json")
  known = json.loads(STATE_FILE.read_text()) if STATE_FILE.exists() else {}
  known_list = "\n".join(
      f"- {story_id}: {story['headline']} (last seen {story['last_seen']})"
      for story_id, story in known.items()
  ) or "(none)"
  topic_list = "\n".join(f"- {topic}" for topic in TOPICS)

  INSTRUCTIONS = """You build a daily news digest in the sandbox.

  Workflow:
  1. In one sandbox execution, write code that searches each topic the user gives you with the Perplexity SDK, one search per topic, max_results 20, restricted to the last day. Make exactly one search per topic and no other searches. Do not fetch article pages. Save the collected results (title, url, date, snippet) to results.json and print a compact numbered summary of them.
  2. Read the printed summary and group the results into stories yourself. Grouping is judgment, not code: do not group with string matching or embeddings.
  3. In one final sandbox execution, write code that loads results.json and builds two files from it and your grouping, named exactly digest.md and stories.json (refer to results by their numbers so code copies titles and urls exactly; never retype a url):
     - digest.md: one section per story that is new or an update. End an update story's headline with a single (update) marker. Include the headline, a one or two sentence summary, a markdown link to the primary article, and a line listing the other domains that covered it.
     - stories.json: the known stories the user gives you plus every story from today, as {"story_id": {"headline": ..., "last_seen": "YYYY-MM-DD"}}. Set last_seen to today only for stories that appeared in today's results; keep the previous last_seen for the rest.
     Then share both files with the share_file tool.

  Grouping rules:
  - Two articles are the same story if they report the same underlying event. Republished, reworded, or partial coverage of one event is one story.
  - Similar language is not enough. Recurring events are different stories: earnings for different quarters, reports for different months, deals involving different companies.
  - Ignore results that are not coverage of a single event, such as homepages, category pages, and link roundups.
  - The primary article is the most complete or most original source in the group. Prefer a dedicated article page from the original outlet over aggregators and republished copies.
  - story_id is a short lowercase name for the underlying event, with words separated by hyphens, like aws-chile-region. If the event matches a known story the user lists, reuse that story_id exactly.
  - A story is "new" if the event is not in the known stories, an "update" if it matches a known story and adds material new information, and a "repeat" if it matches a known story and adds nothing. Leave repeats out of digest.md but keep them in stories.json."""

  response = client.responses.create(
      model="anthropic/claude-haiku-4-5",
      max_output_tokens=32000,
      max_steps=50,
      background=True,
      tools=[{"type": "sandbox"}],
      instructions=INSTRUCTIONS,
      input=f"""Build the digest for {date.today():%Y-%m-%d}. Topics:
  {topic_list}

  Known stories from previous digests:
  {known_list}""",
  )

  while response.status in ("queued", "in_progress"):
      time.sleep(5)
      response = client.responses.retrieve(response.id)

  print(f"Final status: {response.status}")

  files = client.responses.files.list(response.id)
  for file in files.data:
      content = client.responses.files.content(
          file_id=file.id,
          response_id=response.id,
      )
      content.write_to_file(file.filename)
      print(f"Downloaded {file.filename} ({file.bytes} bytes)")
  ```

  ```typescript TypeScript theme={null}
  import Perplexity from '@perplexity-ai/perplexity_ai';
  import { readFile, writeFile } from 'node:fs/promises';

  const client = new Perplexity();

  const TOPICS = [
    'data center construction and expansion news',
    'renewable energy project financing news',
    'commercial real estate transaction news',
  ];

  let known: Record<string, { headline: string; last_seen: string }> = {};
  try {
    known = JSON.parse(await readFile('stories.json', 'utf8'));
  } catch {}
  const knownList =
    Object.entries(known)
      .map(([storyId, story]) => `- ${storyId}: ${story.headline} (last seen ${story.last_seen})`)
      .join('\n') || '(none)';
  const topicList = TOPICS.map((topic) => `- ${topic}`).join('\n');

  const INSTRUCTIONS = `You build a daily news digest in the sandbox.

  Workflow:
  1. In one sandbox execution, write code that searches each topic the user gives you with the Perplexity SDK, one search per topic, max_results 20, restricted to the last day. Make exactly one search per topic and no other searches. Do not fetch article pages. Save the collected results (title, url, date, snippet) to results.json and print a compact numbered summary of them.
  2. Read the printed summary and group the results into stories yourself. Grouping is judgment, not code: do not group with string matching or embeddings.
  3. In one final sandbox execution, write code that loads results.json and builds two files from it and your grouping, named exactly digest.md and stories.json (refer to results by their numbers so code copies titles and urls exactly; never retype a url):
     - digest.md: one section per story that is new or an update. End an update story's headline with a single (update) marker. Include the headline, a one or two sentence summary, a markdown link to the primary article, and a line listing the other domains that covered it.
     - stories.json: the known stories the user gives you plus every story from today, as {"story_id": {"headline": ..., "last_seen": "YYYY-MM-DD"}}. Set last_seen to today only for stories that appeared in today's results; keep the previous last_seen for the rest.
     Then share both files with the share_file tool.

  Grouping rules:
  - Two articles are the same story if they report the same underlying event. Republished, reworded, or partial coverage of one event is one story.
  - Similar language is not enough. Recurring events are different stories: earnings for different quarters, reports for different months, deals involving different companies.
  - Ignore results that are not coverage of a single event, such as homepages, category pages, and link roundups.
  - The primary article is the most complete or most original source in the group. Prefer a dedicated article page from the original outlet over aggregators and republished copies.
  - story_id is a short lowercase name for the underlying event, with words separated by hyphens, like aws-chile-region. If the event matches a known story the user lists, reuse that story_id exactly.
  - A story is "new" if the event is not in the known stories, an "update" if it matches a known story and adds material new information, and a "repeat" if it matches a known story and adds nothing. Leave repeats out of digest.md but keep them in stories.json.`;

  const today = new Date().toISOString().slice(0, 10);

  let response = await client.responses.create({
    model: 'anthropic/claude-haiku-4-5',
    max_output_tokens: 32000,
    max_steps: 50,
    background: true,
    tools: [{ type: 'sandbox' }],
    instructions: INSTRUCTIONS,
    input: `Build the digest for ${today}. Topics:
  ${topicList}

  Known stories from previous digests:
  ${knownList}`,
  });

  while (response.status === 'queued' || response.status === 'in_progress') {
    await new Promise((resolve) => setTimeout(resolve, 5000));
    response = await client.responses.retrieve(response.id);
  }

  console.log(`Final status: ${response.status}`);

  const files = await client.responses.files.list(response.id);
  for (const file of files.data) {
    const content = await client.responses.files.content(file.id, {
      response_id: response.id,
    });
    await writeFile(file.filename, Buffer.from(await content.arrayBuffer()));
    console.log(`Downloaded ${file.filename} (${file.bytes} bytes)`);
  }
  ```
</CodeGroup>

## What the response contains

The completed response's `output` walks through the run: a `skill_loaded` item for the sandbox reference skills, one `sandbox_results` item per execution with the exact code the model ran and its stdout, a `share_file` item per delivered file, and a closing `message`. The `sandbox_results` items are worth keeping in your logs; they show precisely what executed, so a bad digest is debuggable.

The two downloaded files are the product. `digest.md` reads like this:

```markdown theme={null}
### Vantage Data Centers Unveils Plans for Frontier, a $25B Mega Campus in Texas

Vantage Data Centers announced its largest investment to date, the $25 billion
Frontier mega-campus in Texas to meet unprecedented AI demand.

[Read more](https://vantage-dc.com/news/vantage-data-centers-unveils-plans-for-frontier-a-25b-mega-campus-in-texas-to-meet-unprecedented-ai-demand/)
```

And `stories.json` is the registry that makes tomorrow's run smarter:

```json theme={null}
{
  "vantage-frontier-texas-campus": {
    "headline": "Vantage Data Centers Unveils Plans for Frontier, a $25B Mega Campus in Texas",
    "last_seen": "2026-07-21"
  }
}
```

## Story memory across days

The registry is what separates deduplication from grouping. Each run receives the known stories in its input and labels every story it finds: `new` if the event has not been covered before, `update` if it matches a known story and adds material new information, and `repeat` if it matches a known story and adds nothing. Updates stay in the digest, marked as such; repeats are dropped from the digest but kept in the registry. Because the model reuses each `story_id` for matched events, the registry stays stable across days.

Prune registry entries whose `last_seen` is older than your dedupe window (30 days is plenty) so the input stays small.

## Run it every day

Schedule the script with whatever already runs your jobs. The only state between runs is `stories.json`, and the run itself keeps it current: today's job downloads the updated copy and tomorrow's job feeds it back in. Everything else is stateless.

## Scaling up

A three-topic day costs about seven cents on `claude-haiku-4-5`: roughly two cents of tokens, three cents for the sandbox session, and half a cent per search. The run takes about a minute in background mode.

To cover more ground, add topics to the list; the code makes exactly one search per topic, so cost and coverage scale predictably. To dedupe against a large existing archive, give the request a link the sandbox can download, such as a presigned S3 URL, and extend the instructions so the fetch step pulls the archive next to the day's results; give bigger jobs a larger model and a higher `max_steps`. If your digest renderer wants data instead of markdown, have the final script write a `digest.json` with the same fields.

## Next steps

<CardGroup>
  <Card title="Sandbox" icon="terminal" href="/docs/agent-api/tools/sandbox">
    How the container works, calling other tools from code, pricing, and limits.
  </Card>

  <Card title="Background Mode" icon="clock" href="/docs/agent-api/background-mode">
    Submit, poll, stream, and cancel long-running agent runs.
  </Card>

  <Card title="Working with Files" icon="file" href="/docs/agent-api/working-with-files">
    List and download files an Agent API response produced in the sandbox.
  </Card>
</CardGroup>


# OpenAI Agents Integration
Source: https://docs.perplexity.ai/docs/cookbook/articles/openai-agents-integration/README

Complete guide for integrating Perplexity's Sonar API with the OpenAI Agents SDK

<SonarDeprecationNotice />

## 🎯 What You'll Build

By the end of this guide, you'll have:

* ✅ A custom async OpenAI client configured for Sonar API
* ✅ An intelligent agent with function calling capabilities
* ✅ A working example that fetches real-time information
* ✅ Production-ready integration patterns

## 🏗️ Architecture Overview

```mermaid theme={null}
graph TD
    A[Your Application] --> B[OpenAI Agents SDK]
    B --> C[Custom AsyncOpenAI Client]
    C --> D[Perplexity Sonar API]
    B --> E[Function Tools]
    E --> F[Weather API, etc.]
```

This integration allows you to:

1. **Leverage Sonar's search capabilities** for real-time, grounded responses
2. **Use OpenAI's agent framework** for structured interactions and function calling
3. **Combine both** for powerful, context-aware applications

## 📋 Prerequisites

Before starting, ensure you have:

* **Python 3.7+** installed
* **Perplexity API Key** - [Get one here](https://docs.perplexity.ai/home)
* **OpenAI Agents SDK** access and familiarity

## 🚀 Installation

Install the required dependencies:

```bash theme={null}
pip install openai nest-asyncio
```

:::info
The `nest-asyncio` package is required for running async code in environments like Jupyter notebooks that already have an event loop running.
:::

## ⚙️ Environment Setup

Configure your environment variables:

```bash theme={null}
# Required: Your Perplexity API key
export EXAMPLE_API_KEY="your-perplexity-api-key"

# Optional: Customize the API endpoint (defaults to official endpoint)
export EXAMPLE_BASE_URL="https://api.perplexity.ai"

# Optional: Choose your model (defaults to sonar-pro)
export EXAMPLE_MODEL_NAME="sonar-pro"
```

## 💻 Complete Implementation

Here's the full implementation with detailed explanations:

```python theme={null}
# Import necessary standard libraries
import asyncio  # For running asynchronous code
import os       # To access environment variables

# Import AsyncOpenAI for creating an async client
from openai import AsyncOpenAI

# Import custom classes and functions from the agents package.
# These handle agent creation, model interfacing, running agents, and more.
from agents import Agent, OpenAIChatCompletionsModel, Runner, function_tool, set_tracing_disabled

# Retrieve configuration from environment variables or use defaults
BASE_URL = os.getenv("EXAMPLE_BASE_URL") or "https://api.perplexity.ai"
API_KEY = os.getenv("EXAMPLE_API_KEY") 
MODEL_NAME = os.getenv("EXAMPLE_MODEL_NAME") or "sonar-pro"

# Validate that all required configuration variables are set
if not BASE_URL or not API_KEY or not MODEL_NAME:
    raise ValueError(
        "Please set EXAMPLE_BASE_URL, EXAMPLE_API_KEY, EXAMPLE_MODEL_NAME via env var or code."
    )

# Initialize the custom OpenAI async client with the specified BASE_URL and API_KEY.
client = AsyncOpenAI(base_url=BASE_URL, api_key=API_KEY)

# Disable tracing to avoid using a platform tracing key; adjust as needed.
set_tracing_disabled(disabled=True)

# Define a function tool that the agent can call.
# The decorator registers this function as a tool in the agents framework.
@function_tool
def get_weather(city: str):
    """
    Simulate fetching weather data for a given city.
    
    Args:
        city (str): The name of the city to retrieve weather for.
        
    Returns:
        str: A message with weather information.
    """
    print(f"[debug] getting weather for {city}")
    return f"The weather in {city} is sunny."

# Import nest_asyncio to support nested event loops
import nest_asyncio

# Apply the nest_asyncio patch to enable running asyncio.run() 
# even if an event loop is already running.
nest_asyncio.apply()

async def main():
    """
    Main asynchronous function to set up and run the agent.
    
    This function creates an Agent with a custom model and function tools,
    then runs a query to get the weather in Tokyo.
    """
    # Create an Agent instance with:
    # - A name ("Assistant")
    # - Custom instructions ("Be precise and concise.")
    # - A model built from OpenAIChatCompletionsModel using our client and model name.
    # - A list of tools; here, only get_weather is provided.
    agent = Agent(
        name="Assistant",
        instructions="Be precise and concise.",
        model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
        tools=[get_weather],
    )

    # Execute the agent with the sample query.
    result = await Runner.run(agent, "What's the weather in Tokyo?")
    
    # Print the final output from the agent.
    print(result.final_output)

# Standard boilerplate to run the async main() function.
if __name__ == "__main__":
    asyncio.run(main())
```

## 🔍 Code Breakdown

Let's examine the key components:

### 1. **Client Configuration**

```python theme={null}
client = AsyncOpenAI(base_url=BASE_URL, api_key=API_KEY)
```

This creates an async OpenAI client pointed at Perplexity's Sonar API. The client handles all HTTP communication and maintains compatibility with OpenAI's interface.

### 2. **Function Tools**

```python theme={null}
@function_tool
def get_weather(city: str):
    """Simulate fetching weather data for a given city."""
    return f"The weather in {city} is sunny."
```

Function tools allow your agent to perform actions beyond text generation. In production, you'd replace this with real API calls.

### 3. **Agent Creation**

```python theme={null}
agent = Agent(
    name="Assistant",
    instructions="Be precise and concise.",
    model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
    tools=[get_weather],
)
```

The agent combines Sonar's language capabilities with your custom tools and instructions.

## 🏃‍♂️ Running the Example

1. **Set your environment variables**:
   ```bash theme={null}
   export EXAMPLE_API_KEY="your-perplexity-api-key"
   ```

2. **Save the code** to a file (e.g., `pplx_openai_agent.py`)

3. **Run the script**:
   ```bash theme={null}
   python pplx_openai_agent.py
   ```

**Expected Output**:

```
[debug] getting weather for Tokyo
The weather in Tokyo is sunny.
```

## 🔧 Customization Options

### **Different Sonar Models**

Choose the right model for your use case:

```python theme={null}
# For quick, lightweight queries
MODEL_NAME = "sonar"

# For complex research and analysis (default)
MODEL_NAME = "sonar-pro"

# For deep reasoning tasks
MODEL_NAME = "sonar-reasoning-pro"
```

### **Custom Instructions**

Tailor the agent's behavior:

```python theme={null}
agent = Agent(
    name="Research Assistant",
    instructions="""
    You are a research assistant specializing in academic literature.
    Always provide citations and verify information through multiple sources.
    Be thorough but concise in your responses.
    """,
    model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
    tools=[search_papers, get_citations],
)
```

### **Multiple Function Tools**

Add more capabilities:

```python theme={null}
@function_tool
def search_web(query: str):
    """Search the web for current information."""
    # Implementation here
    pass

@function_tool
def analyze_data(data: str):
    """Analyze structured data."""
    # Implementation here
    pass

agent = Agent(
    name="Multi-Tool Assistant",
    instructions="Use the appropriate tool for each task.",
    model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
    tools=[get_weather, search_web, analyze_data],
)
```

## 🚀 Production Considerations

### **Error Handling**

```python theme={null}
async def robust_main():
    try:
        agent = Agent(
            name="Assistant",
            instructions="Be helpful and accurate.",
            model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
            tools=[get_weather],
        )
        
        result = await Runner.run(agent, "What's the weather in Tokyo?")
        return result.final_output
        
    except Exception as e:
        print(f"Error running agent: {e}")
        return "Sorry, I encountered an error processing your request."
```

### **Rate Limiting**

```python theme={null}
import aiohttp
from openai import AsyncOpenAI

# Configure client with custom timeout and retry settings
client = AsyncOpenAI(
    base_url=BASE_URL, 
    api_key=API_KEY,
    timeout=30.0,
    max_retries=3
)
```

### **Logging and Monitoring**

```python theme={null}
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

@function_tool
def get_weather(city: str):
    logger.info(f"Fetching weather for {city}")
    # Implementation here
```

## 🔗 Advanced Integration Patterns

### **Streaming Responses**

For real-time applications:

```python theme={null}
async def stream_agent_response(query: str):
    agent = Agent(
        name="Streaming Assistant",
        instructions="Provide detailed, step-by-step responses.",
        model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
        tools=[get_weather],
    )
    
    async for chunk in Runner.stream(agent, query):
        print(chunk, end='', flush=True)
```

### **Context Management**

For multi-turn conversations:

```python theme={null}
class ConversationManager:
    def __init__(self):
        self.agent = Agent(
            name="Conversational Assistant",
            instructions="Maintain context across multiple interactions.",
            model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
            tools=[get_weather],
        )
        self.conversation_history = []
    
    async def chat(self, message: str):
        result = await Runner.run(self.agent, message)
        self.conversation_history.append({"user": message, "assistant": result.final_output})
        return result.final_output
```

## ⚠️ Important Notes

* **API Costs**: Monitor your usage as both Perplexity and OpenAI Agents may incur costs
* **Rate Limits**: Respect API rate limits and implement appropriate backoff strategies
* **Error Handling**: Always implement robust error handling for production applications
* **Security**: Keep your API keys secure and never commit them to version control

## 🎯 Use Cases

This integration pattern is perfect for:

* **🔍 Research Assistants** - Combining real-time search with structured responses
* **📊 Data Analysis Tools** - Using Sonar for context and agents for processing
* **🤖 Customer Support** - Grounded responses with function calling capabilities
* **📚 Educational Applications** - Real-time information with interactive features

## 📚 References

* [Perplexity Sonar API Documentation](https://docs.perplexity.ai/home)
* [OpenAI Agents SDK Documentation](https://github.com/openai/openai-agents-python)
* [AsyncOpenAI Client Reference](https://platform.openai.com/docs/api-reference)
* [Function Calling Best Practices](https://platform.openai.com/docs/guides/function-calling)

***

**Ready to build?** This integration opens up powerful possibilities for creating intelligent, grounded agents. Start with the basic example and gradually add more sophisticated tools and capabilities! 🚀


# Search Domain Filtering Patterns
Source: https://docs.perplexity.ai/docs/cookbook/articles/search-domain-filtering/README

Use search_domain_filter for focused search — allowlist patterns for trusted sources, denylist for excluding domains, and practical patterns for news, government, and competitive intelligence

This guide covers search domain filtering on the Agent API. You will learn how to use allowlists to restrict search to trusted domains, denylists to exclude unwanted sources, and practical patterns for common use cases like news-only search, government data, and competitor exclusion.

<Info>
  Domain filtering is configured per-tool under the `tools` array via `tools[].filters.search_domain_filter`. For the full reference, see [Agent API Filters](/docs/agent-api/tools/web-search#filters).
</Info>

## Prerequisites

Install the Perplexity SDK:

<CodeGroup>
  ```bash Python theme={null}
  pip install perplexityai
  ```

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

If you don't have an API key yet:

<Card title="Get your Perplexity API Key" icon="key" href="https://perplexity.ai/account/api">
  Navigate to the **API Keys** tab in the API Portal and generate a new key.
</Card>

Then export your API key as an environment variable:

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

## How Domain Filtering Works

The `search_domain_filter` parameter accepts a list of domain strings:

* **Allowlist** (no prefix): Include only results from these domains. `["reuters.com", "apnews.com"]` means search only Reuters and AP News.
* **Denylist** (`-` prefix): Exclude results from these domains. `["-reddit.com", "-twitter.com"]` means exclude Reddit and Twitter.

*You can also add a path to a domain to narrow results to one section of a site — `["nature.com/articles"]` searches only that section, while `["-reddit.com/r/all"]` excludes that section but still searches the rest of the site.*

<Warning>
  **Never mix allowlist and denylist entries in the same request.** The API does not support combining `"reuters.com"` and `"-reddit.com"` in the same array. Use either all allowlist or all denylist entries.
</Warning>

## Basic Domain Filtering

Domain filters are configured per-tool under the `tools` array.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Allowlist: search only specific domains
  response = client.responses.create(
      model="openai/gpt-5.4",
      input="What are the latest developments in AI regulation?",
      tools=[{
          "type": "web_search",
          "filters": {
              "search_domain_filter": ["reuters.com", "apnews.com", "bbc.com"],
          },
      }],
  )
  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.4",
      input: "What are the latest developments in AI regulation?",
      tools: [{
          type: "web_search" as const,
          filters: {
              search_domain_filter: ["reuters.com", "apnews.com", "bbc.com"],
          },
      }],
  });
  console.log(response.output_text);
  ```
</CodeGroup>

## Pattern: Denylist Filtering

Use the `-` prefix to exclude specific domains from search results.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Denylist: exclude social media and user-generated content
  response = client.responses.create(
      model="openai/gpt-5.4",
      input="What are the latest developments in AI regulation?",
      tools=[{
          "type": "web_search",
          "filters": {
              "search_domain_filter": ["-reddit.com", "-twitter.com", "-quora.com", "-medium.com"],
          },
      }],
  )
  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.4",
      input: "What are the latest developments in AI regulation?",
      tools: [{
          type: "web_search" as const,
          filters: {
              search_domain_filter: ["-reddit.com", "-twitter.com", "-quora.com", "-medium.com"],
          },
      }],
  });
  console.log(response.output_text);
  ```
</CodeGroup>

## Pattern: Path Filtering

Add a path after a domain to limit results to one section of a site — such as documentation, a subreddit, a blog, or a news vertical. This works in both allowlist and denylist mode.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Allowlist a single section of a site, and exclude a section of another
  response = client.responses.create(
      model="openai/gpt-5.4",
      input="Summarize recent peer-reviewed CRISPR results",
      tools=[{
          "type": "web_search",
          "filters": {
              "search_domain_filter": ["nature.com/articles", "science.org"],
          },
      }],
  )
  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.4",
      input: "Summarize recent peer-reviewed CRISPR results",
      tools: [{
          type: "web_search" as const,
          filters: {
              search_domain_filter: ["nature.com/articles", "science.org"],
          },
      }],
  });
  console.log(response.output_text);
  ```
</CodeGroup>

<Note>
  Paths match on segment boundaries, so `"example.com/docs"` matches `/docs` and `/docs/intro` but not `/documentation`. Subdomains are included (`blog.example.com/docs` matches). Query strings after the boundary are allowed (`/docs?x=1`).
</Note>

## Pattern: News-Only Search

Restrict results to major news outlets for current events and breaking news.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  NEWS_DOMAINS = [
      "reuters.com",
      "apnews.com",
      "bbc.com",
      "nytimes.com",
      "washingtonpost.com",
      "theguardian.com",
      "bloomberg.com",
      "ft.com",
  ]

  response = client.responses.create(
      model="openai/gpt-5.4",
      input="What happened in global markets today?",
      tools=[{
          "type": "web_search",
          "filters": {
              "search_domain_filter": NEWS_DOMAINS,
              "search_recency_filter": "day",
          },
      }],
  )
  print(response.output_text)
  ```

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

  const client = new Perplexity();

  const NEWS_DOMAINS = [
      "reuters.com",
      "apnews.com",
      "bbc.com",
      "nytimes.com",
      "washingtonpost.com",
      "theguardian.com",
      "bloomberg.com",
      "ft.com",
  ];

  const response = await client.responses.create({
      model: "openai/gpt-5.4",
      input: "What happened in global markets today?",
      tools: [{
          type: "web_search" as const,
          filters: {
              search_domain_filter: NEWS_DOMAINS,
              search_recency_filter: "day",
          },
      }],
  });
  console.log(response.output_text);
  ```
</CodeGroup>

<Tip>
  Combine `search_domain_filter` with `search_recency_filter` for time-sensitive queries. Options are `day`, `week`, `month`, and `year`.
</Tip>

## Pattern: Government and Official Sources

Restrict to government domains for policy, regulation, and official statistics.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  GOV_DOMAINS = [
      ".gov",          # US federal and state
      ".gov.uk",       # UK government
      ".europa.eu",    # EU institutions
      "who.int",       # World Health Organization
      "worldbank.org", # World Bank
  ]

  response = client.responses.create(
      model="openai/gpt-5.4",
      input="What are the current US federal guidelines on AI usage in healthcare?",
      tools=[{
          "type": "web_search",
          "filters": {
              "search_domain_filter": GOV_DOMAINS,
          },
      }],
  )
  print(response.output_text)
  ```

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

  const client = new Perplexity();

  const GOV_DOMAINS = [
      ".gov",
      ".gov.uk",
      ".europa.eu",
      "who.int",
      "worldbank.org",
  ];

  const response = await client.responses.create({
      model: "openai/gpt-5.4",
      input: "What are the current US federal guidelines on AI usage in healthcare?",
      tools: [{
          type: "web_search" as const,
          filters: {
              search_domain_filter: GOV_DOMAINS,
          },
      }],
  });
  console.log(response.output_text);
  ```
</CodeGroup>

## Pattern: Academic and Research Filtering

Target educational and research institutions.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  ACADEMIC_DOMAINS = [
      ".edu",
      "arxiv.org",
      "scholar.google.com",
      "pubmed.ncbi.nlm.nih.gov",
      "nature.com",
      "science.org",
      "ieee.org",
  ]

  response = client.responses.create(
      model="openai/gpt-5.4",
      input="What are recent advances in protein structure prediction?",
      tools=[{
          "type": "web_search",
          "filters": {
              "search_domain_filter": ACADEMIC_DOMAINS,
          },
      }],
  )
  print(response.output_text)
  ```

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

  const client = new Perplexity();

  const ACADEMIC_DOMAINS = [
      ".edu",
      "arxiv.org",
      "scholar.google.com",
      "pubmed.ncbi.nlm.nih.gov",
      "nature.com",
      "science.org",
      "ieee.org",
  ];

  const response = await client.responses.create({
      model: "openai/gpt-5.4",
      input: "What are recent advances in protein structure prediction?",
      tools: [{
          type: "web_search" as const,
          filters: {
              search_domain_filter: ACADEMIC_DOMAINS,
          },
      }],
  });
  console.log(response.output_text);
  ```
</CodeGroup>

## Pattern: Competitor Exclusion

Use denylists to exclude competitor websites from search results when building customer-facing content.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Exclude competitor domains from product research
  EXCLUDED_DOMAINS = [
      "-competitor-a.com",
      "-competitor-b.io",
      "-competitor-c.ai",
  ]

  response = client.responses.create(
      model="openai/gpt-5.4",
      input="What are the best practices for building real-time data pipelines?",
      tools=[{
          "type": "web_search",
          "filters": {
              "search_domain_filter": EXCLUDED_DOMAINS,
          },
      }],
  )
  print(response.output_text)
  ```

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

  const client = new Perplexity();

  const EXCLUDED_DOMAINS = [
      "-competitor-a.com",
      "-competitor-b.io",
      "-competitor-c.ai",
  ];

  const response = await client.responses.create({
      model: "openai/gpt-5.4",
      input: "What are the best practices for building real-time data pipelines?",
      tools: [{
          type: "web_search" as const,
          filters: {
              search_domain_filter: EXCLUDED_DOMAINS,
          },
      }],
  });
  console.log(response.output_text);
  ```
</CodeGroup>

## Configurable Filter Builder

A reusable helper that builds domain filter configurations from named presets.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Named filter presets
  FILTER_PRESETS = {
      "news": ["reuters.com", "apnews.com", "bbc.com", "bloomberg.com", "ft.com"],
      "academic": [".edu", "arxiv.org", "nature.com", "science.org", "pubmed.ncbi.nlm.nih.gov"],
      "government": [".gov", ".gov.uk", ".europa.eu", "who.int"],
      "tech": ["techcrunch.com", "arstechnica.com", "theverge.com", "wired.com"],
      "no_social": ["-reddit.com", "-twitter.com", "-facebook.com", "-tiktok.com", "-quora.com"],
      "no_seo_spam": ["-pinterest.com", "-medium.com", "-hubspot.com"],
  }


  def search_with_preset(query: str, preset: str, recency: str = None) -> str:
      """Run a search with a named domain filter preset."""
      if preset not in FILTER_PRESETS:
          raise ValueError(f"Unknown preset: {preset}. Options: {list(FILTER_PRESETS.keys())}")

      filters = {"search_domain_filter": FILTER_PRESETS[preset]}
      if recency:
          filters["search_recency_filter"] = recency

      response = client.responses.create(
          model="openai/gpt-5.4",
          input=query,
          tools=[{"type": "web_search", "filters": filters}],
      )
      return response.output_text


  # Usage
  print("--- News Search ---")
  print(search_with_preset("Latest AI regulation news", "news", recency="week"))

  print("\n--- Academic Search ---")
  print(search_with_preset("CRISPR gene editing recent papers", "academic"))

  print("\n--- Clean Search (no social media) ---")
  print(search_with_preset("Best Python testing frameworks", "no_social"))
  ```

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

  const client = new Perplexity();

  const FILTER_PRESETS: Record<string, string[]> = {
      news: ["reuters.com", "apnews.com", "bbc.com", "bloomberg.com", "ft.com"],
      academic: [".edu", "arxiv.org", "nature.com", "science.org", "pubmed.ncbi.nlm.nih.gov"],
      government: [".gov", ".gov.uk", ".europa.eu", "who.int"],
      tech: ["techcrunch.com", "arstechnica.com", "theverge.com", "wired.com"],
      no_social: ["-reddit.com", "-twitter.com", "-facebook.com", "-tiktok.com", "-quora.com"],
      no_seo_spam: ["-pinterest.com", "-medium.com", "-hubspot.com"],
  };

  async function searchWithPreset(query: string, preset: string, recency?: string): Promise<string> {
      if (!(preset in FILTER_PRESETS)) {
          throw new Error(`Unknown preset: ${preset}. Options: ${Object.keys(FILTER_PRESETS).join(", ")}`);
      }

      const filters: Record<string, any> = { search_domain_filter: FILTER_PRESETS[preset] };
      if (recency) filters.search_recency_filter = recency;

      const response = await client.responses.create({
          model: "openai/gpt-5.4",
          input: query,
          tools: [{ type: "web_search" as const, filters }],
      });
      return response.output_text;
  }

  console.log("--- News Search ---");
  console.log(await searchWithPreset("Latest AI regulation news", "news", "week"));

  console.log("\n--- Academic Search ---");
  console.log(await searchWithPreset("CRISPR gene editing recent papers", "academic"));

  console.log("\n--- Clean Search (no social media) ---");
  console.log(await searchWithPreset("Best Python testing frameworks", "no_social"));
  ```
</CodeGroup>

## Common Pitfalls

### Mixing Allowlist and Denylist

```python theme={null}
# ❌ WRONG: mixing allowlist and denylist
search_domain_filter=["reuters.com", "-reddit.com"]

# ✅ CORRECT: use only allowlist
search_domain_filter=["reuters.com", "apnews.com", "bbc.com"]

# ✅ CORRECT: use only denylist
search_domain_filter=["-reddit.com", "-twitter.com"]
```

### Using Wildcards Incorrectly

```python theme={null}
# ❌ WRONG: wildcards are not supported
search_domain_filter=["*.gov"]

# ✅ CORRECT: use the TLD directly
search_domain_filter=[".gov"]

# ✅ CORRECT: narrow to a section with a path prefix (no wildcards)
search_domain_filter=["example.com/blog"]
```

### Empty Filter Arrays

```python theme={null}
# ❌ WRONG: empty array has undefined behavior
search_domain_filter=[]

# ✅ CORRECT: omit the parameter to search all domains
# (simply don't include search_domain_filter)
```

## Tips and Best Practices

1. **Keep allowlists focused.** 5-10 domains is usually sufficient. Too many domains dilutes the filter's purpose.

2. **Use denylists for broad exclusion.** When you want to exclude a few noisy sources but otherwise search the full web, denylists are more practical than trying to allowlist everything else.

3. **Combine with recency filters.** For time-sensitive queries, add `search_recency_filter` alongside domain filters.

4. **Test your filters.** Run the same query with and without filters to verify that results change as expected.

5. **TLD filters work broadly.** Using `.gov` matches any domain ending in `.gov`, including `whitehouse.gov`, `irs.gov`, and state domains like `ca.gov`.

6. **Store presets in configuration.** Define filter presets in your app configuration rather than hardcoding them in every request.

## Next Steps

<CardGroup>
  <Card title="Agent API Filters" icon="filter" href="/docs/agent-api/tools/web-search#filters">
    Full reference for domain, date range, and location filters on the Agent API.
  </Card>

  <Card title="Search API Filters" icon="filter" href="/docs/search/filters/domain-filter">
    Domain filtering on the raw Search API for result-level control.
  </Card>

  <Card title="Academic Search" icon="graduation-cap" href="/docs/cookbook/articles/academic-search/README">
    Specialized academic search with domain filtering.
  </Card>
</CardGroup>


# Streaming Citation Parsing
Source: https://docs.perplexity.ai/docs/cookbook/articles/streaming-citations/README

Consume streaming responses from the Agent API and extract, validate, and display citations in real-time as chunks arrive

This guide shows how to consume streaming responses from the Agent API, extract citations as they arrive, validate source URLs, and build a fully cited output. Streaming is essential for responsive UIs and long-running searches — you can display text and sources progressively instead of waiting for the full response.

<Info>
  The `fast` preset is optimized for quick, citation-rich answers. The model inserts numbered references like `[1]`, `[2]` in the text, and the corresponding source URLs arrive in the `search_results` output item. See the [Agent API Presets](/docs/agent-api/presets) docs for all available presets.
</Info>

## Prerequisites

Install the SDKs:

<CodeGroup>
  ```bash Python theme={null}
  pip install perplexityai openai
  ```

  ```bash TypeScript theme={null}
  npm install @perplexity-ai/perplexity_ai openai
  ```
</CodeGroup>

If you don't have an API key yet:

<Card title="Get your Perplexity API Key" icon="key" href="https://perplexity.ai/account/api">
  Navigate to the **API Keys** tab in the API Portal and generate a new key.
</Card>

Then export your API key as an environment variable:

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

## How Streaming Citations Work

When you stream an Agent API response with a search-enabled preset, the API sends a sequence of server-sent events (SSE). The flow is:

1. **Search results** arrive via `response.reasoning.search_results` events — one event per search the model runs — containing URLs, titles, and snippets for each source.
2. **Content chunks** arrive incrementally as the model generates text via `response.output_text.delta` events.
3. **Citation references** appear in the text as numbered markers like `[1]`, `[2]`, mapping to the search result `id` field.

Your client accumulates the text, collects search results, then maps the numbered references to source URLs using the `id` field.

<Warning>
  **A response can contain more than one batch of search results.** Single-step presets like `fast` typically search once, but multi-step presets (such as deep research) run many searches — one `search_results` event (streaming) or output item (non-streaming) per search, all sharing a single citation `id` space. Always collect the results from **every** event or item. If you keep only the first batch, most `[N]` references in the text won't resolve and citations will look hallucinated.
</Warning>

## Basic Streaming with Citations

<CodeGroup>
  ```python Python theme={null}
  import os
  from openai import OpenAI

  # The OpenAI SDK supports Agent API streaming via the /v1/responses alias
  client = OpenAI(
      api_key=os.environ["PERPLEXITY_API_KEY"],
      base_url="https://api.perplexity.ai/v1",
  )

  stream = client.responses.create(
      input="What are the latest breakthroughs in quantum computing?",
      stream=True,
      extra_body={"preset": "fast"},
  )

  full_content = ""
  search_results = []

  for event in stream:
      event_type = event.type

      # Collect search results (one event per search — accumulate, don't overwrite)
      if event_type == "response.reasoning.search_results":
          search_results.extend(event.results or [])

      # Accumulate content from each delta
      if event_type == "response.output_text.delta":
          full_content += event.delta
          print(event.delta, end="", flush=True)

  print("\n\n--- Citations ---")
  for result in search_results:
      print(f"[{result['id']}] {result['title']} — {result['url']}")
  ```

  ```typescript TypeScript theme={null}
  import OpenAI from "openai";

  // The OpenAI SDK supports Agent API streaming via the /v1/responses alias
  const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai/v1",
  });

  const stream = await client.responses.create({
      input: "What are the latest breakthroughs in quantum computing?",
      stream: true,
      preset: "fast",
  } as any);

  let fullContent = "";
  let searchResults: Array<{ id: number; title: string; url: string }> = [];

  for await (const event of stream) {
      // Collect search results (one event per search — accumulate, don't overwrite)
      if (event.type === "response.reasoning.search_results") {
          searchResults.push(...((event as any).results ?? []));
      }

      // Accumulate content from each delta
      if (event.type === "response.output_text.delta") {
          fullContent += event.delta;
          process.stdout.write(event.delta);
      }
  }

  console.log("\n\n--- Citations ---");
  searchResults.forEach((result) => {
      console.log(`[${result.id}] ${result.title} — ${result.url}`);
  });
  ```

  ```bash curl theme={null}
  curl -N "https://api.perplexity.ai/v1/agent" \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "preset": "fast",
      "input": "What are the latest breakthroughs in quantum computing?",
      "stream": true
    }'
  ```
</CodeGroup>

## Parsing Citation References from Text

The model inserts numbered references like `[1]`, `[2]` into the generated text. To build a rich output with clickable links, parse these references and map them to source URLs using the search results.

<CodeGroup>
  ```python Python theme={null}
  import re
  from perplexity import Perplexity

  client = Perplexity()


  def extract_citation_refs(text: str) -> list[int]:
      """Extract all citation reference numbers from text, e.g. [1], [2]."""
      return sorted(set(int(m) for m in re.findall(r"\[(\d+)\]", text)))


  def build_cited_output(content: str, search_results: list) -> str:
      """Replace [N] references with markdown links and append a references section."""
      cited_content = content

      # Build a map from id to URL
      url_map = {r.id: r.url for r in search_results}
      title_map = {r.id: r.title for r in search_results}

      # Replace inline references with markdown links
      for ref_id, url in url_map.items():
          cited_content = cited_content.replace(
              f"[{ref_id}]",
              f"[[{ref_id}]]({url})"
          )

      # Append a references section with all cited sources
      used_refs = extract_citation_refs(content)
      if used_refs:
          cited_content += "\n\n---\n**References:**\n"
          for ref in used_refs:
              if ref in url_map:
                  cited_content += f"- [{ref}] {title_map[ref]} — {url_map[ref]}\n"

      return cited_content


  # Non-streaming request to get content + search results
  response = client.responses.create(
      preset="fast",
      input="What is CRISPR gene editing and how does it work?",
  )

  # Extract search results from the response output.
  # Multi-step presets return one search_results item per research step,
  # all sharing a single id space — collect the results from every item.
  content = response.output_text
  search_results = []
  for item in response.output:
      if item.type == "search_results":
          search_results.extend(item.results or [])

  # Build the final output with linked citations
  output = build_cited_output(content, search_results)
  print(output)
  ```

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

  const client = new Perplexity();

  function extractCitationRefs(text: string): number[] {
      const refs = new Set<number>();
      for (const match of text.matchAll(/\[(\d+)\]/g)) {
          refs.add(parseInt(match[1]));
      }
      return [...refs].sort((a, b) => a - b);
  }

  function buildCitedOutput(
      content: string,
      searchResults: Array<{ id: number; url: string; title: string }>
  ): string {
      let cited = content;

      // Build maps from id to URL and title
      const urlMap = new Map(searchResults.map((r) => [r.id, r.url]));
      const titleMap = new Map(searchResults.map((r) => [r.id, r.title]));

      // Replace inline references with markdown links
      for (const [id, url] of urlMap) {
          cited = cited.replaceAll(`[${id}]`, `[[${id}]](${url})`);
      }

      // Append a references section
      const usedRefs = extractCitationRefs(content);
      if (usedRefs.length > 0) {
          cited += "\n\n---\n**References:**\n";
          for (const ref of usedRefs) {
              if (urlMap.has(ref)) {
                  cited += `- [${ref}] ${titleMap.get(ref)} — ${urlMap.get(ref)}\n`;
              }
          }
      }

      return cited;
  }

  // Non-streaming request to get content + search results
  const response = await client.responses.create({
      preset: "fast",
      input: "What is CRISPR gene editing and how does it work?",
  });

  // Extract search results from the response output.
  // Multi-step presets return one search_results item per research step,
  // all sharing a single id space — collect the results from every item.
  const content = response.output_text;
  const searchResults: Array<{ id: number; url: string; title: string }> = [];
  for (const item of response.output) {
      if (item.type === "search_results") {
          searchResults.push(...((item as any).results ?? []));
      }
  }

  const output = buildCitedOutput(content, searchResults);
  console.log(output);
  ```
</CodeGroup>

## Validating Citation URLs

In production systems, you should validate that citation URLs are well-formed and reachable before presenting them to users. This avoids broken links and improves trust in the output.

<CodeGroup>
  ```python Python theme={null}
  import asyncio
  import aiohttp
  from urllib.parse import urlparse


  def is_valid_url(url: str) -> bool:
      """Check that a URL has a valid structure."""
      try:
          result = urlparse(url)
          return all([result.scheme in ("http", "https"), result.netloc])
      except Exception:
          return False


  async def check_url_reachable(url: str, timeout: float = 5.0) -> dict:
      """HEAD-request a URL to check if it's reachable."""
      if not is_valid_url(url):
          return {"url": url, "valid": False, "reason": "malformed URL"}

      try:
          async with aiohttp.ClientSession() as session:
              async with session.head(url, timeout=aiohttp.ClientTimeout(total=timeout), allow_redirects=True) as resp:
                  return {
                      "url": url,
                      "valid": resp.status < 400,
                      "status": resp.status,
                  }
      except asyncio.TimeoutError:
          return {"url": url, "valid": False, "reason": "timeout"}
      except Exception as e:
          return {"url": url, "valid": False, "reason": str(e)}


  async def validate_citations(search_results: list) -> list[dict]:
      """Validate all citation URLs from search results concurrently."""
      tasks = [check_url_reachable(r.url) for r in search_results]
      return await asyncio.gather(*tasks)


  # Usage after getting a response:
  # results = asyncio.run(validate_citations(search_results))
  # for r in results:
  #     status = "OK" if r["valid"] else f"FAILED ({r.get('reason', r.get('status'))})"
  #     print(f"  {r['url']}: {status}")
  ```

  ```typescript TypeScript theme={null}
  function isValidUrl(url: string): boolean {
      try {
          const parsed = new URL(url);
          return parsed.protocol === "http:" || parsed.protocol === "https:";
      } catch {
          return false;
      }
  }

  async function checkUrlReachable(url: string, timeoutMs = 5000): Promise<{ url: string; valid: boolean; reason?: string; status?: number }> {
      if (!isValidUrl(url)) {
          return { url, valid: false, reason: "malformed URL" };
      }

      try {
          const controller = new AbortController();
          const timer = setTimeout(() => controller.abort(), timeoutMs);
          const resp = await fetch(url, { method: "HEAD", signal: controller.signal, redirect: "follow" });
          clearTimeout(timer);
          return { url, valid: resp.status < 400, status: resp.status };
      } catch (e: any) {
          return { url, valid: false, reason: e.message };
      }
  }

  async function validateCitations(searchResults: Array<{ url: string }>): Promise<Array<{ url: string; valid: boolean; reason?: string }>> {
      return Promise.all(searchResults.map(r => checkUrlReachable(r.url)));
  }

  // Usage after getting a response:
  // const results = await validateCitations(searchResults);
  // results.forEach(r => {
  //     const status = r.valid ? "OK" : `FAILED (${r.reason ?? r.status})`;
  //     console.log(`  ${r.url}: ${status}`);
  // });
  ```
</CodeGroup>

<Warning>
  **Never ask the model to generate source URLs.** Always use the `search_results` output from the API response. Model-generated URLs can be hallucinated. The search results contain verified URLs from real web searches.
</Warning>

## Progressive Display with Live Citation Count

For chat UIs, it's useful to show a live citation counter as text streams in, then render the full reference list once the stream completes.

<CodeGroup>
  ```python Python theme={null}
  import os
  import re
  import sys
  from openai import OpenAI

  client = OpenAI(
      api_key=os.environ["PERPLEXITY_API_KEY"],
      base_url="https://api.perplexity.ai/v1",
  )


  def stream_with_progress(query: str):
      """Stream a response with a live citation counter."""
      stream = client.responses.create(
          input=query,
          stream=True,
          extra_body={"preset": "fast"},
      )

      full_content = ""
      search_results = []
      seen_refs = set()

      for event in stream:
          if event.type == "response.reasoning.search_results":
              search_results.extend(event.results or [])

          if event.type == "response.output_text.delta":
              full_content += event.delta
              sys.stdout.write(event.delta)
              sys.stdout.flush()

              # Track new citation references against accumulated text
              # (individual deltas may split [N] across chunks)
              current_refs = set(int(m) for m in re.findall(r"\[(\d+)\]", full_content))
              if current_refs - seen_refs:
                  seen_refs = current_refs
                  sys.stdout.write(f" [📚 {len(seen_refs)} sources]")
                  sys.stdout.flush()

      # Final summary
      print(f"\n\n{'='*60}")
      print(f"Response complete: {len(search_results)} sources found, {len(seen_refs)} cited")
      print(f"{'='*60}")

      # Build URL map from search results
      url_map = {r["id"]: r for r in search_results}
      for ref_id in sorted(seen_refs):
          if ref_id in url_map:
              r = url_map[ref_id]
              print(f"  ✓ [{ref_id}] {r['title']} — {r['url']}")

      return full_content, search_results


  content, results = stream_with_progress(
      "What are the environmental impacts of lithium mining?"
  )
  ```

  ```typescript TypeScript theme={null}
  import OpenAI from "openai";

  const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai/v1",
  });

  async function streamWithProgress(query: string) {
      const stream = await client.responses.create({
          input: query,
          stream: true,
          preset: "fast",
      } as any);

      let fullContent = "";
      let searchResults: Array<{ id: number; title: string; url: string }> = [];
      const seenRefs = new Set<number>();

      for await (const event of stream) {
          if (event.type === "response.reasoning.search_results") {
              searchResults.push(...((event as any).results ?? []));
          }

          if (event.type === "response.output_text.delta") {
              fullContent += event.delta;
              process.stdout.write(event.delta);

              // Track new citation references against accumulated text
              // (individual deltas may split [N] across chunks)
              const prevSize = seenRefs.size;
              for (const match of fullContent.matchAll(/\[(\d+)\]/g)) {
                  seenRefs.add(parseInt(match[1]));
              }
              if (seenRefs.size > prevSize) {
                  process.stdout.write(` [📚 ${seenRefs.size} sources]`);
              }
          }
      }

      console.log(`\n\n${"=".repeat(60)}`);
      console.log(`Response complete: ${searchResults.length} sources found, ${seenRefs.size} cited`);
      console.log("=".repeat(60));

      const urlMap = new Map(searchResults.map((r) => [r.id, r]));
      for (const refId of [...seenRefs].sort((a, b) => a - b)) {
          const r = urlMap.get(refId);
          if (r) {
              console.log(`  ✓ [${refId}] ${r.title} — ${r.url}`);
          }
      }

      return { fullContent, searchResults };
  }

  await streamWithProgress("What are the environmental impacts of lithium mining?");
  ```
</CodeGroup>

## Handling Search Results

The Agent API returns one or more `search_results` output items with rich metadata (id, title, snippet, URL, date) for each source — one item per search the model ran. This is richer than a flat URL list — use it to build source cards, sidebars, or detailed reference sections.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Non-streaming request to show the full response structure
  response = client.responses.create(
      preset="fast",
      input="What is the current state of fusion energy research?",
  )

  content = response.output_text

  # Extract search results from every search_results item in the output
  search_results = []
  for item in response.output:
      if item.type == "search_results":
          search_results.extend(item.results or [])

  print("--- Answer ---")
  print(content)

  print("\n--- Search Results (rich metadata) ---")
  for result in search_results:
      print(f"  [{result.id}] {result.title}")
      print(f"      URL:  {result.url}")
      print(f"      Date: {result.date}")
      print(f"      Snippet: {result.snippet[:100]}...")
      print()
  ```

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

  const client = new Perplexity();

  const response = await client.responses.create({
      preset: "fast",
      input: "What is the current state of fusion energy research?",
  });

  const content = response.output_text;

  // Extract search results from every search_results item in the output
  const searchResults: any[] = [];
  for (const item of response.output) {
      if (item.type === "search_results") {
          searchResults.push(...((item as any).results ?? []));
      }
  }

  console.log("--- Answer ---");
  console.log(content);

  console.log("\n--- Search Results (rich metadata) ---");
  for (const result of searchResults) {
      console.log(`  [${result.id}] ${result.title}`);
      console.log(`      URL:  ${result.url}`);
      console.log(`      Date: ${result.date}`);
      console.log(`      Snippet: ${result.snippet?.slice(0, 100)}...`);
      console.log();
  }
  ```
</CodeGroup>

<Tip>
  Each search result includes `id`, `title`, `url`, `snippet`, and `date`. The `id` maps directly to the `[N]` references in the text. Use this to build rich source cards for your UI.
</Tip>

## Complete Example: Streaming Research Assistant

A self-contained script that streams an Agent API response, extracts citations, validates URLs, and produces a formatted markdown output.

<CodeGroup>
  ```python Python theme={null}
  import os
  import re
  from urllib.parse import urlparse
  from openai import OpenAI

  client = OpenAI(
      api_key=os.environ["PERPLEXITY_API_KEY"],
      base_url="https://api.perplexity.ai/v1",
  )


  def is_valid_url(url: str) -> bool:
      try:
          result = urlparse(url)
          return all([result.scheme in ("http", "https"), result.netloc])
      except Exception:
          return False


  def stream_and_collect(query: str) -> tuple[str, list[dict]]:
      """Stream an Agent API response and return the full content and search results."""
      stream = client.responses.create(
          input=query,
          stream=True,
          extra_body={"preset": "fast"},
      )

      content = ""
      search_results = []

      for event in stream:
          if event.type == "response.reasoning.search_results":
              search_results.extend(event.results or [])

          if event.type == "response.output_text.delta":
              content += event.delta
              print(event.delta, end="", flush=True)

      print()  # newline after streaming
      return content, search_results


  def format_markdown_report(query: str, content: str, search_results: list[dict]) -> str:
      """Build a markdown report with inline citation links."""
      # Build URL map from search results
      url_map = {r["id"]: r["url"] for r in search_results}
      title_map = {r["id"]: r["title"] for r in search_results}

      # Replace [N] with markdown links
      formatted = content
      for ref_id, url in url_map.items():
          if is_valid_url(url):
              formatted = formatted.replace(f"[{ref_id}]", f"[\\[{ref_id}\\]]({url})")

      # Build the report
      report = f"# {query}\n\n{formatted}\n\n"

      # Append sources
      used_refs = sorted(set(int(m) for m in re.findall(r"\[(\d+)\]", content)))
      if search_results:
          report += "## Sources\n\n"
          for result in search_results:
              marker = "→" if result["id"] in used_refs else " "
              report += f"{marker} **[{result['id']}]** {result['title']} — {result['url']}\n\n"

      return report


  if __name__ == "__main__":
      query = "What are the most promising approaches to carbon capture technology?"

      print(f"Researching: {query}\n")
      print("-" * 60)

      content, search_results = stream_and_collect(query)

      print(f"\n{'=' * 60}")
      print(f"Collected {len(search_results)} sources\n")

      # Filter out any malformed URLs
      valid_results = [r for r in search_results if is_valid_url(r["url"])]
      invalid_count = len(search_results) - len(valid_results)
      if invalid_count:
          print(f"Warning: {invalid_count} sources had malformed URLs and were excluded.\n")

      report = format_markdown_report(query, content, valid_results)
      print(report)
  ```
</CodeGroup>

## Tips and Best Practices

1. **Use a search-enabled preset** like `fast` or `low` for citation-rich responses. Different presets use different citation formats — `fast` uses `[1]`, while `low` uses `[web:1]`.

2. **Accumulate search results from every event or item.** A response contains one `search_results` event (streaming) or output item (non-streaming) per search the model ran — multi-step presets run many. Append each batch to a single list; overwriting on each event or reading only the first item silently drops most sources.

3. **Use the `id` field to map citations.** Each search result has a numeric `id` that corresponds to the `[N]` reference in the text.

4. **Validate URLs before displaying them.** Use HEAD requests with timeouts to filter out any unreachable sources.

5. **Never generate your own URLs.** Use only the `search_results` from the API response. Model-generated URLs can be hallucinated.

6. **Handle missing references gracefully.** If a `[N]` reference in the text has no matching `id` in your collected search results, display the reference number without a link rather than crashing.

7. **Consider rate limiting for URL validation.** If the response includes many sources, validate them with concurrency limits to avoid overwhelming target servers.

## Next Steps

<CardGroup>
  <Card title="Agent API Presets" icon="bolt" href="/docs/agent-api/presets">
    Explore all presets and their citation formats.
  </Card>

  <Card title="Agent API Quickstart" icon="rocket" href="/docs/agent-api/quickstart">
    Get started with the Agent API for multi-provider access and tools.
  </Card>

  <Card title="Agent API Streaming" icon="stream" href="/docs/agent-api/output-control">
    Streaming patterns and event types for the Agent API.
  </Card>
</CardGroup>


# Structured Output Extraction
Source: https://docs.perplexity.ai/docs/cookbook/articles/structured-output-extraction/README

Get typed, schema-validated JSON responses from the Agent API using response_format with JSON schemas for data extraction, pipelines, and structured research

This guide shows how to extract structured, typed JSON from the Agent API using the `response_format` parameter with JSON schemas. You will learn practical patterns for product data extraction, research findings, comparison tables, and building reliable data pipelines — all with guaranteed schema conformance.

<Info>
  The Agent API enforces your JSON schema at generation time, so responses always conform to the specified structure. For the full parameter reference, see [Output Control](/docs/agent-api/output-control).
</Info>

## Prerequisites

Install the Perplexity SDK:

<CodeGroup>
  ```bash Python theme={null}
  pip install perplexityai
  ```

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

If you don't have an API key yet:

<Card title="Get your Perplexity API Key" icon="key" href="https://perplexity.ai/account/api">
  Navigate to the **API Keys** tab in the API Portal and generate a new key.
</Card>

Then export your API key as an environment variable:

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

## How Structured Outputs Work

When you pass `response_format` with `type: "json_schema"`, the Agent API constrains the model's output to match your schema exactly. The response in `output_text` is a valid JSON string you can parse directly.

The schema format follows [JSON Schema](https://json-schema.org/) with a few constraints specific to the Perplexity API:

* **No recursive schemas.** The schema cannot reference itself.
* **No unconstrained objects.** Avoid `additionalProperties: true` or bare `object` types without defined properties.
* **Named schemas required.** Each schema needs a `name` field for identification.

## Basic: Extracting a Single Entity

Extract structured data about a single topic with web search grounding.

<CodeGroup>
  ```python Python theme={null}
  import json
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.4",
      input="What is the current market cap, CEO, and founding year of NVIDIA?",
      tools=[{"type": "web_search"}],
      response_format={
          "type": "json_schema",
          "json_schema": {
              "name": "company_profile",
              "schema": {
                  "type": "object",
                  "properties": {
                      "company_name": {"type": "string"},
                      "ticker": {"type": "string"},
                      "ceo": {"type": "string"},
                      "founded_year": {"type": "integer"},
                      "market_cap_usd": {"type": "string"},
                      "sector": {"type": "string"},
                      "headquarters": {"type": "string"},
                  },
                  "required": ["company_name", "ticker", "ceo", "founded_year", "market_cap_usd", "sector", "headquarters"],
                  "additionalProperties": false,
              },
          },
      },
  )

  company = json.loads(response.output_text)
  print(f"{company['company_name']} ({company['ticker']})")
  print(f"  CEO: {company['ceo']}")
  print(f"  Founded: {company['founded_year']}")
  print(f"  Market Cap: {company['market_cap_usd']}")
  print(f"  Sector: {company['sector']}")
  ```

  ```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.4",
      input: "What is the current market cap, CEO, and founding year of NVIDIA?",
      tools: [{ type: "web_search" }],
      response_format: {
          type: "json_schema",
          json_schema: {
              name: "company_profile",
              schema: {
                  type: "object",
                  properties: {
                      company_name: { type: "string" },
                      ticker: { type: "string" },
                      ceo: { type: "string" },
                      founded_year: { type: "integer" },
                      market_cap_usd: { type: "string" },
                      sector: { type: "string" },
                      headquarters: { type: "string" },
                  },
                  required: ["company_name", "ticker", "ceo", "founded_year", "market_cap_usd", "sector", "headquarters"],
              },
          },
      },
  });

  const company = JSON.parse(response.output_text);
  console.log(`${company.company_name} (${company.ticker})`);
  console.log(`  CEO: ${company.ceo}`);
  console.log(`  Founded: ${company.founded_year}`);
  console.log(`  Market Cap: ${company.market_cap_usd}`);
  console.log(`  Sector: ${company.sector}`);
  ```
</CodeGroup>

## Extracting Lists: Product Comparisons

Extract a structured comparison of multiple items from a single query.

<CodeGroup>
  ```python Python theme={null}
  import json
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.4",
      input="Compare the top 3 electric vehicles under $40,000 available in the US in 2026",
      tools=[{"type": "web_search"}],
      response_format={
          "type": "json_schema",
          "json_schema": {
              "name": "ev_comparison",
              "schema": {
                  "type": "object",
                  "properties": {
                      "vehicles": {
                          "type": "array",
                          "items": {
                              "type": "object",
                              "properties": {
                                  "make": {"type": "string"},
                                  "model": {"type": "string"},
                                  "year": {"type": "integer"},
                                  "starting_price_usd": {"type": "integer"},
                                  "range_miles": {"type": "integer"},
                                  "battery_kwh": {"type": "number"},
                                  "pros": {"type": "array", "items": {"type": "string"}},
                                  "cons": {"type": "array", "items": {"type": "string"}},
                              },
                              "required": ["make", "model", "year", "starting_price_usd", "range_miles", "battery_kwh", "pros", "cons"],
                              "additionalProperties": false,
                          },
                      },
                      "comparison_date": {"type": "string"},
                  },
                  "required": ["vehicles", "comparison_date"],
                  "additionalProperties": false,
              },
          },
      },
  )

  data = json.loads(response.output_text)
  print(f"EV Comparison (as of {data['comparison_date']})\n")

  for v in data["vehicles"]:
      print(f"{v['year']} {v['make']} {v['model']}")
      print(f"  Price: ${v['starting_price_usd']:,}")
      print(f"  Range: {v['range_miles']} mi | Battery: {v['battery_kwh']} kWh")
      print(f"  Pros: {', '.join(v['pros'])}")
      print(f"  Cons: {', '.join(v['cons'])}")
      print()
  ```

  ```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.4",
      input: "Compare the top 3 electric vehicles under $40,000 available in the US in 2026",
      tools: [{ type: "web_search" }],
      response_format: {
          type: "json_schema",
          json_schema: {
              name: "ev_comparison",
              schema: {
                  type: "object",
                  properties: {
                      vehicles: {
                          type: "array",
                          items: {
                              type: "object",
                              properties: {
                                  make: { type: "string" },
                                  model: { type: "string" },
                                  year: { type: "integer" },
                                  starting_price_usd: { type: "integer" },
                                  range_miles: { type: "integer" },
                                  battery_kwh: { type: "number" },
                                  pros: { type: "array", items: { type: "string" } },
                                  cons: { type: "array", items: { type: "string" } },
                              },
                              required: ["make", "model", "year", "starting_price_usd", "range_miles", "battery_kwh", "pros", "cons"],
                          },
                      },
                      comparison_date: { type: "string" },
                  },
                  required: ["vehicles", "comparison_date"],
              },
          },
      },
  });

  const data = JSON.parse(response.output_text);
  console.log(`EV Comparison (as of ${data.comparison_date})\n`);

  for (const v of data.vehicles) {
      console.log(`${v.year} ${v.make} ${v.model}`);
      console.log(`  Price: $${v.starting_price_usd.toLocaleString()}`);
      console.log(`  Range: ${v.range_miles} mi | Battery: ${v.battery_kwh} kWh`);
      console.log(`  Pros: ${v.pros.join(", ")}`);
      console.log(`  Cons: ${v.cons.join(", ")}`);
      console.log();
  }
  ```
</CodeGroup>

## Research Findings Extraction

Parse search-grounded research into a structured format suitable for reports or databases.

<CodeGroup>
  ```python Python theme={null}
  import json
  from perplexity import Perplexity

  client = Perplexity()

  response = client.responses.create(
      model="openai/gpt-5.4",
      input="What are the most recent clinical trial results for GLP-1 receptor agonists in treating obesity?",
      tools=[{"type": "web_search"}],
      instructions="Provide findings from the most recent clinical trials. Include specific numbers and trial names where available.",
      response_format={
          "type": "json_schema",
          "json_schema": {
              "name": "research_findings",
              "schema": {
                  "type": "object",
                  "properties": {
                      "topic": {"type": "string"},
                      "findings": {
                          "type": "array",
                          "items": {
                              "type": "object",
                              "properties": {
                                  "trial_name": {"type": "string"},
                                  "drug": {"type": "string"},
                                  "phase": {"type": "string"},
                                  "key_result": {"type": "string"},
                                  "sample_size": {"type": "string"},
                                  "publication_year": {"type": "integer"},
                              },
                              "required": ["trial_name", "drug", "phase", "key_result", "sample_size", "publication_year"],
                              "additionalProperties": false,
                          },
                      },
                      "summary": {"type": "string"},
                  },
                  "required": ["topic", "findings", "summary"],
                  "additionalProperties": false,
              },
          },
      },
  )

  data = json.loads(response.output_text)
  print(f"Topic: {data['topic']}\n")
  print(f"Summary: {data['summary']}\n")

  for finding in data["findings"]:
      print(f"  {finding['trial_name']} ({finding['drug']}, Phase {finding['phase']})")
      print(f"    Result: {finding['key_result']}")
      print(f"    N={finding['sample_size']}, Published: {finding['publication_year']}")
      print()
  ```

  ```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.4",
      input: "What are the most recent clinical trial results for GLP-1 receptor agonists in treating obesity?",
      tools: [{ type: "web_search" }],
      instructions: "Provide findings from the most recent clinical trials. Include specific numbers and trial names where available.",
      response_format: {
          type: "json_schema",
          json_schema: {
              name: "research_findings",
              schema: {
                  type: "object",
                  properties: {
                      topic: { type: "string" },
                      findings: {
                          type: "array",
                          items: {
                              type: "object",
                              properties: {
                                  trial_name: { type: "string" },
                                  drug: { type: "string" },
                                  phase: { type: "string" },
                                  key_result: { type: "string" },
                                  sample_size: { type: "string" },
                                  publication_year: { type: "integer" },
                              },
                              required: ["trial_name", "drug", "phase", "key_result", "sample_size", "publication_year"],
                          },
                      },
                      summary: { type: "string" },
                  },
                  required: ["topic", "findings", "summary"],
              },
          },
      },
  });

  const data = JSON.parse(response.output_text);
  console.log(`Topic: ${data.topic}\n`);
  console.log(`Summary: ${data.summary}\n`);

  for (const finding of data.findings) {
      console.log(`  ${finding.trial_name} (${finding.drug}, Phase ${finding.phase})`);
      console.log(`    Result: ${finding.key_result}`);
      console.log(`    N=${finding.sample_size}, Published: ${finding.publication_year}`);
      console.log();
  }
  ```
</CodeGroup>

## Building a Data Pipeline

Chain structured output extraction into a pipeline that queries, extracts, and stores structured data.

<CodeGroup>
  ```python Python theme={null}
  import json
  import csv
  import io
  from perplexity import Perplexity

  client = Perplexity()

  SCHEMA = {
      "type": "json_schema",
      "json_schema": {
          "name": "startup_funding",
          "schema": {
              "type": "object",
              "properties": {
                  "companies": {
                      "type": "array",
                      "items": {
                          "type": "object",
                          "properties": {
                              "name": {"type": "string"},
                              "round": {"type": "string"},
                              "amount_usd": {"type": "string"},
                              "lead_investor": {"type": "string"},
                              "sector": {"type": "string"},
                              "date": {"type": "string"},
                          },
                          "required": ["name", "round", "amount_usd", "lead_investor", "sector", "date"],
                          "additionalProperties": false,
                      },
                  },
              },
              "required": ["companies"],
              "additionalProperties": false,
          },
      },
  }


  def extract_funding_rounds(sector: str) -> list[dict]:
      """Query the API and return structured funding data for a sector."""
      response = client.responses.create(
          model="openai/gpt-5.4",
          input=f"List the 5 largest startup funding rounds in {sector} from the past 3 months",
          tools=[{"type": "web_search"}],
          response_format=SCHEMA,
      )
      data = json.loads(response.output_text)
      return data["companies"]


  def pipeline(sectors: list[str]) -> str:
      """Run extraction across multiple sectors and produce a CSV."""
      all_rows = []
      for sector in sectors:
          print(f"Extracting: {sector}...")
          rows = extract_funding_rounds(sector)
          for row in rows:
              row["query_sector"] = sector
              all_rows.append(row)

      # Convert to CSV
      output = io.StringIO()
      writer = csv.DictWriter(output, fieldnames=["query_sector", "name", "round", "amount_usd", "lead_investor", "sector", "date"])
      writer.writeheader()
      writer.writerows(all_rows)
      return output.getvalue()


  if __name__ == "__main__":
      csv_output = pipeline(["AI infrastructure", "climate tech", "biotech"])
      print(csv_output)
  ```
</CodeGroup>

## Schema Design Constraints

<Warning>
  The Agent API enforces these constraints on JSON schemas:

  * **`additionalProperties` must be `false`.** Every `"type": "object"` in the schema must include `"additionalProperties": false`. This applies to the top-level schema and all nested objects.
  * **No recursive schemas.** A schema cannot reference itself with `$ref` pointing to its own definition.
  * **No unconstrained dicts.** Avoid `"type": "object"` without `properties`. Every object type must have explicitly defined properties.
  * **All properties should be `required`.** While optional properties are allowed, making all properties required ensures consistent output structure.
  * **No `$ref` to external schemas.** All definitions must be inline.
</Warning>

### Patterns That Work

```json theme={null}
// ✅ Flat object with typed fields
{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "count": { "type": "integer" },
    "tags": { "type": "array", "items": { "type": "string" } }
  },
  "required": ["name", "count", "tags"]
}

// ✅ Array of typed objects
{
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "key": { "type": "string" },
      "value": { "type": "number" }
    },
    "required": ["key", "value"]
  }
}

// ✅ Enum for constrained values
{
  "type": "string",
  "enum": ["low", "medium", "high"]
}
```

### Patterns to Avoid

```json theme={null}
// ❌ Recursive schema (self-referencing)
{
  "type": "object",
  "properties": {
    "children": { "$ref": "#" }
  }
}

// ❌ Unconstrained object
{
  "type": "object",
  "additionalProperties": true
}

// ❌ Bare dict/map type
{
  "type": "object"
}
```

## Combining Structured Output with Function Calling

You can use `response_format` alongside custom tools. The model calls your functions first, then formats the final response according to your schema.

<CodeGroup>
  ```python Python theme={null}
  import json
  from perplexity import Perplexity

  client = Perplexity()

  tools = [
      {"type": "web_search"},
      {
          "type": "function",
          "name": "get_internal_price",
          "description": "Look up the internal wholesale price for a product SKU.",
          "parameters": {
              "type": "object",
              "properties": {
                  "sku": {"type": "string", "description": "Product SKU"}
              },
              "required": ["sku"]
          },
      },
  ]


  def get_internal_price(sku: str) -> dict:
      prices = {"SKU-A100": 8500, "SKU-H100": 25000, "SKU-4090": 1600}
      return {"sku": sku, "wholesale_price_usd": prices.get(sku, 0)}


  response = client.responses.create(
      model="openai/gpt-5.4",
      tools=tools,
      input="Get the current retail price for the NVIDIA H100 GPU from the web, and also look up our internal wholesale price for SKU-H100. Compare them.",
      response_format={
          "type": "json_schema",
          "json_schema": {
              "name": "price_comparison",
              "schema": {
                  "type": "object",
                  "properties": {
                      "product": {"type": "string"},
                      "retail_price_usd": {"type": "string"},
                      "wholesale_price_usd": {"type": "integer"},
                      "margin_percent": {"type": "string"},
                      "source": {"type": "string"},
                  },
                  "required": ["product", "retail_price_usd", "wholesale_price_usd", "margin_percent", "source"],
                  "additionalProperties": false,
              },
          },
      },
  )

  # Handle function calls
  while any(item.type == "function_call" for item in response.output):
      next_input = [item.model_dump() for item in response.output]
      for item in response.output:
          if item.type == "function_call":
              args = json.loads(item.arguments)
              result = get_internal_price(**args)
              next_input.append({
                  "type": "function_call_output",
                  "call_id": item.call_id,
                  "output": json.dumps(result),
              })
      response = client.responses.create(
          model="openai/gpt-5.4",
          tools=tools,
          input=next_input,
          response_format={
              "type": "json_schema",
              "json_schema": {
                  "name": "price_comparison",
                  "schema": {
                      "type": "object",
                      "properties": {
                          "product": {"type": "string"},
                          "retail_price_usd": {"type": "string"},
                          "wholesale_price_usd": {"type": "integer"},
                          "margin_percent": {"type": "string"},
                          "source": {"type": "string"},
                      },
                      "required": ["product", "retail_price_usd", "wholesale_price_usd", "margin_percent", "source"],
                      "additionalProperties": false,
                  },
              },
          },
      )

  data = json.loads(response.output_text)
  print(f"Product: {data['product']}")
  print(f"Retail: {data['retail_price_usd']} (from {data['source']})")
  print(f"Wholesale: ${data['wholesale_price_usd']:,}")
  print(f"Margin: {data['margin_percent']}")
  ```
</CodeGroup>

<Tip>
  When combining structured outputs with function calling, pass the same `response_format` in every turn of the multi-turn loop. The schema is only enforced on the final text output, not on function call arguments.
</Tip>

## Next Steps

<CardGroup>
  <Card title="Output Control" icon="adjustments" href="/docs/agent-api/output-control">
    Full reference for response\_format, streaming, and output shaping.
  </Card>

  <Card title="Function Calling" icon="code-circle" href="/docs/cookbook/articles/function-calling-e2e/README">
    Combine structured outputs with multi-turn function calling.
  </Card>

  <Card title="Agent API Quickstart" icon="rocket" href="/docs/agent-api/quickstart">
    Get started with the Agent API in minutes.
  </Card>

  <Card title="Agent API Models" icon="brain" href="/docs/agent-api/models">
    Choose the right model for structured extraction tasks.
  </Card>
</CardGroup>


# Examples Overview
Source: https://docs.perplexity.ai/docs/cookbook/examples/README

Runnable projects covering the Agent API, Search API, and Embeddings API

# Examples Overview

Ready-to-run projects that demonstrate real-world use cases across every Perplexity API. Each example includes complete setup instructions and working code.

## Choosing the Right Example

| If you want to...                     | Use this example                                                                    | API                    | Language           |
| ------------------------------------- | ----------------------------------------------------------------------------------- | ---------------------- | ------------------ |
| Conduct deep web research             | [Agent Research Assistant](/docs/cookbook/examples/agent-research-assistant/README) | Agent API              | Python, TypeScript |
| Compare models across providers       | [Model Comparison](/docs/cookbook/examples/model-comparison/README)                 | Agent API              | Python             |
| Monitor news topics in real time      | [Search News Monitor](/docs/cookbook/examples/search-news-monitor/README)           | Search API             | Python, TypeScript |
| Build a document Q\&A system          | [Document Q\&A](/docs/cookbook/examples/document-qa/README)                         | Embeddings + Agent API | Python             |
| Build a TypeScript CLI agent          | [TypeScript Agent CLI](/docs/cookbook/examples/typescript-agent-cli/README)         | Agent API              | TypeScript         |
| Analyze images with web context       | [Image Analysis](/docs/cookbook/examples/image-analysis/README)                     | Agent API              | Python, TypeScript |
| Ask questions about uploaded files    | [File Attachment Q\&A](/docs/cookbook/examples/file-attachment-qa/README)           | Agent API              | Python             |
| Search SEC filings for financial data | [SEC Filing Search](/docs/cookbook/examples/sec-filing-search/README)               | Agent API              | Python             |
| Run code and build a PDF in a sandbox | [Competitor Buzz Tracker](/docs/cookbook/examples/competitor-buzz-tracker/README)   | Agent API              | Python             |
| Source candidates for a hiring brief  | [Talent Sourcer](/docs/cookbook/examples/talent-sourcer/README)                     | Agent API              | Python             |
| Pick an open model via an MCP server  | [Model Picker](/docs/cookbook/examples/model-picker/README)                         | Agent API              | Python             |

## By API

### Agent API

<CardGroup>
  <Card title="Agent Research Assistant" icon="magnifying-glass" href="/docs/cookbook/examples/agent-research-assistant/README">
    Deep web research using the `medium` preset with structured report output.
  </Card>

  <Card title="Model Comparison" icon="chart-bar" href="/docs/cookbook/examples/model-comparison/README">
    Compare responses from 5 providers side-by-side — quality, latency, and cost.
  </Card>

  <Card title="TypeScript Agent CLI" icon="terminal" href="/docs/cookbook/examples/typescript-agent-cli/README">
    Interactive TypeScript CLI with streaming, model selection, and web search.
  </Card>

  <Card title="Image Analysis" icon="image" href="/docs/cookbook/examples/image-analysis/README">
    Vision + web search for context-enriched image analysis.
  </Card>

  <Card title="File Attachment Q&A" icon="file-lines" href="/docs/cookbook/examples/file-attachment-qa/README">
    Upload documents and ask questions about them with optional web search enrichment.
  </Card>

  <Card title="Competitor Buzz Tracker" icon="chart-line" href="/docs/cookbook/examples/competitor-buzz-tracker/README">
    Two chained agent requests: the sandbox searches and counts each brand's share of voice, then renders a downloadable bar-chart PDF.
  </Card>

  <Card title="Talent Sourcer" icon="users" href="/docs/cookbook/examples/talent-sourcer/README">
    Wide search in a sandbox: source engineers by skill, location, and tenure, verify each, and rank them with their GitHub and profile links into an HTML shortlist.
  </Card>

  <Card title="Model Picker" icon="robot" href="/docs/cookbook/examples/model-picker/README">
    Connect the Hugging Face MCP server and web search in one request: find open models on the live Hub, verify their downloads and license, and check benchmarks before recommending one.
  </Card>
</CardGroup>

### Search API

<CardGroup>
  <Card title="Search News Monitor" icon="newspaper" href="/docs/cookbook/examples/search-news-monitor/README">
    Multi-topic news monitoring with domain filtering and recency control.
  </Card>

  <Card title="SEC Filing Search" icon="file-invoice" href="/docs/cookbook/examples/sec-filing-search/README">
    Search SEC.gov and EDGAR for financial filings with structured data extraction.
  </Card>
</CardGroup>

### Embeddings API

<CardGroup>
  <Card title="Document Q&A" icon="file-lines" href="/docs/cookbook/examples/document-qa/README">
    Self-contained RAG system with contextualized embeddings and Agent API answer generation.
  </Card>
</CardGroup>

## API Key Setup

All examples require a Perplexity API key. Set it as an environment variable:

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

<Tip>
  Get your API key at [perplexity.ai/account/api](https://perplexity.ai/account/api).
</Tip>

## Common Requirements

* **Python 3.9+** or **Node.js 18+** (depending on the example)
* **Perplexity API Key**
* **Internet connection** for API calls

Additional requirements vary by example and are listed in each project's documentation.

## Contributing

Found a bug or want to add an example? See our [Contributing Guidelines](https://github.com/ppl-ai/api-cookbook/blob/main/CONTRIBUTING.md).


# Agent Research Assistant
Source: https://docs.perplexity.ai/docs/cookbook/examples/agent-research-assistant/README

A CLI tool that uses Perplexity's Agent API with the medium preset to conduct multi-step web research and produce structured reports

# Agent Research Assistant

A command-line research tool that leverages Perplexity's Agent API with the `medium` preset to conduct thorough, multi-step web research on any topic. The tool produces structured reports with sections, cited sources, and confidence scores.

## Features

* Multi-step web research powered by the `medium` preset
* Structured JSON output with sections, sources, and confidence scores using `response_format` with `json_schema`
* Configurable model selection (defaults to `openai/gpt-5.2` via the medium preset)
* Clean CLI interface that accepts a topic and outputs a formatted report
* Source tracking with URLs and relevance annotations
* Exportable reports in JSON or plain text

## Installation

<CodeGroup>
  ```bash Python theme={null}
  pip install perplexityai pydantic
  ```

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

## API Key Setup

Set your Perplexity API key as an environment variable. The SDK reads it automatically:

```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```

## Usage

```bash theme={null}
# Python
python research_assistant.py "Impact of microplastics on marine ecosystems"

# TypeScript
npx ts-node research_assistant.ts "Impact of microplastics on marine ecosystems"

# Override the default model
python research_assistant.py "Quantum computing breakthroughs" --model openai/gpt-5.4

# Export as JSON
python research_assistant.py "CRISPR gene therapy trials" --json > report.json
```

## How It Works

1. The CLI accepts a research topic as input.
2. A structured JSON schema is defined for the report format using Pydantic (Python) or a TypeScript interface.
3. The tool calls the Agent API with `preset="medium"`, which configures the model (`openai/gpt-5.2`), enables `web_search` and `fetch_url` tools, and allows up to 10 reasoning steps.
4. The `response_format` parameter with `json_schema` enforces structured output matching the report schema.
5. The response is parsed and displayed as a formatted research report.

<Info>
  The `medium` preset is optimized for complex, in-depth analysis. It uses `openai/gpt-5.2` with up to 10K max tokens and 10 reasoning steps. You can override the model by passing `--model` to the CLI.
</Info>

## Full Code

<CodeGroup>
  ```python Python theme={null}
  import json
  import argparse
  from typing import List, Optional
  from pydantic import BaseModel
  from perplexity import Perplexity


  class ReportSource(BaseModel):
      title: str
      url: str
      relevance: str


  class ReportSection(BaseModel):
      heading: str
      content: str
      confidence: float
      sources: List[ReportSource]


  class ResearchReport(BaseModel):
      title: str
      summary: str
      sections: List[ReportSection]
      conclusion: str
      overall_confidence: float
      total_sources: int


  def run_research(topic: str, model: Optional[str] = None) -> ResearchReport:
      """Conduct deep research on a topic and return a structured report."""
      client = Perplexity()

      params = {
          "preset": "medium",
          "input": (
              f"Conduct thorough research on the following topic and produce a "
              f"detailed report with multiple sections, cited sources, and "
              f"confidence scores for each section.\n\nTopic: {topic}"
          ),
          "response_format": {
              "type": "json_schema",
              "json_schema": {
                  "name": "research_report",
                  "schema": ResearchReport.model_json_schema(),
              },
          },
      }

      if model:
          params["model"] = model

      response = client.responses.create(**params)
      return ResearchReport.model_validate_json(response.output_text)


  def format_report(report: ResearchReport) -> str:
      """Format a ResearchReport into human-readable text."""
      lines = [f"{'=' * 60}", f"RESEARCH REPORT: {report.title}", f"{'=' * 60}", ""]
      lines += [f"SUMMARY:", report.summary, ""]

      for i, section in enumerate(report.sections, 1):
          lines.append(f"--- Section {i}: {section.heading} ---")
          lines.append(f"Confidence: {section.confidence:.0%}\n")
          lines.append(section.content)
          if section.sources:
              lines.append("\nSources:")
              for src in section.sources:
                  lines.append(f"  - {src.title} ({src.relevance})")
                  lines.append(f"    {src.url}")
          lines.append("")

      lines += [f"{'=' * 60}", "CONCLUSION:", report.conclusion, ""]
      lines += [f"Overall Confidence: {report.overall_confidence:.0%}"]
      lines += [f"Total Sources: {report.total_sources}", f"{'=' * 60}"]
      return "\n".join(lines)


  def main():
      parser = argparse.ArgumentParser(description="Agent Research Assistant")
      parser.add_argument("topic", help="The research topic")
      parser.add_argument("--model", help="Override the default model", default=None)
      parser.add_argument("--json", action="store_true", help="Output raw JSON")
      args = parser.parse_args()

      print(f"Researching: {args.topic}")
      print("This may take a moment (deep research uses multi-step reasoning)...\n")

      report = run_research(args.topic, model=args.model)

      if args.json:
          print(json.dumps(report.model_dump(), indent=2))
      else:
          print(format_report(report))


  if __name__ == "__main__":
      main()
  ```

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

  interface ReportSource {
    title: string;
    url: string;
    relevance: string;
  }

  interface ReportSection {
    heading: string;
    content: string;
    confidence: number;
    sources: ReportSource[];
  }

  interface ResearchReport {
    title: string;
    summary: string;
    sections: ReportSection[];
    conclusion: string;
    overall_confidence: number;
    total_sources: number;
  }

  const reportSchema = {
    type: "object" as const,
    properties: {
      title: { type: "string" },
      summary: { type: "string" },
      sections: {
        type: "array",
        items: {
          type: "object",
          properties: {
            heading: { type: "string" },
            content: { type: "string" },
            confidence: { type: "number" },
            sources: {
              type: "array",
              items: {
                type: "object",
                properties: {
                  title: { type: "string" },
                  url: { type: "string" },
                  relevance: { type: "string" },
                },
                required: ["title", "url", "relevance"],
              },
            },
          },
          required: ["heading", "content", "confidence", "sources"],
        },
      },
      conclusion: { type: "string" },
      overall_confidence: { type: "number" },
      total_sources: { type: "number" },
    },
    required: ["title", "summary", "sections", "conclusion", "overall_confidence", "total_sources"],
  };

  async function runResearch(topic: string, model?: string): Promise<ResearchReport> {
    const client = new Perplexity();

    const params: Record<string, unknown> = {
      preset: "medium",
      input:
        `Conduct thorough research on the following topic and produce a ` +
        `detailed report with multiple sections, cited sources, and ` +
        `confidence scores for each section.\n\nTopic: ${topic}`,
      response_format: {
        type: "json_schema",
        json_schema: { name: "research_report", schema: reportSchema },
      },
    };

    if (model) params.model = model;

    const response = await client.responses.create(params as any);
    return JSON.parse(response.output_text) as ResearchReport;
  }

  async function main() {
    const topic = process.argv[2];
    if (!topic) {
      console.error("Usage: ts-node research_assistant.ts <topic> [--model <model>] [--json]");
      process.exit(1);
    }

    const modelIdx = process.argv.indexOf("--model");
    const model = modelIdx !== -1 ? process.argv[modelIdx + 1] : undefined;
    const outputJson = process.argv.includes("--json");

    console.log(`Researching: ${topic}`);
    console.log("This may take a moment (deep research uses multi-step reasoning)...\n");

    const report = await runResearch(topic, model);

    if (outputJson) {
      console.log(JSON.stringify(report, null, 2));
    } else {
      console.log(`RESEARCH REPORT: ${report.title}\n`);
      console.log(`SUMMARY: ${report.summary}\n`);
      report.sections.forEach((s, i) => {
        console.log(`--- Section ${i + 1}: ${s.heading} (${(s.confidence * 100).toFixed(0)}%) ---`);
        console.log(s.content);
        s.sources.forEach((src) => console.log(`  - ${src.title}: ${src.url}`));
        console.log();
      });
      console.log(`CONCLUSION: ${report.conclusion}`);
      console.log(`Overall Confidence: ${(report.overall_confidence * 100).toFixed(0)}%`);
    }
  }

  main();
  ```
</CodeGroup>

## Example Output

```bash theme={null}
python research_assistant.py "Impact of microplastics on marine ecosystems"
```

```
Researching: Impact of microplastics on marine ecosystems
This may take a moment (deep research uses multi-step reasoning)...

============================================================
RESEARCH REPORT: Impact of Microplastics on Marine Ecosystems
============================================================

SUMMARY:
Microplastics have become a pervasive pollutant in marine environments
worldwide, affecting organisms from plankton to large marine mammals.

--- Section 1: Sources and Distribution ---
Confidence: 92%

Microplastics originate from the degradation of larger plastic debris,
synthetic textiles, industrial processes, and cosmetic products...

Sources:
  - NOAA Marine Debris Program (high)
    https://marinedebris.noaa.gov/...

--- Section 2: Biological Effects on Marine Organisms ---
Confidence: 88%

Research demonstrates that microplastics affect marine life at multiple
trophic levels...

Sources:
  - Environmental Science & Technology (high)
    https://pubs.acs.org/...

============================================================
CONCLUSION:
Microplastics pose a significant and growing threat to marine ecosystems.

Overall Confidence: 89%
Total Sources: 12
============================================================
```

<Tip>
  For shorter, faster research tasks, consider using the `low` preset instead. It uses `openai/gpt-5.4` with up to 3 reasoning steps -- a good balance of speed and thoroughness.
</Tip>

<Warning>
  The first request with a new JSON Schema may take 10 to 30 seconds to prepare. Subsequent requests with the same schema will not see this delay. See the [structured outputs guide](/docs/agent-api/output-control#structured-outputs) for details.
</Warning>

## Limitations

* Deep research requests consume more tokens and cost more than standard requests due to multi-step reasoning and tool usage.
* Structured output with JSON schema requires the model to adhere to the schema. Very complex schemas may reduce output quality.
* Confidence scores are model-generated estimates and should be treated as relative indicators, not absolute measures.
* The quality of research depends on the availability and quality of web sources for the given topic.


# Competitor Buzz Tracker
Source: https://docs.perplexity.ai/docs/cookbook/examples/competitor-buzz-tracker/README

Turn a basket of searches and keyword rules into a one-page share-of-voice chart (PDF) with two chained Agent API requests. The first searches and counts inside the sandbox and returns a structured-output JSON contract. The second renders the bar chart and shares it as a downloadable file.

# Competitor Buzz Tracker

A command-line example that turns a product and its competitors into a one-page
competitive news report (PDF): how many of the articles in the news right now
mention each brand, and each brand's share of the total. You hand the tool a **basket** — a few
searches plus keyword rules — and the model does the rest.

It does this by writing the code itself. Driving the
[`sandbox`](https://docs.perplexity.ai/docs/agent-api/tools/sandbox) tool, the
model writes Python, runs it in the sandbox, and loops — searching the web,
deduplicating and classifying the results, fixing its own errors, and re-running
— all server-side. You never run any analysis or charting code locally: the
script just submits the requests, polls the background responses, and downloads
the finished PDF. Every number on the chart is computed, not guessed.

<Frame>
  <img alt="Competitor Buzz Tracker PDF: horizontal bar chart of news mentions for Galaxy, iPhone, Pixel, and Other, each labeled with its total and share of voice." />

  <img alt="Competitor Buzz Tracker PDF: horizontal bar chart of news mentions for Galaxy, iPhone, Pixel, and Other, each labeled with its total and share of voice." />
</Frame>

## What the sandbox does here

* **Runs the analysis as code, not from memory.** Like a code interpreter, the
  sandbox lets the model solve a quantitative task by writing and running Python
  instead of guessing. The mention counts and share-of-voice percentages come
  from code it actually executed over the search results — so the numbers are
  real, not plausible-sounding. The script enforces this: it checks the response
  contains a `sandbox_results` item and refuses the result otherwise, so the
  model can't skip the tool and return invented counts.
* **Searches the web in the same run.** The sandbox can reach Perplexity search
  from inside the run, so the model pulls the articles itself and classifies them
  in the same request — no separate scraping step, no glue code, no extra tool to
  wire up.
* **Returns a real file with zero setup on your side.** matplotlib and the
  runtime live in the sandbox; the model renders the chart, shares it with
  `share_file`, and you download the `.pdf` from the response by id. One request
  in, one file out — nothing to install or host locally. A plain chat completion
  would only return text.

## Without the sandbox

To build the same report yourself, you'd stand up a runtime: a machine with
Python and matplotlib, the search and classification code, and somewhere to
execute it and capture the file. With the `sandbox` tool the model writes and
runs that code server-side and hands back the finished PDF — nothing to install,
host, or keep running — and it adapts the code to whatever the search returns
instead of you maintaining a rigid pipeline.

## Installation

Keep the project files in the same directory:
`competitor_buzz_tracker.py`, `observability.py` (imported by the script),
`requirements.txt`, and your `basket.yaml`.

1. Install the dependencies — the [Perplexity Python SDK](https://github.com/ppl-ai/perplexity-python),
   PyYAML (to read the basket config), and Pydantic (for the response schema).
   They're pinned in `requirements.txt`:

```text requirements.txt theme={null}
perplexityai==0.38.0
PyYAML==6.0.2
pydantic==2.13.4
```

```bash theme={null}
pip install -r requirements.txt
```

2. Set your Perplexity API key:

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

The SDK reads the key from this environment variable.

<Note>
  This example uses the Agent API `sandbox` tool. See the
  [Sandbox docs](https://docs.perplexity.ai/docs/agent-api/tools/sandbox) for
  setup and usage details.
</Note>

## Usage

You describe the job in a small YAML basket: a chart title, the search
queries to run, and the keyword rules that classify each result. One article can
match several keywords — a story that mentions both Pixel and Galaxy counts for
both; one that matches none counts under "Other". More queries mean broader
coverage.

```yaml basket.yaml theme={null}
title: "iPhone vs Pixel vs Galaxy — market buzz"

queries:
  - "smartphone news today"
  - "latest phone news"
  - "new phone launch"
  - "smartphone announcements"
  - "flagship smartphone news"
  - "Android phone news"
  - "new phone releases"
  - "phone review roundup"
  - "best new phones"
  - "upcoming smartphones"
  - "foldable phone news"
  - "budget phone news"
  - "phone camera comparison"
  - "smartphone deals this week"
  - "mobile phone industry news"

keywords:
  - name: iPhone
    regex: "iphone|apple phone"
  - name: Pixel
    regex: "pixel"
  - name: Galaxy
    regex: "galaxy|samsung"
```

Each keyword's `regex` is a single case-insensitive pattern — use `|` for
alternatives (e.g. `"galaxy|samsung"`). Save it as `basket.yaml`, then run:

```bash theme={null}
python competitor_buzz_tracker.py --config basket.yaml [--output FILE] [--show-code]
```

This writes `competitor-buzz-<date>_<time>.pdf` to the current directory. Add
`--show-code` to also print the Python the agent wrote and ran in the sandbox.

## How it works

You describe the job in plain language and hand the model the `sandbox` tool;
from there it writes the Python, runs it, fixes its own errors, and hands back
the counts and the chart — you never touch the analysis code yourself.

This example splits that work across two chained requests rather than one.
Analysis and rendering are different jobs, and splitting them keeps each prompt
short, lets you run the mechanical step on a cheaper model (`openai/gpt-5.4`) and
the rendering on the flagship (`openai/gpt-5.5`), and puts an inspectable
checkpoint in the middle.

**Request 1 (analytics)** gets the `sandbox` tool and a
[`response_format`](https://docs.perplexity.ai/docs/agent-api/output-control)
schema. The model searches each query from inside the sandbox, pools the
results, deduplicates by URL, regex-matches each article against the keyword
rules, and counts mentions per brand plus its share of voice. The schema turns
its answer into a typed contract instead of prose:

```python theme={null}
class Series(BaseModel):
    model_config = ConfigDict(extra="forbid")
    keyword: str
    total: int
    share_of_voice: float


class NewsMentions(BaseModel):
    model_config = ConfigDict(extra="forbid")
    title: str
    articles: int
    series: List[Series]
```

**Request 2 (chart)** gets only that JSON and the `sandbox` tool, then renders
the horizontal bar chart to `report.pdf` and shares it with `share_file`.

There's no shared memory between the two: the script validates request 1's JSON
against the schema and passes it into request 2, so the intermediate is plain
data you can print or unit-test before anything is drawn. Both requests run with
`background=True` and are polled until they finish, because a sandbox run can
take a while.

## Prompting guidance

You don't write the analysis code — each request describes its job as a plain
prompt, about as long as a chat message, and the model turns that into Python it
runs in the sandbox. The analytics request just sends the basket's queries and
keyword rules as its prompt:

```text theme={null}
Count how often each brand shows up in current phone news.

Search the web for each of these queries, pool the results, and drop duplicate
URLs:
  - smartphone news today
  - latest phone news
  - ...  (the rest of the basket)

Tag each article with these regexes (case-insensitive; an article can match
several; none -> "Other"):
  - iPhone: iphone|apple phone
  - Pixel: pixel
  - Galaxy: galaxy|samsung

Return JSON: title, articles (number of unique articles), and series — for each
brand and "Other", its total and its share_of_voice.
```

The keyword rules live in the YAML, not in code, so you change what's tracked by
editing the basket — not by touching any Python.

<Accordion title="See the Python the agent wrote (--show-code)">
  With `--show-code`, the script prints every sandbox cell the model ran. On the
  run above the analytics agent took five cells — including one that just
  inspected a search result to learn its fields — before settling on the code
  below. Lightly condensed, it's what it actually executed: search each query,
  canonicalize and deduplicate URLs, regex-classify each result, count mentions,
  and print the JSON the schema expects.

  ```python theme={null}
  import json, re
  from urllib.parse import urlsplit, urlunsplit, parse_qsl, urlencode
  from collections import Counter
  import pplx_sdk  # search interface available inside the sandbox

  queries = ["smartphone news today", "latest phone news", ...]

  def canon(url):                      # normalize so near-duplicate URLs collapse
      s = urlsplit(url)
      host = s.netloc.lower().removeprefix("www.")
      path = re.sub(r"/+", "/", s.path or "/").rstrip("/") or "/"
      keep = [(k, v) for k, v in parse_qsl(s.query)
              if not k.lower().startswith(("utm_", "fbclid", "gclid"))]
      return urlunsplit((s.scheme or "https", host, path, urlencode(keep), ""))

  unique = {}
  for q in queries:
      for h in pplx_sdk.search.web(q, limit=10):
          url = getattr(h, "url", None)
          if url:
              unique.setdefault(canon(url), {
                  "title": getattr(h, "title", "") or "",
                  "summary": getattr(h, "summary", "") or "",
                  "url": url,
                  "domain": getattr(h, "domain", "") or "",
              })

  patterns = {
      "iPhone": re.compile(r"iphone|apple phone", re.I),
      "Pixel": re.compile(r"pixel", re.I),
      "Galaxy": re.compile(r"galaxy|samsung", re.I),
  }
  counts = Counter()
  for h in unique.values():
      text = " ".join(h[k] for k in ("title", "summary", "url", "domain"))
      matched = [b for b, p in patterns.items() if p.search(text)]
      for b in (matched or ["Other"]):
          counts[b] += 1

  total = sum(counts.values())
  print(json.dumps({                       # the JSON contract the schema expects
      "title": "iPhone vs Pixel vs Galaxy — market buzz",
      "articles": len(unique),
      "series": [
          {"keyword": k, "total": counts[k],
           "share_of_voice": round(100 * counts[k] / total, 1)}
          for k in ["iPhone", "Pixel", "Galaxy", "Other"]
      ],
  }))
  ```

  It's regular Python you can read and sanity-check — no framework, no hidden
  state. The model writes fresh code each run, so the exact shape varies between
  runs. `pplx_sdk` is the search interface available inside the sandbox.
</Accordion>

## Full code

The script is one file; cost reporting and the `--show-code` helper live in a
small `observability.py` beside it (off the critical path, so it's easy to drop
or move into shared tooling later).

<Accordion title="Full code — competitor_buzz_tracker.py and observability.py">
  <CodeGroup>
    ```python competitor_buzz_tracker.py theme={null}
    #!/usr/bin/env python3
    """
    Competitor Buzz Tracker - a basket of searches and keyword rules becomes a
    one-page market-buzz chart (PDF) via two Perplexity Agent API requests:
    analytics (sandbox searches the web and counts -> JSON) then chart (sandbox ->
    report.pdf, shared with share_file). See the README for details.
    """

    import argparse
    import os
    import sys
    import time
    from datetime import datetime
    from typing import Any, List, Optional, Tuple

    import yaml
    from pydantic import BaseModel, ConfigDict

    from perplexity import Perplexity

    from observability import print_costs, print_sandbox_code

    POLL_INTERVAL_SECONDS = 4
    POLL_TIMEOUT_SECONDS = 900
    MAX_STEPS = 10

    # A cheaper model handles the mechanical search-and-count; the flagship
    # writes the chart code.
    ANALYTICS_MODEL = "openai/gpt-5.4"
    CHART_MODEL = "openai/gpt-5.5"

    ANALYTICS_SYSTEM = """Work in a Python sandbox: search the web, then \
    classify and count the results with code. Don't estimate the numbers - \
    print the final JSON from the sandbox."""


    ANALYTICS_TEMPLATE = """Count how often each brand shows up in current \
    phone news.

    Search the web for each of these queries, pool the results, and drop \
    duplicate URLs:
    {query_lines}

    Tag each article with these regexes (case-insensitive; an article can \
    match several; none -> "Other"):
    {keyword_lines}

    Return JSON: title "{title}", articles (number of unique articles), and \
    series - for each brand and "Other", its total and its share_of_voice \
    (its total over the sum of all totals, as a percent rounded to one \
    decimal)."""

    CHART_SYSTEM = """Work in a Python sandbox with matplotlib (Agg \
    backend). Build the chart, save it as report.pdf, and share it with \
    share_file."""

    CHART_TEMPLATE = """Make a horizontal bar chart from this data.

    DATA:
    {data_json}

    One bar per entry in "series", length = its total, sorted longest \
    first, labeled with its total and share_of_voice. Title = the "title" \
    field; add a subtitle with the "articles" count and \
    "snapshot {snapshot_date}". Keep it clean."""


    class Series(BaseModel):
        model_config = ConfigDict(extra="forbid")
        keyword: str
        total: int
        share_of_voice: float


    class NewsMentions(BaseModel):
        model_config = ConfigDict(extra="forbid")
        title: str
        articles: int
        series: List[Series]


    def load_basket(path: str) -> dict:
        with open(path, "r", encoding="utf-8") as fh:
            return yaml.safe_load(fh)


    def analytics_prompt(basket: dict) -> str:
        keyword_lines = "\n".join(
            f"  - {kw['name']}: {kw['regex']}" for kw in basket["keywords"]
        )
        return ANALYTICS_TEMPLATE.format(
            title=basket["title"],
            query_lines="\n".join(f"  - {q}" for q in basket["queries"]),
            keyword_lines=keyword_lines,
        )


    def chart_prompt(data: NewsMentions, snapshot_date: str) -> str:
        return CHART_TEMPLATE.format(
            data_json=data.model_dump_json(indent=2),
            snapshot_date=snapshot_date,
        )


    def final_text(response: Any) -> str:
        chunks: List[str] = []
        for item in getattr(response, "output", None) or []:
            if getattr(item, "type", None) != "message":
                continue
            for block in getattr(item, "content", None) or []:
                if getattr(block, "type", None) == "output_text":
                    text = getattr(block, "text", None)
                    if text:
                        chunks.append(text)
        return "\n\n".join(chunks)


    def ran_sandbox(response: Any) -> bool:
        return any(
            getattr(item, "type", None) == "sandbox_results"
            for item in getattr(response, "output", None) or []
        )


    def submit_and_wait(client: Perplexity, **create_kwargs: Any) -> Any:
        response = client.responses.create(background=True, **create_kwargs)
        print(f"Submitted response {response.id}; working...", file=sys.stderr)
        deadline = time.time() + POLL_TIMEOUT_SECONDS
        while response.status in ("queued", "in_progress"):
            if time.time() > deadline:
                raise TimeoutError("Timed out waiting for the response to finish.")
            time.sleep(POLL_INTERVAL_SECONDS)
            response = client.responses.retrieve(response.id)
        if response.status != "completed":
            raise RuntimeError(f"Request ended with status {response.status!r}.")
        return response


    def run_analytics(
        client: Perplexity, basket: dict, model: str
    ) -> Tuple[NewsMentions, Any]:
        response = submit_and_wait(
            client,
            model=model,
            instructions=ANALYTICS_SYSTEM,
            input=analytics_prompt(basket),
            tools=[{"type": "sandbox"}],
            response_format={
                "type": "json_schema",
                "json_schema": {
                    "name": "news_mentions",
                    "schema": NewsMentions.model_json_schema(),
                },
            },
            max_steps=MAX_STEPS,
        )
        if not ran_sandbox(response):
            raise RuntimeError("Analytics request did not run the sandbox.")
        return NewsMentions.model_validate_json(final_text(response)), response


    def run_chart(
        client: Perplexity, data: NewsMentions, snapshot_date: str, model: str
    ) -> Any:
        return submit_and_wait(
            client,
            model=model,
            instructions=CHART_SYSTEM,
            input=chart_prompt(data, snapshot_date),
            tools=[{"type": "sandbox"}],
            max_steps=MAX_STEPS,
        )


    def download_pdf(
        client: Perplexity, response: Any, output: Optional[str]
    ) -> Optional[str]:
        files = client.responses.files.list(response.id)
        pdf = next(
            (f for f in files.data if f.filename.lower().endswith(".pdf")), None
        )
        if pdf is None:
            names = ", ".join(f.filename for f in files.data) or "(none)"
            print(
                f"No PDF was shared by the sandbox. Files: {names}",
                file=sys.stderr,
            )
            return None

        stamp = datetime.now().strftime("%Y-%m-%d_%H-%M")
        out_path = output or f"competitor-buzz-{stamp}.pdf"
        content = client.responses.files.content(pdf.id, response_id=response.id)
        content.write_to_file(out_path)
        return out_path


    def main() -> int:
        parser = argparse.ArgumentParser(
            description=(
                "Generate a one-page market-buzz chart (PDF) from a basket "
                "config, using two Perplexity Agent API requests (analytics, "
                "then chart)."
            )
        )
        parser.add_argument(
            "--config",
            default="basket.yaml",
            help="Path to the basket YAML config (default: basket.yaml).",
        )
        parser.add_argument(
            "--output",
            help=(
                "Output PDF path. Defaults to competitor-buzz-<time>.pdf in the "
                "working directory."
            ),
        )
        parser.add_argument(
            "--show-code",
            action="store_true",
            help="Print the Python the agent wrote and ran in the sandbox.",
        )
        args = parser.parse_args()

        if not os.environ.get("PERPLEXITY_API_KEY"):
            print("Set PERPLEXITY_API_KEY in your environment.", file=sys.stderr)
            return 1

        basket = load_basket(args.config)
        client = Perplexity()

        names = ", ".join(kw["name"] for kw in basket["keywords"])
        snapshot_date = datetime.now().date().isoformat()
        try:
            print(
                f"[1/2] Measuring news buzz for {names}...", file=sys.stderr
            )
            data, analytics_response = run_analytics(
                client, basket, ANALYTICS_MODEL
            )
            parts = [
                f"{s.keyword} {s.total} ({s.share_of_voice}%)"
                for s in data.series
            ]
            print(
                f"      {data.articles} articles - {', '.join(parts)}",
                file=sys.stderr,
            )

            print("[2/2] Rendering the report PDF...", file=sys.stderr)
            chart_response = run_chart(
                client, data, snapshot_date, CHART_MODEL
            )
        except Exception as err:  # noqa: BLE001
            print(f"Error: {err}", file=sys.stderr)
            return 2

        out_path = download_pdf(client, chart_response, args.output)
        if args.show_code:
            print_sandbox_code(analytics_response, "analytics")
            print_sandbox_code(chart_response, "chart")
        print_costs(
            [("Analytics", analytics_response), ("Chart", chart_response)]
        )
        if out_path:
            print(f"\nSaved report to {out_path}", file=sys.stderr)
            return 0
        return 3


    if __name__ == "__main__":
        sys.exit(main())
    ```

    ```python observability.py theme={null}
    """Optional observability helpers for the Competitor Buzz Tracker.

    Kept in a separate module so the main script stays focused on the Agent API
    calls. Nothing here is on the critical path (cost reporting and showing the
    code the model ran), so it could later move into shared tooling or the SDK.
    """

    import sys
    from typing import Any, List, Tuple


    def print_costs(stages: List[Tuple[str, Any]]) -> None:
        """Print per-request cost and the combined total to stderr."""
        amounts: List[float] = []
        currency = "USD"
        for label, response in stages:
            cost = getattr(getattr(response, "usage", None), "cost", None)
            total = getattr(cost, "total_cost", None)
            if total is not None:
                currency = getattr(cost, "currency", "USD")
                amounts.append(total)
                print(f"{label} cost: {total:.4f} {currency}", file=sys.stderr)
        if amounts:
            print(f"Total cost: {sum(amounts):.4f} {currency}", file=sys.stderr)


    def sandbox_code(response: Any) -> List[str]:
        """Return the code cells the model wrote and ran in the sandbox."""
        cells: List[str] = []
        for item in getattr(response, "output", None) or []:
            if getattr(item, "type", None) != "sandbox_results":
                continue
            data = item.model_dump() if hasattr(item, "model_dump") else {}
            code = data.get("code")
            if code:
                cells.append(code)
        return cells


    def print_sandbox_code(response: Any, label: str = "") -> None:
        """Print the code the model ran in the sandbox (for inspection)."""
        cells = sandbox_code(response)
        if not cells:
            return
        where = f" [{label}]" if label else ""
        print(f"--- sandbox code{where} ---", file=sys.stderr)
        for i, code in enumerate(cells, 1):
            print(f"\n# cell {i}/{len(cells)}", file=sys.stderr)
            print(code, file=sys.stderr)
    ```
  </CodeGroup>
</Accordion>

## Example Output

A real run — `python competitor_buzz_tracker.py --config basket.yaml`
(results vary with live coverage):

```
[1/2] Measuring news buzz for iPhone, Pixel, Galaxy...
Submitted response resp_b89831b8-cb87-41ef-8756-1b9447fb19d7; working...
      120 articles - iPhone 68 (29.6%), Pixel 52 (22.6%), Galaxy 91 (39.6%), Other 19 (8.3%)
[2/2] Rendering the report PDF...
Submitted response resp_93c0ab7d-325a-4101-9655-cc4ad40863c3; working...
Analytics cost: 0.2515 USD
Chart cost: 0.0567 USD
Total cost: 0.3083 USD

Saved report to competitor-buzz-2026-06-18_21-12.pdf
```

The PDF is a horizontal bar chart of mentions per brand, sorted, each bar labeled
with its total and share of voice, under a subtitle showing the article count and
`snapshot <date>`. Every count comes from search results the model actually
classified with the keyword rules — not from its training data. (Shares are
rounded to one decimal, so they may not sum to exactly 100%.)

## Limitations

* **Coverage varies.** Output depends on live news, so counts differ by topic and
  over time.
* **Billing.** This makes two Agent API requests, so each run is billed for two
  sets of model tokens and two sandbox sessions, plus the in-sandbox searches in
  request 1, at their standard rates.

## Resources

* [Sandbox Tool](https://docs.perplexity.ai/docs/agent-api/tools/sandbox)
* [Structured Outputs](https://docs.perplexity.ai/docs/agent-api/output-control)
* [Agent API Quickstart](https://docs.perplexity.ai/docs/agent-api/quickstart)
* [Search API](https://docs.perplexity.ai/docs/search/quickstart)
* [Pricing](https://docs.perplexity.ai/docs/getting-started/pricing)
* [Perplexity Python SDK](https://github.com/ppl-ai/perplexity-python)


# Daily Knowledge Bot
Source: https://docs.perplexity.ai/docs/cookbook/examples/daily-knowledge-bot/README

A Python application that delivers interesting facts about rotating topics using the Perplexity AI API

<SonarDeprecationNotice />

# Daily Knowledge Bot

A Python application that delivers interesting facts about rotating topics using the Perplexity AI API. Perfect for daily learning, newsletter content, or personal education.

## 🌟 Features

* **Daily Topic Rotation**: Automatically selects topics based on the day of the month
* **AI-Powered Facts**: Uses Perplexity's Sonar API to generate interesting and accurate facts
* **Customizable Topics**: Easily extend or modify the list of topics
* **Persistent Storage**: Saves facts to dated text files for future reference
* **Robust Error Handling**: Gracefully manages API failures and unexpected errors
* **Configurable**: Uses environment variables for secure API key management

## 📋 Requirements

* Python 3.6+
* Required packages:
  * requests
  * python-dotenv
  * (optional) logging

## 🚀 Installation

1. Clone this repository or download the script
2. Install the required packages:

```bash theme={null}
# Install from requirements file (recommended)
pip install -r requirements.txt

# Or install manually
pip install requests python-dotenv
```

3. Set up your Perplexity API key:
   * Create a `.env` file in the same directory as the script
   * Add your API key: `PERPLEXITY_API_KEY=your_api_key_here`

## 🔧 Usage

### Running the Bot

Simply execute the script:

```bash theme={null}
python daily_knowledge_bot.py
```

This will:

1. Select a topic based on the current day
2. Fetch an interesting fact from Perplexity AI
3. Save the fact to a dated text file in your current directory
4. Display the fact in the console

### Customizing Topics

Edit the `topics.txt` file (one topic per line) or modify the `topics` list directly in the script.

Example topics:

```
astronomy
history
biology
technology
psychology
ocean life
ancient civilizations
quantum physics
art history
culinary science
```

### Automated Scheduling

#### On Linux/macOS (using cron):

```bash theme={null}
# Edit your crontab
crontab -e

# Add this line to run daily at 8:00 AM
0 8 * * * /path/to/python3 /path/to/daily_knowledge_bot.py
```

#### On Windows (using Task Scheduler):

1. Open Task Scheduler
2. Create a new Basic Task
3. Set it to run daily
4. Add the action: Start a program
5. Program/script: `C:\path\to\python.exe`
6. Arguments: `C:\path\to\daily_knowledge_bot.py`

## 🔍 Configuration Options

The following environment variables can be set in your `.env` file:

* `PERPLEXITY_API_KEY` (required): Your Perplexity API key
* `OUTPUT_DIR` (optional): Directory to save fact files (default: current directory)
* `TOPICS_FILE` (optional): Path to your custom topics file

## 📄 Output Example

```
DAILY FACT - 2025-04-02
Topic: astronomy

Saturn's iconic rings are relatively young, potentially forming only 100 million years ago. This means dinosaurs living on Earth likely never saw Saturn with its distinctive rings, as they may have formed long after the dinosaurs went extinct. The rings are made primarily of water ice particles ranging in size from tiny dust grains to boulder-sized chunks.
```

## 🛠️ Extending the Bot

Some ways to extend this bot:

* Add email or SMS delivery capabilities
* Create a web interface to view fact history
* Integrate with social media posting
* Add multimedia content based on the facts
* Implement advanced scheduling with specific topics on specific days

## ⚠️ Limitations

* API rate limits may apply based on your Perplexity account
* Quality of facts depends on the AI model
* The free version of the Sonar API has a token limit that may truncate longer responses

## 📜 License

[MIT License](https://github.com/ppl-ai/api-cookbook/blob/main/LICENSE)

## 🙏 Acknowledgements

* This project uses the Perplexity AI API ([https://docs.perplexity.ai/](https://docs.perplexity.ai/))
* Inspired by daily knowledge calendars and fact-of-the-day services


# Grounded Data Story with Kimi K3
Source: https://docs.perplexity.ai/docs/cookbook/examples/data-story-kimi-k3/README

Turn any topic into a self-contained, source-linked interactive HTML report using Kimi K3, live web search, and the Agent API.

Build a tool that researches any topic and creates an interactive HTML report, using Perplexity's [Agent API](/docs/agent-api/quickstart) and [perplexity/kimi-k3](/docs/agent-api/models).

<Note>
  The output is a draft. Review the claims before you publish anything.
</Note>

## Prerequisites

* Python 3.10 or newer (tested on 3.12)
* A [Perplexity API key](https://www.perplexity.ai/settings/api)
* Internet access for live runs

## Installation

Copy the ten parts under [Full code](#full-code) into a single file named `data_story.py`, then set up an environment:

```bash theme={null}
python3 -m venv .venv
source .venv/bin/activate
python -m pip install perplexityai==0.43.1
```

The pinned version keeps request serialization and background-response handling predictable.

## API key setup

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

The SDK picks this up automatically. Don't paste the key into the script.

## Quick start

```bash theme={null}
python data_story.py "The rise of open-weights AI models"
```

That runs the default `quick` profile. For a higher-budget version at a specific path:

```bash theme={null}
python data_story.py \
  "The rise of open-weights AI models" \
  --profile showcase \
  --output open-weights.html
```

## Usage

```bash theme={null}
python data_story.py TOPIC \
  [--profile {quick,showcase}] \
  [--effort {minimal,low,medium,high,xhigh,max}] \
  [--max-output-tokens N] \
  [--max-steps N] \
  [--wait-timeout SECONDS] \
  [--output PATH] \
  [--receipt PATH]
```

Preview the exact request without spending anything:

```bash theme={null}
python data_story.py "The rise of open-weights AI models" --dry-run
```

If a run outlives your terminal, pick it back up instead of paying for a new one:

```bash theme={null}
python data_story.py \
  --resume resp_your_response_id \
  --output open-weights.html \
  --receipt open-weights.html.receipt.json
```

Reuse the same `--receipt` path when resuming so the original request, any earlier errors, and the resume history all land in one file. It defaults to `<output>.receipt.json`.

## Configuration

| Setting              | `quick` (default) | `showcase` |
| -------------------- | ----------------: | ---------: |
| Reasoning effort     |          `medium` |     `high` |
| Output-token ceiling |            49,152 |     65,536 |
| Max agent steps      |                 8 |         20 |

Override any of it:

```bash theme={null}
python data_story.py "AI inference economics" \
  --effort xhigh \
  --max-output-tokens 64000 \
  --max-steps 14
```

`max_output_tokens` is a ceiling, not a reservation. You're billed for the work the run actually does. Check [current pricing](/docs/getting-started/pricing) before large runs.

The ceiling covers reasoning tokens as well as the visible page, and this model reasons at length before it writes. A budget that looks generous for a single HTML file can still run out mid-document, which is why `quick` sets 49,152 rather than a number closer to the finished page size. If a run does exhaust its budget, the script says so and names the ceiling instead of reporting a malformed document.

All six effort levels work. In `perplexityai==0.43.1` the generated type doesn't include `max`, so the script routes that one value through the SDK's `extra_body` pass-through and uses the typed `reasoning` field for everything else.

## Dry-run preview

`--dry-run` is deterministic, needs no API key, and spends nothing. Abridged output:

```json theme={null}
{
  "model": "perplexity/kimi-k3",
  "background": true,
  "store": true,
  "max_output_tokens": 49152,
  "max_steps": 8,
  "tools": [
    {
      "type": "web_search"
    }
  ],
  "reasoning": {
    "effort": "medium"
  }
}
```

A completed run writes two files:

```text theme={null}
data-story-<timestamp>.html
data-story-<timestamp>.html.receipt.json
```

## How it works

1. Build one Agent API request with `web_search`, an effort level, an output ceiling, and a step limit.
2. Submit it once with `background=True` and `store=True`, with create-retries off.
3. The response ID comes back immediately. Write it to the receipt before anything else, because that ID is your recovery path.
4. Poll `client.responses.retrieve(response_id)` with bounded timeouts and backoff, printing status changes and new search queries as they appear.
5. Kimi K3 tags every stat card and chart mark with a numeric result ID and leaves a `PERPLEXITY_SOURCES` placeholder.
6. On completion, validate the document, match every referenced ID against the API's `search_results`, inject the real URLs and a Content Security Policy, then write the file atomically.

Only `completed` counts as success. `queued` and `in_progress` mean keep waiting; anything else is treated as terminal, so a new status can never trap you in an infinite poll.

If the create call dies before returning an ID, the outcome is genuinely unknown. The CLI records `submission_unknown` and stops rather than risk double-billing you. Check your API activity before resubmitting.

### Trace every number to a source

K3 never writes an external URL. The prompt asks it for citation fragments like `#source-3` and `data-source-id="3"`, and the CLI substitutes the real URL for result 3 from the API's structured output. A model can hallucinate a URL; it can't hallucinate an array index that has to match.

The validator rejects incomplete documents, unknown source IDs, model-written URLs, remote assets, frames, active forms, network-capable JavaScript, non-focusable chart marks, SVG SMIL animation, and marks drawn outside their chart's `viewBox`. It also blocks global `svg { width: 100% }` rules, which quietly turn 16px icons into full-page graphics.

That catches structural and rendering failures. It says nothing about whether a sentence interprets its source correctly.

## Prompting notes

* Keep research and page-building in one two-phase prompt so K3 can connect source IDs to the markup it writes.
* Ask for the source's own terminology and rule out inferred scope. A citation can be real while the sentence around it overstates the finding.
* Specify the chart contract mechanically: numeric `data-source-id`, matching citation, focusable geometry, shared axis scale, visible bounds, tooltip per mark.
* Require CSS animation with a reduced-motion query. SMIL is rejected because CSS can't reliably switch it off.
* Scope responsive sizing to `figure svg`, never to every SVG on the page.

## Full code

The script is split into ten parts below. Each part is collapsed so you can read what it does before opening it. Expand a part to read or copy it, and append the ten in order into a single file named `data_story.py`.

### 1. Configure the model and run profiles

Imports, the model ID, and the two run profiles. `PENDING_STATUSES` is the allowlist that keeps polling alive. Every status outside it ends the run, so a new server-side status can never leave you looping forever. `CSP_META` is the Content Security Policy stamped into the finished page, which is what makes the output safe to open locally.

<Accordion title="Show the code (86 lines)">
  ```python data_story.py (part 1 of 10) theme={null}
  """Grounded Data Story: Kimi K3 + Perplexity Agent API.

  One durable agent run: Kimi K3 researches a topic with live web_search,
  then writes a self-contained interactive HTML data story. The CLI preserves
  the background response ID, polls under a local deadline, validates the
  artifact, injects authoritative API source links, and records exact usage.

  Usage:
      python data_story.py "The rise of open-weights AI models"
      python data_story.py "Global EV adoption" --profile showcase --output ev.html
      python data_story.py --resume resp_abc123 --output recovered.html
  """

  from __future__ import annotations

  import argparse
  from datetime import datetime, timezone
  from html import escape
  from html.parser import HTMLParser
  import json
  import os
  from pathlib import Path
  import re
  import shlex
  import sys
  import tempfile
  import time
  from typing import Any, Callable, Iterable
  from urllib.parse import urlsplit

  import httpx
  from perplexity import (
      APIConnectionError,
      APIError,
      APIStatusError,
      InternalServerError,
      Perplexity,
      RateLimitError,
  )


  MODEL = "perplexity/kimi-k3"
  EFFORT_LEVELS = ["minimal", "low", "medium", "high", "xhigh", "max"]
  PROFILES = {
      "quick": {"effort": "medium", "max_output_tokens": 49152, "max_steps": 8},
      "showcase": {"effort": "high", "max_output_tokens": 65536, "max_steps": 20},
  }
  PENDING_STATUSES = {"queued", "in_progress"}
  SOURCE_PLACEHOLDER = "<!-- PERPLEXITY_SOURCES -->"

  # Styles the CLI owns for the source list it injects. Every colour derives from
  # the surrounding text via currentColor, so this adapts to whatever palette the
  # model chose instead of assuming one.
  SOURCE_STYLE = """<style>
    .source-list{margin:0;padding-left:1.6rem;}
    .source-list li{margin:.4rem 0;padding:.2rem .45rem;border-radius:5px;scroll-margin-top:1.5rem;}
    .source-list a{color:inherit;text-decoration:underline;
      text-underline-offset:2px;text-decoration-thickness:1px;}
    .source-list a:hover,.source-list a:focus-visible{text-decoration-thickness:2px;}
    .source-list .source-date{opacity:.7;}
    .source-list li:target{
      background:color-mix(in srgb, currentColor 14%, transparent);
      outline:2px solid color-mix(in srgb, currentColor 45%, transparent);
      outline-offset:1px;}
  </style>"""
  POLL_INTERVAL_SECONDS = 3.0
  POLL_RETRY_ATTEMPTS = 4
  DEFAULT_WAIT_TIMEOUT_SECONDS = 3600
  MIN_CITED_SOURCES = 3

  CSP_CONTENT = (
      "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; "
      "img-src data:; connect-src 'none'; font-src 'none'; media-src 'none'; "
      "object-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'"
  )
  CSP_META = (
      '<meta http-equiv="Content-Security-Policy" '
      f'content="{CSP_CONTENT}">'
  )

  STORY_SYSTEM = (
      "You are a data journalist and front-end engineer. Research with web_search, "
      "then design and hand-code a beautiful, self-contained interactive HTML data "
      "story. Every externally verifiable factual claim must be supported by a "
      "web_search result from this run; never rely on memory for facts."
  )
  ```
</Accordion>

### 2. Write the two-phase prompt

One prompt, two phases: research first, then build the page. Keeping them together is deliberate, because K3 needs the search results in the same context to wire each number back to the result that produced it. Note that it asks for `data-source-id="3"`, never a URL. That's the whole grounding trick.

<Accordion title="Show the code (64 lines)">
  ```python data_story.py (part 2 of 10) theme={null}

  STORY_TASK = f"""\
  Create a single-page interactive data story about: {{topic}}

  Phase 1 - Research (web_search):
  Run several focused searches. Collect 10-15 concrete, recent facts and figures:
  numbers, dates, rankings, and growth rates. Track the numeric result ID and
  publication date for each fact. Prefer primary sources published within the
  last 12 months. If sources disagree, use the most recent authoritative figure.

  Phase 2 - Build (write the code yourself):
  Design one polished, self-contained HTML file. Keep all CSS and JavaScript
  inline; use no external libraries, assets, or network requests. It must include:

  1. A hero header with a title, one-line takeaway, and covered date range. Put
     inline citations after every factual claim in the takeaway.
  2. Exactly 3-4 key-stat cards. Give each card class="stat-card" and the
     supporting result ID as data-source-id="N". Put the matching #source-N
     citation link inside that same card.
  3. At least two hand-coded SVG charts with labels, gridlines, and hover
     tooltips. Put each SVG inside its own <figure>. Give the SVG role="img", an
     accessible <title>, gridlines with class="gridline", and at least two axis
     labels with class="axis-label". Give every plotted value class="data-mark",
     tabindex="0", its supporting result ID as data-source-id="N", and a nested
     <title> tooltip. Use only untransformed circle, ellipse, rect, or line
     primitives for each data mark. Add a <figcaption> whose citations cover every
     result ID plotted in that chart. Derive every mark coordinate from the same
     scale shown by the axis; extend the axis domain so all marks, labels, and
     strokes remain visibly inside the SVG viewBox. Double-check the maximum value
     against the axis before returning the page.
  4. A 2-3 paragraph narrative inside <section class="narrative"> that connects
     the evidence. End every factual sentence with one or more citation links;
     clearly label interpretation as analysis rather than fact.
  5. Superscript citations for every stat and plotted value, formatted exactly
     as <sup><a class="citation" href="#source-N">[N]</a></sup>, where N is a
     numeric web_search result ID from this run.
  6. Put this exact placeholder where the complete sources section belongs:
     {SOURCE_PLACEHOLDER}

  Do not write external URLs yourself. The CLI replaces the placeholder with
  titles, dates, and canonical URLs taken directly from the API search_results.
  Do not use fetch, XMLHttpRequest, WebSocket, EventSource, sendBeacon, dynamic
  imports, iframes, forms, remote images, external CSS, or external scripts.
  Do not use SVG SMIL elements such as <animate>, <animateMotion>, or
  <animateTransform>; animate only with CSS so reduced-motion preferences work.

  Use the source's exact terminology and scope. Do not turn "versions" into
  "fine-tunes," infer distribution-channel coverage, or add unsupported rhetoric.
  When two series are not directly comparable, say so without declaring a winner.

  Design: dark background, high-contrast accent palette, modern sans-serif
  system font stack, generous whitespace, subtle CSS animations, responsive
  layout, keyboard-visible focus states, and a
  @media (prefers-reduced-motion: reduce) rule that disables both animation and
  transition. Scope responsive chart sizing to figure svg; never apply width:100%
  to every svg because small interface icons must retain their explicit size.
  Keep SVG text legible at a 390px-wide viewport.

  Output format - IMPORTANT:
  First, a 2-3 sentence summary of what the data says. Do not expose research
  notes, working, or a fact list. Then output exactly one HTML document starting
  with <!DOCTYPE html> and ending with </html>. Do not use Markdown fences and do
  not put any text after </html>.
  """
  ```
</Accordion>

### 3. Define the errors and the run receipt

Five exception types that separate "still working" from "failed" from "we genuinely don't know." `SubmissionUnknownError` is the important one: if the connection dies before an ID comes back, you can't tell whether you were billed. `atomic_write_text` writes to a temp file and renames, so a crash mid-write can't leave you with a half-written report.

<Accordion title="Show the code (133 lines)">
  ```python data_story.py (part 3 of 10) theme={null}


  class RunError(RuntimeError):
      """Base class for recoverable or terminal run failures."""


  class SubmissionUnknownError(RunError):
      """The create connection failed before a response ID was received."""


  class PendingRunError(RunError):
      """Local waiting ended while the durable server-side run may continue."""

      def __init__(self, response_id: str):
          self.response_id = response_id
          super().__init__(
              f"Run {response_id} did not reach a known terminal state locally. "
              "Resume without creating a new run: "
              f"python data_story.py --resume {response_id}"
          )


  class TerminalRunError(RunError):
      """The Agent API reported a non-success terminal status."""


  class StoryValidationError(RunError):
      """The completed response did not satisfy the artifact contract."""


  def get_value(value: Any, name: str, default: Any = None) -> Any:
      if isinstance(value, dict):
          return value.get(name, default)
      return getattr(value, name, default)


  def plain_value(value: Any) -> Any:
      if value is None or isinstance(value, (str, int, float, bool)):
          return value
      if isinstance(value, dict):
          return {str(key): plain_value(item) for key, item in value.items()}
      if isinstance(value, (list, tuple)):
          return [plain_value(item) for item in value]
      if hasattr(value, "model_dump"):
          return value.model_dump(mode="json")
      return str(value)


  def utc_now() -> str:
      return datetime.now(timezone.utc).isoformat()


  def atomic_write_text(path: Path, text: str) -> None:
      path.parent.mkdir(parents=True, exist_ok=True)
      temporary: Path | None = None
      try:
          with tempfile.NamedTemporaryFile(
              "w", encoding="utf-8", dir=path.parent, prefix=f".{path.name}.", delete=False
          ) as handle:
              handle.write(text)
              handle.flush()
              os.fsync(handle.fileno())
              temporary = Path(handle.name)
          os.replace(temporary, path)
          temporary = None
      finally:
          if temporary is not None:
              temporary.unlink(missing_ok=True)


  def write_receipt(path: Path, receipt: dict[str, Any]) -> None:
      receipt["updated_at"] = utc_now()
      api_key = os.environ.get("PERPLEXITY_API_KEY")

      def redacted(value: Any) -> Any:
          if isinstance(value, str):
              return value.replace(api_key, "[REDACTED]") if api_key else value
          if isinstance(value, dict):
              return {key: redacted(item) for key, item in value.items()}
          if isinstance(value, list):
              return [redacted(item) for item in value]
          return value

      atomic_write_text(path, json.dumps(redacted(receipt), indent=2, ensure_ascii=False) + "\n")


  def begin_client_attempt(receipt: dict[str, Any], mode: str) -> dict[str, Any]:
      """Start a receipt attempt and migrate receipts created by older versions."""
      if not receipt.get("attempts") and (
          "client_elapsed_seconds" in receipt or "client_error" in receipt
      ):
          legacy: dict[str, Any] = {
              "mode": "resume" if receipt.get("resume_history") else "submit",
              "status": receipt.get("status", "unknown"),
              "finished_at": receipt.get("updated_at"),
          }
          if "client_elapsed_seconds" in receipt:
              legacy["elapsed_seconds"] = receipt["client_elapsed_seconds"]
          if "client_error" in receipt:
              legacy["error"] = receipt["client_error"]
          receipt.setdefault("attempts", []).append(legacy)

      receipt.pop("client_error", None)
      receipt.pop("client_wait_status", None)
      attempt = {"mode": mode, "status": "running", "started_at": utc_now()}
      receipt.setdefault("attempts", []).append(attempt)
      return attempt


  def finish_client_attempt(
      receipt: dict[str, Any],
      attempt: dict[str, Any],
      status: str,
      elapsed_seconds: float,
      error: BaseException | None = None,
  ) -> None:
      elapsed = round(elapsed_seconds, 3)
      attempt.update({"status": status, "finished_at": utc_now(), "elapsed_seconds": elapsed})
      if error is not None:
          detail = {"type": type(error).__name__, "message": str(error)}
          attempt["error"] = detail
          receipt["client_error"] = detail
      else:
          receipt.pop("client_error", None)
          receipt.pop("client_wait_status", None)
      elapsed_attempts = [
          float(item["elapsed_seconds"])
          for item in receipt.get("attempts", [])
          if isinstance(item, dict) and isinstance(item.get("elapsed_seconds"), (int, float))
      ]
      receipt["attempt_count"] = len(receipt.get("attempts", []))
      receipt["last_client_attempt_elapsed_seconds"] = elapsed
      receipt["client_elapsed_seconds"] = round(sum(elapsed_attempts), 3)
  ```
</Accordion>

### 4. Build the request and record the response

`build_request` assembles the payload and routes `max` effort through `extra_body` (the typed field doesn't accept it in SDK 0.43.1). `checkpoint_response` saves the response ID to disk the moment it arrives, before any other work, so a crash on the next line still leaves you a `--resume` path.

<Accordion title="Show the code (124 lines)">
  ```python data_story.py (part 4 of 10) theme={null}


  def resolve_config(
      profile: str,
      effort: str | None = None,
      max_output_tokens: int | None = None,
      max_steps: int | None = None,
  ) -> dict[str, Any]:
      config = dict(PROFILES[profile])
      if effort is not None:
          config["effort"] = effort
      if max_output_tokens is not None:
          config["max_output_tokens"] = max_output_tokens
      if max_steps is not None:
          config["max_steps"] = max_steps
      if config["max_output_tokens"] < 1:
          raise ValueError("max_output_tokens must be at least 1")
      if not 1 <= config["max_steps"] <= 100:
          raise ValueError("max_steps must be between 1 and 100")
      return config


  def build_request(
      topic: str,
      effort: str,
      max_output_tokens: int,
      max_steps: int,
  ) -> dict[str, Any]:
      request: dict[str, Any] = {
          "model": MODEL,
          "background": True,
          "store": True,
          "max_output_tokens": max_output_tokens,
          "max_steps": max_steps,
          "instructions": STORY_SYSTEM,
          "input": STORY_TASK.format(topic=topic),
          "tools": [{"type": "web_search"}],
      }
      if effort == "max":
          # perplexityai 0.43.1 omits documented "max" from its generated enum.
          request["extra_body"] = {"reasoning": {"effort": "max"}}
      else:
          request["reasoning"] = {"effort": effort}
      return request


  def wire_request_preview(request: dict[str, Any]) -> dict[str, Any]:
      preview = {key: value for key, value in request.items() if key != "extra_body"}
      preview.update(request.get("extra_body", {}))
      return preview


  def response_error(response: Any) -> Any:
      return plain_value(get_value(response, "error"))


  def checkpoint_response(
      response: Any,
      receipt: dict[str, Any],
      receipt_path: Path,
      sequence_number: int | None = None,
  ) -> None:
      response_id = get_value(response, "id")
      if response_id:
          receipt["response_id"] = response_id
      provider_status = get_value(response, "status")
      if provider_status is not None:
          receipt["provider_status"] = provider_status
      receipt["model"] = get_value(response, "model", receipt.get("model"))
      created_at = get_value(response, "created_at")
      if created_at is not None:
          receipt["provider_created_at"] = created_at
      if sequence_number is not None:
          receipt["last_sequence_number"] = sequence_number
      error = response_error(response)
      if error:
          receipt["error"] = error
      usage = get_value(response, "usage")
      if usage is not None:
          receipt["usage"] = plain_value(usage)
      write_receipt(receipt_path, receipt)


  def source_records_from_item(item: Any) -> tuple[list[str], list[dict[str, Any]]]:
      if get_value(item, "type") != "search_results":
          return [], []
      queries = [str(query) for query in get_value(item, "queries", []) or []]
      sources = []
      for result in get_value(item, "results", []) or []:
          sources.append(
              {
                  "id": str(get_value(result, "id", "")),
                  "title": str(get_value(result, "title", "") or ""),
                  "url": str(get_value(result, "url", "") or ""),
                  "date": get_value(result, "date"),
                  "last_updated": get_value(result, "last_updated"),
                  "snippet": str(get_value(result, "snippet", "") or ""),
              }
          )
      return queries, sources


  def response_research(response: Any) -> tuple[list[str], list[dict[str, Any]]]:
      queries: list[str] = []
      sources: list[dict[str, Any]] = []
      for item in get_value(response, "output", []) or []:
          item_queries, item_sources = source_records_from_item(item)
          queries.extend(item_queries)
          sources.extend(item_sources)
      return list(dict.fromkeys(queries)), sources


  def record_research(
      receipt: dict[str, Any],
      receipt_path: Path,
      queries: Iterable[str],
      sources: Iterable[dict[str, Any]],
  ) -> None:
      receipt["queries"] = list(dict.fromkeys([*receipt.get("queries", []), *queries]))
      existing = {str(item.get("id")): item for item in receipt.get("sources", [])}
      for source in sources:
          existing[str(source.get("id"))] = source
      receipt["sources"] = list(existing.values())
      write_receipt(receipt_path, receipt)
  ```
</Accordion>

### 5. Poll until the run finishes

Retrieve the response on an interval until it finishes or the local deadline expires. Transient errors get bounded retries; new search queries print as they appear so a ten-minute run isn't a blank terminal. Hitting the deadline raises rather than killing the job. The run keeps going server-side and you resume with the ID.

<Accordion title="Show the code (86 lines)">
  ```python data_story.py (part 5 of 10) theme={null}


  def poll_response(
      client: Perplexity,
      response_id: str,
      receipt: dict[str, Any],
      receipt_path: Path,
      wait_timeout: float,
      poll_interval: float = POLL_INTERVAL_SECONDS,
      sleep: Callable[[float], None] = time.sleep,
      monotonic: Callable[[], float] = time.monotonic,
      started_at: float | None = None,
  ) -> Any:
      started = monotonic() if started_at is None else started_at
      deadline = started + wait_timeout
      poll_client = client.with_options(max_retries=0)
      last_status: str | None = None
      last_heartbeat = started
      retry_attempt = 0
      receipt["status"] = "waiting"
      write_receipt(receipt_path, receipt)
      while True:
          before_request = monotonic()
          if before_request >= deadline:
              receipt["client_wait_status"] = "timed_out"
              write_receipt(receipt_path, receipt)
              raise PendingRunError(response_id)
          remaining = deadline - before_request
          try:
              response = poll_client.responses.retrieve(
                  response_id,
                  timeout=min(remaining, 30.0),
              )
              retry_attempt = 0
          except (
              APIConnectionError, InternalServerError, RateLimitError, httpx.HTTPError
          ) as error:
              retry_attempt += 1
              now = monotonic()
              if retry_attempt >= POLL_RETRY_ATTEMPTS:
                  receipt["client_wait_status"] = "retrieval_failed"
                  write_receipt(receipt_path, receipt)
                  raise PendingRunError(response_id) from error
              delay = min(2 ** (retry_attempt - 1), 8, max(0.0, deadline - now))
              if delay <= 0:
                  receipt["client_wait_status"] = "timed_out"
                  write_receipt(receipt_path, receipt)
                  raise PendingRunError(response_id)
              print(f"\n  retrieval interrupted; retrying in {delay:g}s", file=sys.stderr)
              sleep(delay)
              continue

          status = str(get_value(response, "status", "unknown"))
          checkpoint_response(response, receipt, receipt_path)
          queries, sources = response_research(response)
          if queries or sources:
              known_queries = set(receipt.get("queries", []))
              record_research(receipt, receipt_path, queries, sources)
              for query in queries:
                  if query not in known_queries:
                      print(f"\r  searched: {query}" + " " * 20, file=sys.stderr)

          now = monotonic()
          if status != last_status or now - last_heartbeat >= 15:
              print(
                  f"\r  {status} · {now - started:,.0f}s elapsed" + " " * 20,
                  end="",
                  file=sys.stderr,
                  flush=True,
              )
              last_status = status
              last_heartbeat = now

          if status == "completed":
              print(file=sys.stderr)
              return response
          if status not in PENDING_STATUSES:
              print(file=sys.stderr)
              detail = response_error(response) or "No provider error detail was returned."
              raise TerminalRunError(f"Run {response_id} ended with status {status}: {detail}")
          if now >= deadline:
              receipt["client_wait_status"] = "timed_out"
              write_receipt(receipt_path, receipt)
              print(file=sys.stderr)
              raise PendingRunError(response_id)
          sleep(min(poll_interval, deadline - now))
  ```
</Accordion>

### 6. Submit the run exactly once

The paid call, made exactly once. `background=True` and `store=True` make it durable; automatic create-retries are turned off so a flaky network can't quietly submit twice. Everything after this point is recovery rather than resubmission.

<Accordion title="Show the code (69 lines)">
  ```python data_story.py (part 6 of 10) theme={null}


  def run_background(
      client: Perplexity,
      create_kwargs: dict[str, Any],
      receipt: dict[str, Any],
      receipt_path: Path,
      wait_timeout: float,
      sleep: Callable[[float], None] = time.sleep,
      monotonic: Callable[[], float] = time.monotonic,
  ) -> Any:
      started = monotonic()
      create_client = client.with_options(max_retries=0)
      try:
          response = create_client.responses.create(
              timeout=wait_timeout,
              **create_kwargs,
          )
      except APIStatusError as error:
          if 400 <= error.status_code < 500:
              raise
          receipt["submission_error"] = {
              "type": type(error).__name__,
              "message": str(error),
          }
          receipt["status"] = "submission_unknown"
          write_receipt(receipt_path, receipt)
          raise SubmissionUnknownError(
              "The server returned an error after the create request was sent. The "
              "submission outcome is unknown, so the CLI will not retry automatically."
          ) from error
      except (APIError, httpx.HTTPError) as error:
          receipt["submission_error"] = {
              "type": type(error).__name__,
              "message": str(error),
          }
          receipt["status"] = "submission_unknown"
          write_receipt(receipt_path, receipt)
          raise SubmissionUnknownError(
              "The create connection failed before a response ID arrived. The submission "
              "outcome is unknown, so the CLI will not retry automatically."
          ) from error

      response_id = get_value(response, "id")
      if not response_id:
          receipt["status"] = "submission_unknown"
          write_receipt(receipt_path, receipt)
          raise SubmissionUnknownError("The create response did not contain a response ID.")

      checkpoint_response(response, receipt, receipt_path)
      queries, sources = response_research(response)
      if queries or sources:
          record_research(receipt, receipt_path, queries, sources)
      status = str(get_value(response, "status", "unknown"))
      if status == "completed":
          return response
      if status not in PENDING_STATUSES:
          detail = response_error(response) or "No provider error detail was returned."
          raise TerminalRunError(f"Run {response_id} ended with status {status}: {detail}")
      return poll_response(
          client,
          str(response_id),
          receipt,
          receipt_path,
          wait_timeout,
          sleep=sleep,
          monotonic=monotonic,
          started_at=started,
      )
  ```
</Accordion>

### 7. Extract the HTML and measure the SVG

Pull the document out of the response, then the geometry helpers: `svg_viewbox` reads the coordinate space and `primitive_bounds` computes where a shape actually lands. These feed the check that catches chart marks drawn outside their own chart.

`check_output_budget` runs first and handles the most common way a run fails. When the model spends its entire output budget, the page stops mid-tag and the document is genuinely malformed, so every downstream check reports a broken document rather than the real cause. Comparing `output_tokens` against the ceiling separates the two, and the error names the ceiling and the flag to raise it.

<Accordion title="Show the code (120 lines)">
  ```python data_story.py (part 7 of 10) theme={null}


  def final_text(response: Any) -> str:
      return "".join(
          str(get_value(block, "text", ""))
          for item in get_value(response, "output", []) or []
          if get_value(item, "type") == "message"
          for block in get_value(item, "content", []) or []
          if get_value(block, "type") == "output_text"
      )


  def check_output_budget(response: Any, ceiling: int | None) -> None:
      """Fail with the real reason when the model ran out of output budget.

      `max_output_tokens` covers reasoning tokens as well as the visible document,
      so a long research phase can consume the budget before the closing `</html>`
      is written. Spending the whole ceiling is the signature of that truncation,
      and saying so is more useful than reporting a malformed document.
      """
      if not ceiling:
          return
      usage = get_value(response, "usage")
      used = get_value(usage, "output_tokens") if usage is not None else None
      if isinstance(used, int) and used >= ceiling:
          raise StoryValidationError(
              f"The run used its entire output budget of {ceiling} tokens, so the "
              "document was cut off before it finished. The budget covers reasoning "
              "tokens as well as the page. Retry with a higher ceiling, for example "
              f"--max-output-tokens {ceiling * 2}, or resume the response ID from the "
              "receipt."
          )


  def extract_html(text: str) -> tuple[str, str]:
      if len(re.findall(r"<!doctype\s+html\b", text, re.IGNORECASE)) != 1:
          raise StoryValidationError("Expected exactly one <!DOCTYPE html> document.")
      start = re.search(r"<!doctype\s+html\b[^>]*>", text, re.IGNORECASE)
      end_matches = list(re.finditer(r"</html\s*>", text, re.IGNORECASE))
      if start is None or len(end_matches) != 1:
          raise StoryValidationError("The response must contain one complete HTML document.")
      end = end_matches[0]
      if text[end.end() :].strip():
          raise StoryValidationError("Unexpected text appeared after </html>.")
      summary = text[: start.start()].strip()
      # Some agentic models expose research notes before a final `---` separator.
      # Keep only the intended summary while preserving the strict HTML boundary.
      if re.search(r"(?m)^---\s*$", summary):
          summary = re.split(r"(?m)^---\s*$", summary)[-1].strip()
      return summary, text[start.start() : end.end()]


  def has_external_css_url(text: str) -> bool:
      for match in re.finditer(r"url\s*\(\s*([^)]*?)\s*\)", text, re.IGNORECASE):
          target = match.group(1).strip().strip("'\"").strip()
          if target and not target.lower().startswith("data:") and not target.startswith("#"):
              return True
      return False


  def numeric_attribute(values: dict[str, str], name: str, default: float | None = None) -> float | None:
      raw = values.get(name)
      if raw is None or not raw.strip():
          return default
      if not re.fullmatch(
          r"[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?",
          raw.strip(),
      ):
          return None
      return float(raw)


  def svg_viewbox(value: str) -> tuple[float, float, float, float] | None:
      parts = [part for part in re.split(r"[\s,]+", value.strip()) if part]
      if len(parts) != 4:
          return None
      try:
          x, y, width, height = (float(part) for part in parts)
      except ValueError:
          return None
      if width <= 0 or height <= 0:
          return None
      return x, y, width, height


  def primitive_bounds(
      tag: str, values: dict[str, str]
  ) -> tuple[float, float, float, float] | None:
      """Return untransformed bounds for simple SVG mark primitives."""
      if tag == "circle":
          cx = numeric_attribute(values, "cx", 0.0)
          cy = numeric_attribute(values, "cy", 0.0)
          radius = numeric_attribute(values, "r")
          if None in {cx, cy, radius} or radius < 0:  # type: ignore[operator]
              return None
          return cx - radius, cy - radius, cx + radius, cy + radius  # type: ignore[operator]
      if tag == "ellipse":
          cx = numeric_attribute(values, "cx", 0.0)
          cy = numeric_attribute(values, "cy", 0.0)
          rx = numeric_attribute(values, "rx")
          ry = numeric_attribute(values, "ry")
          if None in {cx, cy, rx, ry} or rx < 0 or ry < 0:  # type: ignore[operator]
              return None
          return cx - rx, cy - ry, cx + rx, cy + ry  # type: ignore[operator]
      if tag == "rect":
          x = numeric_attribute(values, "x", 0.0)
          y = numeric_attribute(values, "y", 0.0)
          width = numeric_attribute(values, "width")
          height = numeric_attribute(values, "height")
          if None in {x, y, width, height} or width < 0 or height < 0:  # type: ignore[operator]
              return None
          return x, y, x + width, y + height  # type: ignore[operator]
      if tag == "line":
          x1 = numeric_attribute(values, "x1", 0.0)
          y1 = numeric_attribute(values, "y1", 0.0)
          x2 = numeric_attribute(values, "x2", 0.0)
          y2 = numeric_attribute(values, "y2", 0.0)
          if None in {x1, y1, x2, y2}:
              return None
          return min(x1, x2), min(y1, y2), max(x1, x2), max(y1, y2)  # type: ignore[type-var]
  ```
</Accordion>

### 8. Validate the generated document

An `HTMLParser` subclass that walks the generated document and rejects anything unsafe or broken: remote assets, frames, active forms, network-capable JavaScript, unknown source IDs, model-written URLs, non-focusable chart marks, SMIL animation, out-of-bounds geometry, and global `svg { width: 100% }` rules. The longest section here, and the reason the output is trustworthy enough to open.

<Accordion title="Show the code (193 lines)">
  ```python data_story.py (part 8 of 10) theme={null}
      return None


  class StoryInspector(HTMLParser):
      VOID_ELEMENTS = {
          "area", "base", "br", "col", "embed", "hr", "img", "input", "link",
          "meta", "param", "source", "track", "wbr",
      }

      def __init__(self) -> None:
          super().__init__(convert_charrefs=True)
          self.placeholder_count = 0
          self.stat_cards: list[dict[str, Any]] = []
          self.figures: list[dict[str, Any]] = []
          self.svgs: list[dict[str, Any]] = []
          self.marks: list[dict[str, Any]] = []
          self.citation_ids: list[str] = []
          self.external_links: list[str] = []
          self.unsafe: list[str] = []
          self.structure_errors: list[str] = []
          self.script_depth = 0
          self.style_depth = 0
          self.script_text: list[str] = []
          self.style_text: list[str] = []
          self.narrative_paragraph_citations: list[int] = []
          self.stack: list[dict[str, Any]] = []

      def handle_comment(self, data: str) -> None:
          if data.strip() == "PERPLEXITY_SOURCES":
              self.placeholder_count += 1

      def handle_startendtag(
          self, tag: str, attrs: list[tuple[str, str | None]]
      ) -> None:
          self.handle_starttag(tag, attrs)
          if tag.lower() not in self.VOID_ELEMENTS:
              self.handle_endtag(tag)

      def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None:
          tag = tag.lower()
          values = {name.lower(): value or "" for name, value in attrs}
          classes = set(values.get("class", "").split())

          parent = self.stack[-1] if self.stack else {}
          stat_index = parent.get("stat_index")
          figure_index = parent.get("figure_index")
          svg_index = parent.get("svg_index")
          mark_index = parent.get("mark_index")
          narrative = bool(parent.get("narrative")) or (
              tag == "section" and "narrative" in classes
          )
          paragraph_index = parent.get("paragraph_index")

          if "stat-card" in classes:
              stat_index = len(self.stat_cards)
              self.stat_cards.append({
                  "source_id": values.get("data-source-id") or None,
                  "citation_ids": [],
              })
          if tag == "figure":
              figure_index = len(self.figures)
              self.figures.append({"citation_ids": [], "svg_indices": []})
          if tag == "svg":
              svg_index = len(self.svgs)
              self.svgs.append({
                  "figure_index": figure_index,
                  "viewbox": svg_viewbox(values.get("viewbox", "")),
                  "mark_indices": [],
                  "gridlines": 0,
                  "axis_labels": 0,
                  "accessible_titles": 0,
                  "accessible": values.get("role") == "img" and bool(
                      values.get("aria-label") or values.get("aria-labelledby")
                  ),
              })
              if figure_index is not None:
                  self.figures[figure_index]["svg_indices"].append(svg_index)
          if "data-mark" in classes:
              mark_index = len(self.marks)
              self.marks.append({
                  "source_id": values.get("data-source-id") or None,
                  "svg_index": svg_index,
                  "has_title": False,
                  "focusable": values.get("tabindex") == "0",
                  "bounds": [],
                  "invalid_geometry": False,
                  "transformed": bool(values.get("transform")),
              })
              if svg_index is not None:
                  self.svgs[svg_index]["mark_indices"].append(mark_index)
          if mark_index is not None and tag in {"circle", "ellipse", "rect", "line"}:
              bounds = primitive_bounds(tag, values)
              if bounds is None:
                  self.marks[mark_index]["invalid_geometry"] = True
              else:
                  self.marks[mark_index]["bounds"].append(bounds)
              if values.get("transform"):
                  self.marks[mark_index]["transformed"] = True
          if svg_index is not None:
              if "gridline" in classes:
                  self.svgs[svg_index]["gridlines"] += 1
              if "axis-label" in classes:
                  self.svgs[svg_index]["axis_labels"] += 1
              if tag == "title":
                  if mark_index is not None:
                      self.marks[mark_index]["has_title"] = True
                  else:
                      self.svgs[svg_index]["accessible_titles"] += 1
          if tag == "p" and narrative:
              self.narrative_paragraph_citations.append(0)
              paragraph_index = len(self.narrative_paragraph_citations) - 1

          if tag == "a":
              href = values.get("href", "")
              if href and not href.startswith("#"):
                  self.external_links.append(href)
              if "citation" in classes:
                  match = re.fullmatch(r"#source-(\d+)", href)
                  if match:
                      source_id = match.group(1)
                      self.citation_ids.append(source_id)
                      if stat_index is not None:
                          self.stat_cards[stat_index]["citation_ids"].append(source_id)
                      if figure_index is not None:
                          self.figures[figure_index]["citation_ids"].append(source_id)
                      if paragraph_index is not None:
                          self.narrative_paragraph_citations[paragraph_index] += 1
                  else:
                      self.unsafe.append("A citation has an invalid source fragment.")
          if tag == "script":
              self.script_depth += 1
              if values.get("src"):
                  self.unsafe.append("External script src is not allowed.")
          if tag == "style":
              self.style_depth += 1
          if tag == "link":
              self.unsafe.append("External link elements are not allowed.")
          if tag in {"iframe", "object", "embed", "base"}:
              self.unsafe.append(f"<{tag}> is not allowed.")
          if tag in {"animate", "animatemotion", "animatetransform", "set"}:
              self.unsafe.append("SVG SMIL animation is not allowed; use reduced-motion-safe CSS.")
          if tag == "form":
              self.unsafe.append("Forms are not allowed.")
          if tag in {"img", "audio", "video", "source", "track"}:
              source = values.get("src", "")
              if source and not source.lower().startswith("data:"):
                  self.unsafe.append(f"External <{tag}> assets are not allowed.")
              if values.get("srcset"):
                  self.unsafe.append("srcset assets are not allowed.")
          if tag == "meta" and values.get("http-equiv", "").lower() == "refresh":
              self.unsafe.append("Meta refresh is not allowed.")
          for name in ("src", "srcset", "action", "formaction"):
              if re.search(r"(?:https?:)?//", values.get(name, ""), re.IGNORECASE):
                  self.unsafe.append(f"Remote {name} is not allowed.")
          for name, value in values.items():
              if name.startswith("on"):
                  self.unsafe.append("Inline event-handler attributes are not allowed.")
              if has_external_css_url(value):
                  self.unsafe.append("External CSS URLs are not allowed.")

          if tag not in self.VOID_ELEMENTS:
              self.stack.append({
                  "tag": tag,
                  "stat_index": stat_index,
                  "figure_index": figure_index,
                  "svg_index": svg_index,
                  "mark_index": mark_index,
                  "narrative": narrative,
                  "paragraph_index": paragraph_index,
              })

      def handle_endtag(self, tag: str) -> None:
          tag = tag.lower()
          if tag == "script" and self.script_depth:
              self.script_depth -= 1
          if tag == "style" and self.style_depth:
              self.style_depth -= 1
          matching = next(
              (index for index in range(len(self.stack) - 1, -1, -1)
               if self.stack[index]["tag"] == tag),
              None,
          )
          if matching is None:
              self.structure_errors.append(f"Unexpected closing </{tag}> tag.")
          else:
              if matching != len(self.stack) - 1:
                  self.structure_errors.append(f"Mismatched nesting before </{tag}>.")
              del self.stack[matching:]

      def handle_data(self, data: str) -> None:
          if self.script_depth:
              self.script_text.append(data)
          if self.style_depth:
  ```
</Accordion>

### 9. Inject the real source URLs

Where grounding actually happens. Every `data-source-id` the model wrote is matched against the API's structured `search_results`, and the real title, date, and URL are substituted in. An ID with no matching result fails the run.

Three details keep the injected list from looking bolted on. `has_sources_heading` checks whether the model already wrote its own Sources heading above the placeholder, and skips ours when it did, so the page never shows the word twice. `SOURCE_STYLE` then styles the list using `inherit` and `currentColor` rather than fixed colors, so it picks up whatever palette the model chose and a `:target` rule highlights the entry a citation jumps to.

`renumber_sources` handles the numbering. The model cites raw search-result IDs, which are sparse, so a marker reading `[33]` would sit above an ordered list that renders it as `3.`. The function maps each cited ID to its position in order of first appearance, then rewrites the marker text, the anchor target, and the `data-source-id` attribute together in a single pass so a swap like 1 to 2 and 2 to 1 cannot cascade.

<Accordion title="Show the code (239 lines)">
  ```python data_story.py (part 9 of 10) theme={null}
              self.style_text.append(data)


  def authoritative_sources(sources: Iterable[dict[str, Any]]) -> dict[str, dict[str, Any]]:
      authoritative: dict[str, dict[str, Any]] = {}
      for source in sources:
          source_id = str(source.get("id", ""))
          if not re.fullmatch(r"\d+", source_id):
              raise StoryValidationError(f"Search result has an invalid numeric ID: {source_id!r}")
          url = str(source.get("url", ""))
          parsed = urlsplit(url)
          if parsed.scheme not in {"http", "https"} or not parsed.netloc:
              raise StoryValidationError(f"Search result {source_id} has an invalid URL.")
          if source_id in authoritative and authoritative[source_id]["url"] != url:
              raise StoryValidationError(f"Search result ID {source_id} maps to conflicting URLs.")
          authoritative[source_id] = source
      if not authoritative:
          raise StoryValidationError("The completed response contained no usable search results.")
      return authoritative


  def has_sources_heading(document: str, placeholder_index: int) -> bool:
      """Report whether the model already wrote a Sources heading above the placeholder.

      Only the innermost enclosing section is inspected, so a heading somewhere
      earlier in the page does not suppress our own.
      """
      prefix = document[:placeholder_index]
      section_start = prefix.rfind("<section")
      segment = prefix[section_start:] if section_start != -1 else prefix
      return re.search(r"<h[1-6]\b[^>]*>\s*sources\s*</h[1-6]>", segment, re.IGNORECASE) is not None


  def renumber_sources(document: str, used_ids: list[str]) -> tuple[str, list[str]]:
      """Renumber citations 1..N in order of first appearance.

      The model cites raw search-result IDs, which are sparse, so an ordered list
      renders "1." next to a marker that reads "[33]". Every marker, anchor target,
      and data-source-id is rewritten together, and the returned IDs are the new
      ones in list order.
      """
      mapping = {old: str(index) for index, old in enumerate(used_ids, start=1)}

      def rewrite_anchor(match: re.Match[str]) -> str:
          anchor = match.group(0)
          old = match.group(1)
          new = mapping.get(old)
          if new is None:
              return anchor
          opening_end = anchor.index(">") + 1
          opening = anchor[:opening_end].replace(f"#source-{old}", f"#source-{new}")
          body = re.sub(rf"\b{re.escape(old)}\b", new, anchor[opening_end:], count=1)
          return opening + body

      document = re.sub(
          r'<a\b[^>]*\bhref="#source-(\d+)"[^>]*>.*?</a>',
          rewrite_anchor,
          document,
          flags=re.DOTALL,
      )
      document = re.sub(
          r'data-source-id="(\d+)"',
          lambda match: f'data-source-id="{mapping.get(match.group(1), match.group(1))}"',
          document,
      )
      return document, [mapping[old] for old in used_ids]


  def source_section(
      source_ids: Iterable[str],
      sources: dict[str, dict[str, Any]],
      *,
      include_heading: bool = True,
  ) -> str:
      rows = []
      for source_id in source_ids:
          source = sources[source_id]
          title = escape(str(source.get("title") or source["url"]))
          url = escape(str(source["url"]), quote=True)
          date = source.get("date") or source.get("last_updated")
          date_text = f" <span class=\"source-date\">({escape(str(date))})</span>" if date else ""
          rows.append(
              f'    <li id="source-{source_id}"><a href="{url}" target="_blank" '
              f'rel="noopener noreferrer">{title}</a>{date_text}</li>'
          )
      ordered_list = '  <ol class="source-list">\n' + "\n".join(rows) + "\n  </ol>"
      if not include_heading:
          return ordered_list.strip()
      return (
          '<section id="sources" class="sources" aria-labelledby="sources-heading">\n'
          '  <h2 id="sources-heading">Sources</h2>\n'
          + ordered_list
          + "\n</section>"
      )


  def insert_csp(document: str) -> str:
      csp_pattern = re.compile(
          r'<meta\b(?=[^>]*\bhttp-equiv\s*=\s*["\']?Content-Security-Policy["\']?)[^>]*>',
          re.IGNORECASE,
      )
      document = csp_pattern.sub("", document)
      head = re.search(r"<head\b[^>]*>", document, re.IGNORECASE)
      if head is None:
          raise StoryValidationError("The HTML document is missing <head>.")
      return document[: head.end()] + "\n  " + CSP_META + document[head.end() :]


  def insert_source_style(document: str) -> str:
      """Append the source-list styles as the last rule set in <head>."""
      head_end = re.search(r"</head\s*>", document, re.IGNORECASE)
      if head_end is None:
          raise StoryValidationError("The HTML document is missing </head>.")
      return document[: head_end.start()] + "  " + SOURCE_STYLE + "\n" + document[head_end.start() :]


  def finalize_html(raw_html: str, search_sources: Iterable[dict[str, Any]]) -> str:
      if raw_html.count(SOURCE_PLACEHOLDER) != 1:
          raise StoryValidationError("Expected exactly one PERPLEXITY_SOURCES placeholder.")
      inspector = StoryInspector()
      inspector.feed(raw_html)
      inspector.close()
      if inspector.placeholder_count != 1:
          raise StoryValidationError("The source placeholder must be an HTML comment.")
      if inspector.structure_errors or inspector.stack:
          raise StoryValidationError("The HTML contains unbalanced or mismatched tags.")
      if not 3 <= len(inspector.stat_cards) <= 4:
          raise StoryValidationError("Expected exactly 3-4 .stat-card elements.")
      chart_svgs = [svg for svg in inspector.svgs if svg["mark_indices"]]
      if len(chart_svgs) < 2:
          raise StoryValidationError("Expected at least two SVG charts.")
      if not 2 <= len(inspector.narrative_paragraph_citations) <= 3:
          raise StoryValidationError("Expected 2-3 paragraphs inside .narrative.")
      if any(count == 0 for count in inspector.narrative_paragraph_citations):
          raise StoryValidationError("Every narrative paragraph needs at least one citation.")
      if inspector.external_links:
          raise StoryValidationError("The model wrote external URLs instead of source IDs.")

      script = "\n".join(inspector.script_text)
      style = "\n".join(inspector.style_text)
      if re.search(
          r"\b(?:fetch|XMLHttpRequest|WebSocket|EventSource|sendBeacon|import)\s*\(",
          script,
          re.IGNORECASE,
      ):
          inspector.unsafe.append("Network-capable JavaScript is not allowed.")
      if re.search(r"@import", style, re.IGNORECASE) or has_external_css_url(style):
          inspector.unsafe.append("Remote CSS is not allowed.")
      if re.search(
          r"(?:^|})\s*svg\s*(?:,[^{]*)?\{[^}]*\bwidth\s*:\s*100\s*%",
          style,
          re.IGNORECASE | re.DOTALL,
      ):
          inspector.unsafe.append("Scope width:100% to chart SVGs instead of every SVG.")
      if not re.search(r"prefers-reduced-motion\s*:\s*reduce", style, re.IGNORECASE):
          inspector.unsafe.append("A prefers-reduced-motion: reduce rule is required.")
      if not re.search(r"animation\s*:\s*none\b", style, re.IGNORECASE):
          inspector.unsafe.append("Reduced-motion CSS must disable animation.")
      if not re.search(r"transition\s*:\s*none\b", style, re.IGNORECASE):
          inspector.unsafe.append("Reduced-motion CSS must disable transitions.")
      if inspector.unsafe:
          raise StoryValidationError(" ".join(dict.fromkeys(inspector.unsafe)))

      linked_ids: list[str | None] = []
      for card in inspector.stat_cards:
          source_id = card["source_id"]
          linked_ids.append(source_id)
          if set(card["citation_ids"]) != {source_id}:
              raise StoryValidationError(
                  "Every stat card must contain a citation to its own data-source-id."
              )

      if any(mark["svg_index"] is None for mark in inspector.marks):
          raise StoryValidationError("Every .data-mark must be inside an SVG chart.")

      for svg in chart_svgs:
          if svg["figure_index"] is None:
              raise StoryValidationError("Every SVG chart must be inside a <figure>.")
          if svg["viewbox"] is None:
              raise StoryValidationError("Every SVG chart needs a valid numeric viewBox.")
          if not svg["accessible"] or svg["accessible_titles"] < 1:
              raise StoryValidationError("Every SVG chart needs role=img and an accessible title.")
          if svg["gridlines"] < 1:
              raise StoryValidationError("Every SVG chart needs at least one .gridline.")
          if svg["axis_labels"] < 2:
              raise StoryValidationError("Every SVG chart needs at least two .axis-label elements.")
          chart_ids = set()
          for mark_index in svg["mark_indices"]:
              mark = inspector.marks[mark_index]
              linked_ids.append(mark["source_id"])
              chart_ids.add(mark["source_id"])
              if not mark["has_title"]:
                  raise StoryValidationError("Every chart data mark needs a nested <title> tooltip.")
              if not mark["focusable"]:
                  raise StoryValidationError("Every chart data mark needs tabindex=0 for keyboard access.")
              if mark["transformed"] or mark["invalid_geometry"] or not mark["bounds"]:
                  raise StoryValidationError(
                      "Every chart data mark needs untransformed numeric circle, ellipse, rect, or line geometry."
                  )
              view_x, view_y, view_width, view_height = svg["viewbox"]
              epsilon = 1e-6
              for left, top, right, bottom in mark["bounds"]:
                  if (
                      left < view_x - epsilon
                      or top < view_y - epsilon
                      or right > view_x + view_width + epsilon
                      or bottom > view_y + view_height + epsilon
                  ):
                      raise StoryValidationError(
                          "A chart data mark falls outside its SVG viewBox; rescale the axis and geometry."
                      )
          figure = inspector.figures[svg["figure_index"]]
          if not chart_ids.issubset(set(figure["citation_ids"])):
              raise StoryValidationError(
                  "Each figure must cite every source ID used by its chart marks."
              )

      if any(source_id is None or not re.fullmatch(r"\d+", source_id) for source_id in linked_ids):
          raise StoryValidationError("Every stat card and data mark needs a numeric data-source-id.")
      citation_ids = inspector.citation_ids
      if len(set(citation_ids)) < MIN_CITED_SOURCES:
          raise StoryValidationError(f"Expected citations to at least {MIN_CITED_SOURCES} sources.")

      sources = authoritative_sources(search_sources)
      used_ids = list(dict.fromkeys(citation_ids))
      missing = sorted(set(used_ids) - set(sources))
      if missing:
          raise StoryValidationError(f"Citations reference unknown search result IDs: {missing}")

      renumbered_html, new_ids = renumber_sources(raw_html, used_ids)
      renumbered_sources = {new: sources[old] for old, new in zip(used_ids, new_ids)}

      placeholder_index = renumbered_html.index(SOURCE_PLACEHOLDER)
      rendered = source_section(
          new_ids,
          renumbered_sources,
          include_heading=not has_sources_heading(renumbered_html, placeholder_index),
      )
      finalized = renumbered_html.replace(SOURCE_PLACEHOLDER, rendered)
  ```
</Accordion>

### 10. Parse arguments and run the CLI

Argument parsing, cost formatting, and `main`, which wires it all together: parse, resolve the profile, submit or resume, poll, validate, finalize, write the receipt, and print the summary. This section also handles `--dry-run`, which prints the request and exits without an API key.

<Accordion title="Show the code (240 lines)">
  ```python data_story.py (part 10 of 10) theme={null}
      return insert_source_style(insert_csp(finalized))


  def run_cost(response: Any) -> float | None:
      cost = get_value(get_value(response, "usage"), "cost")
      total = get_value(cost, "total_cost")
      return float(total) if total is not None else None


  def format_cost(cost: float | None) -> str:
      return "unavailable" if cost is None else f"${cost:.4f}"


  def count_sources(document: str) -> int:
      return len(
          set(
              re.findall(
                  r'''<a\b[^>]*\bhref\s*=\s*["'](https?://[^"']+)["']''',
                  document,
                  re.IGNORECASE,
              )
          )
      )


  def resume_command(response_id: str, output_path: Path, receipt_path: Path) -> str:
      return (
          f"python data_story.py --resume {shlex.quote(response_id)} "
          f"--output {shlex.quote(str(output_path))} "
          f"--receipt {shlex.quote(str(receipt_path))}"
      )


  def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
      parser = argparse.ArgumentParser(description="Build a grounded interactive data story with Kimi K3.")
      parser.add_argument("topic", nargs="?", help="What the data story should cover")
      parser.add_argument("--resume", metavar="RESPONSE_ID", help="Resume a durable background run")
      parser.add_argument("--profile", choices=sorted(PROFILES), default="quick")
      parser.add_argument("--effort", choices=EFFORT_LEVELS, help="Override the profile effort")
      parser.add_argument("--max-output-tokens", type=int, help="Override the output-token ceiling")
      parser.add_argument("--max-steps", type=int, help="Override research-loop steps (1-100)")
      parser.add_argument("--wait-timeout", type=float, default=DEFAULT_WAIT_TIMEOUT_SECONDS,
                          help="Seconds to wait locally before exiting resumably (default: 3600)")
      parser.add_argument("--output", help="Output HTML path")
      parser.add_argument("--receipt", help="Run receipt JSON path")
      parser.add_argument("--dry-run", action="store_true", help="Print the request without calling the API")
      args = parser.parse_args(argv)
      if bool(args.topic) == bool(args.resume):
          parser.error("provide exactly one of topic or --resume RESPONSE_ID")
      if args.resume and not re.fullmatch(r"resp_[A-Za-z0-9_-]+", args.resume):
          parser.error("--resume must be a valid resp_... ID")
      if args.resume and args.dry_run:
          parser.error("--dry-run cannot be combined with --resume")
      if args.wait_timeout <= 0:
          parser.error("--wait-timeout must be greater than zero")
      try:
          args.config = resolve_config(
              args.profile, args.effort, args.max_output_tokens, args.max_steps
          )
      except ValueError as error:
          parser.error(str(error))
      return args


  def main(
      argv: list[str] | None = None,
      client_factory: Callable[..., Perplexity] = Perplexity,
  ) -> int:
      args = parse_args(argv)
      timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M")
      output_path = Path(args.output or f"data-story-{timestamp}.html")
      receipt_path = Path(args.receipt or f"{output_path}.receipt.json")
      if output_path.resolve() == receipt_path.resolve():
          print("--output and --receipt must be different files.", file=sys.stderr)
          return 2

      request = None
      if args.topic:
          request = build_request(args.topic, **args.config)
          if args.dry_run:
              print(json.dumps(wire_request_preview(request), indent=2))
              return 0

      if not os.environ.get("PERPLEXITY_API_KEY"):
          print("Set PERPLEXITY_API_KEY in your environment.", file=sys.stderr)
          return 2

      receipt: dict[str, Any]
      if args.resume and receipt_path.exists():
          try:
              loaded = json.loads(receipt_path.read_text(encoding="utf-8"))
          except (OSError, json.JSONDecodeError) as error:
              print(f"Cannot resume with unreadable receipt {receipt_path}: {error}", file=sys.stderr)
              return 2
          if not isinstance(loaded, dict):
              print(f"Cannot resume: {receipt_path} is not a JSON object.", file=sys.stderr)
              return 2
          stored_id = loaded.get("response_id")
          if stored_id and stored_id != args.resume:
              print(
                  f"Cannot resume {args.resume}: receipt belongs to {stored_id}.",
                  file=sys.stderr,
              )
              return 2
          receipt = loaded
          receipt["response_id"] = args.resume
          receipt["output_path"] = str(output_path)
          receipt.setdefault("queries", [])
          receipt.setdefault("sources", [])
      else:
          receipt = {
              "created_at": utc_now(),
              "status": "starting",
              "topic": args.topic,
              "profile": args.profile if args.topic else None,
              "config": args.config if args.topic else None,
              "output_path": str(output_path),
              "request": wire_request_preview(request) if request else None,
              "response_id": args.resume,
              "queries": [],
              "sources": [],
          }

      started = time.monotonic()
      attempt = begin_client_attempt(receipt, "resume" if args.resume else "submit")
      if args.resume:
          receipt["status"] = "resuming"
          receipt.setdefault("resume_history", []).append(attempt["started_at"])
      write_receipt(receipt_path, receipt)
      client = client_factory()
      try:
          if args.resume:
              print(f"\nResuming durable run {args.resume}\n", file=sys.stderr)
              response = poll_response(
                  client, args.resume, receipt, receipt_path, args.wait_timeout
              )
          else:
              print(
                  f"\nBuilding a data story: {args.topic} "
                  f"({args.profile}, K3 effort: {args.config['effort']})\n",
                  file=sys.stderr,
              )
              assert request is not None
              response = run_background(
                  client, request, receipt, receipt_path, args.wait_timeout
              )

          if get_value(response, "status") == "completed":
              receipt.setdefault("provider_completed_at", utc_now())
              if not args.resume:
                  receipt["background_elapsed_seconds"] = round(time.monotonic() - started, 3)
          checkpoint_response(response, receipt, receipt_path)
          actual_model = get_value(response, "model")
          if actual_model != MODEL:
              raise StoryValidationError(
                  f"Expected completed model {MODEL}, received {actual_model or 'unknown'}."
              )
          queries, sources = response_research(response)
          record_research(receipt, receipt_path, queries, sources)
          check_output_budget(response, args.config.get("max_output_tokens"))
          summary, raw_html = extract_html(final_text(response))
          finalized_html = finalize_html(raw_html, sources)
          atomic_write_text(output_path, finalized_html)

          cost = run_cost(response)
          receipt["artifact"] = {
              "path": str(output_path),
              "bytes": len(finalized_html.encode("utf-8")),
              "linked_sources": count_sources(finalized_html),
          }
          receipt["provider_cost"] = cost
          receipt["provider_cost_display"] = format_cost(cost)
          receipt["status"] = "completed"
          finish_client_attempt(
              receipt, attempt, "completed", time.monotonic() - started
          )
          write_receipt(receipt_path, receipt)

          print(f"\n{summary}\n", file=sys.stderr)
          print(
              f"Saved: {output_path}  ({len(finalized_html)/1024:.0f} KB, "
              f"{count_sources(finalized_html)} verified source links)  "
              f"cost {format_cost(cost)}",
              file=sys.stderr,
          )
          print(f"Receipt: {receipt_path}", file=sys.stderr)
          return 0
      except KeyboardInterrupt:
          receipt["client_wait_status"] = "interrupted"
          response_id = receipt.get("response_id")
          receipt["status"] = "interrupted" if response_id else "submission_unknown"
          finish_client_attempt(
              receipt, attempt, receipt["status"], time.monotonic() - started,
              KeyboardInterrupt("Interrupted locally"),
          )
          write_receipt(receipt_path, receipt)
          if response_id:
              print(
                  f"\nInterrupted locally. Resume without a new paid run:\n"
                  f"  {resume_command(response_id, output_path, receipt_path)}",
                  file=sys.stderr,
              )
          else:
              print("\nInterrupted before a response ID was received; do not blindly retry.", file=sys.stderr)
          return 130
      except RunError as error:
          if isinstance(error, StoryValidationError):
              receipt["status"] = "validation_failed"
          elif isinstance(error, TerminalRunError):
              receipt["status"] = "provider_failed"
          elif isinstance(error, PendingRunError):
              receipt["status"] = "waiting"
          elif not isinstance(error, SubmissionUnknownError):
              receipt["status"] = "failed"
          finish_client_attempt(
              receipt, attempt, receipt["status"], time.monotonic() - started, error
          )
          write_receipt(receipt_path, receipt)
          print(f"Error: {error}", file=sys.stderr)
          if isinstance(error, PendingRunError):
              print(
                  "Resume without a new paid run:\n"
                  f"  {resume_command(error.response_id, output_path, receipt_path)}",
                  file=sys.stderr,
              )
          return 1
      except (APIError, httpx.HTTPError) as error:
          receipt["status"] = "api_error"
          finish_client_attempt(
              receipt, attempt, receipt["status"], time.monotonic() - started, error
          )
          write_receipt(receipt_path, receipt)
          print(f"API request failed: {error}", file=sys.stderr)
          return 1
      finally:
          client.close()


  if __name__ == "__main__":
      raise SystemExit(main())
  ```
</Accordion>

## Offline verification

These checks make no network requests and spend no credits:

```bash theme={null}
python -m py_compile data_story.py
python data_story.py --help
python data_story.py "The rise of open-weights AI models" --dry-run
```

## Limitations

* **It's a draft.** Structural citation checks can't tell whether a sentence misreads or overstates its source.
* **Chart geometry can be in-bounds and still wrong.** Marks are checked against the `viewBox`, not against the axis they imply. Verify the scale.
* **Check mobile label sizes.** A chart can avoid overflow and still be unreadable at 390px.
* **Sparse search coverage fails closed.** If results are thin or contradictory, validation fails and nothing is written.
* **High-effort runs take minutes.** Use `--resume` with the response ID rather than resubmitting.
* **A dense topic can still exhaust the budget.** Reasoning and the page share one ceiling. The run fails after you have paid for it, so raise `--max-output-tokens` rather than retrying the same budget.
* **One page, one file.** Multi-page output needs a different approach.
* **Receipts exclude the API key** but may include topic and source snippets. Review before sharing.

## Resources

* [Agent API Quickstart](/docs/agent-api/quickstart)
* [Background Mode](/docs/agent-api/background-mode)
* [Create a Response](/api-reference/agent-post)
* [Retrieve a Response](/api-reference/agent-get)
* [Agent API Prompt Guide](/docs/agent-api/prompt-guide)
* [Python SDK Configuration](/docs/sdk/configuration)
* [Models and reasoning effort](/docs/agent-api/models)
* [Kimi K3 Model Card](https://huggingface.co/moonshotai/Kimi-K3)


# Perplexity Discord Bot
Source: https://docs.perplexity.ai/docs/cookbook/examples/discord-py-bot/README

A simple discord.py bot that integrates Perplexity's Sonar API to bring AI answers to your Discord server.

<SonarDeprecationNotice />

A simple `discord.py` bot that integrates [Perplexity's Sonar API](https://docs.perplexity.ai/) into your Discord server. Ask questions and get AI-powered answers with web access through slash commands or by mentioning the bot.

<img alt="Discord Bot Demo" />

## ✨ Features

* **🌐 Web-Connected AI**: Uses Perplexity's Sonar API for up-to-date information
* **⚡ Slash Command**: Simple `/ask` command for questions
* **💬 Mention Support**: Ask questions by mentioning the bot
* **🔗 Source Citations**: Automatically formats and links to sources
* **🔒 Secure Setup**: Environment-based configuration for API keys

## 🛠️ Prerequisites

<Steps>
  <Step title="Python Environment">
    **Python 3.8+** installed on your system

    ```bash theme={null}
    python --version  # Should be 3.8 or higher
    ```
  </Step>

  <Step title="Perplexity API Access">
    **Active Perplexity API Key** from the [Perplexity API Platform console](https://console.perplexity.ai)

    <Note>You'll need a paid Perplexity account to access the API. See the [pricing page](https://www.perplexity.ai/pricing) for current rates.</Note>
  </Step>

  <Step title="Discord Bot Application">
    **Discord Bot Token** from the [Discord Developer Portal](https://discord.com/developers/applications)
  </Step>
</Steps>

## 🚀 Quick Start

### 1. Repository Setup

Clone the repository and navigate to the bot directory:

```bash theme={null}
git clone https://github.com/ppl-ai/api-cookbook.git
cd api-cookbook/docs/examples/discord-py-bot/
```

### 2. Install Dependencies

```bash theme={null}
# Create a virtual environment (recommended)
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install required packages
pip install -r requirements.txt
```

### 3. Configure API Keys

<Steps>
  <Step title="Get Your Perplexity API Key">
    1. Visit the [Perplexity API Platform console](https://console.perplexity.ai)
    2. Generate a new API key
    3. Copy the key to the .env file

    <Warning>Keep your API key secure! Never commit it to version control or share it publicly.</Warning>
  </Step>

  <Step title="Create Discord Bot Application">
    1. Go to the [Discord Developer Portal](https://discord.com/developers/applications)
    2. Click **"New Application"** and give it a descriptive name
    3. Navigate to the **"Bot"** section
    4. Click **"Reset Token"** (or "Add Bot" if first time)
    5. Copy the bot token
  </Step>

  <Step title="Configure Environment Variables">
    Copy the example environment file and add your keys:

    ```bash theme={null}
    cp env.example .env
    ```

    Edit `.env` with your credentials:

    ```bash title=".env" theme={null}
    DISCORD_TOKEN="your_discord_bot_token_here"
    PERPLEXITY_API_KEY="your_perplexity_api_key_here"
    ```
  </Step>
</Steps>

## 🎯 Usage Guide

### Bot Invitation & Setup

<Steps>
  <Step title="Generate Invite URL">
    In the Discord Developer Portal:

    1. Go to **OAuth2** → **URL Generator**
    2. Select scopes: `bot` and `applications.commands`
    3. Select bot permissions: `Send Messages`, `Use Slash Commands`
    4. Copy the generated URL
  </Step>

  <Step title="Invite to Server">
    1. Paste the URL in your browser
    2. Select the Discord server to add the bot to
    3. Confirm the permissions
  </Step>

  <Step title="Start the Bot">
    ```bash theme={null}
    python bot.py
    ```

    You should see output confirming the bot is online and commands are synced.
  </Step>
</Steps>

### How to Use

**Slash Command:**

```
/ask [your question here]
```

<img alt="Slash Command Demo" />

**Mention the Bot:**

```
@YourBot [your question here]
```

<img alt="Mention Command Demo" />

## 📊 Response Format

The bot provides clean, readable responses with:

* **AI Answer**: Direct response from Perplexity's Sonar API
* **Source Citations**: Clickable links to sources (when available)
* **Automatic Truncation**: Responses are trimmed to fit Discord's limits

## 🔧 Technical Details

This bot uses:

* **Model**: Perplexity's `sonar-pro` model
* **Response Limit**: 2000 tokens from API, truncated to fit Discord
* **Temperature**: 0.2 for consistent, factual responses
* **No Permissions**: Anyone in the server can use the bot


# Disease Information App
Source: https://docs.perplexity.ai/docs/cookbook/examples/disease-qa/README

An interactive browser-based application that provides structured information about diseases using Perplexity's Sonar API

<SonarDeprecationNotice />

# Disease Information App

An interactive browser-based application that provides structured information about diseases using Perplexity's Sonar API. This app generates a standalone HTML interface that allows users to ask questions about various diseases and receive organized responses with citations.

## 🌟 Features

* **User-Friendly Interface**: Clean, responsive design that works across devices
* **AI-Powered Responses**: Leverages Perplexity's Sonar API for accurate medical information
* **Structured Knowledge Cards**: Organizes information into Overview, Causes, and Treatments
* **Citation Tracking**: Lists sources of information with clickable links
* **Client-Side Caching**: Prevents duplicate API calls for previously asked questions
* **Standalone Deployment**: Generate a single HTML file that can be used without a server
* **Comprehensive Error Handling**: User-friendly error messages and robust error management

## 📋 Requirements

* Python 3.6+
* Jupyter Notebook or JupyterLab (for development/generation)
* Required packages:
  * requests
  * pandas
  * python-dotenv
  * IPython

## 🚀 Setup & Installation

1. Clone this repository or download the notebook
2. Install the required packages:

```bash theme={null}
# Install from requirements file (recommended)
pip install -r requirements.txt

# Or install manually
pip install requests pandas python-dotenv ipython
```

3. Set up your Perplexity API key:
   * Create a `.env` file in the same directory as the notebook
   * Add your API key: `PERPLEXITY_API_KEY=your_api_key_here`

## 🔧 Usage

### Running the Notebook

1. Open the notebook in Jupyter:

```bash theme={null}
jupyter notebook Disease_Information_App.ipynb
```

2. Run all cells to generate and launch the browser-based application
3. The app will automatically open in your default web browser

### Using the Generated HTML

You can also directly use the generated `disease_qa.html` file:

1. Open it in any modern web browser
2. Enter a question about a disease (e.g., "What is diabetes?", "Tell me about Alzheimer's disease")
3. Click "Ask" to get structured information about the disease

### Deploying the App

For personal or educational use, simply share the generated HTML file.

For production use, consider:

1. Setting up a proper backend to secure your API key
2. Hosting the file on a web server
3. Adding analytics and user management as needed

## 🔍 How It Works

This application:

1. Uses a carefully crafted prompt to instruct the AI to output structured JSON
2. Processes this JSON to extract Overview, Causes, Treatments, and Citations
3. Presents the information in a clean knowledge card format
4. Implements client-side API calls with proper error handling
5. Provides a responsive design suitable for both desktop and mobile

## ⚙️ Technical Details

### API Structure

The app expects the AI to return a JSON object with this structure:

```json theme={null}
{
  "overview": "A brief description of the disease.",
  "causes": "The causes of the disease.",
  "treatments": "Possible treatments for the disease.",
  "citations": ["https://example.com/citation1", "https://example.com/citation2"]
}
```

### Files Generated

* `disease_qa.html` - The standalone application
* `disease_app.log` - Detailed application logs (when running the notebook)

### Customization Options

You can modify:

* The HTML/CSS styling in the `create_html_ui` function
* The AI model used (default is "sonar-pro")
* The structure of the prompt for different information fields
* Output file location and naming

## 🛠️ Extending the App

Potential extensions:

* Add a Flask/Django backend to secure the API key
* Implement user accounts and saved questions
* Add visualization of disease statistics
* Create a comparison view for multiple diseases
* Add natural language question reformatting
* Implement feedback mechanisms for answer quality

## ⚠️ Important Notes

* **API Key Security**: The current implementation embeds your API key in the HTML file. This is suitable for personal use but not for public deployment.
* **Not Medical Advice**: This app provides general information and should not be used for medical decisions. Always consult healthcare professionals for medical advice.
* **API Usage**: Be aware of Perplexity API rate limits and pricing for your account.

## 📜 License

[MIT License](https://github.com/ppl-ai/api-cookbook/blob/main/LICENSE)

## 🙏 Acknowledgements

* This project uses the [Perplexity AI Sonar API](https://docs.perplexity.ai/)
* Inspired by interactive knowledge bases and medical information platforms


# Document Q&A with Embeddings
Source: https://docs.perplexity.ai/docs/cookbook/examples/document-qa/README

A self-contained RAG system that ingests documents, generates contextualized embeddings, and answers questions using the Agent API

# Document Q\&A with Embeddings

A self-contained retrieval-augmented generation (RAG) system that ingests documents, generates contextualized embeddings for semantic search, and produces grounded answers using the Agent API.

## Features

* Ingest plain-text documents and automatically split them into chunks
* Generate document-aware embeddings using `pplx-embed-context-v1-4b`
* In-memory vector store with numpy cosine similarity search
* Answer generation via the Agent API with `anthropic/claude-sonnet-4-6`
* Full working pipeline: load, chunk, embed, query, answer

## Architecture

**Indexing:** Load documents, split into overlapping chunks, embed with contextualized embeddings, store in memory.

**Query:** Embed the user question, compute cosine similarity, retrieve top-k chunks, generate an answer with the Agent API.

<Info>
  Contextualized embeddings produce higher-quality representations than standard embeddings for document chunks because the model understands that chunks belong to the same document.
</Info>

## Installation

```bash theme={null}
pip install perplexityai numpy
```

```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```

## Usage

Save the full code below to `document_qa.py` and run:

```bash theme={null}
python document_qa.py
```

For interactive mode:

```bash theme={null}
python document_qa.py --interactive
```

## Full Code

```python theme={null}
import base64
import sys
import numpy as np
from perplexity import Perplexity

client = Perplexity()

# --- Chunking ---

def chunk_text(text, chunk_size=300, overlap=50):
    """Split text into overlapping chunks by word count."""
    words = text.split()
    chunks, start = [], 0
    while start < len(words):
        chunks.append(" ".join(words[start : start + chunk_size]))
        start += chunk_size - overlap
    return chunks

# --- Embedding helpers ---

def decode_embedding(b64_string):
    """Decode a base64-encoded int8 embedding to float32."""
    return np.frombuffer(base64.b64decode(b64_string), dtype=np.int8).astype(np.float32)

def cosine_similarity(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

# --- Build index ---

def build_index(documents, chunk_size=300, overlap=50):
    """Chunk documents and generate contextualized embeddings."""
    all_doc_chunks, metadata = [], []
    for doc in documents:
        chunks = chunk_text(doc["content"], chunk_size, overlap)
        all_doc_chunks.append(chunks)
        metadata.append({"title": doc["title"], "chunks": chunks})

    print(f"Embedding {sum(len(c) for c in all_doc_chunks)} chunks...")
    response = client.contextualized_embeddings.create(
        input=all_doc_chunks,
        model="pplx-embed-context-v1-4b"
    )

    index = []
    for doc_obj in response.data:
        meta = metadata[doc_obj.index]
        for chunk_obj in doc_obj.data:
            index.append({
                "text": meta["chunks"][chunk_obj.index],
                "embedding": decode_embedding(chunk_obj.embedding),
                "doc_title": meta["title"],
            })
    print(f"Index built: {len(index)} chunks.")
    return index

# --- Retrieve ---

def retrieve(index, query_text, top_k=3):
    """Embed the query and return the top-k most similar chunks."""
    qr = client.contextualized_embeddings.create(
        input=[[query_text]], model="pplx-embed-context-v1-4b"
    )
    q_emb = decode_embedding(qr.data[0].data[0].embedding)
    scored = sorted(
        [{**item, "score": float(cosine_similarity(q_emb, item["embedding"]))} for item in index],
        key=lambda x: x["score"], reverse=True,
    )
    return scored[:top_k]

# --- Generate answer ---

def generate_answer(query_text, chunks):
    """Send retrieved context to the Agent API for answer generation."""
    context = "\n\n".join(
        f"[Source {i}: {c['doc_title']}]\n{c['text']}" for i, c in enumerate(chunks, 1)
    )
    response = client.responses.create(
        model="anthropic/claude-sonnet-4-6",
        input=[{
            "role": "user",
            "content": (
                f"Answer the following question based ONLY on the provided context. "
                f"If the context does not contain enough information, say so.\n\n"
                f"Context:\n{context}\n\nQuestion: {query_text}"
            ),
        }],
        instructions=(
            "You are a precise document Q&A assistant. Answer using only the "
            "provided context. Cite source numbers. Be concise."
        ),
        max_output_tokens=1024,
    )
    return response.output_text

# --- Full pipeline ---

def query(index, query_text, top_k=3):
    print(f"\nQuery: {query_text}")
    retrieved = retrieve(index, query_text, top_k)
    for r in retrieved:
        print(f"  [{r['doc_title']}] score={r['score']:.4f}: {r['text'][:70]}...")
    return generate_answer(query_text, retrieved)

# --- Sample documents ---

sample_documents = [
    {
        "title": "Introduction to Transformers",
        "content": (
            "The Transformer architecture was introduced in the paper Attention Is All "
            "You Need by Vaswani et al. in 2017. It replaced recurrent layers with "
            "self-attention mechanisms, enabling parallel processing of input sequences. "
            "The key innovation is multi-head attention, which allows the model to attend "
            "to information from different representation subspaces. Transformers consist "
            "of an encoder and decoder with stacked layers of multi-head attention and "
            "feed-forward sub-layers. The architecture has become the foundation for "
            "modern language models including BERT, GPT, and T5."
        ),
    },
    {
        "title": "Retrieval-Augmented Generation",
        "content": (
            "Retrieval-Augmented Generation (RAG) combines information retrieval with "
            "text generation. Instead of relying solely on knowledge stored in model "
            "parameters, RAG systems retrieve relevant documents from an external "
            "knowledge base and use them as context. This reduces hallucination because "
            "the model grounds its responses in retrieved evidence. A typical RAG "
            "pipeline has three stages: indexing, retrieval, and generation. During "
            "indexing, documents are chunked and embedded into a vector store. At query "
            "time, the question is embedded and compared against stored vectors. The "
            "most relevant chunks are prepended to the prompt for answer generation."
        ),
    },
]

if __name__ == "__main__":
    index = build_index(sample_documents)
    if "--interactive" in sys.argv:
        print("\nInteractive mode. Type 'quit' to exit.\n")
        while True:
            q = input("Question: ").strip()
            if q.lower() in ("quit", "exit", "q"):
                break
            if q:
                print(f"\nAnswer:\n{query(index, q)}\n")
    else:
        answer = query(index, "How does RAG reduce hallucination?")
        print(f"\nAnswer:\n{answer}")
```

## Example Output

```
Embedding 4 chunks across 2 documents...
Index built: 4 chunks.

Query: How does RAG reduce hallucination?
  [Retrieval-Augmented Generation] score=0.8432: Retrieval-Augmented Generation (RAG) combines information retrieval w...
  [Retrieval-Augmented Generation] score=0.7891: most relevant chunks are prepended to the prompt for answer generatio...
  [Introduction to Transformers] score=0.6104: The Transformer architecture was introduced in the paper Attention Is...

Answer:
RAG reduces hallucination by grounding the model's responses in retrieved evidence
rather than relying solely on knowledge stored in model parameters [Source 1]. The
most relevant document chunks are prepended to the prompt, so the language model bases
its answers on concrete textual evidence from the knowledge base [Source 2].
```

<Tip>
  For production workloads, replace the in-memory numpy index with a dedicated vector database such as Pinecone, Weaviate, or Qdrant. The embedding and retrieval logic remains the same.
</Tip>

<Warning>
  Contextualized embeddings require that chunks within each document are sent in their original sequential order. Shuffling chunks will degrade embedding quality.
</Warning>

## Limitations

* The in-memory store is suitable for prototyping but will not scale to large collections. Use a vector database for production.
* Chunk size and overlap may need tuning for your documents. Shorter chunks improve precision; longer chunks preserve context.
* The `pplx-embed-context-v1-4b` model has a 32K token context window per document.
* Answer quality depends on retrieval quality. If the wrong chunks are retrieved, the answer will reflect that.


# Equity Research Brief
Source: https://docs.perplexity.ai/docs/cookbook/examples/equity-research-brief/README

Generate institutional-grade equity research briefs from any public ticker using the Perplexity Agent API and the built-in finance_search tool.

<SonarDeprecationNotice />

# Equity Research Brief

A command-line tool that generates a structured equity research brief for any public ticker using Perplexity's [Agent API](https://docs.perplexity.ai/docs/agent-api/quickstart) and the built-in [`finance_search`](https://docs.perplexity.ai/docs/agent-api/tools/finance-search) tool.

`finance_search` returns structured market data — quotes, financials, earnings transcripts, peer comparisons, analyst estimates — so the model can compose a report grounded in numbers, not just narrative. The tool is purpose-built for agentic investor workflows.

## Features

* One command produces a 6-section brief: snapshot, business overview, financial trajectory, latest earnings, peer context, risks, bottom line
* Uses the Agent API's `finance_search` tool for structured fundamentals, quotes, and earnings-call transcripts
* Three preset configurations matching the official `finance_search` recommendations:
  * `quote` — live price/quote only, fastest and cheapest
  * `single` — single-company historical lookup with web context
  * `research` — full multi-step cross-company brief (default)
* Prints citation-ready Perplexity finance source URLs alongside the brief
* Reports `finance_search` invocation count and total request cost
* `--json` flag emits the raw Agent API response for downstream pipelines

## Prerequisites

* Python 3.9+
* A Perplexity API key with Agent API access. `finance_search` is currently in beta — see the [Finance Search docs](https://docs.perplexity.ai/docs/agent-api/tools/finance-search) for availability.

## Installation

```bash theme={null}
cd docs/examples/equity-research-brief
pip install -r requirements.txt
chmod +x equity_research_brief.py
```

## API Key Setup

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

You can also pass the key via `--api-key`, or place it in a `.pplx_api_key` file in the working directory.

## Quick Start

Generate a full research brief on NVIDIA:

```bash theme={null}
./equity_research_brief.py NVDA
```

## Usage

```bash theme={null}
./equity_research_brief.py TICKER [--config {quote,single,research}] [--json] [--api-key KEY]
```

### Just a live quote (cheapest, \~1 tool call)

```bash theme={null}
./equity_research_brief.py AAPL --config quote
```

### Single-company historical lookup with web context

```bash theme={null}
./equity_research_brief.py MSFT --config single
```

### Full multi-step research brief (default)

```bash theme={null}
./equity_research_brief.py NVDA --config research
```

### Emit raw Agent API JSON

```bash theme={null}
./equity_research_brief.py TSLA --json | jq '.usage.cost'
```

## Configuration Reference

| Config     | Model                       | Tools                                         | Max steps | Best for                              |
| ---------- | --------------------------- | --------------------------------------------- | --------- | ------------------------------------- |
| `quote`    | `perplexity/sonar`          | `finance_search`                              | 1         | Live prices, quotes, fastest path     |
| `single`   | `openai/gpt-5.5`            | `web_search` + `finance_search` + `fetch_url` | 5         | One-company historical fundamentals   |
| `research` | `anthropic/claude-opus-4-7` | `web_search` + `finance_search` + `fetch_url` | 10        | Multi-company comparisons, full brief |

These configurations are taken directly from the [`finance_search` recommended configurations](https://docs.perplexity.ai/docs/agent-api/tools/finance-search).

## Example Output (truncated)

```
## 1. Snapshot

- **Price:** $200.23 (as of 2026-05-01 14:10 UTC)
- **Market cap:** $4.87T
- **P/E (TTM):** 40.86
- **52-week range:** $110.82 – $216.83

## 2. Business overview

NVIDIA designs accelerated computing platforms — GPUs, networking, and full-stack
software — used in AI training and inference, gaming, professional visualization,
and automotive. Data Center is the dominant revenue line.

## 3. Financial trajectory
| FY    | Revenue     | Operating margin | Net income |
| ----- | ----------- | ---------------- | ---------- |
| FY25  | $130.5B     | 62.4%            | $72.9B     |
...

---
finance_search: 4 invocation(s) across categories [earnings_history, financials, profile, quote]

Finance sources:
  - https://www.perplexity.ai/finance/NVDA
  - https://www.perplexity.ai/finance/NVDA/earnings?eventId=409967
  - ...

Cost: 0.2817 USD
```

## Code Walkthrough

The script does three things:

**1. Issue a single Agent API call with `finance_search` enabled.**

```python theme={null}
from perplexity import Perplexity

client = Perplexity()
response = client.responses.create(
    model="anthropic/claude-opus-4-7",
    instructions=SYSTEM_PROMPT,
    input=BRIEF_TEMPLATE.format(ticker="NVDA"),
    tools=[
        {"type": "web_search"},
        {"type": "finance_search"},
        {"type": "fetch_url"},
    ],
    max_output_tokens=4096,
    max_steps=10,
)
```

The model decides which `finance_search` categories to fetch (quote, financials, transcript, etc.) based on the prompt. You don't need to hand-pick fields.

**2. Walk `response.output` to extract both the assistant text and the structured `finance_results` blocks.**

```python theme={null}
for item in response.output:
    if item.type == "finance_results":
        for r in item.results:
            print(r.category, r.tickers, r.sources)
    elif item.type == "message":
        for block in item.content:
            if block.type == "output_text":
                print(block.text)
```

**3. Surface cost and finance source URLs alongside the prose.** The Perplexity finance pages returned in `result.sources` are stable, citation-ready links — useful when the brief is consumed by humans or by a downstream RAG pipeline.

## Prompting Guidance

`finance_search` works best when the prompt asks for a business outcome, not for specific data shapes. The system prompt instructs the model to:

* be quantitative and attribute numbers to the right period (e.g. `FY2025`, `Q3 FY26`)
* never invent numbers — if `finance_search` doesn't return a field, say so explicitly
* format the output in clean Markdown

This pattern is documented in the [finance\_search prompt guidance](https://docs.perplexity.ai/docs/agent-api/tools/finance-search#prompt-guidance).

## Pricing

`finance_search` is billed at **\$5 per 1,000 invocations**, separate from model token usage. Each preset has different cost characteristics:

* `quote`: typically 1 invocation, \~\$0.007 per brief
* `single`: 1–3 invocations + GPT-5.5 tokens
* `research`: 3–6 invocations + Claude Opus tokens

See [Perplexity Pricing](https://docs.perplexity.ai/docs/getting-started/pricing) for current rates.

## Limitations

* `finance_search` is currently in beta and may not be enabled on all API keys
* Results depend on Perplexity's finance data coverage; obscure or non-US tickers may return less structured data
* This is not investment advice. The "Bottom line" section is explicitly framed as analytical opinion, not a recommendation

## Resources

* [Agent API Quickstart](https://docs.perplexity.ai/docs/agent-api/quickstart)
* [Finance Search Tool](https://docs.perplexity.ai/docs/agent-api/tools/finance-search)
* [Web Search Tool](https://docs.perplexity.ai/docs/agent-api/tools/web-search)
* [Perplexity Python SDK](https://pypi.org/project/perplexityai/)


# Fact Checker CLI
Source: https://docs.perplexity.ai/docs/cookbook/examples/fact-checker-cli/README

A command-line tool that identifies false or misleading claims in articles or statements using Perplexity's Sonar API

<SonarDeprecationNotice />

# Fact Checker CLI

A command-line tool that identifies false or misleading claims in articles or statements using Perplexity's Sonar API for web research.

## Features

* Analyze claims or entire articles for factual accuracy
* Identify false, misleading, or unverifiable claims
* Provide explanations and corrections for inaccurate information
* Output results in human-readable format or structured JSON
* Cite reliable sources for fact-checking assessments
* Leverages Perplexity's structured outputs for reliable JSON parsing (for Tier 3+ users)

## Installation

### 1. Install required dependencies

```bash theme={null}
# Install from requirements file (recommended)
pip install -r requirements.txt

# Or install manually
pip install requests pydantic newspaper3k
```

### 2. Make the script executable

```bash theme={null}
chmod +x fact_checker.py
```

## API Key Setup

The tool requires a Perplexity API key to function. You can provide it in one of these ways:

### 1. As a command-line argument

```bash theme={null}
./fact_checker.py --api-key YOUR_API_KEY
```

### 2. As an environment variable

```bash theme={null}
export PPLX_API_KEY=YOUR_API_KEY
```

### 3. In a file

Create a file named `pplx_api_key` or `.pplx_api_key` in the same directory as the script:

```bash theme={null}
echo "YOUR_API_KEY" > .pplx_api_key
chmod 600 .pplx_api_key
```

**Note:** If you're using the structured outputs feature, you'll need a Perplexity API account with Tier 3 or higher access level.

## Quick Start

Run the following command immediately after setup:

```bash theme={null}
./fact_checker.py -t "The Earth is flat and NASA is hiding the truth."
```

This will analyze the claim, research it using Perplexity's Sonar API, and return a detailed fact check with ratings, explanations, and sources.

## Usage

### Check a claim

```bash theme={null}
./fact_checker.py --text "The Earth is flat and NASA is hiding the truth."
```

### Check an article from a file

```bash theme={null}
./fact_checker.py --file article.txt
```

### Check an article from a URL

```bash theme={null}
./fact_checker.py --url https://www.example.com/news/article-to-check
```

### Specify a different model

```bash theme={null}
./fact_checker.py --text "Global temperatures have decreased over the past century." --model "sonar-pro"
```

### Output results as JSON

```bash theme={null}
./fact_checker.py --text "Mars has a breathable atmosphere." --json
```

### Use a custom prompt file

```bash theme={null}
./fact_checker.py --text "The first human heart transplant was performed in the United States." --prompt-file custom_prompt.md
```

### Enable structured outputs (for Tier 3+ users)

Structured output is disabled by default. To enable it, pass the `--structured-output` flag:

```bash theme={null}
./fact_checker.py --text "Vaccines cause autism." --structured-output
```

### Get help

```bash theme={null}
./fact_checker.py --help
```

## Output Format

The tool provides output including:

* **Overall Rating**: MOSTLY\_TRUE, MIXED, or MOSTLY\_FALSE
* **Summary**: A brief overview of the fact-checking findings
* **Claims Analysis**: A list of specific claims with individual ratings:
  * TRUE: Factually accurate and supported by evidence
  * FALSE: Contradicted by evidence
  * MISLEADING: Contains some truth but could lead to incorrect conclusions
  * UNVERIFIABLE: Cannot be conclusively verified with available information
* **Explanations**: Detailed reasoning for each claim
* **Sources**: Citations and URLs used for verification

## Example

Run the following command:

```bash theme={null}
./fact_checker.py -t "The Great Wall of China is visible from the moon."
```

Example output:

```
Fact checking in progress...

🔴 OVERALL RATING: MOSTLY_FALSE

📝 SUMMARY:
The claim that the Great Wall of China is visible from the moon is false. This is a common misconception that has been debunked by NASA astronauts and scientific evidence.

🔍 CLAIMS ANALYSIS:

Claim 1: ❌ FALSE  
  Statement: "The Great Wall of China is visible from the moon."  
  Explanation: The Great Wall of China is not visible from the moon with the naked eye. NASA astronauts have confirmed this, including Neil Armstrong who stated he could not see the Wall from lunar orbit. The Wall is too narrow and is similar in color to its surroundings when viewed from such a distance.  
  Sources:
    - NASA.gov
    - Scientific American
    - National Geographic
```

## Limitations

* The accuracy of fact-checking depends on the quality of information available through the Perplexity Sonar API.
* Like all language models, the underlying AI may have limitations in certain specialized domains.
* The structured outputs feature requires a Tier 3 or higher Perplexity API account.
* The tool does not replace professional fact-checking services for highly sensitive or complex content.


# Document Q&A
Source: https://docs.perplexity.ai/docs/cookbook/examples/file-attachment-qa/README

Load documents and ask questions about them via the Agent API — text extraction, web search enrichment, multi-turn Q&A, and structured output extraction

# Document Q\&A

Load a document and ask questions about it using the Agent API. This example shows how to read document content, combine it with web search for enriched answers, and build a multi-turn Q\&A session over document content.

## Features

* Load documents (text, CSV, JSON, markdown) and pass content to the Agent API
* Ask questions grounded in the document content
* Optionally combine with `web_search` for context enrichment
* Multi-turn conversation to drill into specific sections
* Structured output extraction from document content

<Info>
  Pass document content directly in the `input` parameter of the Agent API. For text-based formats, read the file and include it in the prompt. Combine with `web_search` for context enrichment beyond the document.
</Info>

## Installation

```bash theme={null}
pip install perplexityai
```

```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```

## Usage

Save the full code below to `doc_qa.py` and run:

```bash theme={null}
python doc_qa.py report.txt "What are the key findings in this report?"
```

For interactive mode:

```bash theme={null}
python doc_qa.py report.txt --interactive
```

## Full Code

<CodeGroup>
  ```python Python theme={null}
  import sys
  import json
  import argparse
  from pathlib import Path
  from perplexity import Perplexity

  client = Perplexity()

  MAX_CONTENT_CHARS = 50000  # Truncate very large files to stay within token limits


  def read_document(file_path: str) -> str:
      """Read a document file and return its text content."""
      path = Path(file_path)
      content = path.read_text(errors="replace")
      if len(content) > MAX_CONTENT_CHARS:
          content = content[:MAX_CONTENT_CHARS] + "\n\n[... truncated ...]"
      return content


  def ask_about_document(
      file_path: str,
      question: str,
      use_web_search: bool = False,
      conversation_history: list = None,
  ) -> dict:
      """Ask a question about a document's content."""
      doc_content = read_document(file_path)
      filename = Path(file_path).name

      # Build the input with document content and question
      full_input = (
          f"Document: {filename}\n"
          f"{'='*60}\n"
          f"{doc_content}\n"
          f"{'='*60}\n\n"
          f"Question: {question}"
      )

      # Include conversation history for multi-turn
      if conversation_history:
          messages = conversation_history + [{"role": "user", "content": full_input}]
          response = client.responses.create(
              model="openai/gpt-5.4",
              input=messages,
              tools=[{"type": "web_search"}] if use_web_search else [],
              instructions="Answer questions based on the provided document content. Be specific and cite sections when possible.",
          )
      else:
          response = client.responses.create(
              model="openai/gpt-5.4",
              input=full_input,
              tools=[{"type": "web_search"}] if use_web_search else [],
              instructions="Answer questions based on the provided document content. Be specific and cite sections when possible.",
          )

      usage = response.usage
      return {
          "answer": response.output_text,
          "model": response.model,
          "tokens": {
              "input": usage.input_tokens if usage else 0,
              "output": usage.output_tokens if usage else 0,
          },
      }


  def extract_structured_data(file_path: str, schema_name: str, schema: dict) -> dict:
      """Extract structured data from a document using a JSON schema."""
      doc_content = read_document(file_path)

      response = client.responses.create(
          model="openai/gpt-5.4",
          input=f"Extract the requested structured data from this document:\n\n{doc_content}",
          response_format={
              "type": "json_schema",
              "json_schema": {"name": schema_name, "schema": schema},
          },
      )

      return json.loads(response.output_text)


  def interactive_session(file_path: str, use_web_search: bool = False):
      """Run an interactive Q&A session over a document."""
      print(f"Document loaded: {file_path}")
      print(f"Web search: {'enabled' if use_web_search else 'disabled'}")
      print("Type 'quit' to exit.\n")

      history = []

      while True:
          question = input("Question: ").strip()
          if question.lower() in ("quit", "exit", "q"):
              break
          if not question:
              continue

          result = ask_about_document(file_path, question, use_web_search, history)
          print(f"\nAnswer:\n{result['answer']}\n")
          print(f"({result['tokens']['input']}+{result['tokens']['output']} tokens)\n")

          # Add to conversation history for multi-turn
          history.append({"role": "user", "content": question})
          history.append({"role": "assistant", "content": result["answer"]})


  def main():
      parser = argparse.ArgumentParser(description="Document Q&A")
      parser.add_argument("file", help="Path to the document file")
      parser.add_argument("question", nargs="?", help="Question to ask")
      parser.add_argument("--interactive", action="store_true", help="Interactive mode")
      parser.add_argument("--web-search", action="store_true", help="Enable web search")
      args = parser.parse_args()

      if not Path(args.file).exists():
          print(f"Error: File not found: {args.file}", file=sys.stderr)
          sys.exit(1)

      if args.interactive:
          interactive_session(args.file, args.web_search)
      elif args.question:
          result = ask_about_document(args.file, args.question, args.web_search)
          print(result["answer"])
      else:
          print("Error: Provide a question or use --interactive.", file=sys.stderr)
          sys.exit(1)


  if __name__ == "__main__":
      main()
  ```
</CodeGroup>

## Example Output

```bash theme={null}
python doc_qa.py quarterly_report.txt "What was the total revenue for Q3?"
```

```
Based on the quarterly report, total revenue for Q3 was $4.2 billion,
representing a 15% year-over-year increase. The report attributes this
growth primarily to the cloud services division, which grew 28% compared
to the same period last year (see Section 3, Financial Highlights).
```

With web search enrichment:

```bash theme={null}
python doc_qa.py quarterly_report.txt "How does this compare to industry benchmarks?" --web-search
```

```
According to the report, Q3 revenue was $4.2 billion (from document).
For comparison, the industry average revenue growth for cloud-focused
companies in Q3 2025 was approximately 12% year-over-year (from web
search: Bloomberg industry analysis). This places the company above
the industry benchmark by roughly 3 percentage points.
```

## Structured Data Extraction from Documents

Extract specific fields from a document into a typed JSON structure:

```python theme={null}
# Extract key metrics from a financial report
schema = {
    "type": "object",
    "properties": {
        "company_name": {"type": "string"},
        "quarter": {"type": "string"},
        "total_revenue": {"type": "string"},
        "net_income": {"type": "string"},
        "revenue_growth_yoy": {"type": "string"},
        "key_highlights": {"type": "array", "items": {"type": "string"}},
    },
    "required": ["company_name", "quarter", "total_revenue", "net_income", "revenue_growth_yoy", "key_highlights"],
    "additionalProperties": false,
}

data = extract_structured_data("quarterly_report.txt", "financial_summary", schema)
print(json.dumps(data, indent=2))
```

<Tip>
  Combine document content with structured outputs to build reliable document processing pipelines. The JSON schema ensures consistent output regardless of document format variations.
</Tip>

<Warning>
  Very large documents are truncated to stay within token limits. For large files, consider splitting into sections and processing each separately.
</Warning>

## Limitations

* Very large documents are truncated. The default limit is 50,000 characters (\~12,500 tokens).
* Text-based formats (.txt, .csv, .md, .json) work best. For PDFs, use a library like `pdfplumber` or `PyPDF2` to extract text first.
* Conversation history for multi-turn sessions does not re-read the file — the document content is included in the first message.


# Financial News Tracker
Source: https://docs.perplexity.ai/docs/cookbook/examples/financial-news-tracker/README

A real-time financial news monitoring tool that fetches and analyzes market news using Perplexity's Sonar API

<SonarDeprecationNotice />

# Financial News Tracker

A command-line tool that fetches and analyzes real-time financial news using Perplexity's Sonar API. Get comprehensive market insights, news summaries, and investment analysis for any financial topic.

## Features

* Real-time financial news aggregation from multiple sources
* Market sentiment analysis (Bullish/Bearish/Neutral)
* Impact assessment for news items (High/Medium/Low)
* Sector and company-specific analysis
* Investment insights and recommendations
* Customizable time ranges (24h to 1 year)
* Structured JSON output support
* Beautiful emoji-enhanced CLI output

## Installation

### 1. Install required dependencies

```bash theme={null}
# Install from requirements file (recommended)
pip install -r requirements.txt

# Or install manually
pip install requests pydantic
```

### 2. Make the script executable

```bash theme={null}
chmod +x financial_news_tracker.py
```

## API Key Setup

The tool requires a Perplexity API key. You can provide it in one of these ways:

### 1. As an environment variable (recommended)

```bash theme={null}
export PPLX_API_KEY=YOUR_API_KEY
```

### 2. As a command-line argument

```bash theme={null}
./financial_news_tracker.py "tech stocks" --api-key YOUR_API_KEY
```

### 3. In a file

Create a file named `pplx_api_key` or `.pplx_api_key` in the same directory:

```bash theme={null}
echo "YOUR_API_KEY" > .pplx_api_key
chmod 600 .pplx_api_key
```

## Quick Start

Get the latest tech stock news:

```bash theme={null}
./financial_news_tracker.py "tech stocks"
```

This will fetch recent financial news about tech stocks, analyze market sentiment, and provide actionable insights.

## Usage Examples

### Basic usage - Get news for a specific topic

```bash theme={null}
./financial_news_tracker.py "S&P 500"
```

### Get cryptocurrency news from the past week

```bash theme={null}
./financial_news_tracker.py "cryptocurrency" --time-range 1w
```

### Track specific company news

```bash theme={null}
./financial_news_tracker.py "AAPL Apple stock"
```

### Get news about market sectors

```bash theme={null}
./financial_news_tracker.py "energy sector oil prices"
```

### Output as JSON for programmatic use

```bash theme={null}
./financial_news_tracker.py "inflation rates" --json
```

### Use a different model

```bash theme={null}
./financial_news_tracker.py "Federal Reserve interest rates" --model sonar
```

### Enable structured output (requires Tier 3+ API access)

```bash theme={null}
./financial_news_tracker.py "tech earnings" --structured-output
```

## Time Range Options

* `24h` - Last 24 hours (default)
* `1w` - Last week
* `1m` - Last month
* `3m` - Last 3 months
* `1y` - Last year

## Output Format

The tool provides comprehensive financial analysis including:

### 1. Executive Summary

A brief overview of the key financial developments

### 2. Market Analysis

* **Market Sentiment**: Overall market mood (🐂 Bullish, 🐻 Bearish, ⚖️ Neutral)
* **Key Drivers**: Factors influencing the market
* **Risks**: Current market risks and concerns
* **Opportunities**: Potential investment opportunities

### 3. News Items

Each news item includes:

* **Headline**: The main news title
* **Impact**: Market impact level (🔴 High, 🟡 Medium, 🟢 Low)
* **Summary**: Brief description of the news
* **Affected Sectors**: Industries or companies impacted
* **Source**: News source attribution

### 4. Investment Insights

Actionable recommendations and analysis based on the news

## Example Output

```
📊 FINANCIAL NEWS REPORT: tech stocks
📅 Period: Last 24 hours

📝 EXECUTIVE SUMMARY:
Tech stocks showed mixed performance today as AI-related companies surged while 
semiconductor stocks faced pressure from supply chain concerns...

📈 MARKET ANALYSIS:
  Sentiment: 🐂 BULLISH

  Key Drivers:
    • Strong Q4 earnings from major tech companies
    • AI sector momentum continues
    • Federal Reserve signals potential rate cuts

  ⚠️ Risks:
    • Semiconductor supply chain disruptions
    • Regulatory scrutiny on big tech
    • Valuation concerns in AI sector

  💡 Opportunities:
    • Cloud computing growth
    • AI infrastructure plays
    • Cybersecurity demand surge

📰 KEY NEWS ITEMS:

1. Microsoft Hits All-Time High on AI Growth
   Impact: 🔴 HIGH
   Summary: Microsoft stock reached record levels following strong Azure AI revenue...
   Sectors: Cloud Computing, AI, Software
   Source: Bloomberg

💼 INSIGHTS & RECOMMENDATIONS:
  • Consider diversifying within tech sector
  • AI infrastructure companies show strong momentum
  • Monitor semiconductor sector for buying opportunities
```

## Advanced Features

### Custom Queries

You can combine multiple topics for comprehensive analysis:

```bash theme={null}
# Get news about multiple related topics
./financial_news_tracker.py "NVIDIA AMD semiconductor AI chips"

# Track geopolitical impacts on markets
./financial_news_tracker.py "oil prices Middle East geopolitics"

# Monitor economic indicators
./financial_news_tracker.py "inflation CPI unemployment Federal Reserve"
```

### JSON Output

For integration with other tools or scripts:

```bash theme={null}
./financial_news_tracker.py "bitcoin" --json | jq '.market_analysis.market_sentiment'
```

## Tips for Best Results

1. **Be Specific**: Include company tickers, sector names, or specific events
2. **Combine Topics**: Mix company names with relevant themes (e.g., "TSLA electric vehicles")
3. **Use Time Ranges**: Match the time range to your investment horizon
4. **Regular Monitoring**: Set up cron jobs for daily market updates

## Limitations

* Results depend on available public information
* Not financial advice - always do your own research
* Historical data may be limited for very recent events
* Structured output requires Tier 3+ Perplexity API access

## Error Handling

The tool includes comprehensive error handling for:

* Invalid API keys
* Network connectivity issues
* API rate limits
* Invalid queries
* Parsing errors

## Integration Examples

### Daily Market Report

Create a script for daily updates:

```bash theme={null}
#!/bin/bash
# daily_market_report.sh

echo "=== Daily Market Report ===" > market_report.txt
echo "Date: $(date)" >> market_report.txt
echo "" >> market_report.txt

./financial_news_tracker.py "S&P 500 market overview" >> market_report.txt
./financial_news_tracker.py "top gaining stocks" >> market_report.txt
./financial_news_tracker.py "cryptocurrency bitcoin ethereum" >> market_report.txt
```

### Python Integration

```python theme={null}
import subprocess
import json

def get_financial_news(query, time_range="24h"):
    result = subprocess.run(
        ["./financial_news_tracker.py", query, "--time-range", time_range, "--json"],
        capture_output=True,
        text=True
    )
    
    if result.returncode == 0:
        return json.loads(result.stdout)
    else:
        raise Exception(f"Error fetching news: {result.stderr}")

# Example usage
news = get_financial_news("tech stocks", "1w")
print(f"Market sentiment: {news['market_analysis']['market_sentiment']}")
```


# Image Analysis
Source: https://docs.perplexity.ai/docs/cookbook/examples/image-analysis/README

Vision-powered image analysis with web search for context-enriched results using the Perplexity Agent API

# Image Analysis

Analyze images using vision models through the Perplexity Agent API, then enrich the analysis with web search to provide real-world context. This example combines image understanding with live information retrieval in a two-step pipeline: identify what is in the image, then research the identified subjects.

## Features

* Upload images via base64 encoding or public HTTPS URL
* Analyze images with vision-capable models like `openai/gpt-5.4` through the Agent API
* Combine image analysis with web search for context enrichment
* Two-step pipeline: identify, then research
* Support for PNG, JPEG, WEBP, and GIF formats

## Installation

<CodeGroup>
  ```bash Python theme={null}
  pip install perplexityai
  ```

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

```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```

## Usage

<CodeGroup>
  ```bash Python theme={null}
  python image_analysis.py path/to/photo.jpg
  python image_analysis.py https://example.com/photo.jpg
  ```

  ```bash TypeScript theme={null}
  npx tsx image_analysis.ts path/to/photo.jpg
  npx tsx image_analysis.ts https://example.com/photo.jpg
  ```
</CodeGroup>

## Full Code

<CodeGroup>
  ```python Python theme={null}
  import sys
  import base64
  from perplexity import Perplexity

  client = Perplexity()


  def encode_image(image_path):
      """Read a local image and return a base64 data URI."""
      with open(image_path, "rb") as f:
          encoded = base64.b64encode(f.read()).decode("utf-8")
      ext = image_path.rsplit(".", 1)[-1].lower()
      mime = {"png": "image/png", "jpg": "image/jpeg", "jpeg": "image/jpeg",
              "webp": "image/webp", "gif": "image/gif"}.get(ext, "image/png")
      return f"data:{mime};base64,{encoded}"


  def identify_image(image_source):
      """Step 1: Identify objects and subjects in an image."""
      image_url = image_source if image_source.startswith("http") else encode_image(image_source)

      response = client.responses.create(
          model="openai/gpt-5.4",
          input=[{
              "role": "user",
              "content": [
                  {
                      "type": "input_text",
                      "text": (
                          "Analyze this image in detail. Identify all notable objects, "
                          "people, landmarks, species, or text. For each, provide a "
                          "concise label and brief description. Format as a numbered list."
                      ),
                  },
                  {"type": "input_image", "image_url": image_url},
              ],
          }],
          max_output_tokens=1024,
      )
      return response.output_text


  def research_subjects(identification_text):
      """Step 2: Research identified subjects with web search."""
      response = client.responses.create(
          model="openai/gpt-5.4",
          input=(
              f"The following subjects were identified in an image:\n\n"
              f"{identification_text}\n\n"
              f"Research each subject. For each, provide:\n"
              f"- What it is and why it is notable\n"
              f"- Key facts or recent news\n"
              f"- Historical or cultural significance if applicable\n\n"
              f"Combine the analysis into a comprehensive report."
          ),
          tools=[{"type": "web_search"}],
          instructions="You are an image research assistant. Provide accurate, up-to-date information. Synthesize image observations with research.",
      )
      return response.output_text


  def analyze(image_source):
      """Full pipeline: identify then research."""
      print(f"Analyzing: {image_source}\n")
      print("Step 1: Identifying subjects...")
      identification = identify_image(image_source)
      print(f"\n{identification}\n")
      print("Step 2: Researching subjects...")
      report = research_subjects(identification)
      print(f"\n{report}")


  if __name__ == "__main__":
      if len(sys.argv) < 2:
          print("Usage: python image_analysis.py <image_path_or_url>")
          sys.exit(1)
      analyze(sys.argv[1])
  ```

  ```typescript TypeScript theme={null}
  import Perplexity from "@perplexity-ai/perplexity_ai";
  import * as fs from "fs";
  import * as path from "path";

  const client = new Perplexity();

  function encodeImage(imagePath: string): string {
    const encoded = fs.readFileSync(imagePath).toString("base64");
    const ext = path.extname(imagePath).slice(1).toLowerCase();
    const mime: Record<string, string> = {
      png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg",
      webp: "image/webp", gif: "image/gif",
    };
    return `data:${mime[ext] || "image/png"};base64,${encoded}`;
  }

  async function identifyImage(imageSource: string): Promise<string> {
    const imageUrl = imageSource.startsWith("http")
      ? imageSource
      : encodeImage(imageSource);

    const response = await client.responses.create({
      model: "openai/gpt-5.4",
      input: [{
        role: "user",
        content: [
          {
            type: "input_text",
            text: "Analyze this image in detail. Identify all notable objects, "
              + "people, landmarks, species, or text. For each, provide a "
              + "concise label and brief description. Format as a numbered list.",
          },
          { type: "input_image", image_url: imageUrl },
        ],
      }],
      max_output_tokens: 1024,
    });
    return response.output_text;
  }

  async function researchSubjects(identificationText: string): Promise<string> {
    const response = await client.responses.create({
      model: "openai/gpt-5.4",
      input:
        `The following subjects were identified in an image:\n\n`
        + `${identificationText}\n\n`
        + `Research each subject. For each, provide:\n`
        + `- What it is and why it is notable\n`
        + `- Key facts or recent news\n`
        + `- Historical or cultural significance if applicable\n\n`
        + `Combine the analysis into a comprehensive report.`,
      tools: [{ type: "web_search" }],
      instructions: "You are an image research assistant. Provide accurate, up-to-date information. Synthesize image observations with research.",
    });
    return response.output_text;
  }

  async function analyze(imageSource: string): Promise<void> {
    console.log(`Analyzing: ${imageSource}\n`);
    console.log("Step 1: Identifying subjects...");
    const identification = await identifyImage(imageSource);
    console.log(`\n${identification}\n`);
    console.log("Step 2: Researching subjects...");
    const report = await researchSubjects(identification);
    console.log(`\n${report}`);
  }

  const arg = process.argv[2];
  if (!arg) { console.log("Usage: npx tsx image_analysis.ts <image_path_or_url>"); process.exit(1); }
  analyze(arg);
  ```
</CodeGroup>

## Example Output

```
Analyzing: golden_gate.jpg

Step 1: Identifying subjects...

1. Golden Gate Bridge - Iconic red-orange suspension bridge spanning
   the Golden Gate strait in San Francisco, California.
2. San Francisco Bay - Body of water beneath the bridge, connecting
   to the Pacific Ocean.
3. Marin Headlands - Hilly terrain on the far side, part of the
   Golden Gate National Recreation Area.
4. Fog bank - Low-lying cloud formation rolling in from the Pacific.

Step 2: Researching subjects...

## Golden Gate Bridge - Comprehensive Analysis

### The Bridge
The Golden Gate Bridge is a suspension bridge spanning the one-mile-wide
strait connecting San Francisco Bay to the Pacific Ocean. Completed in
1937, it held the record for the longest suspension bridge span at 4,200
feet until 1964. Its "International Orange" color was chosen for fog
visibility and aesthetic harmony.

### San Francisco Bay
San Francisco Bay is a shallow estuary encompassing approximately 1,600
square miles of watershed, one of the largest natural harbors on the
Pacific coast.

### Marin Headlands
Part of the Golden Gate National Recreation Area, offering hiking trails
with panoramic views of the bridge and city skyline.

### Fog Patterns
Summer fog through the Golden Gate is a defining feature of San
Francisco's microclimate, formed when warm inland air draws cool Pacific
air through the strait.
```

<Warning>
  Base64-encoded images count toward input token usage. A 1024x768 image consumes approximately 1,048 tokens. The maximum file size for base64 images is 50 MB.
</Warning>

<Info>
  Vision input is supported on the Agent API via the `input_image` content type. Use a vision-capable model like `openai/gpt-5.4`. Check the [Agent API Image Attachments docs](/docs/agent-api/image-attachments) for supported formats and size limits.
</Info>

## Limitations

* Image analysis requires a vision-capable model (e.g., `openai/gpt-5.4`). Not all models support `input_image`.
* Web search quality in Step 2 depends on identification accuracy in Step 1.
* Only publicly accessible HTTPS URLs work for URL-based input. Private URLs will fail.
* Animated GIFs are supported but only the first frame is analyzed.


# Multi-Provider Model Comparison
Source: https://docs.perplexity.ai/docs/cookbook/examples/model-comparison/README

A CLI tool that sends the same prompt to multiple AI models via Perplexity's Agent API and compares response quality, latency, and cost

<SonarDeprecationNotice />

# Multi-Provider Model Comparison

A command-line tool that sends the same prompt to multiple AI models through Perplexity's Agent API and produces a side-by-side comparison of response quality, latency, and cost. Useful for evaluating which model best fits your use case.

## Features

* Send identical prompts to 5 models across different providers in a single run
* Measure response latency using wall-clock timing
* Extract per-request cost from the `response.usage.cost.total_cost` field
* Tabulated output comparing response length, latency, and cost
* Model fallback chain support using the `models=[...]` parameter for high-availability workflows
* Configurable prompt input via command-line argument or file

## Supported Models

The default comparison set spans five providers:

| Model                          | Provider   |
| ------------------------------ | ---------- |
| `openai/gpt-5.4`               | OpenAI     |
| `anthropic/claude-sonnet-4-6`  | Anthropic  |
| `google/gemini-3.1-flash-lite` | Google     |
| `xai/grok-4.20-non-reasoning`  | xAI        |
| `perplexity/sonar`             | Perplexity |

## Installation

```bash theme={null}
pip install perplexityai
```

## API Key Setup

Set your Perplexity API key as an environment variable. The SDK reads it automatically:

```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```

<Info>
  Perplexity's Agent API provides access to models from multiple providers through a single API key. You do not need separate API keys for OpenAI, Anthropic, Google, or xAI.
</Info>

## Usage

### Compare models with a prompt

```bash theme={null}
python model_comparison.py "Explain the CAP theorem in distributed systems"
```

### Read the prompt from a file

```bash theme={null}
python model_comparison.py --file prompt.txt
```

### Use a custom set of models

```bash theme={null}
python model_comparison.py "What is quantum entanglement?" \
  --models openai/gpt-5.4 anthropic/claude-sonnet-4-6 perplexity/sonar
```

### Export results as JSON

```bash theme={null}
python model_comparison.py "Summarize recent AI safety research" --json > results.json
```

### Use model fallback chain

Instead of comparing models, you can test the fallback chain feature. The API tries each model in order until one succeeds:

```bash theme={null}
python model_comparison.py "Latest AI news" --fallback
```

## How It Works

1. The CLI accepts a prompt and an optional list of models.
2. For each model, the tool records a start timestamp, calls `client.responses.create(model=..., input=...)`, and records the end timestamp.
3. From each response, it extracts `response.usage.cost.total_cost` for the request cost and computes latency as the elapsed wall-clock time.
4. Results are collected and displayed in a comparison table sorted by latency.
5. In fallback mode, the tool sends a single request with `models=[...]` and reports which model was ultimately used.

<Tip>
  The `response.usage.cost` object includes `input_cost`, `output_cost`, and `total_cost` in USD. This makes it straightforward to compare the true cost of each model for your specific prompt.
</Tip>

## Full Code

<CodeGroup>
  ```python Python theme={null}
  import sys
  import json
  import time
  import argparse
  from typing import List, Optional
  from perplexity import Perplexity

  DEFAULT_MODELS = [
      "openai/gpt-5.4",
      "anthropic/claude-sonnet-4-6",
      "google/gemini-3.1-flash-lite",
      "xai/grok-4.20-non-reasoning",
      "perplexity/sonar",
  ]


  def compare_models(prompt: str, models: List[str]) -> List[dict]:
      """Send the same prompt to each model and collect metrics."""
      client = Perplexity()
      results = []

      for model in models:
          print(f"  Querying {model}...")
          try:
              start = time.time()
              response = client.responses.create(
                  model=model,
                  input=prompt,
                  max_output_tokens=1024,
              )
              elapsed = time.time() - start

              output_text = response.output_text
              total_cost = response.usage.cost.total_cost
              input_tokens = response.usage.input_tokens
              output_tokens = response.usage.output_tokens

              results.append({
                  "model": model,
                  "status": "success",
                  "latency_s": round(elapsed, 2),
                  "response_length": len(output_text),
                  "input_tokens": input_tokens,
                  "output_tokens": output_tokens,
                  "cost_usd": total_cost,
                  "preview": output_text[:120].replace("\n", " "),
              })
          except Exception as e:
              results.append({
                  "model": model,
                  "status": "error",
                  "error": str(e),
                  "latency_s": None,
                  "response_length": 0,
                  "input_tokens": 0,
                  "output_tokens": 0,
                  "cost_usd": None,
                  "preview": "",
              })

      return results


  def run_fallback(prompt: str, models: List[str]) -> dict:
      """Send a single request with a model fallback chain."""
      client = Perplexity()

      print(f"  Sending request with fallback chain: {models}")
      start = time.time()
      response = client.responses.create(
          models=models,
          input=prompt,
          max_output_tokens=1024,
      )
      elapsed = time.time() - start

      return {
          "requested_models": models,
          "model_used": response.model,
          "latency_s": round(elapsed, 2),
          "response_length": len(response.output_text),
          "cost_usd": response.usage.cost.total_cost,
          "preview": response.output_text[:200].replace("\n", " "),
      }


  def format_table(results: List[dict]) -> str:
      """Format comparison results as a text table."""
      # Sort by latency (successful responses first)
      successful = [r for r in results if r["status"] == "success"]
      failed = [r for r in results if r["status"] != "success"]
      successful.sort(key=lambda r: r["latency_s"])

      lines = []
      header = f"{'Model':<42} {'Latency':>8} {'Length':>8} {'Tokens':>8} {'Cost':>10}"
      lines.append(header)
      lines.append("-" * len(header))

      for r in successful:
          tokens = f"{r['input_tokens']}+{r['output_tokens']}"
          cost = f"${r['cost_usd']:.5f}"
          lines.append(
              f"{r['model']:<42} {r['latency_s']:>7.2f}s {r['response_length']:>8} {tokens:>8} {cost:>10}"
          )

      for r in failed:
          lines.append(f"{r['model']:<42} {'FAILED':>8} {'-':>8} {'-':>8} {'-':>10}")

      return "\n".join(lines)


  def main():
      parser = argparse.ArgumentParser(
          description="Multi-Provider Model Comparison"
      )
      parser.add_argument("prompt", nargs="?", help="The prompt to send")
      parser.add_argument("--file", help="Read prompt from a file")
      parser.add_argument(
          "--models",
          nargs="+",
          default=DEFAULT_MODELS,
          help="Models to compare",
      )
      parser.add_argument(
          "--fallback",
          action="store_true",
          help="Use model fallback chain instead of comparing",
      )
      parser.add_argument(
          "--json", action="store_true", help="Output results as JSON"
      )
      args = parser.parse_args()

      # Resolve prompt
      if args.file:
          with open(args.file, "r") as f:
              prompt = f.read().strip()
      elif args.prompt:
          prompt = args.prompt
      else:
          print("Error: Provide a prompt or use --file.", file=sys.stderr)
          sys.exit(1)

      print(f"Prompt: {prompt[:80]}{'...' if len(prompt) > 80 else ''}\n")

      if args.fallback:
          print("Running model fallback chain...\n")
          result = run_fallback(prompt, args.models)
          if args.json:
              print(json.dumps(result, indent=2))
          else:
              print(f"Fallback chain: {' -> '.join(result['requested_models'])}")
              print(f"Model used:     {result['model_used']}")
              print(f"Latency:        {result['latency_s']}s")
              print(f"Response length: {result['response_length']} chars")
              print(f"Cost:           ${result['cost_usd']:.5f}")
              print(f"\nPreview: {result['preview']}")
      else:
          print(f"Comparing {len(args.models)} models...\n")
          results = compare_models(prompt, args.models)
          if args.json:
              print(json.dumps(results, indent=2))
          else:
              print(format_table(results))
              print(f"\nComparison complete. {len(results)} models evaluated.")


  if __name__ == "__main__":
      main()
  ```
</CodeGroup>

## Example Output

Running the comparison:

```bash theme={null}
python model_comparison.py "Explain the CAP theorem in distributed systems"
```

Produces output like:

```
Prompt: Explain the CAP theorem in distributed systems

Comparing 5 models...

  Querying openai/gpt-5.4...
  Querying anthropic/claude-sonnet-4-6...
  Querying google/gemini-3.1-flash-lite...
  Querying xai/grok-4.20-non-reasoning...
  Querying perplexity/sonar...

Model                                      Latency   Length   Tokens       Cost
------------------------------------------------------------------------------
xai/grok-4.20-non-reasoning              1.24s     1842    18+312  $0.00048
google/gemini-3.1-flash-lite                      1.87s     2105    18+356  $0.00031
perplexity/sonar                             2.13s     1654    18+280  $0.00034
openai/gpt-5.4                               3.41s     2487    18+421  $0.00438
anthropic/claude-sonnet-4-6                  3.78s     2301    18+389  $0.00527

Comparison complete. 5 models evaluated.
```

Running with the fallback chain:

```bash theme={null}
python model_comparison.py "Latest AI news" --fallback
```

```
Prompt: Latest AI news

Running model fallback chain...

  Sending request with fallback chain: ['openai/gpt-5.4', ...]

Fallback chain: openai/gpt-5.4 -> anthropic/claude-sonnet-4-6 -> google/gemini-3.1-flash-lite -> xai/grok-4.20-non-reasoning -> perplexity/sonar
Model used:     openai/gpt-5.4
Latency:        3.12s
Response length: 2034 chars
Cost:           $0.00415

Preview: The AI landscape continues to evolve rapidly in 2025...
```

<Info>
  Model fallback is useful for production systems where availability matters more than model selection. The API tries each model in the `models` array in order and returns the first successful response. See the [model fallback guide](/docs/agent-api/model-fallback) for details.
</Info>

## Tips for Meaningful Comparisons

1. **Use the same `max_output_tokens`** across all models to keep output lengths comparable.
2. **Run multiple trials** and average the results, since latency can vary between requests due to load.
3. **Test with representative prompts** for your actual use case rather than generic questions.
4. **Consider cost per token** in addition to total cost, especially for high-volume applications.

## Limitations

* Latency measurements reflect end-to-end wall-clock time including network round trips, not pure model inference time.
* Cost values come from the API response and reflect per-request pricing at the time of the call.
* Response quality is subjective and not captured by quantitative metrics alone. Review the actual output text for qualitative evaluation.
* Rate limits vary by model and provider. Sequential comparison requests may be affected by rate limiting on high-demand models.


# Model Picker
Source: https://docs.perplexity.ai/docs/cookbook/examples/model-picker/README

Describe a task and get a grounded shortlist of open models to use. One Agent API request combines the Hugging Face MCP server with web search to find, verify, and recommend a model.

# Model Picker

A command-line example that turns a plain-language task into a shortlist of open models, with one recommendation and the evidence behind it.
You describe what you need - `"on-device English speech-to-text, small enough to run on a laptop"` - and the model returns a table of real Hugging Face repos plus a pick you can defend.

It does this with one Agent API request that combines two tools.
The [`mcp`](/docs/agent-api/tools/mcp) tool connects the model to the [Hugging Face MCP server](https://huggingface.co/settings/mcp), so it can search the live model registry and read each repo's real metadata.
The [`web_search`](/docs/agent-api/tools/web-search) tool lets it check benchmarks, quality, and known issues in the same run.
The Hub says which models exist and how they are adopted and licensed; the web says whether they are any good.
Neither tool alone is enough.

## What MCP does here

* **Gives the model live registry facts.** The `mcp` tool lets it call `hub_repo_search` and `hub_repo_details` to pull the models that exist right now, with their real download counts, licenses, and last-modified dates.
* **No integration code on your side.** Agent API discovers the server's tools when the request starts and calls them like native tools. You point the `mcp` tool at the server URL - there is no Hugging Face SDK to install, no endpoints to wrap, no schema to maintain.
* **Read-only by design.** The example allow-lists the Hub's read tools (`hub_repo_search`, `hub_repo_details`, `paper_search`, `hf_doc_search`, `hf_doc_fetch`) with `allowed_tools`, so the model can look up models but nothing else.

## Without MCP

Ask a plain chat model to pick a model and it answers from training data: it names repos it remembers, guesses at download counts, and cannot tell you what shipped last month or whether a license changed.
The alternative is to do it by hand: query the Hugging Face API for candidates, then fetch, rank, and cross-check each one against the web yourself.
The `mcp` tool and `web_search` do that whole job inside the one request above.

## Installation

Keep `model_picker.py` and `requirements.txt` in the same directory.

1. Install the [Perplexity Python SDK](https://github.com/ppl-ai/perplexity-python), pinned in `requirements.txt`:

```text requirements.txt theme={null}
perplexityai==0.39.0
```

```bash theme={null}
pip install -r requirements.txt
```

2. Set your Perplexity API key:

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

The SDK reads the key from this environment variable.
The Hugging Face MCP server (`https://huggingface.co/mcp`) needs no key - the example connects to it anonymously.

3. (Optional) Raise the Hugging Face rate limit. Anonymous access to the MCP server is rate-limited. For heavier use, create a [Hugging Face token](https://huggingface.co/settings/tokens) (a read token is enough) and export it as `HF_TOKEN`:

```bash theme={null}
export HF_TOKEN="hf_..."
```

When set, the script passes it to the server in the `mcp` tool's `authorization` field. Leave it unset to run anonymously.

<Note>
  This example uses the Agent API `mcp` tool. See the [MCP docs](/docs/agent-api/tools/mcp) for setup and usage details.
</Note>

## Usage

Pass the task as a single argument:

```bash theme={null}
python model_picker.py "on-device English speech-to-text, small enough to run on a laptop"
```

The script prints a Markdown brief: a shortlist table and one recommendation with citations.
Add `--show-tools` to also print the tool calls the model made, in order, so you can see the Hub lookups and the web searches that produced the answer.

## How it works

The whole run is a single `client.responses.create` call given two tools - the Hugging Face `mcp` server and `web_search` - and one instruction: ground every claim in the tools.

That instruction is the point of the example.
Without it, the model treats the tools as optional and skips them.
The system prompt closes that door: it makes the model verify each candidate against the Hub and the web before it recommends anything.

In practice, the run has two phases.
First, the model narrows the field on the Hub, refining its search several times and then reading the repo details of the finalists.
Then it switches to the web to check how good those finalists actually are, and only then writes the shortlist and its pick.

<Accordion title="See the tool calls (--show-tools)">
  In the trace, Hugging Face MCP calls appear as `mcp:<tool>`; the Agent API's web searches appear as `web_search` with the queries it ran.
  On the run below, the model searched the Hub seven times, read the finalists' details once, then ran a round of web search before answering - Hub first, web second.

  ```text theme={null}
  1. mcp:hub_repo_search {"filters":["automatic-speech-recognition"],"query":"English speech to text on device small whisper","sort":"downloads"}
  2. mcp:hub_repo_search {"author":"openai","filters":["automatic-speech-recognition"],"query":"whisper"}
     ... (searches 3-7: distil-whisper, wav2vec2, faster-whisper, facebook/wav2vec2-base-960h, nvidia parakeet) ...
  8. mcp:hub_repo_details {"repo_ids":["openai/whisper-base.en","openai/whisper-small.en","distil-whisper/distil-small.en","distil-whisper/distil-medium.en","facebook/wav2vec2-base-960h"], ...}
  9. web_search openai whisper base.en small.en benchmarks known issues; distil-whisper distil-small.en distil-medium.en benchmarks; facebook wav2vec2-base-960h benchmarks
  ```

  The model writes these queries itself and refines them between calls, so the exact shape varies from run to run.
</Accordion>

## Full code

The script is one file: build the two tools, submit one background request, poll until it finishes, and print the answer (plus an optional tool trace).

<Accordion title="Full code - model_picker.py">
  ```python model_picker.py theme={null}
  #!/usr/bin/env python3
  """Model Picker - turn a plain-language task into a grounded shortlist of open
  models, using one Agent API request that combines the Hugging Face MCP server
  with web search. See the README for details.
  """

  import argparse
  import os
  import sys
  import time
  from typing import Any, List

  from perplexity import Perplexity

  POLL_INTERVAL_SECONDS = 4
  POLL_TIMEOUT_SECONDS = 600
  MAX_STEPS = 20
  MODEL = "openai/gpt-5.5"
  HF_MCP_URL = "https://huggingface.co/mcp"

  # Read-only subset of the server's tools, so the model can look up models but nothing else.
  HF_ALLOWED_TOOLS = [
      "hub_repo_search",
      "hub_repo_details",
      "paper_search",
      "hf_doc_search",
      "hf_doc_fetch",
  ]

  # Force the model to verify against the tools instead of answering from memory.
  INSTRUCTIONS = """You recommend open models from Hugging Face for a user's task.

  Ground every claim in tools - never recommend a model from memory:
  - Find candidates with hub_repo_search. If a search returns weak or empty
    results, refine it (change the query wording, task filter, or sort) and
    search again before giving up.
  - For each finalist, call hub_repo_details to confirm its real task, license,
    download count, and last-modified date. Drop candidates you cannot verify.
  - Use web_search to check each finalist's benchmarks, quality, and any known
    issues or deprecations. Always run at least one web_search before you
    recommend.

  Then answer in Markdown:
  1. A shortlist table with columns: Model | Downloads | License | Hugging Face link.
  2. One recommendation with a short justification tied to the task's
     constraints, citing the Hub links and the web sources you used.
  Prefer models with a clear open license and real adoption over obscure repos."""

  PROMPT_TEMPLATE = """Recommend an open model for this task:

  {task}

  Search Hugging Face for candidates, verify each with its repo details, and
  check the web for benchmarks and known issues before recommending one."""


  def build_tools() -> List[dict]:
      mcp_tool = {
          "type": "mcp",
          "server_label": "huggingface",
          "server_url": HF_MCP_URL,
          "allowed_tools": HF_ALLOWED_TOOLS,
      }
      # Optional: set HF_TOKEN to authenticate and raise the anonymous rate limit.
      token = os.environ.get("HF_TOKEN")
      if token:
          mcp_tool["authorization"] = token
      return [mcp_tool, {"type": "web_search"}]


  def submit_and_wait(client: Perplexity, **create_kwargs: Any) -> Any:
      response = client.responses.create(background=True, **create_kwargs)
      print(f"Submitted response {response.id}; working...", file=sys.stderr)
      deadline = time.time() + POLL_TIMEOUT_SECONDS
      while response.status in ("queued", "in_progress"):
          if time.time() > deadline:
              raise TimeoutError("Timed out waiting for the response to finish.")
          time.sleep(POLL_INTERVAL_SECONDS)
          response = client.responses.retrieve(response.id)
      if response.status != "completed":
          raise RuntimeError(f"Request ended with status {response.status!r}.")
      return response


  def final_text(response: Any) -> str:
      # Built by hand: response.output_text raises when a message block has no text.
      chunks: List[str] = []
      for item in response.output or []:
          if getattr(item, "type", None) != "message":
              continue
          for block in getattr(item, "content", None) or []:
              if getattr(block, "type", None) == "output_text" and block.text:
                  chunks.append(block.text)
      return "\n\n".join(chunks)


  def print_tool_trace(response: Any) -> None:
      # MCP calls arrive as mcp_call items; web searches as search_results items.
      print("--- tool trace ---", file=sys.stderr)
      n = 0
      for item in response.output or []:
          kind = getattr(item, "type", None)
          if kind == "mcp_call":
              n += 1
              print(f"\n{n}. mcp:{item.name} {(item.arguments or '').strip()[:200]}", file=sys.stderr)
          elif kind == "search_results":
              n += 1
              queries = getattr(item, "queries", None) or []
              print(f"\n{n}. web_search {'; '.join(queries)}", file=sys.stderr)


  def main() -> int:
      parser = argparse.ArgumentParser(description="Recommend an open model for a task.")
      parser.add_argument(
          "task",
          help='The task in plain language, e.g. "on-device English speech-to-text".',
      )
      parser.add_argument(
          "--show-tools",
          action="store_true",
          help="Print the tool calls the model made, in order.",
      )
      args = parser.parse_args()

      if not os.environ.get("PERPLEXITY_API_KEY"):
          print("Set PERPLEXITY_API_KEY in your environment.", file=sys.stderr)
          return 1

      client = Perplexity()
      print(f"Finding open models for: {args.task}", file=sys.stderr)
      try:
          response = submit_and_wait(
              client,
              model=MODEL,
              instructions=INSTRUCTIONS,
              input=PROMPT_TEMPLATE.format(task=args.task),
              tools=build_tools(),
              max_steps=MAX_STEPS,
          )
      except Exception as err:
          print(f"Error: {err}", file=sys.stderr)
          return 2

      if args.show_tools:
          print_tool_trace(response)
      print(final_text(response) or "(no answer returned)")
      return 0


  if __name__ == "__main__":
      sys.exit(main())
  ```
</Accordion>

## Example Output

A real run - `python model_picker.py "on-device English speech-to-text, small enough to run on a laptop"` (results vary with the live Hub and web):

```markdown theme={null}
## Shortlist

| Model | Downloads | License | Hugging Face link |
|---|---:|---|---|
| distil-whisper/distil-small.en | 895.7K | MIT | https://hf.co/distil-whisper/distil-small.en |
| openai/whisper-small.en | 3.7M | Apache-2.0 | https://hf.co/openai/whisper-small.en |
| openai/whisper-base.en | 20.7M | Apache-2.0 | https://hf.co/openai/whisper-base.en |
| distil-whisper/distil-medium.en | 6.5M | MIT | https://hf.co/distil-whisper/distil-medium.en |
| facebook/wav2vec2-base-960h | 113.6M | Apache-2.0 | https://hf.co/facebook/wav2vec2-base-960h |

## Recommendation: distil-whisper/distil-small.en

For on-device English speech-to-text on a laptop, I'd pick distil-whisper/distil-small.en.
It is verified on the Hub as automatic-speech-recognition, English-only, 166.1M params, MIT
licensed, and the smallest Distil-Whisper checkpoint - aimed at memory-constrained,
on-device use, with roughly 6x faster inference while staying close to Whisper quality.
It is smaller than openai/whisper-small.en (166M vs 242M), and a better accuracy/speed
tradeoff than whisper-base.en if you can spare the memory. Known caveat: run distilled
models through Hugging Face Transformers rather than the openai/whisper package, and expect
accuracy to vary with audio quality and accent.
```

Every model in the table is one the request actually looked up on the Hub, with download counts and licenses from the repos' real metadata.

## Limitations

* **Live variance.** The shortlist depends on the live Hub and current web results, so the exact models and the recommendation can differ between runs.
* **Anonymous rate limits.** The example connects to the Hugging Face MCP server anonymously, which is rate-limited. For heavier use, set `HF_TOKEN` (see [Installation](#installation)) to authenticate and raise the limit.
* **Third-party servers.** Remote MCP servers are third-party services - connect only servers you trust. See [Risks and safety](/docs/agent-api/tools/mcp#risks-and-safety).

## Resources

* [MCP Tool](/docs/agent-api/tools/mcp)
* [Web Search Tool](/docs/agent-api/tools/web-search)
* [Hugging Face MCP server](https://huggingface.co/settings/mcp)
* [Agent API Quickstart](/docs/agent-api/quickstart)
* [Pricing](/docs/getting-started/pricing)
* [Perplexity Python SDK](https://github.com/ppl-ai/perplexity-python)


# Academic Research Finder CLI
Source: https://docs.perplexity.ai/docs/cookbook/examples/research-finder/README

A command-line tool that uses Perplexity's Sonar API to find and summarize academic literature

<SonarDeprecationNotice />

# Academic Research Finder CLI

A command-line tool that uses Perplexity's Sonar API to find and summarize academic literature (research papers, articles, etc.) related to a given question or topic.

## Features

* Takes a natural language question or topic as input, ideally suited for academic inquiry.
* Leverages Perplexity Sonar API, guided by a specialized prompt to prioritize scholarly sources (e.g., journals, conference proceedings, academic databases).
* Outputs a concise summary based on the findings from academic literature.
* Lists the primary academic sources used, aiming to include details like authors, year, title, publication, and DOI/link when possible.
* Supports different Perplexity models (defaults to `sonar-pro`).
* Allows results to be output in JSON format.

## Installation

### 1. Install required dependencies

Ensure you are using the Python environment you intend to run the script with (e.g., `python3.10` if that's your target).

```bash theme={null}
# Install from requirements file (recommended)
pip install -r requirements.txt

# Or install manually
pip install requests
```

### 2. Make the script executable (Optional)

```bash theme={null}
chmod +x research_finder.py
```

Alternatively, you can run the script using `python3 research_finder.py ...`.

## API Key Setup

The tool requires a Perplexity API key (`PPLX_API_KEY`) to function. You can provide it in one of these ways (checked in this order):

1. **As a command-line argument:**
   ```bash theme={null}
   python3 research_finder.py "Your query" --api-key YOUR_API_KEY
   ```
2. **As an environment variable:**
   ```bash theme={null}
   export PPLX_API_KEY=YOUR_API_KEY
   python3 research_finder.py "Your query"
   ```
3. **In a file:** Create a file named `pplx_api_key`, `.pplx_api_key`, `PPLX_API_KEY`, or `.PPLX_API_KEY` in the *same directory as the script* or in the *current working directory* containing just your API key.
   ```bash theme={null}
   echo "YOUR_API_KEY" > .pplx_api_key
   chmod 600 .pplx_api_key # Optional: restrict permissions
   python3 research_finder.py "Your query"
   ```

## Usage

Run the script from the `sonar-use-cases/research_finder` directory or provide the full path.

```bash theme={null}
# Basic usage
python3 research_finder.py "What are the latest advancements in quantum computing?"

# Using a specific model
python3 research_finder.py "Explain the concept of Large Language Models" --model sonar-small-online

# Getting output as JSON
python3 research_finder.py "Summarize the plot of Dune Part Two" --json

# Using a custom system prompt file
python3 research_finder.py "Benefits of renewable energy" --prompt-file /path/to/your/custom_prompt.md

# Using an API key via argument
python3 research_finder.py "Who won the last FIFA World Cup?" --api-key sk-...

# Using the executable (if chmod +x was used)
./research_finder.py "Latest news about Mars exploration"
```

### Arguments

* `query`: (Required) The research question or topic (enclose in quotes if it contains spaces).
* `-m`, `--model`: Specify the Perplexity model (default: `sonar-pro`).
* `-k`, `--api-key`: Provide the API key directly.
* `-p`, `--prompt-file`: Path to a custom system prompt file.
* `-j`, `--json`: Output the results in JSON format.

## Example Output (Human-Readable - *Note: Actual output depends heavily on the query and API results*)

```
Initializing research assistant for query: "Recent studies on transformer models in NLP"...
Researching in progress...

✅ Research Complete!

📝 SUMMARY:
Recent studies on transformer models in Natural Language Processing (NLP) continue to explore architectural improvements, efficiency optimizations, and new applications. Key areas include modifications to the attention mechanism (e.g., sparse attention, linear attention) to handle longer sequences more efficiently, techniques for model compression and knowledge distillation, and applications beyond text, such as in computer vision and multimodal tasks. Research also focuses on understanding the internal workings and limitations of large transformer models.

🔗 SOURCES:
  1. Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., ... & Polosukhin, I. (2017). Attention is all you need. Advances in neural information processing systems, 30. (arXiv:1706.03762)
  2. Tay, Y., Dehghani, M., Bahri, D., & Metzler, D. (2020). Efficient transformers: A survey. arXiv preprint arXiv:2009.06732.
  3. Beltagy, I., Peters, M. E., & Cohan, A. (2020). Longformer: The long-document transformer. arXiv preprint arXiv:2004.05150.
  4. Rogers, A., Kovaleva, O., & Rumshisky, A. (2020). A primer in bertology: What we know about how bert works. Transactions of the Association for Computational Linguistics, 8, 842-866. (arXiv:2002.12327)
```

## Limitations

* The ability of the Sonar API to consistently prioritize and access specific academic databases or extract detailed citation information (like DOIs) may vary. The quality depends on the API's search capabilities and the structure of the source websites.
* The script performs basic parsing to separate summary and sources; complex or unusual API responses might not be parsed perfectly. Check the raw response in case of issues.
* Queries that are too broad or not well-suited for academic search might yield less relevant results.
* Error handling for API rate limits or specific API errors could be more granular.


# Search News Monitor
Source: https://docs.perplexity.ai/docs/cookbook/examples/search-news-monitor/README

A CLI tool that uses Perplexity's Search API to monitor real-time news across multiple configurable topics with domain and recency filtering

<SonarDeprecationNotice />

# Search News Monitor

A command-line tool that uses Perplexity's Search API (`client.search.create(...)`) to monitor real-time news across multiple topics. Configure topics, domain filters, and recency windows to build a continuous news monitoring pipeline.

## Features

* Monitor multiple topics in a single run using the Search API
* Filter results by domain with `search_domain_filter` (allowlist or denylist)
* Control recency with `search_recency_filter` (day, week, month, year)
* Access structured result fields: `title`, `url`, `snippet`, `date`
* Configurable polling interval for continuous monitoring
* Output as formatted text or JSON for downstream processing

## Installation

<CodeGroup>
  ```bash Python theme={null}
  pip install perplexityai
  ```

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

## API Key Setup

Set your Perplexity API key as an environment variable. The SDK reads it automatically:

```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```

## Usage

```bash theme={null}
# Monitor default topics
python news_monitor.py

# Specify custom topics
python news_monitor.py --topics "artificial intelligence" "climate policy" "space exploration"

# Filter to specific domains (allowlist)
python news_monitor.py --topics "AI regulation" --domains reuters.com apnews.com bbc.co.uk

# Exclude domains (denylist)
python news_monitor.py --topics "technology" --exclude-domains pinterest.com reddit.com

# Set recency filter
python news_monitor.py --topics "semiconductor industry" --recency day

# Run in continuous monitoring mode
python news_monitor.py --topics "cybersecurity" --watch --interval 300

# Export as JSON
python news_monitor.py --topics "renewable energy" --json > news.json
```

## How It Works

1. The CLI accepts a list of topics and optional filtering parameters.
2. For each topic, it calls `client.search.create(query=..., max_results=...)` with the configured domain and recency filters.
3. Each search result contains `title`, `url`, `snippet`, and `date` fields, which are extracted and formatted.
4. In watch mode, the tool repeats the search at a configurable interval, displaying only new results since the last poll.

<Tip>
  Use the `search_recency_filter` parameter with values like `"day"`, `"week"`, `"month"`, or `"year"` to focus on recent news. This is simpler than specifying exact date ranges and works well for monitoring workflows.
</Tip>

<Warning>
  Domain filters operate in either allowlist or denylist mode, not both simultaneously. Use `--domains` for allowlist or `--exclude-domains` for denylist, but not both in the same request. A maximum of 20 domains can be specified.
</Warning>

## Full Code

<CodeGroup>
  ```python Python theme={null}
  import sys
  import json
  import time
  import argparse
  from typing import List, Optional
  from perplexity import Perplexity

  DEFAULT_TOPICS = ["artificial intelligence", "climate change", "cybersecurity"]


  def search_topic(
      client, topic, max_results=5, domains=None, exclude_domains=None, recency=None,
  ):
      """Search for news on a single topic and return structured results."""
      params = {"query": topic, "max_results": max_results}
      if domains:
          params["search_domain_filter"] = domains
      elif exclude_domains:
          params["search_domain_filter"] = [f"-{d}" for d in exclude_domains]
      if recency:
          params["search_recency_filter"] = recency

      search = client.search.create(**params)
      return [
          {
              "title": item.title,
              "url": item.url,
              "snippet": item.snippet[:200] if item.snippet else "",
              "date": item.date if hasattr(item, "date") else None,
          }
          for item in search.results
      ]


  def monitor_once(client, topics, max_results, domains, exclude_domains, recency):
      """Run a single monitoring pass across all topics."""
      return {
          topic: search_topic(client, topic, max_results, domains, exclude_domains, recency)
          for topic in topics
      }


  def format_results(all_results):
      """Format monitoring results as human-readable text."""
      lines = [f"NEWS MONITOR - {time.strftime('%Y-%m-%d %H:%M:%S')}", "=" * 60]
      for topic, results in all_results.items():
          lines.append(f"\n[ {topic.upper()} ] - {len(results)} results")
          lines.append("-" * 40)
          if not results:
              lines.append("  No results found.")
              continue
          for i, r in enumerate(results, 1):
              lines.append(f"  {i}. {r['title']}")
              lines.append(f"     {r['url']}")
              if r["date"]:
                  lines.append(f"     Published: {r['date']}")
              if r["snippet"]:
                  lines.append(f"     {r['snippet']}...")
              lines.append("")
      return "\n".join(lines)


  def main():
      parser = argparse.ArgumentParser(description="Search News Monitor")
      parser.add_argument("--topics", nargs="+", default=DEFAULT_TOPICS)
      parser.add_argument("--max-results", type=int, default=5)
      parser.add_argument("--domains", nargs="+", help="Allowlist domains")
      parser.add_argument("--exclude-domains", nargs="+", help="Denylist domains")
      parser.add_argument("--recency", choices=["day", "week", "month", "year"], default="week")
      parser.add_argument("--watch", action="store_true", help="Continuous monitoring")
      parser.add_argument("--interval", type=int, default=300, help="Poll interval (seconds)")
      parser.add_argument("--json", action="store_true", help="Output as JSON")
      args = parser.parse_args()

      if args.domains and args.exclude_domains:
          print("Error: Use --domains or --exclude-domains, not both.", file=sys.stderr)
          sys.exit(1)

      client = Perplexity()
      print(f"Monitoring {len(args.topics)} topics: {', '.join(args.topics)}")
      print(f"Recency: {args.recency} | Max results per topic: {args.max_results}\n")

      seen_urls = set()
      while True:
          all_results = monitor_once(
              client, args.topics, args.max_results, args.domains, args.exclude_domains, args.recency,
          )
          if args.watch:
              filtered = {}
              for topic, results in all_results.items():
                  new = [r for r in results if r["url"] not in seen_urls]
                  seen_urls.update(r["url"] for r in new)
                  filtered[topic] = new
              all_results = filtered

          print(json.dumps(all_results, indent=2) if args.json else format_results(all_results))

          if not args.watch:
              break
          print(f"\nNext check in {args.interval} seconds... (Ctrl+C to stop)\n")
          time.sleep(args.interval)


  if __name__ == "__main__":
      main()
  ```

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

  const DEFAULT_TOPICS = ["artificial intelligence", "climate change", "cybersecurity"];

  interface SearchResult {
    title: string;
    url: string;
    snippet: string;
    date: string | null;
  }

  async function searchTopic(
    client: InstanceType<typeof Perplexity>,
    topic: string,
    maxResults: number,
    domains?: string[],
    recency?: string
  ): Promise<SearchResult[]> {
    const params: Record<string, unknown> = { query: topic, max_results: maxResults };
    if (domains) params.search_domain_filter = domains;
    if (recency) params.search_recency_filter = recency;

    const search = await client.search.create(params as any);
    return (search as any).results.map((item: any) => ({
      title: item.title,
      url: item.url,
      snippet: item.snippet ? item.snippet.substring(0, 200) : "",
      date: item.date || null,
    }));
  }

  function formatResults(allResults: Record<string, SearchResult[]>): string {
    const lines: string[] = [];
    const ts = new Date().toISOString().replace("T", " ").substring(0, 19);
    lines.push(`NEWS MONITOR - ${ts}`, "=".repeat(60));

    for (const [topic, results] of Object.entries(allResults)) {
      lines.push(`\n[ ${topic.toUpperCase()} ] - ${results.length} results`, "-".repeat(40));
      if (!results.length) { lines.push("  No results found."); continue; }
      results.forEach((r, i) => {
        lines.push(`  ${i + 1}. ${r.title}`, `     ${r.url}`);
        if (r.date) lines.push(`     Published: ${r.date}`);
        if (r.snippet) lines.push(`     ${r.snippet}...`);
        lines.push("");
      });
    }
    return lines.join("\n");
  }

  async function main() {
    const args = process.argv.slice(2);
    const topicsIdx = args.indexOf("--topics");
    let topics = DEFAULT_TOPICS;
    if (topicsIdx !== -1) {
      topics = [];
      for (let i = topicsIdx + 1; i < args.length && !args[i].startsWith("--"); i++)
        topics.push(args[i]);
    }

    const recencyIdx = args.indexOf("--recency");
    const recency = recencyIdx !== -1 ? args[recencyIdx + 1] : "week";
    const maxIdx = args.indexOf("--max-results");
    const maxResults = maxIdx !== -1 ? parseInt(args[maxIdx + 1]) : 5;
    const watch = args.includes("--watch");
    const intervalIdx = args.indexOf("--interval");
    const interval = intervalIdx !== -1 ? parseInt(args[intervalIdx + 1]) : 300;
    const outputJson = args.includes("--json");

    const client = new Perplexity();
    console.log(`Monitoring ${topics.length} topics: ${topics.join(", ")}`);
    console.log(`Recency: ${recency} | Max results per topic: ${maxResults}\n`);

    const seenUrls = new Set<string>();
    while (true) {
      const allResults: Record<string, SearchResult[]> = {};
      for (const topic of topics)
        allResults[topic] = await searchTopic(client, topic, maxResults, undefined, recency);

      let display = allResults;
      if (watch) {
        display = {};
        for (const [topic, results] of Object.entries(allResults)) {
          const fresh = results.filter((r) => !seenUrls.has(r.url));
          fresh.forEach((r) => seenUrls.add(r.url));
          display[topic] = fresh;
        }
      }

      console.log(outputJson ? JSON.stringify(display, null, 2) : formatResults(display));
      if (!watch) break;
      console.log(`\nNext check in ${interval} seconds... (Ctrl+C to stop)\n`);
      await new Promise((r) => setTimeout(r, interval * 1000));
    }
  }

  main();
  ```
</CodeGroup>

## Example Output

```bash theme={null}
python news_monitor.py --topics "artificial intelligence" "climate policy" --recency day
```

```
Monitoring 2 topics: artificial intelligence, climate policy
Recency: day | Max results per topic: 5

NEWS MONITOR - 2026-02-26 14:30:00
============================================================

[ ARTIFICIAL INTELLIGENCE ] - 5 results
----------------------------------------
  1. OpenAI Announces New Enterprise AI Safety Framework
     https://www.reuters.com/technology/openai-enterprise-safety-2026
     Published: 2026-02-26
     OpenAI introduced a comprehensive safety framework for enterprise
     deployments, addressing concerns about autonomous agent behavior...

  2. EU AI Act Enforcement Begins for High-Risk Systems
     https://www.bbc.co.uk/news/technology-ai-act-enforcement
     Published: 2026-02-26
     The European Union has started enforcing new requirements for
     high-risk AI systems under the AI Act...

[ CLIMATE POLICY ] - 3 results
----------------------------------------
  1. G7 Nations Agree on Carbon Border Adjustment Timeline
     https://www.reuters.com/sustainability/g7-carbon-border-2026
     Published: 2026-02-26
     G7 leaders reached consensus on implementing coordinated carbon
     border adjustment mechanisms by 2028...
```

<Info>
  The Search API returns structured results with `title`, `url`, `snippet`, and `date` fields. Unlike the Agent API or Sonar API, it does not generate AI summaries -- it returns raw ranked web results. See the [Search API quickstart](/docs/search/quickstart) for full details.
</Info>

## Continuous Monitoring Tips

1. **Set appropriate intervals.** For breaking news, use 60-120 second intervals. For general topic monitoring, 300-600 seconds is sufficient.
2. **Combine recency with domain filters.** Use `--recency day` with trusted news domains for a curated news feed.
3. **Pipe JSON output to other tools.** Use `--json` with tools like `jq` or downstream scripts for alerting and aggregation.
4. **Track seen URLs.** The watch mode automatically deduplicates results across polling cycles using URL tracking.

## Limitations

* The Search API charges per request. Frequent polling across many topics will increase costs.
* The `search_recency_filter` is relative to the current time and cannot specify exact date ranges. For precise date filtering, use `search_after_date_filter` and `search_before_date_filter` instead.
* Search result availability depends on web indexing. Very recent content (within minutes) may not appear immediately.
* The `snippet` field length varies by result and may be truncated for long pages.


# SEC Filing Search
Source: https://docs.perplexity.ai/docs/cookbook/examples/sec-filing-search/README

Use search domain filtering to query SEC.gov and EDGAR for financial filings, extract key financial data, and build structured financial summaries

# SEC Filing Search

Search SEC.gov and EDGAR for financial filings using domain filtering, extract key financial metrics, and produce structured summaries of public company filings. This example demonstrates practical financial data extraction using the Agent API with targeted domain filters.

## Features

* Search SEC.gov and EDGAR exclusively using `search_domain_filter`
* Extract key metrics from 10-K, 10-Q, and 8-K filings
* Structured JSON output for financial data
* Compare filings across companies or time periods
* Combine SEC data with broader market context via web search

<Info>
  This example uses the Agent API's `web_search` tool with domain filtering to target SEC.gov specifically. The search is grounded in actual SEC filings rather than secondary reporting.
</Info>

## Installation

```bash theme={null}
pip install perplexityai
```

```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```

## Usage

Save the full code below to `sec_search.py` and run:

```bash theme={null}
python sec_search.py "Apple 10-K 2025 revenue and operating income"
```

Compare companies:

```bash theme={null}
python sec_search.py --compare AAPL MSFT GOOGL --metric revenue
```

## Full Code

<CodeGroup>
  ```python Python theme={null}
  import sys
  import json
  import argparse
  from perplexity import Perplexity

  client = Perplexity()

  SEC_DOMAINS = [
      "sec.gov",
      "edgar.sec.gov",
      "efts.sec.gov",
  ]


  def search_sec_filings(query: str) -> dict:
      """Search SEC filings with domain-filtered web search."""
      response = client.responses.create(
          model="openai/gpt-5.4",
          input=query,
          tools=[{
              "type": "web_search",
              "filters": {
                  "search_domain_filter": SEC_DOMAINS,
              },
          }],
          instructions=(
              "You are a financial analyst assistant. Search SEC filings for the requested "
              "information. Cite specific filing types (10-K, 10-Q, 8-K) and dates. "
              "Report exact numbers from the filings, not estimates."
          ),
          max_output_tokens=2048,
      )

      return {
          "query": query,
          "answer": response.output_text,
          "model": response.model,
          "cost": response.usage.cost.total_cost,
      }


  def extract_financial_metrics(company: str, filing_type: str = "10-K") -> dict:
      """Extract structured financial metrics from SEC filings."""
      response = client.responses.create(
          model="openai/gpt-5.4",
          input=f"Find the most recent {filing_type} filing for {company} on SEC EDGAR and extract key financial metrics.",
          tools=[{
              "type": "web_search",
              "filters": {
                  "search_domain_filter": SEC_DOMAINS,
              },
          }],
          instructions=(
              f"Search SEC EDGAR for {company}'s most recent {filing_type} filing. "
              "Extract the exact financial figures reported. Use numbers directly from the filing."
          ),
          response_format={
              "type": "json_schema",
              "json_schema": {
                  "name": "sec_financials",
                  "schema": {
                      "type": "object",
                      "properties": {
                          "company": {"type": "string"},
                          "ticker": {"type": "string"},
                          "filing_type": {"type": "string"},
                          "filing_period": {"type": "string"},
                          "filing_date": {"type": "string"},
                          "total_revenue": {"type": "string"},
                          "net_income": {"type": "string"},
                          "total_assets": {"type": "string"},
                          "total_debt": {"type": "string"},
                          "operating_income": {"type": "string"},
                          "eps_diluted": {"type": "string"},
                          "cash_and_equivalents": {"type": "string"},
                      },
                      "required": [
                          "company", "ticker", "filing_type", "filing_period", "filing_date",
                          "total_revenue", "net_income", "total_assets", "total_debt",
                          "operating_income", "eps_diluted", "cash_and_equivalents",
                      ],
                      "additionalProperties": False,
                  },
              },
          },
      )

      return json.loads(response.output_text)


  def compare_companies(tickers: list[str], metric: str = "revenue") -> list[dict]:
      """Compare a specific financial metric across multiple companies."""
      results = []
      for ticker in tickers:
          print(f"  Searching {ticker}...")
          try:
              data = extract_financial_metrics(ticker)
              results.append(data)
          except Exception as e:
              results.append({"ticker": ticker, "error": str(e)})
      return results


  def search_filing_changes(company: str) -> str:
      """Search for material changes or risk factors in recent filings."""
      response = client.responses.create(
          model="openai/gpt-5.4",
          input=(
              f"What are the key risk factors and material changes disclosed in {company}'s "
              f"most recent 10-K or 10-Q filing on SEC EDGAR?"
          ),
          tools=[{
              "type": "web_search",
              "filters": {
                  "search_domain_filter": SEC_DOMAINS,
              },
          }],
          instructions=(
              "Focus on risk factors (Item 1A) and material changes. "
              "Cite specific sections and filing dates."
          ),
          max_output_tokens=2048,
      )
      return response.output_text


  def main():
      parser = argparse.ArgumentParser(description="SEC Filing Search")
      parser.add_argument("query", nargs="?", help="Search query for SEC filings")
      parser.add_argument("--extract", help="Extract financial metrics for a company ticker")
      parser.add_argument("--compare", nargs="+", help="Compare companies by ticker")
      parser.add_argument("--metric", default="revenue", help="Metric to compare")
      parser.add_argument("--risks", help="Search risk factors for a company")
      parser.add_argument("--json", action="store_true", help="Output as JSON")
      args = parser.parse_args()

      if args.compare:
          print(f"Comparing {len(args.compare)} companies...\n")
          results = compare_companies(args.compare, args.metric)
          if args.json:
              print(json.dumps(results, indent=2))
          else:
              for r in results:
                  if "error" in r:
                      print(f"  {r['ticker']}: ERROR - {r['error']}")
                  else:
                      print(f"  {r['company']} ({r['ticker']}) — {r['filing_type']} ({r['filing_period']})")
                      print(f"    Revenue: {r['total_revenue']}")
                      print(f"    Net Income: {r['net_income']}")
                      print(f"    Operating Income: {r['operating_income']}")
                      print(f"    EPS: {r['eps_diluted']}")
                      print()

      elif args.extract:
          print(f"Extracting financials for {args.extract}...\n")
          data = extract_financial_metrics(args.extract)
          if args.json:
              print(json.dumps(data, indent=2))
          else:
              print(f"{data['company']} ({data['ticker']})")
              print(f"Filing: {data['filing_type']} for {data['filing_period']} (filed {data['filing_date']})")
              print(f"  Revenue:          {data['total_revenue']}")
              print(f"  Net Income:       {data['net_income']}")
              print(f"  Operating Income: {data['operating_income']}")
              print(f"  Total Assets:     {data['total_assets']}")
              print(f"  Total Debt:       {data['total_debt']}")
              print(f"  Cash:             {data['cash_and_equivalents']}")
              print(f"  EPS (diluted):    {data['eps_diluted']}")

      elif args.risks:
          print(f"Searching risk factors for {args.risks}...\n")
          print(search_filing_changes(args.risks))

      elif args.query:
          result = search_sec_filings(args.query)
          if args.json:
              print(json.dumps(result, indent=2))
          else:
              print(result["answer"])

      else:
          print("Error: Provide a query, --extract TICKER, --compare TICKERS, or --risks COMPANY", file=sys.stderr)
          sys.exit(1)


  if __name__ == "__main__":
      main()
  ```
</CodeGroup>

## Example Output

### Basic Filing Search

```bash theme={null}
python sec_search.py "Apple 10-K 2025 revenue breakdown by segment"
```

```
According to Apple's FY2025 10-K filing (filed October 2025), total net
revenue was $394.3 billion. Revenue by segment:

- iPhone: $200.6B (50.8%)
- Services: $96.2B (24.4%)
- Mac: $29.4B (7.5%)
- iPad: $28.3B (7.2%)
- Wearables, Home and Accessories: $39.8B (10.1%)

Services revenue grew 14% year-over-year, continuing to be the fastest-
growing segment. (Source: Apple Inc. 10-K, SEC EDGAR)
```

### Structured Extraction

```bash theme={null}
python sec_search.py --extract AAPL --json
```

```json theme={null}
{
  "company": "Apple Inc.",
  "ticker": "AAPL",
  "filing_type": "10-K",
  "filing_period": "FY2025 (ending September 2025)",
  "filing_date": "2025-10-31",
  "total_revenue": "$394.3 billion",
  "net_income": "$101.2 billion",
  "total_assets": "$352.6 billion",
  "total_debt": "$98.3 billion",
  "operating_income": "$123.4 billion",
  "eps_diluted": "$6.72",
  "cash_and_equivalents": "$29.9 billion"
}
```

### Company Comparison

```bash theme={null}
python sec_search.py --compare AAPL MSFT GOOGL
```

```
Comparing 3 companies...

  Apple Inc. (AAPL) — 10-K (FY2025)
    Revenue: $394.3 billion
    Net Income: $101.2 billion
    Operating Income: $123.4 billion
    EPS: $6.72

  Microsoft Corporation (MSFT) — 10-K (FY2025)
    Revenue: $254.2 billion
    Net Income: $89.4 billion
    Operating Income: $115.6 billion
    EPS: $12.01

  Alphabet Inc. (GOOGL) — 10-K (FY2025)
    Revenue: $348.2 billion
    Net Income: $86.7 billion
    Operating Income: $108.3 billion
    EPS: $7.02
```

<Tip>
  SEC EDGAR contains the official, audited financial data for all US public companies. By restricting search to `sec.gov` and `edgar.sec.gov`, you ensure your financial data comes from primary source filings rather than secondary reporting.
</Tip>

<Warning>
  Financial data extracted by the model should be verified against the original filing before use in official reports or investment decisions. The model may occasionally misparse tables or footnotes.
</Warning>

## Limitations

* The search is limited to what SEC EDGAR makes publicly available and indexable.
* Very recent filings may not yet be indexed by the search engine.
* Complex financial tables (multi-year comparisons, segment breakdowns with footnotes) may be summarized rather than fully extracted.
* The model provides data as-is from filings. It does not adjust for accounting method changes between periods.


# Talent Sourcer
Source: https://docs.perplexity.ai/docs/cookbook/examples/talent-sourcer/README

Build a vetted engineer sourcing shortlist with one Agent API request. The model works in a Python sandbox - segmenting the brief, calling people_search across sub-segments, verifying each candidate's role, location, and tenure with web_search, collecting GitHub, social, and publication links, scoring and de-duplicating in code, then rendering an HTML shortlist and sharing it with share_file.

# Talent Sourcer

Some tasks aren't hard. They're just big, and that's what trips up agents.
Sourcing every engineer who fits a hiring brief - the right skill, the right
city, enough tenure to be worth a call - with each person's current role and
their public links, is a hundred near-identical lookups, not a hard reasoning
problem. This example is a small CLI for that job. Give it a role, a skill, a
location, and a minimum tenure, and it returns a verified shortlist as an HTML
table: name, current role, company, location, years at the company, a relevance
score, public links (GitHub, profile, a notable publication), and a verified
flag per person.

It runs as a single Agent API request built around one tool, `sandbox`, whose
code calls `people_search` and `web_search` from inside the run. You don't write
the collection logic. The agent writes and runs it.

## Why one call isn't enough

The obvious first try is one `people_search` call on "engineers who work on LLM
inference in NYC". It returns the obvious dozen names and nothing else: no
long-tail coverage, no check that anyone's role is current, no confirmation of
location or tenure, no links, no scoring. Wide collection needs many searches,
then per-row verification and bookkeeping the model can't hold in its head. The
fix isn't a smarter search. It's collection discipline, and that's what
`sandbox` provides.

## The sandbox does the work

[`sandbox`](https://docs.perplexity.ai/docs/agent-api/tools/sandbox) is an
isolated container where the agent writes and runs its own Python inside the
request. You describe the job in plain language, and the model writes the code:
the segment list, the loop, the hard-filter checks, dedup by `(name, company)`,
scoring, the sort, the file write. A loop doesn't forget candidate #47, and code
only writes rows it actually has, so there's nothing to hallucinate. The run
ends with a real file, returned via `share_file`, instead of text you still have
to parse.

The run leans on three Agent API tools, `sandbox` first and the other two called
from inside its code:

* `sandbox` -
  [code execution in an isolated container](https://docs.perplexity.ai/docs/agent-api/tools/sandbox).
  The engine: the agent writes the collection loop and runs it server-side.
* `people_search` -
  [a dedicated people-finding tool](https://docs.perplexity.ai/docs/agent-api/tools/people-search),
  not a generic web search. It returns professional details (name, title,
  company) from public sources, queried the way a recruiter thinks (role,
  company, seniority, skill, education, location), as structured data the code
  can dedupe and score.
* `web_search` -
  [the verification pass](https://docs.perplexity.ai/docs/agent-api/tools/web-search):
  confirm each candidate's current role, location, and tenure, and collect their
  public links - a GitHub profile, another relevant public profile, a notable
  publication or talk - each with a real URL. Its domain, recency, and date
  filters let the agent lean on fresh or trusted sources.

You only declare `sandbox` in the request. From inside the run its code reaches
`people_search` and `web_search` with no separate declaration, each still billed
per call. That's what lets the whole loop live in one request.

<Note>
  `people_search` returns publicly available professional information only.
  Keep the task framed that way: recruiting, sourcing, or org mapping over broad
  professional criteria, not a private dossier on one named individual.
</Note>

## Installation

Keep `talent_sourcer.py` and `requirements.txt` in the same directory.

1. Install the dependencies, just the [Perplexity Python SDK](https://github.com/ppl-ai/perplexity-python),
   pinned in `requirements.txt`:

```text requirements.txt theme={null}
perplexityai==0.38.0
```

```bash theme={null}
pip install -r requirements.txt
```

2. Set your Perplexity API key:

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

The SDK reads the key from this environment variable.

<Note>
  This example uses the Agent API `sandbox` tool. See the
  [Sandbox docs](https://docs.perplexity.ai/docs/agent-api/tools/sandbox) for
  setup and usage details.
</Note>

## Usage

```bash theme={null}
python talent_sourcer.py --role "engineers" --skill "LLM inference" --location "NYC" --min-tenure 3 --target 25
```

* `--role` - the kind of person to source, e.g. `"engineers"` (default `engineers`).
* `--skill` - the experience to require, e.g. `"LLM inference"`.
* `--location` - where the candidate must be based, e.g. `"NYC"` (optional).
* `--min-tenure` - minimum years at the current company, e.g. `3` (`0` to skip the filter).
* `--target` - exactly how many candidates to return, the top N by score (default 25).
* `--output` - HTML path (default `candidate-shortlist-<time>.html`).

The run writes one self-contained HTML file you can open in a browser, with a row
per candidate. The full script is `talent_sourcer.py` in this folder.

<Note>
  A full run takes a few minutes (often 2-5), not seconds. The wait is the
  verification: dozens of sequential `people_search` and `web_search` calls are what
  buy completeness. Because the run streams, you watch that progress live instead of
  staring at a blank terminal.
</Note>

## How it works

The whole job is one Agent API request with the `sandbox` tool, run with
`stream=True` so events arrive as the work happens:

```python theme={null}
stream = client.responses.create(
    stream=True,
    model="openai/gpt-5.5",
    instructions=SOURCER_SYSTEM,
    input=SOURCER_TASK.format(brief=brief, filters=filters, target=target, columns=", ".join(COLUMNS)),
    tools=[{"type": "sandbox"}],
)
```

We handle three event types. `response.output_text.delta` carries the model's reply
token by token. `response.sandbox.results` fires once per sandbox execution while
the run is still going, which is the live progress you watch. `response.completed`
returns the finished response, which we keep for the file download and cost:

```python theme={null}
for event in client.responses.create(stream=True, **create_kwargs):
    if event.type == "response.output_text.delta":
        print(event.delta, end="", flush=True)
    elif event.type == "response.sandbox.results":
        for line in progress_lines(event):
            if line != last:
                print(f"  · {line}", file=sys.stderr)
                last = line
    elif event.type == "response.completed":
        final = event.response
```

What makes the agent disciplined lives in the prompt. The hard filters are built
from your flags and passed in as their own block, so "based in NYC" and "3+ years
at the company" are constraints the code enforces, not hints:

```python theme={null}
SOURCER_TASK = """\
Build a vetted sourcing shortlist of {brief}.
Return exactly {target} candidates: the top {target} by relevance score.

Hard filters every kept candidate must satisfy:
{filters}

Workflow, organized in the Python sandbox:

1. Find candidates with people_search. Run several targeted searches across
   sub-segments (sub-skills, seniority levels, nearby employers, the location)
   rather than one broad query, so coverage is exhaustive.

2. Verify EACH candidate with web_search against the hard filters: confirm their
   current title and company, that they are based in the target location, and how
   long they have been at their current company. Then collect their public links:
   a GitHub profile, another relevant public profile, and a notable
   publication, talk, or open-source project - each a real source URL. If you
   cannot confirm a filter or a link, keep the person but set verified=false.
   Never invent a role, company, tenure, or URL.

3. In code: collect rows, deduplicate by (name, company), drop candidates that
   clearly fail a hard filter, assign a relevance_score from 0-100 against the
   brief, sort by score descending, and keep the top {target}.

4. Render an HTML file named 'candidates.html': a clean, styled page with a
   heading (the brief and the final count) and a table with these columns:
   {columns}. In 'Links', render each collected URL as a labeled link
   (GitHub, Profile, Publication). Show 'Tenure' in years at the current company
   and 'Verified' as yes/no. Share it with share_file.

As you work, print() a short, human-readable status line from your sandbox code at
the start of each phase, prefixed with 'PROGRESS:' - for example
'PROGRESS: Searching for candidates', 'PROGRESS: Verifying candidate 5/40',
'PROGRESS: Rendering shortlist'. Never put tool names, query strings, or raw
result counts in these lines, and do not narrate progress in your reply.

Keep your final reply to one short sentence, then a single line:
TOTAL=<number of candidates in the table>.
"""
```

Each rule maps to the result: per-segment search for coverage, hard filters the
code enforces row by row, `verified=false` instead of an invented role or URL,
and dedup, scoring, and rendering as code so the accumulation is a program, not a
memory exercise.

## Full code

The whole tool is one short file.

<Accordion title="Full code - talent_sourcer.py">
  ```python theme={null}
  #!/usr/bin/env python3
  """Build a vetted sourcing shortlist of engineers. The model runs code in a
  sandbox: it finds candidates by segment with people_search, verifies each with
  web_search - confirming role, location, and tenure, and collecting GitHub,
  social, and publication links - then writes an HTML table and shares it. We
  download the file."""

  import argparse
  import os
  import re
  import sys
  from datetime import datetime

  from perplexity import Perplexity

  MODEL = "openai/gpt-5.5"
  PROGRESS_PREFIX = "PROGRESS:"

  DEFAULT_ROLE = "engineers"
  DEFAULT_SKILL = "LLM inference"
  DEFAULT_LOCATION = "NYC"
  DEFAULT_MIN_TENURE = 3
  DEFAULT_TARGET = 25

  COLUMNS = ["Name", "Title", "Company", "Location", "Tenure", "Relevance", "Links", "Verified"]

  SOURCER_SYSTEM = (
      "You assemble a vetted sourcing shortlist of technical candidates for a "
      "recruiter. This is a WIDE collection task: completeness, hard-filter "
      "matching, and per-row verification matter more than depth on any one person."
  )
  SOURCER_TASK = """\
  Build a vetted sourcing shortlist of {brief}.
  Return exactly {target} candidates: the top {target} by relevance score.

  Hard filters every kept candidate must satisfy:
  {filters}

  Workflow, organized in the Python sandbox:

  1. Find candidates with people_search. Run several targeted searches across
     sub-segments (sub-skills, seniority levels, nearby employers, the location)
     rather than one broad query, so coverage is exhaustive.

  2. Verify EACH candidate with web_search against the hard filters: confirm their
     current title and company, that they are based in the target location, and how
     long they have been at their current company. Then collect their public links:
     a GitHub profile, another relevant public profile, and a notable
     publication, talk, or open-source project - each a real source URL. If you
     cannot confirm a filter or a link, keep the person but set verified=false.
     Never invent a role, company, tenure, or URL.

  3. In code: collect rows, deduplicate by (name, company), drop candidates that
     clearly fail a hard filter, assign a relevance_score from 0-100 against the
     brief, sort by score descending, and keep the top {target}.

  4. Render an HTML file named 'candidates.html': a clean, styled page with a
     heading (the brief and the final count) and a table with these columns:
     {columns}. In 'Links', render each collected URL as a labeled link
     (GitHub, Profile, Publication). Show 'Tenure' in years at the current company
     and 'Verified' as yes/no. Share it with share_file.

  As you work, print() a short, human-readable status line from your sandbox code at
  the start of each phase, prefixed with 'PROGRESS:' - for example
  'PROGRESS: Searching for candidates', 'PROGRESS: Verifying candidate 5/40',
  'PROGRESS: Rendering shortlist'. Never put tool names, query strings, or raw
  result counts in these lines, and do not narrate progress in your reply.

  Keep your final reply to one short sentence, then a single line:
  TOTAL=<number of candidates in the table>.
  """


  def build_brief(role, skill, location):
      brief = f"{role} with hands-on experience in {skill}"
      return f"{brief} based in {location}" if location else brief


  def build_filters(skill, location, min_tenure):
      lines = [f"- Hands-on experience in {skill}."]
      if location:
          lines.append(f"- Currently based in {location}.")
      if min_tenure > 0:
          lines.append(f"- At least {min_tenure} years at their current company.")
      return "\n".join(lines)


  def progress_lines(event):
      for result in event.model_dump().get("results") or []:
          for line in (result.get("stdout") or "").splitlines():
              if line.startswith(PROGRESS_PREFIX):
                  yield line[len(PROGRESS_PREFIX):].strip()


  def stream_run(client, **create_kwargs):
      final, last = None, None
      for event in client.responses.create(stream=True, **create_kwargs):
          if event.type == "response.output_text.delta":
              print(event.delta, end="", flush=True)
          elif event.type == "response.sandbox.results":
              for line in progress_lines(event):
                  if line != last:
                      print(f"  · {line}", file=sys.stderr)
                      last = line
          elif event.type == "response.completed":
              final = event.response
      print()
      return final


  def find_candidates(client, brief, filters, target):
      return stream_run(
          client,
          model=MODEL,
          instructions=SOURCER_SYSTEM,
          input=SOURCER_TASK.format(
              brief=brief, filters=filters, target=target, columns=", ".join(COLUMNS)
          ),
          tools=[{"type": "sandbox"}],
      )


  def final_text(response):
      return "".join(
          block.text
          for item in response.output if item.type == "message"
          for block in item.content if block.type == "output_text"
      )


  def cost(response):
      usage = getattr(getattr(response, "usage", None), "cost", None)
      return float(getattr(usage, "total_cost", 0.0) or 0.0)


  def download_html(client, response, output):
      files = client.responses.files.list(response.id)
      html = next(f for f in files.data if f.filename.lower().endswith(".html"))
      out_path = output or f"candidate-shortlist-{datetime.now():%Y-%m-%d_%H-%M}.html"
      client.responses.files.content(html.id, response_id=response.id).write_to_file(out_path)
      return out_path


  def main():
      parser = argparse.ArgumentParser(description="Build a vetted engineer sourcing shortlist.")
      parser.add_argument("--role", default=DEFAULT_ROLE)
      parser.add_argument("--skill", default=DEFAULT_SKILL)
      parser.add_argument("--location", default=DEFAULT_LOCATION)
      parser.add_argument("--min-tenure", type=int, default=DEFAULT_MIN_TENURE)
      parser.add_argument("--target", type=int, default=DEFAULT_TARGET)
      parser.add_argument("--output")
      args = parser.parse_args()

      if not os.environ.get("PERPLEXITY_API_KEY"):
          sys.exit("Set PERPLEXITY_API_KEY in your environment.")

      client = Perplexity()
      brief = build_brief(args.role, args.skill, args.location)
      filters = build_filters(args.skill, args.location, args.min_tenure)

      print(f"\nSourcing a vetted shortlist of: {brief} (target {args.target})\n", file=sys.stderr)
      response = find_candidates(client, brief, filters, args.target)
      out_path = download_html(client, response, args.output)

      match = re.search(r"TOTAL=(\d+)", final_text(response))
      total = match.group(1) if match else "?"
      print(f"\nCandidates: {total}   ${cost(response):.4f}", file=sys.stderr)
      print(f"Saved shortlist to {out_path}", file=sys.stderr)


  if __name__ == "__main__":
      main()
  ```
</Accordion>

## Example Output

A real run of `python talent_sourcer.py --role "engineers" --skill "LLM
inference" --location "NYC" --min-tenure 3 --target 25` (results vary with live
coverage):

Because the run streams, each phase line appears as it happens, first the segment
sweep, then the per-candidate verification, so you watch the work instead of
waiting on a blank terminal (progress abridged):

```
Sourcing a vetted shortlist of: engineers with hands-on experience in LLM inference based in NYC (target 25)

  · Searching for candidates
  · Verifying candidate 1/30
  · Verifying candidate 2/30
  ...
  · Verifying candidate 30/30
  · Searching for candidates
  · Verifying candidate 1/11
  ...
  · Verifying candidate 11/11
  · Rendering shortlist
Done — the shortlist HTML file has been shared.
TOTAL=25
Candidates: 25   $1.8765
Saved shortlist to candidate-shortlist-2026-06-19_23-47.html
```

The prompt searches in rounds and verifies more candidates than `--target`, then
keeps the top N by relevance score. Here it swept two segment rounds, verified
about 40 people in all, and returned the best 25.

The shared `candidates.html` is a styled table, one row per candidate, with name,
title, company, location, years at the company, relevance, public links, and a
verified flag. The candidates are real people surfaced via People Search, each
with source links. They're sourcing leads for outreach, not endorsements, so
always confirm before reaching out.

On the run above, the agent returned 25 verified candidates for about \$1.88.
That covers model tokens over the sandbox loop, one \$0.03 sandbox session, and
the `people_search` / `web_search` calls billed per invocation. That's a list a
recruiter would spend half a day assembling, done in minutes. Depth is the dial:
`--target`, verification breadth, and the model all move the cost.

## Limitations

* Cost scales with depth. Each run pays for model tokens, a `$0.03` sandbox
  session, and one billed call per `people_search` / `web_search` invocation. A
  thorough run is dollars, not cents.
* Coverage varies. Output depends on live results. Not every candidate has a
  public GitHub or confirmable tenure - the `verified` flag and `Links` column
  reflect what could actually be sourced.
* Keep it professional and wide. `people_search` returns public professional
  information, so frame the task as recruiting, sourcing, or org mapping, not a
  deep dossier on one person.

## Resources

* [People Search](https://docs.perplexity.ai/docs/agent-api/tools/people-search)
* [Sandbox](https://docs.perplexity.ai/docs/agent-api/tools/sandbox)
* [Web Search](https://docs.perplexity.ai/docs/agent-api/tools/web-search)
* [Streaming Outputs](https://docs.perplexity.ai/docs/agent-api/output-control)
* [Agent API Quickstart](https://docs.perplexity.ai/docs/agent-api/quickstart)
* [Pricing](https://docs.perplexity.ai/docs/getting-started/pricing)


# TypeScript Agent CLI
Source: https://docs.perplexity.ai/docs/cookbook/examples/typescript-agent-cli/README

An interactive TypeScript CLI with streaming responses, model selection, and web search using the Perplexity Agent API

# TypeScript Agent CLI

A TypeScript-first interactive command-line interface that connects to the Perplexity Agent API with streaming responses, runtime model selection, and integrated web search.

## Features

* Interactive REPL with streaming token output
* Runtime model selection from a curated list
* Web search integration via the `web_search` tool
* TypeScript-specific patterns: type narrowing, const assertions, typed error classes
* Conversation history for multi-turn interactions
* Graceful error handling and clean shutdown

## Installation

```bash theme={null}
mkdir typescript-agent-cli && cd typescript-agent-cli
npm init -y
npm install @perplexity-ai/perplexity_ai
npm install -D typescript @types/node tsx
```

```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```

## Usage

```bash theme={null}
npx tsx src/cli.ts
```

The CLI prompts you to select a model, then enters an interactive loop:

```
Available models:
  1. OpenAI GPT-5.1 (openai/gpt-5.4)
  2. Google Gemini 3 Flash (google/gemini-3.1-flash-lite)

Select a model (1-2): 1

> What is the current state of quantum computing?
```

Commands: `/search` (enable web search), `/nosearch` (disable), `/clear` (reset history), `/quit` (exit).

## Full Code

Save as `src/cli.ts`:

```typescript theme={null}
import Perplexity from "@perplexity-ai/perplexity_ai";
import * as readline from "readline";

// --- Configuration ---

const AVAILABLE_MODELS = [
  { name: "openai/gpt-5.4", label: "OpenAI GPT-5.1" },
  { name: "google/gemini-3.1-flash-lite", label: "Google Gemini 3 Flash" },
] as const;

type ModelName = (typeof AVAILABLE_MODELS)[number]["name"];

interface Message {
  role: "user" | "assistant";
  content: string;
}

// --- Helpers ---

function createRL(): readline.Interface {
  return readline.createInterface({ input: process.stdin, output: process.stdout });
}

function ask(rl: readline.Interface, prompt: string): Promise<string> {
  return new Promise((resolve) => rl.question(prompt, (a) => resolve(a.trim())));
}

// --- Model selection ---

async function selectModel(rl: readline.Interface): Promise<ModelName> {
  console.log("\nAvailable models:");
  AVAILABLE_MODELS.forEach((m, i) =>
    console.log(`  ${i + 1}. ${m.label} (${m.name})`)
  );
  while (true) {
    const idx = parseInt(await ask(rl, `\nSelect a model (1-${AVAILABLE_MODELS.length}): `), 10) - 1;
    if (idx >= 0 && idx < AVAILABLE_MODELS.length) {
      console.log(`Using model: ${AVAILABLE_MODELS[idx].name}\n`);
      return AVAILABLE_MODELS[idx].name;
    }
    console.log("Invalid selection.");
  }
}

// --- Streaming query ---

async function streamQuery(
  client: Perplexity,
  model: ModelName,
  history: Message[],
  userMessage: string,
  useWebSearch: boolean
): Promise<string> {
  const input = [
    ...history.map((m) => ({ role: m.role as "user" | "assistant", content: m.content })),
    { role: "user" as const, content: userMessage },
  ];

  const tools: Array<{ type: "web_search" }> = useWebSearch
    ? [{ type: "web_search" as const }]
    : [];

  const stream = await client.responses.create({
    model,
    input,
    tools,
    stream: true,
    instructions: "You are a helpful assistant. Use web search when available for current events. Be concise.",
    max_output_tokens: 2048,
  });

  let fullResponse = "";
  for await (const chunk of stream) {
    if (chunk.type === "response.output_text.delta") {
      const delta = (chunk as any).delta as string;
      process.stdout.write(delta);
      fullResponse += delta;
    }
    if (chunk.type === "response.output_item.added") {
      const item = (chunk as any).item;
      if (item?.type === "search_results") {
        process.stdout.write("\n[Searching the web...]\n");
      }
    }
    if (chunk.type === "response.completed") {
      const usage = (chunk as any).response?.usage;
      if (usage) {
        process.stdout.write(`\n\n[Tokens: ${usage.input_tokens} in / ${usage.output_tokens} out]`);
      }
    }
  }
  process.stdout.write("\n");
  return fullResponse;
}

// --- Command handling ---

function handleCommand(cmd: string, state: { webSearch: boolean; history: Message[] }): boolean {
  switch (cmd.toLowerCase()) {
    case "/quit": case "/exit":
      console.log("Goodbye."); return true;
    case "/search":
      state.webSearch = true; console.log("Web search enabled."); return false;
    case "/nosearch":
      state.webSearch = false; console.log("Web search disabled."); return false;
    case "/clear":
      state.history = []; console.log("History cleared."); return false;
    case "/help":
      console.log("\n  /search  /nosearch  /clear  /quit  /help\n"); return false;
    default:
      console.log(`Unknown command: ${cmd}. Type /help.`); return false;
  }
}

// --- Main ---

async function main(): Promise<void> {
  const client = new Perplexity();
  const rl = createRL();
  const model = await selectModel(rl);
  const state = { webSearch: true, history: [] as Message[] };

  console.log("Type a message to chat, or /help for commands. Web search is ON.\n");
  process.on("SIGINT", () => { console.log("\nGoodbye."); rl.close(); process.exit(0); });

  while (true) {
    const input = await ask(rl, "> ");
    if (!input) continue;
    if (input.startsWith("/")) { if (handleCommand(input, state)) break; continue; }

    try {
      const response = await streamQuery(client, model, state.history, input, state.webSearch);
      state.history.push({ role: "user", content: input });
      state.history.push({ role: "assistant", content: response });
      if (state.history.length > 20) state.history = state.history.slice(-20);
    } catch (error: unknown) {
      if (error instanceof Perplexity.APIConnectionError) {
        console.error("\nConnection error. Check your network.");
      } else if (error instanceof Perplexity.RateLimitError) {
        console.error("\nRate limit exceeded. Wait and retry.");
      } else if (error instanceof Perplexity.APIStatusError) {
        console.error(`\nAPI error: ${(error as any).message}`);
      } else {
        console.error("\nUnexpected error:", error);
      }
    }
    console.log();
  }
  rl.close();
}

main();
```

## Example Session

```
Available models:
  1. OpenAI GPT-5.1 (openai/gpt-5.4)
  2. Google Gemini 3 Flash (google/gemini-3.1-flash-lite)

Select a model (1-2): 1
Using model: openai/gpt-5.4

Type a message to chat, or /help for commands. Web search is ON.

> What were the major AI announcements this week?
[Searching the web...]
This week saw several notable AI developments:
1. Anthropic released Claude 4 with improved reasoning...
2. Google DeepMind published new protein folding results...
3. OpenAI announced enterprise partnerships for GPT-5...

[Tokens: 1420 in / 287 out]

> /nosearch
Web search disabled.

> Explain transformers in simple terms
A transformer is a neural network architecture that processes all
parts of an input simultaneously rather than sequentially...

[Tokens: 2580 in / 195 out]

> /quit
Goodbye.
```

## Key TypeScript Patterns

### Const Assertions for Tool Types

Use `as const` to narrow tool type literals:

```typescript theme={null}
const tools = [{ type: "web_search" as const }];
```

### Streaming Event Type Narrowing

Check `chunk.type` before accessing event-specific fields:

```typescript theme={null}
for await (const chunk of stream) {
  if (chunk.type === "response.output_text.delta") {
    process.stdout.write((chunk as any).delta);
  }
}
```

### Typed Error Handling

```typescript theme={null}
try {
  // API call
} catch (error) {
  if (error instanceof Perplexity.APIConnectionError) {
    // Handle network issues
  } else if (error instanceof Perplexity.RateLimitError) {
    // Handle rate limits
  }
}
```

<Tip>
  Conversation history is preserved across turns, so the model can reference earlier messages. Use `/clear` to start a fresh conversation without restarting the CLI.
</Tip>

## Limitations

* The CLI uses Node.js `readline`, which does not support arrow-key history navigation. For a richer experience, consider `inquirer` or `prompts`.
* Conversation history is in-memory only and lost when the process exits.
* Streaming events may vary by model provider. The `response.output_text.delta` event is consistent across all models.


# Getting Started
Source: https://docs.perplexity.ai/docs/cookbook/getting-started

How to use the Perplexity API Cookbook, plus a quick start for getting your API key and installing the SDK.

A collection of practical guides, runnable examples, and integration patterns for building with [**Perplexity's API Platform**](https://docs.perplexity.ai/) — covering the Agent API, Search API, Embeddings API, and Sonar API.

<Note>
  Looking for a specific recipe? Browse and filter every recipe by product, capability, and topic on the [Cookbook home page](/docs/cookbook).
</Note>

## How to Use This Cookbook

<CardGroup>
  <Card title="Guides" icon="book" href="/docs/cookbook/articles/function-calling-e2e/README">
    Practical deep-dives on patterns that go beyond the docs — structured outputs, function calling, RAG pipelines, and cross-cutting best practices.
  </Card>

  <Card title="Examples" icon="code-circle" href="/docs/cookbook/examples/README">
    Runnable projects covering every API. From research assistants and news monitors to document Q\&A and image analysis — with Python and TypeScript.
  </Card>

  <Card title="Integration Guides" icon="link" href="/docs/cookbook/articles/openai-agents-integration/README">
    Connect Perplexity with external frameworks like the OpenAI Agents SDK, LangChain memory systems, and persistent storage.
  </Card>

  <Card title="Community Showcase" icon="sparkles" href="/docs/cookbook/showcase/briefo">
    Real-world applications built by the community — see what others are building with the API Platform.
  </Card>
</CardGroup>

## Quick Start

<Steps>
  <Step title="Get API Access">
    To use the Perplexity API Platform, you'll need an API key. If you don't have one yet:

    <Card title="Get your Perplexity API Key" icon="key" href="https://perplexity.ai/account/api">
      Navigate to the **API Keys** tab in the API Portal and generate a new key.
    </Card>
  </Step>

  <Step title="Install the SDK">
    The Perplexity API SDK is available in Python and TypeScript. Install the package for your preferred language:

    <CodeGroup>
      ```bash Python theme={null}
      pip install perplexityai
      ```

      ```bash TypeScript theme={null}
      npm install @perplexity-ai/perplexity_ai
      ```
    </CodeGroup>
  </Step>

  <Step title="Pick a Starting Point">
    The Perplexity API Platform supports a wide range of use cases across its different APIs. Here are some recommended starting points based on your goals:

    * New to the platform? Refer to our <u>[Quick Start Guide](/docs/getting-started/quickstart)</u>
    * Want to build something? Take a look at our <u>[Examples](/docs/cookbook/examples/README)</u>
  </Step>
</Steps>


# Cookbook
Source: https://docs.perplexity.ai/docs/cookbook/index

Guides, runnable examples, and community projects for building with the Perplexity Agent, Search, and Embeddings APIs. Search or filter by product and category.

<CookbookGallery />


# 4Point Hoops | AI Basketball Analytics Platform
Source: https://docs.perplexity.ai/docs/cookbook/showcase/4point-Hoops

Advanced NBA analytics platform that combines live Basketball-Reference data with Perplexity Sonar to deliver deep-dive player stats, cross-season comparisons and expert-grade AI explanations

<SonarDeprecationNotice />

![4Point Hoops Dashboard](https://d112y698adiu2z.cloudfront.net/photos/production/software_photos/003/442/047/datas/original.png)

**4Point Hoops** is an advanced NBA analytics platform that turns raw basketball statistics into actionable, narrative-driven insights. By scraping Basketball-Reference in real time and routing context-rich prompts to Perplexity's Sonar Pro model, it helps fans, analysts, and fantasy players understand the "why" and "what's next" – not just the numbers.

<iframe title="YouTube video player" />

## Features

* **Player Analytics** with season & playoff splits, shot-type breakdowns, and performance radar for any NBA player
* **Cross-Era Comparisons** enabling side-by-side stat comparisons (e.g., Michael Jordan '97 vs. Stephen Curry '22)
* **Team Dashboards** with standings, playoff-probability Sankey flows, and auto-refreshing KPI tiles
* **AI Explain & Similar Players** providing one-click Sonar explanations of stat lines and AI-picked comparable athletes
* **Basketball AI Chat** allowing users to ask an expert LLM about NBA history, rosters, or projections
* **Credit-Based SaaS System** with Firebase Auth, Google login, credit wallets, and admin tooling

## Prerequisites

* Node.js 16+ and npm
* Python 3.8+ and pip
* Firebase project setup
* Perplexity API key (Sonar Pro)
* Basketball-Reference access

## Installation

```bash theme={null}
# Clone the frontend repository
git clone https://github.com/rapha18th/hoop-ai-frontend-44.git
cd hoop-ai-frontend-44
npm install

# Clone the backend repository
git clone https://github.com/rapha18th/4Point-Hoops-Server.git
cd 4Point-Hoops-Server
pip install -r requirements.txt
```

## Configuration

Create `.env` file in the backend directory:

```ini theme={null}
PERPLEXITY_API_KEY=your_sonar_pro_api_key
FIREBASE_PROJECT_ID=your_firebase_project_id
FIREBASE_PRIVATE_KEY=your_firebase_private_key
FIREBASE_CLIENT_EMAIL=your_firebase_client_email
```

## Usage

1. **Start Backend**:
   ```bash theme={null}
   cd 4Point-Hoops-Server
   python app.py
   ```

2. **Start Frontend**:
   ```bash theme={null}
   cd hoop-ai-frontend-44
   npm run dev
   ```

3. **Access Application**: Open the frontend URL and explore NBA analytics with AI-powered insights

4. **Use AI Features**: Click "AI Explain" on any player or stat to get intelligent analysis powered by Perplexity Sonar

## Code Explanation

* **Frontend**: React with shadcn/ui components and Recharts for data visualization
* **Backend**: Python Flask API serving Basketball-Reference data and managing Perplexity API calls
* **Data Pipeline**: BRScraper for real-time data collection with Firebase caching
* **AI Integration**: Perplexity Sonar Pro for intelligent basketball analysis and explanations
* **Authentication**: Firebase Auth with Google login and credit-based access control
* **Deployment**: Frontend on Netlify, backend on Hugging Face Spaces with Docker

## Links

* [Frontend Repository](https://github.com/rapha18th/hoop-ai-frontend-44)
* [Backend Repository](https://github.com/rapha18th/4Point-Hoops-Server)
* [Live Demo](https://4pointhoops.netlify.app/)
* [Devpost Submission](https://devpost.com/software/4point-hoops)


# Ellipsis | One-Click Podcast Generation Agent
Source: https://docs.perplexity.ai/docs/cookbook/showcase/Ellipsis

A next-gen podcast generation agent that brings human-like, high-quality audio content to life on any topic with just one click

<SonarDeprecationNotice />

**Ellipsis** is a next-generation podcast generation agent that brings human-like, high-quality audio content to life on any topic with just one click. Whether it's breaking news, deep-dive tech explainers, movie reviews, or post-match sports breakdowns, Ellipsis crafts intelligent podcast episodes that sound like they were created by seasoned hosts in a professional studio.

## Features

* **Intelligent Multi-Speaker Dialogue** with multiple distinct voices and personalities
* **Comprehensive Topic Coverage** from LLM architectures to lunar eclipses
* **Custom Evaluation Engine** ensuring factual accuracy, legal compliance, and conversational quality
* **Fully Automated Podcast Generation** with human-like, podcast-ready audio output
* **Real-time Streaming Updates** via Server-Sent Events (SSE)
* **Podbean Integration** for direct podcast publishing
* **Trending Topics Detection** using Perplexity API

## Prerequisites

* Node.js v16+ and npm/yarn
* Python 3.10+ and pip
* Redis server running (default on port 6380)
* Perplexity API key, Podbean credentials

## Installation

```bash theme={null}
# Clone the repository
git clone https://github.com/dineshkannan010/Ellipsis.git
cd Ellipsis

# Backend setup
cd backend
python -m venv venv
source venv/bin/activate    # macOS/Linux
pip install -r requirements.txt

# Install native packages
pip install llama-cpp-python --extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cpu
pip install git+https://github.com/freddyaboulton/orpheus-cpp.git
pip install huggingface_hub[hf_xet] hf_xet

# Frontend setup
cd ../frontend
npm install
```

## Configuration

Create `backend/.env`:

```ini theme={null}
REDIS_URL=redis://your-redis-host:6379
PERPLEXITY_API_KEY=your_key_here
PODBEAN_CLIENT_ID=...
PODBEAN_CLIENT_SECRET=...
```

Create `frontend/.env`:

```ini theme={null}
REACT_APP_API_URL=http://your-backend-host:5000
```

## Usage

1. **Start Redis Server**:
   ```bash theme={null}
   redis-server --port 6380
   ```

2. **Launch Backend**:
   ```bash theme={null}
   cd backend
   python app.py
   ```

3. **Launch Frontend**:
   ```bash theme={null}
   cd frontend
   npm run dev
   ```

4. **Optional: Podbean Integration**:
   ```bash theme={null}
   cd backend/integrations/podbean_mcp
   pip install -e .
   python server.py
   python client.py server.py
   ```

5. **Generate Content**: Enter a topic in the homepage textbox and hit Enter. Switch to `ContentGenerationView` to see live script & audio progress.

## Code Explanation

* **Backend**: Python Flask with Redis pub/sub, llama.cpp, and Orpheus TTS for audio generation
* **Frontend**: React with Vite, Tailwind CSS, and Server-Sent Events for real-time updates
* **AI Integration**: Perplexity API for content generation and trending topics detection
* **Audio Processing**: Multi-speaker TTS with distinct voice personalities
* **Content Evaluation**: Built-in pipelines for factual accuracy and legal compliance
* **Podcast Publishing**: Direct integration with Podbean via MCP server

## Demo Video

<iframe title="YouTube video player" />

## Links

* [GitHub Repository](https://github.com/dineshkannan010/Ellipsis)
* [Devpost Submission](https://devpost.com/software/ellipsis)


# BazaarAISaathi | AI-Powered Indian Stock Market Assistant
Source: https://docs.perplexity.ai/docs/cookbook/showcase/bazaar-ai-saathi

An AI-powered platform for Indian stock market analysis, portfolio optimization, and investment strategies using Perplexity Sonar API

<SonarDeprecationNotice />

**BazaarAISaathi** is an AI-powered platform designed to empower investors with actionable insights into the Indian stock market. Leveraging advanced natural language processing, real-time data analytics, and expert-driven financial modeling, the app delivers personalized investment strategies, market sentiment analysis, and portfolio optimization recommendations.

## Features

* **Financial Independence Planner (FIRE)** with personalized plans based on age, salary, and goals
* **Investment Advice Tester** using EasyOCR for text extraction and AI validation
* **Fundamental & Technical Analysis** with comprehensive company reports and trading strategies
* **Portfolio Analysis** with multi-dimensional analysis and stock-wise recommendations
* **Market Research & Competitor Benchmarking** using AI-driven industry trend analysis
* **Real-Time Stock Data** with live price tracking and trend analysis
* **Hypothesis Testing** using historical and real-time market data
* **Investment Books Summary** with concise summaries of top 50 investment books

## Prerequisites

* Python 3.8+ and pip
* Streamlit for web application framework
* Perplexity API key (Sonar models)
* Optional: EasyOCR for image text extraction

## Installation

```bash theme={null}
# Clone the repository
git clone https://github.com/mahanteshimath/BazaarAISaathi.git
cd BazaarAISaathi

# Install dependencies
pip install -r requirements.txt
```

## Configuration

Create `secrets.toml` file for Streamlit secrets:

```ini theme={null}
PERPLEXITY_API_KEY = "your_perplexity_api_key"
# Add other API keys as needed
```

## Usage

1. **Start the Application**:
   ```bash theme={null}
   streamlit run Home.py
   ```

2. **Access Features**:
   * Navigate through different pages for specific functionality
   * Use the main dashboard for overview and navigation
   * Access specialized tools like portfolio analysis, FIRE planning, and tip testing

3. **Run Specific Modules**:
   ```bash theme={null}
   streamlit run pages/Financial_Independence.py
   streamlit run pages/Portfolio_Analysis.py
   streamlit run pages/Tip_Tester.py
   ```

## Code Explanation

* **Frontend**: Streamlit web application with interactive pages and real-time data visualization
* **Backend**: Python-based business logic with Pandas for data manipulation and analysis
* **AI Integration**: Perplexity Sonar API models (sonar-deep-research, sonar-reasoning-pro, sonar-pro) for financial analysis
* **Data Processing**: Real-time stock data fetching, CSV data management, and market insights generation
* **Text Extraction**: EasyOCR integration for processing investment tips from images
* **Portfolio Management**: Comprehensive portfolio analysis with optimization recommendations
* **Market Analysis**: Technical and fundamental analysis with sentiment scoring

## Demo Video

<iframe title="YouTube video player" />

## Links

* [GitHub Repository](https://github.com/mahanteshimath/BazaarAISaathi)
* [Live Application](https://bazaar-ai-saathi.streamlit.app/)
* [Architecture Diagram](https://github.com/mahanteshimath/BazaarAISaathi/raw/main/src/App_Architecture.jpg)


# Briefo | Perplexity Powered News & Finance Social App
Source: https://docs.perplexity.ai/docs/cookbook/showcase/briefo

AI curated newsfeed, social discussion, and deep research reports built on the Sonar API

<SonarDeprecationNotice />

**Briefo** delivers a personalized, AI generated newsfeed and company deep dives. Readers can follow breaking stories, request on demand financial analyses, and discuss insights with friends, all in one mobile experience powered by Perplexity’s Sonar API.

## Features

* Personalized newsfeed across 17 categories with AI summaries and source links
* Private and public threads for article discussion and sharing
* Watch list with real time market snapshots and optional AI analyses
* Deep research reports generated on 12 selectable criteria such as management, competitors, and valuation
* General purpose chat assistant that remembers each user’s preferred topics

## Prerequisites

* Node 18 LTS or newer
* npm, Yarn, or pnpm
* Expo CLI (`npm i -g expo-cli`)
* Supabase CLI 1.0 or newer for local emulation and Edge Function deploys

## Installation

```bash theme={null}
git clone https://github.com/adamblackman/briefo-public.git
cd briefo-public
npm install
```

### Environment Variables

```ini theme={null}
# .env              (project root)
MY_SUPABASE_URL=https://<project>.supabase.co
MY_SUPABASE_SERVICE_ROLE_KEY=...
PERPLEXITY_API_KEY=...
LINKPREVIEW_API_KEY=...
ALPACA_API_KEY=...
ALPACA_SECRET_KEY=...

# .env.local        (inside supabase/)
# duplicate or override any secrets needed by Edge Functions
```

## Usage

Run the Expo development server:

```bash theme={null}
npx expo start
```

Deploy Edge Functions when you are ready:

```bash theme={null}
supabase functions deploy perplexity-news perplexity-chat perplexity-research portfolio-tab-data
```

## Code Explanation

* Frontend: React Native with Expo Router (Typescript) targeting iOS, Android, and Web
* Backend: Supabase (PostgreSQL, Row Level Security, Realtime) for data and authentication
* Edge Functions: Typescript on Deno calling Perplexity, Alpaca, Alpha Vantage, and LinkPreview APIs
* Hooks: Reusable React Query style data hooks live in lib/ and hooks/
* Testing and Linting: ESLint, Prettier, and Expo Lint maintain code quality

## Links

[GitHub Repository](https://github.com/adamblackman/briefo-public)
[Live Demo](https://www.briefo.fun/)


# CityPulse | AI-Powered Geospatial Discovery Search
Source: https://docs.perplexity.ai/docs/cookbook/showcase/citypulse-ai-search

Real-time local discovery search using Perplexity AI for personalized location insights and recommendations

<SonarDeprecationNotice />

# CityPulse - AI-Powered Geospatial Discovery

![CityPulse Main Interface](https://raw.githubusercontent.com/anevsky/CityPulse/main/assets/CityPulse-GeoSearch-App-1.jpg)

CityPulse is an intelligent location-based discovery search that helps users explore what's happening around them right now. It demonstrates how to create personalized, real-time local insights using Perplexity's Sonar models.

[![Demo Video](https://cdn.loom.com/sessions/thumbnails/6507fa27571442e680edf787b0f0690d-2fa2c36169822631-full-play.gif)](https://youtu.be/Y0UIhh3diJg)

## What CityPulse Does

* **Real-time local discovery** - Find current events, restaurants, and local alerts near any location
* **AI-powered search suggestions** - Get intelligent search recommendations as you type
* **Personalized insights** - Receive AI-generated advice on what to try, best times to visit, and pro tips
* **Interactive mapping** - Explore results on an interactive map with custom markers and detailed popups

![Search Interface](https://raw.githubusercontent.com/anevsky/CityPulse/main/assets/CityPulse-GeoSearch-App-2.jpg)

## How It Uses Perplexity Sonar

CityPulse leverages two key Perplexity models:

**Sonar for Real-Time Data**

```python theme={null}
# Get current local information with geographic context
response = client.chat.completions.create(
    model="sonar",
    messages=[{
        "role": "user", 
        "content": f"Find current events, restaurants, and alerts near {lat}, {lng}"
    }],
    response_format={"type": "json_schema", "json_schema": {"schema": LOCAL_INFO_SCHEMA}}
)
```

**Sonar Reasoning Pro for Personalized Insights**

```python theme={null}
# Generate AI-powered location recommendations
response = client.chat.completions.create(
    model="sonar-reasoning-pro",
    messages=[{
        "role": "user",
        "content": f"Provide personalized insights for {location_name}: what to try, best times to visit, pro tips"
    }]
)
```

The app uses structured JSON schemas to ensure consistent data formatting and includes citation tracking for source verification.

![AI Insights](https://raw.githubusercontent.com/anevsky/CityPulse/main/assets/CityPulse-GeoSearch-App-3.jpg)

## Links

* [GitHub Repository](https://github.com/anevsky/CityPulse)
* [Live Demo](https://citypulse-ppx.uc.r.appspot.com/)
* **[Built with ❤️ by Alex Nevsky](https://alexnevsky.com)**


# CycleSyncAI | Personalized Health Plans Powered by Sonar API
Source: https://docs.perplexity.ai/docs/cookbook/showcase/cycle-sync-ai

iOS app that delivers personalized diet and workout recommendations for women, powered by Apple HealthKit and Perplexity's Sonar Pro API.

<SonarDeprecationNotice />

**CycleSyncAI** is an iOS app designed to provide personalized **diet and workout recommendations** tailored to a woman's **menstrual cycle phase**.

By integrating menstrual data from Apple **HealthKit** and optional user profile inputs (age, weight, height, medical conditions, dietary restrictions, goals, and preferences), the app generates dynamic, phase-aware suggestions to support holistic wellness.

Unlike static wellness tools, **CycleSyncAI** leverages **Perplexity's Sonar Pro API** to deliver **expert-informed**, LLM-generated guidance — including a daily grocery list and motivational feedback — customized to the user's cycle and lifestyle.

## Problem & Solution

> **Why it matters:**\
> Most apps overlook the hormonal changes that affect women's fitness and nutrition needs across their cycle, leaving users with generic advice.

**CycleSyncAI** bridges this gap by combining Apple HealthKit data with Sonar Pro's LLM to generate **adaptive, cycle-aware recommendations** for better health outcomes.

## Features

* **Personalized diet & workout suggestions** per cycle phase
* Syncs with Apple HealthKit for real-time cycle tracking
* User profile inputs for advanced personalization (age, goals, restrictions, etc.)
* **Auto-generated daily grocery list**
* Smooth, modern UI with gradients and subtle animations
* **Motivational AI feedback** tailored to user preferences
* Local data storage and private processing

## Motivation

> "I wanted a tailored regime for myself and couldn't find it all in one place."

**CycleSyncAI** was born from the need for a science-backed, easy-to-use app that adapts wellness guidance to women's natural hormonal rhythms, something missing in most mainstream fitness and nutrition platforms.

## Repository Structure

```text theme={null}
CycleSyncAI.xcodeproj          → Xcode project file  
CycleSyncAI/                   → Source code  
├── EatPlanViewController.swift        → Diet plan generation & display  
├── WorkoutPlanViewController.swift    → Workout plan generation & display  
├── HomepageViewController.swift       → Navigation & main screen  
├── UserProfileViewController.swift    → Input & storage of user data  
├── HealthManager.swift                → Apple HealthKit menstrual data  
├── UserProfile.swift                  → Local profile model  
Main.storyboard               → App UI & layout  
Assets.xcassets              → Images & app icons  
Info.plist                   → Permissions & configurations  
```

## Setup Instructions

1. Clone the repo
2. Open in **Xcode**
3. Ensure Apple HealthKit is enabled on your device
4. Insert your **Sonar Pro API key**
5. Run the app on a physical device (recommended)

## Sonar API Usage

The app sends structured prompts to the **Sonar Pro API** including:

* Cycle phase (from HealthKit)
* User profile info (age, weight, goals, etc.)
* Meal preferences & restrictions

In return, it receives:

* **Personalized diet plan**
* **Custom workout plan**
* **Daily grocery list**
* **Motivational feedback**

These are parsed and rendered as styled HTML inside the app using WebViews.

## Demo Video

<iframe title="YouTube video player" />

> *Note: The LLM takes \~30–60 seconds per request. This wait time was trimmed in the video for brevity.*

## Impact

**CycleSyncAI** empowers women to make informed, body-aware decisions in daily life. The app supports better:

* Energy management
* Fitness results
* Mental well-being
* Motivation and confidence

It also reduces decision fatigue with automatically prepared grocery lists and uplifting guidance.

## Links

* [GitHub Repository](https://github.com/medhini98/cyclesyncai-api-cookbook)


# Daily News Briefing | AI-Powered News Summaries for Obsidian
Source: https://docs.perplexity.ai/docs/cookbook/showcase/daily-news-briefing

An Obsidian plugin that delivers AI-powered daily news summaries directly to your vault using Perplexity's Sonar API for intelligent content curation

<SonarDeprecationNotice />

**Daily News Briefing** is an Obsidian plugin that delivers AI-powered news summaries directly to your vault. Stay informed about your topics of interest with smart, automated news collection and summarization using Perplexity's Sonar API for intelligent content curation.

<iframe title="Daily News Briefing Demo" />

## Features

* **Personalized News Collection** based on your topics of interest and preferences
* **AI-Powered Summarization** of news articles using Perplexity Sonar API
* **Automated Daily Briefings** delivered directly to your Obsidian vault
* **Customizable Delivery Schedule** and format options
* **Seamless Obsidian Integration** with your existing knowledge management workflow
* **Trusted Source Filtering** to ensure quality and reliability
* **Markdown Formatting** for easy linking and organization within your vault

## Prerequisites

* Obsidian desktop app installed
* Perplexity API key (Sonar API access)
* Internet connection for fetching news articles
* Typescript development environment (for customization)

## Installation

```bash theme={null}
# Clone the repository
git clone https://github.com/ChenziqiAdam/Daily-News-Briefing.git
cd Daily-News-Briefing

# Install dependencies
npm install

# Build the plugin
npm run build
```

## Configuration

1. **Install Plugin**: Copy the built plugin to your Obsidian plugins folder
2. **Enable Plugin**: Activate in Obsidian settings
3. **API Setup**: Enter your Perplexity API key in plugin settings
4. **Configure Topics**: Set up your news topics and delivery preferences

## Usage

1. **Configure Interests**: Set up preferred topics, sources, and delivery schedule
2. **Automated Collection**: Plugin uses Perplexity Sonar API to gather latest news
3. **AI Summarization**: Articles are processed and summarized using Perplexity's capabilities
4. **Vault Delivery**: Summaries are formatted as Markdown notes in your Obsidian vault
5. **Knowledge Integration**: Link news briefings with other notes in your knowledge base

## Code Explanation

* **Frontend**: Typescript-based Obsidian plugin with custom UI components
* **AI Integration**: Perplexity Sonar API for intelligent news gathering and summarization
* **Content Processing**: Automated article extraction and summarization workflows
* **Scheduling**: Configurable delivery schedules and topic monitoring
* **Markdown Generation**: Structured content formatting for Obsidian compatibility
* **Error Handling**: Robust error management for API limits and network issues

## Technical Implementation

The plugin leverages Perplexity Sonar API for:

```typescript theme={null}
// News gathering with Perplexity Sonar API
const newsQuery = `latest news about ${topic} in the past 24 hours`;
const searchResponse = await perplexityClient.search({
  query: newsQuery,
  max_results: 5,
  include_domains: userPreferences.trustedSources || []
});

// AI-powered summarization
const summaryPrompt = `Summarize these news articles about ${topic}`;
const summaryResponse = await perplexityClient.generate({
  prompt: summaryPrompt,
  model: "sonar-medium-online",
  max_tokens: 500
});
```

## Links

* [GitHub Repository](https://github.com/ChenziqiAdam/Daily-News-Briefing)


# Executive Intelligence | AI-Powered Strategic Decision Platform
Source: https://docs.perplexity.ai/docs/cookbook/showcase/executive-intelligence

A comprehensive Perplexity Sonar-powered application that provides executives and board members with instant, accurate, and credible intelligence for strategic decision-making

<SonarDeprecationNotice />

**Executive Intelligence** is a comprehensive Perplexity Sonar-powered application that provides executives and board members with instant, accurate, and credible intelligence for strategic decision-making. It delivers board-ready insights derived from real-time data sources, powered by Perplexity's Sonar API.

<iframe title="YouTube video player" />

## Features

* **Competitive Intelligence Briefs** with comprehensive, board-ready competitive analysis and verifiable citations
* **Scenario Planning ("What If?" Analysis)** for dynamic future scenario generation based on real-time data
* **Board Pack Memory** for saving and organizing intelligence briefs, scenario analyses, and benchmark reports
* **Instant Benchmarking & Peer Comparison** with source-cited visual comparisons across critical metrics
* **Real-time Data Integration** leveraging Perplexity Sonar API for up-to-date market intelligence
* **Professional Formatting** with structured reports, executive summaries, and board-ready presentations

## Prerequisites

* Node.js 18+ and npm/yarn
* Git
* Perplexity API key (Sonar Pro)

## Installation

```bash theme={null}
# Clone the repository
git clone https://github.com/raishs/perplexityhackathon.git
cd perplexityhackathon

# Install dependencies
npm install

# Set up environment variables
cp .env.example .env.local
```

## Configuration

Create `.env.local` file:

```ini theme={null}
PERPLEXITY_API_KEY=your_perplexity_api_key
```

## Usage

1. **Start Development Server**:
   ```bash theme={null}
   npm run dev
   ```

2. **Access Application**: Open [http://localhost:3000](http://localhost:3000) in your browser

3. **Generate Intelligence**:
   * Enter a company name in the input field
   * Click "Competitive Analysis" for comprehensive briefs
   * Use "Scenario Planning" for "what-if" analysis
   * Access "Benchmarking" for peer comparisons
   * Save reports to "Board Pack" for later access

4. **Board Pack Management**: Use the "📁 Board Pack" button to view and manage saved intelligence reports

## Code Explanation

* **Frontend**: Next.js with Typescript and React for modern, responsive UI
* **Backend**: Next.js API routes handling Perplexity Sonar API integration
* **AI Integration**: Perplexity Sonar Pro for real-time competitive intelligence and scenario analysis
* **State Management**: React Context for boardroom memory and persistent data storage
* **Markdown Processing**: Custom utilities for parsing AI responses and citation handling
* **Error Handling**: Comprehensive timeout and error management for API calls
* **Professional Output**: Structured formatting for board-ready presentations with source citations

## Links

* [GitHub Repository](https://github.com/raishs/perplexityhackathon)


# Fact Dynamics | Real-time Fact-Checking Flutter App
Source: https://docs.perplexity.ai/docs/cookbook/showcase/fact-dynamics

Cross-platform app for real-time fact-checking of debates, speeches, and images using Perplexity's Sonar API

<SonarDeprecationNotice />

# Fact Dynamics | Real-time Fact-Checking Flutter App

<p>
  <img alt="Fact Dynamics logo" />
</p>

**Hackathon Submission** - Built for Perplexity Hackathon in Information Tools & Deep Research categories.

Fact Dynamics is a cross-platform Flutter app that provides real-time fact-checking for spoken content and images. Perfect for live debates, presentations, and on-the-fly information verification.

## Features

* Real-time speech transcription and fact-checking during live conversations

* Image text extraction and claim verification with source citations

* Claim rating system (TRUE, FALSE, MISLEADING, UNVERIFIABLE) with explanations

* Source citations - Provides authoritative URLs backing each verdict

* Debate mode with continuous speech recognition and streaming feedback

* User authentication via Firebase (Google, Email) with persistent chat history

* Cross-platform support for iOS, Android, and Web

## Prerequisites

* Flutter SDK 3.0.0 or newer
* Dart SDK 2.17.0 or newer
* Firebase CLI for authentication and database setup
* Perplexity API key for Sonar integration
* Device with microphone access for speech recognition

## Installation (Follow Detailed guideline on the Repository)

```bash theme={null}
git clone https://github.com/vishnu32510/fact_pulse.git
cd fact_pulse
flutter pub get
```

## Usage

### Real-time Speech Fact-Checking

* Streams 5-second audio chunks through Flutter's `speech_to_text`
* Sends transcribed snippets to Sonar API with structured prompts
* Returns JSON with claims, ratings (TRUE/FALSE/MISLEADING/UNVERIFIABLE), explanations, and sources

### Image Analysis

* Uploads images/URLs to Sonar API for text extraction
* Verifies extracted claims against authoritative sources
* Provides comprehensive analysis with source attribution

## Screenshots

<table>
  <tr>
    <td>
      <img alt="Dashboard" />
    </td>

    <td>
      <img alt="Fact checking interface" />
    </td>
  </tr>
</table>

## Code Explanation

* Frontend: Flutter with BLoC pattern for state management targeting iOS, Android, and Web
* Backend: Firebase (Firestore, Authentication) for user data and chat history persistence
* Speech Processing: speech\_to\_text package for real-time audio transcription
* API Integration: Custom Dart client calling Perplexity Sonar API with structured prompts
* Image Processing: Built-in image picker with base64 encoding for multimodal analysis
* Data Architecture: Firestore collections per user with subcollections for debates, speeches, and images

## Open Source SDKs

Built two reusable packages for the Flutter community:

* **[perplexity\_dart](https://pub.dev/packages/perplexity_dart)** - Core Dart SDK for Perplexity API
* **[perplexity\_flutter](https://pub.dev/packages/perplexity_flutter)** - Flutter widgets and BLoC integration

## Demo Video

<iframe title="YouTube video player" />

## Links

* **[GitHub Repository](https://github.com/vishnu32510/fact_pulse)** - Full source code
* **[Live Demo](https://fact-pulse.web.app/)** - Try the web version
* **[Devpost Submission](https://devpost.com/software/fact-dynamics)** - Hackathon entry


# FirstPrinciples | AI Learning Roadmap Generator
Source: https://docs.perplexity.ai/docs/cookbook/showcase/first-principle

An AI-powered learning roadmap generator that uses conversational AI to help users identify specific learning topics and provides personalized step-by-step learning plans

<SonarDeprecationNotice />

**FirstPrinciples App** is an AI-powered tool that transforms your broad learning goals into structured, personalized roadmaps. Through an interactive chat, the AI engages you in a conversation, asking targeted questions to refine your learning needs before generating a detailed plan. The application is built to help you learn more efficiently by providing a clear path forward.

<video />

## Features

* **Interactive Chat Interface** for defining and refining learning goals through conversation
* **AI-Powered Topic Narrowing** with smart, targeted questions to specify learning objectives
* **Session Management** allowing multiple roadmap discussions and progress tracking
* **Visual Progress Indicators** showing when sufficient information has been gathered
* **Personalized Learning Plans** with structured, step-by-step roadmaps
* **Conversational AI Flow** combining OpenAI and Perplexity APIs for intelligent interactions

## Prerequisites

* Python 3.8+ and pip
* Node.js 16+ and npm
* OpenAI API key
* Perplexity API key

## Installation

```bash theme={null}
# Clone the repository
git clone https://github.com/william-Dic/First-Principle.git
cd First-Principle

# Backend setup
cd flask-server
pip install -r requirements.txt

# Frontend setup
cd ../client
npm install
```

## Configuration

Create `.env` file in the `flask-server` directory:

```ini theme={null}
OPENAI_API_KEY=your_openai_api_key
PERPLEXITY_API_KEY=your_perplexity_api_key
PERPLEXITY_API_KEY=your_perplexity_api_key
```

## Usage

1. **Start Backend**:
   ```bash theme={null}
   cd flask-server
   python server.py
   ```
   Server runs on [http://localhost:5000](http://localhost:5000)

2. **Start Frontend**:
   ```bash theme={null}
   cd client
   npm start
   ```
   Client runs on [http://localhost:3000](http://localhost:3000)

3. **Generate Roadmap**:
   * Open [http://localhost:3000](http://localhost:3000) in your browser
   * Describe what you want to learn in the chat interface
   * Answer AI follow-up questions to refine your learning goals
   * Receive a personalized, structured learning roadmap

## Code Explanation

* **Frontend**: React application with conversational chat interface and progress indicators
* **Backend**: Flask server managing API calls, session state, and conversation flow
* **AI Integration**: Combines OpenAI API for conversational flow and Perplexity API for intelligent topic analysis
* **Session Management**: Tracks conversation state and learning goal refinement
* **Roadmap Generation**: Creates structured, actionable learning plans based on user input
* **Conversational Flow**: Implements goal-oriented dialogue to narrow down learning objectives

## Links

* [GitHub Repository](https://github.com/william-Dic/First-Principle.git)
* [Demo Video](https://github.com/user-attachments/assets/6016c5dd-6c18-415e-b982-fafb56170b87)


# FlameGuardAI | AI-powered wildfire prevention
Source: https://docs.perplexity.ai/docs/cookbook/showcase/flameguardai

AI-powered wildfire prevention using OpenAI Vision + Perplexity Sonar API

<SonarDeprecationNotice />

## 🧠 What it does

**FlameGuard AI™** helps homeowners, buyers, and property professionals detect and act on **external fire vulnerabilities** like wildfires or neighboring structure fires. It's more than a scan — it's a personalized research assistant for your home.

### Demo

<iframe title="YouTube video player" />

### Try It Out

* [FlameGuard AI](https://flameguardai.dlyog.com)
* [GitHub Repo](https://github.com/dlyog/fire-risk-assessor-drone-ai)

### Key Features:

* 📸 Upload a home photo
* 👁️ Analyze visible fire risks via **OpenAI Vision API**
* 📚 Trigger deep research using the **Perplexity Sonar API**
* 📄 Get a detailed, AI-generated report with:
  * Risk summary
  * Prevention strategies
  * Regional best practices
* 🛠️ Optional contractor referrals for mitigation
* 💬 Claude (MCP) chatbot integration for conversational analysis
* 🧾 GDPR-compliant data controls

Whether you're protecting your home, buying a new one, or just want peace of mind — **FlameGuard AI™ turns a photo into a plan**.

## ⚙️ How it works

### The FlameGuard AI™ Process

1. **📸 Upload**: User uploads a photo of their property
2. **👁️ AI Vision Analysis**: OpenAI Vision API identifies specific vulnerabilities (e.g., flammable roof, dry brush nearby)
3. **🔍 Deep Research**: For each risk, we generate a **custom research plan** and run **iterative agentic-style calls** to Perplexity Sonar
4. **📄 Report Generation**: Research is **aggregated, organized, and formatted** into an actionable HTML report — complete with citations, links, and visual guidance
5. **📧 Delivery**: Detailed report sent via email with DIY solutions and professional recommendations

### 🔍 Deep Research with Perplexity Sonar API

The real innovation is how we use the **Perplexity Sonar API**:

* We treat it like a research assistant gathering the best available information
* Each vulnerability triggers multiple queries covering severity, mitigation strategies, and localized insights
* Results include regional fire codes, weather patterns, and local contractor availability

This kind of **structured, trustworthy, AI-powered research would not be possible without Perplexity**.

### Technical Stack

FlameGuard AI™ is powered by a modern GenAI stack and built to scale:

* **Frontend**: Lightweight HTML dashboard with user account control, photo upload, and report access
* **Backend**: Python (Flask) with RESTful APIs
* **Database**: PostgreSQL (local) with **Azure SQL-ready** schema
* **AI Integration**: OpenAI Vision API + Perplexity Sonar API
* **Cloud-ready**: Built for **Azure App Service** with Dockerized deployment

## 🏆 Accomplishments that we're proud of

* Successfully used **OpenAI Vision + Perplexity Sonar API** together in a meaningful, real-world workflow
* Built a functioning **MCP server** that integrates seamlessly with Claude for desktop users
* Created a product that is **genuinely useful for homeowners today** — not just a demo
* Kept the experience simple, affordable, and scalable from the ground up
* Made structured deep research feel accessible and trustworthy

## 📚 What we learned

* The **Perplexity Sonar API** is incredibly powerful when used agentically — not just for answers, but for reasoning.
* Combining **multimodal AI (image + research)** opens up powerful decision-support tools.
* Users want **actionable insights**, not just data — pairing research with guidance makes all the difference.
* Trust and clarity are key: our design had to communicate complex information simply and helpfully.

## 🚀 What's next for FlameGuard AI™ - Prevention is Better Than Cure

We're just getting started.

### Next Steps:

* 🌐 Deploy to **Azure App Services** with production-ready database
* 📱 Launch mobile version with location-based scanning
* 🏡 Partner with **home inspection services** and **homeowners associations**
* 💬 Enhance Claude/MCP integration with voice-activated AI reporting
* 💸 Introduce B2B plans for real estate firms and home safety consultants
* 🛡️ Expand database of **local contractor networks** and regional fire codes

We're proud to stand with homeowners — not just to raise awareness, but to enable action.

**FlameGuard AI™ – Because some homes survive when others don't.**

***

**Contact us to know more: [info@dlyog.com](mailto:info@dlyog.com)**


# Flow & Focus | Personalized News for Genuine Understanding
Source: https://docs.perplexity.ai/docs/cookbook/showcase/flow-and-focus

A personalized news app combining vertical feed discovery with AI-powered deep dives using Perplexity Sonar Pro and Deep Research models

<SonarDeprecationNotice />

**Flow & Focus** is a personalized news application that transforms news consumption into a learning experience. It uniquely combines rapid discovery through a vertical news feed (Flow) with in-depth, interactive learning dialogues (Focus), powered by Perplexity's Sonar Pro and Sonar Deep Research models.

<iframe title="YouTube video player" />

## Features

* **Dual Mode Interface**: Flow Feed for quick news discovery and Focus for personalized deep dives
* **Vertical News Feed**: Swipeable news snippets with AI-generated summaries, tags, and background images
* **Interactive Deep Dives**: Tap key phrases for focused content, with horizontally scrollable detail panes
* **Personalized Learning**: AI-powered conversation segments with personas like "Oracle" and "Explorer"
* **Smart Personalization**: Tracks reading patterns to tailor content selection automatically
* **Real-time Content**: Leverages Sonar Pro for up-to-date news and Sonar Deep Research for detailed analysis
* **Visual Enhancement**: Dynamic background images generated via Runware.ai based on content keywords

## Prerequisites

* Node.js 18+ and npm
* Perplexity API key
* Runware API key for image generation
* Next.js 15 and React 19 environment

## Installation

```bash theme={null}
# Clone the repository
git clone https://github.com/michitomo/NewsReel.git
cd NewsReel

# Install dependencies
npm install

# Set up environment variables
cp .env.example .env.local
```

## Configuration

Create `.env.local` file:

```ini theme={null}
PERPLEXITY_API_KEY=your_perplexity_api_key_here
RUNWARE_API_KEY=your_runware_api_key_here
PERPLEXITY_FOCUS_MODEL=sonar-deep-research
```

## Usage

1. **Start Development Server**:
   ```bash theme={null}
   npm run dev
   ```

2. **Access Application**: Open [http://localhost:3000](http://localhost:3000) in your browser

3. **Flow Feed**: Scroll vertically through news snippets and tap key phrases for deep dives

4. **Focus Mode**: Generate personalized digests with interactive conversation segments

5. **Personalization**: Your viewing patterns automatically influence content selection

## Code Explanation

* **Frontend**: Next.js 15 with React 19, Typescript, Tailwind CSS, and Framer Motion for animations
* **State Management**: Zustand with localStorage persistence for user preferences
* **AI Integration**: Perplexity Sonar Pro for real-time news and Sonar Deep Research for in-depth analysis
* **Image Generation**: Runware SDK integration for dynamic background images based on content keywords
* **API Routes**: Server-side integration handling Perplexity and Runware API calls
* **Mobile-First Design**: Swipe gestures and responsive layout for intuitive mobile experience

## Links

* [GitHub Repository](https://github.com/michitomo/NewsReel)
* [Demo Video](https://www.youtube.com/watch?v=09h7zluuhQI)
* [Perplexity Hackathon](https://perplexityhackathon.devpost.com/)
* [Perplexity Hackathon Project](https://devpost.com/software/flow-focus)


# Greenify | Localized community-driven greenification/plantation solution with AI
Source: https://docs.perplexity.ai/docs/cookbook/showcase/greenify

A mobile application that analyzes photos and location data to suggest suitable plants and build sustainable communities using Perplexity Sonar API

<SonarDeprecationNotice />

**Greenify** is a mobile application designed to encourage sustainable practices by analyzing live images and building communities. Users capture photos of their space (balcony, roadside, basement, etc.) and Greenify automatically analyzes the image using Perplexity's Sonar API to suggest suitable plants for that location. The app also connects like-minded people in the locality to create communities for sustainable, economic, and social growth.

<iframe title="YouTube video player" />

## Features

* **AI-Powered Plant Analysis** using image recognition and location data to suggest suitable plants
* **Location-Based Recommendations** considering weather, sunlight, and environmental conditions
* **Community Building** connecting users with similar plant interests and sustainable goals
* **Cross-Platform Mobile App** built with Expo for iOS, Android, and web
* **Real-time Weather Integration** for accurate plant suitability assessment
* **Structured JSON Output** using Pydantic models for consistent data handling
* **AR Model Support** for enhanced plant visualization

## Abstract Data Flow Diagram

![Abstract Data Flow Diagram](https://d112y698adiu2z.cloudfront.net/photos/production/software_photos/003/418/290/datas/gallery.jpg)

## Prerequisites

* Node.js 20.19.4+ and npm
* Python 3.10.0+ and pip
* Expo CLI and SDK 51+
* Perplexity API key (Sonar Pro and Sonar Deep Research)
* Android SDK/Studio or Xcode (for local builds)
* Mobile device with camera for image capture

## Installation

```bash theme={null}
# Clone the repository
git clone https://github.com/deepjyotipaulhere/greenify.git
cd greenify

# Install frontend dependencies
npm install

# Install backend dependencies
cd service
pip install -r requirements.txt
```

## Configuration

Create `.env` file in the `service` directory:

```ini theme={null}
PERPLEXITY_API_KEY=your_perplexity_api_key_here
```

## Usage

1. **Start Backend Service**:
   ```bash theme={null}
   cd service
   python app.py
   ```

2. **Start Frontend App**:
   ```bash theme={null}
   npx expo start
   ```

3. **Access the App**:
   * Install Expo Go app and scan QR code, or
   * Open web browser on mobile and navigate to the URL shown

4. **Use the App**:
   * Grant camera and location permissions
   * Take a photo of your space (balcony, garden, etc.)
   * Receive AI-powered plant recommendations
   * Connect with nearby users for community building

![demo](https://raw.githubusercontent.com/deepjyotipaulhere/greenify/refs/heads/master/assets/images/ezgif-4647c5467e6dac.gif)

## Code Explanation

* **Frontend**: React Native with Expo for cross-platform mobile development
* **Backend**: Python Flask API handling image processing and Perplexity API integration
* **AI Integration**: Perplexity Sonar Pro for image analysis and Sonar Deep Research for plant recommendations
* **Data Models**: Pydantic models for structured JSON output and data validation
* **Image Processing**: Real-time image analysis with location-based context
* **Community Features**: User matching based on plant suggestions and sustainable interests
* **Weather Integration**: Real-time weather data for accurate plant suitability assessment

## Links

* [GitHub Repository](https://github.com/deepjyotipaulhere/greenify)
* [Live Demo](https://greenify.expo.app)


# Monday – Voice-First AI Learning Assistant
Source: https://docs.perplexity.ai/docs/cookbook/showcase/monday

An accessible, multimodal AI learning companion that delivers contextual reasoning, 3D visualizations, and curated educational content via natural voice interaction.

<SonarDeprecationNotice />

**Monday** is a voice-enabled AI learning companion designed to bridge the gap between natural language queries and high-quality educational content. Inspired by Marvel's JARVIS and FRIDAY, Monday delivers tailored responses in three modes—Basic, Reasoning, and Deep Research—while integrating immersive visualizations, curated video content, and accessibility-first design.

## Features

* **Three Learning Modes**: Basic factual answers, step-by-step reasoning, and deep research investigations
* **Voice-first interaction** for hands-free learning with natural language processing
* **Real-time 3D visualizations** of concepts using Three.js & WebXR
* **Curated educational YouTube video integration** from trusted sources
* **Multi-modal feedback** combining text, speech (via ElevenLabs), and spatial panels
* **VR-optional design** for immersive experiences without requiring a headset
* **Accessibility-focused interface** for mobility- and vision-impaired users

## Prerequisites

* Node.js 18 LTS or newer
* Modern web browser (Chrome, Edge, or Firefox recommended)
* Microphone for voice interaction
* Optional: VR headset for immersive mode (WebXR compatible)
* Perplexity API key, ElevenLabs API key, and YouTube API key

## Installation

```bash theme={null}
# Clone the repository
git clone https://github.com/srivastavanik/monday.git
cd monday
git checkout final
cd nidsmonday

# Install dependencies
npm install
```

```ini theme={null}
# Create a .env file and set your API keys
PERPLEXITY_API_KEY=your_api_key
ELEVENLABS_API_KEY=your_api_key
YOUTUBE_API_KEY=your_api_key
```

```bash theme={null}
# Start Backend Server
node backend-server.js

# Start frontend
npm run dev
```

## Usage

1. Launch the app in your browser
2. Say **"Hey Monday"** to activate the assistant
3. Ask a question in one of three modes:
   * **Basic Mode** – "What is photosynthesis?"
   * **Reasoning Mode** – "Think about how blockchain works."
   * **Deep Research Mode** – "Research into the history of quantum mechanics."
4. View answers as floating text panels, voice responses, and interactive 3D models

## Code Explanation

* **Frontend**: Typescript with Three.js for 3D visualizations and WebXR for VR support
* **Backend**: Node.js with Socket.IO for real-time voice command processing
* **AI Integration**: Perplexity Sonar API for intelligent responses with reasoning extraction
* **Voice Processing**: ElevenLabs for speech synthesis and natural language understanding
* **Content Curation**: YouTube API integration with smart keyword extraction for educational videos
* **Accessibility**: Voice-first design with spatial audio and haptic feedback support

## Demo Video

<iframe title="YouTube video player" />


# MVP LifeLine | AI Youth Empowerment Platform
Source: https://docs.perplexity.ai/docs/cookbook/showcase/mvp-lifeline-ai-app

A multilingual, offline-first AI platform that helps underserved youth Earn, Heal, and Grow using real-time AI and holistic tools

<SonarDeprecationNotice />

**MVP LifeLine** is a multilingual, offline-first AI platform empowering youth emotionally, financially, and professionally—anytime, anywhere. Over 1.3 billion youth globally face barriers to career opportunities and mental well-being, especially in underserved and remote regions. MVP LifeLine breaks these barriers by combining AI, offline access, multilingual support, and a holistic tool ecosystem.

## Features

* **Dual Mode AI** with Career Coach and Emotional Companion powered by Perplexity Sonar API
* **Multilingual Support** across 10+ languages including English, French, Arabic, Spanish, Hindi, and regional languages
* **Offline-First Design** with SMS/USSD integration for low-connectivity regions
* **Holistic Tool Ecosystem** covering career, wellness, finance, and productivity
* **SmartQ Access** for context-aware, emotionally intelligent AI responses
* **Digital Hustle Hub** with AI gig discovery and freelancing tools
* **Wellness Zone** with guided meditations and mental reset prompts
* **Finance Zone** with budget tracking and youth-friendly money tips
* **Productivity Zone** with AI Kanban board and habit tracking

## Prerequisites

* Flutter SDK and Dart
* Firebase project setup
* Twilio account for SMS/USSD integration
* Perplexity API key (Sonar)
* OpenAI API key (for augmentation)

## Installation

```bash theme={null}
# Clone the repository
git clone https://github.com/JohnUmoh/asgard.git
cd asgard

# Install Flutter dependencies
flutter pub get

# Configure Firebase
flutterfire configure

# Set up environment variables
cp .env.example .env
```

## Configuration

Create `.env` file:

```ini theme={null}
PERPLEXITY_API_KEY=your_sonar_api_key
OPENAI_API_KEY=your_openai_api_key
FIREBASE_PROJECT_ID=your_firebase_project_id
TWILIO_ACCOUNT_SID=your_twilio_sid
TWILIO_AUTH_TOKEN=your_twilio_token
```

## Usage

1. **Setup Firebase**:
   ```bash theme={null}
   flutterfire configure
   ```

2. **Run the Application**:
   ```bash theme={null}
   flutter run
   ```

3. **Access Features**:
   * Switch between Career Coach and Emotional Companion modes
   * Use SmartQ for AI-powered assistance in multiple languages
   * Access offline features via SMS/USSD when connectivity is limited
   * Explore career tools, wellness features, and productivity boosters

## Code Explanation

* **Frontend**: Flutter cross-platform application with responsive design for mobile and web
* **Backend**: Firebase for authentication, data storage, and real-time synchronization
* **AI Integration**: Perplexity Sonar API for dual-mode AI interactions (Career Coach & Emotional Companion)
* **Offline Support**: Twilio integration for SMS/USSD communication in low-connectivity areas
* **Multilingual**: Sonar API handling 10+ languages with context-aware responses
* **Data Sync**: Offline data capture with automatic re-sync when connectivity returns
* **Personalization**: AI adapts to user's language, literacy level, mood history, and preferences

## Links

* [GitHub Repository](https://github.com/JohnUmoh/asgard)
* [Live Demo](https://mvplifelineaiapp.netlify.app)


# PerplexiCart | AI-Powered Value-Aligned Shopping Assistant
Source: https://docs.perplexity.ai/docs/cookbook/showcase/perplexicart

An AI shopping assistant that uses Perplexity Sonar to deliver structured research, value-aligned recommendations, and transparent citations across the web

<SonarDeprecationNotice />

**PerplexiCart** helps users make informed, value-aligned purchasing decisions. Powered by the **Perplexity Sonar API**, it analyzes products across the web and returns structured insights with prioritized recommendations, pros/cons, trade‑off analysis, and user sentiment — tailored to preferences like Eco‑Friendly, Durability, Ethical, and region‑specific needs.

<iframe title="YouTube video player" />

## Features

* **Intelligent Product Recommendations** beyond simple spec comparison
* **Priority-Based Value Alignment** (Best Value, Eco‑Friendly, Ethical, Durability, Made in India)
* **Contextual Personalization** (skin type, usage patterns, region, etc.)
* **Structured Research Output** with:
  * Research summary and top recommendations
  * Value alignment with reasoning
  * Pros/Cons and key specifications
  * User sentiment and community insights (Reddit, Quora)
  * Trade‑off analysis and buying tips
* **Transparent Sources** with citations for verification

## Prerequisites

* Node.js 18+ and npm/yarn
* Python 3.10+ and pip
* Perplexity API key

## Installation

```bash theme={null}
# Clone the repository
git clone https://github.com/fizakhan90/perplexicart.git
cd perplexicart

# Backend (FastAPI) setup
cd backend
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install -r requirements.txt

# Frontend (Next.js) setup
cd ../frontend
npm install
```

## Configuration

Create a `.env` file in the backend directory:

```ini theme={null}
PERPLEXITY_API_KEY=your_perplexity_api_key
```

(Optional) Add any app‑specific settings as needed (cache, region defaults, etc.).

## Usage

1. **Start Backend (FastAPI)**:
   ```bash theme={null}
   cd backend
   uvicorn main:app --reload  # adapt module:app if your entrypoint differs
   ```

2. **Start Frontend (Next.js)**:
   ```bash theme={null}
   cd frontend
   npm run dev
   ```

3. **Open the App**: Visit `http://localhost:3000` and search for a product. Select your priority (e.g., Eco‑Friendly) and add optional context (skin type, region).

## Code Explanation

* **Backend (FastAPI)**: Orchestrates Sonar calls with dynamic prompt engineering based on query, selected priority, and context
* **Structured Outputs**: Enforces a strict JSON schema via `response_format` to ensure consistent UI rendering
* **Live Web Research**: Directs Sonar to search e‑commerce platforms, forums, review blogs, and sustainability reports
* **Semantic Analysis**: Extracts value alignment, pros/cons, sentiment, and cites sources for transparency
* **Frontend (Next.js/React)**: Presents a clear, user‑friendly view of recommendations, trade‑offs, and citations

## How the Sonar API Is Used

PerplexiCart leverages the **Perplexity Sonar API** as its intelligence core, dynamically generating customized prompts based on user inputs like search queries, priorities and context. The API performs comprehensive web research across e-commerce sites, forums, and review platforms, with responses structured in a consistent JSON format. Through semantic analysis, it extracts key product insights including alignment with user priorities, pros/cons, and sentiment - all backed by cited sources. The FastAPI backend processes these structured responses before serving them to the Next.js frontend for a polished user experience.

## Links

* **Live Demo**: [https://perplexicart.vercel.app/](https://perplexicart.vercel.app/)
* **GitHub Repository**: [https://github.com/fizakhan90/perplexicart](https://github.com/fizakhan90/perplexicart)


# PerplexiGrid | Interactive Analytics Dashboards
Source: https://docs.perplexity.ai/docs/cookbook/showcase/perplexigrid

Instantly generate analytics dashboards from natural language using live data via Perplexity Sonar API.

<SonarDeprecationNotice />

**PerplexiGrid** turns natural language into rich, interactive dashboards. Connect your data and mix it with live web data, ask a question, and let the Sonar API do the rest! Complete with drag-and-drop layout, AI widget generation, and ECharts-powered visualizations.

## Features

* **Natural Language to Dashboards**: Convert plain English prompts into fully functional analytics dashboards with 25+ widget types
* **Live Data Integration**: Blend your own data sources with real-time web data for comprehensive insights
* **Interactive Grid Layout**: Drag-and-drop interface for customizing dashboard layouts and styling
* **AI-Powered Refinement**: Refine or add widgets using conversational updates
* **Export & Share**: Generate PDF exports, high-res images, and shareable dashboard links

## How it uses Sonar

PerplexiGrid leverages the Sonar API through four specialized modes:

* **Full Dashboard Generation (f1)**: Creates comprehensive dashboards with multiple widgets using Sonar Pro's advanced capabilities
* **Lightweight Mode (l1)**: Generates quick visualizations for embedded systems and real-time applications
* **Dashboard Updates (r1)**: Enables dynamic modifications through natural language while maintaining context
* **Widget Refinement (r2)**: Provides precise control over individual widget updates

The system uses structured JSON schema responses to ensure consistent, ECharts-compatible output that can be directly rendered as interactive visualizations.

## Usage

1. Open the app and start a new dashboard
2. Prompt it like: *"Show me market trends in AI startups in 2024"*  (Sonar generates chart configs, which are parsed and rendered as live widgets)

![Prompt #1](https://www.perplexigrid.com/guide/prompt_dark.gif)

3. Rearrange and style the widgets with the grid interface

![Prompt #2](https://www.perplexigrid.com/guide/move_dark.gif)
![Prompt #3](https://www.perplexigrid.com/guide/customize_dark.gif)

5. Add your own datasources to blend your data with live web data

![Prompt #4](https://www.perplexigrid.com/guide/datasource_dark.gif)

6. Refine them via text prompts or export the dashboard as needed
7. Collaborate and share easily

![Prompt #5](https://www.perplexigrid.com/guide/invite_dark.gif)

## Code Explanation

The user sends messages that are turned into prompts to a Supabase Edge Function that wraps the Perplexity Sonar API.\
Depending on the mode (`f1`, `l1`, `r1`, or `r2`), the function generates full structured outputs for dashboards, lightweight visualizations, or targeted updates.\
The generated layout is parsed into structured widget definitions and passed through our widget creation engine.

Explore our [main sonar-api service here.](https://github.com/PetarRan/perplexigrid/blob/main/server/supabase/functions/_shared/perplexityService.ts)

## Prompt Modes

| Mode | Description                          | Use Case                                                               | Notes                                                                     |
| ---- | ------------------------------------ | ---------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `f1` | First-time full dashboard generation | User starts with an empty canvas and enters an initial prompt          | Produces a complete dashboard layout with multiple widgets                |
| `l1` | Lightweight dashboard generation     | Used for quick insights or previews with minimal tokens                | Faster and cheaper, but returns fewer widgets with less instruction depth |
| `r1` | Full dashboard regeneration          | User wants to replace all existing widgets with a new prompt           | Rebuilds the entire dashboard while keeping layout intact                 |
| `r2` | Targeted widget update               | User wants to change a specific widget (e.g., "make this a pie chart") | Only the selected widget is modified based on the new instruction         |

## Tech Stack

* **Frontend**: React + Vite (Typescript), ECharts, react-grid-layout
* **Backend**: Supabase Edge Functions (Typescript on Deno)
* **AI Engine**: Perplexity Sonar Pro
* **Infrastructure**: Supabase (PostgreSQL, RLS, Auth), Vercel deployment

## Links

* [GitHub Repository](https://github.com/PetarRan/perplexigrid)
* [Live Demo](https://app.perplexigrid.com)
* [Website](https://www.perplexigrid.com)


# Perplexity Client | Desktop AI Chat Interface with API Controls
Source: https://docs.perplexity.ai/docs/cookbook/showcase/perplexity-client

An Electron-based desktop client for Perplexity API with advanced features like model selection, custom system prompts, and API debugging mode

<SonarDeprecationNotice />

**Perplexity Client** is an Electron-based desktop application that provides a polished interface for interacting with Perplexity's Sonar API. It exposes advanced API parameters like max tokens, making it ideal for developers who want fine-grained control over their AI interactions while enjoying a beautiful, macOS-inspired UI.

<img alt="Perplexity Client Interface" />

## Features

* **Multiple Sonar Models** with support for Sonar, Sonar Pro, and Sonar Reasoning Pro
* **Custom Spaces** with save/load functionality for different use cases
* **API Parameter Controls** including max tokens adjustments
* **API Debugging Mode** showing full request/response payloads for troubleshooting
* **Token Usage Tracking** to monitor API consumption and costs
* **Focus Modes** for specialized tasks like coding, writing, and research

## Prerequisites

* Node.js v16 or higher
* npm or yarn
* Perplexity API key

## Installation

```bash theme={null}
# Clone the repository
git clone https://github.com/straight-heart/Perplexity-client-.git
cd Perplexity-client-

# Install dependencies
npm install

npm run dev
```

## Build

Build the application for your platform:

```bash theme={null}
npm run build:win    # Windows
npm run build:mac    # macOS
npm run build:linux  # Linux
```

## Configuration

API keys are managed directly within the application:

1. Launch the app and open Settings (gear icon)
2. In the **API Keys** section, click **Add Key**
3. Enter your Perplexity API key
4. The key is stored securely and persists across sessions

For custom system prompts, use the **Spaces** feature to save and switch between different instruction sets.

## Usage

1. **Launch**: Run `npm run dev` or use the built application
2. **Add API Key**: Open Settings and add your Perplexity API key
3. **Select Model**: Use the dropdown to choose between Sonar variants
4. **Create Spaces**: Set up custom system prompts for different tasks
5. **Chat**: Start conversing with real-time streaming responses
6. **Debug**: Enable API debugging to see full request/response details
7. **Track Usage**: Monitor token consumption in the Settings panel

## Screenshots

| Feature                      | Preview                  |
| ---------------------------- | ------------------------ |
| Spaces (Custom Instructions) | <img alt="Spaces" />     |
| Model & Parameter Controls   | <img alt="Parameters" /> |
| API Debugging Mode           | <img alt="Debug" />      |
| Theme Selection              | <img alt="Themes" />     |

## Limitations

* Desktop only (Windows, macOS, Linux) — no mobile or web version
* Requires internet connection for API calls
* API key required for functionality

## Links

* [GitHub Repository](https://github.com/straight-heart/Perplexity-client-)


# Perplexity Dart & Flutter SDKs
Source: https://docs.perplexity.ai/docs/cookbook/showcase/perplexity-flutter

Lightweight, type-safe SDKs for seamless Perplexity API integration in Dart and Flutter applications

<SonarDeprecationNotice />

# Perplexity Dart & Flutter SDKs

**Perplexity Dart & Flutter SDKs** provide a comprehensive toolkit for integrating Perplexity's AI capabilities into Dart and Flutter applications. Built specifically for the Flutter community, these packages include a lightweight core API client and ready-to-use Flutter widgets with BLoC state management.

## Features

* Type-safe API client with fully typed models and compile-time safety
* Streaming and non-streaming chat completions with real-time response handling
* Support for all Perplexity models (Sonar, Sonar Pro, Deep Research, Reasoning variants)
* Multi-image processing with base64, data URI, and HTTPS URL support
* Ready-to-use Flutter widgets with BLoC state management integration
* Advanced configuration options (search filters, domain restrictions)
* Cross-platform support for iOS, Android, Web, and Desktop
* Future-proof design with custom model string support for new Perplexity releases

## Prerequisites

* Dart SDK 2.17.0 or newer
* Flutter SDK 3.0.0 or newer (for Flutter-specific features)
* Perplexity API key from Perplexity API Console
* Basic knowledge of Flutter BLoC pattern for widget integration

## Installation

### For Dart Projects (Core API Only)

```bash theme={null}
dart pub add perplexity_dart
```

### For Flutter Projects (Full Widget Support)

```bash theme={null}
flutter pub add perplexity_flutter
```

### Environment Variables

```dart theme={null}
// Add to your app's configuration
const String perplexityApiKey = 'your_perplexity_api_key_here';
```

## Usage

### Core API Integration

* Type-safe client with all Perplexity models (Sonar, Sonar Pro, Deep Research, Reasoning)
* Streaming and non-streaming chat completions
* Multimodal processing with flexible MessagePart system for text + images

### Flutter Widget Layer

* `ChatWrapperWidget` for BLoC state management
* `PerplexityChatView` for real-time message display
* `PerplexityChatInput` for user interaction handling

## Code Explanation

* Core Layer: Pure Dart API client (`perplexity_dart`) for cross-platform Perplexity API integration
* UI Layer: Flutter widgets (`perplexity_flutter`) with BLoC state management for rapid development
* Type Safety: Fully typed models and responses prevent runtime errors and provide IntelliSense
* Multimodal: Flexible MessagePart system for combining text and images in single requests
* Streaming: Built-in support for real-time chat completions with proper chunk handling
* Architecture: Two-layer design allows lightweight API usage or full Flutter widget integration

## Architecture

### Two-Layer Design

* **Core (`perplexity_dart`)** - Pure Dart API client for all platforms
* **UI (`perplexity_flutter`)** - Flutter widgets + BLoC state management

Uses flexible MessagePart system for multimodal content combining text and images.

## Links

### Packages

* [perplexity\_dart on pub.dev](https://pub.dev/packages/perplexity_dart) | [GitHub](https://github.com/vishnu32510/perplexity_dart)
* [perplexity\_flutter on pub.dev](https://pub.dev/packages/perplexity_flutter) | [GitHub](https://github.com/vishnu32510/perplexity_flutter)

### Examples

* [Flutter Example App](https://github.com/vishnu32510/perplexity_dart/tree/main/example_flutter_app)
* [Dart Examples](https://github.com/vishnu32510/perplexity_dart/tree/main/example)


# Perplexity Lens | AI-Powered Knowledge Graph Browser Extension
Source: https://docs.perplexity.ai/docs/cookbook/showcase/perplexity-lens

A browser extension that builds personalized knowledge graphs using Perplexity AI for smart text selection, webpage summarization, and contextual insights

<SonarDeprecationNotice />

**Perplexity Lens** is a powerful browser extension that transforms your browsing experience by providing AI-powered insights using Perplexity AI and creating a personalized knowledge graph that visually connects the concepts you encounter online.

<iframe title="YouTube video player" />

## Features

* **Smart Text Selection** with AI-generated explanations for selected text
* **Webpage Summarization** for instant, concise overviews of entire pages
* **Contextual RAG Insights** using Retrieval-Augmented Generation for detailed context and meanings
* **Knowledge Graph Visualization** with interactive D3.js graphs showing concept connections
* **Public Sharing** with URL generation for sharing graphs with others
* **User Authentication** via Firebase for secure access
* **Dual Storage** with local IndexedDB and cloud Firebase storage
* **Responsive UI** fully functional across all devices

## Prerequisites

* Node.js v14+ and npm v6+
* Google Chrome or compatible browser
* Firebase account for cloud functionality
* Firebase CLI (`npm install -g firebase-tools`)
* Perplexity API key and OpenAI API key

## Installation

```bash theme={null}
# Clone the repository
git clone https://github.com/iamaayushijain/perplexity-lens.git
cd perplexity_lens

# Install dependencies
npm install

# Build the extension
npm run build
```

## Configuration

Edit `src/config.ts`:

```typescript theme={null}
export const PERPLEXITY_API_KEY = 'your-perplexity-key';
export const EMBEDDING_API_KEY = 'your-openai-key';
export const FIREBASE_HOSTING_URL = 'https://your-project-id.web.app';
```

## Usage

1. **Load Extension**: Go to `chrome://extensions/`, enable Developer mode, click "Load unpacked" and select the `dist/` directory

2. **Sign In**: Click the extension icon and authenticate via Firebase

3. **Use Features**:
   * **Highlight Text**: Select text on any webpage for AI-powered insights
   * **Summarize Page**: Use the "Summarize" feature for webpage overviews
   * **Ask Anything**: Hover or click on words/phrases for definitions or explanations
   * **View Graph**: Navigate to the Graph tab to see your knowledge graph
   * **Explore**: Zoom, drag, and hover over nodes in the interactive graph
   * **Share**: Click "Share Graph" to generate a public link

## Code Explanation

* **Frontend**: React with Typescript and TailwindCSS for modern, responsive UI
* **Browser Extension**: Chrome extension architecture with popup and content scripts
* **AI Integration**: Perplexity AI for intelligent text explanations and summarization
* **Knowledge Graph**: D3.js for interactive graph visualization and concept connections
* **Storage**: Dual storage system with local IndexedDB and cloud Firebase
* **Authentication**: Firebase Auth for secure user access and data management
* **RAG System**: Retrieval-Augmented Generation for contextual insights and definitions

## Links

* [GitHub Repository](https://github.com/iamaayushijain/perplexity-lens)
* [Blog Post](https://ashjin.hashnode.dev/perplexity-lens-supercharge-your-web-experience-with-personalized-knowledge-graphs)


# PosterLens | Scientific Poster Scanner & Research Assistant
Source: https://docs.perplexity.ai/docs/cookbook/showcase/posterlens

An iOS app that transforms static scientific posters into interactive insights using OCR and Perplexity's Sonar Pro API for semantic search and context

<SonarDeprecationNotice />

**PosterLens** is an iOS app that transforms static scientific posters into interactive, explorable insights using OCR and AI. Created for the Perplexity Hackathon 2025, it allows researchers, MSLs, and medical writers to scan posters and explore them interactively using natural language, extracting meaning and surfacing related studies instantly.

![PosterLens Screenshot](https://cdn.prod.website-files.com/66d49e8555a289120a81ec3e/68930ad938e072c05d1be0b9_PosterLens.png)

## Features

* **Scientific Poster Scanning** using device camera and Apple Vision OCR
* **Natural Language Q\&A** about poster content with AI-powered responses
* **Semantic Search Integration** using Perplexity Sonar Pro for related studies
* **Citation Validation** with PubMed E-utilities for academic accuracy
* **Auto-Generated Research Questions** and future research directions
* **On-Device Processing** for privacy and performance
* **Interactive Research Experience** transforming static content into dynamic insights

## Prerequisites

* iOS 17+ device with camera
* Xcode 15+ for development
* Apple Developer account for App Store distribution
* Perplexity API key (Sonar Pro)
* OpenAI API key (GPT-3.5)
* PubMed E-utilities access

## Installation

```bash theme={null}
# Clone the repository
git clone https://github.com/nickjlamb/PosterLens.git
cd PosterLens

# Open in Xcode
open PosterLens.xcodeproj
```

## Configuration

Add your API keys to the project configuration:

```swift theme={null}
// API Configuration
PERPLEXITY_API_KEY=your_sonar_pro_api_key
OPENAI_API_KEY=your_gpt_api_key
PUBMED_API_KEY=your_pubmed_api_key
```

## Usage

1. **Install from App Store**: Download PosterLens from the iOS App Store
2. **Scan Poster**: Point your camera at a scientific poster
3. **OCR Processing**: Apple Vision automatically extracts text content
4. **Ask Questions**: Use natural language to query the poster content
5. **Explore Related Research**: Discover semantically related studies via Sonar Pro
6. **Validate Citations**: Check academic references with PubMed integration

## Code Explanation

* **Frontend**: Native iOS app built with SwiftUI for modern UI/UX
* **OCR Processing**: Apple Vision framework for text extraction from images
* **AI Integration**: Perplexity Sonar Pro API for semantic search and context understanding
* **Natural Language**: GPT-3.5 for Q\&A and content interpretation
* **Academic Validation**: PubMed E-utilities for citation verification
* **On-Device Processing**: Local OCR and processing for privacy and performance
* **Research Enhancement**: Auto-generation of research questions and future directions

## Links

* [GitHub Repository](https://github.com/nickjlamb/PosterLens)
* [App Store](https://apps.apple.com/us/app/posterlens-research-scanner/id6745453368)


# Sonar Chromium Browser | Native Search Omnibox and Context Menu
Source: https://docs.perplexity.ai/docs/cookbook/showcase/sonar-chromium-browser

Chromium browser patch with native Perplexity Sonar API integration providing omnibox answers and context-menu summarization

<SonarDeprecationNotice />

**Sonar Chromium Browser** is a Chromium browser patch that natively integrates Perplexity's Sonar API to provide AI-powered functionality directly in the browser. Users can type `sonar <query>` in the omnibox for instant AI answers or select text and right-click "Summarize with Sonar" for quick summaries, streamlining research and browsing workflows.

## Features

* **Omnibox AI Answers** with `sonar <query>` syntax for instant responses
* **Context-menu Summarization** for selected text with one-click access
* **Native Browser Integration** using Chromium's omnibox and context-menu APIs
* **Dual Model Support** using Sonar Pro for omnibox and Sonar for summaries
* **Debounced Input Handling** for efficient API usage
* **Custom Browser Build** demonstrating AI integration patterns

## Prerequisites

* Ubuntu 22.04 (WSL2 recommended)
* Chromium source code checkout
* Perplexity API key
* 16GB+ RAM for Chromium build
* Git and standard build tools

## Installation

```bash theme={null}
# Clone the repository
git clone https://github.com/KoushikBaagh/perplexity-hackathon-chromium.git
cd perplexity-hackathon-chromium

# Apply patches to Chromium source
# Follow the README for detailed Chromium setup instructions
```

## Configuration

Update API keys in the modified files:

```cpp theme={null}
// In sonar_autocomplete_provider.cc and render_view_context_menu.cc
const std::string API_KEY = "your_perplexity_api_key_here";
```

## Usage

1. **Build Chromium** with applied patches following the repository instructions
2. **Launch the custom browser** with AI integration
3. **Use Omnibox AI**: Type `sonar what is quantum tunneling?` in address bar
4. **Use Context Summarization**: Select text, right-click "Summarize with Sonar"

## Code Explanation

* **Omnibox Integration**: Custom autocomplete provider hooking into Chromium's omnibox API
* **Context Menu**: Modified render view context menu for text summarization
* **API Integration**: Direct Perplexity Sonar API calls with debounced input handling
* **Model Selection**: Sonar Pro for omnibox queries, Sonar for text summarization
* **Browser Architecture**: Demonstrates Chromium extension points for AI features
* **Build Process**: Custom Chromium build with AI patches applied

## Demo Video

<iframe title="YouTube video player" />

## Links

* [GitHub Repository](https://github.com/KoushikBaagh/perplexity-hackathon-chromium)
* [Chromium Gerrit Repository](https://chromium-review.googlesource.com/c/chromium/src/+/6778540)


# StarPlex | AI-Powered Startup Intelligence Platform
Source: https://docs.perplexity.ai/docs/cookbook/showcase/starplex

An AI-powered startup intelligence platform that helps entrepreneurs validate their business ideas and find the right resources to succeed

<SonarDeprecationNotice />

**StarPlex** is an AI-powered startup intelligence platform that helps entrepreneurs validate their business ideas and connect with the resources they need to succeed. Powered primarily by **Perplexity Sonar Pro**, it features an interactive **3D globe interface** as its main UI. Simply enter your startup idea, and watch as the AI engine analyzes and visualizes insights directly on the globe—mapping out competitors, markets, demographics, VCs, and potential co-founders across the world in real-time.

<iframe title="StarPlex Demo" />

## Features

* **Market Validation Analysis** with AI-proof scoring, market cap estimation, and growth trend analysis
* **Interactive 3D Globe Interface** for visualizing global startup intelligence data
* **Competitor Research** with threat scoring and competitive landscape mapping
* **VC & Investor Matching** based on investment thesis and portfolio alignment
* **Co-founder Discovery** with compatibility scoring and expertise matching
* **Demographic Research** with heatmap visualization of target audience locations
* **AI Pitch Deck Generation** creating investor-ready presentations
* **Context-Aware Chatbot** with RAG integration across all research data

## Prerequisites

* Node.js 18+ and npm
* Python 3.8+ and pip
* Perplexity API key (Sonar Pro)
* Mapbox token and SERP API key

## Installation

```bash theme={null}
# Clone the repository
git clone https://github.com/JerryWu0430/StarPlex.git
cd StarPlex

# Backend setup
cd backend
pip install -r requirements.txt

# Frontend setup
cd ../frontend
npm install
```

## Configuration

Create `.env` file in the backend directory:

```ini theme={null}
PERPLEXITY_API_KEY=your_perplexity_api_key
MAPBOX_TOKEN=your_mapbox_token
SERPAPI_KEY=your_serpapi_key
```

## Usage

1. **Start Backend**:
   ```bash theme={null}
   cd backend
   python main.py
   ```

2. **Start Frontend**:
   ```bash theme={null}
   cd frontend
   npm run dev
   ```

3. **Access Application**: Open [http://localhost:3000](http://localhost:3000) and enter your startup idea

4. **Explore Intelligence**: Use the 3D globe to visualize competitors, VCs, demographics, and co-founders

5. **Generate Assets**: Create pitch decks and chat with the AI assistant about your analysis

## How StarPlex Uses Perplexity Sonar API

StarPlex leverages Perplexity's Sonar API through a **multi-module intelligence architecture**:

**Market Analysis Engine**
Uses Sonar Pro for comprehensive market validation, combining Google Trends data with AI analysis to generate market cap estimates, AI-disruption scores, and growth projections with structured JSON outputs.

**Competitor Intelligence**
Employs multiple concurrent Sonar queries to identify competing companies, funding status, and threat levels. Each competitor receives a 1-10 threat score with detailed competitive positioning analysis.

**VC & Co-founder Matching**
Leverages Sonar's real-time web knowledge to find relevant investors and potential co-founders, scoring matches based on investment thesis alignment, expertise fit, and geographic proximity.

**Context-Aware Business Assistant**
Implements RAG (Retrieval-Augmented Generation) by feeding all research data into Sonar conversations, creating a knowledgeable startup advisor that can answer questions about market positioning, competitive threats, and strategic decisions.

**Geographic Intelligence**
Combines Sonar's demographic insights with Mapbox geocoding to create interactive heatmaps showing where target audiences are concentrated globally.

## Code Explanation

* **Backend**: Python FastAPI with AsyncIO for concurrent Perplexity API calls across multiple analysis modules
* **Frontend**: Next.js with React 19, featuring Cobe for 3D globe visualization and Mapbox GL for interactive mapping
* **AI Integration**: Multi-model Perplexity strategy using Sonar Pro for complex analysis and Sonar for faster queries
* **Data Pipeline**: Intelligent caching, structured JSON responses, and real-time streaming for immediate user feedback
* **Visualization**: Dynamic data binding between Perplexity insights and interactive globe/map interfaces

## Links

* [GitHub Repository](https://github.com/JerryWu0430/StarPlex)
* [Live Demo](https://starplex.app)
* [Devpost Submission](https://devpost.com/software/starplex)


# TruthTracer | AI-Powered Misinformation Detection Platform
Source: https://docs.perplexity.ai/docs/cookbook/showcase/truth-tracer

A comprehensive misinformation detection platform that uses Perplexity's Sonar API to analyze claims, trace trust chains, and provide Socratic reasoning for fact verification

<SonarDeprecationNotice />

**TruthTracer** is a comprehensive misinformation detection platform that leverages Perplexity's Sonar API to provide multi-layered claim analysis. The platform combines fact-checking, trust chain tracing, and Socratic reasoning to deliver accurate, evidence-based verification results with confidence scores and detailed sourcing.

### Demo

<iframe title="YouTube video player" />

## Features

* **Multi-method Analysis** combining fact-checking, trust chain analysis, and Socratic reasoning
* **AI-Powered Verification** using Perplexity's Sonar, Sonar Deep Research, and Sonar Reasoning Pro models
* **Real-time Processing** with parallel execution of multiple analysis methods
* **Evidence-based Results** providing sources, confidence scores, and detailed reasoning
* **Clean Architecture** with NestJS backend and React frontend
* **Production-Ready** with Docker deployment, comprehensive testing, and API documentation
* **Configurable Confidence Scoring** with customizable weights and thresholds

## Prerequisites

* Node.js 18+ and npm
* Perplexity API key (Sonar models access)
* Docker (optional for deployment)
* Git for repository cloning

## Installation

```bash theme={null}
# Clone the backend repository
git clone https://github.com/anthony-okoye/truth-tracer-backend.git
cd truth-tracer-backend

# Install dependencies
npm install

# Clone the frontend repository
git clone https://github.com/anthony-okoye/truth-tracer-front.git
cd truth-tracer-front

# Install frontend dependencies
npm install
```

## Configuration

Create `.env` file in the backend directory:

```ini theme={null}
# Required
SONAR_API_KEY=your_perplexity_api_key
SONAR_API_URL=https://api.perplexity.ai

# Optional configuration
SONAR_TIMEOUT=30000
SONAR_MAX_RETRIES=3
CONFIDENCE_WEIGHT_FACT_CHECK=0.35
CONFIDENCE_WEIGHT_TRUST_CHAIN=0.25
CONFIDENCE_WEIGHT_SOCRATIC=0.20
```

## Usage

1. **Start Backend**:

```bash theme={null}
   cd truth-tracer-backend
   npm run start:dev
```

2. **Start Frontend**:

```bash theme={null}
   cd truth-tracer-front
   npm start
```

3. **Access Application**: Open [http://localhost:3000](http://localhost:3000) in your browser

4. **Analyze Claims**:
   * Enter a claim in the text area
   * Click "Analyze Claim" to run fact-checking, trust chain analysis, and Socratic reasoning
   * View results with confidence scores, sources, and detailed explanations

## Code Explanation

* **Backend**: NestJS application with clean architecture following Typescript best practices
* **AI Integration**: Perplexity Sonar API with three specialized models - Sonar for fact-checking, Sonar Deep Research for trust chain analysis, and Sonar Reasoning Pro for logical evaluation
* **Parallel Processing**: Simultaneous execution of all three analysis methods for efficient claim verification
* **Response Sanitization**: Custom JSON parsing and validation to handle various API response formats
* **Confidence Scoring**: Weighted scoring system combining results from all three analysis methods
* **Frontend**: React application with intuitive claim submission interface and detailed results visualization
* **Testing**: Comprehensive test suite including unit tests, end-to-end tests, and claim analysis testing

## How the Sonar API Is Used

TruthTracer leverages Perplexity's Sonar API through three distinct analysis approaches:

```typescript theme={null}
// Parallel execution of multiple Sonar models
const [factCheckResult, trustChainResult, socraticResult] = await Promise.all([
  sonarClient.chat.completions.create({
    model: "sonar",
    messages: [{ role: "user", content: factCheckPrompt }],
    max_tokens: 500
  }),
  sonarClient.chat.completions.create({
    model: "sonar-deep-research", 
    messages: [{ role: "user", content: trustChainPrompt }],
    max_tokens: 2500
  }),
  sonarClient.chat.completions.create({
    model: "sonar-reasoning-pro",
    messages: [{ role: "user", content: socraticPrompt }],
    max_tokens: 4000
  })
]);
```

## Links

* [Live Demo](https://truthtracer.netlify.app/)
* [Backend Repository](https://github.com/anthony-okoye/truth-tracer-backend)
* [Frontend Repository](https://github.com/anthony-okoye/truth-tracer-front)


# UnCovered | Real-Time Fact-Checking Chrome Extension
Source: https://docs.perplexity.ai/docs/cookbook/showcase/uncovered

A Chrome extension that brings real-time fact-checking to anything you see online in just 2 clicks, powered by Perplexity's Sonar API for instant verification

<SonarDeprecationNotice />

**UnCovered** is a Chrome extension that verifies text, images, websites, and screenshots in real-time—right where you browse. Built on Perplexity's Sonar API, it provides instant truth with citations, verdicts, and deep analysis using just a right-click, without breaking your browsing flow.

## Features

* **3-Click Verification**: Select → Right-click → Verify (Text, Image, Link, or Screenshot)
* **Text Analysis Modes**: Quick Search, Fact-Check, and Deep Research capabilities
* **Image Fact-Checking**: Reverse image analysis and multimodal claim verification
* **Screenshot & Video Frame Capture**: Analyze visuals like infographics, memes, or chart snapshots
* **Citation-Backed Results**: All answers include sources and fact-verdicts (True/False/Unconfirmed)
* **Instant Rebuttal Generator**: Create concise, fact-based replies to misinformation
* **Zero-Friction UX**: Stay on the same page — no copy-paste, no new tabs required

## Prerequisites

* Chrome browser
* Node.js 16+ and npm
* MongoDB database
* Cloudinary account for image storage
* Perplexity API key (Sonar Pro and Deep Research access)
* Google OAuth credentials

## Installation

```bash theme={null}
# Clone the repository
git clone https://github.com/aayushsingh7/UnCovered.git
cd UnCovered

# Install dependencies
npm install

# Build the Chrome extension
npm run build
```

## Configuration

Set up your environment variables:

```ini theme={null}
PERPLEXITY_API_KEY=your_sonar_api_key
MONGODB_URI=your_mongodb_connection_string
CLOUDINARY_URL=your_cloudinary_credentials
GOOGLE_OAUTH_CLIENT_ID=your_google_oauth_id
```

## Usage

1. **Text/Link Verification**:
   * Select text or right-click a link
   * Choose Quick Search / Fact-Check / Deep Research
   * Get trusted results with verdicts and citations

2. **Image Verification**:
   * Right-click any image
   * Choose from Quick Search or Fact-Check
   * Detect misinformation and visual manipulation

3. **Screenshot/Infographic Analysis**:
   * Click UnCovered icon in the toolbar
   * Use "Capture Screen" to analyze visual content

4. **Get Instant Rebuttal**:
   * Auto-generate fact-based responses to correct misinformation

## Code Explanation

* **Frontend**: Vanilla JavaScript Chrome extension with context menu integration
* **Backend**: Node.js Express server handling API requests and user authentication
* **AI Integration**: Perplexity Sonar Pro and Deep Research APIs for intelligent fact-checking
* **Image Processing**: Cloudinary integration for screenshot and image analysis
* **Database**: MongoDB for user data and verification history
* **Authentication**: Google OAuth for secure user management
* **Multimodal Analysis**: Support for text, images, screenshots, and video frames

## Technical Implementation

UnCovered leverages Perplexity Sonar API in three core modes:

```javascript theme={null}
// Quick Search and Fact-Check with Sonar Pro
const quickResponse = await perplexityClient.chat.completions.create({
  model: "sonar-pro",
  messages: [{ role: "user", content: factCheckPrompt }]
});

// Deep Research for comprehensive analysis
const deepResponse = await perplexityClient.chat.completions.create({
  model: "sonar-deep-research", 
  messages: [{ role: "user", content: deepAnalysisPrompt }]
});
```

## Demo Video

<iframe title="UnCovered Demo" />

## Links

* [GitHub Repository](https://github.com/aayushsingh7/UnCovered)
* [Live Demo](https://uncovered.vercel.app)


# Valetudo AI | Trusted Medical Answer Assistant
Source: https://docs.perplexity.ai/docs/cookbook/showcase/valetudo-ai

Sonar-powered medical assistant for fast, science-backed answers.

<SonarDeprecationNotice />

# Valetudo AI

**Valetudo AI** is a science-backed medical assistant powered by the Perplexity Sonar API. It provides fast, clear, and well-cited answers to health questions — helping users cut through misinformation with filters, image analysis, and ready-made prompt templates.

Designed for conscious users — like parents, patients, and medical students — seeking reliable information.

## Features

* **Cited Answers** — sourced from a curated list of 10 trusted medical domains
* **Smart Filters** — by date and country for localized, up-to-date insights
* **Image Upload** — analyze photos of medication, conditions, or packaging
* **Prompt Templates** — 7 categories for symptom checks, drug safety, research, and more
* **Simple UI** — built with React and Tailwind CSS

## How It Uses the Sonar API

Valetudo AI integrates with [Perplexity Sonar Pro](https://docs.perplexity.ai), leveraging advanced features for domain-specific search and rich responses:

| Feature          | API Field                         | Purpose                                           |
| ---------------- | --------------------------------- | ------------------------------------------------- |
| Context Control  | `search_context_size: medium`     | Balances speed and depth for focused medical Q\&A |
| Trusted Domains  | `search_domain_filter`            | Restricts results to vetted health sources        |
| Visual Input     | `image_url`                       | Enables image-based medical queries               |
| Freshness Filter | `search_after/before_date_filter` | Helps surface recent and relevant findings        |
| Local Relevance  | `user_location`                   | Tailors answers based on user’s region            |

## Links

* [GitHub Repository](https://github.com/vero-code/valetudo-ai)
* [Devpost Submission](https://devpost.com/software/valetudo-ai)
* [View All Screenshots](https://github.com/vero-code/valetudo-ai/tree/master/screenshots)

## Demo Video

See Valetudo AI in action:

<iframe title="YouTube video player" />

## Screenshots

### Home Interface

![Home screen](https://raw.githubusercontent.com/vero-code/valetudo-ai/refs/heads/master/screenshots/1-home.png)

### Prompt Templates

![Prompt templates](https://raw.githubusercontent.com/vero-code/valetudo-ai/refs/heads/master/screenshots/10-prompts.png)

### Image Upload

![Image upload](https://raw.githubusercontent.com/vero-code/valetudo-ai/refs/heads/master/screenshots/8-image-upload.png)

### Date & Location Filters

![Date filter](https://raw.githubusercontent.com/vero-code/valetudo-ai/refs/heads/master/screenshots/7-date-filter.png)

![Location filter](https://raw.githubusercontent.com/vero-code/valetudo-ai/refs/heads/master/screenshots/9-location-filter.png)


# Best Practices
Source: https://docs.perplexity.ai/docs/embeddings/best-practices

Optimize your embeddings workflow with batch processing, caching, RAG patterns, and performance tips.

## Overview

This guide covers best practices for getting the most out of Perplexity's Embeddings API, including dimension reduction, batch processing, RAG patterns, and error handling.

## Matryoshka Dimension Reduction

Perplexity embeddings support Matryoshka representation learning, allowing you to reduce embedding dimensions while maintaining quality. This enables faster similarity search and reduced storage costs.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Full dimensions (2560 for 4b model)
  full_response = client.embeddings.create(
      input=["Your text here"],
      model="pplx-embed-v1-4b"
  )
  print(f"Full: {full_response.data[0].embedding}")  # 2560-dim base64 string

  # Reduced dimensions - faster search, smaller storage
  reduced_response = client.embeddings.create(
      input=["Your text here"],
      model="pplx-embed-v1-4b",
      dimensions=512
  )
  print(f"Reduced: {reduced_response.data[0].embedding}")  # 512-dim base64 string
  ```

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

  const client = new Perplexity();

  // Full dimensions (2560 for 4b model)
  const fullResponse = await client.embeddings.create({
      input: ["Your text here"],
      model: "pplx-embed-v1-4b"
  });
  console.log(`Full: ${fullResponse.data![0].embedding}`);

  // Reduced dimensions - faster search, smaller storage
  const reducedResponse = await client.embeddings.create({
      input: ["Your text here"],
      model: "pplx-embed-v1-4b",
      dimensions: 512
  });
  console.log(`Reduced: ${reducedResponse.data![0].embedding}`);
  ```
</CodeGroup>

<Note>
  **Trade-off:** Lower dimensions = faster search + less storage, but slightly lower quality. Start with full dimensions and reduce if needed.
</Note>

## Encoding Formats

Control precision and size of embedding outputs:

| Format          | Description                                                 |     Decoded Size     | Similarity Metric | Use Case                                      |
| --------------- | ----------------------------------------------------------- | :------------------: | :---------------: | --------------------------------------------- |
| `base64_int8`   | Base64-encoded signed int8 (-128 to 127)                    |   dimensions bytes   | Cosine similarity | Default, good balance of quality and size     |
| `base64_binary` | Base64-encoded packed bits (1 bit per dimension, LSB first) | dimensions / 8 bytes |  Hamming distance | Maximum compression for large-scale retrieval |

<CodeGroup>
  ```python Python theme={null}
  import base64
  import numpy as np

  # Decode base64_int8 (default)
  response = client.embeddings.create(
      input=["Your text"],
      model="pplx-embed-v1-4b"
  )
  int8_embedding = np.frombuffer(
      base64.b64decode(response.data[0].embedding), dtype=np.int8
  )

  # Binary embeddings for large-scale retrieval systems
  response = client.embeddings.create(
      input=["Your text"],
      model="pplx-embed-v1-4b",
      encoding_format="base64_binary"
  )
  binary_bytes = np.frombuffer(
      base64.b64decode(response.data[0].embedding), dtype=np.uint8
  )
  # Unpack bits: each byte contains 8 dimensions (LSB first)
  binary_embedding = np.unpackbits(binary_bytes, bitorder="little")
  ```

  ```typescript TypeScript theme={null}
  // Decode base64_int8 (default)
  const response = await client.embeddings.create({
      input: ["Your text"],
      model: "pplx-embed-v1-4b"
  });
  const buffer = Buffer.from(response.data![0].embedding, 'base64');
  const int8Embedding = new Int8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);

  // Binary embeddings for large-scale retrieval systems
  const binaryResponse = await client.embeddings.create({
      input: ["Your text"],
      model: "pplx-embed-v1-4b",
      encoding_format: "base64_binary"
  });
  const binaryBuffer = Buffer.from(binaryResponse.data![0].embedding, 'base64');
  // Each byte contains 8 dimensions as packed bits (LSB first)
  ```
</CodeGroup>

<Tip>
  `base64_int8` produces the same quality as bfloat16 with significantly reduced storage. Use `base64_binary` for extreme compression in large-scale systems.
</Tip>

## Similarity Metrics

Perplexity embedding models produce **unnormalized** embeddings. Choosing the correct similarity metric is critical for accurate retrieval.

<Warning>
  `pplx-embed-v1` and `pplx-embed-context-v1` natively produce unnormalized int8-quantized embeddings. You **must** compare them via cosine similarity. Using inner product or L2 distance directly will produce incorrect results because most embedding models are pre-normalized, but Perplexity embeddings are not.
</Warning>

### int8 Embeddings (`base64_int8`)

Compare using **cosine similarity**. If your vector database does not support cosine similarity natively, convert the embeddings to float32 and L2-normalize them before storing:

<CodeGroup>
  ```python Python theme={null}
  import base64
  import numpy as np

  def decode_and_normalize(b64_string):
      """Decode and L2-normalize for vector DBs that only support inner product."""
      embedding = np.frombuffer(base64.b64decode(b64_string), dtype=np.int8).astype(np.float32)
      norm = np.linalg.norm(embedding)
      if norm > 0:
          embedding = embedding / norm
      return embedding

  # After normalization, cosine similarity == inner product
  ```

  ```typescript TypeScript theme={null}
  function decodeAndNormalize(b64String: string): Float32Array {
      const buffer = Buffer.from(b64String, 'base64');
      const int8 = new Int8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
      const float32 = new Float32Array(int8.length);

      // Convert to float32
      let norm = 0;
      for (let i = 0; i < int8.length; i++) {
          float32[i] = int8[i];
          norm += float32[i] * float32[i];
      }

      // L2-normalize so inner product == cosine similarity
      norm = Math.sqrt(norm);
      if (norm > 0) {
          for (let i = 0; i < float32.length; i++) {
              float32[i] /= norm;
          }
      }
      return float32;
  }
  ```
</CodeGroup>

### Binary Embeddings (`base64_binary`)

Compare using **Hamming distance**. Binary embeddings encode each dimension as a single bit, so the natural distance metric is the number of differing bits between two vectors.

```python theme={null}
import numpy as np

def hamming_distance(a: np.ndarray, b: np.ndarray) -> int:
    """Hamming distance between two binary vectors (as uint8 packed bits)."""
    return np.unpackbits(np.bitwise_xor(a, b)).sum()
```

<Note>
  Most vector databases (Pinecone, Weaviate, Qdrant, Milvus) support cosine similarity as a distance metric. Verify your database's configuration before indexing embeddings.
</Note>

## RAG Pattern

Combine embeddings with Perplexity's Agentic Research API for retrieval-augmented generation:

<CodeGroup>
  ```python Python theme={null}
  import base64
  import numpy as np
  from perplexity import Perplexity

  client = Perplexity()

  def decode_embedding(b64_string):
      return np.frombuffer(base64.b64decode(b64_string), dtype=np.int8).astype(np.float32)

  def cosine_similarity(a, b):
      return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

  # 1. Your knowledge base (embed once, store in vector DB)
  knowledge_base = [
      "Perplexity API provides web-grounded AI responses",
      "The Embeddings API supports Matryoshka dimension reduction",
      "Contextualized embeddings share context across document chunks"
  ]

  kb_response = client.embeddings.create(input=knowledge_base, model="pplx-embed-v1-4b")
  kb_embeddings = [decode_embedding(emb.embedding) for emb in kb_response.data]

  # 2. User query
  user_query = "How do I reduce embedding dimensions?"

  # 3. Find relevant context
  query_response = client.embeddings.create(input=[user_query], model="pplx-embed-v1-4b")
  query_embedding = decode_embedding(query_response.data[0].embedding)

  scores = [(i, cosine_similarity(query_embedding, emb)) for i, emb in enumerate(kb_embeddings)]
  top_docs = sorted(scores, key=lambda x: x[1], reverse=True)[:2]
  context = "\n".join([knowledge_base[i] for i, _ in top_docs])

  # 4. Generate answer with context
  response = client.responses.create(
      model="openai/gpt-5.5",
      input=f"Answer using this context:\n\n{context}\n\nQuestion: {user_query}"
  )

  print(response.output[0].content[0].text)
  ```

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

  const client = new Perplexity();

  function decodeEmbedding(b64String: string): Int8Array {
      const buffer = Buffer.from(b64String, 'base64');
      return new Int8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  }

  function cosineSimilarity(a: Int8Array, b: Int8Array): number {
      let dotProduct = 0, normA = 0, normB = 0;
      for (let i = 0; i < a.length; i++) {
          dotProduct += a[i] * b[i];
          normA += a[i] * a[i];
          normB += b[i] * b[i];
      }
      return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
  }

  // 1. Your knowledge base
  const knowledgeBase = [
      "Perplexity API provides web-grounded AI responses",
      "The Embeddings API supports Matryoshka dimension reduction",
      "Contextualized embeddings share context across document chunks"
  ];

  const kbResponse = await client.embeddings.create({
      input: knowledgeBase,
      model: "pplx-embed-v1-4b"
  });
  const kbEmbeddings = kbResponse.data!.map(emb => decodeEmbedding(emb.embedding!));

  // 2. User query
  const userQuery = "How do I reduce embedding dimensions?";

  // 3. Find relevant context
  const queryResponse = await client.embeddings.create({
      input: [userQuery],
      model: "pplx-embed-v1-4b"
  });
  const queryEmbedding = decodeEmbedding(queryResponse.data![0].embedding!);

  const scores = kbEmbeddings.map((emb, i) => ({
      index: i,
      score: cosineSimilarity(queryEmbedding, emb)
  }));
  const topDocs = scores.sort((a, b) => b.score - a.score).slice(0, 2);
  const context = topDocs.map(d => knowledgeBase[d.index]).join("\n");

  // 4. Generate answer with context
  const response = await client.responses.create({
      model: "openai/gpt-5.5",
      input: `Answer using this context:\n\n${context}\n\nQuestion: ${userQuery}`
  });

  console.log((response.output[0] as any).content[0].text);
  ```
</CodeGroup>

## Batch Processing

Process large datasets efficiently with async batching:

<CodeGroup>
  ```python Python theme={null}
  import asyncio
  from perplexity import AsyncPerplexity

  async def batch_embed(texts: list[str], batch_size: int = 100):
      async with AsyncPerplexity() as client:
          results = []
          for i in range(0, len(texts), batch_size):
              batch = texts[i:i + batch_size]
              response = await client.embeddings.create(
                  input=batch,
                  model="pplx-embed-v1-4b"
              )
              results.extend(response.data)
              print(f"Processed {min(i + batch_size, len(texts))}/{len(texts)}")
          return results

  # Usage
  texts = ["Document " + str(i) for i in range(1000)]
  embeddings = asyncio.run(batch_embed(texts))
  print(f"Generated {len(embeddings)} embeddings")
  ```

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

  async function batchEmbed(texts: string[], batchSize: number = 100) {
      const client = new Perplexity();
      const results: any[] = [];

      for (let i = 0; i < texts.length; i += batchSize) {
          const batch = texts.slice(i, i + batchSize);
          const response = await client.embeddings.create({
              input: batch,
              model: "pplx-embed-v1-4b"
          });
          results.push(...(response.data ?? []));
          console.log(`Processed ${Math.min(i + batchSize, texts.length)}/${texts.length}`);
      }

      return results;
  }

  // Usage
  const texts = Array.from({ length: 1000 }, (_, i) => `Document ${i}`);
  const embeddings = await batchEmbed(texts);
  console.log(`Generated ${embeddings.length} embeddings`);
  ```
</CodeGroup>

## Error Handling

<CodeGroup>
  ```python Python theme={null}
  import perplexity
  from perplexity import Perplexity

  client = Perplexity()

  try:
      response = client.embeddings.create(
          input=["Your text"],
          model="pplx-embed-v1-4b"
      )
  except perplexity.BadRequestError as e:
      print(f"Invalid request: {e}")
  except perplexity.RateLimitError:
      print("Rate limited, please retry later")
  except perplexity.APIStatusError as e:
      print(f"API error: {e.status_code}")
  ```

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

  const client = new Perplexity();

  try {
      const response = await client.embeddings.create({
          input: ["Your text"],
          model: "pplx-embed-v1-4b"
      });
  } catch (error) {
      if (error instanceof Perplexity.BadRequestError) {
          console.error("Invalid request:", error.message);
      } else if (error instanceof Perplexity.RateLimitError) {
          console.error("Rate limited, please retry later");
      } else if (error instanceof Perplexity.APIError) {
          console.error(`API error: ${error.status}`);
      }
  }
  ```
</CodeGroup>

## Tips

<Steps>
  <Step title="Batch requests">
    Send up to 512 texts per request to maximize throughput and reduce API calls.
  </Step>

  <Step title="Match models">
    Always use the same embedding model for both queries and documents to ensure consistent similarity scores.
  </Step>

  <Step title="Use cosine similarity">
    Perplexity embeddings are unnormalized. Always use cosine similarity for `base64_int8` and Hamming distance for `base64_binary`. If your vector DB only supports inner product, L2-normalize the embeddings before storing.
  </Step>

  <Step title="Cache embeddings">
    Store computed embeddings in a vector database. Never recompute embeddings for the same text.
  </Step>

  <Step title="Use Matryoshka wisely">
    Start with full dimensions for best quality. Reduce dimensions only if you need faster search or smaller storage.
  </Step>

  <Step title="Binary for scale">
    Use `base64_binary` encoding format for large-scale retrieval systems where storage and speed are critical.
  </Step>
</Steps>

## Related Resources

<CardGroup>
  <Card title="Quickstart" icon="rocket" href="/docs/embeddings/quickstart">
    Get started with basic embeddings functionality.
  </Card>

  <Card title="Contextualized Embeddings" icon="file-lines" href="/docs/embeddings/contextualized-embeddings">
    Document-aware embeddings for chunks with shared context.
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/embeddings-post">
    Complete Embeddings API documentation.
  </Card>

  <Card title="SDK Guide" icon="code" href="/docs/sdk/overview">
    Perplexity SDK features and best practices.
  </Card>
</CardGroup>


# Contextualized Embeddings
Source: https://docs.perplexity.ai/docs/embeddings/contextualized-embeddings

Generate document-aware embeddings for chunks that share context, improving retrieval quality for document-based applications.

## Overview

Contextualized embeddings generate embeddings for document chunks that share context awareness. Unlike standard embeddings where each text is embedded independently, contextualized embeddings understand that chunks belong to the same document and incorporate that relationship.

<Info>
  Use contextualized embeddings when embedding chunks from the same document (e.g., paragraphs, sections). Use [standard embeddings](/docs/embeddings/quickstart) for independent texts like search queries or standalone sentences.
</Info>

## Models

|             Model            | Dimensions | Context | MRL | Quantization | Price (\$/1M tokens) |
| :--------------------------: | :--------: | :-----: | :-: | :----------: | :------------------: |
| `pplx-embed-context-v1-0.6b` |    1024    |   32K   | Yes |  INT8/BINARY |        \$0.008       |
|  `pplx-embed-context-v1-4b`  |    2560    |   32K   | Yes |  INT8/BINARY |        \$0.05        |

All models use mean pooling and require no instruction prefix.

## Basic Usage

Pass documents as nested arrays where each inner array represents chunks from a single document:

<Warning>
  **Chunk ordering:** Chunks within each document must be sent in the order they appear in the source document. The model uses sequential context to generate document-aware embeddings, so maintaining the original order is essential for optimal results.
</Warning>

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.contextualized_embeddings.create(
      input=[
          # Document 1: Three chunks
          [
              "Curiosity begins in childhood with endless questions about the world.",
              "As we grow, curiosity drives us to explore new ideas and challenge assumptions.",
              "Scientific breakthroughs often start with a simple curious question."
          ],
          # Document 2: Two chunks
          [
              "The Curiosity rover explores Mars, searching for signs of ancient life.",
              "Each discovery on Mars sparks new questions about our place in the universe."
          ]
      ],
      model="pplx-embed-context-v1-4b"
  )

  for doc in response.data:
      for chunk in doc.data:
          print(f"Doc {doc.index}, Chunk {chunk.index}: {chunk.embedding}")
  ```

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

  const client = new Perplexity();

  const response = await client.contextualizedEmbeddings.create({
      input: [
          // Document 1: Three chunks
          [
              "Curiosity begins in childhood with endless questions about the world.",
              "As we grow, curiosity drives us to explore new ideas and challenge assumptions.",
              "Scientific breakthroughs often start with a simple curious question."
          ],
          // Document 2: Two chunks
          [
              "The Curiosity rover explores Mars, searching for signs of ancient life.",
              "Each discovery on Mars sparks new questions about our place in the universe."
          ]
      ],
      model: "pplx-embed-context-v1-4b"
  });

  for (const doc of response.data!) {
      for (const chunk of doc.data!) {
          console.log(`Doc ${doc.index}, Chunk ${chunk.index}: ${chunk.embedding!}`);
      }
  }
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/v1/contextualizedembeddings' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "input": [
        [
          "Curiosity begins in childhood with endless questions about the world.",
          "As we grow, curiosity drives us to explore new ideas and challenge assumptions.",
          "Scientific breakthroughs often start with a simple curious question."
        ],
        [
          "The Curiosity rover explores Mars, searching for signs of ancient life.",
          "Each discovery on Mars sparks new questions about our place in the universe."
        ]
      ],
      "model": "pplx-embed-context-v1-4b"
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "object": "list",
    "data": [
      {
        "object": "list",
        "index": 0,
        "data": [
          { "object": "embedding", "index": 0, "embedding": "/* base64-encoded signed int8 values */" },
          { "object": "embedding", "index": 1, "embedding": "/* base64-encoded signed int8 values */" },
          { "object": "embedding", "index": 2, "embedding": "/* base64-encoded signed int8 values */" }
        ]
      },
      {
        "object": "list",
        "index": 1,
        "data": [
          { "object": "embedding", "index": 0, "embedding": "/* base64-encoded signed int8 values */" },
          { "object": "embedding", "index": 1, "embedding": "/* base64-encoded signed int8 values */" }
        ]
      }
    ],
    "model": "pplx-embed-context-v1-4b",
    "usage": {
      "prompt_tokens": 72,
      "total_tokens": 72
    }
  }
  ```
</Accordion>

## Parameters

| Parameter         | Type                   | Required |    Default    | Description                                                                                               |
| ----------------- | ---------------------- | :------: | :-----------: | --------------------------------------------------------------------------------------------------------- |
| `input`           | array\[array\[string]] |    Yes   |       -       | Nested array: each inner array contains chunks from one document. Max 512 documents, 16,000 total chunks. |
| `model`           | string                 |    Yes   |       -       | Model identifier: `pplx-embed-context-v1-0.6b` or `pplx-embed-context-v1-4b`                              |
| `dimensions`      | integer                |    No    |      Full     | Matryoshka dimension (128-1024 for 0.6b, 128-2560 for 4b)                                                 |
| `encoding_format` | string                 |    No    | `base64_int8` | Output encoding: `base64_int8` (signed int8) or `base64_binary` (packed bits)                             |

<Warning>
  **Input limits:** Total tokens per document must not exceed 32K. Total chunks across all documents must not exceed 16,000. All chunks in a single request must not exceed 120,000 tokens combined. Empty strings are not allowed.
</Warning>

## Golden Chunk Retrieval Example

Build a chunk retrieval system where chunks from the same document share context:

<CodeGroup>
  ```python Python theme={null}
  import base64
  import numpy as np
  from perplexity import Perplexity

  client = Perplexity()

  def decode_embedding(b64_string):
      """Decode a base64-encoded int8 embedding."""
      return np.frombuffer(base64.b64decode(b64_string), dtype=np.int8).astype(np.float32)

  def cosine_similarity(a, b):
      return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

  # Your documents, each split into chunks
  documents = [
      {
          "title": "Machine Learning Guide",
          "chunks": [
              "Machine learning is a subset of AI that enables systems to learn.",
              "Supervised learning uses labeled data for training models.",
              "Unsupervised learning finds patterns in unlabeled data."
          ]
      },
      {
          "title": "Deep Learning Fundamentals",
          "chunks": [
              "Deep learning uses neural networks with multiple layers.",
              "Convolutional networks excel at image processing tasks.",
              "Transformers revolutionized natural language processing."
          ]
      }
  ]

  # 1. Embed all document chunks with context awareness
  doc_chunks = [doc["chunks"] for doc in documents]
  doc_response = client.contextualized_embeddings.create(
      input=doc_chunks,
      model="pplx-embed-context-v1-4b"
  )

  # Build index
  chunk_index = []
  for doc_obj in doc_response.data:
      for chunk_obj in doc_obj.data:
          chunk_index.append({
              "doc_idx": doc_obj.index,
              "chunk_idx": chunk_obj.index,
              "embedding": decode_embedding(chunk_obj.embedding),
              "text": documents[doc_obj.index]["chunks"][chunk_obj.index],
              "doc_title": documents[doc_obj.index]["title"]
          })

  # 2. Embed the query using the same contextualized model
  # Wrap each query as a single-element inner list: [[query1], [query2]]
  query = "How do neural networks process images?"
  query_response = client.contextualized_embeddings.create(
      input=[[query]],
      model="pplx-embed-context-v1-4b"
  )
  query_embedding = decode_embedding(query_response.data[0].data[0].embedding)

  # 3. Find most relevant chunks
  results = []
  for item in chunk_index:
      score = cosine_similarity(query_embedding, item["embedding"])
      results.append({**item, "score": score})

  results = sorted(results, key=lambda x: x["score"], reverse=True)

  print(f"Query: {query}\n")
  print("Top results:")
  for r in results[:3]:
      print(f"  [{r['doc_title']}] {r['score']:.4f}: {r['text'][:60]}...")
  ```

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

  const client = new Perplexity();

  function decodeEmbedding(b64String: string): Int8Array {
      const buffer = Buffer.from(b64String, 'base64');
      return new Int8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  }

  function cosineSimilarity(a: Int8Array, b: Int8Array): number {
      let dotProduct = 0, normA = 0, normB = 0;
      for (let i = 0; i < a.length; i++) {
          dotProduct += a[i] * b[i];
          normA += a[i] * a[i];
          normB += b[i] * b[i];
      }
      return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
  }

  // Your documents, each split into chunks
  const documents = [
      {
          title: "Machine Learning Guide",
          chunks: [
              "Machine learning is a subset of AI that enables systems to learn.",
              "Supervised learning uses labeled data for training models.",
              "Unsupervised learning finds patterns in unlabeled data."
          ]
      },
      {
          title: "Deep Learning Fundamentals",
          chunks: [
              "Deep learning uses neural networks with multiple layers.",
              "Convolutional networks excel at image processing tasks.",
              "Transformers revolutionized natural language processing."
          ]
      }
  ];

  // 1. Embed all document chunks with context awareness
  const docChunks = documents.map(doc => doc.chunks);
  const docResponse = await client.contextualizedEmbeddings.create({
      input: docChunks,
      model: "pplx-embed-context-v1-4b"
  });

  // Build index
  const chunkIndex = docResponse.data!.flatMap(docObj =>
      docObj.data!.map(chunkObj => ({
          docIdx: docObj.index,
          chunkIdx: chunkObj.index,
          embedding: decodeEmbedding(chunkObj.embedding!),
          text: documents[docObj.index as number].chunks[chunkObj.index as number],
          docTitle: documents[docObj.index as number].title
      }))
  );

  // 2. Embed the query using the same contextualized model
  // Wrap each query as a single-element inner list: [[query1], [query2]]
  const query = "How do neural networks process images?";
  const queryResponse = await client.contextualizedEmbeddings.create({
      input: [[query]],
      model: "pplx-embed-context-v1-4b"
  });
  const queryEmbedding = decodeEmbedding(queryResponse.data![0].data![0].embedding!);

  // 3. Find most relevant chunks
  const results = chunkIndex
      .map(item => ({
          ...item,
          score: cosineSimilarity(queryEmbedding, item.embedding)
      }))
      .sort((a, b) => b.score - a.score);

  console.log(`Query: ${query}\n`);
  console.log("Top results:");
  for (const r of results.slice(0, 3)) {
      console.log(`  [${r.docTitle}] ${r.score.toFixed(4)}: ${r.text.slice(0, 60)}...`);
  }
  ```
</CodeGroup>

## When to Use Contextualized vs Standard

| Use Case                  | Recommendation            |
| ------------------------- | ------------------------- |
| Independent sentences     | Standard embeddings       |
| FAQ entries               | Standard embeddings       |
| General-purpose retrieval | Standard embeddings       |
| Document paragraphs       | Contextualized embeddings |
| PDF sections              | Contextualized embeddings |
| Article chunks            | Contextualized embeddings |
| Code file segments        | Contextualized embeddings |

<Tip>
  **Rule of thumb:** If chunks come from the same source document and their meaning depends on surrounding context, use contextualized embeddings. If each text stands alone, use standard embeddings. When using contextualized embeddings, embed queries with the same contextualized model by wrapping each query as a single-element inner list (e.g., `[[query]]`).
</Tip>

## Related Resources

<CardGroup>
  <Card title="Quickstart" icon="rocket" href="/docs/embeddings/quickstart">
    Get started with standard embeddings.
  </Card>

  <Card title="Best Practices" icon="star" href="/docs/embeddings/best-practices">
    Batch processing, caching, and RAG patterns.
  </Card>
</CardGroup>


# Embeddings API
Source: https://docs.perplexity.ai/docs/embeddings/quickstart

Generate high-quality text embeddings for semantic search, RAG, and machine learning applications.

## Overview

Perplexity's Embeddings API generates high-quality text embeddings for semantic search and retrieval. Choose between **standard embeddings** for independent texts or **contextualized embeddings** for document chunks that share context.

<Info>
  We recommend using our [official SDKs](/docs/sdk/overview) for a more convenient and type-safe way to interact with the Embeddings API.
</Info>

<Card title="Pricing" icon="receipt" href="/docs/getting-started/pricing">
  Pay-as-you-go pricing for all APIs. No subscription required.
</Card>

## Available Models

|             Model            | Dimensions | Context | MRL | Quantization | Price (\$/1M tokens) |
| :--------------------------: | :--------: | :-----: | :-: | :----------: | :------------------: |
|     `pplx-embed-v1-0.6b`     |    1024    |   32K   | Yes |  INT8/BINARY |        \$0.004       |
|      `pplx-embed-v1-4b`      |    2560    |   32K   | Yes |  INT8/BINARY |        \$0.03        |
| `pplx-embed-context-v1-0.6b` |    1024    |   32K   | Yes |  INT8/BINARY |        \$0.008       |
|  `pplx-embed-context-v1-4b`  |    2560    |   32K   | Yes |  INT8/BINARY |        \$0.05        |

All models use mean pooling and require no instruction prefix—you can embed text directly without prompt engineering.

<Warning>
  Perplexity embeddings are **unnormalized**. Always compare `base64_int8` embeddings via **cosine similarity** (not inner product or L2 distance). Compare `base64_binary` embeddings via **Hamming distance**. See [Best Practices](/docs/embeddings/best-practices) for details and normalization helpers.
</Warning>

<Tip>
  **When to use which:**

  * **Standard embeddings** (`pplx-embed-v1-*`) - Independent texts, search queries, single sentences
  * **Contextualized embeddings** (`pplx-embed-context-v1-*`) - Document chunks that benefit from shared context (e.g., paragraphs from the same article)
</Tip>

## Installation

<CodeGroup>
  ```bash Python theme={null}
  pip install perplexityai
  ```

  ```bash TypeScript/JavaScript theme={null}
  npm install @perplexity-ai/perplexity_ai
  ```
</CodeGroup>

## Authentication

Set your API key as an environment variable:

<Tabs>
  <Tab title="macOS/Linux">
    ```bash theme={null}
    export PERPLEXITY_API_KEY="your_api_key_here"
    ```
  </Tab>

  <Tab title="Windows">
    ```powershell theme={null}
    setx PERPLEXITY_API_KEY "your_api_key_here"
    ```
  </Tab>
</Tabs>

## Next Steps

<CardGroup>
  <Card title="Standard Embeddings" icon="cube" href="/docs/embeddings/standard-embeddings">
    Embed independent texts, queries, and sentences.
  </Card>

  <Card title="Contextualized Embeddings" icon="file-lines" href="/docs/embeddings/contextualized-embeddings">
    Document-aware embeddings for chunks that share context.
  </Card>

  <Card title="Best Practices" icon="star" href="/docs/embeddings/best-practices">
    Batch processing, caching, RAG patterns, and performance optimization.
  </Card>

  <Card title="Model Cards" icon="link" href="https://huggingface.co/perplexity-ai">
    See the model cards on HuggingFace.
  </Card>
</CardGroup>


# Standard Embeddings
Source: https://docs.perplexity.ai/docs/embeddings/standard-embeddings

Generate embeddings for independent texts, search queries, and single sentences.

## Overview

Use standard embeddings for independent text embedding (queries, documents, and semantic search) where each text is self-contained.

## Models

|         Model        | Dimensions | Context | MRL | Quantization | Price (\$/1M tokens) |
| :------------------: | :--------: | :-----: | :-: | :----------: | :------------------: |
| `pplx-embed-v1-0.6b` |    1024    |   32K   | Yes |  INT8/BINARY |        \$0.004       |
|  `pplx-embed-v1-4b`  |    2560    |   32K   | Yes |  INT8/BINARY |        \$0.03        |

## Basic Usage

Generate embeddings for a list of texts:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.embeddings.create(
      input=[
          "Scientists explore the universe driven by curiosity.",
          "Curiosity compels us to seek explanations, not just observations.",
          "Historical discoveries began with curious questions.",
          "The pursuit of knowledge distinguishes human curiosity from mere stimulus response.",
          "Philosophy examines the nature of curiosity."
      ],
      model="pplx-embed-v1-4b"
  )

  for emb in response.data:
      print(f"Index {emb.index}: {emb.embedding}")
  ```

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

  const client = new Perplexity();

  const response = await client.embeddings.create({
      input: [
          "Scientists explore the universe driven by curiosity.",
          "Curiosity compels us to seek explanations, not just observations.",
          "Historical discoveries began with curious questions.",
          "The pursuit of knowledge distinguishes human curiosity from mere stimulus response.",
          "Philosophy examines the nature of curiosity."
      ],
      model: "pplx-embed-v1-4b"
  });

  for (const emb of response.data!) {
      console.log(`Index ${emb.index}: ${emb.embedding!}`);
  }
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/v1/embeddings' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "input": [
        "Scientists explore the universe driven by curiosity.",
        "Curiosity compels us to seek explanations, not just observations.",
        "Historical discoveries began with curious questions.",
        "The pursuit of knowledge distinguishes human curiosity from mere stimulus response.",
        "Philosophy examines the nature of curiosity."
      ],
      "model": "pplx-embed-v1-4b"
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "object": "list",
    "data": [
      {
        "object": "embedding",
        "index": 0,
        "embedding": "/* base64-encoded signed int8 values */"
      },
      {
        "object": "embedding",
        "index": 1,
        "embedding": "/* base64-encoded signed int8 values */"
      },
      {
        "object": "embedding",
        "index": 2,
        "embedding": "/* base64-encoded signed int8 values */"
      },
      {
        "object": "embedding",
        "index": 3,
        "embedding": "/* base64-encoded signed int8 values */"
      },
      {
        "object": "embedding",
        "index": 4,
        "embedding": "/* base64-encoded signed int8 values */"
      }
    ],
    "model": "pplx-embed-v1-4b",
    "usage": {
      "prompt_tokens": 42,
      "total_tokens": 42,
      "cost": {
        "input_cost": 0.0000013,
        "total_cost": 0.0000013,
        "currency": "USD"
      }
    }
  }
  ```
</Accordion>

## Semantic Search Example

Build a simple semantic search system:

<CodeGroup>
  ```python Python theme={null}
  import base64
  import numpy as np
  from perplexity import Perplexity

  client = Perplexity()

  def decode_embedding(b64_string):
      """Decode a base64-encoded int8 embedding."""
      return np.frombuffer(base64.b64decode(b64_string), dtype=np.int8).astype(np.float32)

  def cosine_similarity(a, b):
      return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

  # 1. Embed your documents
  documents = [
      "Python is a versatile programming language",
      "Machine learning automates analytical model building",
      "The Eiffel Tower is located in Paris, France"
  ]

  doc_response = client.embeddings.create(input=documents, model="pplx-embed-v1-4b")
  doc_embeddings = [decode_embedding(emb.embedding) for emb in doc_response.data]

  # 2. Embed a search query
  query = "What programming languages are good for data science?"
  query_response = client.embeddings.create(input=[query], model="pplx-embed-v1-4b")
  query_embedding = decode_embedding(query_response.data[0].embedding)

  # 3. Find most similar documents
  scores = [
      (i, cosine_similarity(query_embedding, doc_emb))
      for i, doc_emb in enumerate(doc_embeddings)
  ]
  ranked = sorted(scores, key=lambda x: x[1], reverse=True)

  print("Search results:")
  for idx, score in ranked:
      print(f"  {score:.4f}: {documents[idx]}")
  ```

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

  const client = new Perplexity();

  function decodeEmbedding(b64String: string): Int8Array {
      const buffer = Buffer.from(b64String, 'base64');
      return new Int8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  }

  function cosineSimilarity(a: Int8Array, b: Int8Array): number {
      let dotProduct = 0, normA = 0, normB = 0;
      for (let i = 0; i < a.length; i++) {
          dotProduct += a[i] * b[i];
          normA += a[i] * a[i];
          normB += b[i] * b[i];
      }
      return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
  }

  // 1. Embed your documents
  const documents = [
      "Python is a versatile programming language",
      "Machine learning automates analytical model building",
      "The Eiffel Tower is located in Paris, France"
  ];

  const docResponse = await client.embeddings.create({
      input: documents,
      model: "pplx-embed-v1-4b"
  });
  const docEmbeddings = docResponse.data!.map(emb => decodeEmbedding(emb.embedding!));

  // 2. Embed a search query
  const query = "What programming languages are good for data science?";
  const queryResponse = await client.embeddings.create({
      input: [query],
      model: "pplx-embed-v1-4b"
  });
  const queryEmbedding = decodeEmbedding(queryResponse.data![0].embedding!);

  // 3. Find most similar documents
  const scores = docEmbeddings.map((docEmb, i) => ({
      index: i,
      score: cosineSimilarity(queryEmbedding, docEmb)
  }));
  const ranked = scores.sort((a, b) => b.score - a.score);

  console.log("Search results:");
  for (const { index, score } of ranked) {
      console.log(`  ${score.toFixed(4)}: ${documents[index]}`);
  }
  ```
</CodeGroup>

## Parameters

| Parameter         | Type                     | Required |    Default    | Description                                                                                                                                              |
| ----------------- | ------------------------ | :------: | :-----------: | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `input`           | string \| array\[string] |    Yes   |       -       | Text(s) to embed. Max 512 texts per request. Each input must not exceed 32K tokens. Total tokens must not exceed 120,000. Empty strings are not allowed. |
| `model`           | string                   |    Yes   |       -       | Model identifier: `pplx-embed-v1-0.6b` or `pplx-embed-v1-4b`                                                                                             |
| `dimensions`      | integer                  |    No    |      Full     | Matryoshka dimension (128-1024 for 0.6b, 128-2560 for 4b)                                                                                                |
| `encoding_format` | string                   |    No    | `base64_int8` | Output encoding: `base64_int8` (signed int8) or `base64_binary` (packed bits)                                                                            |

<Warning>
  **Input limits:** Each text must not exceed 32K tokens. Requests exceeding this limit will be rejected. All inputs in a single request must not exceed 120,000 tokens combined.
</Warning>

## Related Resources

<CardGroup>
  <Card title="Contextualized Embeddings" icon="file-lines" href="/docs/embeddings/contextualized-embeddings">
    Document-aware embeddings for chunks that share context.
  </Card>

  <Card title="Best Practices" icon="star" href="/docs/embeddings/best-practices">
    Batch processing, caching, and RAG patterns.
  </Card>
</CardGroup>


# Router Models & Pricing
Source: https://docs.perplexity.ai/docs/gateway/models

The model catalog for the Perplexity Router API, with per-token pricing for Perplexity-hosted and third-party models.

<Note>
  Router API is in private preview. Email [api@perplexity.ai](mailto:api@perplexity.ai) to request access.
</Note>

## Overview

Every model below is available through both Router endpoints — [Chat Completions](/api-reference/gateway-chat-completions-post) and [Messages](/api-reference/gateway-messages-post) — under the same `creator/model-name` id. Prices are in USD per 1 million tokens, and you are billed at the requested model's rates regardless of how the request is served.

For the live catalog, query [`GET /models`](/api-reference/gateway-models-get); the tables below show the current catalog.

<Note>
  Cached input is billed separately from fresh input: cache reads are billed at the discounted per-model rate shown in the "Cache read" column, and cache writes at the rate shown (or at the input rate where no dedicated write rate is listed). Reasoning tokens are billed at the output rate.
</Note>

## Perplexity-Hosted Models

Open-source models hosted by Perplexity — the `perplexity/` prefix reflects who serves the model, not who created it. The catalog includes models from DeepSeek, Moonshot AI, NVIDIA, and Z.AI:

| Model                                           |    Input |  Output | Cache read |
| ----------------------------------------------- | -------: | ------: | ---------: |
| **`perplexity/deepseek-v4-flash-0731`**         |   \$0.13 |  \$0.26 |    \$0.028 |
| **`perplexity/kimi-k3`**                        |   \$3.00 | \$15.00 |     \$0.30 |
| **`perplexity/glm-5.2`**                        |   \$1.40 |  \$4.40 |     \$0.14 |
| **`perplexity/nemotron-3.5-lightning-30b-a3b`** | \$0.0115 |  \$0.17 |  \$0.00115 |
| **`perplexity/nemotron-3-ultra-550b-a55b`**     |   \$0.25 |  \$2.50 |     \$0.25 |

## Listing Models Programmatically

```bash theme={null}
curl 'https://api.perplexity.ai/router/v1/models' \
  -H "Authorization: Bearer $PERPLEXITY_API_KEY" | jq
```

The response lists every available model sorted by id, including each model's base token prices. Requesting a model that is not in the catalog returns a `400` naming the invalid model — the catalog is also the allowlist.

## Next Steps

<CardGroup>
  <Card title="Quickstart" icon="rocket" href="/docs/gateway/quickstart">
    Make your first Router API call.
  </Card>

  <Card title="Pricing & Billing" icon="receipt" href="/docs/getting-started/pricing">
    How credits, billing, and usage tiers work across the platform.
  </Card>
</CardGroup>


# Perplexity Router API
Source: https://docs.perplexity.ai/docs/gateway/quickstart

Unified access to open-weight models through OpenAI Chat Completions, OpenAI Responses, and Anthropic Messages APIs, with your Perplexity API key.

<Note>
  Router API is in private preview. Email [api@perplexity.ai](mailto:api@perplexity.ai) to request access.
</Note>

## Overview

The Router API provides unified access to open-weight models hosted by Perplexity through a single API and API key. Send requests in the OpenAI Chat Completions, OpenAI Responses, or Anthropic Messages format, pick any model from the [catalog](/docs/gateway/models), and the platform routes each request to a healthy deployment automatically — no per-provider accounts, SDKs, or failover logic on your side.

Any model in the catalog can be called through any supported schema, regardless of the model's original provider. This makes the Router a drop-in replacement for existing OpenAI or Anthropic integrations — only the base URL and API key need to change.

Use the Router API for direct model access with your own prompts and tools. For web-grounded answers with built-in citations, use the [Agent API](/docs/agent-api/quickstart).

The base URL is `https://api.perplexity.ai/router/v1`, and your existing Perplexity API key works as-is.

## Installation

The Router API supports the OpenAI Chat Completions and Responses formats plus the Anthropic Messages format, so you can use either provider's official SDK — install whichever matches your integration (or both):

<CodeGroup>
  ```bash Python theme={null}
  pip install openai       # OpenAI Chat Completions and Responses formats
  pip install anthropic    # Anthropic Messages format
  ```

  ```bash Typescript theme={null}
  npm install openai              # OpenAI Chat Completions and Responses formats
  npm install @anthropic-ai/sdk   # Anthropic Messages format
  ```
</CodeGroup>

## Authentication

Set your API key as an environment variable:

<Tabs>
  <Tab title="macOS/Linux">
    ```bash theme={null}
    export PERPLEXITY_API_KEY="your_api_key_here"
    ```
  </Tab>

  <Tab title="Windows">
    ```powershell theme={null}
    setx PERPLEXITY_API_KEY "your_api_key_here"
    ```
  </Tab>
</Tabs>

Requests authenticate with an `Authorization: Bearer` header, which the SDKs set for you from the `api_key` parameter.

## Basic Usage

Point the OpenAI SDK at the Router base URL and pass any model id from the [catalog](/docs/gateway/models). Model ids use `creator/model-name` slugs, so switching providers is a one-line change:

<CodeGroup>
  ```python Python theme={null}
  from openai import OpenAI
  import os

  client = OpenAI(
      api_key=os.environ.get("PERPLEXITY_API_KEY"),
      base_url="https://api.perplexity.ai/router/v1"
  )

  response = client.chat.completions.create(
      model="perplexity/kimi-k3",
      max_tokens=1024,
      messages=[
          {"role": "user", "content": "Explain the CAP theorem in two sentences."}
      ]
  )

  print(response.choices[0].message.content)
  ```

  ```typescript Typescript theme={null}
  import OpenAI from 'openai';

  const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai/router/v1"
  });

  const response = await client.chat.completions.create({
      model: "perplexity/kimi-k3",
      max_tokens: 1024,
      messages: [
          { role: "user", content: "Explain the CAP theorem in two sentences." }
      ]
  });

  console.log(response.choices[0].message.content);
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/router/v1/chat/completions' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "perplexity/kimi-k3",
      "max_tokens": 1024,
      "messages": [
        {"role": "user", "content": "Explain the CAP theorem in two sentences."}
      ]
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "chatcmpl-Xr7aQ2mVb9L4tW8pDcEfGh1JkNs0y",
    "object": "chat.completion",
    "created": 1753747200,
    "model": "perplexity/kimi-k3",
    "choices": [
      {
        "index": 0,
        "message": {
          "role": "assistant",
          "content": "The CAP theorem states that a distributed system can guarantee at most two of three properties: consistency, availability, and partition tolerance. Since network partitions are unavoidable in practice, designers must choose between consistency and availability when a partition occurs.",
          "annotations": []
        },
        "logprobs": null,
        "finish_reason": "stop"
      }
    ],
    "usage": {
      "prompt_tokens": 18,
      "completion_tokens": 52,
      "total_tokens": 70,
      "prompt_tokens_details": {
        "cached_tokens": 0
      }
    }
  }
  ```
</Accordion>

The response echoes the model id you requested, and you are always billed at that model's [published rates](/docs/gateway/models) no matter how the request was served.

## OpenAI Responses

Use `client.responses.create()` with the same Router base URL when your integration uses the OpenAI Responses format. The Router Responses endpoint is stateless, so include the full conversation in `input` on each request.

<CodeGroup>
  ```python Python theme={null}
  from openai import OpenAI
  import os

  client = OpenAI(
      api_key=os.environ.get("PERPLEXITY_API_KEY"),
      base_url="https://api.perplexity.ai/router/v1"
  )

  response = client.responses.create(
      model="perplexity/kimi-k3",
      input="Explain the CAP theorem in two sentences.",
      max_output_tokens=1024
  )

  print(response.output_text)
  ```

  ```typescript Typescript theme={null}
  import OpenAI from 'openai';

  const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai/router/v1"
  });

  const response = await client.responses.create({
      model: "perplexity/kimi-k3",
      input: "Explain the CAP theorem in two sentences.",
      max_output_tokens: 1024
  });

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

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/router/v1/responses' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "perplexity/kimi-k3",
      "input": "Explain the CAP theorem in two sentences.",
      "max_output_tokens": 1024
    }' | jq
  ```
</CodeGroup>

## Streaming Chat Completions

Set `stream: true` to receive tokens as server-sent events. To get token usage with a streamed response, also set `stream_options: {"include_usage": true}` — usage then arrives in a final chunk before `data: [DONE]`:

<CodeGroup>
  ```python Python theme={null}
  from openai import OpenAI
  import os

  client = OpenAI(
      api_key=os.environ.get("PERPLEXITY_API_KEY"),
      base_url="https://api.perplexity.ai/router/v1"
  )

  stream = client.chat.completions.create(
      model="perplexity/kimi-k3",
      max_tokens=1024,
      messages=[
          {"role": "user", "content": "Write a haiku about network latency."}
      ],
      stream=True,
      stream_options={"include_usage": True}
  )

  for chunk in stream:
      if chunk.choices and chunk.choices[0].delta.content:
          print(chunk.choices[0].delta.content, end="")
      if chunk.usage:
          print(f"\n\nTokens used: {chunk.usage.total_tokens}")
  ```

  ```typescript Typescript theme={null}
  import OpenAI from 'openai';

  const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai/router/v1"
  });

  const stream = await client.chat.completions.create({
      model: "perplexity/kimi-k3",
      max_tokens: 1024,
      messages: [
          { role: "user", content: "Write a haiku about network latency." }
      ],
      stream: true,
      stream_options: { include_usage: true }
  });

  for await (const chunk of stream) {
      if (chunk.choices[0]?.delta?.content) {
          process.stdout.write(chunk.choices[0].delta.content);
      }
      if (chunk.usage) {
          console.log(`\n\nTokens used: ${chunk.usage.total_tokens}`);
      }
  }
  ```

  ```bash cURL theme={null}
  curl -N -X POST 'https://api.perplexity.ai/router/v1/chat/completions' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "perplexity/kimi-k3",
      "max_tokens": 1024,
      "messages": [
        {"role": "user", "content": "Write a haiku about network latency."}
      ],
      "stream": true,
      "stream_options": {"include_usage": true}
    }'
  ```
</CodeGroup>

## Anthropic Messages

The same models are available in the Anthropic Messages format at `/router/v1/messages`, so code written against the Anthropic SDK works with a base-URL change:

<Info>
  The Anthropic SDK appends `/v1/messages` to its base URL, so configure it with `https://api.perplexity.ai/router` (no `/v1`). The OpenAI SDK appends `/chat/completions` and is configured with `https://api.perplexity.ai/router/v1`.
</Info>

<CodeGroup>
  ```python Python theme={null}
  from anthropic import Anthropic
  import os

  client = Anthropic(
      api_key=os.environ.get("PERPLEXITY_API_KEY"),
      base_url="https://api.perplexity.ai/router"
  )

  message = client.messages.create(
      model="perplexity/kimi-k3",
      max_tokens=1024,
      messages=[
          {"role": "user", "content": "Explain the CAP theorem in two sentences."}
      ]
  )

  print(message.content[0].text)
  ```

  ```typescript Typescript theme={null}
  import Anthropic from '@anthropic-ai/sdk';

  const client = new Anthropic({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai/router"
  });

  const message = await client.messages.create({
      model: "perplexity/kimi-k3",
      max_tokens: 1024,
      messages: [
          { role: "user", content: "Explain the CAP theorem in two sentences." }
      ]
  });

  console.log(message.content[0].text);
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/router/v1/messages' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "perplexity/kimi-k3",
      "max_tokens": 1024,
      "messages": [
        {"role": "user", "content": "Explain the CAP theorem in two sentences."}
      ]
    }' | jq
  ```
</CodeGroup>

## Discovering Models

List the current catalog at any time — the response is OpenAI-compatible, sorted by model id, and includes each model's base token prices in USD per 1M tokens:

```bash theme={null}
curl 'https://api.perplexity.ai/router/v1/models' \
  -H "Authorization: Bearer $PERPLEXITY_API_KEY" | jq
```

<Accordion title="Response">
  ```json theme={null}
  {
    "object": "list",
    "data": [
      {
        "id": "perplexity/deepseek-v4-flash-0731",
        "object": "model",
        "created": 0,
        "owned_by": "perplexity",
        "pricing": {
          "input": 0.13,
          "output": 0.26,
          "cache_read": 0.028,
          "unit": "usd_per_1m_tokens"
        }
      },
      {
        "id": "perplexity/glm-5.2",
        "object": "model",
        "created": 0,
        "owned_by": "perplexity",
        "pricing": {
          "input": 1.4,
          "output": 4.4,
          "cache_read": 0.14,
          "unit": "usd_per_1m_tokens"
        }
      },
      {
        "id": "perplexity/kimi-k3",
        "object": "model",
        "created": 0,
        "owned_by": "perplexity",
        "pricing": {
          "input": 3,
          "output": 15,
          "cache_read": 0.3,
          "unit": "usd_per_1m_tokens"
        }
      }
    ]
  }
  ```
</Accordion>

See the [models page](/docs/gateway/models) for the full catalog with pricing.

## Next Steps

<CardGroup>
  <Card title="Models & Pricing" icon="brain" href="/docs/gateway/models">
    The model catalog with per-token rates.
  </Card>

  <Card title="Routing & Reliability" icon="arrows-shuffle" href="/docs/gateway/routing-and-reliability">
    How requests are routed and what happens when a provider fails.
  </Card>

  <Card title="Chat Completions Reference" icon="code" href="/api-reference/gateway-chat-completions-post">
    Full request and response schema.
  </Card>

  <Card title="Responses Reference" icon="code" href="/api-reference/gateway-responses-post">
    The OpenAI Responses-compatible endpoint schema.
  </Card>

  <Card title="Messages Reference" icon="code" href="/api-reference/gateway-messages-post">
    The Anthropic-compatible endpoint schema.
  </Card>
</CardGroup>

Need help? Check out our [community](https://community.perplexity.ai) for support.


# Routing & Reliability
Source: https://docs.perplexity.ai/docs/gateway/routing-and-reliability

How the Perplexity Router API routes requests across model deployments, and what happens automatically when a provider degrades or fails.

<Note>
  Router API is in private preview. Email [api@perplexity.ai](mailto:api@perplexity.ai) to request access.
</Note>

## Overview

Depending on the model, a model id in the [catalog](/docs/gateway/models) can be served by any of several underlying deployments. The platform decides where each request runs — there are no routing parameters to set, and no per-provider configuration on your side. You send a model id; routing, health monitoring, and failover happen automatically.

Responses always echo the model id you requested, and billing always uses that model's [published rates](/docs/gateway/models), regardless of which deployment served the request.

## How Requests Are Routed

When a model has more than one deployment, traffic is spread across them according to a weighted split that is continuously adjusted based on observed health — error rates, capacity, and latency. Deployments that degrade shed traffic to healthy ones automatically and regain it gradually as they recover.

Multi-turn conversations are kept on the same deployment where possible, so prompt caching keeps working across requests — send the same conversation prefix and you benefit from [cache-read pricing](/docs/gateway/models) without doing anything special.

## Automatic Failover

When a deployment fails — a provider error, a rate limit, or a timeout — the request is retried on another deployment for that model when one is available. Each attempt is bounded by time-to-first-token and total-duration limits, and exceeding either counts as a failure.

Two behaviors worth designing around:

* **Errors you can fix are not retried.** Deterministic client errors — an invalid request or a prompt that exceeds the model's context window — surface immediately as a `400` rather than being retried across deployments.
* **When every deployment fails**, the request returns a `429` indicating the model is overloaded, with a `Retry-After` header. Retrying after the indicated interval is safe: requests that fail before producing any output are not billed.

## Streaming and Reliability

Failures before the first token are handled invisibly — failover happens before the stream starts, and you receive a normal response. If a stream fails after output has begun, it ends with an in-band error event; your client should treat an unterminated stream as incomplete. Streamed requests are billed for the tokens actually delivered.

## Next Steps

<CardGroup>
  <Card title="Models & Pricing" icon="brain" href="/docs/gateway/models">
    The model catalog with per-token rates.
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/gateway-chat-completions-post">
    Request and response schemas, including error shapes.
  </Card>
</CardGroup>


# API Groups & Billing
Source: https://docs.perplexity.ai/docs/getting-started/api-groups

Learn how to use the Perplexity API Portal to manage access, usage, billing, and team collaboration.

## What is an API Group?

An **API Group** is your organization's workspace in the Perplexity API Portal. It allows you to:

* **Manage billing** and payment methods for API usage
* **Create and control API keys** for accessing the Perplexity API
* **Invite team members** and control their permissions (optional)
* **Monitor usage and costs** across all your API keys

## Prerequisites

Before getting started, make sure you have:

* A Perplexity account (sign up at [perplexity.ai](https://perplexity.ai))
* **Admin permissions** for billing and API key management
* A **credit card** ready for payment setup (you won't be charged initially)

<Note>
  If you're joining an existing team, you'll need an invitation from an Admin. Contact your team lead to get access.
</Note>

## Accessing the API Portal

Navigate to [console.perplexity.ai](https://console.perplexity.ai) to access your API group. The left-hand sidebar is divided into two sections:

* **Group**: Settings, Members, Billing, API keys, Files
* **API Playground**: Search API, Agent API

***

## Creating and Managing an API Group

To set up your organization:

<Steps>
  <Step title="Access Group Settings">
    Click **Settings** in the left sidebar under **Group**.

    <Frame>
      <img alt="API Group Settings" />
    </Frame>
  </Step>

  <Step title="Complete Organization Details">
    Fill out your organization's name, address, and tax details.

    <Frame>
      <img alt="API Group Setup" />
    </Frame>

    <Info>
      Your organization name and address will appear on invoices and help us support you better.
    </Info>
  </Step>
</Steps>

***

## Billing and Payment Methods

### How Billing Works

The Perplexity API uses a **credit-based billing system**:

* **Credits** are purchased in advance and used for API calls
* **Different models** consume different amounts of credits per request
* **Usage is charged** based on tokens processed and search queries made
* **Automatic top-up** can be enabled to avoid service interruptions

<Info>
  See our [Pricing page](./pricing) for detailed cost information per model and usage type.
</Info>

### Setting Up Payment

<Card title="Access Billing Dashboard" icon="credit-card" href="https://console.perplexity.ai/group/billing">
  Navigate directly to your API billing dashboard to manage payment methods, view usage, and configure billing settings.
</Card>

<Steps>
  <Step title="Navigate to Billing">
    Click **Billing** in the left sidebar. This page shows your credit balance, payment method, usage chart, and billing breakdown.

    <Frame>
      <img alt="API Billing Dashboard" />
    </Frame>
  </Step>

  <Step title="Add Payment Method">
    Click **Add payment method** and enter your credit card information. Payment is managed via Stripe — you can also click **Manage ↗** to access the Stripe portal directly.

    <Note>
      Adding a payment method will not charge your credit card. It stores payment information for future API usage.
    </Note>
  </Step>

  <Step title="Configure Auto Reload (Recommended)">
    Enable automatic credit top-up by clicking **Change preferences** next to **Auto reload**.

    <Frame>
      <img alt="API Billing Dashboard" />
    </Frame>

    <Warning>
      If you run out of credits, your API keys will be blocked until you add to your credit balance. Auto reload prevents this by automatically adding credits when your balance drops below a threshold.
    </Warning>
  </Step>
</Steps>

### Credit Balance

The Billing page displays your **remaining credit balance** prominently at the top. You can purchase additional credits at any time using the **Buy more credits** link.

Your current **usage tier** is also shown here — click **Learn more ↗** for details on tier thresholds and benefits.

***

## Managing API Keys

### What are API Keys?

API keys are your credentials for accessing the Perplexity API. Each key:

* **Authenticates your requests** to the Perplexity API
* **Tracks usage** for attribution
* **Can be revoked** for security purposes
* **Should be kept secure** and never shared publicly

<Info>
  You'll need to include your API key in the Authorization header of every API request: `Authorization: Bearer $PERPLEXITY_API_KEY`
</Info>

### Creating an API Key

<Steps>
  <Step title="Navigate to API Keys">
    Click **API keys** in the left sidebar.

    <Frame>
      <img alt="API Keys" />
    </Frame>
  </Step>

  <Step title="Generate New Key">
    Click **+ Generate API Key** to create a new API key.

    <Frame>
      <img alt="API Keys" />
    </Frame>
  </Step>
</Steps>

<Warning>
  API keys are sensitive credentials. Never expose them in client-side code or share them in public repositories.
</Warning>

***

## Adding and Managing Members

Admins can invite team members to the organization with specific roles: **Admin** or **Member**.

### Adding a Member

<Steps>
  <Step title="Navigate to Members">
    Click **Members** in the left sidebar. This page shows your current team members and their roles.
  </Step>

  <Frame>
    <img alt="Members" />
  </Frame>

  <Step title="Initiate Member Invitation">
    Click **+ Add Member**. Enter the user's email address and click **Invite**.

    <Frame>
      <img alt="Add Member" />
    </Frame>
  </Step>

  <Step title="Member Receives Invitation">
    The invited user will receive an email with a link to join your group.

    <Check>
      Once they accept, they'll appear in your member list with their assigned role.
    </Check>
  </Step>
</Steps>

### Filtering Members by Role

Use the dropdown to filter your list of team members by role.

### Roles

* **Admin**: Full access to invite/remove members, manage billing, and view usage data.
* **Member**: Can view usage and account limits but cannot modify settings.

<Warning>
  Only Admins can make changes to billing and member permissions.
</Warning>

***

## Viewing Usage Metrics

All members can monitor API usage directly from the **Billing** page in the console.

<Frame>
  <img alt="Usage Metrics" />
</Frame>

The **Usage** chart lets you track activity over time with the following filters:

* **Metric selector**: Choose from Chat Completions API Requests, Input Tokens, Output Tokens, Citation Tokens, Reasoning Tokens, Deep Research Requests Count, Search API Requests Count, or Pro Search API Requests Count
* **Time range**: Filter by Last 7 Days, Last 30 Days, or custom range

Below the chart, the **Billing breakdown** table shows a per-model breakdown of usage quantity, rate, and cost — giving you a clear picture of spend by product.

<Check>
  Usage metrics help you monitor API activity and optimize for cost or performance.
</Check>

## Invoice History

Below the usage chart and billing breakdown on the **Billing** page, you'll find your **Invoice history** — a record of all past invoices with their date, status, and cost.

<Frame>
  <img alt="Invoice History" />
</Frame>

Invoices are generated automatically each billing cycle. Use the **Previous** and **Next** controls to paginate through older records.


# Perplexity with AG2
Source: https://docs.perplexity.ai/docs/getting-started/integrations/ag2

Use the Perplexity Search API as a tool inside AG2 (AutoGen) agents.

<SonarDeprecationNotice />

## Overview

AG2 ships a `PerplexitySearchToolkit` that wraps the [Perplexity Search API](/docs/search/quickstart) as a native AG2 tool. The tool returns ranked web results — title, URL, snippet, and date — without generating an LLM answer, which keeps token usage minimal and lets the calling agent decide how to consume them.

<Info>
  **AG2** (formerly AutoGen) is an open-source framework for building multi-agent conversational AI systems. Learn more at [ag2.ai](https://ag2.ai).
</Info>

## Installation

```bash theme={null}
pip install "ag2[perplexity]"
```

## API Key Setup

Set your Perplexity API key as an environment variable, or pass it to the toolkit constructor:

```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```

<Card title="Get API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate your API key from the Perplexity dashboard.
</Card>

## Quick Start

Register `PerplexitySearchToolkit` with an AG2 `Agent`:

```python theme={null}
from autogen.beta import Agent
from autogen.beta.tools.search import PerplexitySearchToolkit

toolkit = PerplexitySearchToolkit()
search = toolkit.search()

agent = Agent(
    "researcher",
    prompt="Answer using fresh information from the web.",
    tools=[search],
)

await agent.ask("What were the top tech announcements this week?")
```

The tool calls the Perplexity Search API under the hood and returns structured `PerplexitySearchResult` objects.

## Configuration

All search parameters are passed to `toolkit.search()` and forwarded to the Search API:

```python theme={null}
from autogen.beta.tools.search import PerplexitySearchToolkit

toolkit = PerplexitySearchToolkit()
search = toolkit.search(
    max_results=5,
    max_tokens_per_page=512,
    search_domain_filter=["arxiv.org", "-medium.com"],  # prefix with '-' to exclude
    search_recency_filter="week",                         # hour | day | week | month | year
    search_after_date_filter="1/1/2025",
    search_before_date_filter="12/31/2025",
)
```

You can also pass any parameter as an AG2 `Variable` so it can be resolved from the conversation context at runtime:

```python theme={null}
from autogen.beta import Variable
from autogen.beta.tools.search import PerplexitySearchToolkit

toolkit = PerplexitySearchToolkit()
search = toolkit.search(
    max_results=Variable("user_max"),
    search_recency_filter=Variable(),  # resolved from the variable named after the parameter
)
```

## Response Shape

Each call returns a `PerplexitySearchResponse` with the original query and a list of `PerplexitySearchResult` items:

```python theme={null}
@dataclass(slots=True)
class PerplexitySearchResult:
    title: str
    url: str
    snippet: str | None = None
    date: str | None = None

@dataclass(slots=True)
class PerplexitySearchResponse:
    query: str
    results: list[PerplexitySearchResult]
    content: str | None = None
    citations: list[str]
    images: list[PerplexityImageMeta]
```

## Links & Resources

<CardGroup>
  <Card title="AG2 Docs" icon="book" href="https://docs.ag2.ai">
    Build multi-agent systems with AG2.
  </Card>

  <Card title="Tool Source" icon="brand-github" href="https://github.com/ag2ai/ag2/blob/main/autogen/beta/tools/search/perplexity.py">
    PerplexitySearchToolkit implementation.
  </Card>

  <Card title="Search API Quickstart" icon="search" href="/docs/search/quickstart">
    Learn more about the underlying Perplexity Search API.
  </Card>

  <Card title="Common Toolkits" icon="toolbox" href="https://docs.ag2.ai/docs/beta/tools/common_toolkits">
    Browse all built-in AG2 tools.
  </Card>
</CardGroup>

## Support

Need help with the integration?

* Browse the [AG2 documentation](https://docs.ag2.ai)
* Review our [FAQ](/docs/resources/faq)


# Perplexity with Agno
Source: https://docs.perplexity.ai/docs/getting-started/integrations/agno

Use Perplexity's Agent API through Agno's OpenAI Responses integration.

<SonarDeprecationNotice />

## Overview

[Agno](https://docs.agno.com) is an open-source Python framework for building agents, teams, and workflows. Connect it to Perplexity's [Agent API](/docs/agent-api/quickstart) through Agno's OpenAI Responses-compatible model class.

## Installation

```bash theme={null}
pip install agno openai
```

## API Key Setup

Set your Perplexity API key as an environment variable:

```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```

<Card title="Get API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate your Perplexity API key from the API portal.
</Card>

## Quick Start

Use `OpenAIResponses` with the Agent API base URL and any supported Agent API model. Pass a research [preset](/docs/agent-api/presets) through `extra_body` so answers are grounded in live web results:

```python theme={null}
import os

from agno.agent import Agent
from agno.models.openai import OpenAIResponses

agent = Agent(
    model=OpenAIResponses(
        id="openai/gpt-5.6-luna",
        base_url="https://api.perplexity.ai/v1",
        api_key=os.environ["PERPLEXITY_API_KEY"],
        extra_body={"preset": "medium"},
    ),
    markdown=True,
)

agent.print_response(
    "What are the latest breakthroughs in fusion energy this year?",
    stream=True,
)
```

Swap `id` for any [Agent API model](/docs/agent-api/models) to route third-party models through Perplexity. The Agent API also provides research-backed [presets](/docs/agent-api/presets) and additional built-in [tools](/docs/agent-api/tools).

## Links & Resources

<CardGroup>
  <Card title="Agno OpenAIResponses Docs" icon="book" href="https://docs.agno.com/models/providers/native/openai/responses/usage/basic">
    Configure Agno's OpenAI Responses-compatible model.
  </Card>

  <Card title="Agent API Models" icon="sparkles" href="/docs/agent-api/models">
    Browse supported models and pricing.
  </Card>

  <Card title="Agno Docs" icon="globe" href="https://docs.agno.com">
    Learn more about agents, teams, and workflows in Agno.
  </Card>
</CardGroup>


# Perplexity with Google Antigravity
Source: https://docs.perplexity.ai/docs/getting-started/integrations/antigravity

Call Perplexity's Agent API from applications you build or edit inside Google Antigravity.

<SonarDeprecationNotice />

## Overview

[Google Antigravity](https://antigravity.google) is an agent-first development environment where AI agents plan, write, and iterate on your code across editor, terminal, and browser surfaces. While Antigravity ships with its own built-in agent models, the code your agents author can call any external API — including Perplexity's [Agent API](/docs/agent-api/quickstart) and [Search API](/docs/search/quickstart) — for real-time web research, citations, and grounded answers.

This guide shows how to add the Perplexity Agent API to a project you're building inside Antigravity, using the OpenAI Responses‑compatible interface.

<Info>
  **Scope of this guide.** Antigravity does not currently expose a BYOK or custom-provider hook for swapping its built-in agent model with Perplexity. This guide covers the supported path: calling Perplexity from your **application code** authored inside Antigravity (web apps, CLIs, coding assistants, internal tools, etc.). If Antigravity adds a custom-provider configuration in the future, the same base URL and API key documented here will apply.
</Info>

<Card title="Get a Perplexity API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate an API key in the Perplexity API Console, then store it in your project as `PERPLEXITY_API_KEY`.
</Card>

***

## When to Use This

The Agent API is a strong fit when your Antigravity-built project needs grounded, web-aware answers without you having to wire up search, scraping, and citation handling yourself. Common patterns:

* **AI features in web or mobile apps** — drop a research or Q\&A surface into a product without standing up your own retrieval stack.
* **Coding assistants and dev tools** — let agents fetch up-to-date library docs, error explanations, or changelogs at runtime.
* **Internal tools and dashboards** — answer questions over the live web (market data, competitive moves, news) with sources attached.
* **CLIs and scripts** — quick research utilities you run from the Antigravity terminal.

***

## Setup

<Steps>
  <Step title="Store Your API Key as an Environment Variable">
    In the Antigravity terminal (or your project's `.env` file), set:

    <Tabs>
      <Tab title="macOS / Linux">
        ```bash theme={null}
        export PERPLEXITY_API_KEY="pplx-..."
        ```
      </Tab>

      <Tab title="Windows (PowerShell)">
        ```powershell theme={null}
        setx PERPLEXITY_API_KEY "pplx-..."
        ```
      </Tab>

      <Tab title=".env file">
        ```bash theme={null}
        PERPLEXITY_API_KEY=pplx-...
        ```
      </Tab>
    </Tabs>

    Never hardcode the key in source files — Antigravity agents may commit or share code they read, so treating the key as an environment variable keeps it out of the repo.
  </Step>

  <Step title="Install an SDK">
    The Agent API is compatible with the [OpenAI Responses API](/docs/agent-api/openai-compatibility), so the OpenAI SDK works directly. The native Perplexity SDK is also available and provides cleaner preset syntax.

    <Tabs>
      <Tab title="TypeScript / Node">
        ```bash theme={null}
        npm install openai
        ```
      </Tab>

      <Tab title="Python">
        ```bash theme={null}
        pip install openai
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Point the Client at Perplexity">
    Set the base URL to `https://api.perplexity.ai/v1` and read the API key from the environment.

    <Tabs>
      <Tab title="TypeScript / Node">
        ```typescript theme={null}
        import OpenAI from "openai";

        const client = new OpenAI({
          apiKey: process.env.PERPLEXITY_API_KEY,
          baseURL: "https://api.perplexity.ai/v1",
        });

        const response = await client.responses.create({
          input: "Summarize the top three AI infrastructure announcements this week with sources.",
          preset: "low",
        } as any);

        console.log(response.output_text);
        ```
      </Tab>

      <Tab title="Python">
        ```python theme={null}
        import os
        from openai import OpenAI

        client = OpenAI(
            api_key=os.environ.get("PERPLEXITY_API_KEY"),
            base_url="https://api.perplexity.ai/v1",
        )

        response = client.responses.create(
            input="Summarize the top three AI infrastructure announcements this week with sources.",
            extra_body={"preset": "low"},
        )

        print(response.output_text)
        ```
      </Tab>
    </Tabs>

    The OpenAI SDK sends `client.responses.create(...)` to `POST /v1/responses`, which Perplexity accepts as an alias for the canonical `POST /v1/agent` endpoint. No other configuration is required.
  </Step>
</Steps>

***

## Using It from Inside Antigravity

Once the client is wired up, you can prompt Antigravity's agent to use the Perplexity client wherever your app needs grounded answers. A few prompts that work well:

* *"Add a `/research` endpoint that takes a `query` string and returns the Perplexity Agent API response with citations."*
* *"Wrap the Perplexity call in a `researchTopic(topic: string)` helper and call it from the dashboard's news widget."*
* *"Write a CLI subcommand `pplx ask` that streams a Perplexity Agent API response to stdout."*

Because the SDK is the standard OpenAI client, Antigravity's agent will already know the call shape — you mainly need to make sure it uses the right `baseURL` and reads `PERPLEXITY_API_KEY` from the environment.

<Tip>
  If Antigravity's agent generates code that points at `https://api.openai.com/v1` or omits the `baseURL` entirely, ask it to "use the Perplexity base URL `https://api.perplexity.ai/v1`" — it will regenerate the client with the correct endpoint.
</Tip>

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Base URL Must Be Exactly https://api.perplexity.ai/v1">
    The OpenAI SDK appends `/responses` to the base URL on its own. Do **not** include `/agent` or `/responses` in the base URL, and do not omit `/v1`.

    | Correct                        | Wrong                                       |
    | ------------------------------ | ------------------------------------------- |
    | `https://api.perplexity.ai/v1` | `https://api.perplexity.ai/v1/agent`        |
    |                                | `https://api.perplexity.ai/v1/responses`    |
    |                                | `https://api.perplexity.ai` (missing `/v1`) |

    Wrong base URLs typically surface as 404s or authentication errors.
  </Accordion>

  <Accordion title="Can I Replace Antigravity's Built-In Agent Model with Perplexity?">
    Not today. Antigravity does not expose a custom-provider or BYOK setting that would let you route its in-editor agent through Perplexity. Use this guide's pattern — calling the Perplexity Agent API from your application code — instead.

    If Antigravity adds custom-provider support in the future, the configuration will be: base URL `https://api.perplexity.ai/v1`, API key from `PERPLEXITY_API_KEY`, and an OpenAI Responses‑compatible transport.
  </Accordion>

  <Accordion title="API Key Isn't Being Picked Up">
    Antigravity terminal sessions inherit environment variables from where Antigravity was launched. If `echo $PERPLEXITY_API_KEY` is empty in the integrated terminal, either set it in your shell profile (`~/.zshrc`, `~/.bashrc`) and relaunch Antigravity, or load it from a project-local `.env` file using something like `dotenv`.
  </Accordion>

  <Accordion title="Choosing a Model vs. a Preset">
    Presets like `low` are pre-configured for common research workloads and are the easiest starting point. If you need a specific third-party model (Claude, GPT, Gemini, etc.), pass `model="anthropic/claude-sonnet-4-6"` (or another value from the [Agent API models list](/docs/agent-api/models)) instead of `preset`.
  </Accordion>
</AccordionGroup>

***

## Links & Resources

<CardGroup>
  <Card title="Agent API Quickstart" icon="rocket" href="/docs/agent-api/quickstart">
    Build with the Agent API using OpenAI-compatible or native SDKs.
  </Card>

  <Card title="OpenAI Compatibility" icon="plug" href="/docs/agent-api/openai-compatibility">
    Full reference for using the OpenAI SDK against Perplexity.
  </Card>

  <Card title="Agent API Presets" icon="sparkles" href="/docs/agent-api/presets">
    Pre-configured setups like `low` for common workloads.
  </Card>

  <Card title="Agent API Models" icon="brain" href="/docs/agent-api/models">
    Full list of third-party and Perplexity models available via the Agent API.
  </Card>

  <Card title="Perplexity SDK" icon="code" href="/docs/sdk/overview">
    Native SDK with cleaner preset syntax and full type safety.
  </Card>

  <Card title="API Console" icon="key" href="https://console.perplexity.ai">
    Generate and manage your Perplexity API keys.
  </Card>
</CardGroup>


# Perplexity with AnythingLLM
Source: https://docs.perplexity.ai/docs/getting-started/integrations/anythingllm

Use Perplexity as the LLM provider in AnythingLLM for grounded, citation-backed chat over your documents and workspaces.

<SonarDeprecationNotice />

## Overview

[AnythingLLM](https://anythingllm.com) is an all-in-one AI productivity app that turns any document, resource, or piece of content into context for LLM-powered chat. It supports both desktop and self-hosted deployments and works with dozens of LLM providers — including Perplexity as a first-class cloud provider, giving every workspace access to web-grounded answers with citations.

<Info>
  **AnythingLLM** is built and maintained by Mintplex Labs. It supports per-workspace LLM configuration, so you can use Perplexity in one workspace and a different provider in another. Learn more at [anythingllm.com](https://anythingllm.com).
</Info>

## Setup

<Steps>
  <Step title="Get your API key">
    Generate a Perplexity API key from the [API portal](https://console.perplexity.ai/group/keys).

    <Card title="Get API Key" icon="key" href="https://console.perplexity.ai/group/keys">
      Generate your Perplexity API key.
    </Card>
  </Step>

  <Step title="Open LLM settings">
    In AnythingLLM, go to **Settings → LLM Preference**.
  </Step>

  <Step title="Select Perplexity AI">
    Choose **Perplexity AI** from the provider list and paste your API key.
  </Step>

  <Step title="Choose a model">
    Once your key is entered, the **Chat Model Selection** dropdown automatically populates with available Perplexity models. Pick the model you want (e.g., `sonar-pro`) and save.
  </Step>
</Steps>

## System vs. Workspace Models

AnythingLLM lets you scope LLM choice at two levels:

* **System LLM** — The default provider used for every workspace and agent.
* **Workspace LLM** — Per-workspace override that takes precedence when chatting inside that workspace.

You can mix providers freely. For example, set Anthropic as your system default and use Perplexity in a specific workspace where you need real-time web grounding for research-heavy chats.

To override per workspace: open the workspace, go to **Workspace Settings → Chat Settings → Workspace LLM Provider**, and select **Perplexity AI** with the model you want.

## Available Models

All Perplexity models supported by the API are available to AnythingLLM users — the model dropdown populates dynamically once your API key is validated. Recommended models:

* `sonar` — fast, cost-effective web-grounded chat
* `sonar-pro` — advanced reasoning with broader citation depth
* `sonar-reasoning-pro` — multi-step reasoning with search

See the full list of [Perplexity models and capabilities](/docs/sonar/models).

## Use Cases

Pairing Perplexity with AnythingLLM gives you:

* **Live web answers inside document workflows** — your workspace can answer questions about uploaded PDFs and the open web in the same chat.
* **Citation-grounded retrieval** — Perplexity returns source URLs you can audit alongside your retrieval-augmented context.
* **No-RAG fallback for current events** — when documents don't contain the answer, the model can reach for live web context automatically.

## Agent Configuration

When using AnythingLLM's [AI agents](https://docs.anythingllm.com/agent/setup), you can configure Perplexity as the agent's LLM in the workspace's **Agent Configuration** menu. This is useful for agents that need to chain web research with skills like web browsing, document Q\&A, or external API calls.

## Links & Resources

<CardGroup>
  <Card title="AnythingLLM Perplexity Docs" icon="book" href="https://docs.anythingllm.com/setup/llm-configuration/cloud/perplexity-ai">
    Official AnythingLLM setup guide for Perplexity AI.
  </Card>

  <Card title="AnythingLLM Docs" icon="globe" href="https://docs.anythingllm.com">
    Full AnythingLLM documentation.
  </Card>

  <Card title="Perplexity API Reference" icon="code" href="/api-reference">
    Full Perplexity API reference.
  </Card>

  <Card title="Perplexity Models" icon="sparkles" href="/docs/sonar/models">
    Available Sonar models and capabilities.
  </Card>
</CardGroup>

## Support

Need help with the integration?

* Browse the [AnythingLLM documentation](https://docs.anythingllm.com)
* Review our [FAQ](/docs/resources/faq)


# Perplexity with CAMEL-AI
Source: https://docs.perplexity.ai/docs/getting-started/integrations/camel

Use the Perplexity Search API as a tool inside CAMEL-AI multi-agent systems.

<SonarDeprecationNotice />

## Overview

CAMEL-AI's `SearchToolkit` ships a `search_perplexity` method that wraps the [Perplexity Search API](/docs/search/quickstart) as a native CAMEL tool. The tool returns ranked web results — title, URL, snippet, and date — so the calling `ChatAgent` can ground its responses on fresh, citable sources.

<Info>
  **CAMEL-AI** is an open-source framework for building communicative multi-agent systems. Learn more at [camel-ai.org](https://www.camel-ai.org).
</Info>

## Installation

```bash theme={null}
pip install camel-ai
```

## API Key Setup

Set your Perplexity API key as an environment variable:

```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```

<Card title="Get API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate your API key from the Perplexity dashboard.
</Card>

## Quick Start

Register `search_perplexity` as a tool on a `ChatAgent`:

```python theme={null}
from camel.agents import ChatAgent
from camel.toolkits import FunctionTool, SearchToolkit

agent = ChatAgent(
    system_message=(
        "You are a helpful assistant that can use the Perplexity "
        "search engine to answer questions."
    ),
    tools=[FunctionTool(SearchToolkit().search_perplexity)],
)

response = agent.step(
    input_message="What are the latest developments in multi-agent AI systems?",
    response_format=None,
)
print(response.msgs[0].content)
```

The tool calls `POST https://api.perplexity.ai/search` under the hood and returns the raw API response so the agent can pick which results to cite.

## Configuration

All Search API parameters are supported directly on `search_perplexity`:

```python theme={null}
from camel.toolkits import SearchToolkit

toolkit = SearchToolkit()

results = toolkit.search_perplexity(
    query="AI safety research",
    max_results=5,
    max_tokens_per_page=512,
    country="US",
    search_recency_filter="week",                         # hour | day | week | month | year
    search_domain_filter=["arxiv.org", "-medium.com"],   # prefix with '-' to exclude
    search_language_filter=["en"],
)
```

You can also pass a list of queries for batched search, or use `extra_params` to forward any additional Search API field that isn't yet a first-class argument:

```python theme={null}
results = toolkit.search_perplexity(
    query=["NVIDIA earnings", "AMD earnings"],
    max_results=3,
    extra_params={
        "search_after_date_filter": "1/1/2026",
        "search_before_date_filter": "5/1/2026",
    },
)
```

## Response Shape

`search_perplexity` returns the raw Perplexity Search API response as a `Dict[str, Any]`. On success it contains a `results` list along with `id` and `server_time`:

```python theme={null}
{
    "id": "...",
    "server_time": "...",
    "results": [
        {
            "title": "...",
            "url": "...",
            "snippet": "...",
            "date": "...",          # may be present
            "last_updated": "...",  # may be present
        },
        # ...
    ],
}
```

On failure the response is a dictionary with an `error` key describing the issue (missing API key, HTTP error, or request exception).

## Links & Resources

<CardGroup>
  <Card title="CAMEL-AI Docs" icon="book" href="https://docs.camel-ai.org">
    Build multi-agent systems with CAMEL-AI.
  </Card>

  <Card title="Tool Source" icon="brand-github" href="https://github.com/camel-ai/camel/blob/master/camel/toolkits/search_toolkit.py">
    SearchToolkit.search\_perplexity implementation.
  </Card>

  <Card title="Search API Quickstart" icon="search" href="/docs/search/quickstart">
    Learn more about the underlying Perplexity Search API.
  </Card>

  <Card title="Example Script" icon="code" href="https://github.com/camel-ai/camel/blob/master/examples/toolkits/search_toolkit.py">
    End-to-end CAMEL example using Perplexity search.
  </Card>
</CardGroup>

## Support

Need help with the integration?

* Browse the [CAMEL-AI documentation](https://docs.camel-ai.org)
* Review our [FAQ](/docs/resources/faq)


# Perplexity with Claude Code
Source: https://docs.perplexity.ai/docs/getting-started/integrations/claude-code

Use Perplexity inside Claude Code — call the API from project code with the official TypeScript SDK, use the OpenAI-compatible base URL, or wire up the hosted Perplexity Docs MCP for in-editor documentation lookup.

<SonarDeprecationNotice />

## Overview

[Claude Code](https://docs.claude.com/en/docs/claude-code) is Anthropic's agentic coding tool that lives in your terminal, IDE, and CI. It can edit files, run commands, and call Model Context Protocol (MCP) servers as part of its workflow. This guide covers three integration paths for Perplexity:

<CardGroup>
  <Card title="Official TypeScript SDK" icon="code">
    Let Claude Code write and run application code that calls the Perplexity API directly. **Recommended.**
  </Card>

  <Card title="OpenAI-Compatible SDK" icon="plug">
    Reuse an existing OpenAI client by pointing `baseURL` at `https://api.perplexity.ai/v1`.
  </Card>

  <Card title="Claude Code MCP" icon="book">
    Register the hosted Perplexity Docs MCP with `claude mcp add` so Claude Code can look up Perplexity docs while you work.
  </Card>
</CardGroup>

<Info>
  **Recommended path:** Have Claude Code build features against your project code using the official SDK (or the OpenAI-compatible SDK), and register the Perplexity Docs MCP for in-editor documentation lookup. Claude Code does **not** officially support swapping its underlying model for the Perplexity API — see [Replacing Claude Code's model (not recommended)](#replacing-claude-codes-model-not-recommended).
</Info>

## Prerequisites

* Claude Code installed — see the [Claude Code quickstart](https://docs.claude.com/en/docs/claude-code/quickstart)
* Node.js 18+ for the TypeScript examples
* A Perplexity API key

<Card title="Get API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate a key from the Perplexity API Portal.
</Card>

## API key handling

Never hardcode your API key in source files or commit it to a repository. Store it in an environment variable and read it at runtime:

<Tabs>
  <Tab title="macOS/Linux">
    ```bash theme={null}
    export PERPLEXITY_API_KEY="your_api_key_here"
    ```
  </Tab>

  <Tab title="Windows">
    ```powershell theme={null}
    setx PERPLEXITY_API_KEY "your_api_key_here"
    ```
  </Tab>

  <Tab title=".env (project-local)">
    Create a `.env` file in your project root and add it to `.gitignore`:

    ```bash theme={null}
    # .env
    PERPLEXITY_API_KEY=your_api_key_here
    ```

    Load it at startup (for example with [`dotenv`](https://www.npmjs.com/package/dotenv)):

    ```typescript theme={null}
    import "dotenv/config";
    ```
  </Tab>
</Tabs>

<Warning>
  Treat `PERPLEXITY_API_KEY` like a password. Don't paste it into prompts, share it with Claude Code, or commit it to source control. If a key is exposed, [rotate it](https://console.perplexity.ai/group/keys) immediately.
</Warning>

***

## Path 1: Official TypeScript SDK (recommended)

Have Claude Code scaffold and edit code that calls the Perplexity API using the official SDK. This is the most reliable path and gives you full type safety, preset support, and access to every API feature.

### Install

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

<Tip>
  `pnpm` and `yarn` work the same way: `pnpm add @perplexity-ai/perplexity_ai` / `yarn add @perplexity-ai/perplexity_ai`.
</Tip>

### Agent API with `low`

The Agent API is the recommended surface for most applications. Use the `low` preset for web-grounded responses with sensible defaults:

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

const client = new Perplexity(); // reads PERPLEXITY_API_KEY from the environment

const response = await client.responses.create({
  preset: "low",
  input: "Summarize the latest changes to the Perplexity Agent API.",
});

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

<Accordion title="Python equivalent">
  ```python theme={null}
  from perplexity import Perplexity

  client = Perplexity()  # reads PERPLEXITY_API_KEY from the environment

  response = client.responses.create(
      preset="low",
      input="Summarize the latest changes to the Perplexity Agent API.",
  )

  print(f"Model used: {response.model}")
  print(response.output_text)
  ```
</Accordion>

### Add web search

Enable the `web_search` tool for explicit control over when search is used:

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

const client = new Perplexity();

const response = await client.responses.create({
  model: "openai/gpt-5.4",
  input: "What are the latest developments in AI inference hardware?",
  tools: [{ type: "web_search" }],
  instructions:
    "You have access to a web_search tool. Use it for questions about current events, news, or recent developments.",
});

if (response.status === "completed") {
  console.log(response.output_text);
}
```

<Tip>
  Ask Claude Code to scaffold these calls for you — for example, *"Add a `summarize.ts` script that uses `@perplexity-ai/perplexity_ai` with the `low` preset and reads `PERPLEXITY_API_KEY` from the environment."* Claude Code will edit the file, install the package, and run it.
</Tip>

For more presets, tools, and configuration options see the [Agent API quickstart](/docs/agent-api/quickstart) and the [SDK overview](/docs/sdk/overview).

***

## Path 2: OpenAI-compatible SDK

If your project already uses an OpenAI client, you can reuse it by pointing the `baseURL` at `https://api.perplexity.ai/v1`. Perplexity accepts `POST /v1/responses` as an alias for the Agent API.

### Install

```bash theme={null}
npm install openai
```

### Use it

```typescript theme={null}
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.PERPLEXITY_API_KEY,
  baseURL: "https://api.perplexity.ai/v1",
});

const response = await client.responses.create({
  model: "openai/gpt-5.4",
  input: "Explain the key differences between REST and GraphQL APIs.",
});

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

<Accordion title="Python equivalent">
  ```python theme={null}
  import os
  from openai import OpenAI

  client = OpenAI(
      api_key=os.environ.get("PERPLEXITY_API_KEY"),
      base_url="https://api.perplexity.ai/v1",
  )

  response = client.responses.create(
      model="openai/gpt-5.4",
      input="Explain the key differences between REST and GraphQL APIs.",
  )

  print(response.output_text)
  ```
</Accordion>

<Info>
  Use `baseURL` (TypeScript) or `base_url` (Python) — both must include the `/v1` suffix. See the [OpenAI Compatibility guide](/docs/agent-api/openai-compatibility) for the full list of supported parameters and which Perplexity features are available through this path.
</Info>

***

## Path 3: Claude Code MCP for docs lookup

Claude Code supports the Model Context Protocol (MCP). The hosted **Perplexity Docs MCP** at `https://docs.perplexity.ai/mcp` lets Claude Code search and read Perplexity's documentation directly — useful for grounding code suggestions in canonical docs without context-switching to a browser.

### Add the server

Claude Code can register a remote MCP server over HTTP using the `claude mcp add` command with the `--transport http` flag:

<Tabs>
  <Tab title="Project scope">
    Add the server only for the current project (writes to `.mcp.json` in your repo root):

    ```bash theme={null}
    claude mcp add --transport http --scope project perplexity-docs https://docs.perplexity.ai/mcp
    ```
  </Tab>

  <Tab title="User scope">
    Add the server for all projects on this machine:

    ```bash theme={null}
    claude mcp add --transport http --scope user perplexity-docs https://docs.perplexity.ai/mcp
    ```
  </Tab>
</Tabs>

<Tip>
  If you'd rather not run the CLI, you can also edit the project's `.mcp.json` directly:

  ```json theme={null}
  {
    "mcpServers": {
      "perplexity-docs": {
        "type": "http",
        "url": "https://docs.perplexity.ai/mcp"
      }
    }
  }
  ```

  Claude Code reads `.mcp.json` at the repo root for project-scoped servers. Refer to the [Claude Code MCP documentation](https://docs.claude.com/en/docs/claude-code/mcp) for the canonical schema and any newer transport options.
</Tip>

### Verify and use

<Steps>
  <Step title="Confirm the server is registered">
    Run `claude mcp list` and check that `perplexity-docs` appears in the output.
  </Step>

  <Step title="Restart Claude Code">
    Quit and relaunch Claude Code (or run `/mcp` from inside a session) so the new server is loaded.
  </Step>

  <Step title="Use it from a prompt">
    Ask Claude Code something like *"Using the Perplexity docs MCP, show me how to enable `low` in the Agent API."* Claude Code will call the MCP server and ground its answer in current documentation.
  </Step>
</Steps>

<Info>
  The Docs MCP is read-only and does not require an API key — it only serves Perplexity documentation. To give Claude Code access to Perplexity **search and reasoning** tools (not just docs), install the [Perplexity MCP Server](/docs/getting-started/integrations/mcp-server), which uses `@perplexity-ai/mcp-server` and requires `PERPLEXITY_API_KEY`.
</Info>

***

## Replacing Claude Code's model (not recommended)

Claude Code is designed to run on Anthropic's Claude models, and the agent's tool use, prompting, and editing behavior are tuned to those models. Pointing the Claude Code CLI at the Perplexity API as an alternative model provider is **not an officially supported configuration**.

Instead:

* **Use Perplexity from your project code** (Path 1 or Path 2). Claude Code will happily write, edit, and run code that calls Perplexity for web-grounded answers, research, and search.
* **Add the Perplexity Docs MCP** (Path 3) so Claude Code can look up Perplexity documentation in-session.

This combination gives you Claude Code's editing and orchestration strengths alongside Perplexity's search-grounded responses, without depending on undocumented model-override behavior.

***

## Next steps

<CardGroup>
  <Card title="Agent API quickstart" icon="rocket" href="/docs/agent-api/quickstart">
    Presets, tools, and the full Agent API surface used by the examples above.
  </Card>

  <Card title="Perplexity SDK overview" icon="code-circle" href="/docs/sdk/overview">
    Install, configure, and use the official Python and TypeScript SDKs.
  </Card>

  <Card title="OpenAI compatibility" icon="plug" href="/docs/agent-api/openai-compatibility">
    Drop-in compatibility details, supported parameters, and migration tips.
  </Card>

  <Card title="Perplexity MCP Server" icon="server" href="/docs/getting-started/integrations/mcp-server">
    Add Perplexity search, ask, research, and reason tools to Claude Code and other MCP clients.
  </Card>
</CardGroup>

<Info>
  Need help? Join the [Perplexity developer community](https://community.perplexity.ai) for support and discussion.
</Info>


# Perplexity with Composio
Source: https://docs.perplexity.ai/docs/getting-started/integrations/composio

Expose Perplexity's Agent, Search, and Embeddings APIs as MCP tools or direct API actions for any AI agent framework via Composio.

<SonarDeprecationNotice />

## Overview

[Composio](https://composio.dev) is a universal tool gateway for AI agents. The Composio Perplexity toolkit exposes Perplexity's Agent, Search, and Embeddings APIs as tools that any agent framework can call through a single MCP URL or direct API integration.

<Info>
  **Composio** handles authentication, secure credential storage, OAuth flows, and tool routing for 1000+ apps. Learn more at [composio.dev](https://composio.dev).
</Info>

The toolkit ships these Perplexity actions:

* **Execute Agent** — `POST /v1/agent` (Agent API responses)
* **Perplexity Search (Raw Results)** — `POST /search`
* **Create Embeddings** — `POST /v1/embeddings`
* **Create Contextualized Embeddings** — `POST /v1/contextualizedembeddings`
* **List Models** — `GET /v1/models`

## Prerequisites

* A [Composio account](https://composio.dev) and API key
* A Perplexity API key

<Card title="Get API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate your Perplexity API key from the API portal.
</Card>

## Installation

```bash theme={null}
pip install composio
```

For agent-framework integrations, install your framework SDK alongside Composio (Composio supports Claude Agent SDK, OpenAI Agents SDK, LangChain, LlamaIndex, Mastra, Pydantic AI, AutoGen, CrewAI, Google ADK, and more).

## Quick Start: Tool Router (MCP)

The Tool Router exposes Perplexity as an MCP server your agent can connect to. This works with any MCP-compatible client (Claude Code, Cursor, OpenCode, etc.).

```python theme={null}
from composio import Composio

composio = Composio(api_key="your-composio-api-key")
session = composio.create(user_id="your-user-id")
url = session.mcp.url

print(f"MCP URL: {url}")
```

Wire that URL into your agent's MCP configuration:

```python theme={null}
import asyncio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions

options = ClaudeAgentOptions(
    permission_mode="bypassPermissions",
    mcp_servers={
        "tool_router": {
            "type": "http",
            "url": url,
            "headers": {"x-api-key": "your-composio-api-key"},
        }
    },
    system_prompt="You are a helpful assistant with access to Perplexity tools.",
    max_turns=10,
)

async def main():
    async with ClaudeSDKClient(options=options) as client:
        await client.query("Summarize the latest AI research papers")
        async for message in client.receive_response():
            if hasattr(message, "content"):
                for block in message.content:
                    if hasattr(block, "text"):
                        print(block.text)

asyncio.run(main())
```

## Quick Start: Direct API Actions

You can also execute Perplexity actions directly from Composio without an MCP layer:

```python theme={null}
from composio import Composio

composio = Composio(api_key="your-composio-api-key")

# Connect the user's Perplexity account once
composio.toolkits.authorize(
    user_id="your-user-id",
    toolkit="perplexityai",
)

# Run an Agent API request
result = composio.tools.execute(
    slug="PERPLEXITYAI_EXECUTE_AGENT",
    user_id="your-user-id",
    arguments={
        "model": "openai/gpt-5.6-sol",
        "tools": [{"type": "web_search"}],
        "input": "What are the latest fusion-energy headlines?",
    },
)

print(result["data"])
```

## Supported Agent Frameworks

Composio's Perplexity toolkit works with every agent framework Composio supports, including:

* ChatGPT, OpenAI Agents SDK, Codex
* Claude Agents SDK, Claude Code
* Cursor, VS Code, OpenCode
* Google ADK, LangChain, AI SDK, Mastra AI
* LlamaIndex, CrewAI, Pydantic AI, AutoGen

Each framework has a dedicated setup guide in the [Composio Perplexity toolkit](https://composio.dev/toolkits/perplexityai) page.

## Authentication

Composio stores your Perplexity API key securely and injects it into every request. You provide your key once during the toolkit authorization flow — either through the Composio dashboard or programmatically via `composio.toolkits.authorize(...)`. Composio handles token refresh, scope management, and request signing on every call.

## Links & Resources

<CardGroup>
  <Card title="Composio Perplexity Toolkit" icon="toolbox" href="https://composio.dev/toolkits/perplexityai">
    Full toolkit documentation with framework-specific guides.
  </Card>

  <Card title="Composio Docs" icon="book" href="https://docs.composio.dev">
    Composio platform documentation.
  </Card>

  <Card title="Perplexity API Reference" icon="code" href="/api-reference">
    Full Perplexity API reference.
  </Card>

  <Card title="Agent API Models" icon="sparkles" href="/docs/agent-api/models">
    Available models and pricing.
  </Card>
</CardGroup>

## Support

Need help with the integration?

* Browse the [Composio documentation](https://docs.composio.dev)
* Review our [FAQ](/docs/resources/faq)


# Perplexity Computer MCP Server
Source: https://docs.perplexity.ai/docs/getting-started/integrations/computer-mcp-server

Give AI assistants the ability to complete real-world tasks using Perplexity Computer through the Model Context Protocol (MCP).

<SonarDeprecationNotice />

## Overview

The Perplexity Computer MCP Server connects AI assistants to [Perplexity Computer](https://www.perplexity.ai), a general-purpose AI agent that can complete virtually any task on your behalf. Through the Model Context Protocol, your MCP client can delegate complex, multi-step work to Computer and receive structured results.

<Note>
  This integration is separate from the [Perplexity API MCP Server](/docs/getting-started/integrations/mcp-server), which is focused on Perplexity's Search and Completion APIs.
</Note>

Computer can:

* **Search and browse** the web for real-time information, including login-gated pages
* **Write and execute code** in an interactive Linux sandbox with Python, Node, and standard Unix tools
* **Create documents and media** including PDFs, slide decks, spreadsheets, images, and videos
* **Read and send emails** via Gmail and Outlook, and schedule calendar events
* **Manage tasks** across GitHub, Linear, Jira, Asana, Slack, Notion, and more
* **Analyze data** from Snowflake, Databricks, Google Sheets, Salesforce, and other sources
* **Build and deploy websites** to a live public URL in minutes
* **Connect to 400+ services** through a managed connector framework with one-click OAuth

## Authentication

The Computer MCP Server authenticates users via **OAuth 2.0** using your Perplexity account. No API key is required.

On first use, compatible MCP clients open a browser window to complete the authorization flow automatically.

<Info>
  Computer usage is billed against your Perplexity account credits. If your balance is insufficient, Computer returns `insufficient_credits` with a link to manage billing.
</Info>

## Installation

<Steps>
  <Step title="Step 1: Install the server">
    Add the Computer MCP server to your client.

    <Tabs>
      <Tab title="Claude Code">
        ```bash theme={null}
        claude mcp add perplexity-computer --transport http https://www.perplexity.ai/rest/computer/mcp
        ```
      </Tab>

      <Tab title="Codex">
        ```bash theme={null}
        codex mcp add perplexity-computer --url https://www.perplexity.ai/rest/computer/mcp
        ```
      </Tab>

      <Tab title="Cursor">
        Add to your `mcp.json`:

        ```json theme={null}
        {
          "mcpServers": {
            "perplexity-computer": {
              "url": "https://www.perplexity.ai/rest/computer/mcp"
            }
          }
        }
        ```
      </Tab>

      <Tab title="VS Code">
        Add to your `.vscode/mcp.json`:

        ```json theme={null}
        {
          "servers": {
            "perplexity-computer": {
              "type": "http",
              "url": "https://www.perplexity.ai/rest/computer/mcp"
            }
          }
        }
        ```
      </Tab>

      <Tab title="Windsurf">
        Add to your `~/.codeium/windsurf/mcp_config.json`:

        ```json theme={null}
        {
          "mcpServers": {
            "perplexity-computer": {
              "serverUrl": "https://www.perplexity.ai/rest/computer/mcp"
            }
          }
        }
        ```
      </Tab>

      <Tab title="Claude Desktop">
        Add to your `claude_desktop_config.json`:

        ```json theme={null}
        {
          "mcpServers": {
            "perplexity-computer": {
              "url": "https://www.perplexity.ai/rest/computer/mcp"
            }
          }
        }
        ```
      </Tab>

      <Tab title="Other Clients">
        Any MCP client that supports the HTTP transport can connect using the server URL:

        ```
        https://www.perplexity.ai/rest/computer/mcp
        ```

        Refer to your client's documentation for the correct configuration format.
      </Tab>
    </Tabs>
  </Step>

  <Step title="Step 2: Authenticate with Perplexity Computer">
    After installation, you will be asked to authenticate with your Perplexity account, and will be directed to a browser window to complete the OAuth flow.

    <img alt="Perplexity OAuth screen for Computer MCP" />
  </Step>

  <Step title="Step 3: Start using the Computer MCP">
    Once authenticated, you're ready to start delegating tasks to Perplexity Computer through your MCP client.

    Run a short flow to test the connection and see Computer in action:

    ```text theme={null}
    Summarize the top 5 stories on Hacker News right now.
    ```

    Then follow up in the same conversation:

    ```text theme={null}
    Turn that into a PDF report.
    ```
  </Step>
</Steps>

## Conversation Threading

Computer remembers the context from the first message and builds on it. To keep follow-up prompts in the same workflow, your MCP client must pass the `thread_id` from the previous response.

The first call creates a new thread and returns a `thread_id`. Reuse that `thread_id` on later calls to continue the same session.

```
1. call_perplexity_computer(message: "Summarize the top 5 stories on Hacker News right now")
   -> { thread_id: "123e4567-e89b-12d3-a456-426614174000", event: "complete", text: "Here are today's top stories..." }

2. call_perplexity_computer(message: "Turn that into a PDF report", thread_id: "123e4567-e89b-12d3-a456-426614174000")
   -> { thread_id: "123e4567-e89b-12d3-a456-426614174000", event: "complete", text: "Here's the report.\n\n[report.pdf](https://...)" }
```

This also applies to interactive events. If Computer needs to connect to a service mid-task, it returns an `auth_required` event, and after authentication the conversation resumes on the same thread:

```
1. call_perplexity_computer(message: "Email me a summary of my unread Slack messages")
   -> { thread_id: "123e4567-e89b-12d3-a456-426614174001", event: "auth_required", interactive: { type: "auth_required", connector: "slack", auth_url: "https://..." } }

2. notify_connected(thread_id: "123e4567-e89b-12d3-a456-426614174001", message: "Slack connected")
   -> { thread_id: "123e4567-e89b-12d3-a456-426614174001", event: "complete", text: "Done! Sent the summary to your email." }
```

## Status and Progress Updates

Computer tasks can take several minutes when they involve browsing, connector authentication, code execution, or file generation. The MCP tool call remains open until Computer reaches a final state or an actionable checkpoint.

Use the `event` field in each response as the current status for the task. The same response also includes the `thread_id` you need for follow-up calls:

```
{
  "thread_id": "123e4567-e89b-12d3-a456-426614174000",
  "event": "complete",
  "text": "Finished the report."
}
```

When Computer needs input before it can continue, the response includes an actionable event and an `interactive` object:

```
{
  "thread_id": "123e4567-e89b-12d3-a456-426614174000",
  "event": "ask_user_question",
  "text": "Which format should I use?\n1. PDF\n2. DOCX",
  "interactive": {
    "type": "ask_user_question",
    "thread_id": "123e4567-e89b-12d3-a456-426614174000",
    "respond_with_tool": "answer_question"
  }
}
```

Handle these checkpoints by calling the indicated follow-up tool with the same `thread_id`:

| Event                | Follow-up                                                                            |
| -------------------- | ------------------------------------------------------------------------------------ |
| `ask_user_question`  | Call `answer_question` with the user's answer.                                       |
| `confirm_action`     | Call `confirm_action_approve` or `confirm_action_deny`.                              |
| `auth_required`      | Open the OAuth URL, then call `notify_connected`.                                    |
| `sleep` or `waiting` | Call `call_perplexity_computer` with the same `thread_id` when you want to continue. |

<Info>
  The Computer MCP server sends status updates as MCP progress notifications while a task runs. Your client must include a progress token and support progress notifications to display them. These updates are task statuses rather than token-by-token response streaming.
</Info>

If the tool returns `timeout`, the MCP server did not receive a checkpoint before its wait window expired. The task may still be running. Keep the `thread_id` and call `call_perplexity_computer` again with that same `thread_id` to continue or ask for the latest status.

## File Uploads

Computer can work on files you provide. To attach a file to a task, request a presigned S3 envelope with `create_attachment_upload`, upload the bytes directly to S3, and pass the returned URL in `attachment_urls` on your next tool call. The MCP server never sees the file contents, so uploads scale to large binaries without going through the worker.

The maximum file size is **200 MB** per attachment.

<Steps>
  <Step title="Step 1: Request an upload envelope">
    Call `create_attachment_upload` with the file's `filename`, `mime_type`, and `size_bytes`. The server returns a presigned S3 POST you can use for the next few minutes.

    ```
    create_attachment_upload(
      filename: "report.pdf",
      mime_type: "application/pdf",
      size_bytes: 482190,
    )
    -> {
      attachment_url: "https://bucket.s3.amazonaws.com/uploads/<uuid>/report.pdf",
      upload_url: "https://bucket.s3.amazonaws.com",
      upload_fields: { "key": "uploads/<uuid>/report.pdf", "policy": "...", ... },
    }
    ```
  </Step>

  <Step title="Step 2: POST the bytes to S3">
    Send an unauthenticated `multipart/form-data` POST to `upload_url`. Include every key from `upload_fields` as a form field, then add the file under a `file` part.

    ```bash theme={null}
    curl -X POST "$UPLOAD_URL" \
      -F "key=$KEY" \
      -F "policy=$POLICY" \
      -F "x-amz-signature=$SIGNATURE" \
      -F "file=@./report.pdf"
    ```

    S3 returns `204 No Content` on success. The file is now reachable at `attachment_url`.
  </Step>

  <Step title="Step 3: Reference the file in a task">
    Pass the `attachment_url` to any task tool via the `attachment_urls` array. You can attach files to a new task or to a follow-up on an existing thread.

    ```
    call_perplexity_computer(
      message: "Summarize this report and pull out the key risks.",
      attachment_urls: ["https://bucket.s3.amazonaws.com/uploads/<uuid>/report.pdf"],
    )
    ```
  </Step>
</Steps>

### `create_attachment_upload`

Request a presigned S3 POST for a single file. Returns an envelope your client uses to upload bytes directly to S3.

| Parameter    | Type    | Required | Description                                                     |
| ------------ | ------- | -------- | --------------------------------------------------------------- |
| `filename`   | string  | Yes      | File name including extension (e.g. `report.pdf`).              |
| `mime_type`  | string  | Yes      | Content type of the file (e.g. `application/pdf`, `image/png`). |
| `size_bytes` | integer | Yes      | File size in bytes. Must not exceed 200 MB.                     |

Returns:

| Field            | Type   | Description                                                             |
| ---------------- | ------ | ----------------------------------------------------------------------- |
| `attachment_url` | string | Pass this back in `attachment_urls` on a follow-up tool call.           |
| `upload_url`     | string | The S3 endpoint to POST the file to.                                    |
| `upload_fields`  | object | Form fields to include alongside the `file` part in the multipart POST. |

## Capabilities

### Browser Control

Computer includes a full cloud browser for tasks that go beyond search. When a task requires interacting with a website, filling forms, or accessing login-gated content, Computer launches a browser session automatically.

| Capability           | Description                                                                                           |
| -------------------- | ----------------------------------------------------------------------------------------------------- |
| Navigation           | Navigate to any URL, click elements, fill forms, and extract structured data.                         |
| Authentication       | Handle multi-step login flows and authenticated sessions.                                             |
| Screenshots          | Take high-fidelity screenshots of any webpage.                                                        |
| Batch processing     | Run browser tasks across dozens of URLs in parallel, collecting results into structured output.       |
| JavaScript rendering | Access content on dynamic, JavaScript-heavy pages that aren't available through simple HTTP requests. |

### Code Execution

Computer runs code in a sandboxed Linux VM with a persistent file workspace. Python, Node.js, ffmpeg, and standard Unix tools are pre-installed, and additional packages can be installed on the fly.

| Capability            | Description                                                                         |
| --------------------- | ----------------------------------------------------------------------------------- |
| Interactive execution | Write and execute Python or Node scripts in real time, iterating on results.        |
| Data processing       | Process CSV, JSON, Excel, PDF, images, audio, and video files.                      |
| Shell commands        | Run shell commands for system operations, data processing, and automation.          |
| Visualizations        | Generate charts, plots, and data analysis outputs.                                  |
| File workspace        | Persistent directory where files are created, read, and managed across the session. |

### Connected Services

Computer connects to **400+ external services** through a managed connector framework. Users authenticate once via OAuth, and Computer uses tokens securely to read data, take actions, and search across services.

| Category           | Services                                                               |
| ------------------ | ---------------------------------------------------------------------- |
| Communication      | Slack, Gmail, Outlook, Microsoft Teams                                 |
| Calendar           | Google Calendar, Outlook Calendar                                      |
| Documents          | Notion, Google Docs, Google Sheets, Dropbox, OneDrive, SharePoint, Box |
| Project Management | Linear, Jira, Asana, Confluence, Trello                                |
| CRM & Sales        | HubSpot, Salesforce                                                    |
| Development        | GitHub, GitLab, Vercel, Supabase                                       |
| Data & Analytics   | Snowflake, Databricks, Airtable, Google Sheets                         |
| Finance            | Stripe, Ramp, Plaid                                                    |
| Research           | CB Insights, PitchBook, Statista, SEC EDGAR                            |
| And more           | Hundreds of additional connectors across categories                    |

When a task requires a service that isn't connected yet, Computer provides an OAuth link. Authenticate in your browser and the connector becomes available immediately.

## Available Tools

<CardGroup>
  <Card
    title="call_perplexity_computer"
    icon={
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
  <path d="M10.2 9.3V11.1" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
  <path d="M13.8 9.3V11.1" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
  <path d="M3 19.2H21" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
  <path d="M17.4 4.8H6.6C5.606 4.8 4.8 5.606 4.8 6.6V13.8C4.8 14.794 5.606 15.6 6.6 15.6H17.4C18.394 15.6 19.2 14.794 19.2 13.8V6.6C19.2 5.606 18.394 4.8 17.4 4.8Z" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
</svg>
}
  >
    Send a message to Perplexity Computer to start or continue any task. This is the primary tool you'll use for all interactions.

    **Best for:** Starting new tasks, sending follow-up instructions, and resuming paused conversations.
  </Card>

  <Card title="answer_question" icon="message">
    Relays answers when Computer asks for more information. Clients that support MCP elicitation can handle this within the active call.

    **Triggered by:** `ask_user_question` events.
  </Card>

  <Card title="confirm_action_approve / deny" icon="shield-check">
    Approves or denies a sensitive action like sending an email or deploying code. Clients that support MCP elicitation can handle this within the active call.

    **Triggered by:** `confirm_action` events.
  </Card>

  <Card title="notify_connected" icon="plug">
    Resumes a task after you complete an OAuth flow for a third-party service.

    **Triggered by:** `auth_required` events.
  </Card>

  <Card title="create_attachment_upload" icon="paperclip">
    Creates a presigned S3 upload envelope for a file you want Computer to use.

    **Best for:** Attaching files without sending their bytes through the MCP server.
  </Card>
</CardGroup>

### `call_perplexity_computer`

The primary tool. Send a message to start a new task or continue an existing conversation.

| Parameter         | Type      | Required | Description                                                              |
| ----------------- | --------- | -------- | ------------------------------------------------------------------------ |
| `message`         | string    | No       | The task description or follow-up message.                               |
| `thread_id`       | string    | No       | Thread ID to continue an existing conversation. Omit to start a new one. |
| `attachment_urls` | string\[] | No       | URLs from `create_attachment_upload` for files to attach to this turn.   |

<Info>
  Clients that support MCP elicitation can handle `ask_user_question` and `confirm_action` within the active tool call. Otherwise, use the following tools to resume the task after an interactive event.
</Info>

### `answer_question`

Relays answers when Computer returns an `ask_user_question` event.

| Parameter         | Type      | Required | Description                                                              |
| ----------------- | --------- | -------- | ------------------------------------------------------------------------ |
| `thread_id`       | string    | Yes      | The thread ID from the active conversation.                              |
| `answers`         | object    | Yes      | Key-value pairs mapping each question to your answer.                    |
| `attachment_urls` | string\[] | No       | URLs from `create_attachment_upload` for files to attach to this answer. |

### `confirm_action_approve`

Approves a pending action from a `confirm_action` event.

| Parameter         | Type      | Required | Description                                                                |
| ----------------- | --------- | -------- | -------------------------------------------------------------------------- |
| `thread_id`       | string    | Yes      | The thread ID from the active conversation.                                |
| `result`          | string    | Yes      | Reason or message for the approval.                                        |
| `attachment_urls` | string\[] | No       | URLs from `create_attachment_upload` for files to attach to this approval. |

### `confirm_action_deny`

Denies a pending action from a `confirm_action` event.

| Parameter         | Type      | Required | Description                                                              |
| ----------------- | --------- | -------- | ------------------------------------------------------------------------ |
| `thread_id`       | string    | Yes      | The thread ID from the active conversation.                              |
| `result`          | string    | Yes      | Reason for denying the action.                                           |
| `attachment_urls` | string\[] | No       | URLs from `create_attachment_upload` for files to attach to this denial. |

### `notify_connected`

Resumes a task after you complete an OAuth flow triggered by an `auth_required` event.

| Parameter         | Type      | Required | Description                                                             |
| ----------------- | --------- | -------- | ----------------------------------------------------------------------- |
| `thread_id`       | string    | Yes      | The thread ID from the active conversation.                             |
| `message`         | string    | Yes      | Message about the completed connection.                                 |
| `attachment_urls` | string\[] | No       | URLs from `create_attachment_upload` for files to attach when resuming. |

## Response Format

Task tools return a JSON object with the following fields. `create_attachment_upload` returns the upload envelope described in [File Uploads](#file-uploads) instead.

| Field         | Type   | Description                                                                                                              |
| ------------- | ------ | ------------------------------------------------------------------------------------------------------------------------ |
| `thread_id`   | string | The conversation UUID. Pass this back to continue the conversation. Omitted when a request fails before a thread starts. |
| `event`       | string | The event type indicating what happened. See [Events](#events).                                                          |
| `text`        | string | Markdown-formatted response text.                                                                                        |
| `interactive` | object | Present only for interactive events that require a follow-up action.                                                     |

## Events

Each response includes an `event` field describing the outcome:

| Event                  | Description                                                                 | Action Required                                                                    |
| ---------------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| `complete`             | Task finished successfully.                                                 | None.                                                                              |
| `error`                | Task failed.                                                                | Review the error message.                                                          |
| `cancelled`            | Task was cancelled before completion.                                       | Start a new task or continue the thread with new instructions.                     |
| `sleep`                | Agent is pausing mid-task.                                                  | Call `call_perplexity_computer` with the same `thread_id` to resume.               |
| `waiting`              | Agent is waiting on an external condition or more time to pass.             | Keep the `thread_id` and continue the thread when ready.                           |
| `ask_user_question`    | Agent needs more information.                                               | Call `answer_question` with your answers.                                          |
| `confirm_action`       | Agent wants to perform a sensitive action.                                  | Call `confirm_action_approve` or `confirm_action_deny`.                            |
| `auth_required`        | A third-party service needs authentication.                                 | Open the provided `auth_url` in a browser, then call `notify_connected`.           |
| `two_factor_required`  | A connector or site requires two-factor authentication.                     | Follow the instructions in `text`, then continue with the same `thread_id`.        |
| `insufficient_credits` | Account has insufficient credits.                                           | Top up credits or adjust your spending limit.                                      |
| `access_denied`        | Computer is unavailable for the account.                                    | If you belong to an organization, ask its administrator to enable Computer access. |
| `timeout`              | The MCP server did not receive a checkpoint before the wait window expired. | Retry with the same `thread_id` to continue or request current status.             |

## Links & Resources

<CardGroup>
  <Card
    title="Perplexity Computer"
    icon={
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
  <path d="M10.2 9.3V11.1" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
  <path d="M13.8 9.3V11.1" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
  <path d="M3 19.2H21" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
  <path d="M17.4 4.8H6.6C5.606 4.8 4.8 5.606 4.8 6.6V13.8C4.8 14.794 5.606 15.6 6.6 15.6H17.4C18.394 15.6 19.2 14.794 19.2 13.8V6.6C19.2 5.606 18.394 4.8 17.4 4.8Z" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
</svg>
}
    href="https://www.perplexity.ai"
  >
    Learn more about Perplexity Computer, the Digital Worker that can complete any task on your behalf.
  </Card>

  <Card title="Perplexity API MCP Server" icon="search" href="/docs/getting-started/integrations/mcp-server">
    Power your agents with Perplexity's APIs for real-time information retrieval and generation.
  </Card>
</CardGroup>


# Perplexity with Cursor
Source: https://docs.perplexity.ai/docs/getting-started/integrations/cursor

Use Perplexity inside Cursor — call the API from project code with the official TypeScript SDK, use the OpenAI-compatible base URL, or wire up the hosted Perplexity Docs MCP for in-editor documentation lookup.

<SonarDeprecationNotice />

## Overview

[Cursor](https://cursor.com) is an AI-first code editor that can call any HTTP API from your project code and supports the Model Context Protocol (MCP) for in-editor tools. This guide covers three integration paths for Perplexity:

<CardGroup>
  <Card title="Official TypeScript SDK" icon="code">
    Call the Perplexity API directly from your project code while you build in Cursor. **Recommended.**
  </Card>

  <Card title="OpenAI-Compatible SDK" icon="plug">
    Reuse an existing OpenAI client by pointing `baseURL` at `https://api.perplexity.ai/v1`.
  </Card>

  <Card title="Cursor MCP" icon="book">
    Configure the hosted Perplexity Docs MCP in `.cursor/mcp.json` so Cursor can look up Perplexity docs while you code.
  </Card>
</CardGroup>

<Info>
  **Recommended path:** Use the official SDK (or the OpenAI-compatible SDK) from your application code, and add the Perplexity Docs MCP to Cursor for in-editor documentation lookup. Cursor's "custom OpenAI-compatible model" override pointed at Perplexity is **experimental** and tends to be less reliable than code-level integration or MCP — see [Custom Model Override (Experimental)](#custom-model-override-experimental).
</Info>

## Prerequisites

* Cursor installed ([cursor.com/download](https://cursor.com/download))
* Node.js 18+ for the TypeScript examples
* A Perplexity API key

<Card title="Get API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate a key from the Perplexity API Portal.
</Card>

## API Key Handling

Never hardcode your API key in source files or commit it to a repository. Store it in an environment variable and read it at runtime:

<Tabs>
  <Tab title="macOS/Linux">
    ```bash theme={null}
    export PERPLEXITY_API_KEY="your_api_key_here"
    ```
  </Tab>

  <Tab title="Windows">
    ```powershell theme={null}
    setx PERPLEXITY_API_KEY "your_api_key_here"
    ```
  </Tab>

  <Tab title=".env (project-local)">
    Create a `.env` file in your project root and add it to `.gitignore`:

    ```bash theme={null}
    # .env
    PERPLEXITY_API_KEY=your_api_key_here
    ```

    Load it at startup (for example with [`dotenv`](https://www.npmjs.com/package/dotenv)):

    ```typescript theme={null}
    import "dotenv/config";
    ```
  </Tab>
</Tabs>

<Warning>
  Treat `PERPLEXITY_API_KEY` like a password. Don't paste it into chat, prompts, or shared files. If a key is exposed, [rotate it](https://console.perplexity.ai/group/keys) immediately.
</Warning>

***

## Path 1: Official TypeScript SDK (Recommended)

Build your application in Cursor and call the Perplexity API from your code using the official SDK. This is the most reliable path and gives you full type safety, preset support, and access to every API feature.

### Install

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

<Tip>
  `pnpm` and `yarn` work the same way: `pnpm add @perplexity-ai/perplexity_ai` / `yarn add @perplexity-ai/perplexity_ai`.
</Tip>

### Agent API with `low`

The Agent API is the recommended surface for most applications. Use the `low` preset for web-grounded responses with sensible defaults:

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

const client = new Perplexity(); // reads PERPLEXITY_API_KEY from the environment

const response = await client.responses.create({
  preset: "low",
  input: "Summarize the latest changes to the Perplexity Agent API.",
});

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

<Accordion title="Python equivalent">
  ```python theme={null}
  from perplexity import Perplexity

  client = Perplexity()  # reads PERPLEXITY_API_KEY from the environment

  response = client.responses.create(
      preset="low",
      input="Summarize the latest changes to the Perplexity Agent API.",
  )

  print(f"Model used: {response.model}")
  print(response.output_text)
  ```
</Accordion>

### Add Web Search

Enable the `web_search` tool for explicit control over when search is used:

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

const client = new Perplexity();

const response = await client.responses.create({
  model: "openai/gpt-5.4",
  input: "What are the latest developments in AI inference hardware?",
  tools: [{ type: "web_search" }],
  instructions:
    "You have access to a web_search tool. Use it for questions about current events, news, or recent developments.",
});

if (response.status === "completed") {
  console.log(response.output_text);
}
```

<Tip>
  Cursor's AI chat can scaffold and edit these snippets for you. Open the chat with `Cmd+L` / `Ctrl+L`, paste in your goal, and ask Cursor to "use `@perplexity-ai/perplexity_ai` with the `low` preset."
</Tip>

For more presets, tools, and configuration options see the [Agent API quickstart](/docs/agent-api/quickstart) and the [SDK overview](/docs/sdk/overview).

***

## Path 2: OpenAI-Compatible SDK

If you already have an OpenAI client in your project, you can reuse it by pointing the `baseURL` at `https://api.perplexity.ai/v1`. Perplexity accepts `POST /v1/responses` as an alias for the Agent API.

### Install

```bash theme={null}
npm install openai
```

### Use It

```typescript theme={null}
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.PERPLEXITY_API_KEY,
  baseURL: "https://api.perplexity.ai/v1",
});

const response = await client.responses.create({
  model: "openai/gpt-5.4",
  input: "Explain the key differences between REST and GraphQL APIs.",
});

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

<Accordion title="Python equivalent">
  ```python theme={null}
  import os
  from openai import OpenAI

  client = OpenAI(
      api_key=os.environ.get("PERPLEXITY_API_KEY"),
      base_url="https://api.perplexity.ai/v1",
  )

  response = client.responses.create(
      model="openai/gpt-5.4",
      input="Explain the key differences between REST and GraphQL APIs.",
  )

  print(response.output_text)
  ```
</Accordion>

<Info>
  Use `baseURL` (TypeScript) or `base_url` (Python) — both must include the `/v1` suffix. See the [OpenAI Compatibility guide](/docs/agent-api/openai-compatibility) for the full list of supported parameters and which Perplexity features are available through this path.
</Info>

***

## Path 3: Cursor MCP for Docs Lookup

Cursor supports the Model Context Protocol (MCP). The hosted **Perplexity Docs MCP** at `https://docs.perplexity.ai/mcp` lets Cursor search and read Perplexity's documentation directly from chat — useful for grounding code suggestions in canonical docs without context-switching to a browser.

### Project-Scoped Configuration

Add a `.cursor/mcp.json` file at the root of your project. This makes the server available only for that project:

```json theme={null}
{
  "mcpServers": {
    "perplexity-docs": {
      "url": "https://docs.perplexity.ai/mcp"
    }
  }
}
```

### Global Configuration

To make the server available across all projects, add the same entry to `~/.cursor/mcp.json`:

```json theme={null}
{
  "mcpServers": {
    "perplexity-docs": {
      "url": "https://docs.perplexity.ai/mcp"
    }
  }
}
```

<Steps>
  <Step title="Add the Configuration">
    Save the JSON above to `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global).
  </Step>

  <Step title="Reload Cursor">
    Open **Cursor → Settings → MCP** and confirm `perplexity-docs` appears with a green/ready status. Restart Cursor if needed.
  </Step>

  <Step title="Use It from Chat">
    In Cursor chat, ask questions like *"Using the Perplexity docs MCP, show me how to enable `low` in the Agent API."* Cursor will call the MCP server and ground its answer in current documentation.
  </Step>
</Steps>

<Tip>
  The Docs MCP is read-only and does not require an API key — it only serves Perplexity documentation. To give Cursor access to Perplexity **search and reasoning** tools (not just docs), install the [Perplexity MCP Server](/docs/getting-started/integrations/mcp-server), which uses `@perplexity-ai/mcp-server` and requires `PERPLEXITY_API_KEY`.
</Tip>

***

## Custom Model Override (Experimental)

Cursor lets you point its built-in model picker at an OpenAI-compatible base URL. While it is possible to set this to `https://api.perplexity.ai/v1` and use a Perplexity model name, this path has limitations:

* The Agent API surface (presets, structured tool calls, finance/people search) is not fully exercised by Cursor's internal prompting.
* Cursor's autocomplete and edit features are tuned to specific model behaviors and may not work well with substituted models.
* Streaming, tool use, and error handling can behave differently than in a code-level integration.

For these reasons, **we recommend calling Perplexity from your project code** (Path 1 or Path 2) and using the **Perplexity Docs MCP** (Path 3) for in-editor docs lookup. Reach for the custom model override only when you specifically want Cursor's chat UI to talk to a Perplexity model and are comfortable with the trade-offs.

***

## Next Steps

<CardGroup>
  <Card title="Agent API Quickstart" icon="rocket" href="/docs/agent-api/quickstart">
    Presets, tools, and the full Agent API surface used by the examples above.
  </Card>

  <Card title="Perplexity SDK Overview" icon="code-circle" href="/docs/sdk/overview">
    Install, configure, and use the official Python and TypeScript SDKs.
  </Card>

  <Card title="OpenAI Compatibility" icon="plug" href="/docs/agent-api/openai-compatibility">
    Drop-in compatibility details, supported parameters, and migration tips.
  </Card>

  <Card title="Perplexity MCP Server" icon="server" href="/docs/getting-started/integrations/mcp-server">
    Add Perplexity search, ask, research, and reason tools to Cursor and other MCP clients.
  </Card>
</CardGroup>

<Info>
  Need help? Join the [Perplexity developer community](https://community.perplexity.ai) for support and discussion.
</Info>


# Perplexity with Haystack
Source: https://docs.perplexity.ai/docs/getting-started/integrations/haystack

Use Perplexity's Agent API, Embeddings API, and grounded Search API in Haystack pipelines.

<SonarDeprecationNotice />

## Overview

The `perplexity-haystack` package provides Haystack components for Perplexity's Agent API, Embeddings API, and grounded Search API, so you can build retrieval-augmented and agentic pipelines that combine chat, embeddings, and live web search.

<Info>
  **Haystack** is an open-source Python framework by [deepset](https://deepset.ai) for building production-ready LLM applications, including RAG pipelines and agentic workflows. Learn more at [haystack.deepset.ai](https://haystack.deepset.ai).
</Info>

The integration includes:

* **PerplexityChatGenerator** — Chat generation through the [Agent API](/docs/agent-api/quickstart).
* **PerplexityTextEmbedder** and **PerplexityDocumentEmbedder** — Embeddings through the [Embeddings API](/docs/embeddings/quickstart).
* **PerplexityWebSearch** — Ranked, grounded web results through the [Search API](/docs/search/quickstart).

## Installation

<Tabs>
  <Tab title="pip">
    ```bash theme={null}
    pip install perplexity-haystack
    ```
  </Tab>

  <Tab title="uv">
    ```bash theme={null}
    uv add perplexity-haystack
    ```
  </Tab>
</Tabs>

## API Key Setup

Set your Perplexity API key as an environment variable:

```python theme={null}
import os

os.environ["PERPLEXITY_API_KEY"] = "your_api_key_here"
```

<Card title="Get API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate your API key from the Perplexity dashboard.
</Card>

## Quick Start: Chat (Agent API)

`PerplexityChatGenerator` is powered by the Perplexity Agent API and defaults to `openai/gpt-5.4`.

```python theme={null}
import os

from haystack.dataclasses import ChatMessage
from haystack_integrations.components.generators.perplexity import PerplexityChatGenerator

os.environ["PERPLEXITY_API_KEY"] = "your_api_key_here"

client = PerplexityChatGenerator()
response = client.run(
    messages=[ChatMessage.from_user("What are Agentic Pipelines? Be brief.")]
)

print(response["replies"])
```

### Selecting a Model

You can pick any of the supported Agent API models via the `model` parameter:

```python theme={null}
client = PerplexityChatGenerator(model="anthropic/claude-sonnet-4-6")
```

Supported models include `openai/gpt-5.4` (default), `openai/gpt-5.5`, `anthropic/claude-sonnet-4-6`, `xai/grok-4.5`, and `google/gemini-3-flash-preview`. See the [Agent API models page](/docs/agent-api/models) for the full list.

## Quick Start: Embeddings

Embed a single query with `PerplexityTextEmbedder`:

```python theme={null}
import os

from haystack_integrations.components.embedders.perplexity import PerplexityTextEmbedder

os.environ["PERPLEXITY_API_KEY"] = "your_api_key_here"

embedder = PerplexityTextEmbedder()
response = embedder.run(text="What is Haystack by deepset?")

print(response["embedding"])
```

Embed a list of documents with `PerplexityDocumentEmbedder`:

```python theme={null}
from haystack import Document
from haystack_integrations.components.embedders.perplexity import PerplexityDocumentEmbedder

docs = [Document(content="What is Haystack by deepset?")]
result = PerplexityDocumentEmbedder().run(documents=docs)

print(result["documents"][0].embedding)
```

Both embedders default to `pplx-embed-v1-0.6b`. The larger `pplx-embed-v1-4b` model is also available — set it via the `model` parameter.

## Quick Start: Web Search (Search API)

Use `PerplexityWebSearch` to get ranked, grounded web results inside a Haystack pipeline:

```python theme={null}
import os

from haystack.utils import Secret
from haystack_integrations.components.websearch.perplexity import PerplexityWebSearch

os.environ["PERPLEXITY_API_KEY"] = "your_api_key_here"

websearch = PerplexityWebSearch(
    api_key=Secret.from_env_var("PERPLEXITY_API_KEY"),
    top_k=5,
)
result = websearch.run(query="What is Haystack by deepset?")

documents = result["documents"]
links = result["links"]

print(documents)
print(links)
```

## Links & Resources

<CardGroup>
  <Card title="Haystack Integrations" icon="book" href="https://haystack.deepset.ai/integrations/perplexity">
    Catalog entry on haystack.deepset.ai
  </Card>

  <Card title="Source Code" icon="github" href="https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/perplexity">
    perplexity-haystack on GitHub
  </Card>

  <Card title="PyPI Package" icon="brand-python" href="https://pypi.org/project/perplexity-haystack">
    View on PyPI
  </Card>

  <Card title="Haystack Docs" icon="book-open" href="https://docs.haystack.deepset.ai">
    Full Haystack documentation
  </Card>
</CardGroup>

## Support

Need help with the integration?

* Check the [Haystack documentation](https://docs.haystack.deepset.ai)
* Open an issue at [haystack-core-integrations](https://github.com/deepset-ai/haystack-core-integrations/issues)
* Review our [FAQ](/docs/resources/faq)


# Perplexity with LangChain
Source: https://docs.perplexity.ai/docs/getting-started/integrations/langchain

Call Perplexity's Agent API from LangChain and LangGraph through langchain-openai's Responses support.

<SonarDeprecationNotice />

## Overview

[LangChain](https://www.langchain.com) is a framework for building LLM applications, and [LangGraph](https://www.langchain.com/langgraph) adds stateful agents on top of it.
Reach Perplexity's [Agent API](/docs/agent-api/quickstart) through `langchain-openai`'s `ChatOpenAI` with `use_responses_api=True`, pointed at Perplexity's base URL.

<Info>
  Use `ChatOpenAI` from `langchain-openai` — not `ChatPerplexity` from `langchain-perplexity`, which only speaks Sonar Chat Completions.
  Setting `use_responses_api=True` routes calls to `POST /v1/responses` (the Agent API).
</Info>

## Installation

```bash theme={null}
pip install -U langchain langchain-openai
```

`langchain` 1.0 or later provides `create_agent` and installs LangGraph automatically.

## API Key Setup

```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```

<Card title="Get API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate your Perplexity API key from the API portal.
</Card>

## Chat Model

Point `ChatOpenAI` at Perplexity's `/v1` base URL and enable the built-in `web_search` tool for grounded answers:

<Tip>
  Perplexity's built-in `web_search` is best-in-class web-grounded search — the model calls it to ground answers in live sources.
  See the [`web_search` tool docs](/docs/agent-api/tools/web-search) for filters and options.
</Tip>

```python theme={null}
import os

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    base_url="https://api.perplexity.ai/v1",
    api_key=os.environ["PERPLEXITY_API_KEY"],
    model="openai/gpt-5.6-sol",
    use_responses_api=True,
    model_kwargs={"tools": [{"type": "web_search"}]},
    extra_body={"preset": "medium"},
)

response = llm.invoke("What did Perplexity announce most recently?")
print(response.text)
```

<Info>
  For a standalone chat model, pass Perplexity's built-in tools (`web_search`, `fetch_url`) through `model_kwargs={"tools": [...]}`. Pass Agent-API-only fields such as `preset` through `extra_body` — the underlying OpenAI SDK rejects them as unknown top-level keyword arguments.
  `preset="medium"` selects the `medium` tier; see [Presets](/docs/agent-api/presets) for the full list.
</Info>

## LangChain Agent

Create an agent with `create_agent` from LangChain. Pass Perplexity's built-in tools in the agent's `tools` list:

<Tip>
  `web_search` gives the agent Perplexity's best-in-class web-grounded search, so it can pull in and reason over live sources when a query needs them.
  Learn more in the [`web_search` tool docs](/docs/agent-api/tools/web-search).
</Tip>

```python theme={null}
import os

from langchain.agents import create_agent
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    base_url="https://api.perplexity.ai/v1",
    api_key=os.environ["PERPLEXITY_API_KEY"],
    model="openai/gpt-5.6-sol",
    use_responses_api=True,
    extra_body={"preset": "medium"},
)

agent = create_agent(llm, tools=[{"type": "web_search"}])
result = agent.invoke(
    {"messages": [{"role": "user", "content": "Summarize today's top AI news."}]}
)
print(result["messages"][-1].text)
```

<Warning>
  For agents, do not put built-in tools in `model_kwargs`. When LangChain binds the agent's tools to the model, they replace `model_kwargs["tools"]`. Put built-in tool dictionaries and local tools in the same `tools` list so web search is not silently dropped: `tools=[{"type": "web_search"}, my_local_tool]`.
</Warning>

## Reading Sources

To read structured `search_results` (titles and URLs), call the Agent API directly with the [Perplexity SDK](/docs/sdk/overview):

```python theme={null}
import os

from perplexity import Perplexity

client = Perplexity()

response = client.responses.create(
    model="perplexity/sonar",
    input="What did Perplexity announce most recently?",
    tools=[{"type": "web_search"}],
)

for item in response.output:
    if item.type == "search_results":
        for source in item.results:
            print(source.title, "-", source.url)
```

## Links & Resources

<CardGroup>
  <Card title="Agent API Quickstart" icon="bolt" href="/docs/agent-api/quickstart">
    Build with Agent API models, tools, and presets.
  </Card>

  <Card title="Agent API Models" icon="sparkles" href="/docs/agent-api/models">
    Available models and pricing.
  </Card>

  <Card title="LangGraph Docs" icon="globe" href="https://www.langchain.com/langgraph">
    Build stateful agents with LangGraph.
  </Card>
</CardGroup>


# Perplexity with LiteLLM
Source: https://docs.perplexity.ai/docs/getting-started/integrations/litellm

Use Perplexity's Agent API and presets through LiteLLM's unified interface — Python SDK and Proxy.

<SonarDeprecationNotice />

## Overview

[LiteLLM](https://litellm.ai) is a Python SDK and proxy server that gives you a single OpenAI-compatible interface to 100+ LLM providers. Perplexity's [Agent API](/docs/agent-api/quickstart) — with third-party models like GPT-5, Claude, and Gemini routed through Perplexity — is a first-class provider in LiteLLM.

<Info>
  **LiteLLM** lets you swap providers without rewriting code, run a self-hosted proxy that fronts every model behind one API key, and track spend, latency, and errors per provider. Learn more at [litellm.ai](https://litellm.ai).
</Info>

## Installation

```bash theme={null}
pip install litellm
```

## API Key Setup

LiteLLM reads your Perplexity API key from the environment:

```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```

<Card title="Get API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate your Perplexity API key from the API portal.
</Card>

## Agent API

Use `litellm.responses` to call the [Agent API](/docs/agent-api/quickstart), which routes through Perplexity to third-party models with tool orchestration and presets.

### Presets

```python theme={null}
from litellm import responses
import os

os.environ["PERPLEXITY_API_KEY"] = "your_api_key_here"

response = responses(
    model="perplexity/preset/low",
    input="What are the latest developments in AI?",
    custom_llm_provider="perplexity",
)

print(response.output)
```

Available presets: `fast`, `low`, `medium`, `high`, `xhigh`.

### Tool Use (`web_search` and `fetch_url`)

```python theme={null}
from litellm import responses

response = responses(
    model="perplexity/openai/gpt-5.6-sol",
    input="Research quantum computing breakthroughs and cite sources.",
    custom_llm_provider="perplexity",
    tools=[
        {"type": "web_search"},
        {"type": "fetch_url"},
    ],
    instructions="Use web_search and fetch_url to gather citations.",
    max_output_tokens=1000,
    temperature=0.7,
)

print(response.output)
```

### Structured Outputs

```python theme={null}
from litellm import responses

response = responses(
    model="perplexity/preset/low",
    input="Extract key facts about the Eiffel Tower.",
    custom_llm_provider="perplexity",
    text={
        "format": {
            "type": "json_schema",
            "name": "facts",
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "height_meters": {"type": "number"},
                    "year_built": {"type": "integer"},
                },
                "required": ["name", "height_meters", "year_built"],
            },
            "strict": True,
        }
    },
)
```

### Supported Third-Party Models via Agent API

Prefix any Agent API model ID with `perplexity/` (for example, `perplexity/openai/gpt-5.6-sol`). See the [Agent API model list](/docs/agent-api/models) for the canonical, up-to-date catalogue.

## LiteLLM Proxy

Run LiteLLM as a self-hosted proxy that fronts Perplexity (and any other provider) behind a single OpenAI-compatible endpoint.

### config.yaml

```yaml theme={null}
model_list:
  - model_name: perplexity-low
    litellm_params:
      model: perplexity/preset/low
      api_key: os.environ/PERPLEXITY_API_KEY
```

### Start the Proxy

```bash theme={null}
litellm --config /path/to/config.yaml
```

### Call the Proxy

```bash theme={null}
curl http://0.0.0.0:4000/v1/responses \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer anything" \
  -d '{
    "model": "perplexity-low",
    "input": "What are the latest developments in AI?",
    "tools": [{"type": "web_search"}]
  }'
```

## Links & Resources

<CardGroup>
  <Card title="LiteLLM Perplexity Docs" icon="book" href="https://docs.litellm.ai/docs/providers/perplexity">
    Official LiteLLM Perplexity provider docs.
  </Card>

  <Card title="LiteLLM Docs" icon="globe" href="https://docs.litellm.ai">
    Full LiteLLM documentation.
  </Card>

  <Card title="Perplexity Agent API" icon="robot" href="/docs/agent-api/quickstart">
    Agent API reference and presets.
  </Card>

  <Card title="Agent API Models" icon="sparkles" href="/docs/agent-api/models">
    Available Agent API models.
  </Card>
</CardGroup>

## Support

Need help with the integration?

* Browse the [LiteLLM documentation](https://docs.litellm.ai)
* Review our [FAQ](/docs/resources/faq)


# Perplexity with LiveKit Agents
Source: https://docs.perplexity.ai/docs/getting-started/integrations/livekit

Use Perplexity's Agent API as the LLM brain of a LiveKit voice agent.

<SonarDeprecationNotice />

## Overview

Perplexity's [Agent API](/docs/agent-api/quickstart) is compatible with the OpenAI Responses API, so it works as a drop-in LLM for [LiveKit Agents](https://docs.livekit.io/agents/) through `livekit-plugins-openai`'s `openai.responses.LLM` class, pointed at Perplexity's base URL.

<Info>
  **LiveKit Agents** is an open-source framework for building realtime voice and multimodal AI agents. For new integrations, use the Perplexity **Agent API** via `openai.responses.LLM` — not the `livekit-plugins-perplexity` plugin or `openai.LLM.with_perplexity()`, which both call the legacy Sonar Chat Completions endpoint. Learn more at [livekit.io](https://livekit.io).
</Info>

## Installation

```bash theme={null}
pip install "livekit-agents" "livekit-plugins-openai"
```

## API Key Setup

Set your Perplexity API key as an environment variable and pass it to the constructor:

```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```

<Card title="Get API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate your API key from the Perplexity dashboard.
</Card>

## Quick Start

Use `openai.responses.LLM` anywhere a LiveKit `AgentSession` expects an LLM:

```python theme={null}
import os

from livekit.agents import Agent, AgentSession
from livekit.plugins import openai, silero

session = AgentSession(
    llm=openai.responses.LLM(
        model="openai/gpt-5.6-sol",
        base_url="https://api.perplexity.ai/v1",   # SDK appends /responses -> POST /v1/responses
        api_key=os.environ["PERPLEXITY_API_KEY"],  # required: constructor does not read PERPLEXITY_API_KEY
    ),
    stt=openai.STT(),
    tts=openai.TTS(),
    vad=silero.VAD.load(),
)

agent = Agent(
    instructions="You are a helpful voice assistant. Use web search to answer with up-to-date information.",
    tools=[openai.tools.WebSearch()],  # Perplexity's built-in web_search tool
)

# Run the session inside your LiveKit room entrypoint
```

Because the Agent API is OpenAI-Responses-compatible, the OpenAI plugin talks to `https://api.perplexity.ai/v1` with no other changes.

## Configuration

`openai.responses.LLM` needs two settings to target Perplexity - `base_url` and an explicit `api_key` (the constructor does not read `PERPLEXITY_API_KEY` on its own):

```python theme={null}
import os

from livekit.plugins import openai

llm = openai.responses.LLM(
    model="openai/gpt-5.6-sol",
    base_url="https://api.perplexity.ai/v1",
    api_key=os.environ["PERPLEXITY_API_KEY"],
)
```

Perplexity's built-in tools (like `web_search`, shown in the Quick Start) attach to the `Agent`, not to the LLM.

## Available Models

The integration works with any model exposed through the Perplexity Agent API, addressed as `provider/model` (for example `openai/gpt-5.6-sol`). See the full list on our [models page](/docs/agent-api/models).

## Links & Resources

<CardGroup>
  <Card title="LiveKit Agents Docs" icon="book" href="https://docs.livekit.io/agents/">
    Build realtime voice and multimodal agents with LiveKit.
  </Card>

  <Card title="OpenAI Plugin Source" icon="brand-github" href="https://github.com/livekit/agents/tree/main/livekit-plugins/livekit-plugins-openai">
    The `livekit-plugins-openai` source, including the Responses `LLM`.
  </Card>

  <Card title="Agent API Quickstart" icon="bolt" href="/docs/agent-api/quickstart">
    Request, response, and tool contract used above.
  </Card>

  <Card title="Agent API Models" icon="sparkles" href="/docs/agent-api/models">
    Available models and pricing.
  </Card>
</CardGroup>

## Support

Need help with the integration?

* Browse the [LiveKit Agents documentation](https://docs.livekit.io/agents/)
* Review our [FAQ](/docs/resources/faq)


# Perplexity with Mastra
Source: https://docs.perplexity.ai/docs/getting-started/integrations/mastra

Use Perplexity's Agent API and the Search API in your Mastra agents and tools.

<SonarDeprecationNotice />

## Overview

[Mastra](https://mastra.ai) is an open-source TypeScript framework for building AI agents and workflows. Wire Perplexity's [Agent API](/docs/agent-api/quickstart) into a Mastra `Agent` through the Open Responses provider, or expose the Search API as a Mastra-compatible tool.

<Info>
  **Mastra** provides a unified `Agent` interface, a model router, and a tools/MCP system for orchestrating LLM workflows. Learn more at [mastra.ai](https://mastra.ai).
</Info>

The Mastra ecosystem provides two Perplexity integrations:

* **Agent API** — Run the [Agent API](/docs/agent-api/quickstart) inside a Mastra `Agent` through the Open Responses provider.
* **Perplexity Search tool** — Expose the [Search API](/docs/search/quickstart) as a Mastra tool for ranked web results.

## API Key Setup

Both integrations read your Perplexity API key from the environment:

```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```

The Search tool also accepts `PPLX_API_KEY` as a fallback.

<Card title="Get API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate your API key from the Perplexity dashboard.
</Card>

## Agent API

<Warning>
  Mastra's built-in `perplexity` and `perplexity-agent` model-router providers target Sonar Chat Completions, which is now the [Agent API](/docs/agent-api/quickstart) — more models, tools, and research-backed presets. Reach it through [`@ai-sdk/open-responses`](https://ai-sdk.dev/providers/ai-sdk-providers/open-responses) as shown below, or see the [migration guide](/docs/agent-api/migrate-from-sonar/overview).
</Warning>

The [Agent API](/docs/agent-api/quickstart) speaks the [Open Responses](https://www.openresponses.org/) standard, so the `@ai-sdk/open-responses` provider connects to it directly. Point the provider at Perplexity's `/v1/responses` endpoint, then pass the model id to your Mastra `Agent`:

```bash theme={null}
npm install @mastra/core @ai-sdk/open-responses
```

```ts theme={null}
import { Agent } from "@mastra/core/agent";
import { createOpenResponses } from "@ai-sdk/open-responses";

const perplexity = createOpenResponses({
  name: "perplexity",
  url: "https://api.perplexity.ai/v1/responses",
  apiKey: process.env.PERPLEXITY_API_KEY,
});

const agent = new Agent({
  id: "research-agent",
  name: "Research Agent",
  instructions: "Answer questions clearly and concisely.",
  // Any Agent API model, e.g. openai/gpt-5.6-luna (faster) or openai/gpt-5.6-sol (higher quality).
  model: perplexity("openai/gpt-5.6-luna"),
});

const result = await agent.generate("Explain what the Perplexity Agent API is in two sentences.");
console.log(result.text);
```

The agent supports both `agent.generate(...)` and `agent.stream(...)`. See the [Agent API quickstart](/docs/agent-api/quickstart) for the full model list, built-in tools, and presets. For web-grounded answers, add the `web_search` tool (below).

## Web-Grounded Answers

Add the [`web_search`](/docs/agent-api/tools/web-search) tool to ground the agent's answers in real-time results from Perplexity's web search. The `@ai-sdk/open-responses` provider sends a fixed request body and does not expose the Agent API's built-in tools as first-class options, so enable `web_search` by adding it to the body in the provider's `fetch` hook — every call the agent makes through this provider is then grounded:

```ts theme={null}
import { Agent } from "@mastra/core/agent";
import { createOpenResponses } from "@ai-sdk/open-responses";

// The provider doesn't surface sources on the result, so capture them in the hook.
let sources = [];

const perplexity = createOpenResponses({
  name: "perplexity",
  url: "https://api.perplexity.ai/v1/responses",
  apiKey: process.env.PERPLEXITY_API_KEY,
  fetch: async (url, options) => {
    const body = JSON.parse(options.body as string);
    // Enable the built-in web_search tool by adding it to the request body.
    body.tools = [{ type: "web_search" }];
    const response = await fetch(url, { ...options, body: JSON.stringify(body) });

    // Sources arrive as a separate `search_results` item in the response `output` array.
    // (Skip for streaming, where the body is an event stream rather than JSON.)
    if (!body.stream) {
      const raw = await response.clone().json();
      sources = raw.output
        .filter((item) => item.type === "search_results")
        .flatMap((item) => item.results); // each: { title, url, snippet, date, ... }
    }

    return response;
  },
});

const agent = new Agent({
  id: "research-agent",
  name: "Research Agent",
  instructions: "Answer questions with up-to-date information from the web.",
  model: perplexity("openai/gpt-5.6-luna"),
});

const result = await agent.generate("What are the latest breakthroughs in fusion energy this year?");
console.log(result.text);

for (const source of sources) {
  console.log(source.title, source.url);
}
```

The answer is grounded server-side, but `@ai-sdk/open-responses` does not surface the sources on the result — `result.sources` is empty — so the `fetch` hook reads the raw `search_results` items directly. See [Reading Sources from the Response](/docs/agent-api/prompt-guide) for the full response shape.

## Perplexity Search Tool

The `@mastra/perplexity` package wraps the [Search API](/docs/search/quickstart) as a Mastra-compatible tool. Use this when you want raw ranked web results to feed into an agent.

```bash theme={null}
npm install @mastra/perplexity zod
```

```ts theme={null}
import { createPerplexitySearchTool } from "@mastra/perplexity";

const searchTool = createPerplexitySearchTool({
  apiKey: process.env.PERPLEXITY_API_KEY,
});

const results = await searchTool.execute({
  context: {
    query: "Latest advances in nuclear fusion",
    maxResults: 5,
    searchRecencyFilter: "month",
  },
});

for (const result of results) {
  console.log(result.title, result.url);
}
```

The tool ID is `perplexity-search` and supported input parameters include `query`, `maxResults`, `searchDomainFilter`, `searchRecencyFilter`, `searchAfterDateFilter`, and `searchBeforeDateFilter`. Each result includes `title`, `url`, `snippet`, and an optional `date`.

To register multiple Perplexity tools at once, use `createPerplexityTools(config?)`. See the [Mastra Perplexity tool reference](https://mastra.ai/reference/tools/perplexity) for the full schema.

## Links & Resources

<CardGroup>
  <Card title="Agent API Quickstart" icon="bolt" href="/docs/agent-api/quickstart">
    Build with Agent API models, tools, and presets.
  </Card>

  <Card title="Perplexity SDK" icon="code" href="/docs/sdk/overview">
    Install and configure the official Perplexity SDK.
  </Card>

  <Card title="Perplexity Search Tool" icon="search" href="https://mastra.ai/reference/tools/perplexity">
    Wrap the Perplexity Search API as a Mastra tool.
  </Card>

  <Card title="Mastra Docs" icon="book" href="https://mastra.ai/docs">
    Learn more about agents, tools, and workflows in Mastra.
  </Card>
</CardGroup>

## Support

Need help with the integration?

* Browse the [Mastra documentation](https://mastra.ai/docs)
* Review our [FAQ](/docs/resources/faq)


# Perplexity API MCP Server
Source: https://docs.perplexity.ai/docs/getting-started/integrations/mcp-server

Connect AI assistants to Perplexity's search and reasoning capabilities using the Model Context Protocol (MCP).

<SonarDeprecationNotice />

## Overview

The Perplexity MCP Server enables AI assistants to access Perplexity's powerful search and reasoning capabilities directly within their workflows. Using the Model Context Protocol (MCP), you can integrate real-time web search, conversational AI, and advanced reasoning into any MCP-compatible client.

There are two ways to connect:

* **Remote MCP server (recommended):** hosted by Perplexity at `https://api.perplexity.ai/mcp`. No installation, nothing to update, works with any client that supports remote MCP servers.
* **Local MCP server:** run the open-source server on your machine over stdio. Use this if your client only supports stdio servers or you need to pin a version.

Both expose the same tools and behave identically.

<Info>
  The **Model Context Protocol (MCP)** is an open standard that connects AI assistants with external data sources and tools. Learn more at [modelcontextprotocol.io](https://modelcontextprotocol.io/introduction).
</Info>

<Note>
  This page is for adding Perplexity as an MCP tool inside clients such as Claude Code, Cursor, VS Code, and Claude Desktop. To call the Perplexity API from application code, start with the [Quickstart](/docs/getting-started/quickstart). To select Claude models through the Agent API, use Anthropic model IDs from [Agent API models](/docs/agent-api/models).
</Note>

## Remote MCP Server

Connect to `https://api.perplexity.ai/mcp` (Streamable HTTP) and authenticate with your API key as a bearer token:

```
Authorization: Bearer YOUR_API_KEY
```

<Card title="Generate API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Navigate to the API Portal and generate a new key.
</Card>

<Tabs>
  <Tab title="Claude Code">
    ```bash theme={null}
    claude mcp add --transport http perplexity https://api.perplexity.ai/mcp --header "Authorization: Bearer YOUR_API_KEY"
    ```
  </Tab>

  <Tab title="Cursor">
    [Install in Cursor with one click](https://cursor.com/install-mcp?name=perplexity\&config=eyJ1cmwiOiJodHRwczovL2FwaS5wZXJwbGV4aXR5LmFpL21jcCIsImhlYWRlcnMiOnsiQXV0aG9yaXphdGlvbiI6IkJlYXJlciBZT1VSX0FQSV9LRVkifX0%3D), then replace `YOUR_API_KEY` with your key.

    Or add to your `~/.cursor/mcp.json` manually:

    ```json theme={null}
    {
      "mcpServers": {
        "perplexity": {
          "url": "https://api.perplexity.ai/mcp",
          "headers": {
            "Authorization": "Bearer YOUR_API_KEY"
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="VS Code">
    [Install in VS Code with one click](https://vscode.dev/redirect/mcp/install?name=perplexity\&config=%7B%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fapi.perplexity.ai%2Fmcp%22%2C%22headers%22%3A%7B%22Authorization%22%3A%22Bearer%20%24%7Binput%3Aperplexity-api-key%7D%22%7D%7D\&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22perplexity-api-key%22%2C%22description%22%3A%22Perplexity%20API%20Key%22%2C%22password%22%3Atrue%7D%5D) and VS Code prompts for your key.

    Or add to your `.vscode/mcp.json` manually. The `inputs` block makes VS Code prompt for the key (masked) instead of storing it in a file that gets committed:

    ```json theme={null}
    {
      "inputs": [
        {
          "type": "promptString",
          "id": "perplexity-api-key",
          "description": "Perplexity API Key",
          "password": true
        }
      ],
      "servers": {
        "perplexity": {
          "type": "http",
          "url": "https://api.perplexity.ai/mcp",
          "headers": {
            "Authorization": "Bearer ${input:perplexity-api-key}"
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="Anthropic API">
    Use Perplexity's tools in a Messages API request with the MCP connector:

    ```bash theme={null}
    curl https://api.anthropic.com/v1/messages \
      -H "content-type: application/json" \
      -H "x-api-key: $ANTHROPIC_API_KEY" \
      -H "anthropic-version: 2023-06-01" \
      -H "anthropic-beta: mcp-client-2025-11-20" \
      -d '{
        "model": "claude-opus-5",
        "max_tokens": 1024,
        "messages": [{"role": "user", "content": "What happened in AI this week?"}],
        "mcp_servers": [{
          "type": "url",
          "url": "https://api.perplexity.ai/mcp",
          "name": "perplexity",
          "authorization_token": "YOUR_PERPLEXITY_API_KEY"
        }],
        "tools": [{
          "type": "mcp_toolset",
          "mcp_server_name": "perplexity"
        }]
      }'
    ```

    `authorization_token` accepts your Perplexity API key directly (no OAuth needed); it is sent to our server as a bearer token. Anthropic bills the Messages request as usual; Perplexity tool calls are billed to your Perplexity API key.

    To restrict which tools the model can call, disable tools by default and enable the ones you want:

    ```json theme={null}
    "tools": [{
      "type": "mcp_toolset",
      "mcp_server_name": "perplexity",
      "default_config": {"enabled": false},
      "configs": {
        "perplexity_search": {"enabled": true}
      }
    }]
    ```
  </Tab>

  <Tab title="Other Clients">
    Any client that supports remote MCP servers over Streamable HTTP can connect with:

    | Setting   | Value                                |
    | --------- | ------------------------------------ |
    | URL       | `https://api.perplexity.ai/mcp`      |
    | Transport | Streamable HTTP                      |
    | Header    | `Authorization: Bearer YOUR_API_KEY` |

    If your client only supports stdio servers, use the [local MCP server](#local-mcp-server) below.

    <Note>
      Custom connectors on claude.ai (web) currently require OAuth and cannot send a static API key header. Use Claude Code, Claude Desktop, or the Anthropic API instead.
    </Note>
  </Tab>
</Tabs>

<Note>
  Tool calls are billed to the API key you connect with at standard API pricing. Your key's existing rate limits apply.
</Note>

## Local MCP Server

Run the same server locally over stdio.

### One-Click Install

<CardGroup>
  <Card
    title="Install in Cursor"
    icon={
<svg
  xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 466.73 532.09"
>
  <path
    d="M457.43 125.94 244.42 2.96a22.127 22.127 0 0 0-22.12 0L9.3 125.94C3.55 129.26 0 135.4 0 142.05v247.99c0 6.65 3.55 12.79 9.3 16.11l213.01 122.98a22.127 22.127 0 0 0 22.12 0l213.01-122.98c5.75-3.32 9.3-9.46 9.3-16.11V142.05c0-6.65-3.55-12.79-9.3-16.11h-.01Zm-13.38 26.05L238.42 508.15c-1.39 2.4-5.06 1.42-5.06-1.36V273.58c0-4.66-2.49-8.97-6.53-11.31L24.87 145.67c-2.4-1.39-1.42-5.06 1.36-5.06h411.26c5.84 0 9.49 6.33 6.57 11.39h-.01Z"
    style={{ fill: "var(--color-foreground)" }}
  />
</svg>
}
    href="https://cursor.com/en/install-mcp?name=perplexity&config=eyJ0eXBlIjoic3RkaW8iLCJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBwZXJwbGV4aXR5LWFpL21jcC1zZXJ2ZXIiXSwiZW52Ijp7IlBFUlBMRVhJVFlfQVBJX0tFWSI6IiJ9fQ=="
  >
    Automatically configure the Perplexity MCP server in Cursor with one click.
  </Card>

  <Card
    title="Install in VS Code"
    icon={
<svg
  xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 100 100"
>
  <path
    d="M70.912 99.572a6.193 6.193 0 0 0 4.96-.191l20.588-9.958a6.285 6.285 0 0 0 3.54-5.661V16.239a6.286 6.286 0 0 0-3.54-5.662L75.873.62a6.2 6.2 0 0 0-7.104 1.216L29.355 37.98l-17.168-13.1a4.146 4.146 0 0 0-5.318.238l-5.506 5.035a4.205 4.205 0 0 0-.004 6.194L16.247 50 1.36 63.654a4.205 4.205 0 0 0 .004 6.194l5.506 5.034a4.145 4.145 0 0 0 5.318.238l17.168-13.1L68.77 98.166a6.205 6.205 0 0 0 2.143 1.407Zm4.103-72.39L45.11 50 75.015 72.82V27.18Z"
    fillRule="evenodd"
    style={{ fill: "var(--color-foreground)" }}
  />
</svg>
}
    href="https://vscode.dev/redirect/mcp/install?name=perplexity&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40perplexity-ai%2Fmcp-server%22%5D%2C%22env%22%3A%7B%22PERPLEXITY_API_KEY%22%3A%22%22%7D%7D"
  >
    Automatically configure the Perplexity MCP server in VS Code with one click.
  </Card>
</CardGroup>

### Manual Setup

<Steps>
  <Step title="Get Your API Key">
    <Card title="Generate API Key" icon="key" href="https://console.perplexity.ai/group/keys">
      Navigate to the API Portal and generate a new key.
    </Card>
  </Step>

  <Step title="Configure Your Client">
    Add the MCP server to your client configuration:

    <Tabs>
      <Tab title="Claude Code">
        **Option 1: CLI Command (Recommended)**

        The easiest way to get started:

        ```bash theme={null}
        claude mcp add perplexity --env PERPLEXITY_API_KEY="your_key_here" -- npx -y @perplexity-ai/mcp-server
        ```

        **Option 2: Plugin Install**

        Install via plugin:

        ```bash theme={null}
        export PERPLEXITY_API_KEY="your_key_here"
        claude
        # Then run: /plugin marketplace add perplexityai/modelcontextprotocol
        # Then run: /plugin install perplexity
        ```

        **Option 3: Manual Configuration**

        Add to your `claude.json`:

        ```json theme={null}
        {
          "mcpServers": {
            "perplexity": {
              "type": "stdio",
              "command": "npx",
              "args": ["-y", "@perplexity-ai/mcp-server"],
              "env": {
                "PERPLEXITY_API_KEY": "your_key_here"
              }
            }
          }
        }
        ```
      </Tab>

      <Tab title="Cursor">
        We recommend using the one-click install above for setting up the MCP server in Cursor.

        If you prefer to configure it manually, add the following to your `mcp.json`:

        ```json theme={null}
        {
          "mcpServers": {
            "perplexity": {
              "command": "npx",
              "args": ["-y", "@perplexity-ai/mcp-server"],
              "env": {
                "PERPLEXITY_API_KEY": "your_key_here"
              }
            }
          }
        }
        ```
      </Tab>

      <Tab title="Codex">
        ```bash theme={null}
        codex mcp add perplexity --env PERPLEXITY_API_KEY="your_key_here" -- npx -y @perplexity-ai/mcp-server
        ```
      </Tab>

      <Tab title="Other Clients">
        Most MCP-compatible clients (including Claude Desktop, VS Code, and Windsurf) use the `mcpServers` format. Configuration file locations:

        | Client             | Config File                             |
        | ------------------ | --------------------------------------- |
        | Cursor             | `~/.cursor/mcp.json`                    |
        | VS Code            | `.vscode/mcp.json`                      |
        | Claude Desktop     | `claude_desktop_config.json`            |
        | Windsurf           | `~/.codeium/windsurf/mcp_config.json`   |
        | Google Antigravity | `~/.gemini/antigravity/mcp_config.json` |

        **Standard `mcpServers` format:**

        ```json theme={null}
        {
          "mcpServers": {
            "perplexity": {
              "command": "npx",
              "args": ["-y", "@perplexity-ai/mcp-server"],
              "env": {
                "PERPLEXITY_API_KEY": "your_key_here"
              }
            }
          }
        }
        ```

        **VS Code uses a slightly different format:**

        ```json theme={null}
        {
          "servers": {
            "perplexity": {
              "type": "stdio",
              "command": "npx",
              "args": ["-y", "@perplexity-ai/mcp-server"],
              "env": {
                "PERPLEXITY_API_KEY": "your_key_here"
              }
            }
          }
        }
        ```

        If your client doesn't work with these formats, check its documentation for the correct wrapper format.
      </Tab>
    </Tabs>
  </Step>

  <Step title="Start Using">
    Restart your MCP client and start using Perplexity's tools in your AI workflows.
  </Step>
</Steps>

## Available Tools

<CardGroup>
  <Card title="perplexity_search" icon="search">
    Direct web search using the Perplexity Search API. Returns ranked search results with titles, URLs, snippets, and metadata.

    **Best for:** Finding current information, news, facts, or specific web content.
  </Card>

  <Card title="perplexity_ask" icon="message">
    General-purpose conversational AI with real-time web search, backed by the [Agent API](/docs/agent-api/quickstart) `fast` preset.

    **Best for:** Quick questions, everyday searches, and conversational queries that benefit from web context.
  </Card>

  <Card title="perplexity_research" icon="book">
    Deep, comprehensive research backed by the Agent API `high` preset. Provides thorough analysis with citations.

    **Best for:** Complex topics requiring detailed investigation, comprehensive reports, and in-depth analysis.
  </Card>

  <Card title="perplexity_reason" icon="brain">
    Advanced reasoning and problem-solving backed by the Agent API `medium` preset.

    **Best for:** Logical problems, complex analysis, decision-making, and tasks requiring step-by-step reasoning.
  </Card>
</CardGroup>

<Info>
  For detailed setup instructions, troubleshooting, and proxy configuration, visit our [GitHub repository](https://github.com/perplexityai/modelcontextprotocol).
</Info>


# Perplexity with n8n
Source: https://docs.perplexity.ai/docs/getting-started/integrations/n8n

Add real-time web search, AI agents, and embeddings to your n8n workflows using the native Perplexity node.

<SonarDeprecationNotice />

## Overview

n8n ships a native **Perplexity node** with Agent, Search, and Embeddings resources — all configurable from the visual canvas. Models load dynamically from the API, so the dropdown always reflects the latest options.

<Info>
  **n8n** is a node-based workflow automation platform. It supports both self-hosted and cloud deployments — all examples below work in either. If you're self-hosting, make sure your instance can reach `api.perplexity.ai` outbound. Learn more at [n8n.io](https://n8n.io).
</Info>

The node supports three resources:

* **Agent** — Third-party models (OpenAI, Anthropic, Google, xAI) with tool-calling and structured output
* **Search** — Raw ranked web results for your own processing
* **Embeddings** — Vector generation for RAG and retrieval pipelines

## Prerequisites

* n8n 2.14.0+ (cloud at [app.n8n.cloud](https://app.n8n.cloud) or self-hosted)
* A Perplexity API key

<Card title="Get API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate your Perplexity API key from the console.
</Card>

## Credential Setup

<Steps>
  <Step title="Open Credentials">
    In n8n, go to **Settings → Credentials → Add credential**.
  </Step>

  <Step title="Select Perplexity">
    Search for **Perplexity API** and select it.
  </Step>

  <Step title="Add Your Key">
    Paste your API key and save. The node will reference this credential automatically.
  </Step>
</Steps>

<img alt="Perplexity credential setup" />

***

## Agent

Use the Agent resource to route through third-party models (OpenAI, Anthropic, Google, xAI) with Perplexity's `web_search` and `fetch_url` tools.

Set **Resource** to `Agent` and configure:

| Parameter               | Description                                                                                 |
| ----------------------- | ------------------------------------------------------------------------------------------- |
| **Model**               | Any model from the dynamic dropdown (e.g., `openai/gpt-5.5`, `anthropic/claude-sonnet-4-6`) |
| **Input**               | Your prompt — supports n8n expressions                                                      |
| **Tools**               | Select `web_search`, `fetch_url`, or both                                                   |
| **System Instructions** | Optional system prompt for the agent                                                        |
| **Response Format**     | Optional JSON schema for structured output                                                  |

<img alt="Agent resource configuration" />

***

## Search

Get raw ranked web results without LLM processing. Set **Resource** to `Search`:

| Parameter         | Description                                 |
| ----------------- | ------------------------------------------- |
| **Query**         | The search query — supports n8n expressions |
| **Recency**       | `day`, `week`, `month`, or `year`           |
| **Domain Filter** | Limit to specific domains                   |
| **Language**      | ISO 639-1 language code                     |
| **Country**       | Two-letter country code                     |

Each result includes `title`, `url`, `snippet`, and `date`.

<img alt="Search resource results" />

***

## Embeddings

Generate vectors for RAG and retrieval pipelines. Set **Resource** to `Embeddings`:

| Parameter | Description                                                        |
| --------- | ------------------------------------------------------------------ |
| **Model** | `pplx-embed-v1-4b` (2560 dims) or `pplx-embed-v1-0.6b` (1024 dims) |
| **Input** | Text to embed — supports n8n expressions                           |

The node also supports contextual embeddings via `POST /v1/contextualizedembeddings` for document-chunk-aware vectors.

<img alt="Embeddings resource configuration" />

***

## Error Handling

Use n8n's **Error Trigger** workflow or the built-in **Retry on Fail** setting (node settings → Retry on Fail) to handle transient errors:

* **429 Too Many Requests** — add a **Wait** node with exponential backoff before retrying
* **401 Unauthorized** — verify your Perplexity API credential is saved correctly
* **500 errors** — enable Retry on Fail in the node settings

## Links & Resources

<CardGroup>
  <Card title="n8n Docs" icon="book" href="https://docs.n8n.io">
    Official n8n documentation
  </Card>

  <Card title="n8n Community" icon="users" href="https://community.n8n.io">
    Templates, workflows, and community support
  </Card>

  <Card title="Perplexity API Reference" icon="code" href="/api-reference">
    Full API reference
  </Card>

  <Card title="Agent API" icon="sparkles" href="/docs/agent-api/models">
    Available models and capabilities
  </Card>
</CardGroup>


# Perplexity with OpenClaw
Source: https://docs.perplexity.ai/docs/getting-started/integrations/openclaw

Use Perplexity as an LLM provider and web search provider in OpenClaw.

<SonarDeprecationNotice />

## Overview

<u>[OpenClaw](https://openclaw.ai)</u> is an open-source AI agent that runs in your terminal and connects to multiple LLM providers, featuring support for Perplexity as a web search provider for real-time information retrieval.

You can configure OpenClaw to use Perplexity's Agent API models as your agent, and the Perplexity Search API for web search tool calls. This allows you to leverage Perplexity's powerful models and up-to-date search results directly within OpenClaw's agent framework.

<Card title="Get a Perplexity API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Navigate to the API Console and generate a new key to use with OpenClaw.
</Card>

***

## Search API Setup (Use Perplexity as your Web Search Provider)

Use Perplexity Search API as OpenClaw's web search backend for real-time information retrieval.

<Steps>
  <Step title="Configure the Search Provider">
    <Tabs>
      <Tab title="Interactive CLI (Recommended)">
        The quickest way — no file editing required:

        ```bash theme={null}
        openclaw configure --section web
        ```

        Select **Perplexity** when prompted for a search provider, then paste your API key.
      </Tab>

      <Tab title="Config File (JSON)">
        Edit your `openclaw.json` (run `openclaw config file` to locate it):

        ```json theme={null}
        {
          "plugins": {
            "entries": {
              "perplexity": {
                "config": {
                  "webSearch": {
                    "apiKey": "pplx-..."
                  }
                }
              }
            }
          },
          "tools": {
            "web": {
              "search": {
                "provider": "perplexity"
              }
            }
          }
        }
        ```
      </Tab>

      <Tab title="Environment Variable">
        Set the environment variable and OpenClaw will auto-detect it:

        <Tabs>
          <Tab title="macOS / Linux">
            ```bash theme={null}
            export PERPLEXITY_API_KEY="pplx-..."
            ```
          </Tab>

          <Tab title="Windows (PowerShell)">
            ```powershell theme={null}
            setx PERPLEXITY_API_KEY="pplx-..."
            ```
          </Tab>
        </Tabs>

        Or set `PERPLEXITY_API_KEY` in `~/.openclaw/.env` for daemon installs.
      </Tab>
    </Tabs>
  </Step>

  <Step title="Start using OpenClaw with Perplexity Search">
    Start OpenClaw and ask anything that requires web search:

    ```
    openclaw
    > What are the latest developments in quantum computing?
    ```

    OpenClaw will use Perplexity Search API to retrieve structured results and incorporate them into its response.
  </Step>
</Steps>

### Search Tool Parameters

When OpenClaw invokes `web_search` with Perplexity as the provider, these parameters are available:

| Parameter             | Description                                            |
| --------------------- | ------------------------------------------------------ |
| `query`               | Search query (required)                                |
| `count`               | Number of results (1–10, default: 5)                   |
| `country`             | ISO 3166-1 alpha-2 country code (e.g., `US`, `DE`)     |
| `language`            | ISO 639-1 language code (e.g., `en`, `fr`)             |
| `freshness`           | Time filter: `day`, `week`, `month`, or `year`         |
| `date_after`          | Results published after this date (`YYYY-MM-DD`)       |
| `date_before`         | Results published before this date (`YYYY-MM-DD`)      |
| `domain_filter`       | Domain allowlist or denylist (max 20 entries)          |
| `max_tokens`          | Total content budget (default: 25,000, max: 1,000,000) |
| `max_tokens_per_page` | Per-page token limit (default: 2,048)                  |

<Tip>
  Domain filters support allowlists (`["nature.com", "science.org"]`) and denylists (`["-reddit.com", "-pinterest.com"]`), but you cannot mix both in the same request. See the [domain filter guide](/docs/search/filters/domain-filter) for details.
</Tip>

***

## Agent API Setup (Use Perplexity as your LLM Provider)

Use Perplexity's Agent API to run models like Claude Sonnet, GPT-5, Gemini, and Sonar as your OpenClaw coding agent.

<Steps>
  <Step title="Get Your API Key">
    <Card title="Generate API Key" icon="key" href="https://console.perplexity.ai/group/keys">
      Navigate to the API Console and generate a new key.
    </Card>
  </Step>

  <Step title="Install OpenClaw">
    If you haven't installed OpenClaw yet:

    <Tabs>
      <Tab title="macOS / Linux">
        ```bash theme={null}
        curl -fsSL https://openclaw.ai/install.sh | bash
        ```
      </Tab>

      <Tab title="Windows (PowerShell)">
        ```powershell theme={null}
        iwr -useb https://openclaw.ai/install.ps1 | iex
        ```
      </Tab>
    </Tabs>

    For Docker, Podman, Nix, or other installation methods, see the [OpenClaw install documentation](https://docs.openclaw.ai/install).
  </Step>

  <Step title="Configure Perplexity as an LLM Provider">
    <Tabs>
      <Tab title="Onboarding CLI (Recommended)">
        The quickest way — no file editing required:

        ```bash theme={null}
        openclaw onboard \
          --auth-choice custom-api-key \
          --custom-base-url "https://api.perplexity.ai/v1" \
          --custom-api-key "pplx-YOUR_KEY_HERE" \
          --custom-model-id "anthropic/claude-sonnet-4-6" \ 
          --custom-compatibility openai \
          --custom-provider-id perplexity \
          --install-daemon
        ```

        This registers Perplexity as a provider with one model. To add more models, re-run with a different `--custom-model-id` or switch to the config file method.

        You can replace `anthropic/claude-sonnet-4-6` with any model ID from the [Agent API models list](/docs/agent-api/models) to change your default model.
      </Tab>

      <Tab title="Config File (All Models)">
        Edit your `openclaw.json` (run `openclaw config file` to locate it):

        ```json theme={null}
        {
        "agents": {
          "defaults": {
            "model": {
              "primary": "perplexity/anthropic/claude-sonnet-4-6" // Set your default model here
            }
          }
        },
        "models": {
          "mode": "merge",
          "providers": {
            "perplexity": {
              "baseUrl": "https://api.perplexity.ai/v1",
              "apiKey": "pplx-YOUR_KEY_HERE",
              "api": "openai-responses",
              "models": [
                {
                  "id": "perplexity/sonar",
                  "name": "Sonar (Perplexity)",
                  "api": "openai-responses",
                  "reasoning": false,
                  "input": ["text"],
                  "cost": { "input": 0.25, "output": 2.50, "cacheRead": 0.0625, "cacheWrite": 0 },
                  "contextWindow": 128000,
                  "maxTokens": 16384
                },
                {
                  "id": "anthropic/claude-opus-4-7",
                  "name": "Claude Opus 4.7 (Perplexity)",
                  "api": "openai-responses",
                  "reasoning": false,
                  "input": ["text"],
                  "cost": { "input": 5.00, "output": 25.00, "cacheRead": 0.50, "cacheWrite": 0 },
                  "contextWindow": 200000,
                  "maxTokens": 16384
                },
                {
                  "id": "anthropic/claude-opus-4-5",
                  "name": "Claude Opus 4.5 (Perplexity)",
                  "api": "openai-responses",
                  "reasoning": false,
                  "input": ["text"],
                  "cost": { "input": 5.00, "output": 25.00, "cacheRead": 0.50, "cacheWrite": 0 },
                  "contextWindow": 200000,
                  "maxTokens": 16384
                },
                {
                  "id": "anthropic/claude-sonnet-4-6",
                  "name": "Claude Sonnet 4.6 (Perplexity)",
                  "api": "openai-responses",
                  "reasoning": false,
                  "input": ["text"],
                  "cost": { "input": 3.00, "output": 15.00, "cacheRead": 0.30, "cacheWrite": 0 },
                  "contextWindow": 200000,
                  "maxTokens": 16384
                },
                {
                  "id": "anthropic/claude-sonnet-4-5",
                  "name": "Claude Sonnet 4.5 (Perplexity)",
                  "api": "openai-responses",
                  "reasoning": false,
                  "input": ["text"],
                  "cost": { "input": 3.00, "output": 15.00, "cacheRead": 0.30, "cacheWrite": 0 },
                  "contextWindow": 200000,
                  "maxTokens": 16384
                },
                {
                  "id": "anthropic/claude-haiku-4-5",
                  "name": "Claude Haiku 4.5 (Perplexity)",
                  "api": "openai-responses",
                  "reasoning": false,
                  "input": ["text"],
                  "cost": { "input": 1.00, "output": 5.00, "cacheRead": 0.10, "cacheWrite": 0 },
                  "contextWindow": 200000,
                  "maxTokens": 16384
                },
                {
                  "id": "openai/gpt-5.4",
                  "name": "GPT-5.4 (Perplexity)",
                  "api": "openai-responses",
                  "reasoning": false,
                  "input": ["text"],
                  "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
                  "contextWindow": 128000,
                  "maxTokens": 16384
                },
                {
                  "id": "openai/gpt-5.2",
                  "name": "GPT-5.2 (Perplexity)",
                  "api": "openai-responses",
                  "reasoning": false,
                  "input": ["text"],
                  "cost": { "input": 1.75, "output": 14.00, "cacheRead": 0.175, "cacheWrite": 0 },
                  "contextWindow": 128000,
                  "maxTokens": 16384
                },
                {
                  "id": "openai/gpt-5.1",
                  "name": "GPT-5.1 (Perplexity)",
                  "api": "openai-responses",
                  "reasoning": false,
                  "input": ["text"],
                  "cost": { "input": 1.25, "output": 10.00, "cacheRead": 0.125, "cacheWrite": 0 },
                  "contextWindow": 128000,
                  "maxTokens": 16384
                },
                {
                  "id": "openai/gpt-5-mini",
                  "name": "GPT-5 Mini (Perplexity)",
                  "api": "openai-responses",
                  "reasoning": false,
                  "input": ["text"],
                  "cost": { "input": 0.25, "output": 2.00, "cacheRead": 0.025, "cacheWrite": 0 },
                  "contextWindow": 128000,
                  "maxTokens": 16384
                },
                {
                  "id": "google/gemini-3.1-pro-preview",
                  "name": "Gemini 3.1 Pro (Perplexity)",
                  "api": "openai-responses",
                  "reasoning": false,
                  "input": ["text"],
                  "cost": { "input": 2.00, "output": 12.00, "cacheRead": 0.20, "cacheWrite": 0 },
                  "contextWindow": 200000,
                  "maxTokens": 16384
                },
                {
                  "id": "google/gemini-3-flash-preview",
                  "name": "Gemini 3 Flash (Perplexity)",
                  "api": "openai-responses",
                  "reasoning": false,
                  "input": ["text"],
                  "cost": { "input": 0.50, "output": 3.00, "cacheRead": 0.05, "cacheWrite": 0 },
                  "contextWindow": 200000,
                  "maxTokens": 16384
                },
                {
                  "id": "google/gemini-2.5-pro",
                  "name": "Gemini 2.5 Pro (Perplexity)",
                  "api": "openai-responses",
                  "reasoning": false,
                  "input": ["text"],
                  "cost": { "input": 1.25, "output": 10.00, "cacheRead": 0.125, "cacheWrite": 0 },
                  "contextWindow": 200000,
                  "maxTokens": 16384
                },
                {
                  "id": "google/gemini-2.5-flash",
                  "name": "Gemini 2.5 Flash (Perplexity)",
                  "api": "openai-responses",
                  "reasoning": false,
                  "input": ["text"],
                  "cost": { "input": 0.30, "output": 2.50, "cacheRead": 0.03, "cacheWrite": 0 },
                  "contextWindow": 200000,
                  "maxTokens": 16384
                },
                {
                  "id": "nvidia/nemotron-3-super-120b-a12b",
                  "name": "Nemotron 3 Super (Perplexity)",
                  "api": "openai-responses",
                  "reasoning": false,
                  "input": ["text"],
                  "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
                  "contextWindow": 128000,
                  "maxTokens": 16384
                },
                {
                  "id": "xai/grok-4.20-non-reasoning",
                  "name": "Grok 4.20 Non-Reasoning (Perplexity)",
                  "api": "openai-responses",
                  "reasoning": false,
                  "input": ["text"],
                  "cost": { "input": 1.25, "output": 2.50, "cacheRead": 0.20, "cacheWrite": 0 },
                  "contextWindow": 128000,
                  "maxTokens": 16384
                }
              ]
            }
          }
        }
        }
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Start using OpenClaw">
    Launch OpenClaw and your agent will use Perplexity:

    ```bash theme={null}
    openclaw
    ```
  </Step>
</Steps>

### Agent API Configuration Tips

<AccordionGroup>
  <Accordion title="API transport must be openai-responses">
    Perplexity's Agent API uses the [OpenAI Responses format](/docs/agent-api/openai-compatibility). In `openclaw.json`, set the `api` field to `"openai-responses"` at both the provider level and each model entry.

    Using `"openai-completions"` will not work.
  </Accordion>

  <Accordion title="Base URL must be exactly https://api.perplexity.ai/v1">
    Do **not** include `/agent` or `/responses` in the URL. OpenClaw appends `/responses` automatically.

    Wrong base URLs will cause authentication errors or 404s.

    | Correct                        | Wrong                                       |
    | ------------------------------ | ------------------------------------------- |
    | `https://api.perplexity.ai/v1` | `https://api.perplexity.ai/v1/agent`        |
    |                                | `https://api.perplexity.ai/v1/responses`    |
    |                                | `https://api.perplexity.ai` (missing `/v1`) |
  </Accordion>

  <Accordion title="Model ID format">
    In the config, model IDs under a provider block omit the provider prefix. The full model reference adds it:

    * Config model ID: `anthropic/claude-sonnet-4-6`
    * Full model reference: `perplexity/anthropic/claude-sonnet-4-6`
  </Accordion>
</AccordionGroup>

<Tip>
  For the latest model list and pricing, see the [Agent API models page](/docs/agent-api/models) and [pricing page](/docs/getting-started/pricing).
</Tip>

***

## Links & Resources

<CardGroup>
  <Card title="Agent API Quickstart" icon="robot" href="/docs/agent-api/quickstart">
    Use third-party models with built-in tools and function calling
  </Card>

  <Card title="Agent API Models" icon="list" href="/docs/agent-api/models">
    Full list of available models and pricing
  </Card>

  <Card title="Search API Quickstart" icon="search" href="/docs/search/quickstart">
    Full Perplexity Search API documentation
  </Card>

  <Card title="OpenAI Compatibility" icon="plug" href="/docs/agent-api/openai-compatibility">
    How the Agent API works with OpenAI-compatible clients
  </Card>

  <Card title="OpenClaw Documentation" icon="book" href="https://docs.openclaw.ai">
    OpenClaw's official documentation
  </Card>

  <Card title="API Console" icon="key" href="https://console.perplexity.ai">
    Generate and manage your API keys
  </Card>
</CardGroup>


# Perplexity with OpenCode
Source: https://docs.perplexity.ai/docs/getting-started/integrations/opencode

Use the Perplexity Agent API inside the OpenCode AI coding agent — one endpoint, every frontier model, one API key.

<SonarDeprecationNotice />

## Overview

[OpenCode](https://opencode.ai) is an open-source AI coding agent for your terminal, IDE, or desktop. The Perplexity **Agent API** is compatible with the OpenAI Responses API and exposes frontier models from OpenAI, Anthropic, Google, xAI, and Perplexity through a single endpoint.

Wiring OpenCode to the Agent API means you can swap any frontier model into your coding agent or research subagent — without juggling separate provider accounts.

<Info>
  **OpenCode** ships with multi-agent orchestration: you can configure a `primary` agent for coding and `subagent` agents for specialized tasks. Learn more at [opencode.ai](https://opencode.ai).
</Info>

## Setup

The Agent API implements the OpenAI Responses API, so you configure it in OpenCode as a custom provider using [`@ai-sdk/open-responses`](https://ai-sdk.dev/providers/ai-sdk-providers/open-responses) pointed at Perplexity's `/v1/responses` endpoint.

<Steps>
  <Step title="Install OpenCode">
    Follow the [OpenCode install guide](https://opencode.ai/docs) for your platform (macOS, Linux, Windows).
  </Step>

  <Step title="Get a Perplexity API key">
    <Card title="Get API Key" icon="key" href="https://console.perplexity.ai/group/keys">
      Generate your Perplexity API key from the API portal.
    </Card>

    Export it in your shell:

    ```bash theme={null}
    export PERPLEXITY_API_KEY="pplx-..."
    ```
  </Step>

  <Step title="Configure OpenCode">
    Add the Perplexity Agent API as a provider in your `opencode.json` (or `~/.config/opencode/config.json`). See the configuration below.
  </Step>

  <Step title="Verify">
    Run `/models` to confirm the Perplexity Agent models appear in the selector.
  </Step>
</Steps>

## Provider Configuration

The `@ai-sdk/open-responses` provider is built for servers that implement the OpenAI Responses API — exactly the dialect the Agent API speaks. Point its `url` at Perplexity's `/v1/responses` endpoint and declare the models you want in the picker.

<Warning>
  Use a **Responses API** provider — `@ai-sdk/open-responses` (shown here) or `@ai-sdk/openai`, whose `.responses()` model hits the same route. Do **not** use `@ai-sdk/openai-compatible`: it targets Chat Completions (`/v1/chat/completions`), which is not a valid Agent API route and returns 404.
</Warning>

```json theme={null}
{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "perplexity-agent": {
      "npm": "@ai-sdk/open-responses",
      "name": "Perplexity Agent API",
      "options": {
        "name": "perplexity-agent",
        "url": "https://api.perplexity.ai/v1/responses",
        "apiKey": "{env:PERPLEXITY_API_KEY}",
        "headers": {
          "X-Pplx-Integration": "opencode/1.0"
        }
      },
      "models": {
        "openai/gpt-5.6-sol": { "name": "GPT-5.6 Sol" },
        "openai/gpt-5.6-terra": { "name": "GPT-5.6 Terra" },
        "openai/gpt-5.6-luna": { "name": "GPT-5.6 Luna" },
        "anthropic/claude-opus-4-8": { "name": "Claude Opus 4.8" },
        "anthropic/claude-sonnet-5": { "name": "Claude Sonnet 5" },
        "anthropic/claude-haiku-4-5": { "name": "Claude Haiku 4.5" },
        "google/gemini-3.1-pro-preview": { "name": "Gemini 3.1 Pro" },
        "xai/grok-4.5": { "name": "Grok 4.5" },
        "perplexity/kimi-k2.7-code": { "name": "Kimi K2.7 Code" }
      }
    }
  }
}
```

That's it — one API key, one endpoint, every frontier model.

## Available Models

The Agent API routes to models from multiple providers. The full canonical list lives on the [models page](/docs/agent-api/models); the most useful identifiers for coding work:

| Model ID                        | Best for                                     |
| ------------------------------- | -------------------------------------------- |
| `openai/gpt-5.6-sol`            | Deep reasoning, long-horizon coding tasks    |
| `openai/gpt-5.6-terra`          | General-purpose coding agent                 |
| `openai/gpt-5.6-luna`           | Fast, cheap coding completions               |
| `anthropic/claude-opus-4-8`     | Highest-quality code review and architecture |
| `anthropic/claude-sonnet-5`     | Balanced coding + tool use                   |
| `anthropic/claude-haiku-4-5`    | Fast, low-cost edits                         |
| `google/gemini-3.1-pro-preview` | Long-context refactors                       |
| `xai/grok-4.5`                  | Low-latency edits                            |
| `perplexity/kimi-k2.7-code`     | Dedicated coding and agentic workflows       |

## Use as a Primary Coding Model

Set any Agent API model as your default in `opencode.json`:

```json theme={null}
{
  "$schema": "https://opencode.ai/config.json",
  "model": "perplexity-agent/anthropic/claude-opus-4-8"
}
```

OpenCode addresses each model as `<providerId>/<modelId>`, so the full identifier is `perplexity-agent/anthropic/claude-opus-4-8`.

## Multi-Agent Setup

Assign different Agent API models to different OpenCode agents — all through one Perplexity key. Here a primary coder delegates to a lighter, read-only subagent:

```json theme={null}
{
  "$schema": "https://opencode.ai/config.json",
  "model": "perplexity-agent/anthropic/claude-opus-4-8",
  "agent": {
    "coder": {
      "description": "Primary coding agent",
      "mode": "primary",
      "model": "perplexity-agent/anthropic/claude-opus-4-8",
      "temperature": 0.2,
      "tools": {
        "write": true,
        "edit": true,
        "bash": true
      }
    },
    "researcher": {
      "description": "Read-only subagent for lookups and summarization",
      "mode": "subagent",
      "model": "perplexity-agent/openai/gpt-5.6-sol",
      "temperature": 0.4,
      "tools": {
        "write": false,
        "edit": false,
        "bash": false
      }
    }
  }
}
```

The `coder` owns the filesystem (write, edit, bash) while the read-only `researcher` runs on a separate model for analysis and summarization. Swap either `model` for any [Agent API model](/docs/agent-api/models).

Verify the wiring:

```
/agents   # Should show coder and researcher
/models   # Should include Perplexity Agent models
```

## Why the Agent API

The Agent API is purpose-built for agent loops:

* **One key, every model** — switch between OpenAI, Anthropic, Google, xAI, and Perplexity without managing separate accounts.
* **OpenAI Responses-compatible** — drop-in for any OpenCode provider slot that speaks `/v1/responses`.

## Links & Resources

<CardGroup>
  <Card title="Agent API Quickstart" icon="bolt" href="/docs/agent-api/quickstart">
    Send your first Agent API request.
  </Card>

  <Card title="Agent API Models" icon="sparkles" href="/docs/agent-api/models">
    Full model catalog with pricing.
  </Card>

  <Card title="Perplexity SDK" icon="code" href="/docs/sdk/overview">
    Call the Agent API directly for presets, tools, and full control.
  </Card>

  <Card title="OpenAI Compatibility" icon="plug" href="/docs/agent-api/openai-compatibility">
    Use Agent API with any OpenAI SDK.
  </Card>

  <Card title="OpenCode Providers" icon="book" href="https://opencode.ai/docs/providers/">
    OpenCode custom provider reference.
  </Card>

  <Card title="OpenCode Docs" icon="book-open" href="https://opencode.ai/docs">
    Official OpenCode documentation.
  </Card>
</CardGroup>

## Support

Need help with the integration?

* Browse the [OpenCode documentation](https://opencode.ai/docs)
* Review our [FAQ](/docs/resources/faq)


# Perplexity with Pipedream
Source: https://docs.perplexity.ai/docs/getting-started/integrations/pipedream

Wire Perplexity into Pipedream workflows alongside 3,000+ other apps — automate research, summarization, and grounded responses with code and no-code steps.

<SonarDeprecationNotice />

## Overview

[Pipedream](https://pipedream.com) is a workflow automation platform with 3,000+ pre-built app integrations. The Perplexity app lets you authenticate once and then call Perplexity's Agent API and Search endpoints from any Pipedream workflow — whether triggered by an email, a webhook, an RSS feed, a Slack message, a Google Sheets update, or a schedule.

<Info>
  **Pipedream** supports both no-code visual steps and full-code Node.js / Python steps in the same workflow. Learn more at [pipedream.com](https://pipedream.com).
</Info>

## Authentication

<Steps>
  <Step title="Get your API key">
    Generate a Perplexity API key from the [API portal](https://console.perplexity.ai/group/keys).
  </Step>

  <Step title="Connect Perplexity in Pipedream">
    In Pipedream, open any workflow and add the **Perplexity** app to a step. Click **Connect new account** and paste your API key. Pipedream stores it securely and references it via `$auth.api_key` in all future steps.
  </Step>
</Steps>

<Card title="Get API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate your Perplexity API key from the API portal.
</Card>

## Built-in Action: Create Response

The Perplexity app ships a **Create Response (Agent API)** action that runs an Agent API request — no code required.

* **Endpoint**: `POST /v1/agent`
* **Inputs**: a preset or model, input, tools (`web_search`, `fetch_url`), and optional instructions.
* **Output**: the Agent API response, including `status`, `output`, and usage.

Add it from the step picker by searching **Perplexity → Create Response (Agent API)**.

## Custom Code Step

For new model integrations, use a Pipedream **Node.js code step** to call the Agent API with your saved Perplexity connection:

```javascript theme={null}
import { axios } from "@pipedream/platform";

export default defineComponent({
  props: {
    perplexity: {
      type: "app",
      app: "perplexity",
    },
  },
  async run({ steps, $ }) {
    return await axios($, {
      method: "POST",
      url: "https://api.perplexity.ai/v1/agent",
      headers: {
        Authorization: `Bearer ${this.perplexity.$auth.api_key}`,
        "Content-Type": "application/json",
        "X-Pplx-Integration": "pipedream/1.0",
      },
      data: {
        preset: "low",
        input: "Summarize this week's AI research.",
      },
    });
  },
});
```

You can swap the URL to call any [Perplexity API endpoint](/api-reference):

* `/v1/agent` — Agent API with third-party models and presets
* `/search` — raw ranked web results
* `/v1/embeddings` — vector embeddings

## Example Workflows

Common Perplexity-on-Pipedream patterns:

* **Customer support automation** — incoming email triggers a Perplexity Agent API step that drafts a response, then logs the conversation in a CRM.
* **News-feed summarization** — new article from an RSS trigger is summarized by Perplexity and posted to a Slack channel with citations.
* **Brand monitoring** — social media mentions are piped through Perplexity for sentiment analysis and entity extraction, then written to a Google Sheet.
* **Daily research digest** — a scheduled cron triggers a Perplexity query, and the result is emailed or posted to a chat channel every morning.

## Security & Credentials

Pipedream stores your Perplexity API key encrypted at rest and injects it into every step via the `$auth` object — your key never appears in step UI or logs. You can rotate the key at any time from your account's **Connected Accounts** page.

## Links & Resources

<CardGroup>
  <Card title="Pipedream Perplexity App" icon="plug" href="https://pipedream.com/apps/perplexity">
    Official Perplexity app on Pipedream.
  </Card>

  <Card title="Pipedream Docs" icon="book" href="https://pipedream.com/docs">
    Full Pipedream documentation.
  </Card>

  <Card title="Perplexity API Reference" icon="code" href="/api-reference">
    Full Perplexity API reference.
  </Card>

  <Card title="Agent API Models" icon="cpu" href="/docs/agent-api/models">
    Compare the models available through the Agent API.
  </Card>
</CardGroup>

## Support

Need help with the integration?

* Browse the [Pipedream documentation](https://pipedream.com/docs)
* Review our [FAQ](/docs/resources/faq)


# Perplexity with SuperPlane
Source: https://docs.perplexity.ai/docs/getting-started/integrations/superplane

Run Perplexity agents inside SuperPlane workflows — research, synthesis, and analysis steps with web search, URL fetching, and source citations.

<SonarDeprecationNotice />

## Overview

[SuperPlane](https://superplane.com) is an open-source DevOps control plane for long-lived, event-driven workflows. It exposes Perplexity as a native **component** on the canvas — drop a Perplexity node into any workflow and it runs a Perplexity agent with web search and URL fetching, then emits the response and source citations as a payload for downstream nodes.

<Info>
  **SuperPlane** models workflows as event-driven canvases: nodes emit payloads, downstream nodes subscribe to them, and the runtime tracks every run with full observability. Learn more at [superplane.com](https://superplane.com).
</Info>

## Component: Perplexity

The Perplexity component runs a Perplexity AI agent as a workflow step. Use it for research, synthesis, automated analysis, and content generation grounded in real-time web sources.

### Action

| Action        | Description                                                              |
| ------------- | ------------------------------------------------------------------------ |
| **Run Agent** | Run a Perplexity AI agent with web search and URL fetching capabilities. |

### Configuration

| Parameter        | Description                                                                                                                                                                                        |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Preset**       | Agent preset to use: `fast-search`, `pro-search`, `deep-research`, or `advanced-deep-research`. These map to the Agent API tiers `fast` / `low` / `medium` / `high`. When set, `Model` is ignored. |
| **Model**        | Agent API model identifier to use when no preset is specified (e.g., `perplexity/sonar`).                                                                                                          |
| **Input**        | The prompt or question for the agent. Supports SuperPlane [expressions](https://docs.superplane.com/concepts/expressions).                                                                         |
| **Instructions** | Optional system-level instructions for the agent.                                                                                                                                                  |
| **Web Search**   | Enable the `web_search` tool (default: `true`).                                                                                                                                                    |
| **Fetch URL**    | Enable the `fetch_url` tool (default: `true`).                                                                                                                                                     |

### Output Payload

The component emits a payload with these fields downstream nodes can access via expressions:

| Field       | Description                           |
| ----------- | ------------------------------------- |
| `text`      | The generated text response.          |
| `citations` | Source citations from web results.    |
| `model`     | The specific model used for this run. |
| `usage`     | Token and cost usage information.     |

## API Key Setup

Configure the Perplexity integration in SuperPlane with your API key. Open your canvas's **Integrations** settings, add a Perplexity integration, and paste your key.

<Card title="Get API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate your Perplexity API key from the API portal.
</Card>

## Quick Start

A minimal workflow that asks Perplexity a question whenever a manual run is triggered:

<Steps>
  <Step title="Add a Manual Run trigger">
    Drop a **Manual Run** node onto the canvas — this is the workflow's entry point.
  </Step>

  <Step title="Add a Perplexity node">
    Click **+ Components**, choose **Perplexity → Run Agent**, and drag it onto the canvas. Connect **Manual Run → Perplexity**.
  </Step>

  <Step title="Configure the agent">
    In the Perplexity node:

    * **Preset**: `pro-search`
    * **Input**: `What is the latest news on nuclear fusion?`
    * **Web Search**: enabled
    * **Fetch URL**: enabled
  </Step>

  <Step title="Run">
    Click **Run** on the Manual Run node. The Perplexity node emits a payload with `text`, `citations`, `model`, and `usage`.
  </Step>
</Steps>

## Reading the Response Downstream

Use SuperPlane expressions to pipe the Perplexity output into the next node — for example, a Slack message or a database write:

```
Research result: {{ $['Perplexity'].data.text }}

Sources:
{{ $['Perplexity'].data.citations }}
```

In condition fields (If / Filter), write expressions without `{{ }}`:

```
$['Perplexity'].data.usage.total_tokens > 1000
```

## Use Cases

* **Incident triage** — when an alert fires, run a Perplexity research step to gather background on a vendor, library, or CVE before paging on-call.
* **Release notes synthesis** — turn raw GitHub commit diffs into customer-facing release notes with citations.
* **Competitive monitoring** — schedule a daily canvas that queries Perplexity for industry news and posts a summary to a Slack channel.
* **Document grounding** — feed a Perplexity run's output into a downstream component that updates a Notion page or knowledge base.

## Links & Resources

<CardGroup>
  <Card title="SuperPlane Perplexity Component" icon="book" href="https://docs.superplane.com/components/perplexity">
    Official component documentation.
  </Card>

  <Card title="SuperPlane Docs" icon="globe" href="https://docs.superplane.com">
    Full SuperPlane documentation.
  </Card>

  <Card title="Perplexity Agent API" icon="robot" href="/docs/agent-api/quickstart">
    How the Perplexity agent layer works.
  </Card>

  <Card title="Agent API Models" icon="sparkles" href="/docs/agent-api/models">
    Available models and pricing.
  </Card>
</CardGroup>

## Support

Need help with the integration?

* Browse the [SuperPlane documentation](https://docs.superplane.com)
* Review our [FAQ](/docs/resources/faq)


# Perplexity with the Vercel AI SDK
Source: https://docs.perplexity.ai/docs/getting-started/integrations/vercel-ai-sdk

Use Perplexity's Agent API from Vercel AI SDK (Next.js) apps through the @ai-sdk/open-responses provider.

<SonarDeprecationNotice />

## Overview

The [Vercel AI SDK](https://ai-sdk.dev) is a TypeScript toolkit for building AI apps — Next.js and React — with streaming primitives and UI hooks like `useChat`.
Reach the [Agent API](/docs/agent-api/quickstart) through the [`@ai-sdk/open-responses`](https://ai-sdk.dev/providers/ai-sdk-providers/open-responses) provider, pointed at Perplexity's `/v1/responses` endpoint, to get a native AI SDK model you can pass to `generateText`, `streamText`, and `useChat`.

<Info>
  Create the provider on the server — a Next.js Route Handler, Server Action, or API route — so `PERPLEXITY_API_KEY` never reaches the browser.
</Info>

## Installation

<CodeGroup>
  ```bash pnpm theme={null}
  pnpm add ai @ai-sdk/open-responses
  ```

  ```bash npm theme={null}
  npm install ai @ai-sdk/open-responses
  ```
</CodeGroup>

## API Key Setup

```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```

<Card title="Get API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate your Perplexity API key from the API portal.
</Card>

## Quickstart

Create the provider with `createOpenResponses`, point it at `/v1/responses`, and call `generateText`.

```typescript theme={null}
import { createOpenResponses } from "@ai-sdk/open-responses";
import { generateText } from "ai";

const perplexity = createOpenResponses({
  name: "perplexity",
  url: "https://api.perplexity.ai/v1/responses",
  apiKey: process.env.PERPLEXITY_API_KEY,
});

const { text } = await generateText({
  model: perplexity("openai/gpt-5.6-sol"),
  prompt: "Explain the difference between supervised and unsupervised learning.",
});

console.log(text);
```

## Web-Grounded Answers

Add the [`web_search`](/docs/agent-api/tools/web-search) tool to ground answers in real-time results from Perplexity's web search — the same search that powers Perplexity's own answer engine.
The provider sends a fixed request body and does not expose the Agent API's built-in tools as first-class options, so enable `web_search` by adding it to the body in the provider's `fetch` hook.

```typescript theme={null}
import { createOpenResponses } from "@ai-sdk/open-responses";
import { generateText } from "ai";

// The provider doesn't surface sources on the result, so capture them in the hook.
let sources = [];

const perplexity = createOpenResponses({
  name: "perplexity",
  url: "https://api.perplexity.ai/v1/responses",
  apiKey: process.env.PERPLEXITY_API_KEY,
  fetch: async (url, options) => {
    const body = JSON.parse(options.body as string);
    // Enable the built-in web_search tool by adding it to the request body.
    body.tools = [{ type: "web_search" }];
    const response = await fetch(url, { ...options, body: JSON.stringify(body) });

    // Sources arrive as a separate `search_results` item in the response `output` array.
    // (Skip for streaming, where the body is an event stream rather than JSON.)
    if (!body.stream) {
      const raw = await response.clone().json();
      sources = raw.output
        .filter((item) => item.type === "search_results")
        .flatMap((item) => item.results); // each: { title, url, snippet, date, ... }
    }

    return response;
  },
});

const { text } = await generateText({
  model: perplexity("openai/gpt-5.6-sol"),
  prompt: "What are the latest breakthroughs in fusion energy this year?",
});

console.log(text);

for (const source of sources) {
  console.log(source.title, source.url);
}
```

The answer is grounded server-side, but `@ai-sdk/open-responses` does not surface the sources on the result — `result.sources` is empty.
That's why the `fetch` hook reads them from the raw `search_results` item in the response `output` array.
See [Reading Sources from the Response](/docs/agent-api/prompt-guide) for the full response shape.

## Presets

[Presets](/docs/agent-api/presets) bundle a model, tools, and a tuned system prompt for a use case, so you don't wire them up yourself.
Set `preset` on the request body in the same `fetch` hook — a preset already includes `web_search`, so you don't add tools separately.

```typescript theme={null}
// In the fetch hook, set a preset instead of adding tools:
body.preset = "fast"; // fast | low | medium | high | xhigh
```

<Tip>
  Presets scale from `fast` (single-fact lookups) to `xhigh` (open-ended, agentic work with code execution in a sandbox).
  See the [presets guide](/docs/agent-api/presets) to pick the right one.
</Tip>

## Streaming

Use `streamText` for token-by-token output.
In a Next.js Route Handler, return `result.toUIMessageStreamResponse()` and render it on the client with `useChat`.

```typescript theme={null}
import { streamText } from "ai";

// Reuse the `perplexity` provider created above.
const result = streamText({
  model: perplexity("openai/gpt-5.6-sol"),
  prompt: "What are the latest breakthroughs in fusion energy this year?",
});

for await (const chunk of result.textStream) {
  process.stdout.write(chunk);
}
```

## Supported Models

Pass any [Agent API model](/docs/agent-api/models) to the provider — OpenAI, Anthropic, Google, xAI, and more — all routed through your single Perplexity key.

```typescript theme={null}
perplexity("openai/gpt-5.6-sol");
perplexity("google/gemini-3-flash-preview");
perplexity("xai/grok-4.5");
```

<Card title="Agent API Models" icon="sparkles" href="/docs/agent-api/models">
  Browse every available model and its pricing.
</Card>

## Links & Resources

<CardGroup>
  <Card title="Open Responses Provider" icon="plug" href="https://ai-sdk.dev/providers/ai-sdk-providers/open-responses">
    Configure the AI SDK provider used on this page.
  </Card>

  <Card title="Agent API Quickstart" icon="bolt" href="/docs/agent-api/quickstart">
    Build with Agent API models, tools, and presets.
  </Card>

  <Card title="Web Search Tool" icon="magnifying-glass" href="/docs/agent-api/tools/web-search">
    Ground answers in Perplexity's real-time web search.
  </Card>

  <Card title="Vercel AI SDK Docs" icon="globe" href="https://ai-sdk.dev/docs">
    Core generation APIs and UI hooks.
  </Card>
</CardGroup>

## Support

Need help with the integration?

* Browse the [Vercel AI SDK documentation](https://ai-sdk.dev/docs)
* Review our [FAQ](/docs/resources/faq)


# Overview
Source: https://docs.perplexity.ai/docs/getting-started/overview

Perplexity API Platform - build with the Router, Agent, Search, and Embeddings APIs. Real-time, web-wide research and Q&A capabilities for your products.

<div>
  <div>
    <div>
      <PerplexityLogo />
    </div>

    <div>
      <span>
        Power your products with unparalleled real-time, web-wide research and Q\&A capabilities.
      </span>
    </div>
  </div>

  <QuickstartBanner />

  <SonarMigrationStrip />

  <UseCaseTabs />

  <div>
    <div>
      <h2>Available APIs</h2>
    </div>

    <div>
      <div>
        <a href="/docs/gateway/quickstart">
          <img alt="Router API" />
        </a>

        <a href="/docs/gateway/quickstart">
          Router API
        </a>

        <p>Unified access to open-weight models hosted by Perplexity through one OpenAI-compatible endpoint.</p>
      </div>

      <div>
        <a href="/docs/agent-api/quickstart">
          <img alt="Agent API" />
        </a>

        <a href="/docs/agent-api/quickstart">
          Agent API
        </a>

        <p>Get web-grounded answers with built-in citations in one call, or access third-party models from OpenAI, Anthropic, Google, and xAI with web search tools and presets.</p>
      </div>

      <div>
        <a href="/docs/search/quickstart">
          <img alt="Search API" />
        </a>

        <a href="/docs/search/quickstart">
          Search API
        </a>

        <p>Get raw, ranked web search results with advanced filtering and real-time data.</p>
      </div>

      <div>
        <a href="/docs/embeddings/quickstart">
          <img alt="Embeddings API" />
        </a>

        <a href="/docs/embeddings/quickstart">
          Embeddings API
        </a>

        <p>Generate high-quality embeddings for semantic search and RAG pipelines.</p>
      </div>
    </div>
  </div>
</div>


# Pricing
Source: https://docs.perplexity.ai/docs/getting-started/pricing



<Info>
  This page shows **pricing information** to help you understand API costs.

  For **billing setup**, payment methods, and usage monitoring, visit the [Admin section](/docs/getting-started/api-groups). For **rate limits**, see the [Rate Limits & Usage Tiers](/docs/admin/rate-limits-usage-tiers) page.
</Info>

## Estimate your cost

<PricingCalculator />

## Router API Pricing

Router API usage is billed per token at each model's published rates — there are no per-request fees. Every model has its own input and output rate, with cache reads billed at the model's discounted cache-read rate and reasoning tokens billed at the output rate. You are always billed at the requested model's rates, regardless of how the request is served.

See [Router Models & Pricing](/docs/gateway/models) for the full per-model rate card, including cache-write rates and long-context pricing.

## Agent API Pricing

The Agent API provides access to third-party models from providers including OpenAI, Anthropic, Google, xAI, Z.AI, Moonshot AI, and NVIDIA with **transparent, token-based pricing** at direct provider rates with no markup.

### Model Pricing

Agent API pricing varies by provider and model, with each provider offering multiple models at different price points.

<Card title="View Complete Third-Party Model Pricing" icon="table" href="/docs/agent-api/models">
  See the full pricing breakdown for all available models from OpenAI, Anthropic, Google, xAI, Z.AI, Moonshot AI, and NVIDIA, including cache rates and provider documentation links on the [Agent API Models page](/docs/agent-api/models).
</Card>

### Tool Pricing

When using tools with the Agent API:

| Tool                 |          Price          | Description                                                                                                                                                                                                                                                                                         |
| -------------------- | :---------------------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`web_search`**     | \$0.0025 per invocation | Performs web searches to retrieve current information                                                                                                                                                                                                                                               |
| **`fetch_url`**      | \$0.0005 per invocation | Fetches and extracts content from specific URLs                                                                                                                                                                                                                                                     |
| **`people_search`**  |  \$0.005 per invocation | Looks up professionals, employees, and people. \$5 per 1,000 tool invocations                                                                                                                                                                                                                       |
| **`finance_search`** |  \$0.005 per invocation | Retrieves financial data and market information. \$5 per 1,000 tool invocations                                                                                                                                                                                                                     |
| **`sandbox`**        |    \$0.03 per session   | Isolated container for executing code during an Agent API request. A session covers up to 20 minutes of active use for billing purposes — this is the billing window, not a runtime cap. SDK search queries made from inside the sandbox are billed at \$0.0025 per request (same as `web_search`). |

<Note>
  Most tool costs are per invocation. `sandbox` is billed per container session — a 20-minute billing window per container, not a runtime cap — plus per SDK search query made from inside it. Tool costs are separate from model token costs.
</Note>

## Search API Pricing

| API            | Price per 1K requests | Description                                    |
| -------------- | :-------------------: | ---------------------------------------------- |
| **Search API** |         \$5.00        | Raw web search results with advanced filtering |

<Note>
  **Billing unit:** Search API charges for each successful `POST /search` request, not for each query in the request. A successful request containing an array of up to five queries is one billing unit. Invalid requests, rate-limited requests, and upstream failures are not billed. A successful response is billed even when it returns no results. There are no additional token-based charges.
</Note>

## Sonar API Pricing

<SonarDeprecationNotice />

<Info>
  **Total cost per query** = Token costs + Request fee (varies by search context size, applies to Sonar, Sonar Pro, and Sonar Reasoning Pro models only)
</Info>

<Tabs>
  <Tab title="Token Pricing">
    ## Token Pricing

    **Token pricing** is based on the number of tokens in your request and response.

    | Model                   | Input Tokens (\$/1M) | Output Tokens (\$/1M) | Citation Tokens (\$/1M) | Search Queries (\$/1K) | Reasoning Tokens (\$/1M) |
    | ----------------------- | :------------------: | :-------------------: | :---------------------: | :--------------------: | :----------------------: |
    | **Sonar**               |          \$1         |          \$1          |            -            |            -           |             -            |
    | **Sonar Pro**           |          \$3         |          \$15         |            -            |            -           |             -            |
    | **Sonar Reasoning Pro** |          \$2         |          \$8          |            -            |            -           |             -            |
    | **Sonar Deep Research** |          \$2         |          \$8          |           \$2           |           \$5          |            \$3           |
  </Tab>

  <Tab title="Request Pricing">
    ## Request Pricing by Search Context Size

    **Search context** determines how much web information is retrieved. Higher context = more comprehensive results. The following table shows the request fee for each model for every **1000 requests**.

    | Model                   | Low Context Size | Medium Context Size | High Context Size |
    | ----------------------- | :--------------: | :-----------------: | :---------------: |
    | **Sonar**               |        \$5       |         \$8         |        \$12       |
    | **Sonar Pro**           |        \$6       |         \$10        |        \$14       |
    | **Sonar Reasoning Pro** |        \$6       |         \$10        |        \$14       |

    <Note>
      * **Low**: (default) fastest, cheapest
      * **Medium**: Balanced cost/quality
      * **High**: Maximum search depth, best for research

      [Learn more about search context →](https://docs.perplexity.ai/docs/sonar/filters#context-size-control)
    </Note>
  </Tab>

  <Tab title="Pro Search Pricing">
    ## Pro Search Pricing (Pro Search for Sonar Pro)

    **Pro Search** enhances Sonar Pro with automated tool usage and multi-step reasoning. When enabled, the model can perform multiple web searches and fetch URL content to answer complex queries. [Learn more about Pro Search here](/docs/sonar/pro-search/quickstart).

    <Info>
      Pro Search requires `stream: true` and is enabled via the `search_type` parameter in `web_search_options`.
    </Info>

    ### Search Type Options

    | Search Type | Description                                        |   Request Fee (per 1K)   |
    | ----------- | -------------------------------------------------- | :----------------------: |
    | **`fast`**  | (default) Standard Sonar Pro behavior              |     \$6 / \$10 / \$14    |
    | **`pro`**   | Multi-step tool usage for complex queries          |    \$14 / \$18 / \$22    |
    | **`auto`**  | Automatic classification based on query complexity | Varies by classification |

    <Note>
      Request fees vary by search context size (Low / Medium / High). Token pricing remains the same as standard Sonar Pro (\$3 per 1M input, \$15 per 1M output).
    </Note>
  </Tab>
</Tabs>

## Embeddings API Pricing

Generate high-quality text embeddings for semantic search, retrieval-augmented generation (RAG), and other machine learning applications.

### Standard Embeddings

| Model                | Dimensions | Price (\$/1M tokens) |
| -------------------- | :--------: | :------------------: |
| `pplx-embed-v1-0.6b` |    1024    |        \$0.004       |
| `pplx-embed-v1-4b`   |    2560    |        \$0.03        |

### Contextualized Embeddings

| Model                        | Dimensions | Price (\$/1M tokens) |
| ---------------------------- | :--------: | :------------------: |
| `pplx-embed-context-v1-0.6b` |    1024    |        \$0.008       |
| `pplx-embed-context-v1-4b`   |    2560    |        \$0.05        |

<Card title="View Embeddings API Documentation" icon="cube" href="/docs/embeddings/quickstart">
  Learn how to use the Embeddings API for semantic search, RAG, and more.
</Card>

<AccordionGroup>
  <Accordion title="Token and Cost Glossary">
    ### Input Tokens

    The number of tokens in your prompt or message to the API. This includes:

    * Your question or instruction
    * Any context or examples you provide
    * System messages and formatting

    **Example:** "What is the weather in New York?" = \~8 input tokens

    ### Output Tokens

    The number of tokens in the API's response. This includes:

    * The generated answer or content
    * Any explanations or additional context
    * Search results and references

    **Example:** "The weather in New York is currently sunny with a temperature of 72°F." = \~15 output tokens

    ### Citation Tokens

    Tokens used specifically for generating search results and references in responses. Only applies to **Sonar Deep Research** model.

    **Example:** Including source links, reference numbers, and bibliographic information

    ### Search Context Size vs Context Window

    **Search context size** is *not* the same as the **context window**.

    * **Search context size**: How much web information is retrieved during search (affects request pricing)
    * **Context window**: Maximum tokens the model can process in one request (affects token limits)

    ### Search Queries

    The number of individual searches conducted by **Sonar Deep Research** during query processing. This is separate from your initial user query.

    * The model automatically determines how many searches are needed
    * You cannot control the exact number of search queries
    * The `reasoning_effort` parameter influences the number of searches performed
    * Only applies to **Sonar Deep Research** model

    ### Reasoning Tokens

    Tokens used for step-by-step logical reasoning and problem-solving. Only applies to **Sonar Deep Research** model.

    **Example:** Breaking down a complex math problem into sequential steps with explanations

    <Info>
      **Token Calculation:** 1 token ≈ 4 characters in English text. The exact count may vary based on language and content complexity.
    </Info>
  </Accordion>
</AccordionGroup>

## Cost Examples

<CardGroup>
  <Card title="Agent API Web Search" icon="calculator">
    **`openai/gpt-5.2`** • 500 input + 200 output tokens • 1 web search

    | Component     | Cost           |
    | ------------- | -------------- |
    | Input tokens  | \$0.000875     |
    | Output tokens | \$0.0028       |
    | `web_search`  | \$0.0025       |
    | **Total**     | **\$0.006175** |
  </Card>

  <Card title="Agent API Research Preset" icon="chart-area-line">
    **`low` preset representative run** • 2,000 input + 1,000 output tokens • 1 web search + 1 fetch

    | Component           | Cost        |
    | ------------------- | ----------- |
    | Model input tokens  | \$0.001     |
    | Model output tokens | \$0.003     |
    | `web_search`        | \$0.0025    |
    | `fetch_url`         | \$0.0005    |
    | **Total**           | **\$0.007** |
  </Card>
</CardGroup>

Actual preset costs vary with the selected model, token usage, and tool invocations. When present on a completed response, `usage.cost.total_cost` reports the calculated request cost.

## Purchase Options

<CardGroup>
  <Card title="Perplexity API Platform on AWS Marketplace" icon="aws" href="/docs/resources/aws-marketplace">
    Purchase API credits through AWS Marketplace with consolidated billing and enterprise procurement.
  </Card>

  <Card title="Contact Sales Team" icon="file-pencil" href="https://perplexity.typeform.com/to/m3WnMaG6">
    Fill out our enterprise inquiry form to discuss custom pricing, dedicated support, and enterprise features for teams and organizations.
  </Card>
</CardGroup>


# Quickstart
Source: https://docs.perplexity.ai/docs/getting-started/quickstart

Generate an API key and make your first call in < 3 minutes.

## Generating an API Key

<Card title="Get your Perplexity API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate a new key on the **API Keys** page in the API Console.
</Card>

<Info>
  See the [API Groups](/docs/getting-started/api-groups) page to learn more about API groups.
</Info>

<Card title="Pricing" icon="receipt" href="/docs/getting-started/pricing">
  Pay-as-you-go pricing for all APIs. No subscription required.
</Card>

## Overview

The Perplexity API provides four core APIs for different use cases: **Router** for direct access to open-weight models through OpenAI- and Anthropic-compatible endpoints, **Agent API** for web-grounded AI responses with access to OpenAI, Anthropic, Google, and xAI models, unified search tools, and transparent pricing, **Search** for ranked web search results, and **Embeddings** for generating text embeddings.

All APIs support both REST and SDK access with streaming, filtering, and advanced controls.

## Available APIs

<CardGroup>
  <Card title="Router" icon="arrows-shuffle" href="/docs/gateway/quickstart">
    Unified access to open-weight models hosted by Perplexity through one endpoint.
  </Card>

  <Card title="Agent API" icon="code-circle" href="/docs/agent-api/quickstart">
    Web-grounded answers with built-in citations, plus multi-provider models (OpenAI, Anthropic, Google, xAI), presets, and web search tools.
  </Card>

  <Card title="Search" icon="search" href="/docs/search/quickstart">
    Ranked web search results with filtering, multi-query support, and domain controls.
  </Card>

  <Card title="Embeddings" icon="cube" href="/docs/embeddings/quickstart">
    Generate high-quality text embeddings for semantic search and RAG.
  </Card>
</CardGroup>

## Choosing the Right API

<AccordionGroup>
  <Accordion title="Use the Router API when..." icon="arrows-shuffle">
    * You want **one API for open-weight models** — models hosted by Perplexity with a single endpoint and key
    * You have **existing OpenAI or Anthropic SDK code** — switching is a base-URL change
    * You want **routing and failover handled automatically** instead of building it yourself

    **Best for:** Model-agnostic products, multi-model workloads, consolidating per-provider accounts
  </Accordion>

  <Accordion title="Use the Agent API when..." icon="code-circle">
    * You want **web-grounded answers with built-in citations** - send a message and get a researched, cited response, with conversation context when you need it
    * You prefer **simplicity**: pick a [preset](/docs/agent-api/presets) and get a researched answer in one call, or take **granular control** over model, reasoning, token budgets, and tools
    * You need **multi-provider access** to OpenAI, Anthropic, Google, xAI, and Perplexity's own Sonar model through one API

    **Best for:** AI assistants, research and Q\&A tools, agentic workflows, custom AI applications
  </Accordion>

  <Accordion title="Use the Search API when..." icon="search">
    * You need **raw search results** without LLM processing
    * You want to **build custom AI workflows** with your own models
    * You need **search data** for indexing, analysis, or training

    **Best for:** Custom AI pipelines, data collection, search integration
  </Accordion>

  <Accordion title="Use the Embeddings API when..." icon="cube">
    * You need **semantic similarity** between texts for search or recommendations
    * You're building **RAG pipelines** that require vector representations of documents
    * You need to **cluster, classify, or compare** text without generating a response

    **Best for:** Semantic search, RAG applications, text classification, recommendation systems
  </Accordion>
</AccordionGroup>

## Installation

Install the SDK for your preferred language:

<CodeGroup>
  ```bash Python theme={null}
  pip install perplexityai
  ```

  ```bash Typescript theme={null}
  npm install @perplexity-ai/perplexity_ai
  ```
</CodeGroup>

## Authentication

Set your API key as an environment variable:

<Tabs>
  <Tab title="macOS/Linux">
    ```bash theme={null}
    export PERPLEXITY_API_KEY="your_api_key_here"
    ```
  </Tab>

  <Tab title="Windows">
    ```powershell theme={null}
    setx PERPLEXITY_API_KEY "your_api_key_here"
    ```
  </Tab>
</Tabs>

<Note>
  **OpenAI SDK Compatible:** Perplexity's API supports the OpenAI Chat Completions format. You can use OpenAI client libraries by pointing to our endpoint. See the [OpenAI Compatibility Guide](/docs/agent-api/openai-compatibility) for examples.
</Note>

## Making Your First API Call

Choose your API based on your use case:

<Tabs>
  <Tab title="Router API">
    Use for direct access to open-weight models with the OpenAI SDK:

    <CodeGroup>
      ```python Python theme={null}
      from openai import OpenAI
      import os

      # Point the OpenAI SDK at the Router base URL
      client = OpenAI(
          api_key=os.environ.get("PERPLEXITY_API_KEY"),
          base_url="https://api.perplexity.ai/router/v1"
      )

      # Make the API call with any model from the Router catalog
      response = client.chat.completions.create(
          model="perplexity/kimi-k3",
          max_tokens=1024,
          messages=[
              {"role": "user", "content": "Summarize the key trade-offs between vector and keyword search."}
          ]
      )

      print(response.choices[0].message.content)
      ```

      ```typescript TypeScript theme={null}
      import OpenAI from 'openai';

      // Point the OpenAI SDK at the Router base URL
      const client = new OpenAI({
          apiKey: process.env.PERPLEXITY_API_KEY,
          baseURL: "https://api.perplexity.ai/router/v1"
      });

      // Make the API call with any model from the Router catalog
      const response = await client.chat.completions.create({
          model: "perplexity/kimi-k3",
          max_tokens: 1024,
          messages: [
              { role: "user", content: "Summarize the key trade-offs between vector and keyword search." }
          ]
      });

      console.log(response.choices[0].message.content);
      ```

      ```bash cURL theme={null}
      curl -X POST 'https://api.perplexity.ai/router/v1/chat/completions' \
        -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "perplexity/kimi-k3",
          "max_tokens": 1024,
          "messages": [
            {"role": "user", "content": "Summarize the key trade-offs between vector and keyword search."}
          ]
        }' | jq
      ```
    </CodeGroup>

    <Accordion title="Example Response">
      The response uses the OpenAI Chat Completions format and echoes the model id you requested:

      ```json theme={null}
      {
        "id": "chatcmpl-Xr7aQ2mVb9L4tW8pDcEfGh1JkNs0y",
        "object": "chat.completion",
        "created": 1753747200,
        "model": "perplexity/kimi-k3",
        "choices": [
          {
            "index": 0,
            "message": {
              "role": "assistant",
              "content": "Vector search captures semantic similarity, finding relevant results even when wording differs, but requires embedding infrastructure and can miss exact terms. Keyword search is fast, cheap, and precise for exact matches, but brittle for synonyms and phrasing variation. Most production systems combine both in a hybrid setup.",
              "annotations": []
            },
            "logprobs": null,
            "finish_reason": "stop"
          }
        ],
        "usage": {
          "prompt_tokens": 21,
          "completion_tokens": 64,
          "total_tokens": 85,
          "prompt_tokens_details": {
            "cached_tokens": 0
          }
        }
      }
      ```
    </Accordion>
  </Tab>

  <Tab title="Agent API">
    Use for third-party models with web search tools and presets:

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      # Initialize the client (uses PERPLEXITY_API_KEY environment variable)
      client = Perplexity()

      # Make the API call with a preset
      response = client.responses.create(
          preset="low",
          input="Summarize the core findings of the original 'Attention Is All You Need' transformer paper and explain why it changed NLP.",
      )

      # Print the AI's response
      print(response.output_text)
      ```

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

      // Initialize the client (uses PERPLEXITY_API_KEY environment variable)
      const client = new Perplexity();

      // Make the API call with a preset
      const response = await client.responses.create({
          preset: "low",
          input: "Summarize the core findings of the original 'Attention Is All You Need' transformer paper and explain why it changed NLP.",
      });

      // Print the AI's response
      console.log(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": "low",
          "input": "Summarize the core findings of the original \u0027Attention Is All You Need\u0027 transformer paper and explain why it changed NLP."
        }' | jq
      ```
    </CodeGroup>

    <Accordion title="Example Response">
      The response includes structured output with tool usage and citations:

      ```json theme={null}
      {
        "background": false,
        "completed_at": 1756485272,
        "created_at": 1756485272,
        "error": null,
        "frequency_penalty": 0,
        "id": "resp_1234567890",
        "incomplete_details": null,
        "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to...",
        "max_output_tokens": null,
        "max_tool_calls": null,
        "metadata": {},
        "model": "openai/gpt-5.1",
        "object": "response",
        "output": [
          {
            "type": "message",
            "id": "msg_abc123",
            "role": "assistant",
            "status": "completed",
            "content": [
              {
                "type": "output_text",
                "text": "Recent developments in AI include...",
                "annotations": [
                  {
                    "type": "citation",
                    "url": "https://example.com/article1"
                  }
                ],
                "logprobs": []
              }
            ]
          }
        ],
        "parallel_tool_calls": true,
        "presence_penalty": 0,
        "previous_response_id": null,
        "prompt_cache_key": null,
        "reasoning": null,
        "safety_identifier": null,
        "service_tier": "default",
        "status": "completed",
        "store": true,
        "temperature": 1,
        "text": {
          "format": {
            "type": "text"
          }
        },
        "tool_choice": "auto",
        "tools": [
          {
            "type": "web_search"
          },
          {
            "type": "fetch_url"
          }
        ],
        "top_logprobs": 0,
        "top_p": 1,
        "truncation": "disabled",
        "usage": {
          "cost": {
            "currency": "USD",
            "input_cost": 0.0046,
            "output_cost": 0.0078,
            "tool_calls_cost": 0.0025,
            "total_cost": 0.0149
          },
          "input_tokens": 3681,
          "input_tokens_details": {
            "cached_tokens": 0
          },
          "output_tokens": 780,
          "output_tokens_details": {
            "reasoning_tokens": 0
          },
          "tool_calls_details": {
            "search_web": {
              "invocation": 1
            }
          },
          "total_tokens": 4461
        },
        "user": null
      }
      ```
    </Accordion>
  </Tab>

  <Tab title="Search API">
    Use for ranked web search results without LLM processing:

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      # Initialize the client (uses PERPLEXITY_API_KEY environment variable)
      client = Perplexity()

      # Make the API call
      search = client.search.create(
          query="SpaceX Starship architecture and orbital test milestones",
          max_results=5
      )

      # Print the search results
      for result in search.results:
          print(f"{result.title}: {result.url}")
      ```

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

      // Initialize the client (uses PERPLEXITY_API_KEY environment variable)
      const client = new Perplexity();

      // Make the API call
      const search = await client.search.create({
          query: "SpaceX Starship architecture and orbital test milestones",
          max_results: 5
      });

      // Print the search results
      for (const result of search.results) {
          console.log(`${result.title}: ${result.url}`);
      }
      ```

      ```bash cURL theme={null}
      curl -X POST 'https://api.perplexity.ai/search' \
        -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "query": "SpaceX Starship architecture and orbital test milestones",
          "max_results": 5
        }' | jq
      ```
    </CodeGroup>

    <Accordion title="Example Response">
      The response includes ranked search results with titles, URLs, and snippets:

      ```json theme={null}
      {
        "results": [
          {
            "title": "SpaceX Starship Flight 10: Full Mission Recap",
            "url": "https://example.com/starship-flight-10",
            "snippet": "SpaceX successfully completed its tenth Starship test flight, achieving full booster recovery and orbital insertion...",
            "date": "2026-02-20",
            "last_updated": "2026-02-21"
          },
          {
            "title": "Starship Launch Manifest: 2026 Schedule and Updates",
            "url": "https://example.com/starship-2026-schedule",
            "snippet": "SpaceX has announced an ambitious 2026 launch manifest for Starship, targeting monthly flights and the first cargo mission...",
            "date": "2026-01-15",
            "last_updated": "2026-03-01"
          }
        ],
        "query_info": {
          "query": "SpaceX Starship architecture and orbital test milestones",
          "normalized_query": "spacex starship launch updates 2026"
        }
      }
      ```
    </Accordion>
  </Tab>
</Tabs>

<AccordionGroup>
  <Accordion title="Response — Summarize the core findings of the original 'Attention Is All You Need' transformer pap...">
    ```json theme={null}
    {
      "id": "resp_e80c520d-2788-4b3d-8662-6a0e3d611e8f",
      "created_at": 1779391438,
      "model": "openai/gpt-5.1",
      "object": "response",
      "output": [
        {
          "results": [
            {
              "id": 1,
              "snippet": "Abstract:The dominant sequence transduction models are based on complex recurrent or convolutional neural networks in an encoder-decoder configuration.\nThe best performing models also connect the encoder and decoder through an attention mechanism.\nWe propose a new simple network architecture, the Transformer, based solely on attention mechanisms, dispensing with recurrence and convolutions entirely.\nExperiments on two machine translation tasks show these models to be superior in quality while being more parallelizable and requiring significantly less time to train.\nOur model achieves 28.4 BLEU on the WMT 2014 English-to-German translation task, improving over the existing best results, including ensembles by over 2 BLEU.\nOn the WMT 2014 English-to-French translation task, our model establishes a new single-model state-of-the-art BLEU score of 41.8 after training for 3.5 days on eight GPUs, a small fraction of the training costs of the best models from the literature.\nWe show that the Transformer generalizes well to other tasks by applying it successfully to English constituency parsing both with large and limited training data.",
              "title": "[1706.03762] Attention Is All You Need - arXiv",
              "url": "https://arxiv.org/abs/1706.03762",
              "date": "2017-06-12",
              "last_updated": "2026-05-19",
              "source": "web"
            },
            {
              "id": 2,
              "snippet": "At each layer, each token is then contextualized within the scope of the context window with other (unmasked) tokens via a parallel multi-head attention mechanism, allowing the signal for key tokens to be amplified and less important tokens to be diminished.\n...\nThe original version of the transformer architecture was proposed in the 2017 paper \"Attention Is All You Need\" by researchers at Google.\nThe predecessors of transformers were developed as an improvement over previous architectures for machine translation, but have found many applications since.\n...\nOn 2017-06-12, the original (100M-parameter) encoder–decoder transformer model was published in the \"Attention is all you need\" paper.\nAt the time, the focus of the research was on improving seq2seq for machine translation, by removing its recurrence to process all tokens in parallel, but preserving its dot-product attention mechanism to keep its text processing performance.\nThis led to the introduction of a multi-head attention model that was easier to parallelize due to the use of independent heads and the lack of recurrence.\nIts parallelizability was an important factor to its widespread use in large neural networks.",
              "title": "Transformer (deep learning) - Wikipedia",
              "url": "https://en.wikipedia.org/wiki/Transformer_(deep_learning)",
              "date": "2019-08-25",
              "last_updated": "2026-05-15",
              "source": "web"
            },
            {
              "id": 3,
              "snippet": "We propose a novel, simple network architecture based solely onan attention mechanism, dispensing with recurrence and convolutions entirely.Experiments on two machine translation tasks show these models to be superiorin quality while being more parallelizable and requiring significantly less timeto train.",
              "title": "Attention is All you Need - NIPS papers",
              "url": "https://papers.nips.cc/paper/7181-attention-is-all-you-need",
              "date": "2017-01-01",
              "last_updated": "2026-05-21",
              "source": "web"
            },
            {
              "id": 4,
              "snippet": "The paper introduced a new deep learning architecture known as the transformer, based on the attention mechanism proposed in 2014 by Bahdanau *et al.* The transformer approach it describes has become the main architecture of a wide variety of artificial intelligence, including large language models.\nAt the time, the focus of the research was on improving Seq2seq techniques for machine translation, but the authors go further in the paper, foreseeing the technique's potential for other tasks like question answering and what is now known as multimodal generative AI.\n...\nThe paper is best known for introducing the Transformer architecture, which underlies most modern large language models (LLMs).\nA key reason why the architecture is preferred by most modern LLMs is the parallelizability of the architecture over its predecessors.\nThis ensures that the operations necessary for training can be accelerated on a GPU, allowing both faster training times and models of bigger sizes to be trained.\n...\nOn 2017-06-12, the original (100M-parameter) encoder–decoder transformer model was published in the \"Attention is all you need\" paper.",
              "title": "Attention Is All You Need - Wikipedia",
              "url": "https://en.wikipedia.org/wiki/Attention_Is_All_You_Need",
              "date": "2023-12-04",
              "last_updated": "2026-05-17",
              "source": "web"
            },
            {
              "id": 5,
              "snippet": "In this video, YC's Ankit Gupta traces how AI learned to understand language — from early RNNs and LSTMs to attention mechanisms and the breakthrough 2017 paper Attention Is All You Need — the discovery that unlocked the modern AI era.\n...\n{ts:17} [Music] A transformer is a neural network that uses self attention to take input data\n{ts:26} like text or images, model the relationships between that data, and finally generate outputs like meaningful\n{ts:32} text responses, translations, or classifications.\n...\nThen came the big breakthrough in 2017 when a team of researchers at\n{ts:387} Google published a paper called attention is all you need, which proposed a new machine translation\n{ts:392} architecture that they called a transformer.\n...\n{ts:409} version of the encoder decoder architecture originally proposed in seek to seek.\nInstead of compressing inputs\n{ts:414} into a single vector embedding, transformers kept separate embeddings for each input token and updated these\n{ts:420} through self attention, a mechanism that updated token representations based on a learned weighted dotproduct over the\n{ts:426} embeddings of all other tokens in the sequence.\nBecause each token in this architecture could attend to all others\n{ts:431} simultaneously, transformers could process an entire sequence in parallel, making them dramatically faster than\n{ts:437} RNN's.\nRemarkably, they were also much more accurate on machine translation benchmarks.",
              "title": "Transformers Explained: The Discovery That Changed AI Forever",
              "url": "https://www.youtube.com/watch?v=JZLZQVmfGn8&vl=en-US",
              "date": "2025-10-23",
              "last_updated": "2026-03-27",
              "source": "web"
            },
            {
              "id": 6,
              "snippet": "●Presents a new neural architecture named the Transformer\n●Based solely on the attention mechanism widely used in SEQ2SEQ models\n●More parallelizable compared to existing state-of-the-art (SOTA) models\n●Achieves SOTA in 2 machine translation datasets\n…\n...\n• Less total computational complexity per layer\n• More parallelizable than existing fully autoregressive models\n• Shorten the path between tokens to enable model to learn long-term \ndependency better\n...\nIntroduces a groundbreaking new model that is solely based on attention\n●\nFaster and better than existing models\n●",
              "title": "[PDF] Attention Is All You Need",
              "url": "https://ysu1989.github.io/courses/au20/cse5539/Transformer.pdf",
              "date": null,
              "last_updated": "2026-05-15",
              "source": "web"
            },
            {
              "id": 7,
              "snippet": "The Transformer architecture has revolutionized natural language processing (NLP) since its introduction, establishing itself as a cornerstone for modern advancements in the field.\nThis architecture offers significant improvements in handling a wide range of NLP tasks, from translation to text summarization, by overcoming limitations inherent in previous models.\nIntroduced by Vaswani et al. in the paper “Attention is All You Need” in 2017, the Transformer architecture is characterized by its use of self-attention mechanisms and feed-forward neural networks.\nUnlike its predecessors, such as recurrent neural networks (RNNs) and long short-term memory networks (LSTMs), which process data sequentially, the Transformer processes input data in parallel.\nThis parallelization enables the model to leverage modern hardware more efficiently, resulting in faster training times and improved scalability.\nAt the heart of the Transformer is the self-attention mechanism, which allows the model to weigh the significance of different words in a sentence relative to each other.\nThis feature is critical for understanding contextual relationships and dependencies, regardless of the distance between words in the input sequence.\n...\nThis capacity to capture global dependencies without the constraints of sequential data processing is a notable advantage over traditional models.\n...\nThe Transformer architecture’s flexibility makes it suitable for a broad spectrum of NLP applications.\nIn machine translation, it has significantly improved the accuracy and fluency of translated text.\nFor tasks like text summarization, sentiment analysis, and question answering, Transformers provide state-of-the-art results by effectively capturing and modeling complex language patterns.\n...\nIn summary, the Transformer architecture has fundamentally changed the landscape of NLP by introducing a novel approach to processing and understanding language data.\nIts innovative use of self-attention and parallel processing has paved the way for numerous breakthroughs, making it an essential tool for anyone looking to advance in the field of natural language processing.",
              "title": "What is the Transformer architecture in NLP? - Milvus",
              "url": "https://milvus.io/ai-quick-reference/what-is-the-transformer-architecture-in-nlp",
              "date": "2026-03-26",
              "last_updated": "2026-05-13",
              "source": "web"
            },
            {
              "id": 8,
              "snippet": "In “Attention Is All You Need”, we introduce the Transformer, a novel neural network architecture based on a self-attention mechanism that we believe to be particularly well suited for language understanding.\nIn our paper, we show that the Transformer outperforms both recurrent and convolutional models on academic English to German and English to French translation benchmarks.\nOn top of higher translation quality, the Transformer requires less computation to train and is a much better fit for modern machine learning hardware, speeding up training by up to an order of magnitude.\n...\nIn contrast, the Transformer only performs a small, constant number of steps (chosen empirically).\nIn each step, it applies a self-attention mechanism which directly models relationships between all words in a sentence, regardless of their respective position.",
              "title": "Transformer: A Novel Neural Network Architecture for Language ...",
              "url": "https://research.google/blog/transformer-a-novel-neural-network-architecture-for-language-understanding/",
              "date": null,
              "last_updated": "2026-05-17",
              "source": "web"
            },
            {
              "id": 9,
              "snippet": "A new simple network architecture, the Transformer, based solely on attention mechanisms, dispensing with recurrence and convolutions entirely is proposed, which generalizes well to other tasks by applying it successfully to English constituency parsing both with large and limited training data.",
              "title": "[PDF] Attention is All you Need | Semantic Scholar",
              "url": "https://www.semanticscholar.org/paper/Attention-is-All-you-Need-Vaswani-Shazeer/204e3073870fae3d05bcbc2f6a8e263d9b72e776",
              "date": "2017-06-12",
              "last_updated": "2025-03-22",
              "source": "web"
            },
            {
              "id": 10,
              "snippet": "Abstract:Natural Language Processing (NLP) has witnessed a transformative leap with the advent of transformer-based architectures, which have significantly enhanced the ability of machines to understand and generate human-like text.\nThis paper explores the advancements in transformer models, such as BERT and GPT, focusing on their superior performance in text understanding tasks compared to traditional methods like recurrent neural networks (RNNs).\nBy analyzing statistical properties through visual representations-including probability density functions of text length distributions and feature space classifications-the study highlights the models' proficiency in handling long-range dependencies, adapting to conditional shifts, and extracting features for classification, even with overlapping classes.\nDrawing on recent 2024 research, including enhancements in multi-hop knowledge graph reasoning and context-aware chat interactions, the paper outlines a methodology involving data preparation, model selection, pretraining, fine-tuning, and evaluation.\nThe results demonstrate state-of-the-art performance on benchmarks like GLUE and SQuAD, with F1 scores exceeding 90%, though challenges such as high computational costs persist.\nThis work underscores the pivotal role of transformers in modern NLP and suggests future directions, including efficiency optimization and multimodal integration, to further advance language-based AI systems.",
              "title": "Exploring Transformer-Based Architectures for Text Understanding",
              "url": "https://arxiv.org/abs/2503.20227",
              "date": "2025-03-26",
              "last_updated": "2026-02-21",
              "source": "web"
            }
          ],
          "type": "search_results",
          "queries": [
            "Attention Is All You Need transformer paper core contributions",
            "why transformer architecture changed NLP",
            "Vaswani et al 2017 attention is all you need key results"
          ]
        },
        {
          "id": "msg_b9dc751b-50fd-4941-ad3d-00bb2eb98f73",
          "content": [
            {
              "text": "The paper “Attention Is All You Need” introduced the **Transformer**, a sequence‑to‑sequence model built entirely from attention and feed‑forward layers, and showed it could beat recurrent and convolutional models on machine translation while training much faster and scaling better.[web:1][web:8] This architectural shift made self‑attention the default building block for modern NLP and enabled today’s large language models.[web:2][web:4][web:7]\n\n## Core technical ideas\n\n- The Transformer removes recurrence and convolutions, using stacked self‑attention and position‑wise feed‑forward layers in both encoder and decoder.[web:1][web:3] Positional encodings are added to token embeddings so the model can represent order despite having no recurrence.[web:1]  \n- It introduces **multi‑head** attention: several parallel attention heads project queries/keys/values, attend in different subspaces, then concatenate and linearly mix their outputs.[web:1][web:2] This lets the model capture different types of relations (e.g., syntax and coreference) in parallel.[web:1]  \n- The paper emphasizes three attention types within the architecture: encoder self‑attention, decoder masked self‑attention (preventing access to future tokens), and encoder‑decoder attention where the decoder attends over encoder outputs.[web:1][web:8]\n\n## Empirical results in the paper\n\n- On WMT 2014 English→German translation, the base Transformer reaches 28.4 BLEU, surpassing prior state of the art, including ensembles, by over 2 BLEU.[web:1][web:3] On WMT 2014 English→French, a single Transformer achieves 41.8 BLEU after 3.5 days of training on 8 GPUs, outperforming earlier, much more expensive systems.[web:1]  \n- The authors also show the model generalizes beyond translation by achieving strong results on English constituency parsing, even with limited labeled data.[web:1][web:9] These results demonstrate that attention‑only architectures are not just viable but competitive across sequence tasks.[web:1]\n\n## Why it was faster and more scalable\n\n- Self‑attention lets the model process all tokens in a sequence in parallel, unlike RNNs/LSTMs that must step through tokens sequentially, which makes it far more compatible with GPU/TPU hardware.[web:1][web:7] This parallelism reduced training time “by up to an order of magnitude” relative to recurrent models on the same tasks.[web:8]  \n- For typical sequence lengths, the attention‑based layers in the paper have lower or comparable per‑layer computational complexity than recurrent or convolutional alternatives and much shorter paths between distant tokens, which helps learn long‑range dependencies.[web:1][web:6] This combination of efficiency and representational power is what made large‑scale pretraining feasible.[web:7][web:10]\n\n## How it changed NLP\n\n- The Transformer architecture became the foundation for major pretrained models such as BERT (encoder‑only), GPT (decoder‑only), and many others, which now dominate benchmarks in translation, question answering, summarization, and general language modeling.[web:2][web:7][web:10] These models exploit the same self‑attention blocks introduced in the 2017 paper, often with minor variants.[web:2]  \n- By showing that attention‑only, highly parallel architectures can outperform traditional sequence models, the paper shifted the field’s default design pattern from RNNs/CNNs to transformers and opened the path to scaling parameters and data to today’s very large language models.[web:2][web:4][web:7] Its influence now extends beyond NLP to vision, speech, and multimodal models that reuse the same core transformer building blocks.[web:2][web:4]",
              "type": "output_text",
              "annotations": [],
              "logprobs": []
            }
          ],
          "role": "assistant",
          "status": "completed",
          "type": "message"
        }
      ],
      "status": "completed",
      "error": null,
      "usage": {
        "input_tokens": 6620,
        "output_tokens": 863,
        "total_tokens": 7483,
        "cost": {
          "currency": "USD",
          "input_cost": 0.0038,
          "output_cost": 0.00863,
          "total_cost": 0.01538,
          "cache_creation_cost": null,
          "cache_read_cost": 0.00045,
          "tool_calls_cost": 0.0025
        },
        "input_tokens_details": {
          "cache_creation_input_tokens": 0,
          "cache_read_input_tokens": 3584,
          "cached_tokens": 3584
        },
        "tool_calls_details": {
          "search_web": {
            "invocation": 1
          }
        },
        "output_tokens_details": {
          "reasoning_tokens": 0
        }
      },
      "background": false,
      "completed_at": 1779391438,
      "frequency_penalty": 0,
      "incomplete_details": null,
      "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
      "max_output_tokens": 8192,
      "max_tool_calls": null,
      "metadata": {},
      "parallel_tool_calls": true,
      "presence_penalty": 0,
      "previous_response_id": null,
      "prompt_cache_key": null,
      "reasoning": null,
      "safety_identifier": null,
      "service_tier": "default",
      "store": true,
      "temperature": 1,
      "text": {
        "format": {
          "type": "text"
        }
      },
      "tool_choice": "auto",
      "tools": [
        {
          "type": "web_search"
        },
        {
          "type": "fetch_url"
        }
      ],
      "top_logprobs": 0,
      "top_p": 1,
      "truncation": "disabled",
      "user": null
    }
    ```
  </Accordion>

  <Accordion title="Response — SpaceX Starship architecture and orbital test milestones">
    ```json theme={null}
    {
      "id": "3dbbb4d2-8102-47e7-8457-402f9f83c4df",
      "results": [
        {
          "snippet": "",
          "title": "SpaceX Starship - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/SpaceX_Starship",
          "date": "2018-11-21",
          "last_updated": "2026-05-19"
        },
        {
          "snippet": "",
          "title": "Starship flight test 1 - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/Starship_flight_test_1",
          "date": "2022-05-28",
          "last_updated": "2026-05-13"
        },
        {
          "snippet": "",
          "title": "SpaceX Starship (spacecraft) - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/SpaceX_Starship_(spacecraft)",
          "date": "2023-04-29",
          "last_updated": "2026-04-05"
        },
        {
          "snippet": "On June 19, a Starship prototype exploded on the launch pad at SpaceX’s Starbase facility in Texas during preparations for what would be its tenth test flight.\nAfter three consecutive failed orbital attempts this year, the upcoming launch is shaping up to be a pivotal moment in Elon Musk’s vision to send humans to Mars and beyond.\nSince its first orbital test flight in April 2023, Starship has made notable progress but has also suffered high-profile setbacks, keeping the project under close scrutiny.\nTo date, Starship has completed nine orbital test flights, following a series of ground-based trials.\nCurrent tests are focused on demonstrating the rocket’s ability to recover its booster, reach target altitudes, deploy payloads and execute controlled landings.\nAll these goals are key to making the vehicle reusable.\n...\n### Every Starship prototype built and tested to date:\n**April 3, 2019:** The Starhopper prototype climbed one foot in a tethered test hop.\n**April 5, 2019:** Starhopper rose three feet in a tethered hop, using the full length of the tether.\n**July 25, 2019:** Starhopper jumped to 65 feet (20 meters) in an untethered test flight.\n**Aug. 27, 2019:** Starhopper flew even higher, reaching 500 feet (150 meters), slewing sideways before descending slowly to a nearby landing pad.\n**Nov. 20, 2019:** A larger prototype, Mk1, was built but blew its top off during a cryogenic proof test (also known as a pressure stress test), rendering it unusable for flight.\n**May 29, 2020:** After earlier prototypes SN1 and SN3 exploded during ground tests, SpaceX found success with SN4, which completed five static fire tests before exploding during the final one.\n**Aug. 5, 2020:** SN5 successfully performed a 500-foot (150-meter) flight and landed on a nearby pad.\n**Sept. 3, 2020:** SN6 completed another 500-foot test flight.\n**Dec. 9, 2020:** SN8, the first prototype with fins and a nose cone, was designed to reach higher altitudes.\nIt ascended to 7.8 miles (12.5 kilometers) but descended too fast and exploded upon landing.\n**Feb. 2, 2021:** SN9 flew to 6 miles (10 kilometers) but crashed on landing after one engine failed to ignite.\n**March 3, 2021:** SN10 nearly completed a 6-mile flight but crushed its landing legs, causing it to tip and explode minutes after touchdown.\n**March 30, 2021:** SN11 successfully reached 6 miles but exploded mid-air during descent.\n(SpaceX skipped SN12, SN13, and SN14.)\n**May 5, 2021:** SN15 successfully completed a high-altitude flight and landed intact.\n**Nov. 18, 2023:** The second orbital test flight reached 93 miles (150 kilometers) and became the first Starship to reach outer space, but it exploded before completing its mission.\n**March 14, 2024:** The third orbital test flight reached approximately 1,515 feet (462 meters) before destructing ahead of a planned splashdown.\n**June 6, 2024:** The fourth orbital flight achieved a full ascent burn and completed a landing burn, concluding with a gentle splashdown in the Gulf of Mexico.\n**Oct. 13, 2024:** The fifth orbital flight marked the first successful booster recovery, with the booster returning to the launch tower.\nThe flight completed its mission with no engine failures and ended in a planned splashdown in the Indian Ocean.\n**Nov. 19, 2024:** During the sixth orbital test, the booster latched onto the catch tower but had to divert for a splashdown in the Gulf of Mexico.\nThe ship ignited one of its six engines in space, successfully reentered the atmosphere, and splashed down in the Indian Ocean.\n**Jan. 16, 2025:** The seventh orbital test launched successfully with all six engines ignited, but a fire eight minutes in caused the rocket to explode.\n**March 6, 2025:** The ship lost several engines during ascent, leading to a loss of altitude control and communication.\nIt diverted into a controlled area to prevent debris from falling into public spaces.\n**May 27, 2025:** The ninth orbital test flight marked the first reuse of a Super Heavy booster.\nHowever, the booster exploded unexpectedly, and the ship lost an engine due to a fuel leak.\nAfter abandoning its payload deployment attempt, Starship exploded over the Indian Ocean when it failed to properly reposition for reentry.",
          "title": "From Hops to Orbit: A Fiery History of SpaceX's Starship Program",
          "url": "https://observer.com/2025/07/spacex-starship-test-timeline/",
          "date": "2025-07-23",
          "last_updated": "2026-05-12"
        },
        {
          "snippet": "",
          "title": "SpaceX Starship design history - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/SpaceX_Starship_design_history",
          "date": "2023-11-14",
          "last_updated": "2026-04-29"
        },
        {
          "snippet": "SpaceX's Starship program, which boasts the world's tallest and most powerful rocket, will eventually put people and cargo on Mars.\nThe latest prototype, SN20, is waiting for the chance to go into orbit.\nSeveral other prototypes have made flights, ground tests and sometimes even testing mistakes in the effort to improve future flights.\nHere's an overview of key milestones on Starship's road to the Red Planet.\n...\nMusk rebranded his Mars-colonizing spaceflight system as Starship in 2018.\n\"Technically, two parts: Starship is the spaceship/upper stage & Super Heavy is the rocket booster needed to escape Earth's deep gravity well (not needed for other planets or moons),\" Musk said in a 2018 tweet.\n...\nAt first, Musk planned to make Starship out of carbon fiber, but in January 2019, he announced that the craft would be built from stainless steel instead, Space.com reported.\n...\nMusk chose to put six Raptor engines on the Starship vehicle instead of seven.\nHe also changed the number of Raptors on the Super Heavy, initially dropping the number from 35 to 31 and then increasing it again to include up to 37 Raptors.\n(Not all engines will be needed on each flight, but at least 24 Raptors are required to carry the huge craft into space, Musk has said.)\n...\nStarhopper was a low-altitude prototype of the Starship system that looked more like a flying tank than an aerodynamic rocket.\nSpaceX did two \"static fire\" tests of the system at its facility in Boca Chica, Texas, to evaluate the performance of the engine in 2019, and then followed that up with four short test flights that same year.\n...\nOn the first free flight, on July 25, 2019, the prototype soared to an expected altitude of 65 feet (20 m).\nIts last flight before retiring on Aug. 27, 2019, was expected to go as high as 500 feet (150 m), in line with a limit imposed by the U.S. Federal Aviation Administration (FAA).\n...\nStarship's program tested several ground prototypes before attempting flight.\nThe list of major prototypes in 2019 to 2020 included MK1 (destroyed during a tank pressure test), MK2 (abandoned for a newer design), MK3/SN1 (destroyed during a pressurization test), SN2 (pressure tested successfully), SN3 (destroyed during a test of its pressure tank) and SN4 (destroyed during a static fire test, following several successful tests).\nStarship's SN5 and SN6 prototypes conducted low-altitude test hops.\nSN5 reached an altitude of about 500 feet on Aug. 4, 2020, and moved sideways in the sky to reach its landing area.\nSN6 also made a 500-foot jaunt on Sept. 3, 2020.\n...\nSpaceX deliberately destroyed SN7 during a ground test to gather data for future flights.\nSN8, which took to the air on Dec. 23, 2020, performed complex aerial maneuvers and flips during the program's first high-altitude launch.\nIt flew to 7.8 miles (12.5 kilometers) but failed to stick the landing, according to a video shot from the landing pad that showed it exploding in a fireball on the ground due to lower-than-expected pressure in the fuel tank header.\n...\nIn a quick sequence in February and March 2021, the Starship program sent aloft three more prototypes on high-altitude flights: SN9, SN10 and SN11.\nThe vehicles flew for about 6 minutes each, but all three experienced technical problems during landing that resulted in fiery crashes or after-touchdown explosions.\n...\nSpaceX's Starship SN15 prototype stuck the landing on the 60th anniversary of the United States' first-ever crewed spaceflight, when astronaut Alan Shepard blasted into space aboard NASA's Mercury capsule.\nOn May 5, 2021, SN15 soared 6.2 miles (10 km) into the sky and made several maneuvers in midair.\nSix minutes after takeoff, the prototype made a safe touchdown on a concrete landing pad at Boca Chica.\nAs of August 2021, this was the latest flight for the Starship program.\n...\n\"SN15 has vehicle improvements across structures, avionics and software, and the engines that will allow more speed and efficiency throughout production and flight: specifically, a new enhanced avionics suite, updated propellant architecture in the aft skirt and a new Raptor engine design and configuration.\"\n...\nSpaceX's newest Starship prototype briefly stood atop a Super Heavy rocket booster for the first time on Aug. 6, 2021, marking the tallest-ever rocket ever built.\n\"Dream come true,\" Musk wrote on Twitter of the stacked Starship.\nThe stacking test at Boca Chica included mating the two vehicles for an hour, with the joined Starship system standing 395 feet (120 m).\nFor comparison, NASA's massive Saturn V moon rocket, used for the Apollo missions, was just 363 feet (110 m) tall.\nIndividually, the Super Heavy stands 230 feet (70 m) tall, and Starship SN20 added another 165 feet (50 m) of height.\nThe two vehicles are expected to undergo numerous technical tests in August to prepare them for an orbital attempt.\n## Orbital flight attempt\nRegulation remains the big uncertainty as Starship awaits its chance to make an orbital flight test.\nIf all goes according to plan, Space.com reported, the spaceship will make a round-the-world trip to splash down off the coast of Hawaii after 90 minutes, while the first stage of the Super Heavy rocket should return to Earth 6 minutes after launch in the Gulf of Mexico.\nHowever, the FAA has undertaken an environmental assessment of the Starship's mission, which delayed SpaceX's plans to attempt the flight in July 2021.\nEven after the assessment is finished, there could be more certifications to consider.\n\"Depending on the outcome of that [environmental] assessment, it [SpaceX] may also be required to go through a more detailed review culminating in an updated environmental impact statement.\nOnly after that process is complete can the Federal Aviation Administration move on to licensing a possible orbital Starship launch,\" CNN Business reported in June 2021.",
          "title": "SpaceX Starship: Key milestones for the world's most powerful rocket",
          "url": "https://www.livescience.com/spacex-starship-key-milestones.html",
          "date": "2021-08-26",
          "last_updated": "2026-05-19"
        },
        {
          "snippet": "",
          "title": "SpaceX - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/SpaceX",
          "date": "2004-07-16",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "SpaceX launched the third integrated flight test of its Super Heavy booster and Starship upper stage from the company’s Starbase orbital launch pad at 8:25 a.m.\nCT on March 14.\nThis flight test is an important milestone toward providing NASA with a Starship HLS for its Artemis missions.\n...\nOn March 14, SpaceX launched the third integrated flight test of its Super Heavy booster and Starship upper stage, an important milestone toward providing NASA with a Starship HLS for its Artemis missions.\nA complement of 33 Raptor engines, fueled by super-cooled liquid methane and liquid oxygen, powered the Super Heavy booster with Starship stacked on top, from the company’s Starbase orbital launch pad at 8:25 a.m.\nCDT.\nStarship, using six Raptor engines, separated from the Super Heavy booster employing a hot-staging technique to fire the engines before separation at approximately three minutes into the flight, in accordance with the flight plan.\nThis was the third flight test of the integrated Super Heavy-Starship system.\n...\nThis test accomplished several important firsts that will contribute to the development of Starship for Artemis lunar landing missions.\nThe spacecraft reached its expected orbit and Starship completed the full-duration ascent burn.\nOne objective closely tied to future Artemis operations is the transfer of thousands of pounds of cryogenic propellant between internal tanks during the spacecraft’s coast phase as part of NASA’s Space Technology Missions Directorate 2020 Tipping Point awards.\nThe propellant transfer demonstration operations were completed, and the NASA-SpaceX team is currently reviewing the flight data that was received.\nThis Tipping Point technology demonstration is one of more than 20 development activities NASA is undertaking to solve the challenges of using cryogenic fluids during future missions.\nAs a key step toward understanding how super-cooled propellant sloshes within the tanks when the engines shut down, and how that movement affects Starship’s stability while in orbit, engineers will study flight test data to assess the performance of thrusters that control Starship’s orientation in space.",
          "title": "NASA Artemis Mission Progresses with SpaceX Starship Test Flight",
          "url": "https://www.nasa.gov/directorates/esdmd/artemis-campaign-development-division/human-landing-system-program/nasa-artemis-mission-progresses-with-spacex-starship-test-flight/",
          "date": "2024-03-14",
          "last_updated": "2026-04-18"
        },
        {
          "snippet": "SpaceX is continuing to make progress on the development of Starship, the largest rocket ever built, with the third test flight Thursday accomplishing considerably more than the previous two tests.\nThe 400-foot-tall Starship rocket lifted off from SpaceX’s Starbase facility in southeastern Texas at 8:25 a.m. local time.\nAlthough SpaceX has been developing Starship for years, this is only the third time the company has attempted an orbital mission.\nAfter liftoff, Starship proceeded through a nominal — aerospace speak for normal — ascend.\nAll 33 Raptor engines on the Super Heavy booster performed as designed, and the two stages separated around 2 minutes 45 seconds into the mission.\nCritically, the launch vehicle nailed a novel stage separation technique called “hot staging,” where the upper stage (also called Starship) lights its engines to push away the Super Heavy booster.\nThe hot-staging technique was performed for the first time, ever, during the second Starship test flight last November.\nFrom there, the Starship upper stage continued its ascent to orbit.\nSpaceX CEO Elon Musk congratulated the team on X, saying, “Starship reached orbital velocity!”\n> Starship reached orbital velocity!\n> Congratulations @SpaceX team!!\n> — Elon Musk (@elonmusk) March 14, 2024\nThe booster executed what’s called a boostback burn to adjust its trajectory as it aimed to splash down in the Gulf of Mexico — Falcon 9’s booster performs the same maneuver to vertically land back on Earth — but its engines failed to relight for the landing burn phase.\nThe Super Heavy was subsequently lost.\nThe company nailed another new milestone after it opened Starship’s payload door for the first time.\nThis capability is crucial for SpaceX’s plans to rapidly deploy many hundreds of next-generation Starlink satellites.\nAnother demonstration, a propellant transfer demo, was also completed, though the company did not go into the results of this test.\nPropellant transfer is a crucial part of the company’s plans to return humans to the moon for NASA.\nAs part of SpaceX’s plans for that NASA mission, the company has settled on a mission architecture that could include more than a dozen Starship refueling trips.\nBeing able to refuel the vehicle is also necessary for a future Mars mission.\nStarship continued on its coasting phase, but after around a half hour the company said it wouldn’t attempt to relight the engines to proceed with the test.\n...\nInstead, they let gravity do its work, and the Earth’s powerful gravitational forces pulled Starship back through the lower atmosphere.\nUltimately, mission controllers failed to reestablish communications with Starship, leading SpaceX’s Dan Huot to announce that they had lost the ship: “No splashdown today, but again just it’s incredible to see how much further we got this time around,” he said.",
          "title": "SpaceX makes significant progress with third Starship orbital ...",
          "url": "https://techcrunch.com/2024/03/14/spacex-makes-significant-progress-with-third-starship-orbital-test-flight/",
          "date": "2024-03-14",
          "last_updated": "2026-05-20"
        },
        {
          "snippet": "**genesis of Starship** can be traced back to the early 2010s when SpaceX was actively exploring concepts for a fully reusable launch system.\n...\nDuring this phase, SpaceX experimented with different materials and manufacturing techniques, ultimately settling on stainless steel for the Starship's construction.\n...\n**Starhopper**, a scaled-down prototype, marked a pivotal moment in Starship's development.\n...\nIn 2019, Starhopper conducted several successful tethered and untethered hops, reaching altitudes of up to 150 meters.\nThese tests validated the Raptor engine's performance and demonstrated the feasibility of vertical takeoff and landing (VTOL), a critical capability for full reusability.\n...\n**SN15** represented a significant turning point in the Starship program.\n...\nIn May 2021, SN15 successfully completed a high-altitude flight test, reaching an altitude of 10 kilometers and performing a controlled landing.\nThis marked the first time a Starship prototype had successfully completed a full flight profile, including ascent, descent, and landing, without any major issues.\n...\nFollowing SN15, SpaceX shifted its focus to orbital flight tests.\nThe company began constructing Starship prototypes designed for orbital missions, along with the Super Heavy booster, the massive first stage that will propel Starship into orbit.\nThese prototypes, such as\n*Ship 20 and Booster 4*, underwent extensive testing at SpaceX's Starbase facility in Boca Chica, Texas.\nTesting included static fires of the Super Heavy's numerous Raptor engines, as well as cryogenic proof tests to ensure the structural integrity of both Starship and Super Heavy.\nThe development and testing of orbital-class Starship prototypes represent a major step towards realizing the ultimate goal of a fully reusable space transportation system.\nThese efforts pave the way for future orbital flight tests, which will provide critical data on the performance of Starship and Super Heavy in the harsh environment of space.\n...\nThe\n**first orbital flight test** of Starship is a highly anticipated event that will mark a major milestone in the program's development.\nThis test involves launching a Starship prototype atop a Super Heavy booster, sending it into orbit, and then attempting a controlled reentry and splashdown in the Pacific Ocean.\nThe data gathered from this test will be invaluable for understanding the performance of Starship in a real-world orbital environment and for identifying any areas that require further improvement.\nDespite several delays, SpaceX is working closely with regulatory authorities to obtain the necessary approvals for the orbital flight test.\nThe company has made significant progress in addressing environmental concerns and implementing safety measures to minimize risks.\nOnce the necessary approvals are in place, SpaceX plans to conduct the orbital flight test as soon as possible.\nThis test will be a crucial step towards validating the Starship design and demonstrating its capabilities for future missions.\n...\nFrom early concepts and prototypes to successful high-altitude flights and upcoming orbital tests, the Starship program has made remarkable progress in a relatively short period.",
          "title": "SpaceX Starship Timeline: Key Milestones & Future",
          "url": "https://marcoauggiero.com/blog/spacex-starship-timeline-key-milestones-1761214439931",
          "date": "2025-10-23",
          "last_updated": "2025-10-30"
        }
      ],
      "server_time": null
    }
    ```
  </Accordion>
</AccordionGroup>

## Streaming Responses

Enable streaming for real-time Agent API output:

<Tabs>
  <Tab title="Agent API">
    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      # Make the streaming API call
      stream = client.responses.create(
          preset="low",
          input="Explain the three leading approaches to building a quantum computer: superconducting qubits, trapped-ion qubits, and photonic qubits.",
          stream=True
      )

      # Process the streaming response
      for chunk in stream:
          if chunk.type == "response.output_text.delta":
              print(chunk.delta, end="", flush=True)
      ```

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

      const client = new Perplexity();

      // Make the streaming API call
      const stream = await client.responses.create({
          preset: "low",
          input: "Explain the three leading approaches to building a quantum computer: superconducting qubits, trapped-ion qubits, and photonic qubits.",
          stream: true
      });

      // Process the streaming response
      for await (const chunk of stream) {
          if (chunk.type === "response.output_text.delta") {
              process.stdout.write((chunk as any).delta);
          }
      }
      ```

      ```bash cURL theme={null}
      curl https://api.perplexity.ai/v1/agent \
        -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "preset": "low",
          "input": "Explain the three leading approaches to building a quantum computer: superconducting qubits, trapped-ion qubits, and photonic qubits.",
          "stream": true
        }'
      ```
    </CodeGroup>
  </Tab>
</Tabs>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "resp_a8dc1444-8a50-40c1-a918-f3d8de35c2f7",
    "created_at": 1779391840,
    "model": "openai/gpt-5.1",
    "object": "response",
    "output": [
      {
        "results": [
          {
            "id": 1,
            "snippet": "Superconducting qubits are one of the most widely used\nphysical realizations of quantum computing due to their scalability [6] and the\nsuccess researchers have had in creating a universal set of quantum logic gates\nfor superconducting qubits [1].\nBoth Google and IBM have built functioning su-\nperconducting quantum computers with 72 and 53 qubits respectively, demon-\nstrating the feasibility of constructing a superconducting quantum computer.\nFinally, superconducting qubits are based on circuit systems that can be reli-\nably constructed in a modular fashion [2] making them an excellent foundation\non which to build quantum computers.\n...\nSuperconducting qubits are constructed out of what amount to classical\ncircuit elements that are supercooled and made small enough that the law of\nQuantum Mechanics apply.\nThis means that we will have to develop a means\nof constructing quantum Hamiltonians for systems which are usually treated\nand understood classically.\n...\nThis is incredibly\n...\nA Cooper pair is a system constructed out of a metallic superconducting is-\nland connected by a thin insulating barrier, called a Josephson Junction, to a\nsuperconducting electron reservoir (or in some cases a second superconducting\nisland).\nA Cooper pair box can be used to build a type of superconducting\nqubit known as a charge qubit where the state of the qubit is determined by\nthe number of Cooper pairs that have tunneled across the Josephson Junction\nto the superconducting island.\n...\nDespite the fact that tremendous advances have been made in the construction\nand manipulation of superconducting qubits, there is still great potential for\nimprovement.\nFor example, superconducting qubits, have fairly low coherence\n...\nThis is\ncan be remedied by using fluxonium qubits which couple the superconducting\nisland to the reservoir through an inductor rather than a capacitor and can\ncombine the benefits of the traditional Cooper-pair box and Transmon qubits\nwhile avoiding their drawbacks [3].\nHowever, fluxonium qubits have not been\nsuccessfully incorporated into large-scale circuits and their operation is far more\ndifficult, requiring further research [3].",
            "title": "[PDF] A Brief Introduction to Superconducting Charge Qubits - Chicago U",
            "url": "https://homes.psd.uchicago.edu/~sethi/Teaching/P243-W2021/Final%20Papers/MFarrington_Advanced_Quantum_Mechanics_Final_Project%20(1).pdf",
            "date": null,
            "last_updated": "2026-03-29",
            "source": "web"
          },
          {
            "id": 2,
            "snippet": "These atoms are the heart of our quantum processing units.\nWe trap them in 3D space, and then use lasers to do everything from initial preparation to final readout.\n...\nMost quantum computers rely on superconducting circuits or exotic materials.\nIonQ takes a simpler, more powerful approach: we use single atoms—identical, stable, and natural—as the building blocks of computation.\n...\nOnce we've turned our atom into an ion, we use a specialized chip called a *linear ion trap* to hold it precisely in 3D space.\n...\nWe can (and do!) load any number of ions into a *linear chain*.\nThis on-demand reconfigurability allows us to theoretically create anything from a one-qubit system to a 100+ qubit system without having to fabricate a new chip or change the underlying hardware.\n...\nBefore we can use our ions to perform quantum computations, we have to prepare them for the task.\nThis has two major steps: *cooling*, which reduces computational noise and makes our ions better qubits, followed by *state preparation*, which initializes each ion into a well-defined “zero” state, ready to perform algorithms.\n...\nWe compute using a series of operations called *gates* to manipulate the qubits’ state, first encoding and then operating on the information we want to calculate.\n...\nUsing Doppler Cooling, we can create qubits that are half of one one-thousandth of a degree above absolute zero, without needing to refrigerate any of the supporting hardware.\nThis is extremely cold, but for optimal performance, we need to go colder, as close to absolute zero as we can.\nTo accomplish this, we use a collection of laser-based techniques called *resolved-sideband cooling* to produce qubits so cold that they are almost perfectly still at an atomic level.",
            "title": "Our Trapped Ion Technology - IonQ",
            "url": "https://www.ionq.com/technology",
            "date": null,
            "last_updated": "2026-05-20",
            "source": "web"
          },
          {
            "id": 3,
            "snippet": "The theory of quantum computations is agnostic to the physical system—a quantum bit (qubit) is represented by the same vector regardless of the physical system that implements the quantum computation.\nThe physical system can be based on matter, e.g. trapped ions and superconducting qubits, or based on photons, referred to as photonic quantum computation.",
            "title": "Photonic Quantum Computing - arXiv",
            "url": "https://arxiv.org/html/2404.03367v1",
            "date": "2024-04-04",
            "last_updated": "2026-05-17",
            "source": "web"
          },
          {
            "id": 4,
            "snippet": "**Superconducting qubits** are among the most promising approaches to building quantum computers.\nIt is no surprise that this technology is being used by well-known tech companies in their quest to pioneer the quantum era.\nGoogle’s Sycamore claimed quantum advantage back in 2019 and, in 2021, IBM built its Eagle quantum computer with 127 qubits ! The central insight that allows for these quantum computers is that superconductivity is a quantum phenomenon, so we can use superconducting circuits as quantum systems that we can control at will.\nWe can actually bring the quantum world to a larger scale and manipulate it more freely!\n...\n1. **Well-characterized and scalable qubits**.\nMany of the quantum systems that we find in nature are not qubits, so we must find a way to make them behave as such.\nMoreover, we need to put many of these systems together.\n2. **Qubit initialization**.\nWe must be able to prepare the same state repeatedly within an acceptable margin of error.\n3. **Long coherence times**.\nQubits will lose their quantum properties after interacting with their environment for a while.\nWe would like them to last long enough so that we can perform quantum operations.\n4. **Universal set of gates**.\nWe need to perform arbitrary operations on the qubits.\nTo do this, we require both single-qubit gates and two-qubit gates.\n...\nIf we build a somewhat **small electric circuit using superconducting wires** and bring it to temperatures of about 10 mK, it becomes a quantum system with discrete energy levels.\n...\nThe regime that has been proven ideal is known as the **transmon regime**, and artificial atoms in this regime are called **transmons**.\nThey have proven to be highly effective as qubits, and they are used in many applications nowadays.\nWe can thus work with the first two energy levels of the transmon, which we will also denote \\(\\left\\lvert g \\right\\rangle\\) and \\(\\left\\lvert e \\right\\rangle,\\) the ground and excited states respectively.\n...\nthe second criterion is satisfied effortlessly.\n...\nThe typical times in which a single-qubit gate is executed are in the order of the nanoseconds, making superconducting\nquantum computers the fastest ones out there.\n...\nSuperconducting quantum computing has gained momentum in the last decade as a leading competitor\nin the race for building a functional quantum computer.\nIt is based on artificial versions of atomic systems\ndone using superconducting circuits, which allows for versatility and control.\nThey have been easy to scale so far, but increasing the qubit coherence time and the speed of quantum\noperations and measurements is essential to scaling this technology further.",
            "title": "Quantum computing with superconducting qubits | PennyLane Demos",
            "url": "https://www.pennylane.ai/qml/demos/tutorial_sc_qubits",
            "date": "2022-03-21",
            "last_updated": "2026-05-17",
            "source": "web"
          },
          {
            "id": 5,
            "snippet": "To create a functional quantum computer, we need to produce and control a\nlarge number of qubits.\nThis feat has proven difficult, although significant\nprogress has been made using trapped ions, superconducting circuits,\nand many other technologies.",
            "title": "Photonic quantum computers | PennyLane Demos",
            "url": "https://pennylane.ai/qml/demos/tutorial_photonics",
            "date": "2022-05-30",
            "last_updated": "2026-05-05",
            "source": "web"
          },
          {
            "id": 6,
            "snippet": "The aim of this review is to provide quantum engineers with an introductory guide to the central concepts and challenges in the rapidly accelerating field of superconducting quantum circuits.\nOver the past twenty years, the field has matured from a predominantly basic research endeavor to a one that increasingly explores the engineering of larger-scale superconducting quantum systems.\nHere, we review several foundational elements—qubit design, noise properties, qubit control, and readout techniques—developed during this period, bridging fundamental concepts in circuit quantum electrodynamics and contemporary, state-of-the-art applications in gate-model quantum computation.\n...\nOne prominent platform for constructing a multiqubit quantum processor involves superconducting qubits, in which information is stored in quantum degrees of freedom (DOFs) of nanofabricated, anharmonic oscillators (AHOs) constructed from superconducting circuit elements.\nIn contrast to other platforms, e.g., electron spins in silicon\n9–14 and quantum dots, 15–18 trapped ions, 19–23 ultracold atoms, 24–27 nitrogen-vacancies in diamonds, 28,29 and polarized photons, 30–33 where the quantum information is encoded in natural microscopic quantum systems, superconducting qubits are macroscopic in size and lithographically defined.\nOne remarkable feature of superconducting qubits is that their energy-level spectra are governed by circuit element parameters and thus are configurable; they can be designed to exhibit “atomlike” energy spectra with the desired properties.\nTherefore, superconducting qubits are also often referred to as “artificial atoms,” offering a rich parameter space of possible qubit properties and operation regimes, with predictable performance in terms of transition frequencies, anharmonicity, and complexity.",
            "title": "A quantum engineer's guide to superconducting qubits",
            "url": "https://pubs.aip.org/aip/apr/article/6/2/021318/570326/A-quantum-engineer-s-guide-to-superconducting",
            "date": "2019-06-17",
            "last_updated": "2025-06-08",
            "source": "web"
          },
          {
            "id": 7,
            "snippet": "Photonic offers a unique quantum modality (spin-photon qubits) as the foundation for scalable, distributed, fault tolerant QC systems.\nPhotonic’s core technology offers a plausible shortcut to large-scale fault-tolerant quantum computing.",
            "title": "Photonic Inc.: Distributed Quantum Computing at Scale",
            "url": "https://photonic.com",
            "date": "2025-11-04",
            "last_updated": "2026-05-20",
            "source": "web"
          },
          {
            "id": 8,
            "snippet": "Superconducting qubits are solid state electrical circuits fabricated using techniques adapted from those of conventional integrated microprocessors.\nThey are based on the Josephson tunnel junction, which is so far the only non-dissipative, strongly nonlinear circuit element compatible with low temperature operation.\nIn contrast to microscopic entities such as spins, atoms, or ions, superconducting qubits can be held firmly in one location in space and coupled strongly to their neighbors, an appealing feature for 2-qubit gate array implementation.\nRecently, the coherence factor of bare superconducting artificial atoms has reached that of the hydrogen atom for its 1S-2P transition (~ 20 million).\nThis opinionated review will compare the prospects of the transmon and fluxonium artificial atoms for large scale quantum information processing.",
            "title": "Keynote: Superconducting qubits for quantum computation - YouTube",
            "url": "https://www.youtube.com/watch?v=qsizrKrUZDg",
            "date": "2022-09-07",
            "last_updated": "2026-03-31",
            "source": "web"
          },
          {
            "id": 9,
            "snippet": "In optical systems for quantum information processing, the unit of light in a given mode—or photon—is used to represent a qubit.",
            "title": "Linear optical quantum computing - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/Linear_optical_quantum_computing",
            "date": "2013-12-09",
            "last_updated": "2026-04-17",
            "source": "web"
          },
          {
            "id": 10,
            "snippet": "Superconducting circuits are one of the most promising platforms for scalable quantum technology.\nIn the last couple of decades, it has undergone significant development and is currently being explored by several large tech companies as the future of quantum computing.\nThe analysis of superconducting circuits usually revolves around making efficient two-level quantum systems, also known as qubits, from circuits consisting of capacitors, linear inductors, and a nonlinear inductor also known as a Josephson junction.\nSuperconducting qubits were sparked by the invention of the Josephson junction in the sixties, but a breakthrough came with the transmon qubit in 2007, which increased the lifetime of the qubits.\nDespite all this, no introductory text on the subject exists.",
            "title": "Superconducting Circuit Companion---an Introduction with Worked ...",
            "url": "https://link.aps.org/doi/10.1103/PRXQuantum.2.040204",
            "date": "2021-12-14",
            "last_updated": "2025-11-11",
            "source": "web"
          }
        ],
        "type": "search_results",
        "queries": [
          "superconducting qubits overview",
          "trapped ion quantum computing overview",
          "photonic qubits quantum computing overview"
        ]
      },
      {
        "id": "msg_78f55417-7dad-435b-a49b-98933d85c9ee",
        "content": [
          {
            "text": "Superconducting qubits, trapped ions, and photonic qubits all implement the same abstract idea of a qubit but use very different physical systems, which leads to distinct strengths and weaknesses in speed, coherence, scalability, and engineering complexity.[web:3][web:4][web:5] Together they define the three main hardware “families” that leading labs and companies are pursuing for large‑scale quantum computers.[web:4][web:6]  \n\n## Superconducting qubits  \n\nSuperconducting qubits are tiny electrical circuits made from superconducting materials, typically incorporating Josephson junctions to create a nonlinear “artificial atom” whose lowest two energy levels serve as the qubit states |0⟩ and |1⟩.[web:4][web:6] These circuits are cooled to millikelvin temperatures (∼10 mK) so that quantum effects dominate, enabling fast microwave control of the qubits.[web:4]  \n\nKey features:  \n- **Speed and gate operations**: Single- and two-qubit gates are driven by microwave pulses and can operate in a few to tens of nanoseconds, making superconducting platforms among the fastest gate-based architectures.[web:4][web:6]  \n- Scalability and fabrication: Qubits and couplers are patterned lithographically on chips, similar to classical integrated circuits, which supports dense 2D arrays and has enabled devices in the 50–100+ qubit range from companies like Google and IBM.[web:1][web:4][web:10]  \n- Coherence and noise: Coherence times have improved dramatically (through designs like the transmon and fluxonium), but they remain limited by materials defects, electromagnetic noise, and crosstalk; engineering larger, error-corrected systems requires substantial advances in coherence and packaging.[web:1][web:4][web:6]  \n\nSuperconducting circuits are attractive because they are highly **configurable**: their energy spectra and coupling strengths can be engineered by design, but this flexibility comes at the cost of complex cryogenics and sensitive microwave control infrastructure.[web:6][web:8]  \n\n## Trapped‑ion qubits  \n\nTrapped‑ion quantum computers encode qubits in internal electronic or hyperfine states of individual atomic ions (such as ytterbium or calcium) held in electromagnetic traps in ultra‑high vacuum.[web:2] The ions are arranged in linear chains or small 2D configurations, and lasers are used for cooling, state preparation, gate operations, and readout.[web:2]  \n\nKey features:  \n- **Identical, high‑fidelity qubits**: Because they use natural atoms, each qubit is effectively identical and extremely stable, with very long coherence times compared to most other platforms.[web:2][web:5]  \n- Gate mechanisms: Multi-qubit gates exploit shared motional modes of the ions; tailored laser pulses entangle qubits by coupling internal states to collective motion.[web:2]  \n- Coherence and error rates: Coherence times can be seconds to minutes, and gate and readout fidelities are among the highest in any architecture, but gate speeds (typically microseconds or longer) are slower than in superconducting systems.[web:2][web:5]  \n\nScaling trapped‑ion systems involves engineering larger traps, complex laser delivery, and strategies like modular architectures where chains of ions are interconnected optically or through shuttling, which is technically demanding but conceptually compatible with fault‑tolerant schemes.[web:2][web:5]  \n\n## Photonic qubits  \n\nPhotonic quantum computing uses single photons as the carriers of quantum information, typically encoding qubits in degrees of freedom such as polarization, spatial modes, or time bins.[web:3][web:9] Computation is implemented using optical elements like beam splitters, phase shifters, nonlinear devices, and photon detectors, often in integrated photonic circuits.[web:3][web:5]  \n\nKey features:  \n- **Room‑temperature operation and low decoherence**: Photons interact weakly with the environment, so they can maintain quantum coherence over long distances, and many photonic platforms operate at or near room temperature (apart from some sources and detectors that may need cooling).[web:3][web:5]  \n- Linear optical approaches: In linear optical quantum computing, single photons and linear optics plus measurements and feed‑forward can in principle realize universal quantum computation, though it requires complex resource states and high‑performance single‑photon sources and detectors.[web:3][web:9]  \n- Integration and networking: Photonic qubits are naturally suited for quantum communication and for **distributed** architectures, and integrated photonic chips aim to combine sources, interferometers, and detectors for scalable, manufacturable systems.[web:3][web:5][web:7]  \n\nMajor challenges for photonic platforms include generating indistinguishable single photons on demand, achieving high-efficiency, low-noise detection, and scaling up error-corrected architectures given the probabilistic nature of many photonic operations.[web:3][web:5]  \n\n## Side‑by‑side comparison  \n\n| Aspect                | Superconducting qubits                            | Trapped‑ion qubits                                    | Photonic qubits                                        |\n|-----------------------|---------------------------------------------------|-------------------------------------------------------|--------------------------------------------------------|\n| Physical system       | Superconducting circuits with Josephson junctions.[web:4][web:6] | Atomic ions in EM traps in vacuum.[web:2]            | Single photons in optical modes.[web:3][web:9]         |\n| Operating conditions  | Millikelvin cryogenic temperatures.[web:4]       | Ultra‑high vacuum; laser cooling near motional ground state.[web:2] | Often room temperature optics; some cryogenic detectors.[web:3][web:5] |\n| Gate speed            | Nanoseconds (very fast).[web:4][web:6]           | Microseconds or slower.[web:2]                        | Varies; many operations effectively instantaneous but often probabilistic.[web:3][web:5] |\n| Coherence             | Microseconds–milliseconds; improving but limited by materials and noise.[web:4][web:6] | Very long (up to seconds or more).[web:2]             | Very long in principle; limited by loss rather than dephasing.[web:3][web:5] |\n| Scalability outlook   | Good near‑term chip‑scale scaling; packaging and error correction are main hurdles.[web:4][web:6][web:10] | Excellent qubit quality; scaling control and optics is challenging.[web:2][web:5] | Natural fit for large‑scale networking and integration; resource overhead still large.[web:3][web:5][web:7] |\n\nEach of these three approaches offers a different balance between speed, coherence, control complexity, and manufacturability, which is why all continue to be actively pursued as contenders for practical, fault‑tolerant quantum computers.[web:3][web:4][web:5]",
            "type": "output_text",
            "annotations": [],
            "logprobs": []
          }
        ],
        "role": "assistant",
        "status": "completed",
        "type": "message"
      }
    ],
    "status": "completed",
    "error": null,
    "usage": {
      "input_tokens": 6872,
      "output_tokens": 1528,
      "total_tokens": 8400,
      "cost": {
        "currency": "USD",
        "input_cost": 0.00411,
        "output_cost": 0.01528,
        "total_cost": 0.02234,
        "cache_creation_cost": null,
        "cache_read_cost": 0.00045,
        "tool_calls_cost": 0.0025
      },
      "input_tokens_details": {
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 3584,
        "cached_tokens": 3584
      },
      "tool_calls_details": {
        "search_web": {
          "invocation": 1
        }
      },
      "output_tokens_details": {
        "reasoning_tokens": 0
      }
    },
    "background": false,
    "completed_at": 1779391840,
    "frequency_penalty": 0,
    "incomplete_details": null,
    "instructions": "## Abstract\n<role>\nYou are an AI assistant developed by Perplexity AI. Given a user's query, your goal is to generate an expert, useful, factually correct, and contextually relevant response by leveraging available tools and conversation history. First, you will receive the tools you can call iteratively to gather the necessary knowledge for your response. You need to use these tools rather than using internal knowledge. Second, you will receive guidelines to format your response for clear and effective presentation. Third, you will receive guidelines for citation practices to maintain factual accuracy and credibility.\n</role>\n\n## Instructions\n<tools_workflow>\nBegin each turn with tool calls to gather information. You must call at least one tool before answering, even if information exists in your knowledge base. Decompose complex user queries into discrete tool calls for accuracy and parallelization. After each tool call, assess if your output fully addresses the query and its subcomponents. Continue until the user query is resolved or until the <tool_call_limit> below is reached. End your turn with a comprehensive response. Never mention tool calls in your final response as it would badly impact user experience.\n\n<tool_call_limit> Make at most three tool calls before concluding.</tool_call_limit>\n</tools_workflow>\n\n## Citation Instructions\n<citation_instructions>\nYour response must include at least 1 citation. Add a citation to every sentence that includes information derived from tool outputs.\nTool results are provided using `id` in the format `type:index`. `type` is the data source or context. `index` is the unique identifier per citation.\n<common_source_types> are included below.\n\n<common_source_types>\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n</common_source_types>\n\n<formatting_citations>\nUse brackets to indicate citations like this: [type:index]. Commas, dashes, or alternate formats are not valid citation formats. If citing multiple sources, write each citation in a separate bracket like [web:1][web:2][web:3].\n\nCorrect: \"The Eiffel Tower is in Paris [web:3].\"\nIncorrect: \"The Eiffel Tower is in Paris [web-3].\"\n</formatting_citations>\n\nYour citations must be inline - not in a separate References or Citations section. Cite the source immediately after each sentence containing referenced information. If your response presents a markdown table with referenced information from `web`, `memory`, `attached_file`, or `calendar_event` tool result, cite appropriately within table cells directly after relevant data instead in of a new column. Do not cite `generated_image` or `generated_video` inside table cells.\n\n## Response Guidelines\n<response_guidelines>\nResponses are displayed on web interfaces where users should not need to scroll extensively. Limit responses to 5 sections maximum. Users can ask follow-up questions if they need additional detail. Prioritize the most relevant information for the initial query.\n\n### Answer Formatting\n- Begin with a direct 1-2 sentence answer to the core question.\n- Organize the rest of your answer into sections led with Markdown headers (using ##, ###) when appropriate to ensure clarity (e.g. entity definitions, biographies, and wikis).\n- Your answer should be at least 3 sentences long.\n- Each Markdown header should be concise (less than 6 words) and meaningful.\n- Markdown headers should be plain text, not numbered.\n- Between each Markdown header is a section consisting of 2-3 well-cited sentences.\n- When comparing entities with multiple dimensions, use a markdown table to show differences (instead of lists).\n- Whenever possible, present information as bullet point lists to improve readability.\n- You are allowed to bold at most one word (**example**) per paragraph. You can't bold consecutive words.\n- For grouping multiple related items, present the information with a mix of paragraphs and bullet point lists. Do not nest lists within other lists.\n\n### Tone\n<tone>\nExplain clearly using plain language. Use active voice and vary sentence structure to sound natural. Ensure smooth transitions between sentences. Avoid personal pronouns like \"I\". Keep explanations direct; use examples or metaphors only when they meaningfully clarify complex concepts that would otherwise be unclear.\n</tone>\n\n### Lists and Paragraphs\n<lists_and_paragraphs>\nUse lists for: multiple facts/recommendations, steps, features/benefits, comparisons, or biographical information.\n\nAvoid repeating content in both intro paragraphs and list items. Keep intros minimal. Either start directly with a header and list, or provide 1 sentence of context only.\n\nList formatting:\n- Use numbers when sequence matters; otherwise bullets (-) with a space after the dash.\n- Use numbers when sequence matters; otherwise bullets (-).\n- No whitespace before bullets (i.e. no indenting), one item per line.\n- Sentence capitalization; periods only for complete sentences.\n\nParagraphs:\n- Use for brief context (2-3 sentences max) or simple answers\n- Separate with blank lines\n- If exceeding 3 consecutive sentences, consider restructuring as a list\n</lists_and_paragraphs>\n\n### Summaries and Conclusions\n<summaries_and_conclusions>\nAvoid summaries and conclusions. They are not needed and are repetitive. Markdown tables are not for summaries. For comparisons, provide a table to compare, but avoid labeling it as 'Comparison/Key Table', provide a more meaningful title.\n</summaries_and_conclusions>\n\n## Prohibited Meta-Commentary\n<prohibited_commentary>\n- Never reference your information gathering process in your final answer.\n- Do not use phrases such as:\n- \"Based on my search results...\"\n- \"Now I have gathered comprehensive information...\"\n- \"According to my research...\"\n- \"My search revealed...\"\n- \"I found information about...\"\n- \"Let me provide a detailed answer...\"\n- \"Let me compile this information...\"\n- \"Short Answer: ...\"\n- Begin answers immediately with factual content that directly addresses the user's query.\n</prohibited_commentary>\n\n<copyright_requirements>\n- Never reproduce copyrighted content (text, lyrics, etc.)\n- You may share public domain content (expired copyrights, traditional works)\n- When copyright status is uncertain, treat as copyrighted\n- Keep summaries brief (under 30 words) and original — don't reconstruct sources\n- Brief factual statements (names, dates, facts) are always acceptable\n</copyright_requirements>\n\nCurrent date: Thursday, May 21, 2026\n\n",
    "max_output_tokens": 8192,
    "max_tool_calls": null,
    "metadata": {},
    "parallel_tool_calls": true,
    "presence_penalty": 0,
    "previous_response_id": null,
    "prompt_cache_key": null,
    "reasoning": null,
    "safety_identifier": null,
    "service_tier": "default",
    "store": true,
    "temperature": 1,
    "text": {
      "format": {
        "type": "text"
      }
    },
    "tool_choice": "auto",
    "tools": [
      {
        "type": "web_search"
      },
      {
        "type": "fetch_url"
      }
    ],
    "top_logprobs": 0,
    "top_p": 1,
    "truncation": "disabled",
    "user": null
  }
  ```
</Accordion>

<Info title="Complete Streaming Guide" href="/docs/agent-api/output-control#streaming-responses">
  For a full guide on streaming, including parsing, error handling, citation management, and best practices, see our [streaming guide](/docs/agent-api/output-control#streaming-responses).
</Info>

## Next Steps

Now that you've made your first API call, explore each API in depth:

<CardGroup>
  <Card title="Router API" icon="arrows-shuffle" href="/docs/gateway/quickstart">
    Get started with models across providers
  </Card>

  <Card title="Agent API" icon="code-circle" href="/docs/agent-api/quickstart">
    Get started with third-party models and presets
  </Card>

  <Card title="Search API" icon="search" href="/docs/search/quickstart">
    Get started with web search results
  </Card>

  <Card title="Embeddings API" icon="cube" href="/docs/embeddings/quickstart">
    Get started with text embeddings
  </Card>
</CardGroup>

### Additional Resources

<CardGroup>
  <Card title="Perplexity SDK" icon="book" href="/docs/sdk/overview">
    Learn about the official Perplexity SDK with type safety and async support
  </Card>

  <Card title="Models" icon="brain" href="/docs/agent-api/models">
    Explore available models and their capabilities
  </Card>

  <Card title="API Reference" icon="file-code" href="/api-reference/agent-post">
    View complete API documentation with detailed endpoint specifications
  </Card>

  <Card title="Examples" icon="player-play" href="/docs/cookbook/index">
    Explore code examples, tutorials, and integration patterns
  </Card>
</CardGroup>

<Info>
  Need help? Check out our [community](https://community.perplexity.ai) for support and discussions with other developers.
</Info>


# AWS Marketplace
Source: https://docs.perplexity.ai/docs/resources/aws-marketplace

Subscribe to the Perplexity API Platform through AWS Marketplace for consolidated billing and enterprise procurement.

The Perplexity API Platform is available as a SaaS listing on AWS Marketplace. You purchase API credits through your AWS account — credits are applied to your Perplexity API balance and work across all APIs (Router, Agent, Search, Sonar, and Embeddings).

<Frame>
  <img alt="Perplexity API Platform on AWS Marketplace" />
</Frame>

<Note>
  This listing is for the **API Platform** (Router API, Agent API, Search API, Sonar, and Embeddings). It's a separate product from **Enterprise Pro**, which doesn't include API access.
</Note>

## Why Subscribe Through AWS Marketplace?

Purchasing through AWS Marketplace offers several advantages over direct billing:

* **Consolidated AWS billing** — charges appear on your existing AWS invoice alongside other AWS services, simplifying finance and accounting workflows
* **Enterprise procurement** — satisfies procurement requirements for organizations that mandate AWS Marketplace purchases; no separate vendor relationship needed
* **EDP eligible** — purchases count toward your AWS Enterprise Discount Program (EDP) commitments
* **Simplified vendor management** — no separate contract or payment method to maintain; AWS handles invoicing

<Card title="View the listing on AWS Marketplace" icon="aws" href="https://aws.amazon.com/marketplace/pp/prodview-fslss6gnscauq">
  Subscribe and get started with the Perplexity API Platform.
</Card>

## Pricing

The Perplexity API Platform on AWS Marketplace is available as a **1-month contract** with API platform credits:

| Plan                     |       Credits       | Contract |
| ------------------------ | :-----------------: | :------: |
| **API Platform Credits** | Starting at \$1,000 |  1-month |

Credits are denominated 1:1 with USD — 1 credit = \$1. Credits are applied to your account balance and drawn down as you make API requests.

<Note>
  All Perplexity API products — Router API, Agent API, Search API, Sonar, and Embeddings — draw from the same shared credit pool. You don't need separate budgets per product.

  For per-request and per-token pricing details, see the <u>[Pricing page](/docs/getting-started/pricing)</u>.
</Note>

## How to Subscribe

<Tip>
  Credits don't expire — the **1-month contract** refers to the billing cycle, not a usage deadline, so unused credits remain on your balance.
</Tip>

1. Visit the <u>[Perplexity API Platform listing](https://aws.amazon.com/marketplace/pp/prodview-fslss6gnscauq)</u> on AWS Marketplace
2. Click **View purchase options**
3. Choose your credit amount, then click **Create contract**
4. Confirm the purchase — AWS will process the subscription and notify you by email

<Frame>
  <img alt="AWS Marketplace pricing — API platform credits at $1,000/month" />
</Frame>

Once your subscription is confirmed, you'll receive instructions to link your AWS Marketplace account to the Perplexity API Platform.

## Getting Started After Subscribing

After your AWS Marketplace subscription is confirmed:

1. **Sign in or create an account** — go to <u>[console.perplexity.ai](https://console.perplexity.ai)</u> and sign in with your Perplexity account (or create one if you don't have one yet)
2. **Link your subscription** — follow the prompts in the console to connect your AWS Marketplace purchase to your Perplexity account; this associates your purchased credits with your API Group
3. **Set up your API Group** — your credits are tied to an API Group (your organization's workspace in the API Portal). The person who completes the setup becomes the Admin, with full access to billing, API keys, and member invitations. Additional members can join as Admins (full access) or Members (view-only). See <u>[API Groups & Billing](/docs/getting-started/api-groups)</u>.
4. **Generate an API key** — go to API Keys in the console to create a key for your API Group. See <u>[API Key Management](/docs/admin/api-key-management)</u>.
5. **Start making requests** — credits are applied to your API Group's balance and shared across all products (Router API, Agent API, Search API, Sonar, Embeddings). Monitor remaining balance and usage in the console at any time.

<Frame>
  <img alt="Generating API keys in the Perplexity console" />
</Frame>

## Refund Policy

If you need to cancel your subscription, refunds are available **within 14 days of purchase** provided that **no credits have been used**. To request a refund, contact <u>[aws-api@perplexity.ai](mailto:aws-api@perplexity.ai)</u> with your AWS Marketplace order ID.

<Warning>
  Refunds are not available once any credits have been consumed, or after the 14-day window has passed.
</Warning>

## Support

For questions about your AWS Marketplace subscription, billing, or API usage, contact the Perplexity API team:

**Email:** <u>[aws-api@perplexity.ai](mailto:aws-api@perplexity.ai)</u>

For issues related to AWS Marketplace registration or account linking, contact the Clazar support team:

**Email:** <u>[support@clazar.io](mailto:support@clazar.io)</u>

Include your AWS Marketplace order ID or account email when reaching out so we can locate your subscription quickly.

## Additional Resources

<CardGroup>
  <Card title="Quickstart" icon="bolt" href="/docs/getting-started/quickstart">
    Make your first API request in minutes.
  </Card>

  <Card title="Pricing" icon="calculator" href="/docs/getting-started/pricing">
    Per-request and per-token pricing for all APIs.
  </Card>

  <Card title="AWS Marketplace listing" icon="aws" href="https://aws.amazon.com/marketplace/pp/prodview-fslss6gnscauq">
    View the Perplexity API Platform listing on AWS Marketplace.
  </Card>
</CardGroup>


# Changelog
Source: https://docs.perplexity.ai/docs/resources/changelog



<Tip>
  Looking ahead? Check out our [Feature Roadmap](/docs/resources/feature-roadmap) to see what's coming next.
</Tip>

<Update label="August 2026">
  **Gemini 3.7 Flash**

  The Agent API and Router API now support `google/gemini-3.7-flash` at launch pricing of \$0.375 per million input tokens, \$0.0375 per million cached-input tokens, and \$1.875 per million output tokens. See the [Agent API Models reference](/docs/agent-api/models).
</Update>

<Update label="August 2026">
  **Grok 4.6**

  The Agent API now supports `xai/grok-4.6`, xAI's latest flagship reasoning and agentic model. See pricing in the [Agent API Models reference](/docs/agent-api/models).
</Update>

<Update label="August 2026">
  **NVIDIA Nemotron 3 Ultra**

  The Agent API and Router API now support `perplexity/nemotron-3-ultra-550b-a55b` at \$0.25 per million input or cached-input tokens and \$2.50 per million output tokens. See the [Agent API Models reference](/docs/agent-api/models) or the [Router model catalog](/docs/gateway/models).
</Update>

<Update label="August 2026">
  **NVIDIA Nemotron 3.5 Lightning**

  The Agent API and Router API now support `perplexity/nemotron-3.5-lightning-30b-a3b`, a fast, efficient open-weight reasoning model, at \$0.0115 per million input tokens, \$0.00115 per million cached-input tokens, and \$0.17 per million output tokens. See the [Agent API Models reference](/docs/agent-api/models) or the [Router model catalog](/docs/gateway/models).
</Update>

<Update label="August 2026">
  **DeepSeek V4 Flash 0731**

  The Agent API and Router API now support `perplexity/deepseek-v4-flash-0731`, a fast, efficient open reasoning model with a 1M-token context window. See pricing in the [Agent API Models reference](/docs/agent-api/models) or the [Router model catalog](/docs/gateway/models).
</Update>

<Update label="July 2026">
  **GPT-5.6 price cuts and Sol Fast mode**

  GPT-5.6 Luna now costs \$0.20 per million input tokens and \$1.20 per million output tokens. GPT-5.6 Terra now costs \$2 per million input tokens and \$12 per million output tokens. GPT-5.6 Sol now supports Fast mode at 2× standard token pricing; send `service_tier: "priority"` to use it.
</Update>

<Update label="July 2026">
  **New: Router API**

  Unified access to open-weight models hosted by Perplexity through a single endpoint — with your existing Perplexity API key.

  **Key features:**

  * OpenAI Chat Completions and Anthropic Messages compatibility: switching is a base-URL change
  * Automatic health-based routing and failover across model deployments
  * Per-token pricing at each model's published rates, with no per-request fees

  [Get started with the Router API →](/docs/gateway/quickstart)
</Update>

<Update label="July 2026">
  **Remote MCP Server**

  The [Perplexity MCP Server](/docs/getting-started/integrations/mcp-server) is now available as a remote server hosted by Perplexity at `https://api.perplexity.ai/mcp`. Connect any MCP client that supports Streamable HTTP using your API key as a bearer token, with no local installation and nothing to update. Tools and behavior are identical to the local server, and usage is billed to your API key at standard API pricing.
</Update>

<Update label="July 2026">
  **Low preset updated**

  The Agent API `low` preset now uses `openai/gpt-5.6-luna` with `minimal` reasoning effort and a 32,768-token maximum output. If you use a [frozen configuration](/docs/agent-api/presets#current-preset-values), update these values to match the current preset. Dynamic `low` preset requests pick up the change automatically.
</Update>

<Update label="July 2026">
  **Inline citations for research presets**

  The Agent API's search-backed presets include inline citations: `fast` cites claims drawn from search results with numbered citations such as `[1]`, while `low`, `medium`, and `high` now cite claims drawn from tool results or provided source artifacts with source-typed citations such as `[web:1]`. After a successful tool call, the `low`, `medium`, and `high` presets include at least one citation in the final answer. The [current preset values](/docs/agent-api/presets#current-preset-values) include the system prompts for frozen configurations.
</Update>

<Update label="July 2026">
  **MCP Server 1.0: now backed by the Agent API**

  The [Perplexity MCP Server](/docs/getting-started/integrations/mcp-server) v1.0.0 moves its model-backed tools from the legacy Sonar models to [Agent API presets](/docs/agent-api/presets): `perplexity_ask` uses the `fast` preset, `perplexity_reason` uses `medium`, and `perplexity_research` uses `high`. Tool names and response shapes are unchanged, and all three tools are faster and cheaper on average than their Sonar predecessors. Long-running research now streams progress to MCP clients that request it, and cancelling an MCP request cancels the underlying run.

  The `strip_thinking` and `reasoning_effort` parameters were removed from the tool schemas (the Agent API emits no think tags, and presets manage reasoning effort); clients still sending them are ignored gracefully.
</Update>

<Update label="July 2026">
  **Sonar Chat Completions migration**

  More models, tools, and research-backed presets: Sonar Chat Completions is now [Agent API.](/docs/agent-api/quickstart) Migration guide [here](/docs/agent-api/migrate-from-sonar/overview).
</Update>

<Update label="July 2026">
  **Agent API: New Models**

  The Agent API added support for several new models this month, all with direct first-party token pricing. See the full list in the [Agent API Models reference](/docs/agent-api/models).

  **Claude Opus 5**

  The Agent API now supports `anthropic/claude-opus-5`.

  **GPT-5.6 Family**

  The Agent API now supports `openai/gpt-5.6-sol`, `openai/gpt-5.6-terra`, and `openai/gpt-5.6-luna`, giving you access to the latest GPT-5.6 models.

  **Gemini Flash Models**

  The Agent API now supports `google/gemini-3.6-flash` and `google/gemini-3.5-flash-lite`, adding Google's latest fast and cost-efficient models.

  **Grok 4.5**

  The Agent API now supports `xai/grok-4.5`, xAI's flagship coding and agentic model.

  **Kimi K3**

  The Agent API now supports `perplexity/kimi-k3`, Moonshot AI's flagship reasoning model. See the [Agent API Models reference](/docs/agent-api/models) for pricing and model-specific settings.

  **Retired: Gemini 3.1 Flash Lite Preview**

  `google/gemini-3.1-flash-lite-preview` has been retired: Google removed the underlying preview model from its API. Requests for this id now return a `model not supported` error. Use `google/gemini-3.1-flash-lite` instead — the stable successor at the same pricing. See the [Agent API Models reference](/docs/agent-api/models).
</Update>

<Update label="June 2026">
  **Agent API: New Models**

  The Agent API expanded model coverage this month, all with direct first-party token pricing. See the full list in the [Agent API Models reference](/docs/agent-api/models).

  * **Claude Sonnet 5** — `anthropic/claude-sonnet-5`, Anthropic's latest Sonnet model.
  * **GLM 5.2** — `perplexity/glm-5.2`, Z.AI's flagship reasoning model.
  * **Kimi K2.7 Code** — `perplexity/kimi-k2.7-code`, Moonshot AI's coding and agentic model.
  * **Nemotron 3 Super** — `nvidia/nemotron-3-super-120b-a12b`, NVIDIA's open-weight reasoning model.
</Update>

<Update label="May 2026">
  **Agent API: New Models**

  The Agent API added support for several new third-party models this month, all with direct first-party token pricing. See the full list in the [Agent API Models reference](/docs/agent-api/models).

  * **Claude Opus 4.8** — `anthropic/claude-opus-4-8`, Anthropic's flagship model.
  * **Gemini 3.5 Flash** — `google/gemini-3.5-flash`, Google's fast multimodal model.
  * **Gemini 3.1 Flash Lite** — `google/gemini-3.1-flash-lite` (and `-preview`), a cost-efficient option.
  * **Grok 4.3** and the **Grok 4.20** family — `xai/grok-4.3`, `xai/grok-4.20-non-reasoning`, and `xai/grok-4.20-multi-agent`.
</Update>

<Update label="May 2026">
  **Finance Search: Now Available**

  The `finance_search` tool is now available in the Agent API. Pull structured financial and market data — quotes, financials, earnings, analyst estimates, segment KPIs, ETF constituents, and more — for public companies and instruments. The model decides which fields to fetch based on your prompt, so a single call can return valuation, earnings, and context together.

  **Highlights:**

  * **Quotes and pricing**: Near-real-time prices, OHLCV ranges, pre-market and after-hours data
  * **Financials**: Income statement, balance sheet, cash flow (quarterly and annual), key ratios
  * **Earnings**: Last call transcript, filings, beat/miss history, guidance
  * **Coverage and market activity**: Analyst estimates, top gainers/losers, ownership and corporate actions
  * **Recommended configurations**: Presets for live quotes, single-company historical lookups, and multi-step cross-company research

  Start here: [Finance Search](/docs/agent-api/tools/finance-search)
</Update>

<Update label="April 2026">
  **Agent API: New Third-Party Models**

  The Agent API now supports Claude Opus 4.7, GPT-5.5, and Grok 4.20 Reasoning — extending model choice for tool-calling, structured outputs, and fallback chains. See the full list in the [Agent API Models reference](/docs/agent-api/models).

  **API Key Management: Security Upgrade**

  We've upgraded API key management with a one-time reveal model: full token values are now returned **only at the moment of creation** and cannot be retrieved again from the console or any endpoint. This significantly reduces the blast radius of credential exposure and aligns with industry best practices. Always set a descriptive `token_name` so keys remain identifiable after creation, and rotate regularly.

  Start here: [API Key Management](/docs/admin/api-key-management)

  **New Integration: n8n**

  n8n now ships a native Perplexity node with full API coverage — Chat Completions, Agent, Search, and Embeddings — all configurable from the visual canvas. Models load dynamically from the API, so the dropdown always reflects the latest options.

  Start here: [n8n Integration Guide](/docs/getting-started/integrations/n8n)

  **New Integration: OpenClaw**

  OpenClaw, the open-source terminal AI agent, now supports Perplexity Search API as a native web search provider. Configure your API key once and get structured search results (`title`, `url`, `snippet`) directly inside your terminal workflows.

  Start here: [OpenClaw Integration Guide](/docs/getting-started/integrations/openclaw)

  **API Credits now available through the AWS Marketplace**

  The Perplexity API Platform is now available as a SaaS listing on AWS Marketplace. Purchase API credits through your AWS account for consolidated billing, simplified procurement, and no separate vendor relationship.

  Start here: [AWS Marketplace](/docs/resources/aws-marketplace)

  **`/v1/models` Endpoint**

  A new `GET /v1/models` endpoint lists all available Agent API models in OpenAI-compatible format. No authentication required, useful for dynamic model selection in your integrations.
</Update>

<Update label="March 2026">
  **Agent API: New Third-Party Models**

  The Agent API now supports additional third-party models including GPT-5.4, NVIDIA Nemotron, Claude Sonnet 4.6, and Gemini 3.1 Pro Preview — giving you more flexibility for tool-calling, structured outputs, and model fallback chains.

  **Model Deprecations: Gemini 2.5 Flash & Gemini 2.5 Pro**

  As of March 20, 2026, `google/gemini-2.5-flash` has been deprecated and removed from the API. `google/gemini-2.5-pro` followed on April 1, along with `google/gemini-3-pro-preview`. If you were using these models, we recommend switching to newer alternatives available in the [Agent API Models reference](/docs/agent-api/models).

  **Agent API Endpoint: `/v1/agent`**

  The canonical Agent API endpoint is now `/v1/agent`. The previous `/v1/responses` path continues to work as an alias for OpenAI compatibility, no migration is required.
</Update>

<Update label="February 2026">
  **Agent API: Now Available**

  We're excited to announce the general availability of the **Agent API**! Build autonomous agents with production-ready guidance on model behavior, output controls, and OpenAI-compatibility patterns to seamlessly integrate with your existing systems.

  Start here: [Agent API Quickstart](/docs/agent-api/quickstart)

  **Embeddings API: Now Available**

  We're thrilled to launch the **Embeddings API** with comprehensive guides for standard and contextualized embeddings, plus best practices for semantic search and retrieval workflows.

  Start here: [Embeddings API Quickstart](/docs/embeddings/quickstart)
</Update>

<Update label="December 2025">
  **Model Deprecation: `sonar-reasoning` Removed**

  As of December 15, 2025, the `sonar-reasoning` model has been deprecated and removed from the API. If you were using this model, we recommend migrating to `sonar-reasoning-pro` for enhanced multi-step reasoning capabilities with web search.

  **New: Media Classifier for Intelligent Visual Content**

  We're excited to introduce the **Media Classifier** — an intelligent system that automatically detects when your queries would benefit from visual content and includes relevant images or videos in responses.

  **Key capabilities:**

  * **Automatic detection**: Analyzes queries to identify when visual content adds value
  * **Smart media selection**: Intelligently chooses between images, videos, or both based on query type
  * **Context-aware**: Perfect for educational content, geographic queries, processes, and demonstrations
  * **Configurable control**: Enable/disable and override media types as needed

  Available exclusively with `sonar-pro`, the Media Classifier enhances responses for visual concepts, locations, step-by-step processes, and educational content. [Learn more →](/docs/sonar/media)

  **Search API Enhancements**

  We've made several improvements to the Search API:

  * **New `max_tokens` parameter**: Control the maximum tokens extracted per page in search results. This gives you finer control over response size and costs. [Learn more →](/docs/search/quickstart)
  * **`last_updated_filter` support**: Filter search results by when content was last updated, in addition to publication date. Perfect for finding the most current information. [Learn more →](/docs/search/filters/date-time-filters)
  * **Vercel AI SDK Support**: The Search API is now compatible with the Vercel AI SDK, allowing you to build with Perplexity in a framework-agnostic way. [Learn more →](https://ai-sdk.dev/tools-registry/perplexity-search)

  **Ecosystem & Community**

  New community showcase: [**Perplexity Client**](/docs/cookbook/showcase/perplexity-client) — An Electron-based desktop application with advanced API parameter controls, custom spaces, and API debugging mode. Built by the community for developers who want fine-grained control over their Sonar interactions.
</Update>

<Update label="November 2025">
  **Pro Search: Now Generally Available**

  We're excited to announce the general availability of **Pro Search** for Sonar Pro! Pro Search enhances your queries with automated tool usage, enabling multi-step reasoning through intelligent tool orchestration.

  **Key capabilities:**

  * **Multi-step reasoning**: The model automatically performs multiple web searches and fetches URL content to answer complex queries
  * **Real-time thought streaming**: Watch the model's reasoning process as it works through your question
  * **Automatic classification**: Use `search_type: "auto"` to let the system intelligently route queries based on complexity
  * **Built-in tools**: Access `web_search` and `fetch_url_content` tools that the model uses automatically

  Learn more about Pro Search in our [Pro Search Quickstart](/docs/sonar/pro-search/quickstart) guide.

  **MCP Server: One-Click Installation**

  The [Perplexity MCP Server](/docs/getting-started/integrations/mcp-server) now supports **one-click installation** for popular AI development environments:

  * **Cursor**: Click to auto-configure the Perplexity MCP server
  * **VS Code**: One-click setup via the VS Code MCP extension
  * **Claude Desktop & Claude Code**: Easy JSON configuration

  The MCP server provides four powerful tools: `perplexity_search`, `perplexity_ask`, `perplexity_research`, and `perplexity_reason` — enabling AI assistants to access Perplexity's search and reasoning capabilities directly.
</Update>

<Update label="October 2025">
  **Official Perplexity SDKs**

  We're thrilled to announce the official **Perplexity SDKs** for Python and Typescript! These SDKs provide convenient, type-safe access to all Perplexity APIs with both synchronous and asynchronous clients.

  **Installation:**

  ```bash theme={null}
  # Python
  pip install perplexityai

  # Typescript  
  npm install @perplexity-ai/perplexity_ai
  ```

  **Features:**

  * Full type definitions for all request parameters and response fields
  * Support for Sonar and Search APIs
  * Streaming support with async iterators
  * Automatic environment variable handling for API keys

  Get started with our [SDK Quickstart Guide](/docs/sdk/overview) and explore the [Sonar API Guide](/docs/sonar/quickstart) for detailed usage examples.

  **Interactive Search API Playground**

  Test Search API queries and parameters in real time with our new [Interactive Playground](https://console.perplexity.ai) — **no API key required** to get started. Experiment with filtering options, see response structures, and refine your queries before implementing them in code.

  **New Search API Capabilities**

  * **`language_preference`**: Specify preferred languages for search results (available for `sonar` and `sonar-pro`)
  * **`search_domain_filter`**: Filter results to specific domains for more targeted searches
  * **Date/time filters**: Enhanced control over result freshness with publication and update filters
    **Ecosystem & Community**

  New community showcase: [**StarPlex**](/docs/cookbook/showcase/starplex) — An AI-powered startup intelligence platform featuring an interactive 3D globe interface. Built with Sonar Pro, it helps entrepreneurs validate business ideas by mapping competitors, VCs, and market opportunities worldwide. Featured at recent hackathon events!
</Update>

<Update label="September 2025">
  **New: File Attachments Support**

  You can now upload and analyze documents in multiple formats using Sonar models! This powerful new feature supports PDF, DOC, DOCX, TXT, and RTF files, allowing you to ask questions, extract information, and get summaries from your documents.

  **Key capabilities:**

  * **Document Analysis**: Ask questions about document content and get detailed answers
  * **Content Extraction**: Pull out key information, data points, and insights
  * **Multi-format Support**: Work with PDF, Word documents, text files, and Rich Text Format
  * **Large Document Handling**: Process lengthy documents efficiently
  * **Multi-language Support**: Analyze documents in various languages

  Upload documents either via publicly accessible URLs using the `file_url` content type, similar to our existing image upload functionality.

  Get started with our comprehensive [File Attachments Guide](/docs/sonar/media#sending-files).
</Update>

<Update label="September 2025">
  **New: Search-only API**

  Introducing our standalone Search API that provides direct access to search results without LLM processing! This new endpoint gives you raw, ranked search results from Perplexity's continuously refreshed index.

  **Perfect for:**

  * Building custom search experiences
  * Integrating search results into your own applications
  * Creating specialized workflows that need search data without AI responses
  * Applications requiring just the search functionality

  **Key features:**

  * Direct access to Perplexity's search index
  * All existing search filters and controls
  * Faster responses since no LLM processing is involved
  * Same powerful filtering options (domain, date range, academic sources, etc.)

  This complements our existing chat completions API and gives developers more flexibility in how they use Perplexity's search capabilities.

  Learn more in our [Search API documentation](/docs/search/quickstart).
</Update>

<Update label="September 2025">
  **New: API Key Rotation Mechanism**

  We've introduced a comprehensive API key rotation system to enhance security and simplify key management for your applications.

  **Key features:**

  * **Seamless Rotation**: Replace API keys without service interruption
  * **Automated Workflows**: Set up automatic key rotation schedules
  * **Enhanced Security**: Regularly refresh keys to minimize security risks
  * **Audit Trail**: Track key usage and rotation history
  * **Zero Downtime**: Smooth transitions between old and new keys

  **How it works:**

  1. Generate a new API key while keeping the old one active
  2. Update your applications to use the new key
  3. Deactivate the old key once migration is complete

  This is particularly valuable for production environments where continuous availability is critical, and for organizations with strict security compliance requirements.

  **Best practices:**

  * Rotate keys every 30-90 days depending on your security requirements
  * Use environment variables to manage keys in your applications
  * Test key rotation in staging environments first
  * Monitor key usage to ensure successful transitions

  Access key rotation features through your [API Portal](https://console.perplexity.ai).
</Update>

<Update label="August 2025">
  **API model deprecation notice**

  Please note that as of August 1, 2025, R1-1776 will be removed from the available models.

  R1 has been a popular option for a while, but it hasn't kept pace with recent improvements and lacks support for newer features. To reduce engineering overhead and make room for more capable models, we're retiring it from the API.

  If you liked R1's strengths, we recommend switching to `Sonar Pro Reasoning`. It offers similar behavior with stronger overall performance.
</Update>

<Update label="July 2025">
  **New: Detailed Cost Information in API Responses**

  The API response JSON now includes detailed cost information for each request.

  You'll now see a new structure like this in your response:

  ```json theme={null}
  "usage": {
      "prompt_tokens": 8,
      "completion_tokens": 439,
      "total_tokens": 447,
      "search_context_size": "low",
      "cost": {
       "input_tokens_cost": 2.4e-05,
       "output_tokens_cost": 0.006585,
       "request_cost": 0.006,
       "total_cost": 0.012609
     }
  }
  ```

  **What's included:**

  * **input\_tokens\_cost**: Cost attributed to input tokens
  * **output\_tokens\_cost**: Cost attributed to output tokens
  * **request\_cost**: Fixed cost per request
  * **total\_cost**: The total cost for this API call

  This update enables easier tracking of usage and billing directly from each API response, giving you complete transparency into the costs associated with each request.
</Update>

<Update label="July 2025">
  **New: SEC Filings Filter for Financial Research**

  We're excited to announce the release of our new SEC filings filter feature, allowing you to search specifically within SEC regulatory documents and filings. By setting `search_domain: "sec"` in your API requests, you can now focus your searches on official SEC documents, including 10-K reports, 10-Q quarterly reports, 8-K current reports, and other regulatory filings.

  This feature is particularly valuable for:

  * Financial analysts researching company fundamentals
  * Investment professionals conducting due diligence
  * Compliance officers tracking regulatory changes
  * Anyone requiring authoritative financial information directly from official sources

  The SEC filter works seamlessly with other search parameters like date filters and search context size, giving you precise control over your financial research queries.

  **Example:**

  ```bash theme={null}
  curl --request POST \
    --url https://api.perplexity.ai/v1/sonar \
    --header 'accept: application/json' \
    --header 'authorization: Bearer $PERPLEXITY_API_KEY' \
    --header 'content-type: application/json' \
    --data '{
      "model": "sonar-pro",
      "messages": [{"role": "user", "content": "What was Apple's revenue growth in their latest quarterly report?"}],
      "stream": false,
      "search_domain": "sec",
      "web_search_options": {"search_context_size": "medium"}
  }' | jq
  ```

  For detailed documentation and implementation examples, please see our [SEC Guide](https://docs.perplexity.ai/guides/sec-guide).
</Update>

<Update label="June 2025">
  **Enhanced: Date Range Filtering with Latest Updated Field**

  We've enhanced our date range filtering capabilities with new fields that give you even more control over search results based on content freshness and updates.

  **New fields available:**

  * `latest_updated`: Filter results based on when the webpage was last modified or updated
  * `published_after`: Filter by original publication date (existing)
  * `published_before`: Filter by original publication date (existing)

  The `latest_updated` field is particularly useful for:

  * Finding the most current version of frequently updated content
  * Ensuring you're working with the latest data from news sites, blogs, and documentation
  * Tracking changes and updates to specific web resources over time

  **Example:**

  ```bash theme={null}
  curl --request POST \
    --url https://api.perplexity.ai/v1/sonar \
    --header 'accept: application/json' \
    --header 'authorization: Bearer $PERPLEXITY_API_KEY' \
    --header 'content-type: application/json' \
    --data '{
      "model": "sonar-pro",
      "messages": [{"role": "user", "content": "What are the latest developments in AI research?"}],
      "stream": false,
      "web_search_options": {
        "latest_updated": "2025-06-01",
        "search_context_size": "medium"
      }
  }'
  ```

  For comprehensive documentation and more examples, please see our [Date Range Filter Guide](https://docs.perplexity.ai/guides/date-range-filter-guide).
</Update>

<Update label="June 2025">
  **New: Academic Filter for Scholarly Research**
  We're excited to announce the release of our new academic filter feature, allowing you to tailor your searches specifically to academic and scholarly sources. By setting `search_mode: "academic"` in your API requests, you can now prioritize results from peer-reviewed papers, journal articles, and research publications.

  This feature is particularly valuable for:

  * Students and researchers working on academic papers
  * Professionals requiring scientifically accurate information
  * Anyone seeking research-based answers instead of general web content

  The academic filter works seamlessly with other search parameters like `search_context_size` and date filters, giving you precise control over your research queries.

  **Example:**

  ```bash theme={null}
  curl --request POST \
    --url https://api.perplexity.ai/v1/sonar \
    --header 'accept: application/json' \
    --header 'authorization: Bearer $PERPLEXITY_API_KEY' \
    --header 'content-type: application/json' \
    --data '{
      "model": "sonar-pro",
      "messages": [{"role": "user", "content": "What is the scientific name of the lions mane mushroom?"}],
      "stream": false,
      "search_mode": "academic",
      "web_search_options": {"search_context_size": "low"}
  }'
  ```

  For detailed documentation and implementation examples, please see our [Academic Filter Guide](https://docs.perplexity.ai/guides/academic-filter-guide).
</Update>

<Update label="May 2025">
  **New: Reasoning Effort Parameter for Sonar Deep Research**

  We're excited to announce our new reasoning effort feature for sonar-deep-research. This lets you control how much computational effort the AI dedicates to each query. You can choose from "low", "medium", or "high" to get faster, simpler answers or deeper, more thorough responses.

  This feature has a direct impact on the amount of reasoning tokens consumed for each query, giving you the ability to control costs while balancing between speed and thoroughness.

  **Options:**

  * `"low"`: Faster, simpler answers with reduced token usage
  * `"medium"`: Balanced approach (default)
  * `"high"`: Deeper, more thorough responses with increased token usage

  **Example:**

  ```bash theme={null}
  curl --request POST \
    --url https://api.perplexity.ai/v1/sonar \
    --header 'accept: application/json' \
    --header 'authorization: Bearer ${PPLX_KEY}' \
    --header 'content-type: application/json' \
    --data '{
      "model": "sonar-deep-research",
      "messages": [{"role": "user", "content": "What should I know before markets open today?"}],
      "stream": true,
      "reasoning_effort": "low"
    }'
  ```

  For detailed documentation and implementation examples, please see:
  [Sonar Deep Research Documentation](/docs/sonar/models/sonar-deep-research)
</Update>

<Update label="May 2025">
  **New: Asynchronous API for Sonar Deep Research**

  We're excited to announce the addition of an asynchronous API for Sonar Deep Research, designed specifically for research-intensive tasks that may take longer to process.

  This new API allows you to submit requests and retrieve results later, making it ideal for complex research queries that require extensive processing time.

  The asynchronous API endpoints include:

  1. `GET https://api.perplexity.ai/v1/async/sonar` - Lists all asynchronous chat completion requests for the authenticated user
  2. `POST https://api.perplexity.ai/v1/async/sonar` - Creates an asynchronous chat completion job
  3. `GET https://api.perplexity.ai/v1/async/sonar/{request_id}` - Retrieves the status and result of a specific asynchronous chat completion job

  **Note:** Async requests have a time-to-live (TTL) of 7 days. After this period, the request and its results will no longer be accessible.

  For detailed documentation and implementation examples, please see:
  [Sonar Deep Research Documentation](/docs/sonar/models/sonar-deep-research)
</Update>

<Update label="May 2025">
  **Enhanced API Responses with Search Results**

  We've improved our API responses to give you more visibility into search data by adding a new `search_results` field to the JSON response object.

  This enhancement provides direct access to the search results used by our models, giving you more transparency and control over the information being used to generate responses.

  The `search_results` field includes:

  * `title`: The title of the search result page
  * `url`: The URL of the search result
  * `date`: The publication date of the content

  **Example:**

  ```json theme={null}
  "search_results": [
    {
      "title": "Understanding Large Language Models",
      "url": "https://example.com/llm-article",
      "date": "2023-12-25"
    },
    {
      "title": "Advances in AI Research",
      "url": "https://example.com/ai-research",
      "date": "2024-03-15"
    }
  ]
  ```

  This update makes it easier to:

  * Verify the sources used in generating responses
  * Create custom citation formats for your applications
  * Filter or prioritize certain sources based on your needs

  **Update: The `citations` field has been fully deprecated and removed.** All applications should now use the `search_results` field, which provides more detailed information including titles, URLs, and publication dates.

  The `search_results` field is available across all our search-enabled models and offers enhanced source tracking capabilities.
</Update>

<Update label="April 2025">
  **New API Portal for Organization Management**

  We are excited to announce the release of our new API portal, designed to help you better manage your organization and API usage.

  With this portal, you can:

  * Organize and manage your API keys more effectively.
  * Gain insights into your API usage and team activity.
  * Streamline collaboration within your organization.

  Check it out here:\
  [https://console.perplexity.ai](https://console.perplexity.ai)
</Update>

<Update label="April 2025">
  **New: Location filtering in search**

  Looking to narrow down your search results based on users' locations?\
  We now support user location filtering, allowing you to retrieve results only from a particular user location.

  Check out the [guide](https://docs.perplexity.ai/guides/user-location-filter-guide).
</Update>

<Update label="April 2025">
  **Image uploads now available for all users!**

  You can now upload images to Sonar and use them as part of your multimodal search experience.\
  Give it a try by following our image upload guide:\
  [https://docs.perplexity.ai/guides/image-attachments](https://docs.perplexity.ai/guides/image-attachments)
</Update>

<Update label="April 2025">
  **New: Date range filtering in search**

  Looking to narrow down your search results to specific dates?\
  We now support date range filtering, allowing you to retrieve results only from a particular timeframe.

  Check out the guide:\
  [https://docs.perplexity.ai/guides/date-range-filter-guide](https://docs.perplexity.ai/guides/date-range-filter-guide)
</Update>

<Update label="April 2025">
  **Clarified: Search context pricing update**

  We've fully transitioned to our new pricing model: citation tokens are no longer charged.\
  If you were already using the `search_context_size` parameter, you've been on this model already.

  This change makes pricing simpler and cheaper for everyone — with no downside.

  View the updated pricing:\
  [https://docs.perplexity.ai/guides/pricing](https://docs.perplexity.ai/guides/pricing)
</Update>

<Update label="April 2025">
  **All features now available to everyone**

  We've removed all feature gating based on tiered spending. These were previously only available to users of Tier 3 and above.

  That means **every user now has access to all API capabilities**, regardless of usage volume or spend. Rate limits are still applicable.\
  Whether you're just getting started or scaling up, you get the full power of Sonar out of the box.
</Update>

<Update label="March 2025">
  **Structured Outputs Available for All Users**

  We're excited to announce that structured outputs are now available to all Perplexity API users, regardless of tier level. Based on valuable feedback from our developer community, we've removed the previous Tier 3 requirement for this feature.

  **What's available now:**

  * JSON structured outputs are supported across all models

  This change allows developers to create more reliable and consistent applications from day one. We believe in empowering our community with the tools they need to succeed, and we're committed to continuing to improve accessibility to our advanced features.

  Thank you for your feedback—it helps us make Perplexity API better for everyone.
</Update>

<Update label="March 2025">
  **Improved Sonar Models: New Search Modes**

  We're excited to announce significant improvements to our Sonar models that deliver superior performance at lower costs. Our latest benchmark testing confirms that Sonar and Sonar Pro now outperform leading competitors while maintaining more affordable pricing.

  Key updates include:

  * **Three new search modes** across most Sonar models:
    * High: Maximum depth for complex queries
    * Medium: Balanced approach for moderate complexity
    * Low: Cost-efficient for straightforward queries (equivalent to current pricing)

  * **Simplified billing structure**:
    * Transparent pricing for input/output tokens
    * No charges for citation tokens in responses (except for Sonar Deep Research)

  The current billing structure will be supported as the default option for 30 days (until April 18, 2025). During this period, the new search modes will be available as opt-in features.

  **Important Note:** After April 18, 2025, Sonar Pro and Sonar Reasoning Pro will not return Citation tokens or number of search results in the usage field in the API response.
</Update>

<Update label="January 2025">
  **API model deprecation notice**

  Please note that as of February 22, 2025, several models and model name aliases will no longer be accessible. The following model names will no longer be available via API:

  `llama-3.1-sonar-small-128k-online`

  `llama-3.1-sonar-large-128k-online`

  `llama-3.1-sonar-huge-128k-online`

  We recommend updating your applications to use our recently released Sonar or Sonar Pro models – you can learn more about them here. Thank you for being a Perplexity API user.
</Update>

<Update label="January 2025">
  **Build with Perplexity's new APIs**

  We are expanding API offerings with the most efficient and cost-effective search solutions available:  **Sonar** and **Sonar Pro**.

  **Sonar** gives you fast, straightforward answers

  **Sonar Pro** tackles complex questions that need deeper research and provides more sources

  Both models offer built-in citations, automated scaling of rate limits, and public access to advanced features like structured outputs and search domain filters. And don't worry, we never train on your data. Your information stays yours.

  You can learn more about our new APIs here - [https://docs.perplexity.ai](https://docs.perplexity.ai)
</Update>

<Update label="November 2024">
  **Citations Public Release and Increased Default Rate Limits**

  We are excited to announce the public availability of citations in the Perplexity API. In addition, we have also increased our default rate limit for the sonar online models to 50 requests/min for all users.

  Effective immediately, all API users will see citations returned as part of their requests by default. This is not a breaking change. The **return\_citations** parameter will no longer have any effect.

  For bug reports or enterprise inquiries, please reach out to our team at [api@perplexity.ai](mailto:api@perplexity.ai)
</Update>

<Update label="July 2024">
  **Introducing New and Improved Sonar Models**

  We are excited to announce the launch of our latest Perplexity Sonar models:

  **Online Models** -
  `llama-3.1-sonar-small-128k-online`
  `llama-3.1-sonar-large-128k-online`

  **Chat Models** -
  `llama-3.1-sonar-small-128k-chat`
  `llama-3.1-sonar-large-128k-chat`

  These new additions surpass the performance of the previous iteration. For detailed information on our supported models, please visit our model card documentation.

  **\[Action Required]** Model Deprecation Notice
  Please note that several models will no longer be accessible effective 8/12/2024. We recommend updating your applications to use models in the Llama-3.1 family immediately.

  The following model names will no longer be available via API -
  `llama-3-sonar-small-32k-online`
  `llama-3-sonar-large-32k-online`
  `llama-3-sonar-small-32k-chat`
  `llama-3-sonar-large-32k-chat`
  `llama-3-8b-instruct`
  `llama-3-70b-instruct`
  `mistral-7b-instruct`
  `mixtral-8x7b-instruct`

  We recommend switching to models in the Llama-3.1 family:

  **Online Models** -
  `llama-3.1-sonar-small-128k-online`
  `llama-3.1-sonar-large-128k-online`

  **Chat Models** -
  `llama-3.1-sonar-small-128k-chat`
  `llama-3.1-sonar-large-128k-chat`

  **Instruct Models** -
  `llama-3.1-70b-instruct`
  `llama-3.1-8b-instruct`

  If you have any questions, please email [support@perplexity.ai](mailto:support@perplexity.ai).
  Thank you for being a Perplexity API user.

  Stay curious,

  Team Perplexity
</Update>

***

<Update label="April 2024">
  **Model Deprecation Notice**

  Please note that as of May 14, several models and model name aliases will no longer be accessible. We recommend updating your applications to use models in the Llama-3 family immediately. The following model names will no longer be available via API:

  `codellama-70b-instruct`
  `mistral-7b-instruct`
  `mixtral-8x22b-instruct`
  `pplx-7b-chat`
  `pplx-7b-online`
</Update>


# Get in Touch
Source: https://docs.perplexity.ai/docs/resources/discussions



## Join Our Developer Community

<Card title="Community Forum" icon="users" href="https://community.perplexity.ai">
  The primary hub for our developer ecosystem. Connect with thousands of developers, share ideas, get help, and showcase your projects built with the Perplexity API.
</Card>

<CardGroup>
  <Card title="Discord Community" icon="message-circle" href="https://discord.gg/perplexity-ai">
    Join our Discord server for real-time assistance and discussions with fellow developers.
  </Card>

  <Card title="Stay Updated" icon="bell" href="https://twitter.com/perplexitydevs">
    Follow [@perplexitydevs](https://twitter.com/perplexitydevs) for the latest updates, feature announcements, and developer spotlights.
  </Card>
</CardGroup>

## Sales & Enterprise

For enterprise solutions, custom pricing, or sales questions, contact our sales team.

<Card title="Contact Sales Team" icon="file-pencil" href="https://perplexity.typeform.com/to/m3WnMaG6">
  Fill out our enterprise inquiry form and we'll review your use case to accommodate your needs.

  We offer custom pricing, dedicated support, and enterprise features for teams and organizations.
</Card>

## Technical Support

Need technical assistance? Our support team is here to help.

<Warning>
  **Try the [Community Forum](https://community.perplexity.ai/) first.**

  You'll get faster responses from our active community and team members who monitor the forum regularly.
</Warning>

**Email**: [api@perplexity.ai](mailto:api@perplexity.ai) — For technical issues

## Developer Resources

<Steps>
  <Step title="Report Issues">
    Found a bug? Help us improve by submitting detailed bug reports.

    Create a new post in the [Community Forum](https://community.perplexity.ai/) with the `Bug Reports` tag.
  </Step>

  <Step title="Share Your Work">
    Built something with the Perplexity API? We'd love to showcase your work.

    * Contribute to our [API Cookbook](https://github.com/perplexityai/api-cookbook)
    * Share on X/Twitter with [@perplexitydevs](https://twitter.com/perplexitydevs)
    * Present at our monthly developer showcase
  </Step>

  <Step title="Get Featured">
    Exceptional projects may be featured in our newsletter, blog, social media channels, and our [Cookbook Community Showcase](/docs/cookbook/showcase/briefo).

    <Tip>
      Share your project details and use cases to increase your chances of being featured.
    </Tip>
  </Step>
</Steps>


# Frequently Asked Questions
Source: https://docs.perplexity.ai/docs/resources/faq

Answers to common questions about the Perplexity API, covering models, output and capabilities, search behavior, billing and limits, errors, data privacy, and support.

## Models

<AccordionGroup>
  <Accordion title="Does the API Currently Support Web Browsing?">
    Yes. The Agent API provides a built-in [web search tool](/docs/agent-api/tools/web-search), and research-backed [presets](/docs/agent-api/presets) include search by default.
  </Accordion>

  <Accordion title="What Are the Context Windows for Each Model?">
    Context window size varies by model. See the [Agent API models page](/docs/agent-api/models) and the linked provider documentation.
  </Accordion>

  <Accordion title="Do You Support Fine-Tuning?">
    Currently, we do not support fine-tuning.
  </Accordion>

  <Accordion title="How Are Models Versioned and Deprecated?">
    When a model is retired, we announce it in the [changelog](/docs/resources/changelog) along with a recommended replacement. To avoid disruption, pin an explicit model ID in your requests rather than relying on a default, and watch the changelog for deprecation notices. The current list of available models is on the [Agent API models](/docs/agent-api/models) page.
  </Accordion>
</AccordionGroup>

## Output & Capabilities

<AccordionGroup>
  <Accordion title="Can I Get Structured (JSON) Output?">
    Yes. Use the `text.format` field to constrain a response to a JSON schema. See [Structured Outputs](/docs/agent-api/output-control#structured-outputs) for examples.
  </Accordion>

  <Accordion title="Does the API Support Streaming Responses?">
    Yes. Pass `stream: true` to receive the response incrementally as it is generated, instead of waiting for the full result. See [Streaming Responses](/docs/agent-api/output-control#streaming-responses). The [official SDKs](/docs/sdk/overview) expose streaming directly.
  </Accordion>

  <Accordion title="Does the API Support Tool or Function Calling?">
    Yes. The Agent API provides built-in tools, including [web search](/docs/agent-api/tools/web-search), [fetch URL content](/docs/agent-api/tools/fetch-url-content), [people search](/docs/agent-api/tools/people-search), [finance search](/docs/agent-api/tools/finance-search), and a [code sandbox](/docs/agent-api/tools/sandbox). The model decides when to call them while answering your request.
  </Accordion>

  <Accordion title="To What Extent Is the API OpenAI Compatible?">
    The Perplexity API is designed to be broadly compatible with OpenAI's chat completions endpoint. It adopts a similar structure—including fields such as `id`, `model`, and `usage`—and supports analogous parameters like `model`, `messages`, and `stream`.

    **Key Differences from the standard OpenAI response include:**

    * **Response Object Structure:**
      * OpenAI responses typically have an `object` value of `"chat.completion"` and a `created` timestamp, whereas our response uses `object: "response"` and a `created_at` field.
      * Instead of a `choices` array, our response content is provided under an `output` array that contains detailed message objects.

    * **Message Details:**
      * Each message in our output includes a `type` (usually `"message"`), a unique `id`, and a `status`.
      * The actual text is nested within a `content` array that contains objects with `type`, `text`, and an `annotations` array for additional context.

    * **Additional Fields:**
      * Our API response provides extra meta-information (such as `status`, `error`, `instructions`, and `max_output_tokens`) that are not present in standard OpenAI responses.
      * The `usage` field also differs, offering detailed breakdowns of input and output tokens (including fields like `input_tokens_details` and `output_tokens_details`).

    These differences are intended to provide enhanced functionality and additional context while maintaining broad compatibility with OpenAI's API design.
  </Accordion>

  <Accordion title="Are the Reasoning Tokens in Deep Research Same as CoTs in the Answer?">
    Reasoning tokens in Deep Research are a bit different than the CoTs in the answer—these tokens are used to reason through the research material before generating the final output via the CoTs.
  </Accordion>
</AccordionGroup>

## Search & Results

<AccordionGroup>
  <Accordion title="Why Are the Results from the API Different from the UI?">
    1. The API uses the same search system as the UI with differences in configuration—so their outputs may differ.
    2. The underlying AI model might differ between the API and the UI for a given query.
  </Accordion>

  <Accordion title="Is the Internet Data Access Provided by the API Identical to That of Perplexity's Web Interface?">
    Yes, the API offers exactly the same internet data access as Perplexity's web platform.
  </Accordion>

  <Accordion title="Does the API Use Content Filtering or SafeSearch?">
    Yes, for the API, content filtering in the form of SafeSearch is turned on by default. This helps filter out potentially offensive and inappropriate content, including pornography, from search results. SafeSearch is an automated filter that works across search results to provide a safer experience. You can learn more about SafeSearch on the [official Wikipedia page](https://en.wikipedia.org/wiki/SafeSearch).
  </Accordion>
</AccordionGroup>

## Account, Billing & Limits

<AccordionGroup>
  <Accordion title="How Does API Pricing Work?">
    Pricing is usage-based and varies by API. The Router API charges per token at each model's published rates, with no per-request fees; the Agent API charges per token at direct provider rates with no markup, plus a per-invocation fee for tools; the Search API charges per request; and Embeddings charge per token. See the full breakdown on the [Pricing page](/docs/getting-started/pricing).
  </Accordion>

  <Accordion title="How Do I Add Credits or Set Up Billing?">
    Purchase API credits in the [Billing page](https://console.perplexity.ai/group/billing) in the API Console. Enable **auto top-up** to add credits automatically when your balance runs low and avoid interrupted service. You can also buy credits through the [AWS Marketplace](/docs/resources/aws-marketplace) for consolidated billing, or [contact our sales team](https://perplexity.typeform.com/to/m3WnMaG6) for enterprise procurement. Your [usage tier](/docs/admin/rate-limits-usage-tiers) advances automatically as your cumulative purchases grow.
  </Accordion>

  <Accordion title="How Can I Upgrade to the Next Usage Tier?">
    The only way for an account to be upgraded to the next usage tier is through all-time credit purchase.

    Here are the spending criteria associated with each tier:

    | Tier   | Credit Purchase (all time) |
    | ------ | -------------------------- |
    | Tier 0 | -                          |
    | Tier 1 | \$50                       |
    | Tier 2 | \$250                      |
    | Tier 3 | \$500                      |
    | Tier 4 | \$1000                     |
    | Tier 5 | \$5000                     |
  </Accordion>

  <Accordion title="What Are the Limitations to the Number of API Calls?">
    You can find our [rate limits here](/docs/admin/rate-limits-usage-tiers).
  </Accordion>

  <Accordion title="How Can I Track My Spend/Usage per API Key?">
    We offer a way to track your billing per API key. You can do this by navigating to the following location:

    **Settings > View Dashboard > Invoice history > Invoices**

    Then click on any invoice and each item from the total bill will have a code at the end of it (e.g., pro (743S)). Those 4 characters are the last 4 of your API key.
  </Accordion>
</AccordionGroup>

## Errors & Troubleshooting

<AccordionGroup>
  <Accordion title="How Should I Respond to 401: Authorization Errors?">
    401 error codes indicate that the provided API key is invalid, deleted, or belongs to an account which ran out of credits. You likely need to purchase more credits on the [Billing page](https://console.perplexity.ai/group/billing). You can avoid this issue by configuring auto-top-up.
  </Accordion>

  <Accordion title="How Should I Handle 429: Too Many Requests Errors?">
    A 429 means you've exceeded your rate limit. Rate limits scale with your [usage tier](/docs/admin/rate-limits-usage-tiers) and use a leaky-bucket algorithm that allows short bursts up to your limit. Retry with exponential backoff and jitter, use burst capacity for batch jobs, and upgrade your tier—or [request a custom limit](https://perplexity.typeform.com/to/yctmfyVT)—for sustained higher throughput. See [Error Handling](/docs/sdk/error-handling) for retry examples in both SDKs.
  </Accordion>

  <Accordion title="What Should I Do About 5xx or Connection and Timeout Errors?">
    5xx responses indicate a transient server-side issue, and connection or timeout errors usually point to a network problem. Retry these with exponential backoff, set sensible client timeouts, and log the `X-Request-ID` response header to include when you contact support. The [Error Handling guide](/docs/sdk/error-handling) covers the SDK exception types and recovery patterns.
  </Accordion>

  <Accordion title="Where Can I Check API Status and Incidents?">
    Current API availability and incident history are on the [System Status page](/docs/resources/status). If you're seeing errors that aren't explained there, reach out through the support channels below.
  </Accordion>
</AccordionGroup>

## Data, Privacy & Security

<AccordionGroup>
  <Accordion title="Will User Data Submitted Through the API Be Used for Model Training or Other Purposes?">
    We collect the following types of information:

    **API Usage Data:** We collect billable usage metadata such as the number of requests and tokens. You can view your own usage on the [Billing page](https://console.perplexity.ai/group/billing) in the API Console.

    **User Account Information:** When you create an account with us, we collect your name, email address, and other relevant contact information.

    We do not retain any query data sent through the API and do not train on any of your data.
  </Accordion>

  <Accordion title="Where Are Perplexity's Language Models Hosted?">
    Our compute is hosted via Amazon Web Services in North America. By default, the API has zero day retention of user prompt data, which is never used for AI training.
  </Accordion>

  <Accordion title="What Security and Compliance Certifications Does the API Have?">
    Perplexity maintains a **SOC 2 Type II** report, a **2025 HIPAA gap assessment**, and a **CAIQlite** cloud security assessment. These reports, along with data-processing and other compliance documentation (for example, for DPA or GDPR requests), are available through the [Perplexity Trust Center](https://trust.perplexity.ai/). See [Privacy & Security](/docs/resources/privacy-security) for an overview, or [contact us](mailto:api@perplexity.ai) for documents not published there.
  </Accordion>
</AccordionGroup>

## Support & Reliability

<AccordionGroup>
  <Accordion title="How Do I File a Bug Report and What Happens Afterward?">
    To file a bug report, please head to our [Developer Community](https://community.perplexity.ai/) and create a new post in the "Bug Reports" category.

    We truly appreciate your patience, and we'll get back to you as soon as possible. Due to the current volume of reports, it may take a little time for us to respond—but rest assured, we're on it.
  </Accordion>

  <Accordion title="How Do I Request a New Feature?">
    A Feature Request is a suggestion to improve or add new functionality to the Perplexity API Platform, such as:

    * Requesting support for a new model or capability (e.g., image processing, fine-tuning options)
    * Asking for new API parameters (e.g., additional filters, search options)
    * Suggesting performance improvements (e.g., faster response times, better citation handling)
    * Enhancing existing API features (e.g., improving streaming reliability, adding new output formats)

    If your request aligns with these, please submit a feature request here: [Github Feature requests](https://github.com/ppl-ai/api-discussion/issues)
  </Accordion>

  <Accordion title="What's the Best Way to Stay Up to Date with API Updates?">
    We email users about new developments and also post in the [changelog](/docs/resources/changelog).
  </Accordion>

  <Accordion title="Does Perplexity Provide Service Quality Assurances Such as Service Uptime, Frequency of Failures, and Target Recovery Time in the Event of a Failure?">
    We do not guarantee this at the moment.
  </Accordion>

  <Accordion title="I Have Another Question or an Issue">
    Please reach out to [api@perplexity.ai](mailto:api@perplexity.ai) or [support@perplexity.ai](mailto:support@perplexity.ai) for other API inquiries. You can also post on our [discussion forum](https://github.com/ppl-ai/api-discussion/discussions) and we will get back to you.
  </Accordion>
</AccordionGroup>


# API Roadmap
Source: https://docs.perplexity.ai/docs/resources/feature-roadmap

Upcoming and in-progress features for the Perplexity API.

<Info>
  This page tracks upcoming and in-progress work only. Once a feature ships, it is removed from this roadmap and documented in the [changelog](/docs/resources/changelog).
</Info>

## Upcoming and In Progress

<AccordionGroup>
  <Accordion title="Sandbox API" description="Isolated Python and Bash execution environments">
    We are introducing a Sandbox API for isolated environments for executing Python and Bash code. Each sandbox runs in its own container with dedicated resources, supporting file operations, background processes, and state persistence via pause/resume.

    * **Dedicated per-sandbox containers** for stronger isolation
    * **Python and Bash execution** with file and process support
    * **Pause/resume state persistence** for iterative workflows
  </Accordion>

  <Accordion title="Chat Completions Performance Upgrade" description="Lower latency on existing endpoints">
    We are rolling out performance improvements while preserving compatibility.

    * **Same endpoint contracts** with backward compatibility
    * **Latency improvements** for common request patterns
    * **Automatic rollout** with no migration required for most users
  </Accordion>

  <Accordion title="Video Upload Capabilities" description="Multimodal video processing">
    We're expanding multimodal support to include direct video uploads.

    * **Video content analysis** for uploaded files
    * **Frame-level reasoning** for time-specific insights
    * **Visual scene understanding** across longer media
    * **Multimodal retrieval** across text, image, and video context
  </Accordion>

  <Accordion title="File Search and Connectors" description="Expanded data access">
    We're working on deeper file and data-source access for API organizations.

    * **Repository and connector search** across organization data
    * **Multi-format support** across common document types
    * **External data source integration** for enterprise workflows
  </Accordion>

  <Accordion title="Async API Webhook Support" description="Event-driven completion notifications">
    We plan to add webhook callbacks for async workflows so long-running jobs can notify your systems automatically.

    * **Job completion webhooks** for async requests
    * **Failure webhooks** with retry-safe delivery semantics
    * **Signature verification** for secure callback handling
  </Accordion>

  <Accordion title="Model and SDK Expansion" description="New model surface area and SDK ergonomics">
    We will continue to expand model coverage and improve SDK ergonomics.

    * **Additional model releases** and lifecycle clarity
    * **SDK quality-of-life improvements** for Python and TypeScript
    * **More production-ready examples** for common integration patterns
  </Accordion>

  <Accordion title="Context Management and Memory" description="Improved context handling across calls">
    We're addressing context persistence limits by improving memory-oriented workflows.

    * **Session-aware state handling**
    * **Reduced manual context stitching** across requests
    * **Improved control over long-running conversational workflows**
  </Accordion>

  <Accordion title="Better Error Handling" description="Clearer troubleshooting and recovery">
    We are improving how failures are reported and diagnosed across APIs.

    * **More actionable error messages**
    * **Stronger remediation guidance in docs**
    * **Clearer retry and backoff recommendations**
  </Accordion>

  <Accordion title="Voice-to-Voice API" description="Real-time audio interactions">
    We're building voice-native interaction capabilities for real-time experiences.

    * **Direct voice input and streamed audio output**
    * **Multi-language support**
    * **Low-latency conversation loops**
  </Accordion>

  <Accordion title="Dedicated API Console" description="Standalone developer console separate from the Perplexity app">
    We're building a dedicated API console — a standalone interface for developers that is separate from the Perplexity website. It will serve as the primary hub for API key management, usage visibility, and team controls.

    * **Standalone from the Perplexity app** — purpose-built for API developers
    * **API key management** with fine-grained permissions and rotation
    * **Usage and cost visibility** at the key and team level
    * **Organization controls** for team access and collaboration
  </Accordion>

  <Accordion title="Developer Analytics Dashboard" description="Operational usage insights">
    We're expanding analytics visibility for API teams.

    * **Query and latency analytics**
    * **Error trend monitoring**
    * **Cost and usage forecasting**
  </Accordion>

  <Accordion title="Finance Tools Integration" description="Financial data and analysis">
    We're expanding financial research capabilities with richer structured access.

    * **Market and filing workflows**
    * **Better controls for finance-specific retrieval**
    * **More end-to-end examples for analyst use cases**
  </Accordion>

  <Accordion title="Documentation Overhaul" description="Higher quality docs and guides">
    Documentation improvements remain in progress.

    * **Clearer API selection guides**
    * **More opinionated implementation guides**
    * **Higher-fidelity, production-oriented examples**
  </Accordion>

  <Accordion title="Labs Features via API" description="Experimental capabilities">
    We intend to bring selected experimental features into developer previews.

    * **Early access feature channels**
    * **Prototype integrations for feedback**
    * **Faster developer feedback loops for roadmap planning**
  </Accordion>
</AccordionGroup>

<Note>
  For shipped updates and release dates, see the [changelog](/docs/resources/changelog).
</Note>


# Perplexity Crawlers
Source: https://docs.perplexity.ai/docs/resources/perplexity-crawlers

We strive to improve our service every day by delivering the best search experience possible. To achieve this, we collect data using web crawlers ("robots") and user agents that gather and index information from the internet, operating either automatically or in response to user requests. Webmasters can use the following robots.txt tags to manage how their sites and content interact with Perplexity. Each setting works independently, and it may take up to 24 hours for our systems to reflect changes.

| User Agent      | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| :-------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| PerplexityBot   | `PerplexityBot` is designed to surface and link websites in search results on Perplexity. It is not used to crawl content for AI foundation models. To ensure your site appears in search results, we recommend allowing `PerplexityBot` in your site's `robots.txt` file and permitting requests from our published IP ranges listed below.<br /><br />Full user-agent string: `Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; PerplexityBot/1.0; +https://perplexity.ai/perplexitybot)`<br /><br />Published IP addresses: [https://www.perplexity.com/perplexitybot.json](https://www.perplexity.com/perplexitybot.json)                                                                                                                                        |
| Perplexity‑User | `Perplexity-User` supports user actions within Perplexity. When users ask Perplexity a question, it might visit a web page to help provide an accurate answer and include a link to the page in its response. `Perplexity-User` controls which sites these user requests can access. It is not used for web crawling or to collect content for training AI foundation models.<br /><br />Full user-agent string: `Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Perplexity-User/1.0; +https://perplexity.ai/perplexity-user)`<br /><br />Published IP addresses: [https://www.perplexity.com/perplexity-user.json](https://www.perplexity.com/perplexity-user.json)<br /><br />Since a user requested the fetch, this fetcher generally ignores robots.txt rules. |

## WAF Configuration

If you're using a Web Application Firewall (WAF) to protect your site, you may need to explicitly whitelist Perplexity's bots to ensure they can access your content. Below are configuration guidelines for popular WAF providers.

### Cloudflare WAF

To configure Cloudflare WAF to allow Perplexity bots:

<Steps>
  <Step title="Navigate to WAF settings">
    In your Cloudflare dashboard, go to **Security** → **WAF**.
  </Step>

  <Step title="Create a new rule">
    Click on **Custom rules** and create a new rule to allow Perplexity bots.
  </Step>

  <Step title="Configure rule conditions">
    Set up a rule that combines both User-Agent and IP address conditions:

    * **Field**: User Agent
    * **Operator**: Contains
    * **Value**: `PerplexityBot` OR `Perplexity-User`

    **AND**

    * **Field**: IP Source Address
    * **Operator**: Is in
    * **Value**: Use the IP ranges from the official endpoints listed below
  </Step>

  <Step title="Set rule action">
    Set the action to **Allow** to ensure these requests bypass other security rules.
  </Step>
</Steps>

### AWS WAF

For AWS WAF configuration, create IP sets and string match conditions:

<Steps>
  <Step title="Create IP sets">
    In the AWS WAF console, create IP sets for both PerplexityBot and Perplexity-User using the IP addresses from the official endpoints listed below.
  </Step>

  <Step title="Create string match conditions">
    Create string match conditions for the User-Agent headers:

    * `PerplexityBot`
    * `Perplexity-User`
  </Step>

  <Step title="Create allow rules">
    Create rules that combine the IP sets with the corresponding User-Agent strings, and set the action to **Allow**.
  </Step>

  <Step title="Associate with Web ACL">
    Associate these rules with your Web ACL and ensure they have higher priority than blocking rules.
  </Step>
</Steps>

### IP Address Sources

<Warning>
  Always use the most current IP ranges from the official JSON endpoints. These addresses are updated regularly and should be the source of truth for your WAF configurations.
</Warning>

* **PerplexityBot IP addresses**: [https://www.perplexity.com/perplexitybot.json](https://www.perplexity.com/perplexitybot.json)
* **Perplexity-User IP addresses**: [https://www.perplexity.com/perplexity-user.json](https://www.perplexity.com/perplexity-user.json)

<Tip>
  Set up automated processes to periodically fetch and update your WAF rules with the latest IP ranges from these endpoints to ensure continuous access for Perplexity bots.
</Tip>

### Best Practices

<Tip>
  When configuring WAF rules for Perplexity bots, combine both User-Agent string matching and IP address verification for enhanced security while ensuring legitimate bot traffic can access your content.
</Tip>

<Note>
  Changes to WAF configurations may take some time to propagate. Monitor your logs to ensure the rules are working as expected and that legitimate Perplexity bot traffic is being allowed through.
</Note>


# Privacy & Security
Source: https://docs.perplexity.ai/docs/resources/privacy-security

Learn about Perplexity's data privacy, retention policies, and security certifications for API users

## Data Privacy & Retention

### Zero Data Retention Policy

Perplexity maintains a strict **Zero Data Retention Policy** for the Chat Completions API. We do not retain data sent through the Chat Completions API, and we do not use customer data to train our models or for any purpose beyond processing the immediate request.

### Data We Collect

The only data we collect through the Chat Completions API consists of essential billable metrics required for service operation:

* Number of tokens processed
* Model used for each request
* Request timestamp and duration
* API key identification (for billing purposes)

This billing metadata does not include any content from your prompts, responses, or other user data.

## Security Certifications & Compliance

Perplexity is compliant with industry-leading security standards and certifications:

### Current Certifications

<Check>
  **[SOC 2 Type II Report](https://trust.perplexity.ai/)** - Comprehensive security controls audit covering security, availability, processing integrity, confidentiality, and privacy
</Check>

<Check>
  **[2025 HIPAA Gap Assessment](https://trust.perplexity.ai/)** - Healthcare data protection compliance evaluation
</Check>

<Check>
  **[CAIQlite](https://trust.perplexity.ai/)** - Cloud security assessment questionnaire demonstrating cloud security posture
</Check>

## Additional Security Information

For comprehensive details about our security measures, infrastructure protection, and compliance frameworks, visit our dedicated security portal:

<Card title="Perplexity Trust Center" icon="shield-check" href="https://trust.perplexity.ai/">
  Access detailed security documentation, compliance reports, and transparency information
</Card>

<Info>
  All security measures and certifications are regularly updated and maintained to ensure the highest standards of data protection and service security.
</Info>


# System Status
Source: https://docs.perplexity.ai/docs/resources/status



<ApiStatus />

## Contact & Support

If you experience any issues, please reach out through one of the following channels:

<CardGroup>
  <Card title="Email Support" icon="mail" href="mailto:api@perplexity.ai">
    Send us an email at **[api@perplexity.ai](mailto:api@perplexity.ai)** for enterprise inquiries or bug reports.
  </Card>

  <Card title="Discord Community" icon="message-circle" href="https://discord.com/invite/perplexity-ai">
    Join our Discord community to discuss with other developers and flag bug reports.
  </Card>
</CardGroup>


# Best Practices
Source: https://docs.perplexity.ai/docs/sdk/best-practices

Learn best practices for using the Perplexity SDKs in production, including environment variables, rate limiting, security, and efficient request patterns.

## Overview

This guide covers essential best practices for using the Perplexity SDKs in production environments. Following these practices will help you build robust, secure, and efficient applications.

## Security Best Practices

### Environment Variables

Always store API keys securely using environment variables:

<Steps>
  <Step title="Use environment variables">
    Store API keys in environment variables, never in source code.

    <CodeGroup>
      ```python Python theme={null}
      import os
      from perplexity import Perplexity

      # Good: Use environment variables
      client = Perplexity(
          api_key=os.environ.get("PERPLEXITY_API_KEY")
      )

      # Bad: Never hardcode API keys
      # client = Perplexity(api_key="pplx-abc123...")  # DON'T DO THIS
      ```

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

      // Good: Use environment variables
      const client = new Perplexity({
          apiKey: process.env.PERPLEXITY_API_KEY
      });

      // Bad: Never hardcode API keys
      // const client = new Perplexity({
      //     apiKey: "pplx-abc123..."  // DON'T DO THIS
      // });
      ```
    </CodeGroup>

    <Warning>
      Never commit API keys to version control. Use .env files locally and secure environment variable management in production.
    </Warning>
  </Step>

  <Step title="Use .env files for local development">
    Create a `.env` file for local development (add it to .gitignore):

    ```bash theme={null}
    cat > .env << 'EOF'
    PERPLEXITY_API_KEY=your_api_key_here
    PERPLEXITY_MAX_RETRIES=3
    PERPLEXITY_TIMEOUT=30000
    EOF
    ```

    <CodeGroup>
      ```python Python theme={null}
      from dotenv import load_dotenv
      import os
      from perplexity import Perplexity

      # Load environment variables from .env file
      load_dotenv()

      client = Perplexity(
          api_key=os.getenv("PERPLEXITY_API_KEY"),
          max_retries=int(os.getenv("PERPLEXITY_MAX_RETRIES", "3"))
      )
      ```

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

      // Load environment variables from .env file
      dotenv.config();

      const client = new Perplexity({
          apiKey: process.env.PERPLEXITY_API_KEY,
          maxRetries: parseInt(process.env.PERPLEXITY_MAX_RETRIES || '3')
      });
      ```
    </CodeGroup>
  </Step>

  <Step title="Validate environment variables">
    Check for required environment variables at startup.

    <CodeGroup>
      ```python Python theme={null}
      import os
      import sys
      from perplexity import Perplexity

      def create_client():
          api_key = os.getenv("PERPLEXITY_API_KEY")
          if not api_key:
              print("Error: PERPLEXITY_API_KEY environment variable is required")
              sys.exit(1)
          
          return Perplexity(api_key=api_key)

      client = create_client()
      ```

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

      function createClient(): Perplexity {
          const apiKey = process.env.PERPLEXITY_API_KEY;
          if (!apiKey) {
              console.error("Error: PERPLEXITY_API_KEY environment variable is required");
              process.exit(1);
          }
          
          return new Perplexity({ apiKey });
      }

      const client = createClient();
      ```
    </CodeGroup>
  </Step>
</Steps>

### API Key Rotation

Implement secure API key rotation:

<CodeGroup>
  ```python Python theme={null}
  import os
  import logging
  from perplexity import Perplexity
  from typing import Optional

  class SecurePerplexityClient:
      def __init__(self, primary_key: Optional[str] = None, fallback_key: Optional[str] = None):
          self.primary_key = primary_key or os.getenv("PERPLEXITY_API_KEY")
          self.fallback_key = fallback_key or os.getenv("PERPLEXITY_API_KEY_FALLBACK")
          self.current_client = Perplexity(api_key=self.primary_key)
          self.logger = logging.getLogger(__name__)
      
      def _switch_to_fallback(self):
          """Switch to fallback API key if available"""
          if self.fallback_key:
              self.logger.warning("Switching to fallback API key")
              self.current_client = Perplexity(api_key=self.fallback_key)
              return True
          return False
      
      def search(self, query: str, **kwargs):
          try:
              return self.current_client.search.create(query=query, **kwargs)
          except Exception as e:
              if "authentication" in str(e).lower() and self._switch_to_fallback():
                  return self.current_client.search.create(query=query, **kwargs)
              raise e

  # Usage
  client = SecurePerplexityClient()
  ```

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

  class SecurePerplexityClient {
      private primaryKey: string;
      private fallbackKey?: string;
      private currentClient: Perplexity;
      
      constructor(primaryKey?: string, fallbackKey?: string) {
          this.primaryKey = primaryKey || process.env.PERPLEXITY_API_KEY!;
          this.fallbackKey = fallbackKey || process.env.PERPLEXITY_API_KEY_FALLBACK;
          this.currentClient = new Perplexity({ apiKey: this.primaryKey });
      }
      
      private switchToFallback(): boolean {
          if (this.fallbackKey) {
              console.warn("Switching to fallback API key");
              this.currentClient = new Perplexity({ apiKey: this.fallbackKey });
              return true;
          }
          return false;
      }
      
      async search(query: string, options?: any) {
          try {
              return await this.currentClient.search.create({ query, ...options });
          } catch (error: any) {
              if (error.message.toLowerCase().includes('authentication') && this.switchToFallback()) {
                  return await this.currentClient.search.create({ query, ...options });
              }
              throw error;
          }
      }
  }

  // Usage
  const client = new SecurePerplexityClient();
  ```
</CodeGroup>

## Rate Limiting and Efficiency

### Intelligent Rate Limiting

Implement exponential backoff with jitter:

<CodeGroup>
  ```python Python theme={null}
  import time
  import random
  import asyncio
  from typing import TypeVar, Callable, Any
  import perplexity
  from perplexity import Perplexity

  T = TypeVar('T')

  class RateLimitedClient:
      def __init__(self, client: Perplexity, max_retries: int = 5):
          self.client = client
          self.max_retries = max_retries
      
      def _calculate_delay(self, attempt: int) -> float:
          """Calculate delay with exponential backoff and jitter"""
          base_delay = 2 ** attempt
          jitter = random.uniform(0.1, 0.5)
          return min(base_delay + jitter, 60.0)  # Cap at 60 seconds
      
      def with_retry(self, func: Callable[[], T]) -> T:
          """Execute function with intelligent retry logic"""
          last_exception = None
          
          for attempt in range(self.max_retries):
              try:
                  return func()
              except perplexity.RateLimitError as e:
                  last_exception = e
                  if attempt < self.max_retries - 1:
                      delay = self._calculate_delay(attempt)
                      print(f"Rate limited. Retrying in {delay:.2f}s (attempt {attempt + 1})")
                      time.sleep(delay)
                      continue
                  raise e
              except perplexity.APIConnectionError as e:
                  last_exception = e
                  if attempt < self.max_retries - 1:
                      delay = min(2 ** attempt, 10.0)  # Shorter delay for connection errors
                      print(f"Connection error. Retrying in {delay:.2f}s")
                      time.sleep(delay)
                      continue
                  raise e
          
          raise last_exception
      
      def search(self, query: str, **kwargs):
          return self.with_retry(
              lambda: self.client.search.create(query=query, **kwargs)
          )

  # Usage
  client = RateLimitedClient(Perplexity())
  result = client.search("artificial intelligence")
  ```

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

  class RateLimitedClient {
      private client: Perplexity;
      private maxRetries: number;
      
      constructor(client: Perplexity, maxRetries: number = 5) {
          this.client = client;
          this.maxRetries = maxRetries;
      }
      
      private calculateDelay(attempt: number): number {
          const baseDelay = 2 ** attempt * 1000; // Convert to milliseconds
          const jitter = Math.random() * 500; // 0-500ms jitter
          return Math.min(baseDelay + jitter, 60000); // Cap at 60 seconds
      }
      
      async withRetry<T>(func: () => Promise<T>): Promise<T> {
          let lastError: any;
          
          for (let attempt = 0; attempt < this.maxRetries; attempt++) {
              try {
                  return await func();
              } catch (error: any) {
                  lastError = error;
                  
                  if (error.constructor.name === 'RateLimitError') {
                      if (attempt < this.maxRetries - 1) {
                          const delay = this.calculateDelay(attempt);
                          console.log(`Rate limited. Retrying in ${delay}ms (attempt ${attempt + 1})`);
                          await new Promise(resolve => setTimeout(resolve, delay));
                          continue;
                      }
                  } else if (error.constructor.name === 'APIConnectionError') {
                      if (attempt < this.maxRetries - 1) {
                          const delay = Math.min(2 ** attempt * 1000, 10000);
                          console.log(`Connection error. Retrying in ${delay}ms`);
                          await new Promise(resolve => setTimeout(resolve, delay));
                          continue;
                      }
                  }
                  
                  throw error;
              }
          }
          
          throw lastError;
      }
      
      async search(query: string, options?: any) {
          return this.withRetry(() => 
              this.client.search.create({ query, ...options })
          );
      }
  }

  // Usage
  const client = new RateLimitedClient(new Perplexity());
  const result = await client.search("artificial intelligence");
  ```
</CodeGroup>

### Request Batching

Efficiently batch multiple requests:

<CodeGroup>
  ```python Python theme={null}
  import asyncio
  from typing import Callable, Awaitable, List, TypeVar, Generic
  from perplexity import AsyncPerplexity, DefaultAioHttpClient

  T = TypeVar('T')

  class BatchProcessor(Generic[T]):
      def __init__(self, batch_size: int = 5, delay_between_batches: float = 1.0):
          self.batch_size = batch_size
          self.delay_between_batches = delay_between_batches
      
      async def process_batch(
          self, 
          items: List[str], 
          process_func: Callable[[str], Awaitable[T]]
      ) -> List[T]:
          """Process items in batches with rate limiting"""
          results = []
          
          for i in range(0, len(items), self.batch_size):
              batch = items[i:i + self.batch_size]
              
              # Process batch concurrently
              tasks = [process_func(item) for item in batch]
              batch_results = await asyncio.gather(*tasks, return_exceptions=True)
              
              # Filter out exceptions and collect results
              for result in batch_results:
                  if not isinstance(result, Exception):
                      results.append(result)
              
              # Delay between batches
              if i + self.batch_size < len(items):
                  await asyncio.sleep(self.delay_between_batches)
          
          return results

  # Usage
  async def main():
      processor = BatchProcessor(batch_size=3, delay_between_batches=0.5)
      
      async with AsyncPerplexity(
          http_client=DefaultAioHttpClient()
      ) as client:
          
          async def search_query(query: str):
              return await client.search.create(query=query)
          
          queries = ["AI", "ML", "DL", "NLP", "CV"]
          results = await processor.process_batch(queries, search_query)
          
          print(f"Processed {len(results)} successful queries")

  asyncio.run(main())
  ```

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

  class BatchProcessor<T> {
      constructor(
          private batchSize: number = 5,
          private delayBetweenBatches: number = 1000
      ) {}
      
      async processBatch<R>(
          items: T[],
          processFunc: (item: T) => Promise<R>
      ): Promise<R[]> {
          const results: R[] = [];
          
          for (let i = 0; i < items.length; i += this.batchSize) {
              const batch = items.slice(i, i + this.batchSize);
              
              // Process batch concurrently
              const tasks = batch.map(item => 
                  processFunc(item).catch(error => error)
              );
              const batchResults = await Promise.all(tasks);
              
              // Filter out exceptions and collect results
              for (const result of batchResults) {
                  if (!(result instanceof Error)) {
                      results.push(result);
                  }
              }
              
              // Delay between batches
              if (i + this.batchSize < items.length) {
                  await new Promise(resolve => 
                      setTimeout(resolve, this.delayBetweenBatches)
                  );
              }
          }
          
          return results;
      }
  }

  // Usage
  async function main() {
      const processor = new BatchProcessor<string>(3, 500);
      const client = new Perplexity();
      
      const searchQuery = (query: string) => 
          client.search.create({ query });
      
      const queries = ["AI", "ML", "DL", "NLP", "CV"];
      const results = await processor.processBatch(queries, searchQuery);
      
      console.log(`Processed ${results.length} successful queries`);
  }

  main();
  ```
</CodeGroup>

## Production Configuration

### Configuration Management

Use environment-based configuration for different deployment stages:

<CodeGroup>
  ```python Python theme={null}
  import os
  from dataclasses import dataclass
  from typing import Optional
  import httpx
  from perplexity import Perplexity, DefaultHttpxClient

  @dataclass
  class PerplexityConfig:
      api_key: str
      max_retries: int = 3
      timeout_seconds: float = 30.0
      max_connections: int = 100
      max_keepalive: int = 20
      environment: str = "production"
      
      @classmethod
      def from_env(cls) -> "PerplexityConfig":
          """Load configuration from environment variables"""
          api_key = os.getenv("PERPLEXITY_API_KEY")
          if not api_key:
              raise ValueError("PERPLEXITY_API_KEY environment variable is required")
          
          return cls(
              api_key=api_key,
              max_retries=int(os.getenv("PERPLEXITY_MAX_RETRIES", "3")),
              timeout_seconds=float(os.getenv("PERPLEXITY_TIMEOUT", "30.0")),
              max_connections=int(os.getenv("PERPLEXITY_MAX_CONNECTIONS", "100")),
              max_keepalive=int(os.getenv("PERPLEXITY_MAX_KEEPALIVE", "20")),
              environment=os.getenv("ENVIRONMENT", "production")
          )
      
      def create_client(self) -> Perplexity:
          """Create optimized client based on configuration"""
          timeout = httpx.Timeout(
              connect=5.0,
              read=self.timeout_seconds,
              write=10.0,
              pool=10.0
          )
          
          limits = httpx.Limits(
              max_keepalive_connections=self.max_keepalive,
              max_connections=self.max_connections,
              keepalive_expiry=60.0 if self.environment == "production" else 30.0
          )
          
          return Perplexity(
              api_key=self.api_key,
              max_retries=self.max_retries,
              timeout=timeout,
              http_client=DefaultHttpxClient(limits=limits)
          )

  # Usage
  config = PerplexityConfig.from_env()
  client = config.create_client()
  ```

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

  interface PerplexityConfig {
      apiKey: string;
      maxRetries: number;
      timeoutMs: number;
      maxConnections: number;
      maxKeepalive: number;
      environment: string;
  }

  class ConfigManager {
      static fromEnv(): PerplexityConfig {
          const apiKey = process.env.PERPLEXITY_API_KEY;
          if (!apiKey) {
              throw new Error("PERPLEXITY_API_KEY environment variable is required");
          }
          
          return {
              apiKey,
              maxRetries: parseInt(process.env.PERPLEXITY_MAX_RETRIES || '3'),
              timeoutMs: parseInt(process.env.PERPLEXITY_TIMEOUT || '30000'),
              maxConnections: parseInt(process.env.PERPLEXITY_MAX_CONNECTIONS || '100'),
              maxKeepalive: parseInt(process.env.PERPLEXITY_MAX_KEEPALIVE || '20'),
              environment: process.env.NODE_ENV || 'production'
          };
      }
      
      static createClient(config: PerplexityConfig): Perplexity {
          const httpsAgent = new https.Agent({
              keepAlive: true,
              keepAliveMsecs: config.environment === 'production' ? 60000 : 30000,
              maxSockets: config.maxConnections,
              maxFreeSockets: config.maxKeepalive,
              timeout: config.timeoutMs
          });
          
          return new Perplexity({
              apiKey: config.apiKey,
              maxRetries: config.maxRetries,
              timeout: config.timeoutMs,
              httpAgent: httpsAgent
          } as any);
      }
  }

  // Usage
  const config = ConfigManager.fromEnv();
  const client = ConfigManager.createClient(config);
  ```
</CodeGroup>

### Monitoring and Logging

Implement comprehensive monitoring:

<CodeGroup>
  ```python Python theme={null}
  import logging
  import time
  import functools
  from typing import Any, Callable
  from perplexity import Perplexity
  import perplexity

  # Configure logging
  logging.basicConfig(
      level=logging.INFO,
      format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
  )
  logger = logging.getLogger(__name__)

  class MonitoredPerplexityClient:
      def __init__(self, client: Perplexity):
          self.client = client
          self.request_count = 0
          self.error_count = 0
          self.total_response_time = 0.0
      
      def _log_request(self, method: str, **kwargs):
          """Log request details"""
          self.request_count += 1
          logger.info(f"Making {method} request #{self.request_count}")
          logger.debug(f"Request parameters: {kwargs}")
      
      def _log_response(self, method: str, duration: float, success: bool = True):
          """Log response details"""
          self.total_response_time += duration
          avg_response_time = self.total_response_time / self.request_count
          
          if success:
              logger.info(f"{method} completed in {duration:.2f}s (avg: {avg_response_time:.2f}s)")
          else:
              self.error_count += 1
              logger.error(f"{method} failed after {duration:.2f}s (errors: {self.error_count})")
      
      def search(self, query: str, **kwargs):
          self._log_request("search", query=query, **kwargs)
          start_time = time.time()
          
          try:
              result = self.client.search.create(query=query, **kwargs)
              duration = time.time() - start_time
              self._log_response("search", duration, success=True)
              return result
          except Exception as e:
              duration = time.time() - start_time
              self._log_response("search", duration, success=False)
              logger.error(f"Search error: {type(e).__name__}: {e}")
              raise
      
      def get_stats(self):
          """Get client statistics"""
          return {
              "total_requests": self.request_count,
              "error_count": self.error_count,
              "success_rate": (self.request_count - self.error_count) / max(self.request_count, 1),
              "avg_response_time": self.total_response_time / max(self.request_count, 1)
          }

  # Usage
  client = MonitoredPerplexityClient(Perplexity())
  result = client.search("machine learning")
  print(client.get_stats())
  ```

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

  interface ClientStats {
      totalRequests: number;
      errorCount: number;
      successRate: number;
      avgResponseTime: number;
  }

  class MonitoredPerplexityClient {
      private client: Perplexity;
      private requestCount: number = 0;
      private errorCount: number = 0;
      private totalResponseTime: number = 0;
      
      constructor(client: Perplexity) {
          this.client = client;
      }
      
      private logRequest(method: string, params: any): void {
          this.requestCount++;
          console.log(`Making ${method} request #${this.requestCount}`);
          console.debug(`Request parameters:`, params);
      }
      
      private logResponse(method: string, duration: number, success: boolean = true): void {
          this.totalResponseTime += duration;
          const avgResponseTime = this.totalResponseTime / this.requestCount;
          
          if (success) {
              console.log(`${method} completed in ${duration.toFixed(2)}ms (avg: ${avgResponseTime.toFixed(2)}ms)`);
          } else {
              this.errorCount++;
              console.error(`${method} failed after ${duration.toFixed(2)}ms (errors: ${this.errorCount})`);
          }
      }
      
      async search(query: string, options?: any) {
          this.logRequest("search", { query, ...options });
          const startTime = performance.now();
          
          try {
              const result = await this.client.search.create({ query, ...options });
              const duration = performance.now() - startTime;
              this.logResponse("search", duration, true);
              return result;
          } catch (error) {
              const duration = performance.now() - startTime;
              this.logResponse("search", duration, false);
              console.error(`Search error: ${error}`);
              throw error;
          }
      }
      
      getStats(): ClientStats {
          return {
              totalRequests: this.requestCount,
              errorCount: this.errorCount,
              successRate: (this.requestCount - this.errorCount) / Math.max(this.requestCount, 1),
              avgResponseTime: this.totalResponseTime / Math.max(this.requestCount, 1)
          };
      }
  }

  // Usage
  const client = new MonitoredPerplexityClient(new Perplexity());
  const result = await client.search("machine learning");
  console.log(client.getStats());
  ```
</CodeGroup>

## Error Handling Best Practices

### Graceful Degradation

Implement fallback strategies for different error types:

<CodeGroup>
  ```python Python theme={null}
  from typing import Optional, Dict, Any
  import perplexity
  from perplexity import Perplexity

  class ResilientPerplexityClient:
      def __init__(self, client: Perplexity):
          self.client = client
          self.circuit_breaker_threshold = 5
          self.circuit_breaker_count = 0
          self.circuit_breaker_open = False
      
      def _should_circuit_break(self) -> bool:
          """Check if circuit breaker should be triggered"""
          return self.circuit_breaker_count >= self.circuit_breaker_threshold
      
      def _record_failure(self):
          """Record a failure for circuit breaker"""
          self.circuit_breaker_count += 1
          if self._should_circuit_break():
              self.circuit_breaker_open = True
              print("Circuit breaker activated - temporarily disabling API calls")
      
      def _record_success(self):
          """Record a success - reset circuit breaker"""
          self.circuit_breaker_count = 0
          self.circuit_breaker_open = False
      
      def search_with_fallback(
          self, 
          query: str, 
          fallback_response: Optional[Dict[str, Any]] = None
      ):
          """Search with graceful degradation"""
          if self.circuit_breaker_open:
              print("Circuit breaker open - returning fallback response")
              return fallback_response or {
                  "query": query,
                  "results": [],
                  "status": "service_unavailable"
              }
          
          try:
              result = self.client.search.create(query=query)
              self._record_success()
              return result
              
          except perplexity.RateLimitError:
              print("Rate limited - implementing backoff strategy")
              # Could implement intelligent backoff here
              raise
              
          except perplexity.APIConnectionError as e:
              print(f"Connection error: {e}")
              self._record_failure()
              return fallback_response or {
                  "query": query,
                  "results": [],
                  "status": "connection_error"
              }
              
          except Exception as e:
              print(f"Unexpected error: {e}")
              self._record_failure()
              return fallback_response or {
                  "query": query,
                  "results": [],
                  "status": "error"
              }

  # Usage
  client = ResilientPerplexityClient(Perplexity())
  result = client.search_with_fallback("machine learning")
  ```

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

  interface FallbackResponse {
      query: string;
      results: any[];
      status: string;
  }

  class ResilientPerplexityClient {
      private client: Perplexity;
      private circuitBreakerThreshold: number = 5;
      private circuitBreakerCount: number = 0;
      private circuitBreakerOpen: boolean = false;
      
      constructor(client: Perplexity) {
          this.client = client;
      }
      
      private shouldCircuitBreak(): boolean {
          return this.circuitBreakerCount >= this.circuitBreakerThreshold;
      }
      
      private recordFailure(): void {
          this.circuitBreakerCount++;
          if (this.shouldCircuitBreak()) {
              this.circuitBreakerOpen = true;
              console.log("Circuit breaker activated - temporarily disabling API calls");
          }
      }
      
      private recordSuccess(): void {
          this.circuitBreakerCount = 0;
          this.circuitBreakerOpen = false;
      }
      
      async searchWithFallback(
          query: string,
          fallbackResponse?: FallbackResponse
      ): Promise<any> {
          if (this.circuitBreakerOpen) {
              console.log("Circuit breaker open - returning fallback response");
              return fallbackResponse || {
                  query,
                  results: [],
                  status: "service_unavailable"
              };
          }
          
          try {
              const result = await this.client.search.create({ query });
              this.recordSuccess();
              return result;
              
          } catch (error: any) {
              if (error.constructor.name === 'RateLimitError') {
                  console.log("Rate limited - implementing backoff strategy");
                  throw error;
              } else if (error.constructor.name === 'APIConnectionError') {
                  console.log(`Connection error: ${error.message}`);
                  this.recordFailure();
                  return fallbackResponse || {
                      query,
                      results: [],
                      status: "connection_error"
                  };
              } else {
                  console.log(`Unexpected error: ${error.message}`);
                  this.recordFailure();
                  return fallbackResponse || {
                      query,
                      results: [],
                      status: "error"
                  };
              }
          }
      }
  }

  // Usage
  const client = new ResilientPerplexityClient(new Perplexity());
  const result = await client.searchWithFallback("machine learning");
  ```
</CodeGroup>

## Testing Best Practices

### Unit Testing with Mocking

Create testable code with proper mocking:

<CodeGroup>
  ```python Python theme={null}
  import unittest
  from unittest.mock import Mock, patch
  from perplexity import Perplexity, RateLimitError
  from perplexity.types.search_create_response import SearchCreateResponse, Result

  class TestPerplexityIntegration(unittest.TestCase):
      def setUp(self):
          self.mock_client = Mock(spec=Perplexity)

      def test_search_success(self):
          # Mock successful response
          mock_result = Result(
              title="Test Result",
              url="https://example.com",
              snippet="Test snippet"
          )

          mock_response = SearchCreateResponse(
              id="search_123",
              results=[mock_result]
          )

          self.mock_client.search.create.return_value = mock_response

          # Test your application logic
          result = self.mock_client.search.create(query="Perplexity Search API rate limit and retry handling example")

          self.assertEqual(result.id, "search_123")
          self.assertEqual(len(result.results), 1)
          self.assertEqual(result.results[0].title, "Test Result")

      @patch('perplexity.Perplexity')
      def test_rate_limit_handling(self, mock_perplexity_class):
          # Mock rate limit error
          mock_client = Mock()
          mock_perplexity_class.return_value = mock_client
          mock_client.search.create.side_effect = RateLimitError(
              "Rate limited",
              response=Mock(status_code=429),
              body={}
          )

          # Test your error handling logic here
          with self.assertRaises(RateLimitError):
              mock_client.search.create(query="Perplexity Search API Python SDK quickstart example")

  if __name__ == '__main__':
      unittest.main()
  ```

  ```typescript TypeScript theme={null}
  import { jest, describe, beforeEach, test, expect } from '@jest/globals';
  import Perplexity from '@perplexity-ai/perplexity_ai';

  // Mock the Perplexity client
  jest.mock('@perplexity-ai/perplexity_ai');

  describe('Perplexity Integration', () => {
      let mockClient: any;

      beforeEach(() => {
          mockClient = new Perplexity();
      });

      test('should handle successful search', async () => {
          const mockResponse = {
              id: "search_123",
              results: [{ title: "Test Result", url: "https://example.com", snippet: "Test snippet" }]
          };

          jest.spyOn(mockClient.search, 'create').mockResolvedValue(mockResponse as any);

          const result = await mockClient.search.create({ query: "Perplexity Search API rate limit and retry handling example" });

          expect(result.id).toBe("search_123");
          expect(result.results).toHaveLength(1);
          expect(result.results[0].title).toBe("Test Result");
      });

      test('should handle rate limit errors', async () => {
          const rateLimitError = new Error('Rate limited');

          jest.spyOn(mockClient.search, 'create').mockRejectedValue(rateLimitError);

          await expect(mockClient.search.create({ query: "Perplexity Search API Python SDK quickstart example" })).rejects.toThrow('Rate limited');
      });
  });
  ```
</CodeGroup>

<AccordionGroup>
  <Accordion title="Response — Perplexity Search API rate limit and retry handling example">
    ````json theme={null}
    {
      "id": "fc4a9702-2f8c-454c-bff5-04f63041aaa7",
      "results": [
        {
          "snippet": "",
          "title": "Best Practices",
          "url": "https://docs.perplexity.ai/docs/search/best-practices",
          "date": null,
          "last_updated": "2026-05-26"
        },
        {
          "snippet": "",
          "title": "Perplexity API: Setup, Models, Integration & Best Practices",
          "url": "https://zuplo.com/learning-center/perplexity-api",
          "date": "2025-03-28",
          "last_updated": "2026-05-24"
        },
        {
          "snippet": "I am getting a \" [429] Request rate limit exceeded, please try again later.\" error from make.com.\n...\nYou can try placing a sleep module before each ai module to wait 3-5 seconds.",
          "title": "How can i optimise the number of api calls, and cell ...",
          "url": "https://community.make.com/t/how-can-i-optimise-the-number-of-api-calls-and-cell-updates-in-this-scenario/49923",
          "date": "2024-08-07",
          "last_updated": "2026-05-16"
        },
        {
          "snippet": "## Search API Rate Limits\nThe Search API has separate rate limits that apply to all usage tiers:\n| Endpoint       | Rate Limit             | Burst Capacity |\n| -------------- | ---------------------- | -------------- |\n| POST `/search` | 50 requests per second | 50 requests    |\n**Search Rate Limiter Behavior:**\n* **Burst**: Can handle 50 requests instantly\n* **Sustained**: Exactly 50 QPS average over time\n<Note>\nSearch rate limits are independent of your usage tier and apply consistently across all accounts using the same leaky bucket algorithm.\n</Note>\n...\nWhen you exceed your rate limits:\n1. **429 Error** - Your request gets rejected with \"Too Many Requests\"\n2. **Continuous Refill** - Tokens refill continuously based on your rate limit\n3. **Immediate Recovery** - New requests become available as soon as tokens refill\n**Example Recovery Times:**\n* **50 QPS limit**: 1 token refills every 20ms\n* **500 QPS limit**: 1 token refills every 2ms\n* **1,000 QPS limit**: 1 token refills every 1ms\n...\nVisit the [API Platform console](https://console.perplexity.ai) to see your current tier and total spending.\n...\nAdd credits to your account through the billing section.\nYour tier will automatically upgrade once you reach the spending threshold.\n...\nYour new rate limits take effect immediately after the tier upgrade.\nCheck your settings page to confirm.\n...\nIf you require custom rate limits beyond Tier 5, [fill out our rate limit increase request form](https://perplexity.typeform.com/to/yctmfyVT) and we'll review your use case to accommodate your needs.",
          "title": "Rate Limits & Usage Tiers - Perplexity API",
          "url": "https://docs.perplexity.ai/docs/admin/rate-limits-usage-tiers",
          "date": null,
          "last_updated": "2026-05-26"
        },
        {
          "snippet": "",
          "title": "Best Practices",
          "url": "https://docs.perplexity.ai/docs/sdk/best-practices",
          "date": null,
          "last_updated": "2026-05-27"
        },
        {
          "snippet": "Use highly specific queries for more targeted results.\nFor example, instead of searching for “AI”, use a detailed query like “artificial intelligence machine learning healthcare applications 2024”.\n```\n# Better: Specific query\nsearch = client.search.create(\nquery=\"artificial intelligence medical diagnosis accuracy 2024\",\nmax_results=10\n)\n# Avoid: Vague query\nsearch = client.search.create(\nquery=\"AI medical\",\n...\n)\n```\n...\nBreak your main topic into related sub-queries to cover all aspects of your research.\nUse the multi-query search feature to run multiple related queries in a single request for more comprehensive and relevant information.\n```\n...\nclient = Perplexity()\n# Comprehensive research with related queries\nsearch = client.search.create(\n...\n)\n...\n```\nYou can include up to 5 queries in a single multi-query request for efficient batch processing.\n3\nHandle rate limits efficiently\nImplement exponential backoff for rate limit errors and use appropriate batching strategies.\n```\nimport time\nimport random\nfrom perplexity import RateLimitError\ndef search_with_retry(client, query, max_retries=3):\nfor attempt in range(max_retries):\ntry:\nreturn client.search.create(query=query)\nexcept RateLimitError:\nif attempt < max_retries - 1:\n# Exponential backoff with jitter\ndelay = (2 ** attempt) + random.uniform(0, 1)\ntime.sleep(delay)\nelse:\nraise\n# Usage\ntry:\nsearch = search_with_retry(client, \"AI developments\")\nfor result in search.results:\nprint(f\"{result.title}: {result.url}\")\nexcept RateLimitError:\nprint(\"Maximum retries exceeded for search\")\n```\n4\nProcess concurrent searches efficiently\nUse async for concurrent requests while respecting rate limits.\n```\nimport asyncio\nfrom perplexity import AsyncPerplexity\nasync def batch_search(queries, batch_size=3, delay_ms=1000):\nasync with AsyncPerplexity() as client:\nresults = []\nfor i in range(0, len(queries), batch_size):\nbatch = queries[i:i + batch_size]\nbatch_tasks = [\nclient.search.create(query=query, max_results=5)\nfor query in batch\n]\nbatch_results = await asyncio.gather(*batch_tasks)\nresults.extend(batch_results)\n# Add delay between batches\nif i + batch_size < len(queries):\nawait asyncio.sleep(delay_ms / 1000)\nreturn results\n# Usage\nqueries = [\"AI developments\", \"climate change\", \"space exploration\"]\nresults = asyncio.run(batch_search(queries))\nprint(f\"Processed {len(results)} searches\")\n```\n...\n#### Rate-Limited Concurrent Processing\nFor large-scale applications, implement controlled concurrency with rate limiting:\n```\nimport asyncio\nfrom perplexity import AsyncPerplexity\nclass SearchManager:\ndef __init__(self, max_concurrent=5, delay_between_batches=1.0):\nself.max_concurrent = max_concurrent\nself.delay_between_batches = delay_between_batches\nself.semaphore = asyncio.Semaphore(max_concurrent)\nasync def search_single(self, client, query):\nasync with self.semaphore:\nreturn await client.search.create(query=query, max_results=5)\nasync def search_many(self, queries):\nasync with AsyncPerplexity() as client:\ntasks = [\nself.search_single(client, query)\nfor query in queries\n]\nresults = await asyncio.gather(*tasks, return_exceptions=True)\n# Filter out exceptions and return successful results\nsuccessful_results = [\nresult for result in results\nif not isinstance(result, Exception)\n]\nreturn successful_results\n# Usage\nasync def main():\nmanager = SearchManager(max_concurrent=3)\nqueries = [\n\"AI research 2024\",\n\"quantum computing advances\",\n\"renewable energy innovations\",\n\"biotechnology breakthroughs\",\n\"space exploration updates\"\n]\nresults = await manager.search_many(queries)\nprint(f\"Successfully processed {len(results)} out of {len(queries)} searches\")\nasyncio.run(main())\n```\n#### Error Handling in Async Operations\nImplement robust error handling for async search operations:\n```\nimport asyncio\nimport logging\nfrom perplexity import AsyncPerplexity, APIStatusError, RateLimitError\nlogging.basicConfig(level=logging.INFO)\nlogger = logging.getLogger(__name__)\nasync def resilient_search(client, query, max_retries=3):\nfor attempt in range(max_retries):\ntry:\nresult = await client.search.create(query=query, max_results=5)\nlogger.info(f\"Search successful for: {query}\")\nreturn result\nexcept RateLimitError as e:\nif attempt < max_retries - 1:\ndelay = 2 ** attempt\nlogger.warning(f\"Rate limited for '{query}', retrying in {delay}s\")\nawait asyncio.sleep(delay)\nelse:\nlogger.error(f\"Max retries exceeded for: {query}\")\nreturn None\nexcept APIStatusError as e:\nlogger.error(f\"API error for '{query}': {e}\")\nreturn None\nexcept Exception as e:\nlogger.error(f\"Unexpected error for '{query}': {e}\")\nreturn None\nasync def main():\nasync with AsyncPerplexity() as client:\nqueries = [\"AI developments\", \"invalid query\", \"tech trends\"]\ntasks = [resilient_search(client, query) for query in queries]\nresults = await asyncio.gather(*tasks)\nsuccessful_results = [r for r in results if r is not None]\nprint(f\"Successful searches: {len(successful_results)}/{len(queries)}\")\nasyncio.run(main())\n```\n...\nRequest only the number of results you actually need.\nMore results = longer response times.\n...\nImplement caching for queries that don’t need real-time results.",
          "title": "Best Practices - Perplexity",
          "url": "https://docs.perplexity.ai/guides/search-best-practices",
          "date": "2025-10-09",
          "last_updated": "2026-05-10"
        },
        {
          "snippet": "",
          "title": "Fix Perplexity API Errors 429, 405, 500 | Complete Tutorial 2025",
          "url": "https://www.hostingseekers.com/blog/fix-perplexity-api-errors-tutorial/",
          "date": "2025-11-21",
          "last_updated": "2026-05-16"
        }
      ],
      "server_time": null
    }
    ````
  </Accordion>

  <Accordion title="Response — Perplexity Search API Python SDK quickstart example">
    ```json theme={null}
    {
      "id": "a3284d7c-f02c-45fc-82db-d368ad880edc",
      "results": [
        {
          "snippet": "",
          "title": "Quickstart - Perplexity API",
          "url": "https://docs.perplexity.ai/docs/getting-started/quickstart",
          "date": null,
          "last_updated": "2026-05-26"
        },
        {
          "snippet": "",
          "title": "Perplexity Search API",
          "url": "https://docs.perplexity.ai/docs/search/quickstart",
          "date": null,
          "last_updated": "2026-05-27"
        },
        {
          "snippet": "",
          "title": "Perplexity API",
          "url": "https://docs.perplexity.ai/docs/getting-started/overview",
          "date": null,
          "last_updated": "2026-05-26"
        },
        {
          "snippet": "",
          "title": "Perplexity Search APIdocs.perplexity.ai › guides › search-quickstart",
          "url": "https://docs.perplexity.ai/docs/search/quickstart.md",
          "date": null,
          "last_updated": "2026-05-27"
        },
        {
          "snippet": "### 2.\nSearch API Quickstart (Python & TypeScript SDKs)\nThe docs recommend using official SDKs for safety and type-safety; you can also call the HTTP endpoint directly (POST https://api.perplexity.ai/search) with an Authorization header.\nBelow is a minimal Python example that mirrors the documented pattern.\n#### Basic Python example (client.search.create)\n# Example (conceptual) — mirrors docs pattern\nfrom perplexity import Client  # hypothetical SDK import style\nclient = Client(api_key=”YOUR_API_KEY”)\nresp = client.search.create(\nquery=”latest AI model research 2025″,\nmax_results=5\n)\n# Example response shape (simplified):\n# resp.results -> [ { “title”: “…”, “url”: “…”, “snippet”: “…”, “rank”: 1 }, … ]\nprint(resp.results[0][“title”], resp.results[0][“url”])\nThis call returns ranked results you can present to users or feed into an LLM for grounded synthesis.\nIf you prefer raw HTTP the docs provide a curl example for POST /search.\n...\nStart with the quickstart, use multi-query for depth, control content with max_tokens_per_page, and organize keys and billing via API Groups.",
          "title": "Mastering the Perplexity AI API Documentation",
          "url": "https://seabuckdigital.com/perplexity-ai-api-documentation/",
          "date": "2025-11-08",
          "last_updated": "2026-04-08"
        },
      ],
      "server_time": null
    }
    ```
  </Accordion>
</AccordionGroup>

## Performance Best Practices Summary

<Steps>
  <Step title="Use environment variables for configuration">
    Never hardcode API keys or configuration values.
  </Step>

  <Step title="Implement intelligent rate limiting">
    Use exponential backoff with jitter for retry strategies.
  </Step>

  <Step title="Configure connection pooling">
    Optimize HTTP client settings for your use case.
  </Step>

  <Step title="Monitor and log appropriately">
    Track performance metrics and error rates.
  </Step>

  <Step title="Implement graceful degradation">
    Provide fallback responses when APIs are unavailable.
  </Step>

  <Step title="Write testable code">
    Use dependency injection and mocking for unit tests.
  </Step>
</Steps>

## Related Resources

<CardGroup>
  <Card title="Error Handling" icon="alert-triangle" href="/docs/sdk/error-handling">
    Comprehensive error handling strategies
  </Card>

  <Card title="Performance" icon="bolt" href="/docs/sdk/performance">
    Async operations and optimization techniques
  </Card>

  <Card title="Configuration" icon="settings" href="/docs/sdk/configuration">
    Production-ready configuration patterns
  </Card>

  <Card title="Type Safety" icon="shield-check" href="/docs/sdk/type-safety">
    Leveraging types for safer code
  </Card>
</CardGroup>


# Configuration
Source: https://docs.perplexity.ai/docs/sdk/configuration

Learn how to configure the Perplexity SDKs for retries, timeouts, proxies, and advanced HTTP client customization.

## Overview

The Perplexity SDKs provide extensive configuration options to customize client behavior for different environments and use cases. This guide covers retry configuration, timeout settings, and custom HTTP client setup.

## Retries and Timeouts

### Basic Retry Configuration

Configure how the SDK handles failed requests:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity
  import httpx

  client = Perplexity(
      max_retries=3,  # Default is 2
      timeout=httpx.Timeout(30.0, read=10.0, write=5.0, connect=2.0)
  )

  # Per-request configuration
  search = client.with_options(max_retries=5).search.create(
      query="example"
  )
  ```

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

  const client = new Perplexity({
      maxRetries: 3, // Default is 2
      timeout: 30000, // 30 seconds in milliseconds
  });

  // Per-request configuration
  const search = await client.withOptions({ maxRetries: 5 }).search.create({
      query: "example"
  });
  ```
</CodeGroup>

### Advanced Timeout Configuration

Set granular timeout controls for different phases of the request:

<CodeGroup>
  ```python Python theme={null}
  import httpx
  from perplexity import Perplexity

  # Detailed timeout configuration
  timeout_config = httpx.Timeout(
      connect=5.0,    # Time to establish connection
      read=30.0,      # Time to read response
      write=10.0,     # Time to send request
      pool=10.0       # Time to get connection from pool
  )

  client = Perplexity(timeout=timeout_config)

  # For long-running operations
  long_timeout = httpx.Timeout(
      connect=5.0,
      read=120.0,  # 2 minutes for complex queries
      write=10.0,
      pool=10.0
  )

  client_long = Perplexity(timeout=long_timeout)
  ```

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

  // Basic timeout (applies to entire request)
  const client = new Perplexity({
      timeout: 30000  // 30 seconds
  });

  // For long-running operations
  const clientLong = new Perplexity({
      timeout: 120000  // 2 minutes for complex queries
  });

  // Per-request timeout override
  const result = await client.withOptions({ 
      timeout: 60000  // 1 minute for this specific request
  }).responses.create({
      preset: "low",
      input: "Complex research query..."
  });
  ```
</CodeGroup>

## Custom HTTP Client

### Proxy Configuration

Configure the SDK to work with corporate proxies:

<CodeGroup>
  ```python Python theme={null}
  import httpx
  from perplexity import Perplexity, DefaultHttpxClient

  # HTTP Proxy
  client = Perplexity(
      http_client=DefaultHttpxClient(
          proxy="http://proxy.company.com:8080"
      )
  )

  # HTTPS Proxy with authentication
  client_auth = Perplexity(
      http_client=DefaultHttpxClient(
          proxy="http://username:password@proxy.company.com:8080"
      )
  )

  # SOCKS proxy
  client_socks = Perplexity(
      http_client=DefaultHttpxClient(
          proxy="socks5://proxy.company.com:1080"
      )
  )
  ```

  ```typescript TypeScript theme={null}
  import Perplexity from '@perplexity-ai/perplexity_ai';
  import { HttpsProxyAgent } from 'https-proxy-agent';
  import { SocksProxyAgent } from 'socks-proxy-agent';

  // HTTP/HTTPS Proxy
  const client = new Perplexity({
      httpAgent: new HttpsProxyAgent('http://proxy.company.com:8080')
  } as any);

  // Proxy with authentication
  const clientAuth = new Perplexity({
      httpAgent: new HttpsProxyAgent('http://username:password@proxy.company.com:8080')
  } as any);

  // SOCKS proxy
  const clientSocks = new Perplexity({
      httpAgent: new SocksProxyAgent('socks5://proxy.company.com:1080')
  } as any);
  ```
</CodeGroup>

### Custom Headers and User Agent

Add custom headers to all requests:

<CodeGroup>
  ```python Python theme={null}
  import httpx
  from perplexity import Perplexity, DefaultHttpxClient

  # Custom headers
  headers = {
      "User-Agent": "MyApp/1.0",
      "X-Custom-Header": "custom-value"
  }

  client = Perplexity(
      http_client=DefaultHttpxClient(
          headers=headers
      )
  )

  # Advanced HTTP client configuration
  transport = httpx.HTTPTransport(
      local_address="0.0.0.0",  # Bind to specific interface
      verify=True,              # SSL verification
      cert=None,                # Client certificate
      http2=True               # Enable HTTP/2
  )

  client_advanced = Perplexity(
      http_client=DefaultHttpxClient(
          transport=transport,
          headers=headers
      )
  )
  ```

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

  // Custom headers
  const client = new Perplexity({
      defaultHeaders: {
          "User-Agent": "MyApp/1.0",
          "X-Custom-Header": "custom-value"
      }
  });

  // Advanced fetch configuration
  const clientAdvanced = new Perplexity({
      fetch: (url, options) => {
          return fetch(url, {
              ...options,
              headers: {
                  ...options?.headers,
                  "User-Agent": "MyApp/1.0",
                  "X-Custom-Header": "custom-value"
              }
          });
      }
  });
  ```
</CodeGroup>

### SSL/TLS Configuration

Configure SSL verification and certificates:

<CodeGroup>
  ```python Python theme={null}
  import httpx
  import ssl
  from perplexity import Perplexity, DefaultHttpxClient

  # Disable SSL verification (not recommended for production)
  client_no_ssl = Perplexity(
      http_client=DefaultHttpxClient(
          verify=False
      )
  )

  # Custom SSL context
  ssl_context = ssl.create_default_context()
  ssl_context.check_hostname = False
  ssl_context.verify_mode = ssl.CERT_NONE

  client_custom_ssl = Perplexity(
      http_client=DefaultHttpxClient(
          verify=ssl_context
      )
  )

  # Client certificate authentication
  client_cert = Perplexity(
      http_client=DefaultHttpxClient(
          cert=("client.crt", "client.key")
      )
  )
  ```

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

  // Custom HTTPS agent with SSL options
  const httpsAgent = new https.Agent({
      rejectUnauthorized: false, // Disable SSL verification (not recommended)
      keepAlive: true,
      maxSockets: 50
  });

  const client = new Perplexity({
      httpAgent: httpsAgent
  } as any);

  // For Node.js environments with custom CA certificates
  const httpsAgentCA = new https.Agent({
      ca: ['/* your CA certificate PEM */'],
      cert: '/* client certificate PEM */',
      key: '/* client private key PEM */',
  } as any);

  const clientCert = new Perplexity({
      httpAgent: httpsAgentCA
  } as any);
  ```
</CodeGroup>

## Connection Pooling

Optimize performance with connection pooling:

<CodeGroup>
  ```python Python theme={null}
  import httpx
  from perplexity import Perplexity, DefaultHttpxClient

  # Configure connection limits
  limits = httpx.Limits(
      max_keepalive_connections=20,  # Keep-alive connections
      max_connections=100,           # Total connections
      keepalive_expiry=30.0         # Keep-alive timeout
  )

  client = Perplexity(
      http_client=DefaultHttpxClient(
          limits=limits
      )
  )

  # For high-throughput applications
  high_throughput_limits = httpx.Limits(
      max_keepalive_connections=100,
      max_connections=500,
      keepalive_expiry=60.0
  )

  client_high_throughput = Perplexity(
      http_client=DefaultHttpxClient(
          limits=high_throughput_limits
      )
  )
  ```

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

  // Configure agent pool settings
  const httpsAgent = new https.Agent({
      keepAlive: true,
      keepAliveMsecs: 30000,  // 30 seconds
      maxSockets: 50,         // Max connections per host
      maxFreeSockets: 10,     // Max idle connections per host
      timeout: 60000          // Socket timeout
  });

  const client = new Perplexity({
      httpAgent: httpsAgent
  } as any);

  // For high-throughput applications
  const highThroughputAgent = new https.Agent({
      keepAlive: true,
      keepAliveMsecs: 60000,
      maxSockets: 200,
      maxFreeSockets: 50,
      timeout: 120000
  });

  const clientHighThroughput = new Perplexity({
      httpAgent: highThroughputAgent
  } as any);
  ```
</CodeGroup>

## Environment-Specific Configuration

### Development Configuration

Settings optimized for development and debugging:

<CodeGroup>
  ```python Python theme={null}
  import httpx
  from perplexity import Perplexity, DefaultHttpxClient

  # Development configuration
  dev_client = Perplexity(
      max_retries=1,           # Fail fast in development
      timeout=httpx.Timeout(10.0),  # Short timeout
      http_client=DefaultHttpxClient(
          # Enable detailed logging
          event_hooks={
              'request': [lambda request: print(f"Request: {request.method} {request.url}")],
              'response': [lambda response: print(f"Response: {response.status_code}")]
          }
      )
  )
  ```

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

  // Development configuration
  const devClient = new Perplexity({
      maxRetries: 1,     // Fail fast in development
      timeout: 10000,    // 10 second timeout
      
      // Custom fetch with logging
      fetch: (url, options) => {
          console.log(`Request: ${options?.method || 'GET'} ${url}`);
          return fetch(url, options).then(response => {
              console.log(`Response: ${response.status}`);
              return response;
          });
      }
  });
  ```
</CodeGroup>

### Production Configuration

Settings optimized for production environments:

<CodeGroup>
  ```python Python theme={null}
  import httpx
  from perplexity import Perplexity, DefaultHttpxClient

  # Production configuration
  prod_limits = httpx.Limits(
      max_keepalive_connections=50,
      max_connections=200,
      keepalive_expiry=60.0
  )

  prod_timeout = httpx.Timeout(
      connect=5.0,
      read=60.0,
      write=10.0,
      pool=10.0
  )

  prod_client = Perplexity(
      max_retries=3,
      timeout=prod_timeout,
      http_client=DefaultHttpxClient(
          limits=prod_limits,
          verify=True,  # Always verify SSL in production
          http2=True    # Enable HTTP/2 for better performance
      )
  )
  ```

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

  // Production configuration
  const prodAgent = new https.Agent({
      keepAlive: true,
      keepAliveMsecs: 60000,
      maxSockets: 100,
      maxFreeSockets: 20,
      timeout: 60000
  });

  const prodClient = new Perplexity({
      maxRetries: 3,
      timeout: 60000,
      httpAgent: prodAgent
  } as any);
  ```
</CodeGroup>

## Configuration Patterns

### Environment-Based Configuration

Use environment variables to configure the client:

<CodeGroup>
  ```python Python theme={null}
  import os
  import httpx
  from perplexity import Perplexity, DefaultHttpxClient

  def create_client():
      # Base configuration
      timeout = httpx.Timeout(
          connect=float(os.getenv('PERPLEXITY_CONNECT_TIMEOUT', '5.0')),
          read=float(os.getenv('PERPLEXITY_READ_TIMEOUT', '30.0')),
          write=float(os.getenv('PERPLEXITY_WRITE_TIMEOUT', '10.0'))
      )
      
      max_retries = int(os.getenv('PERPLEXITY_MAX_RETRIES', '3'))
      
      # Optional proxy configuration
      proxy = os.getenv('PERPLEXITY_PROXY')
      http_client_kwargs = {}
      if proxy:
          http_client_kwargs['proxy'] = proxy
      
      return Perplexity(
          max_retries=max_retries,
          timeout=timeout,
          http_client=DefaultHttpxClient(**http_client_kwargs)
      )

  client = create_client()
  ```

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

  function createClient(): Perplexity {
      const maxRetries = parseInt(process.env.PERPLEXITY_MAX_RETRIES || '3');
      const timeout = parseInt(process.env.PERPLEXITY_TIMEOUT || '30000');
      
      const config: any = {
          maxRetries,
          timeout
      };
      
      // Optional proxy configuration
      if (process.env.PERPLEXITY_PROXY) {
          config.httpAgent = new HttpsProxyAgent(process.env.PERPLEXITY_PROXY);
      }
      
      return new Perplexity(config);
  }

  const client = createClient();
  ```
</CodeGroup>

### Configuration Factory

Create reusable configuration patterns:

<CodeGroup>
  ```python Python theme={null}
  import httpx
  from perplexity import Perplexity, DefaultHttpxClient

  class PerplexityClientFactory:
      @staticmethod
      def development():
          return Perplexity(
              max_retries=1,
              timeout=httpx.Timeout(10.0)
          )
      
      @staticmethod
      def production():
          return Perplexity(
              max_retries=3,
              timeout=httpx.Timeout(connect=5.0, read=60.0, write=10.0),
              http_client=DefaultHttpxClient(
                  limits=httpx.Limits(
                      max_keepalive_connections=50,
                      max_connections=200
                  )
              )
          )
      
      @staticmethod
      def high_throughput():
          return Perplexity(
              max_retries=2,
              timeout=httpx.Timeout(connect=2.0, read=30.0, write=5.0),
              http_client=DefaultHttpxClient(
                  limits=httpx.Limits(
                      max_keepalive_connections=100,
                      max_connections=500
                  )
              )
          )

  # Usage
  client = PerplexityClientFactory.production()
  ```

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

  class PerplexityClientFactory {
      static development(): Perplexity {
          return new Perplexity({
              maxRetries: 1,
              timeout: 10000
          });
      }
      
      static production(): Perplexity {
          const agent = new https.Agent({
              keepAlive: true,
              maxSockets: 100,
              timeout: 60000
          });
          
          return new Perplexity({
              maxRetries: 3,
              timeout: 60000,
              httpAgent: agent
          } as any);
      }
      
      static highThroughput(): Perplexity {
          const agent = new https.Agent({
              keepAlive: true,
              maxSockets: 500,
              maxFreeSockets: 100,
              timeout: 30000
          });
          
          return new Perplexity({
              maxRetries: 2,
              timeout: 30000,
              httpAgent: agent
          } as any);
      }
  }

  // Usage
  const client = PerplexityClientFactory.production();
  ```
</CodeGroup>

## Related Resources

<CardGroup>
  <Card title="Error Handling" icon="alert-triangle" href="/docs/sdk/error-handling">
    Handle timeouts and connection errors
  </Card>

  <Card title="Performance" icon="bolt" href="/docs/sdk/performance">
    Optimize async operations and connection pooling
  </Card>
</CardGroup>


# Error Handling
Source: https://docs.perplexity.ai/docs/sdk/error-handling

Learn how to handle API errors gracefully with the Perplexity SDKs for Python and TypeScript.

## Overview

The Perplexity SDKs provide robust error handling with specific exception types for different error scenarios. This guide covers how to catch and handle common API errors gracefully.

## Common Error Types

The SDKs provide specific exception types for different error scenarios:

* **APIConnectionError** - Network connection issues
* **RateLimitError** - API rate limit exceeded
* **APIStatusError** - HTTP status errors (4xx, 5xx)
* **AuthenticationError** - Invalid API key or authentication issues
* **ValidationError** - Invalid request parameters

## Basic Error Handling

Handle common API errors with try-catch blocks:

<CodeGroup>
  ```python Python theme={null}
  import perplexity
  from perplexity import Perplexity

  client = Perplexity()

  try:
      search = client.search.create(query="OpenAI o-series reasoning model benchmarks")
      print(search.results)
  except perplexity.APIConnectionError as e:
      print("Network connection failed")
      print(e.__cause__)
  except perplexity.RateLimitError as e:
      print("Rate limit exceeded, please retry later")
  except perplexity.APIStatusError as e:
      print(f"API error: {e.status_code}")
      print(e.response)
  ```

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

  const client = new Perplexity();

  try {
      const search = await client.search.create({ query: "OpenAI o-series reasoning model benchmarks" });
      console.log(search.results);
  } catch (error: any) {
      if (error.constructor.name === 'APIConnectionError') {
          console.log("Network connection failed");
          console.log(error.cause);
      } else if (error.constructor.name === 'RateLimitError') {
          console.log("Rate limit exceeded, please retry later");
      } else if (error.constructor.name === 'APIStatusError') {
          console.log(`API error: ${error.status}`);
          console.log(error.response);
      }
  }
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "169d5d3b-272a-46ca-a59d-7c218f9d5ce2",
    "results": [
      {
        "snippet": "",
        "title": "Reasoning best practices | OpenAI API",
        "url": "https://developers.openai.com/api/docs/guides/reasoning-best-practices",
        "date": null,
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "",
        "title": "A Comparative Study on Reasoning Patterns of OpenAI's o1 Model",
        "url": "https://arxiv.org/html/2410.13639v1",
        "date": "2024-10-17",
        "last_updated": "2026-03-22"
      },
      {
        "snippet": "**OpenAI o1** is a generative pre-trained transformer (GPT), the first in OpenAI's \"o\" series of reasoning models.\nA preview of o1 was released by OpenAI on September 12, 2024.\no1 spends time \"thinking\" before it answers, making it better at complex reasoning tasks, science and programming than GPT-4o.\nThe full version was released to ChatGPT users on December 5, 2024.\n...\nOpenAI noted that o1 is the first of a series of \"reasoning\" models.\nOpenAI shared in December 2024 benchmark results for its successor, o3 (the name o2 was skipped to avoid trademark conflict with the mobile carrier brand named O2).\n...\no1 spends additional time thinking (generating a chain of thought) before generating an answer, which makes it better for complex reasoning tasks, particularly in science and mathematics.\n...\nOpenAI's test results suggest a correlation between accuracy and the logarithm of the amount of compute spent thinking before answering.\no1-preview performed approximately at a PhD level on benchmark tests related to physics, chemistry, and biology.\nOn the American Invitational Mathematics Examination, it solved 83% (12.5/15) of the problems, compared to 13% (1.8/15) for GPT-4o.\nIt also ranked in the 89th percentile in Codeforces coding competitions.\no1-mini is faster and 80% cheaper than o1-preview.\nIt is particularly suitable for programming and STEM-related tasks, but does not have the same \"broad world knowledge\" as o1-preview.\nOpenAI noted that o1's reasoning capabilities make it better at adhering to safety rules provided in the prompt's context window.\n...\nAccording to OpenAI's assessments, o1-preview and o1-mini crossed into \"medium risk\" in CBRN (biological, chemical, radiological, and nuclear) weapons.\nDan Hendrycks wrote that \"The model already outperforms PhD scientists most of the time on answering questions related to bioweapons.\"\n...\nAccording to OpenAI, o1 may \"fake alignment\", that is, generate a response that is contrary to accuracy and its own chain of thought, in about 0.38% of cases.\n...\nBy changing the numbers and names used in a math problem or simply running the same problem again, LLMs would perform somewhat worse than their best benchmark results.\nAdding extraneous but logically inconsequential information to the problems caused a much greater drop in performance, from −17.5% for o1-preview and −29.1% for o1-mini, to −65.7% for the worst model tested.",
        "title": "OpenAI o1 - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/OpenAI_o1",
        "date": "2024-09-12",
        "last_updated": "2026-03-31"
      },
      {
        "snippet": "",
        "title": "OpenAI O3 & O4 Mini: The First True Reasoning Agents? - YouTube",
        "url": "https://www.youtube.com/watch?v=TGnPcObHdLY",
        "date": "2025-04-16",
        "last_updated": "2026-04-08"
      },
      {
        "snippet": "",
        "title": "Safety",
        "url": "https://openai.com/index/learning-to-reason-with-llms/",
        "date": "2024-09-12",
        "last_updated": "2026-03-29"
      },
      {
        "snippet": "",
        "title": "Introducing OpenAI o3 and o4-mini",
        "url": "https://openai.com/index/introducing-o3-and-o4-mini/",
        "date": "2025-04-16",
        "last_updated": "2026-05-16"
      },
      {
        "snippet": "",
        "title": "OpenAI's o3 model scores 3% on the ARC-AGI-2 benchmark ...",
        "url": "https://forum.effectivealtruism.org/posts/CoPNbwNqDai6orZhv/openai-s-o3-model-scores-3-on-the-arc-agi-2-benchmark",
        "date": "2025-05-01",
        "last_updated": "2026-05-17"
      },
      {
        "snippet": "Built to handle hard problems — they take more time to think before responding, similar to how a person would approach a difficult task.\nThe “ OpenAI o1 preview ” model, specifically, shows incredible results for various hard problems: math, coding, and reasoning.\n...\nToday, OpenAI released the full version of the o1 model, making it production-ready for a wide range of use cases.\nIn this article, we’ll compare its capabilities with GPT-4o and Claude 3.5 Sonnet to see if it lives up to the claim.\n...\nWe compared these models across three key tasks:\nReasoning riddles, Math Problems, and Classifying customer tickets\nAlong the way, we explored the latest benchmarks, evaluated input and output token costs, assessed latency and throughput, and shared guidance on choosing the best model for your needs.\nFor up-to-date rankings, check our leaderboard , or keep reading to see the results of our evaluation.\nFrom this analysis we learn that:\nProduction apps: For apps in productions, we still recommend sing GPT-4o over o1, at least for one-off tasks like the ones we tested here.\nReasoning riddles: OpenAI o1 showed some inconsistency, refusing to answer one question and scoring 60% accuracy, similar to GPT-4o, though the difference isn’t major.\nGPT-4o is a great model for this task.\nClaude 3.5 Sonnet scored a lower accuracy of 56%.\n- Math equations: GPT-4o and the o1 model performed equally well on this task, raising questions about whether the higher cost of o1 is justified.\n- Surprisingly, the latest Claude 3.5 Sonnet lagged significantly behind, achieving only 39% accuracy on these examples.\n- Classification : All models performed similarly: GPT-4o (74%), O1 (73%), and Model 3.5 Sonnet (76%), with GPT-4o improving by 12% since September.\n- GPT-4o had the highest precision (86%) making it ideal for tasks where correct possitive predictions matter most.\nThe o1 model led in recall (82%) making it suitable when you need to capture as many TRUE cases as possible.\nThe Claude 3.5 Sonnet had best F1 score (77%) indicating robust overall classification performance.\n- Speed &amp; Cost: Given that we saw similar results across the three tasks we evaluated, we still can’t justify the cost of o1, and we recommend going with GPT-4o for most use-cases.\n- Complex Problems: Use OpenAI o1 when you need top-tier reasoning and latency isn’t a concern.\nIt’s ideal for agentic workflows with a “planning” stage, where the model creates a detailed plan that smaller, cheaper models can follow\n...\nAs expected, the new o1 models are slower due to their “reasoning” process.\nThis isn’t a drawback necessarily—it just makes them better suited for tasks where thoughtful problem-solving is essential.\nOpenAI o1 is approximately 30 times slower than GPT-4o.\nSimilarly, the o1 mini version is around 16 times slower than GPT-4o mini.\n## Cost comparison\nIt's evident that using OpenAI o1 will cost roughly 6x more than GPT-4o and Claude 3.5 Sonnet for input tokens, and about 5x more for output tokens.\n## Throughput (Output speed)\nOpenAI o1 stands out with the fastest throughput, generating 143 tokens per second.\nHowever, take this throughput data with a grain of salt — while its output speed is significantly higher than the other models, its latency, or time-to-think, is about 30x longer than GPT-4o and Claude 3.5 Sonnet.\n...\nWhen new models are released, we learn about their capabilities from benchmark data reported in the technical reports.\nThe new OpenAI o1 model improves on the most complex reasoning benchmarks:\nExceeds human PhD-level accuracy on challenging benchmark tasks in physics, chemistry, and biology on the GPQA benchmark Coding is easier — It ranks in the 89th percentile on competitive programming questions (Codeforces) It’s also very good at math — In a qualifying exam for the International Mathematics Olympiad (IMO), GPT-4o correctly solved only 13% of problems, while the reasoning model scored 83%.\nNow, this is next level.\nOn the standard ML benchmarks , it has huge improvements across the board:\n...\nThey’ve gathered over 6,000 votes, and the results show that the OpenAI o1 model is consistently ranked #1 across all categories, with Math being the most notable area of impact.\nThe o1-mini model is #1 in technical areas, #2 overall.\nCheck out the full results on this link.\n...\nThe results show that the newest model is great at complex tasks, but not preferred for some natural language tasks — suggesting that maybe the model is not the best for every use-case.\n...\nGPT-4o and the o1 model performed equally well on this task, raising questions about whether the higher cost of o1 is justified.\nSurprisingly, the latest Claude 3.5 Sonnet lagged significantly behind, achieving only 39% accuracy on these examples.\n...\nOpenAI o1 showed some inconsistency, refusing to answer one question and scoring 60% accuracy, similar to GPT-4o, though the difference isn’t major.\nGPT-4o is a great model for this task.\nClaude 3.5 Sonnet scored a lower accuracy of 56%.\n...\nWe ran the evaluation to test if the models' outputs matched our ground truth data for 100 labeled test cases, and we can see that they all got similar accuracies.\nGPT-4o got 74, O1 got 73, Claude 3.5 Sonnet got 76 answers right from total of 100.\nThis reinforces the idea that smarter, more cost-effective models without a \"reasoning module\" like o1 can perform just as well as o1, but without the added expense.\nIn a similar evaluation in September of 2024, we evaluated that GPT-4o had lower accuracy, and classified only 62 of the 100 examples correctly.\nToday, we’re seeing at a 12% improvement on this task!\n...\nToday, O1 has more production-ready properties and is starting to becomemore valuable for production use cases—though it’s best suited for those who can tolerate higher latency and need to tackle the toughest challenges.\nGPT-4O, however, remains the go-to model for many of the production use cases we see in the market.",
        "title": "Analysis: OpenAI o1 vs GPT-4o vs Claude 3.5 Sonnet - Vellum",
        "url": "https://www.vellum.ai/blog/analysis-openai-o1-vs-gpt-4o",
        "date": "2024-12-17",
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "",
        "title": "THE RELATIONSHIP BETWEEN REASONING AND PERFORMANCE",
        "url": "http://arxiv.org/pdf/2502.15631.pdf",
        "date": null,
        "last_updated": "2025-02-25"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

<Info>
  Common HTTP status codes: 400 (Bad Request), 401 (Authentication), 403 (Permission Denied), 404 (Not Found), 429 (Rate Limit), 500+ (Server Error).
</Info>

## Advanced Error Handling

### Exponential Backoff for Rate Limits

Implement intelligent retry logic for rate limit errors:

<CodeGroup>
  ```python Python theme={null}
  import time
  import random
  import perplexity
  from perplexity import Perplexity

  def search_with_retry(client, query, max_retries=3):
      for attempt in range(max_retries):
          try:
              return client.search.create(query=query)
          except perplexity.RateLimitError:
              if attempt == max_retries - 1:
                  raise  # Re-raise on final attempt
              
              # Exponential backoff with jitter
              delay = (2 ** attempt) + random.uniform(0, 1)
              print(f"Rate limited. Retrying in {delay:.2f} seconds...")
              time.sleep(delay)
          except perplexity.APIConnectionError:
              if attempt == max_retries - 1:
                  raise
              
              # Shorter delay for connection errors
              delay = 1 + random.uniform(0, 1)
              print(f"Connection error. Retrying in {delay:.2f} seconds...")
              time.sleep(delay)

  # Usage
  client = Perplexity()
  result = search_with_retry(client, "artificial intelligence")
  ```

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

  async function searchWithRetry(
      client: Perplexity, 
      query: string, 
      maxRetries: number = 3
  ) {
      for (let attempt = 0; attempt < maxRetries; attempt++) {
          try {
              return await client.search.create({ query });
          } catch (error: any) {
              if (attempt === maxRetries - 1) {
                  throw error; // Re-throw on final attempt
              }

              if (error.constructor.name === 'RateLimitError') {
                  // Exponential backoff with jitter
                  const delay = (2 ** attempt + Math.random()) * 1000;
                  console.log(`Rate limited. Retrying in ${delay}ms...`);
                  await new Promise(resolve => setTimeout(resolve, delay));
              } else if (error.constructor.name === 'APIConnectionError') {
                  // Shorter delay for connection errors
                  const delay = (1 + Math.random()) * 1000;
                  console.log(`Connection error. Retrying in ${delay}ms...`);
                  await new Promise(resolve => setTimeout(resolve, delay));
              } else {
                  throw error; // Don't retry other errors
              }
          }
      }
  }

  // Usage
  const client = new Perplexity();
  const result = await searchWithRetry(client, "artificial intelligence");
  ```
</CodeGroup>

### Error Context and Debugging

Extract detailed error information for debugging:

<CodeGroup>
  ```python Python theme={null}
  import perplexity
  from perplexity import Perplexity

  client = Perplexity()

  try:
      response = client.responses.create(
          preset="low",
          input="Explain how the 10-year US Treasury yield is determined and how it influences mortgage rates."
      )
  except perplexity.APIStatusError as e:
      print(f"Status Code: {e.status_code}")
      print(f"Error Type: {e.type}")
      print(f"Error Message: {e.message}")
      
      # Access raw response for detailed debugging
      if hasattr(e, 'response'):
          print(f"Raw Response: {e.response.text}")
          print(f"Request ID: {e.response.headers.get('X-Request-ID')}")
          
  except perplexity.ValidationError as e:
      print(f"Validation Error: {e}")
      # Handle parameter validation errors
      
  except Exception as e:
      print(f"Unexpected error: {type(e).__name__}: {e}")
  ```

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

  const client = new Perplexity();

  try {
      const response = await client.responses.create({
          preset: "low",
          input: "Explain how the 10-year US Treasury yield is determined and how it influences mortgage rates."
      });
  } catch (error: any) {
      if (error.constructor.name === 'APIStatusError') {
          console.log(`Status Code: ${error.status}`);
          console.log(`Error Type: ${error.type}`);
          console.log(`Error Message: ${error.message}`);
          
          // Access raw response for detailed debugging
          if (error.response) {
              console.log(`Raw Response: ${await error.response.text()}`);
              console.log(`Request ID: ${error.response.headers.get('X-Request-ID')}`);
          }
      } else if (error.constructor.name === 'ValidationError') {
          console.log(`Validation Error: ${error.message}`);
          // Handle parameter validation errors
      } else {
          console.log(`Unexpected error: ${error.constructor.name}: ${error.message}`);
      }
  }
  ```
</CodeGroup>

## Error Recovery Strategies

### Graceful Degradation

Implement fallback mechanisms when API calls fail:

<CodeGroup>
  ```python Python theme={null}
  import perplexity
  from perplexity import Perplexity

  def get_ai_response(query, fallback_response="I'm sorry, I'm temporarily unavailable."):
      client = Perplexity()
      
      try:
          response = client.responses.create(
              preset="low",
              input=query
          )
          return response.output_text
          
      except perplexity.RateLimitError:
          return fallback_response
              
      except perplexity.APIConnectionError:
          # Network issues - return cached response or fallback
          return fallback_response
          
      except Exception as e:
          print(f"Unexpected error: {e}")
          return fallback_response

  # Usage
  response = get_ai_response("What is machine learning?")
  print(response)
  ```

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

  async function getAIResponse(
      query: string, 
      fallbackResponse: string = "I'm sorry, I'm temporarily unavailable."
  ): Promise<string> {
      const client = new Perplexity();
      
      try {
          const response = await client.responses.create({
              preset: "low",
              input: query
          });
          return response.output_text ?? fallbackResponse;
          
      } catch (error: any) {
          if (error.constructor.name === 'RateLimitError') {
              return fallbackResponse;
          } else if (error.constructor.name === 'APIConnectionError') {
              // Network issues - return cached response or fallback
              return fallbackResponse;
          } else {
              console.log(`Unexpected error: ${error.message}`);
              return fallbackResponse;
          }
      }
  }

  // Usage
  const response = await getAIResponse("What is machine learning?");
  console.log(response);
  ```
</CodeGroup>

## Best Practices

<Steps>
  <Step title="Always handle rate limits">
    Rate limiting is common with API usage. Always implement retry logic with exponential backoff.

    <Warning>
      Don't implement aggressive retry loops without delays - this can worsen rate limiting.
    </Warning>
  </Step>

  <Step title="Log errors for monitoring">
    Include proper logging to track error patterns and API health.

    <CodeGroup>
      ```python Python theme={null}
      import logging
      import perplexity
      from perplexity import Perplexity

      logging.basicConfig(level=logging.INFO)
      logger = logging.getLogger(__name__)

      client = Perplexity()

      try:
          result = client.search.create(query="discovery of penicillin by Alexander Fleming")
      except perplexity.APIStatusError as e:
          logger.error(f"API Error {e.status_code}: {e.message}", 
                      extra={'request_id': e.response.headers.get('X-Request-ID')})
      ```

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

      const client = new Perplexity();

      try {
          const result = await client.search.create({ query: "discovery of penicillin by Alexander Fleming" });
      } catch (error: any) {
          console.error(`API Error ${error.status}: ${error.message}`, {
              requestId: error.response?.headers.get('X-Request-ID')
          });
      }
      ```
    </CodeGroup>

    <Accordion title="Response">
      ```json theme={null}
      {
        "id": "cf46c6eb-bf6e-4ee4-97f8-9d4dcfd99dd4",
        "results": [
          {
            "snippet": "",
            "title": "Alexander Fleming Discovery and Development of Penicillin",
            "url": "https://www.acs.org/education/whatischemistry/landmarks/flemingpenicillin.html",
            "date": null,
            "last_updated": "2026-05-21"
          },
          {
            "snippet": "“*I did not invent penicillin.\nNature did that.\nI only discovered it by accident*.”\nAlexander Fleming was a Scottish physician-scientist who was recognised for discovering penicillin.\nThe simple discovery and use of the antibiotic agent has saved millions of lives, and earned Fleming – together with Howard Florey and Ernst Chain, who devised methods for the large-scale isolation and production of penicillin – the 1945 Nobel Prize in Physiology/Medicine.\n...\nIn 1928, Fleming began a series of experiments involving the common staphylococcal bacteria.\nAn uncovered Petri dish sitting next to an open window became contaminated with mould spores.\nFleming observed that the bacteria in proximity to the mould colonies were dying, as evidenced by the dissolving and clearing of the surrounding agar gel.\nHe was able to isolate the mould and identified it as a member of the *Penicillium* genus.\nHe found it to be effective against all Gram-positive pathogens, which are responsible for diseases such as scarlet fever, pneumonia, gonorrhoea, meningitis and diphtheria.\nHe discerned that it was not the mould itself but some ‘juice’ it had produced that had killed the bacteria.\nHe named the ‘mould juice’ penicillin.\nLater, he would say: “*When I woke up just after dawn on September 28, 1928, I certainly didn’t plan to revolutionize all medicine by discovering the world’s first antibiotic, or bacteria killer.\nBut I suppose that was exactly what I did*.”\nAlthough Fleming published the discovery of penicillin in the British Journal of Experimental Pathology in 1929, the scientific community greeted his work with little initial enthusiasm.\nAdditionally, Fleming found it difficult to isolate this precious ‘mould juice’ in large quantities.\nIt was not until 1940, just as he was contemplating retirement, that two scientists, Howard Florey and Ernst Chain, became interested in penicillin.\nIn time, they were able to mass-produce it for use during World War II.",
            "title": "Alexander Fleming (1881–1955): Discoverer of penicillin - PMC - NIH",
            "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC4520913/",
            "date": null,
            "last_updated": "2026-04-11"
          },
          {
            "snippet": "",
            "title": "Alexander Fleming - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/Alexander_Fleming",
            "date": "2001-09-18",
            "last_updated": "2026-05-18"
          },
          {
            "snippet": "",
            "title": "Discovery of penicillin - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/Discovery_of_penicillin",
            "date": "2009-09-13",
            "last_updated": "2026-03-28"
          },
          {
            "snippet": "",
            "title": "The Discovery of Penicillin—New Insights After More Than 75 Years ...",
            "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC5403050/",
            "date": null,
            "last_updated": "2026-03-29"
          },
          {
            "snippet": "The accidental discovery of a mouldy petri-dish in 1928 kickstarted a 20-year long journey to develop the world’s first mass produced drug that could clear a bacterial infection; penicillin.\n...\nIn 1928 Dr Alexander Fleming returned from a holiday to find mould growing on a Petri dish of Staphylococcus bacteria.\nHe noticed the mould seemed to be preventing the bacteria around it from growing.\nHe soon identified that the mould produced a self-defence chemical that could kill bacteria.\nHe named the substance penicillin.\nFleming published his findings and presented his discovery to the Medical Research Club.\nTo his surprise, his peers showed little interest in his work.\n...\nNearly ten years later in 1937, while investigating microorganisms and the substances they produced, Howard Florey and Ernst Chain uncovered Fleming’s research and assembled a team of scientists to work solely on the 'Penicillin Project'.\n...\nThe mould produced six times more penicillin than Fleming’s original strain.\n...\nBy 1943, the US had sufficient penicillin stocks to satisfy the demands of the Armed Forces of the United States, as well as their Allies.\n...\nIn 1946 penicillin became available for the first time in the UK for public use, it transformed medicine worldwide and ushered in the age of antibiotics.",
            "title": "How was penicillin developed?",
            "url": "https://www.sciencemuseum.org.uk/objects-and-stories/how-was-penicillin-developed",
            "date": "2021-02-23",
            "last_updated": "2025-11-10"
          },
          {
            "snippet": "Eighty-three years ago today, Sir Alexander Fleming discovered penicillin, one of the most widely used antibiotics.\nInspired by what he saw on the battlefields of World War I, he went back to his laboratory at St. Mary’s Hospital in London to develop a way to fight bacterial infections.\nIn 1928, he accidentally left a petri dish in which he was growing Staphylococcus aureus bacteria uncovered.\nLater, he noticed that there was mold growing on the plate, and around the mold, the staph bacteria were dead.\nFleming isolated it and identified the mold as Penicillium notatum, a type of fungus that is similar to the mold that grows on bread.\nFleming published his findings in the British Journal of Experimental Pathology in 1929, but the report didn’t garner much interest.\nThen in 1938, Ernst Chain, a biochemist working with pathologist Howard Florey at Oxford University, came across Fleming’s paper while he was researching antibacterial compounds.\nScientists in Florey’s lab started working with penicillin, which they eventually injected into mice to test if it could treat bacterial infections.\nTheir experiments were successful and they went on to test it in humans, where they also saw positive results.\nBy 1941, there was an injectable form that could be used to treat patients, which was especially useful for soldiers fighting in World War II.\n...\nIn 1945, Fleming, Chain and Florey were awarded the Nobel Prize in Physiology or Medicine for “the discovery of penicillin and its curative effects in various infectious diseases”.\nFleming died in 1955.",
            "title": "Penicillin: 83 Years Ago Today",
            "url": "https://www.publichealth.columbia.edu/research/center-infection-and-immunity/penicillin-83-years-ago-today",
            "date": "2015-10-16",
            "last_updated": "2026-03-12"
          },
          {
            "snippet": "",
            "title": "History of penicillin - Wikipedia",
            "url": "https://en.wikipedia.org/wiki/History_of_penicillin",
            "date": "2006-03-31",
            "last_updated": "2026-04-08"
          },
          {
            "snippet": "Scottish bacteriologist Alexander Fleming is best known for his discovery of penicillin in 1928, which started the antibiotic revolution.\nFor his discovery of penicillin, he was awarded a share of the 1945 Nobel Prize for Physiology or Medicine.\n### How did Alexander Fleming discover penicillin?\nIn 1928 Alexander Fleming noticed that a culture plate of *Staphylococcus aureus* bacteria had become contaminated by a fungus.\nThe mold, later identified as *Penicillium notatum* (now classified as *P. chrysogenum*), had inhibited the growth of the bacteria.\nHe later established that the mold prevented bacterial growth because it produced an antibiotic, penicillin.\n...\n**Alexander Fleming** (born August 6, 1881, Lochfield Farm, Darvel, Ayrshire, Scotland—died March 11, 1955, London, England) was a Scottish bacteriologist best known for his discovery of penicillin.\n...\nHis work on wound infection and lysozyme, an antibacterial enzyme found in tears and saliva, guaranteed him a place in the history of bacteriology.\nBut it was his discovery of penicillin in 1928, which started the antibiotic revolution, that sealed his lasting reputation.\nFleming was recognized for that achievement in 1945, when he received the Nobel Prize for Physiology or Medicine, along with Australian pathologist Howard Walter Florey and German-born British biochemist Ernst Boris Chain, both of whom isolated and purified penicillin.\n...\nOn September 3, 1928, shortly after his appointment as professor of bacteriology, Fleming noticed that a culture plate of *Staphylococcus aureus* he had been working on had become contaminated by a fungus.\nA mold, later identified as *Penicillium notatum* (now classified as *P. chrysogenum*), had inhibited the growth of the bacteria.\nHe at first called the substance “mould juice” and then “penicillin,” after the mold that produced it.\nFleming decided to investigate further, because he thought that he had found an enzyme more potent than lysozyme.\nIn fact, it was not an enzyme but an antibiotic—one of the first to be discovered.\n...\nPenicillin eventually came into use during World War II as the result of the work of a team of scientists led by Howard Florey at the University of Oxford.",
            "title": "Alexander Fleming | Biography, Education, Discovery, Nobel Prize ...",
            "url": "https://www.britannica.com/biography/Alexander-Fleming",
            "date": "2026-04-24",
            "last_updated": "2026-04-25"
          },
          {
            "snippet": "Fleming’s serendipitous discovery of penicillin changed the course of medicine and earned him a Nobel Prize.\n...\nIn 1928 Alexander Fleming (1881–1955) discovered penicillin, though he did not realize the full significance of his discovery for at least another decade.\nHe eventually received the Nobel Prize in Physiology or Medicine in 1945.\n...\nIn 1928 Alexander Fleming discovered penicillin, made from the *Penicillium notatum* mold, but he did not receive the Nobel Prize in Physiology or Medicine for his discovery until 1945.\nFleming himself did not realize how important his discovery was; for a decade after, he focused instead on penicillin’s potential use as a topical antiseptic for wounds and surface infections and as a means of isolating certain bacteria in laboratory cultures.\n...\nFleming’s legendary discovery of penicillin occurred in 1928, while he was investigating staphylococcus, a common type of bacteria that causes boils and can also cause disastrous infections in patients with weakened immune systems.\nBefore Fleming left for a two-week vacation, a petri dish containing a staphylococcus culture was left on a lab bench and never placed in the incubator as intended.\nSomehow, in preparing the culture, a *Penicillium* mold spore had been accidentally introduced into the medium—perhaps coming in through a window, or more likely floating up a stairwell from the lab below where various molds were being cultured.\nThe temperature conditions that prevailed during Fleming’s absence permitted both the bacteria and the mold spores to grow; had the incubator been used, only the bacteria could have grown.\n...\nHe discovered that the antibacterial substance was not produced by all molds, only by certain strains of *Penicillium*, namely, *Penicillium notatum*.",
            "title": "Alexander Fleming | Science History Institute",
            "url": "https://www.sciencehistory.org/education/scientific-biographies/alexander-fleming/",
            "date": "2026-02-23",
            "last_updated": "2026-05-07"
          }
        ],
        "server_time": null
      }
      ```
    </Accordion>
  </Step>

  <Step title="Set appropriate timeouts">
    Configure timeouts to prevent hanging requests.

    <CodeGroup>
      ```python Python theme={null}
      import httpx
      from perplexity import Perplexity

      client = Perplexity(
          timeout=httpx.Timeout(connect=5.0, read=30.0, write=5.0, pool=10.0)
      )
      ```

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

      const client = new Perplexity({
          timeout: 30000 // 30 seconds
      });
      ```
    </CodeGroup>
  </Step>

  <Step title="Handle authentication errors">
    Check for invalid API keys and provide helpful error messages.

    <CodeGroup>
      ```python Python theme={null}
      try:
          result = client.search.create(query="Perplexity Search API Python SDK quickstart example")
      except perplexity.AuthenticationError:
          print("Invalid API key. Please check your PERPLEXITY_API_KEY environment variable.")
      ```

      ```typescript TypeScript theme={null}
      try {
          const result = await client.search.create({ query: "Perplexity Search API Python SDK quickstart example" });
      } catch (error: any) {
          if (error.constructor.name === 'AuthenticationError') {
              console.log("Invalid API key. Please check your PERPLEXITY_API_KEY environment variable.");
          }
      }
      ```
    </CodeGroup>
  </Step>
</Steps>

## Related Resources

<CardGroup>
  <Card title="Configuration" icon="settings" href="/docs/sdk/configuration">
    Configure timeouts and retries
  </Card>

  <Card title="Best Practices" icon="star" href="/docs/sdk/best-practices">
    Environment variables and rate limiting
  </Card>
</CardGroup>


# Quickstart
Source: https://docs.perplexity.ai/docs/sdk/overview

Learn how to use the official Perplexity SDKs for Python and TypeScript to access the Perplexity APIs with type safety and async support.

## Overview

The official Perplexity SDKs provide convenient access to the Perplexity APIs from Python 3.8+ and Node.js applications. Both SDKs include type definitions for all request parameters and response fields, with both synchronous and asynchronous clients.

Access four APIs: **Agent API** for third-party models with web search tools and presets, **Search** for ranked web search results, **Sonar** for web-grounded AI responses, and **Embeddings** for generating text embeddings.

## Available APIs

<CardGroup>
  <Card title="Agent API" icon="code-circle" href="/docs/agent-api/quickstart">
    Third-party models from OpenAI, Anthropic, Google, and more with presets and web search tools.
  </Card>

  <Card title="Search" icon="search" href="/docs/search/quickstart">
    Ranked web search results with filtering, multi-query support, and domain controls.
  </Card>

  <Card title="Sonar" icon="message" href="/docs/sonar/quickstart">
    AI responses with web-grounded knowledge, conversation context, and streaming support.
  </Card>

  <Card title="Embeddings" icon="cube" href="/docs/embeddings/quickstart">
    Generate high-quality text embeddings for semantic search and RAG.
  </Card>
</CardGroup>

## Installation

Install the SDK for your preferred language:

<CodeGroup>
  ```bash Python theme={null}
  pip install perplexityai
  ```

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

## Authentication

<Card title="Get your Perplexity API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate a new key on the **API Keys** page in the API Console.
</Card>

After generating the key, set it as an environment variable in your terminal:

<Tabs>
  <Tab title="Windows">
    ```bash theme={null}
    setx PERPLEXITY_API_KEY "your_api_key_here"
    ```
  </Tab>

  <Tab title="MacOS/Linux">
    ```bash theme={null}
    export PERPLEXITY_API_KEY="your_api_key_here"
    ```
  </Tab>
</Tabs>

### Using Environment Variables

You can use the environment variable directly:

<CodeGroup>
  ```python Python theme={null}
  import os
  from perplexity import Perplexity

  client = Perplexity() # Automatically uses PERPLEXITY_API_KEY
  ```

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

  const client = new Perplexity({
    apiKey: process.env['PERPLEXITY_API_KEY'], // This is the default and can be omitted
  });
  ```
</CodeGroup>

Or use [python-dotenv](https://pypi.org/project/python-dotenv/) (Python) or [dotenv](https://www.npmjs.com/package/dotenv) (Node.js) to load the environment variable from a `.env` file:

<CodeGroup>
  ```python Python theme={null}
  import os
  from dotenv import load_dotenv
  from perplexity import Perplexity

  load_dotenv()

  client = Perplexity() # Uses PERPLEXITY_API_KEY from .env file
  ```

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

  dotenv.config();

  const client = new Perplexity(); // Uses PERPLEXITY_API_KEY from .env file
  ```
</CodeGroup>

<Tip>
  Now you're ready to start using the Perplexity APIs! Choose your API below for step-by-step usage guides.
</Tip>

<CardGroup>
  <Card title="Agent API" icon="code-circle" href="/docs/agent-api/quickstart">
    Get started with third-party models
  </Card>

  <Card title="Search" icon="search" href="/docs/search/quickstart">
    Get started with web search
  </Card>

  <Card title="Sonar" icon="message" href="/docs/sonar/quickstart">
    Get started with AI responses
  </Card>

  <Card title="Embeddings" icon="cube" href="/docs/embeddings/quickstart">
    Get started with text embeddings
  </Card>
</CardGroup>

## Resources

<CardGroup>
  <Card title="Python Package" icon="brand-python" href="https://pypi.org/project/perplexityai/">
    Install from PyPI with pip
  </Card>

  <Card title="Node.js and TypeScript Package" icon="brand-npm" href="https://www.npmjs.com/package/@perplexity-ai/perplexity_ai">
    Install from npm registry
  </Card>
</CardGroup>


# Performance Optimization
Source: https://docs.perplexity.ai/docs/sdk/performance

Learn how to optimize the Perplexity SDKs for high-throughput applications with async support, connection pooling, and raw response access.

## Overview

The Perplexity SDKs provide several features to optimize performance for high-throughput applications. This guide covers async operations, connection pooling, raw response access, and other performance optimization techniques.

## Async Support

### Basic Async Usage

For applications that need to handle multiple requests concurrently:

<CodeGroup>
  ```bash Python Installation theme={null}
  pip install perplexityai httpx-aiohttp
  ```

  ```bash TypeScript Installation theme={null}
  npm install @perplexity-ai/perplexity_ai
  # Async support is built-in with TypeScript
  ```
</CodeGroup>

<CodeGroup>
  ```python Python theme={null}
  import asyncio
  from perplexity import AsyncPerplexity, DefaultAioHttpClient

  async def main():
      async with AsyncPerplexity(
          http_client=DefaultAioHttpClient()
      ) as client:
          # Single async request
          search = await client.search.create(query="OpenAI o-series reasoning model benchmarks")
          print(search.results)

  asyncio.run(main())
  ```

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

  async function main() {
      const client = new Perplexity();
      
      // Async is built-in for TypeScript
      const search = await client.search.create({ query: "OpenAI o-series reasoning model benchmarks" });
      console.log(search.results);
  }

  main();
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "169d5d3b-272a-46ca-a59d-7c218f9d5ce2",
    "results": [
      {
        "snippet": "",
        "title": "Reasoning best practices | OpenAI API",
        "url": "https://developers.openai.com/api/docs/guides/reasoning-best-practices",
        "date": null,
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "",
        "title": "A Comparative Study on Reasoning Patterns of OpenAI's o1 Model",
        "url": "https://arxiv.org/html/2410.13639v1",
        "date": "2024-10-17",
        "last_updated": "2026-03-22"
      },
      {
        "snippet": "**OpenAI o1** is a generative pre-trained transformer (GPT), the first in OpenAI's \"o\" series of reasoning models.\nA preview of o1 was released by OpenAI on September 12, 2024.\no1 spends time \"thinking\" before it answers, making it better at complex reasoning tasks, science and programming than GPT-4o.\nThe full version was released to ChatGPT users on December 5, 2024.\n...\nOpenAI noted that o1 is the first of a series of \"reasoning\" models.\nOpenAI shared in December 2024 benchmark results for its successor, o3 (the name o2 was skipped to avoid trademark conflict with the mobile carrier brand named O2).\n...\no1 spends additional time thinking (generating a chain of thought) before generating an answer, which makes it better for complex reasoning tasks, particularly in science and mathematics.\n...\nOpenAI's test results suggest a correlation between accuracy and the logarithm of the amount of compute spent thinking before answering.\no1-preview performed approximately at a PhD level on benchmark tests related to physics, chemistry, and biology.\nOn the American Invitational Mathematics Examination, it solved 83% (12.5/15) of the problems, compared to 13% (1.8/15) for GPT-4o.\nIt also ranked in the 89th percentile in Codeforces coding competitions.\no1-mini is faster and 80% cheaper than o1-preview.\nIt is particularly suitable for programming and STEM-related tasks, but does not have the same \"broad world knowledge\" as o1-preview.\nOpenAI noted that o1's reasoning capabilities make it better at adhering to safety rules provided in the prompt's context window.\n...\nAccording to OpenAI's assessments, o1-preview and o1-mini crossed into \"medium risk\" in CBRN (biological, chemical, radiological, and nuclear) weapons.\nDan Hendrycks wrote that \"The model already outperforms PhD scientists most of the time on answering questions related to bioweapons.\"\n...\nAccording to OpenAI, o1 may \"fake alignment\", that is, generate a response that is contrary to accuracy and its own chain of thought, in about 0.38% of cases.\n...\nBy changing the numbers and names used in a math problem or simply running the same problem again, LLMs would perform somewhat worse than their best benchmark results.\nAdding extraneous but logically inconsequential information to the problems caused a much greater drop in performance, from −17.5% for o1-preview and −29.1% for o1-mini, to −65.7% for the worst model tested.",
        "title": "OpenAI o1 - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/OpenAI_o1",
        "date": "2024-09-12",
        "last_updated": "2026-03-31"
      },
      {
        "snippet": "",
        "title": "OpenAI O3 & O4 Mini: The First True Reasoning Agents? - YouTube",
        "url": "https://www.youtube.com/watch?v=TGnPcObHdLY",
        "date": "2025-04-16",
        "last_updated": "2026-04-08"
      },
      {
        "snippet": "",
        "title": "Safety",
        "url": "https://openai.com/index/learning-to-reason-with-llms/",
        "date": "2024-09-12",
        "last_updated": "2026-03-29"
      },
      {
        "snippet": "",
        "title": "Introducing OpenAI o3 and o4-mini",
        "url": "https://openai.com/index/introducing-o3-and-o4-mini/",
        "date": "2025-04-16",
        "last_updated": "2026-05-16"
      },
      {
        "snippet": "",
        "title": "OpenAI's o3 model scores 3% on the ARC-AGI-2 benchmark ...",
        "url": "https://forum.effectivealtruism.org/posts/CoPNbwNqDai6orZhv/openai-s-o3-model-scores-3-on-the-arc-agi-2-benchmark",
        "date": "2025-05-01",
        "last_updated": "2026-05-17"
      },
      {
        "snippet": "Built to handle hard problems — they take more time to think before responding, similar to how a person would approach a difficult task.\nThe “ OpenAI o1 preview ” model, specifically, shows incredible results for various hard problems: math, coding, and reasoning.\n...\nToday, OpenAI released the full version of the o1 model, making it production-ready for a wide range of use cases.\nIn this article, we’ll compare its capabilities with GPT-4o and Claude 3.5 Sonnet to see if it lives up to the claim.\n...\nWe compared these models across three key tasks:\nReasoning riddles, Math Problems, and Classifying customer tickets\nAlong the way, we explored the latest benchmarks, evaluated input and output token costs, assessed latency and throughput, and shared guidance on choosing the best model for your needs.\nFor up-to-date rankings, check our leaderboard , or keep reading to see the results of our evaluation.\nFrom this analysis we learn that:\nProduction apps: For apps in productions, we still recommend sing GPT-4o over o1, at least for one-off tasks like the ones we tested here.\nReasoning riddles: OpenAI o1 showed some inconsistency, refusing to answer one question and scoring 60% accuracy, similar to GPT-4o, though the difference isn’t major.\nGPT-4o is a great model for this task.\nClaude 3.5 Sonnet scored a lower accuracy of 56%.\n- Math equations: GPT-4o and the o1 model performed equally well on this task, raising questions about whether the higher cost of o1 is justified.\n- Surprisingly, the latest Claude 3.5 Sonnet lagged significantly behind, achieving only 39% accuracy on these examples.\n- Classification : All models performed similarly: GPT-4o (74%), O1 (73%), and Model 3.5 Sonnet (76%), with GPT-4o improving by 12% since September.\n- GPT-4o had the highest precision (86%) making it ideal for tasks where correct possitive predictions matter most.\nThe o1 model led in recall (82%) making it suitable when you need to capture as many TRUE cases as possible.\nThe Claude 3.5 Sonnet had best F1 score (77%) indicating robust overall classification performance.\n- Speed &amp; Cost: Given that we saw similar results across the three tasks we evaluated, we still can’t justify the cost of o1, and we recommend going with GPT-4o for most use-cases.\n- Complex Problems: Use OpenAI o1 when you need top-tier reasoning and latency isn’t a concern.\nIt’s ideal for agentic workflows with a “planning” stage, where the model creates a detailed plan that smaller, cheaper models can follow\n...\nAs expected, the new o1 models are slower due to their “reasoning” process.\nThis isn’t a drawback necessarily—it just makes them better suited for tasks where thoughtful problem-solving is essential.\nOpenAI o1 is approximately 30 times slower than GPT-4o.\nSimilarly, the o1 mini version is around 16 times slower than GPT-4o mini.\n## Cost comparison\nIt's evident that using OpenAI o1 will cost roughly 6x more than GPT-4o and Claude 3.5 Sonnet for input tokens, and about 5x more for output tokens.\n## Throughput (Output speed)\nOpenAI o1 stands out with the fastest throughput, generating 143 tokens per second.\nHowever, take this throughput data with a grain of salt — while its output speed is significantly higher than the other models, its latency, or time-to-think, is about 30x longer than GPT-4o and Claude 3.5 Sonnet.\n...\nWhen new models are released, we learn about their capabilities from benchmark data reported in the technical reports.\nThe new OpenAI o1 model improves on the most complex reasoning benchmarks:\nExceeds human PhD-level accuracy on challenging benchmark tasks in physics, chemistry, and biology on the GPQA benchmark Coding is easier — It ranks in the 89th percentile on competitive programming questions (Codeforces) It’s also very good at math — In a qualifying exam for the International Mathematics Olympiad (IMO), GPT-4o correctly solved only 13% of problems, while the reasoning model scored 83%.\nNow, this is next level.\nOn the standard ML benchmarks , it has huge improvements across the board:\n...\nThey’ve gathered over 6,000 votes, and the results show that the OpenAI o1 model is consistently ranked #1 across all categories, with Math being the most notable area of impact.\nThe o1-mini model is #1 in technical areas, #2 overall.\nCheck out the full results on this link.\n...\nThe results show that the newest model is great at complex tasks, but not preferred for some natural language tasks — suggesting that maybe the model is not the best for every use-case.\n...\nGPT-4o and the o1 model performed equally well on this task, raising questions about whether the higher cost of o1 is justified.\nSurprisingly, the latest Claude 3.5 Sonnet lagged significantly behind, achieving only 39% accuracy on these examples.\n...\nOpenAI o1 showed some inconsistency, refusing to answer one question and scoring 60% accuracy, similar to GPT-4o, though the difference isn’t major.\nGPT-4o is a great model for this task.\nClaude 3.5 Sonnet scored a lower accuracy of 56%.\n...\nWe ran the evaluation to test if the models' outputs matched our ground truth data for 100 labeled test cases, and we can see that they all got similar accuracies.\nGPT-4o got 74, O1 got 73, Claude 3.5 Sonnet got 76 answers right from total of 100.\nThis reinforces the idea that smarter, more cost-effective models without a \"reasoning module\" like o1 can perform just as well as o1, but without the added expense.\nIn a similar evaluation in September of 2024, we evaluated that GPT-4o had lower accuracy, and classified only 62 of the 100 examples correctly.\nToday, we’re seeing at a 12% improvement on this task!\n...\nToday, O1 has more production-ready properties and is starting to becomemore valuable for production use cases—though it’s best suited for those who can tolerate higher latency and need to tackle the toughest challenges.\nGPT-4O, however, remains the go-to model for many of the production use cases we see in the market.",
        "title": "Analysis: OpenAI o1 vs GPT-4o vs Claude 3.5 Sonnet - Vellum",
        "url": "https://www.vellum.ai/blog/analysis-openai-o1-vs-gpt-4o",
        "date": "2024-12-17",
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "",
        "title": "THE RELATIONSHIP BETWEEN REASONING AND PERFORMANCE",
        "url": "http://arxiv.org/pdf/2502.15631.pdf",
        "date": null,
        "last_updated": "2025-02-25"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

### Concurrent Requests

Process multiple requests simultaneously for better throughput:

<CodeGroup>
  ```python Python theme={null}
  import asyncio
  from perplexity import AsyncPerplexity, DefaultAioHttpClient

  async def concurrent_searches():
      async with AsyncPerplexity(
          http_client=DefaultAioHttpClient()
      ) as client:
          # Concurrent requests
          queries = ["AI", "machine learning", "deep learning", "neural networks"]
          tasks = [
              client.search.create(query=query)
              for query in queries
          ]
          
          results = await asyncio.gather(*tasks)
          
          for i, result in enumerate(results):
              print(f"Query '{queries[i]}': {len(result.results)} results")

  asyncio.run(concurrent_searches())
  ```

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

  async function concurrentSearches() {
      const client = new Perplexity();
      
      // Concurrent requests
      const queries = ["AI", "machine learning", "deep learning", "neural networks"];
      const tasks = queries.map(query => 
          client.search.create({ query })
      );
      
      const results = await Promise.all(tasks);
      
      results.forEach((result, i) => {
          console.log(`Query '${queries[i]}': ${result.results.length} results`);
      });
  }

  concurrentSearches();
  ```
</CodeGroup>

### Batch Processing with Rate Limiting

Process large numbers of requests while respecting rate limits:

<CodeGroup>
  ```python Python theme={null}
  import asyncio
  from perplexity import AsyncPerplexity, DefaultAioHttpClient

  async def batch_process_with_limit(queries, batch_size=5, delay=1.0):
      async with AsyncPerplexity(
          http_client=DefaultAioHttpClient()
      ) as client:
          results = []
          
          for i in range(0, len(queries), batch_size):
              batch = queries[i:i + batch_size]
              
              # Process batch concurrently
              tasks = [
                  client.search.create(query=query)
                  for query in batch
              ]
              
              batch_results = await asyncio.gather(*tasks, return_exceptions=True)
              results.extend(batch_results)
              
              # Delay between batches to respect rate limits
              if i + batch_size < len(queries):
                  await asyncio.sleep(delay)
          
          return results

  # Usage
  queries = [f"query {i}" for i in range(20)]
  results = asyncio.run(batch_process_with_limit(queries))
  ```

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

  async function batchProcessWithLimit(
      queries: string[], 
      batchSize: number = 5, 
      delay: number = 1000
  ) {
      const client = new Perplexity();
      const results = [];
      
      for (let i = 0; i < queries.length; i += batchSize) {
          const batch = queries.slice(i, i + batchSize);
          
          // Process batch concurrently
          const tasks = batch.map(query => 
              client.search.create({ query }).catch(error => error)
          );
          
          const batchResults = await Promise.all(tasks);
          results.push(...batchResults);
          
          // Delay between batches to respect rate limits
          if (i + batchSize < queries.length) {
              await new Promise(resolve => setTimeout(resolve, delay));
          }
      }
      
      return results;
  }

  // Usage
  const queries = Array.from({ length: 20 }, (_, i) => `query ${i}`);
  const results = await batchProcessWithLimit(queries);
  ```
</CodeGroup>

## Raw Response Access

Access headers, status codes, and raw response data for advanced use cases:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Get raw response with headers
  response = client.search.with_raw_response.create(
      query="OpenAI o-series reasoning model benchmarks"
  )

  print(f"Status Code: {response.status_code}")
  print(f"Request ID: {response.headers.get('X-Request-ID')}")
  print(f"Rate Limit Remaining: {response.headers.get('X-RateLimit-Remaining')}")
  print(f"Rate Limit Reset: {response.headers.get('X-RateLimit-Reset')}")

  # Parse the actual search results
  search = response.parse()
  print(f"Found {len(search.results)} results")
  ```

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

  const client = new Perplexity();

  // Get raw response with headers
  const { data: search, response: rawResponse } = await client.search
      .create({ query: "OpenAI o-series reasoning model benchmarks" })
      .withResponse();

  console.log(`Status Code: ${rawResponse.status}`);
  console.log(`Request ID: ${rawResponse.headers.get('X-Request-ID')}`);
  console.log(`Rate Limit Remaining: ${rawResponse.headers.get('X-RateLimit-Remaining')}`);
  console.log(`Rate Limit Reset: ${rawResponse.headers.get('X-RateLimit-Reset')}`);
  console.log(`Found ${search.results.length} results`);
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "169d5d3b-272a-46ca-a59d-7c218f9d5ce2",
    "results": [
      {
        "snippet": "",
        "title": "Reasoning best practices | OpenAI API",
        "url": "https://developers.openai.com/api/docs/guides/reasoning-best-practices",
        "date": null,
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "",
        "title": "A Comparative Study on Reasoning Patterns of OpenAI's o1 Model",
        "url": "https://arxiv.org/html/2410.13639v1",
        "date": "2024-10-17",
        "last_updated": "2026-03-22"
      },
      {
        "snippet": "**OpenAI o1** is a generative pre-trained transformer (GPT), the first in OpenAI's \"o\" series of reasoning models.\nA preview of o1 was released by OpenAI on September 12, 2024.\no1 spends time \"thinking\" before it answers, making it better at complex reasoning tasks, science and programming than GPT-4o.\nThe full version was released to ChatGPT users on December 5, 2024.\n...\nOpenAI noted that o1 is the first of a series of \"reasoning\" models.\nOpenAI shared in December 2024 benchmark results for its successor, o3 (the name o2 was skipped to avoid trademark conflict with the mobile carrier brand named O2).\n...\no1 spends additional time thinking (generating a chain of thought) before generating an answer, which makes it better for complex reasoning tasks, particularly in science and mathematics.\n...\nOpenAI's test results suggest a correlation between accuracy and the logarithm of the amount of compute spent thinking before answering.\no1-preview performed approximately at a PhD level on benchmark tests related to physics, chemistry, and biology.\nOn the American Invitational Mathematics Examination, it solved 83% (12.5/15) of the problems, compared to 13% (1.8/15) for GPT-4o.\nIt also ranked in the 89th percentile in Codeforces coding competitions.\no1-mini is faster and 80% cheaper than o1-preview.\nIt is particularly suitable for programming and STEM-related tasks, but does not have the same \"broad world knowledge\" as o1-preview.\nOpenAI noted that o1's reasoning capabilities make it better at adhering to safety rules provided in the prompt's context window.\n...\nAccording to OpenAI's assessments, o1-preview and o1-mini crossed into \"medium risk\" in CBRN (biological, chemical, radiological, and nuclear) weapons.\nDan Hendrycks wrote that \"The model already outperforms PhD scientists most of the time on answering questions related to bioweapons.\"\n...\nAccording to OpenAI, o1 may \"fake alignment\", that is, generate a response that is contrary to accuracy and its own chain of thought, in about 0.38% of cases.\n...\nBy changing the numbers and names used in a math problem or simply running the same problem again, LLMs would perform somewhat worse than their best benchmark results.\nAdding extraneous but logically inconsequential information to the problems caused a much greater drop in performance, from −17.5% for o1-preview and −29.1% for o1-mini, to −65.7% for the worst model tested.",
        "title": "OpenAI o1 - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/OpenAI_o1",
        "date": "2024-09-12",
        "last_updated": "2026-03-31"
      },
      {
        "snippet": "",
        "title": "OpenAI O3 & O4 Mini: The First True Reasoning Agents? - YouTube",
        "url": "https://www.youtube.com/watch?v=TGnPcObHdLY",
        "date": "2025-04-16",
        "last_updated": "2026-04-08"
      },
      {
        "snippet": "",
        "title": "Safety",
        "url": "https://openai.com/index/learning-to-reason-with-llms/",
        "date": "2024-09-12",
        "last_updated": "2026-03-29"
      },
      {
        "snippet": "",
        "title": "Introducing OpenAI o3 and o4-mini",
        "url": "https://openai.com/index/introducing-o3-and-o4-mini/",
        "date": "2025-04-16",
        "last_updated": "2026-05-16"
      },
      {
        "snippet": "",
        "title": "OpenAI's o3 model scores 3% on the ARC-AGI-2 benchmark ...",
        "url": "https://forum.effectivealtruism.org/posts/CoPNbwNqDai6orZhv/openai-s-o3-model-scores-3-on-the-arc-agi-2-benchmark",
        "date": "2025-05-01",
        "last_updated": "2026-05-17"
      },
      {
        "snippet": "Built to handle hard problems — they take more time to think before responding, similar to how a person would approach a difficult task.\nThe “ OpenAI o1 preview ” model, specifically, shows incredible results for various hard problems: math, coding, and reasoning.\n...\nToday, OpenAI released the full version of the o1 model, making it production-ready for a wide range of use cases.\nIn this article, we’ll compare its capabilities with GPT-4o and Claude 3.5 Sonnet to see if it lives up to the claim.\n...\nWe compared these models across three key tasks:\nReasoning riddles, Math Problems, and Classifying customer tickets\nAlong the way, we explored the latest benchmarks, evaluated input and output token costs, assessed latency and throughput, and shared guidance on choosing the best model for your needs.\nFor up-to-date rankings, check our leaderboard , or keep reading to see the results of our evaluation.\nFrom this analysis we learn that:\nProduction apps: For apps in productions, we still recommend sing GPT-4o over o1, at least for one-off tasks like the ones we tested here.\nReasoning riddles: OpenAI o1 showed some inconsistency, refusing to answer one question and scoring 60% accuracy, similar to GPT-4o, though the difference isn’t major.\nGPT-4o is a great model for this task.\nClaude 3.5 Sonnet scored a lower accuracy of 56%.\n- Math equations: GPT-4o and the o1 model performed equally well on this task, raising questions about whether the higher cost of o1 is justified.\n- Surprisingly, the latest Claude 3.5 Sonnet lagged significantly behind, achieving only 39% accuracy on these examples.\n- Classification : All models performed similarly: GPT-4o (74%), O1 (73%), and Model 3.5 Sonnet (76%), with GPT-4o improving by 12% since September.\n- GPT-4o had the highest precision (86%) making it ideal for tasks where correct possitive predictions matter most.\nThe o1 model led in recall (82%) making it suitable when you need to capture as many TRUE cases as possible.\nThe Claude 3.5 Sonnet had best F1 score (77%) indicating robust overall classification performance.\n- Speed &amp; Cost: Given that we saw similar results across the three tasks we evaluated, we still can’t justify the cost of o1, and we recommend going with GPT-4o for most use-cases.\n- Complex Problems: Use OpenAI o1 when you need top-tier reasoning and latency isn’t a concern.\nIt’s ideal for agentic workflows with a “planning” stage, where the model creates a detailed plan that smaller, cheaper models can follow\n...\nAs expected, the new o1 models are slower due to their “reasoning” process.\nThis isn’t a drawback necessarily—it just makes them better suited for tasks where thoughtful problem-solving is essential.\nOpenAI o1 is approximately 30 times slower than GPT-4o.\nSimilarly, the o1 mini version is around 16 times slower than GPT-4o mini.\n## Cost comparison\nIt's evident that using OpenAI o1 will cost roughly 6x more than GPT-4o and Claude 3.5 Sonnet for input tokens, and about 5x more for output tokens.\n## Throughput (Output speed)\nOpenAI o1 stands out with the fastest throughput, generating 143 tokens per second.\nHowever, take this throughput data with a grain of salt — while its output speed is significantly higher than the other models, its latency, or time-to-think, is about 30x longer than GPT-4o and Claude 3.5 Sonnet.\n...\nWhen new models are released, we learn about their capabilities from benchmark data reported in the technical reports.\nThe new OpenAI o1 model improves on the most complex reasoning benchmarks:\nExceeds human PhD-level accuracy on challenging benchmark tasks in physics, chemistry, and biology on the GPQA benchmark Coding is easier — It ranks in the 89th percentile on competitive programming questions (Codeforces) It’s also very good at math — In a qualifying exam for the International Mathematics Olympiad (IMO), GPT-4o correctly solved only 13% of problems, while the reasoning model scored 83%.\nNow, this is next level.\nOn the standard ML benchmarks , it has huge improvements across the board:\n...\nThey’ve gathered over 6,000 votes, and the results show that the OpenAI o1 model is consistently ranked #1 across all categories, with Math being the most notable area of impact.\nThe o1-mini model is #1 in technical areas, #2 overall.\nCheck out the full results on this link.\n...\nThe results show that the newest model is great at complex tasks, but not preferred for some natural language tasks — suggesting that maybe the model is not the best for every use-case.\n...\nGPT-4o and the o1 model performed equally well on this task, raising questions about whether the higher cost of o1 is justified.\nSurprisingly, the latest Claude 3.5 Sonnet lagged significantly behind, achieving only 39% accuracy on these examples.\n...\nOpenAI o1 showed some inconsistency, refusing to answer one question and scoring 60% accuracy, similar to GPT-4o, though the difference isn’t major.\nGPT-4o is a great model for this task.\nClaude 3.5 Sonnet scored a lower accuracy of 56%.\n...\nWe ran the evaluation to test if the models' outputs matched our ground truth data for 100 labeled test cases, and we can see that they all got similar accuracies.\nGPT-4o got 74, O1 got 73, Claude 3.5 Sonnet got 76 answers right from total of 100.\nThis reinforces the idea that smarter, more cost-effective models without a \"reasoning module\" like o1 can perform just as well as o1, but without the added expense.\nIn a similar evaluation in September of 2024, we evaluated that GPT-4o had lower accuracy, and classified only 62 of the 100 examples correctly.\nToday, we’re seeing at a 12% improvement on this task!\n...\nToday, O1 has more production-ready properties and is starting to becomemore valuable for production use cases—though it’s best suited for those who can tolerate higher latency and need to tackle the toughest challenges.\nGPT-4O, however, remains the go-to model for many of the production use cases we see in the market.",
        "title": "Analysis: OpenAI o1 vs GPT-4o vs Claude 3.5 Sonnet - Vellum",
        "url": "https://www.vellum.ai/blog/analysis-openai-o1-vs-gpt-4o",
        "date": "2024-12-17",
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "",
        "title": "THE RELATIONSHIP BETWEEN REASONING AND PERFORMANCE",
        "url": "http://arxiv.org/pdf/2502.15631.pdf",
        "date": null,
        "last_updated": "2025-02-25"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

### Response Streaming

For Agent API responses, use streaming to get partial results as they arrive:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Stream Agent API responses
  stream = client.responses.create(
      preset="low",
      input="Explain what factors determine LLM inference throughput on accelerators: memory bandwidth, KV-cache size, batching, and quantization.",
      stream=True
  )

  for event in stream:
      if event.type == "response.output_text.delta":
          print(event.delta, end="", flush=True)
  ```

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

  const client = new Perplexity();

  // Stream Agent API responses
  const stream = await client.responses.create({
      preset: "low",
      input: "Explain what factors determine LLM inference throughput on accelerators: memory bandwidth, KV-cache size, batching, and quantization.",
      stream: true as const
  });

  for await (const event of stream) {
      if (event.type === "response.output_text.delta") {
          process.stdout.write(event.delta);
      }
  }
  ```
</CodeGroup>

<Accordion title="Streaming event excerpt">
  The fields used by the example look like this; the full event also includes sequence and output metadata:

  ```json theme={null}
  {
    "type": "response.output_text.delta",
    "delta": "LLM inference throughput depends on memory bandwidth, KV-cache size, batching, and quantization."
  }
  ```
</Accordion>

## Connection Pooling

### Optimized Connection Settings

Configure connection pooling for better performance:

<CodeGroup>
  ```python Python theme={null}
  import httpx
  from perplexity import Perplexity, DefaultHttpxClient, AsyncPerplexity, DefaultAioHttpClient

  # Sync client with optimized connection pooling
  limits = httpx.Limits(
      max_keepalive_connections=50,  # Keep connections alive
      max_connections=100,           # Total connection pool size
      keepalive_expiry=30.0         # Keep-alive timeout
  )

  sync_client = Perplexity(
      http_client=DefaultHttpxClient(limits=limits)
  )

  # Async client with optimized connection pooling
  async_limits = httpx.Limits(
      max_keepalive_connections=100,
      max_connections=200,
      keepalive_expiry=60.0
  )

  async def create_async_client():
      return AsyncPerplexity(
          http_client=DefaultAioHttpClient(limits=async_limits)
      )
  ```

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

  // Optimized HTTPS agent for connection pooling
  const optimizedAgent = new https.Agent({
      keepAlive: true,
      keepAliveMsecs: 30000,  // 30 seconds
      maxSockets: 50,         // Max connections per host
      maxFreeSockets: 10,     // Max idle connections per host
      timeout: 60000          // Socket timeout
  });

  const client = new Perplexity({
      httpAgent: optimizedAgent
  } as any);

  // For high-throughput applications
  const highThroughputAgent = new https.Agent({
      keepAlive: true,
      keepAliveMsecs: 60000,
      maxSockets: 200,
      maxFreeSockets: 50,
      timeout: 120000
  });

  const clientHighThroughput = new Perplexity({
      httpAgent: highThroughputAgent
  } as any);
  ```
</CodeGroup>

## Performance Monitoring

### Request Timing and Metrics

Monitor performance metrics to identify bottlenecks:

<CodeGroup>
  ```python Python theme={null}
  import time
  import asyncio
  from perplexity import AsyncPerplexity, DefaultAioHttpClient

  class PerformanceMonitor:
      def __init__(self):
          self.request_times = []
          self.error_count = 0
          
      async def timed_request(self, client, query):
          start_time = time.time()
          try:
              result = await client.search.create(query=query)
              duration = time.time() - start_time
              self.request_times.append(duration)
              return result
          except Exception as e:
              self.error_count += 1
              raise e
      
      def get_stats(self):
          if not self.request_times:
              return {"error": "No successful requests"}
          
          return {
              "total_requests": len(self.request_times),
              "error_count": self.error_count,
              "avg_response_time": sum(self.request_times) / len(self.request_times),
              "min_response_time": min(self.request_times),
              "max_response_time": max(self.request_times)
          }

  async def run_performance_test():
      monitor = PerformanceMonitor()
      
      async with AsyncPerplexity(
          http_client=DefaultAioHttpClient()
      ) as client:
          queries = [f"test query {i}" for i in range(10)]
          
          tasks = [
              monitor.timed_request(client, query)
              for query in queries
          ]
          
          await asyncio.gather(*tasks, return_exceptions=True)
          
      print(monitor.get_stats())

  asyncio.run(run_performance_test())
  ```

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

  class PerformanceMonitor {
      private requestTimes: number[] = [];
      private errorCount: number = 0;
      
      async timedRequest(client: Perplexity, query: string) {
          const startTime = performance.now();
          try {
              const result = await client.search.create({ query });
              const duration = performance.now() - startTime;
              this.requestTimes.push(duration);
              return result;
          } catch (error) {
              this.errorCount++;
              throw error;
          }
      }
      
      getStats() {
          if (this.requestTimes.length === 0) {
              return { error: "No successful requests" };
          }
          
          return {
              totalRequests: this.requestTimes.length,
              errorCount: this.errorCount,
              avgResponseTime: this.requestTimes.reduce((a, b) => a + b, 0) / this.requestTimes.length,
              minResponseTime: Math.min(...this.requestTimes),
              maxResponseTime: Math.max(...this.requestTimes)
          };
      }
  }

  async function runPerformanceTest() {
      const monitor = new PerformanceMonitor();
      const client = new Perplexity();
      
      const queries = Array.from({ length: 10 }, (_, i) => `test query ${i}`);
      
      const tasks = queries.map(query => 
          monitor.timedRequest(client, query).catch(error => error)
      );
      
      await Promise.all(tasks);
      
      console.log(monitor.getStats());
  }

  runPerformanceTest();
  ```
</CodeGroup>

## Memory Optimization

### Efficient Data Processing

Process large datasets efficiently with streaming and pagination:

<CodeGroup>
  ```python Python theme={null}
  import asyncio
  from perplexity import AsyncPerplexity, DefaultAioHttpClient

  async def process_large_dataset(queries, process_fn):
      """Process queries in batches to manage memory usage"""
      
      async with AsyncPerplexity(
          http_client=DefaultAioHttpClient()
      ) as client:
          
          async def process_single(query):
              try:
                  result = await client.search.create(query=query)
                  # Process immediately to avoid storing in memory
                  processed = process_fn(result)
                  # Clear the original result from memory
                  del result
                  return processed
              except Exception as e:
                  return f"Error processing {query}: {e}"
          
          # Process in small batches
          batch_size = 5
          for i in range(0, len(queries), batch_size):
              batch = queries[i:i + batch_size]
              
              # Process batch
              tasks = [process_single(query) for query in batch]
              batch_results = await asyncio.gather(*tasks)
              
              # Yield results instead of accumulating
              for result in batch_results:
                  yield result
              
              # Optional: Small delay to prevent overwhelming the API
              await asyncio.sleep(0.1)

  # Usage
  async def summarize_result(search_result):
      """Process function that extracts only what we need"""
      return {
          "query": search_result.query,
          "result_count": len(search_result.results),
          "top_title": search_result.results[0].title if search_result.results else None
      }

  async def main():
      queries = [f"query {i}" for i in range(100)]
      
      async for processed_result in process_large_dataset(queries, summarize_result):
          print(processed_result)

  asyncio.run(main())
  ```

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

  async function* processLargeDataset<T>(
      queries: string[], 
      processFn: (result: any) => T
  ): AsyncGenerator<T | string> {
      const client = new Perplexity();
      
      async function processSingle(query: string): Promise<T | string> {
          try {
              const result = await client.search.create({ query });
              // Process immediately to avoid storing in memory
              const processed = processFn(result);
              return processed;
          } catch (error) {
              return `Error processing ${query}: ${error}`;
          }
      }
      
      // Process in small batches
      const batchSize = 5;
      for (let i = 0; i < queries.length; i += batchSize) {
          const batch = queries.slice(i, i + batchSize);
          
          // Process batch
          const tasks = batch.map(query => processSingle(query));
          const batchResults = await Promise.all(tasks);
          
          // Yield results instead of accumulating
          for (const result of batchResults) {
              yield result;
          }
          
          // Optional: Small delay to prevent overwhelming the API
          await new Promise(resolve => setTimeout(resolve, 100));
      }
  }

  // Usage
  function summarizeResult(searchResult: any) {
      return {
          query: searchResult.query,
          resultCount: searchResult.results.length,
          topTitle: searchResult.results[0]?.title || null
      };
  }

  async function main() {
      const queries = Array.from({ length: 100 }, (_, i) => `query ${i}`);
      
      for await (const processedResult of processLargeDataset(queries, summarizeResult)) {
          console.log(processedResult);
      }
  }

  main();
  ```
</CodeGroup>

## Best Practices

<Steps>
  <Step title="Use async for concurrent operations">
    Always use async clients when you need to process multiple requests simultaneously.

    <Tip>
      For CPU-bound processing after API calls, consider using worker threads or processes.
    </Tip>
  </Step>

  <Step title="Implement connection pooling">
    Configure appropriate connection limits based on your application's needs.

    <CodeGroup>
      ```python Python theme={null}
      # Good: Optimized for your use case
      limits = httpx.Limits(
          max_keepalive_connections=20,  # Based on expected concurrency
          max_connections=50,
          keepalive_expiry=30.0
      )
      ```

      ```typescript TypeScript theme={null}
      // Good: Optimized for your use case
      const agent = new https.Agent({
          keepAlive: true,
          maxSockets: 20,  // Based on expected concurrency
          keepAliveMsecs: 30000
      });
      ```
    </CodeGroup>
  </Step>

  <Step title="Monitor and tune performance">
    Use metrics to identify bottlenecks and optimize accordingly.

    <Warning>
      Don't optimize prematurely - measure first, then optimize based on actual performance data.
    </Warning>
  </Step>

  <Step title="Handle backpressure">
    Implement proper rate limiting and backpressure handling for high-throughput applications.

    <CodeGroup>
      ```python Python theme={null}
      # Use semaphores to limit concurrent requests
      semaphore = asyncio.Semaphore(10)  # Max 10 concurrent requests

      async def rate_limited_request(client, query):
          async with semaphore:
              return await client.search.create(query=query)
      ```

      ```typescript TypeScript theme={null}
      // Use a queue or throttling library
      import pLimit from 'p-limit';

      const limit = pLimit(10);  // Max 10 concurrent requests

      const rateLimitedRequest = (client: Perplexity, query: string) =>
          limit(() => client.search.create({ query }));
      ```
    </CodeGroup>
  </Step>
</Steps>

## Related Resources

<CardGroup>
  <Card title="Configuration" icon="settings" href="/docs/sdk/configuration">
    Optimize connection pooling and timeouts
  </Card>

  <Card title="Error Handling" icon="alert-triangle" href="/docs/sdk/error-handling">
    Handle errors in async operations
  </Card>
</CardGroup>


# Type Safety
Source: https://docs.perplexity.ai/docs/sdk/type-safety

Learn how to leverage full TypeScript definitions and Python type hints with the Perplexity SDKs for better development experience and code safety.

## Overview

Both Perplexity SDKs provide comprehensive type definitions to help you catch errors at development time and provide better IDE support. This guide covers type annotations, generic types, and advanced typing patterns.

## Basic Type Usage

### Type Imports and Annotations

Use type imports for better IDE support and type checking:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity
  from perplexity.types import (
      SearchCreateResponse,
      ResponseCreateResponse,
      SearchResult
  )

  client = Perplexity()

  # Type hints for better IDE support
  search_response: SearchCreateResponse = client.search.create(
      query="OpenAI API release history and developer features"
  )

  # Access typed properties
  result: SearchResult = search_response.results[0]
  print(f"Title: {result.title}")
  print(f"URL: {result.url}")
  print(f"Snippet: {result.snippet}")
  ```

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

  const client = new Perplexity();

  // TypeScript provides full intellisense and type checking
  const searchResponse: Perplexity.Search.SearchCreateResponse = await client.search.create({
      query: "OpenAI API release history and developer features"
  });

  // Access typed properties with intellisense
  const result = searchResponse.results[0];
  console.log(`Title: ${result.title}`);
  console.log(`URL: ${result.url}`);
  console.log(`Snippet: ${result.snippet}`);
  ```
</CodeGroup>

<Accordion title="Response">
  ````json theme={null}
  {
    "id": "4a713b10-40e7-4d2a-9e7b-fdd9870702e8",
    "results": [
      {
        "snippet": "",
        "title": "Changelog | OpenAI API",
        "url": "https://developers.openai.com/api/docs/changelog",
        "date": null,
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "All latest OpenAI models support text and image input, text output, multilingual capabilities, and vision.\nModels are available via the Responses API and our Client SDKs.",
        "title": "Models | OpenAI API",
        "url": "https://developers.openai.com/api/docs/models",
        "date": null,
        "last_updated": "2026-05-07"
      },
      {
        "snippet": "June 11, 2020\n...\nWe’re releasing an API for accessing new AI models developed by OpenAI.\nUnlike most AI systems which are designed for one use-case, the API today provides a general-purpose “text in, text out” interface, allowing users to try it on virtually any English language task.\nYou can now request access in order to integrate the API into your product, develop an entirely new application, or help us explore the strengths and limits of this technology.\nGiven any text prompt, the API will return a text completion, attempting to match the pattern you gave it.\nYou can “program” it by showing it just a few examples of what you’d like it to do; its success generally varies depending on how complex the task is.\nThe API also allows you to hone performance on specific tasks by training on a dataset (small or large) of examples you provide, or by learning from human feedback provided by users or labelers.\n...\nToday the API runs models with weights from the GPT‑3⁠(opens in a new window) family with many speed and throughput improvements.",
        "title": "OpenAI API",
        "url": "https://openai.com/index/openai-api/",
        "date": "2020-06-11",
        "last_updated": "2026-03-29"
      },
      {
        "snippet": "",
        "title": "OpenAI Just Changed Everything (Responses API Walkthrough)",
        "url": "https://www.youtube.com/watch?v=0pGxoubWI6s",
        "date": "2025-03-13",
        "last_updated": "2026-03-31"
      },
      {
        "snippet": "",
        "title": "Call to bring back the rigor in API Development and ...",
        "url": "https://community.openai.com/t/call-to-bring-back-the-rigor-in-api-development-and-production-grade-slas-for-api-improvements/1357192",
        "date": "2025-09-09",
        "last_updated": "2026-05-04"
      },
      {
        "snippet": "Announced Open Responses: an open-source spec for building multi-provider, interoperable LLM interfaces built on top of the original OpenAI Responses API.\nJan 14\nFeature\ngpt-5.2-codex\nv1/responses\nReleased\n```\ngpt-5.2-codex\n```\nto the Responses API.\nGPT-5.2-Codex is a version of GPT-5.2 optimized for agentic coding tasks in Codex or similar environments.\nRead more here.\n...\nUpdated the gpt-realtime-mini and gpt-audio-mini slugs to point to the 2025-12-15 snapshots.\n...\nUpdated the sora-2 slug to point to\n```\nsora-2-2025-12-08\n```\n...\ngpt-image-1.5\nchatgpt-image-latest\nAdded\n```\ngpt-image-1.5\n```\nand\n```\nchatgpt-image-latest\n```\nto the Responses API image generation tool.\n...\ngpt-image-1.5\nchatgpt-image-latest\nReleased gpt-image-1.5 and chatgpt-image-latest, our latest and most advanced models for image generation.\nRead more here.\n...\nReleased four new dated audio snapshots.\nThese updates deliver reliability, quality, and voice fidelity improvements for real-time, voice-driven applications.\nRead more here.\n...\nThis launch also includes support for Custom voices for eligible customers.\n...\nReleased GPT-5.2, the newest flagship model in the GPT-5 model family.\nGPT-5.2 shows improvements over the previous GPT-5.1 in:\n- General intelligence\n...\nFor long-running conversations with the Responses API, you can use the\n```\n...\n```\n...\nReleased GPT-5.1, the newest flagship model in the GPT-5 model family.\n...\nReleased enhanced role-based access controls (RBAC).\nRole-based access control (RBAC) lets you decide who can do what across your organization and projects—both through the API and in the Dashboard.\n...\nExtended prompt cache retention keeps cached prefixes active for longer, up to a maximum of 24 hours.\nExtended Prompt Caching works by offloading the key/value tensors to GPU-local storage when memory is full, significantly increasing the storage capacity available for caching.\n...\nReleased gpt-5-pro, a version of GPT-5 that uses more compute to think harder and provide consistently better answers.\nReleased gpt-realtime-mini and gpt-audio-mini for more cost-efficient speech to speech performance.\nReleased gpt-image-1-mini for more cost-efficient image generation and editing.\nLaunched v1/videos for rich, detailed, and dynamic video generation and remixing with our latest Sora 2 and Sora 2 Pro models.\nLaunched Agent Builder for visually creating custom multi-agent workflows.\nLaunched ChatKit, an embeddable chat interface for deploying agents.\n...\n- Released the Responses API, a new API for creating and using agents and tools.\n- Released a set of built-in tools for the Responses API: web search, file search, and computer use.\n...\n- Announced plans to bring all Assistants API features to the easier to use Responses API, with an anticipated sunset date for Assistants in 2026 (after achieving full feature parity).",
        "title": "Changelog | OpenAI API",
        "url": "https://platform.openai.com/docs/changelog",
        "date": "2025-01-31",
        "last_updated": "2026-01-21"
      },
      {
        "snippet": "",
        "title": "API Platform",
        "url": "https://openai.com/api/",
        "date": "2026-04-09",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "### June, 2025Jun 13featurev1/responses\n- New reusable prompts are now available in the dashboard and Responses API.\nVia API, you can now reference templates created in the dashboard via the\n`prompt`parameter (with a prompt\n`id`, optional\n`version`) and supply dynamic\n`variables`that can include strings, images, or file inputs.\nReusable prompts are not available in Chat Completions.\nLearn more.\n- Released o3-pro, a version of the o3 reasoning model that uses more compute to answer hard problems with better reasoning and consistency.\nPrices for the o3 model have also been reduced for all API requests, including batch and flex processing.\n- Added fine-tuning support with direct preference optimization for the models\n`gpt-4.1-2025-04-14`,\n`gpt-4.1-mini-2025-04-14`, and\n`gpt-4.1-nano-2025-04-14`.\n- New model snapshots available for gpt-4o-audio-preview and gpt-4o-realtime-preview.\nReleased Agents SDK for TypeScript.\n### May, 2025May 20featurev1/responses\n- Added support for new built-in tools in the Responses API, including remote MCP servers and code interpreter.\nLearn more about tools.\n- Added support for using\n`strict`mode for tool schemas when using parallel tool calling with non-fine-tuned models.\n- Added new schema features, including string validation for\n- Launched codex-mini-latest in the API, optimized for use with the Codex CLI.\n...\n- Launched support for reinforcement fine-tuning.\nLearn about available fine-tuning methods.\ngpt-4.1-nano is now available for fine-tuning.\n=======\n...\n### April, 2025Apr 23featurev1/images/generationsv1/images/edits\n- Added a new image generation model,\n`gpt-image-1`.\nThis model sets a new standard for image generation, with improved quality and instruction following.\n- Updated the Image Generation and Edit endpoints to support new parameters specific to the\n`gpt-image-1`model.\n- Added two new o-series reasoning models,\n`o3`and\n`o4-mini`.\nThey set a new standard for math, science, and coding, visual reasoning tasks, and technical writing.\n- Launched Codex, our code generation CLI tool.\n- Added\n`gpt-4.1`,\n`gpt-4.1-mini`, and\n`gpt-4.1-nano`models to the API.\nThese new models feature improved instruction following, coding, and a larger context window (up to 1M tokens).\n`gpt-4.1`and\n`gpt-4.1-mini`are available for supervised fine-tuning.\nAnnounced deprecation of\n`gpt-4.5-preview`.\n### March, 2025Mar 20updatev1/audio\n- Added\n`gpt-4o-mini-tts`,\n`gpt-4o-transcribe`,\n`gpt-4o-mini-transcribe`, and\n`whisper-1`models to the Audio API.\n- Released o1-pro, a version of the o1 reasoning model that uses more compute to answer hard problems with better reasoning and consistency.\nReleased several new models and tools and a new API for agentic workflows:\nReleased the Responses API, a new API for creating and using agents and tools.\nReleased a set of built-in tools for the Responses API: web search, file search, and computer use.\nReleased the Agents SDK, an orchestration framework for designing, building, and deploying agents.\nAnnounced new models:\n`gpt-4o-search-preview`,\n`gpt-4o-mini-search-preview`,\n`computer-use-preview`.\nAnnounced plans to bring all Assistants API features to the easier to use Responses API, with an anticipated sunset date for Assistants in 2026 (after achieving full feature parity).\n- Added\n`metadata`field support to fine-tuning jobs.\n### February, 2025Feb 27featuregpt-4.5v1/chat/completionsv1/assistantsv1/batch\n- Released a research preview of GPT-4.5—our largest and most capable chat model yet.\nGPT-4.5's high \"EQ\" and understanding of user intent make it better at creative tasks and agentic planning.\n### January, 2025Jan 31featureo3-minio3-mini-2025-01-31v1/chat/completions\n- Launched o3-mini, a new small reasoning model that is optimized for science, math, and coding tasks.\n### December, 2024Dec 18feature\nLaunched Admin API Key Rotations, enabling customers to programmatically rotate their admin api keys.\nUpdated Admin API Invites, enabling customers to programmatically invite users to projects at the same time they are invited to organizations.\nAdded new models for o1, gpt-4o-realtime, gpt-4o-audio and more.\nAdded WebRTC connection method for the Realtime API.\nAdded\n...\nAdded\n`developer`message role for o1 model.\nNote that o1-preview and o1-mini do not support system or developer messages.\nLaunched Preference Fine-tuning using Direct Preference Optimization (DPO).\nLaunched beta SDKs for Go and Java.\nLearn more.\nAdded Realtime API support in the Python SDK.\n- Launched Usage API, enabling customers to programmatically query activities and spending across OpenAI APIs.\n### November, 2024Nov 20Updatev1/chat/completions\n- Released gpt-4o-2024-11-20, our newest model in the gpt-4o series.\n- Released Predicted Outputs, which greatly reduces latency for model responses where much of the response is known ahead of time.\nThis is most common when regenerating the content of documents and code files with only minor changes.\n...\n- Released new\n`gpt-4o-audio-preview`model for chat completions, which supports both audio inputs and outputs.\nUses the same underlying model as the Realtime API.\nReleased several new features at OpenAI DevDay in San Francisco:\n...\n- Released\nnew\n`omni-moderation-latest`moderation model, which supports both images and text (for some categories), supports two new text-only harm categories, and has more accurate scores.\n- Released o1-preview and o1-mini, new large language models trained with reinforcement learning to perform complex reasoning tasks.",
        "title": "Changelog - OpenAI API",
        "url": "https://platform.openai.com/docs/changelog/changelog",
        "date": "2025-01-31",
        "last_updated": "2025-06-20"
      },
      {
        "snippet": "",
        "title": "Model Release Notes | OpenAI Help Center",
        "url": "https://help.openai.com/en/articles/9624314-model-release-notes",
        "date": "2025-12-18",
        "last_updated": "2026-04-01"
      },
      {
        "snippet": "### February, 2025Feb 27featuregpt-4.5v1/chat/completionsv1/assistantsv1/batch\n- Released a research preview of GPT-4.5—our largest and most capable chat model yet.\nGPT-4.5's high \"EQ\" and understanding of user intent make it better at creative tasks and agentic planning.\n### January, 2025Jan 31featureo3-minio3-mini-2025-01-31v1/chat/completions\n- Launched o3-mini, a new small reasoning model that is optimized for science, math, and coding tasks.\n### December, 2024Dec 18feature\nLaunched Admin API Key Rotations, enabling customers to programmatically rotate their admin api keys.\nUpdated Admin API Invites, enabling customers to programmatically invite users to projects at the same time they are invited to organizations.\nAdded new models for o1, gpt-4o-realtime, gpt-4o-audio and more.\nAdded WebRTC connection method for the Realtime API.\nAdded\n`reasoning_effort`parameter for o1 models.\nAdded\n`developer`message role for o1 model.\nNote that o1-preview and o1-mini do not support system or developer messages.\nLaunched Preference Fine-tuning using Direct Preference Optimization (DPO).\nLaunched beta SDKs for Go and Java.\nLearn more.\nAdded Realtime API support in the Python SDK.\n- Launched Usage API, enabling customers to programmatically query activities and spending across OpenAI APIs.\n### November, 2024Nov 20Updatev1/chat/completions\n- Released gpt-4o-2024-11-20, our newest model in the gpt-4o series.\n- Released Predicted Outputs, which greatly reduces latency for model responses where much of the response is known ahead of time.\nThis is most common when regenerating the content of documents and code files with only minor changes.\n### October, 2024Oct 30featuregpt-4o-realtime-previewgpt-4o-audio-previewv1/chat/completions\n- Added five new voice types in the Realtime API and Chat Completions API.\n- Released new\n`gpt-4o-audio-preview`model for chat completions, which supports both audio inputs and outputs.\nUses the same underlying model as the Realtime API.\nReleased several new features at OpenAI DevDay in San Francisco:\nRealtime API: Build fast speech-to-speech experiences into your applications using a WebSockets interface.\nModel distillation: Platform for fine-tuning cost-efficient models with your outputs from a large frontier model.\nImage fine-tuning: Fine-tune GPT-4o with images and text to improve vision capabilities.\nEvals: Create and run custom evaluations to measure model performance on specific tasks.\nPrompt caching: Discounts and faster processing times on recently seen input tokens.\nGenerate in playground: Easily generate prompts, function definitions, and structured output schemas in the playground using the Generate button.\n### September, 2024Sep 26featureomni-moderation-latestv1/moderations\n- Released\nnew\n`omni-moderation-latest`moderation model, which supports both images and text (for some categories), supports two new text-only harm categories, and has more accurate scores.\n- Released o1-preview and o1-mini, new large language models trained with reinforcement learning to perform complex reasoning tasks.\n### August, 2024Aug 29featurev1/assistants\n- Assistants API now supports including file search results used by the file search tool, and customizing ranking behavior.\n- GA release for\n`gpt-4o-2024-08-06`fine-tuning—all API users can now fine-tune the latest GPT-4o model.\n- Released dynamic model for\n`chatgpt-4o-latest`—this model will point to the latest GPT-4o model used by ChatGPT.\n- Launched Structured Outputs—model outputs now reliabilty adhere to developer supplied JSON Schemas.\n- Released gpt-4o-2024-08-06, our newest model in the gpt-4o series.\n- Launched Admin and Audit Log APIs, allowing customers to programmatically administer their organization and monitor changes using the audit logs.\nAudit logging must be enabled within settings.\n### July, 2024Jul 24Update\n- Launched self-serve SSO configuration, allowing Enterprise customers on custom and unlimited billing to set up authentication against their desired IDP.\n- Launched fine-tuning for GPT-4o mini, enabling even higher performance for specific use cases.\n- Released GPT-4o mini, our affordable an intelligent small model for fast, lightweight tasks.\n- Released Uploads to upload large files in multiple parts.\n### June, 2024Jun 06Update\n- Parallel function calling\ncan be disabled in Chat Completions and the Assistants API by passing\n`parallel_tool_calls=false`.\n- .NET SDK launched in Beta.\n- Added support for file search customizations .\n### May, 2024May 15Update\n- Added support for archiving projects . Only organization owners can access this functionality.\n- Added support for setting cost limits on a per-project basis for pay as you go customers.\n- Released GPT-4o in the API.\nGPT-4o is our fastest and most affordable flagship model.\n- Added support for image inputs to the Assistants API.\n- Added support for fine-tuned models to the Batch API .\n- Added\n`stream_options: {\"include_usage\": true}`parameter to the Chat Completions and Completions APIs.\nSetting this gives developers access to usage stats when using streaming.\n- Added a new endpoint to delete a message from a thread in the Assistants API.\n### April, 2024Apr 29Update\n- Added a new\nfunction calling option\n`tool_choice: \"required\"`to the Chat Completions and Assistants APIs.\n- Added a guide for the Batch API and Batch API support for embeddings models\n- Introduced a series of updates to the Assistants API , including a new file search tool allowing up to 10,000 files per assistant, new token controls, and support for tool choice.\n- Introduced project based hierarchy for organizing work by projects, including the ability to create API keys and manage rate and cost limits on a per-project basis (cost limits available only for Enterprise customers).\n- Released Batch API\n- Released GPT-4 Turbo with Vision in general availability in the API\n- Added support for seed in the fine-tuning API\n...\n- Added support for temperature and assistant message creation in the Assistants API\n- Added support for streaming in the Assistants API\n...\n- Added\n`timestamp_granularities`parameter to the Audio API\n### January, 2024Jan 25Update\n- Released embedding V3 models and an updated GPT-4 Turbo preview\n- Added\n`dimensions`parameter to the Embeddings API\n...\n### November, 2023Nov 30Update\n- Released OpenAI Deno SDK\n- Released GPT-4 Turbo Preview , updated GPT-3.5 Turbo, GPT-4 Turbo with Vision, Assistants API, DALL·E 3 in the API, and text-to-speech API\n- Deprecated the Chat Completions\n...\n- Released OpenAI Python SDK V1.0\n...\n- Added function calling support to the Fine-tuning API",
        "title": "OpenAI Platform",
        "url": "https://platform.openai.com/docs/changelog/dec-15th-2023",
        "date": "2025-01-31",
        "last_updated": "2025-03-01"
      }
    ],
    "server_time": null
  }
  ````
</Accordion>

### Runtime Type Validation

Python SDK uses Pydantic for runtime type validation:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity
  from perplexity.types import SearchCreateResponse

  client = Perplexity()

  # Runtime validation ensures type safety
  try:
      search_response = client.search.create(
          query="OpenAI o-series reasoning model benchmarks",
          max_results=10
      )
      
      # Pydantic model methods for serialization
      json_data = search_response.to_json()
      dict_data = search_response.to_dict()
      
      # Type validation on field access
      first_result = search_response.results[0]
      print(f"Result type: {type(first_result)}")
      
  except ValueError as e:
      print(f"Type validation error: {e}")
  ```

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

  const client = new Perplexity();

  // TypeScript compile-time type checking
  const searchResponse: Perplexity.Search.SearchCreateResponse = await client.search.create({
      query: "OpenAI o-series reasoning model benchmarks",
      max_results: 10  // TypeScript ensures correct property names
  });

  // Serialization (already plain objects)
  const jsonData = JSON.stringify(searchResponse);
  const objectData = searchResponse; // Already a plain object

  // Type safety at compile time
  const firstResult = searchResponse.results[0];
  console.log(`Result type available in IDE: ${typeof firstResult}`);
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "169d5d3b-272a-46ca-a59d-7c218f9d5ce2",
    "results": [
      {
        "snippet": "",
        "title": "Reasoning best practices | OpenAI API",
        "url": "https://developers.openai.com/api/docs/guides/reasoning-best-practices",
        "date": null,
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "",
        "title": "A Comparative Study on Reasoning Patterns of OpenAI's o1 Model",
        "url": "https://arxiv.org/html/2410.13639v1",
        "date": "2024-10-17",
        "last_updated": "2026-03-22"
      },
      {
        "snippet": "**OpenAI o1** is a generative pre-trained transformer (GPT), the first in OpenAI's \"o\" series of reasoning models.\nA preview of o1 was released by OpenAI on September 12, 2024.\no1 spends time \"thinking\" before it answers, making it better at complex reasoning tasks, science and programming than GPT-4o.\nThe full version was released to ChatGPT users on December 5, 2024.\n...\nOpenAI noted that o1 is the first of a series of \"reasoning\" models.\nOpenAI shared in December 2024 benchmark results for its successor, o3 (the name o2 was skipped to avoid trademark conflict with the mobile carrier brand named O2).\n...\no1 spends additional time thinking (generating a chain of thought) before generating an answer, which makes it better for complex reasoning tasks, particularly in science and mathematics.\n...\nOpenAI's test results suggest a correlation between accuracy and the logarithm of the amount of compute spent thinking before answering.\no1-preview performed approximately at a PhD level on benchmark tests related to physics, chemistry, and biology.\nOn the American Invitational Mathematics Examination, it solved 83% (12.5/15) of the problems, compared to 13% (1.8/15) for GPT-4o.\nIt also ranked in the 89th percentile in Codeforces coding competitions.\no1-mini is faster and 80% cheaper than o1-preview.\nIt is particularly suitable for programming and STEM-related tasks, but does not have the same \"broad world knowledge\" as o1-preview.\nOpenAI noted that o1's reasoning capabilities make it better at adhering to safety rules provided in the prompt's context window.\n...\nAccording to OpenAI's assessments, o1-preview and o1-mini crossed into \"medium risk\" in CBRN (biological, chemical, radiological, and nuclear) weapons.\nDan Hendrycks wrote that \"The model already outperforms PhD scientists most of the time on answering questions related to bioweapons.\"\n...\nAccording to OpenAI, o1 may \"fake alignment\", that is, generate a response that is contrary to accuracy and its own chain of thought, in about 0.38% of cases.\n...\nBy changing the numbers and names used in a math problem or simply running the same problem again, LLMs would perform somewhat worse than their best benchmark results.\nAdding extraneous but logically inconsequential information to the problems caused a much greater drop in performance, from −17.5% for o1-preview and −29.1% for o1-mini, to −65.7% for the worst model tested.",
        "title": "OpenAI o1 - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/OpenAI_o1",
        "date": "2024-09-12",
        "last_updated": "2026-03-31"
      },
      {
        "snippet": "",
        "title": "OpenAI O3 & O4 Mini: The First True Reasoning Agents? - YouTube",
        "url": "https://www.youtube.com/watch?v=TGnPcObHdLY",
        "date": "2025-04-16",
        "last_updated": "2026-04-08"
      },
      {
        "snippet": "",
        "title": "Safety",
        "url": "https://openai.com/index/learning-to-reason-with-llms/",
        "date": "2024-09-12",
        "last_updated": "2026-03-29"
      },
      {
        "snippet": "",
        "title": "Introducing OpenAI o3 and o4-mini",
        "url": "https://openai.com/index/introducing-o3-and-o4-mini/",
        "date": "2025-04-16",
        "last_updated": "2026-05-16"
      },
      {
        "snippet": "",
        "title": "OpenAI's o3 model scores 3% on the ARC-AGI-2 benchmark ...",
        "url": "https://forum.effectivealtruism.org/posts/CoPNbwNqDai6orZhv/openai-s-o3-model-scores-3-on-the-arc-agi-2-benchmark",
        "date": "2025-05-01",
        "last_updated": "2026-05-17"
      },
      {
        "snippet": "Built to handle hard problems — they take more time to think before responding, similar to how a person would approach a difficult task.\nThe “ OpenAI o1 preview ” model, specifically, shows incredible results for various hard problems: math, coding, and reasoning.\n...\nToday, OpenAI released the full version of the o1 model, making it production-ready for a wide range of use cases.\nIn this article, we’ll compare its capabilities with GPT-4o and Claude 3.5 Sonnet to see if it lives up to the claim.\n...\nWe compared these models across three key tasks:\nReasoning riddles, Math Problems, and Classifying customer tickets\nAlong the way, we explored the latest benchmarks, evaluated input and output token costs, assessed latency and throughput, and shared guidance on choosing the best model for your needs.\nFor up-to-date rankings, check our leaderboard , or keep reading to see the results of our evaluation.\nFrom this analysis we learn that:\nProduction apps: For apps in productions, we still recommend sing GPT-4o over o1, at least for one-off tasks like the ones we tested here.\nReasoning riddles: OpenAI o1 showed some inconsistency, refusing to answer one question and scoring 60% accuracy, similar to GPT-4o, though the difference isn’t major.\nGPT-4o is a great model for this task.\nClaude 3.5 Sonnet scored a lower accuracy of 56%.\n- Math equations: GPT-4o and the o1 model performed equally well on this task, raising questions about whether the higher cost of o1 is justified.\n- Surprisingly, the latest Claude 3.5 Sonnet lagged significantly behind, achieving only 39% accuracy on these examples.\n- Classification : All models performed similarly: GPT-4o (74%), O1 (73%), and Model 3.5 Sonnet (76%), with GPT-4o improving by 12% since September.\n- GPT-4o had the highest precision (86%) making it ideal for tasks where correct possitive predictions matter most.\nThe o1 model led in recall (82%) making it suitable when you need to capture as many TRUE cases as possible.\nThe Claude 3.5 Sonnet had best F1 score (77%) indicating robust overall classification performance.\n- Speed &amp; Cost: Given that we saw similar results across the three tasks we evaluated, we still can’t justify the cost of o1, and we recommend going with GPT-4o for most use-cases.\n- Complex Problems: Use OpenAI o1 when you need top-tier reasoning and latency isn’t a concern.\nIt’s ideal for agentic workflows with a “planning” stage, where the model creates a detailed plan that smaller, cheaper models can follow\n...\nAs expected, the new o1 models are slower due to their “reasoning” process.\nThis isn’t a drawback necessarily—it just makes them better suited for tasks where thoughtful problem-solving is essential.\nOpenAI o1 is approximately 30 times slower than GPT-4o.\nSimilarly, the o1 mini version is around 16 times slower than GPT-4o mini.\n## Cost comparison\nIt's evident that using OpenAI o1 will cost roughly 6x more than GPT-4o and Claude 3.5 Sonnet for input tokens, and about 5x more for output tokens.\n## Throughput (Output speed)\nOpenAI o1 stands out with the fastest throughput, generating 143 tokens per second.\nHowever, take this throughput data with a grain of salt — while its output speed is significantly higher than the other models, its latency, or time-to-think, is about 30x longer than GPT-4o and Claude 3.5 Sonnet.\n...\nWhen new models are released, we learn about their capabilities from benchmark data reported in the technical reports.\nThe new OpenAI o1 model improves on the most complex reasoning benchmarks:\nExceeds human PhD-level accuracy on challenging benchmark tasks in physics, chemistry, and biology on the GPQA benchmark Coding is easier — It ranks in the 89th percentile on competitive programming questions (Codeforces) It’s also very good at math — In a qualifying exam for the International Mathematics Olympiad (IMO), GPT-4o correctly solved only 13% of problems, while the reasoning model scored 83%.\nNow, this is next level.\nOn the standard ML benchmarks , it has huge improvements across the board:\n...\nThey’ve gathered over 6,000 votes, and the results show that the OpenAI o1 model is consistently ranked #1 across all categories, with Math being the most notable area of impact.\nThe o1-mini model is #1 in technical areas, #2 overall.\nCheck out the full results on this link.\n...\nThe results show that the newest model is great at complex tasks, but not preferred for some natural language tasks — suggesting that maybe the model is not the best for every use-case.\n...\nGPT-4o and the o1 model performed equally well on this task, raising questions about whether the higher cost of o1 is justified.\nSurprisingly, the latest Claude 3.5 Sonnet lagged significantly behind, achieving only 39% accuracy on these examples.\n...\nOpenAI o1 showed some inconsistency, refusing to answer one question and scoring 60% accuracy, similar to GPT-4o, though the difference isn’t major.\nGPT-4o is a great model for this task.\nClaude 3.5 Sonnet scored a lower accuracy of 56%.\n...\nWe ran the evaluation to test if the models' outputs matched our ground truth data for 100 labeled test cases, and we can see that they all got similar accuracies.\nGPT-4o got 74, O1 got 73, Claude 3.5 Sonnet got 76 answers right from total of 100.\nThis reinforces the idea that smarter, more cost-effective models without a \"reasoning module\" like o1 can perform just as well as o1, but without the added expense.\nIn a similar evaluation in September of 2024, we evaluated that GPT-4o had lower accuracy, and classified only 62 of the 100 examples correctly.\nToday, we’re seeing at a 12% improvement on this task!\n...\nToday, O1 has more production-ready properties and is starting to becomemore valuable for production use cases—though it’s best suited for those who can tolerate higher latency and need to tackle the toughest challenges.\nGPT-4O, however, remains the go-to model for many of the production use cases we see in the market.",
        "title": "Analysis: OpenAI o1 vs GPT-4o vs Claude 3.5 Sonnet - Vellum",
        "url": "https://www.vellum.ai/blog/analysis-openai-o1-vs-gpt-4o",
        "date": "2024-12-17",
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "",
        "title": "THE RELATIONSHIP BETWEEN REASONING AND PERFORMANCE",
        "url": "http://arxiv.org/pdf/2502.15631.pdf",
        "date": null,
        "last_updated": "2025-02-25"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

## Advanced Type Patterns

### Generic Type Helpers

Create reusable typed functions:

<CodeGroup>
  ```python Python theme={null}
  from typing import TypeVar, Generic, List, Optional, Callable
  from perplexity import Perplexity
  from perplexity.types import SearchCreateResponse, ResponseCreateResponse

  T = TypeVar('T')
  R = TypeVar('R')

  class TypedPerplexityClient:
      def __init__(self, client: Perplexity):
          self.client = client
      
      def search_with_transform(
          self, 
          query: str, 
          transform: Callable[[SearchCreateResponse], T]
      ) -> T:
          """Perform search and transform the result with type safety"""
          response = self.client.search.create(query=query)
          return transform(response)
      
      def batch_search(
          self, 
          queries: List[str]
      ) -> List[SearchCreateResponse]:
          """Perform multiple searches with proper typing"""
          results = []
          for query in queries:
              response = self.client.search.create(query=query)
              results.append(response)
          return results

  # Usage with type safety
  client = TypedPerplexityClient(Perplexity())

  def extract_titles(response: SearchCreateResponse) -> List[str]:
      return [result.title for result in response.results]

  # Typed function call
  titles: List[str] = client.search_with_transform("AI research", extract_titles)
  ```

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

  class TypedPerplexityClient {
      constructor(private client: Perplexity) {}
      
      async searchWithTransform<T>(
          query: string,
          transform: (response: Perplexity.Search.SearchCreateResponse) => T
      ): Promise<T> {
          const response = await this.client.search.create({ query });
          return transform(response);
      }
      
      async batchSearch(queries: string[]): Promise<Perplexity.Search.SearchCreateResponse[]> {
          const tasks = queries.map(query => 
              this.client.search.create({ query })
          );
          return Promise.all(tasks);
      }
  }

  // Usage with type safety
  const client = new TypedPerplexityClient(new Perplexity());

  function extractTitles(response: Perplexity.Search.SearchCreateResponse): string[] {
      return response.results.map(result => result.title);
  }

  // Typed function call with full intellisense
  const titles: string[] = await client.searchWithTransform("AI research", extractTitles);
  ```
</CodeGroup>

### Custom Type Guards

Create type guards for safer type checking:

<CodeGroup>
  ```python Python theme={null}
  from typing import Union, TypeGuard
  from perplexity.types import (
      SearchCreateResponse,
      ResponseCreateResponse,
      SearchResult
  )

  def is_search_response(
      response: Union[SearchCreateResponse, ResponseCreateResponse]
  ) -> TypeGuard[SearchCreateResponse]:
      """Type guard to check if response is a search response"""
      return hasattr(response, 'results')

  def is_valid_search_result(result: SearchResult) -> TypeGuard[SearchResult]:
      """Type guard to validate search result structure"""
      return (
          hasattr(result, 'title') and 
          hasattr(result, 'url') and 
          hasattr(result, 'snippet') and
          result.title is not None and
          result.url is not None
      )

  # Usage
  def process_response(
      response: Union[SearchCreateResponse, ResponseCreateResponse]
  ) -> None:
      if is_search_response(response):
          # Python type checker now knows this is SearchCreateResponse
          for result in response.results:
              if is_valid_search_result(result):
                  print(f"Valid result: {result.title}")
              else:
                  print("Invalid result format")
  ```

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

  function isSearchResponse(
      response: Perplexity.Search.SearchCreateResponse | Perplexity.StreamChunk
  ): response is Perplexity.Search.SearchCreateResponse {
      return 'results' in response;
  }

  function isValidSearchResult(result: { title: string; url: string; snippet: string }): boolean {
      return (
          typeof result.title === 'string' &&
          typeof result.url === 'string' &&
          typeof result.snippet === 'string' &&
          result.title.length > 0 &&
          result.url.length > 0
      );
  }

  // Usage
  function processResponse(
      response: Perplexity.Search.SearchCreateResponse | Perplexity.StreamChunk
  ): void {
      if (isSearchResponse(response)) {
          // TypeScript now knows this is SearchCreateResponse
          response.results.forEach(result => {
              if (isValidSearchResult(result)) {
                  console.log(`Valid result: ${result.title}`);
              } else {
                  console.log("Invalid result format");
              }
          });
      }
  }
  ```
</CodeGroup>

## Response Type Utilities

### Extracting Nested Types

Work with nested response structures safely:

<CodeGroup>
  ```python Python theme={null}
  from typing import List, Optional
  from perplexity import Perplexity
  from perplexity.types import (
      SearchCreateResponse,
      SearchResult,
      ResponseCreateResponse
  )

  class ResponseUtils:
      @staticmethod
      def extract_search_titles(response: SearchCreateResponse) -> List[str]:
          """Extract all search result titles with type safety"""
          return [result.title for result in response.results if result.title]
      
      @staticmethod
      def extract_search_urls(response: SearchCreateResponse) -> List[str]:
          """Extract all search result URLs with type safety"""
          return [result.url for result in response.results if result.url]
      
      @staticmethod
      def get_first_search_result(
          response: SearchCreateResponse
      ) -> Optional[SearchResult]:
          """Get first search result safely"""
          return response.results[0] if response.results else None
      
      @staticmethod
      def extract_response_output(
          response: ResponseCreateResponse
      ) -> Optional[str]:
          """Extract response output safely"""
          if response.output:
              return response.output
          return None

  # Usage
  client = Perplexity()
  search_response = client.search.create(query="Python 3.13 free-threaded GIL changes")

  titles = ResponseUtils.extract_search_titles(search_response)
  urls = ResponseUtils.extract_search_urls(search_response)
  first_result = ResponseUtils.get_first_search_result(search_response)

  print(f"Found {len(titles)} results")
  if first_result:
      print(f"First result: {first_result.title}")
  ```

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

  class ResponseUtils {
      static extractSearchTitles(response: Perplexity.Search.SearchCreateResponse): string[] {
          return response.results
              .filter(result => result.title)
              .map(result => result.title);
      }
      
      static extractSearchUrls(response: Perplexity.Search.SearchCreateResponse): string[] {
          return response.results
              .filter(result => result.url)
              .map(result => result.url);
      }
      
      static getFirstSearchResult(
          response: Perplexity.Search.SearchCreateResponse
      ) {
          return response.results[0];
      }
      
      static extractChatContent(
          response: Perplexity.StreamChunk
      ): string | undefined {
          const content = response.choices[0]?.message?.content;
          // Handle content which can be string, array of chunks, or null
          if (typeof content === 'string') {
              return content;
          }
          if (Array.isArray(content)) {
              // Extract text from content chunks
              return content
                  .filter(chunk => chunk.type === 'text' && 'text' in chunk)
                  .map(chunk => (chunk as { text: string }).text)
                  .join('');
          }
          return undefined;
      }
  }

  // Usage
  const client = new Perplexity();
  const searchResponse: Perplexity.Search.SearchCreateResponse = await client.search.create({ 
      query: "Python 3.13 free-threaded GIL changes" 
  });

  const titles = ResponseUtils.extractSearchTitles(searchResponse);
  const urls = ResponseUtils.extractSearchUrls(searchResponse);
  const firstResult = ResponseUtils.getFirstSearchResult(searchResponse);

  console.log(`Found ${titles.length} results`);
  if (firstResult) {
      console.log(`First result: ${firstResult.title}`);
  }
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "915ddb6e-c856-4856-a036-330e8e021895",
    "results": [
      {
        "snippet": "Starting with the 3.13 release, CPython has support for a build of\nPython called where the\n(GIL) is disabled.\nFree-threaded execution allows for full utilization of the\navailable processing power by running threads in parallel on available CPU cores.\nWhile not all software will benefit from this automatically, programs\ndesigned with threading in mind will run faster on multi-core hardware.\nSome third-party packages, in particular ones\n...\nStarting with Python 3.13, the official macOS and Windows installers\noptionally support installing free-threaded Python binaries.\n...\nWhen building CPython from source, the configure option\nshould be used to build a free-threaded Python interpreter.\n...\nTo check if the current interpreter supports free-threading,\nand contain “free-threading build”.\nThe new function can be used to check whether\nthe GIL is actually disabled in the running process.\nThe `sysconfig.get_config_var(\"Py_GIL_DISABLED\")` configuration variable can\nbe used to determine whether the build supports free threading.\nIf the variable\nis set to `1`, then the build supports free threading.\nThis is the recommended\nmechanism for decisions related to the build configuration.\n## The global interpreter lock in free-threaded Python ¶\nFree-threaded builds of CPython support optionally running with the GIL enabled\nat runtime using the environment variable or\nthe command-line option .\nThe GIL may also automatically be enabled when importing a C-API extension\nmodule that is not explicitly marked as supporting free threading.\nA warning\nwill be printed in this case.\n...\n## Thread safety ¶\nThe free-threaded build of CPython aims to provide similar thread-safety\nbehavior at the Python level to the default GIL-enabled build.\nBuilt-in\ntypes like , , and use internal locks\nto protect against concurrent modifications in ways that behave similarly to\nthe GIL.\nHowever, Python has not historically guaranteed specific behavior for\nconcurrent modifications to these built-in types, so this should be treated\nas a description of the current implementation, not a guarantee of current or\nfuture behavior.\nNote\nIt’s recommended to use the or other synchronization\nprimitives instead of relying on the internal locks of built-in types, when\npossible.\n...\nIn the free-threaded build, some objects are .\nImmortal objects are not deallocated and have reference counts that are\nnever modified.\nThis is done to avoid reference count contention that would\nprevent efficient multi-threaded scaling.\nAs of the 3.14 release, immortalization is limited to:\n- Code constants: numeric literals, string literals, and tuple literals\ncomposed of other constants.\n- Strings interned by .\n### Frame objects ¶\nIt is not safe to access from a\nobject if that frame is currently executing in another thread, and doing so may\ncrash the interpreter.\n### Iterators ¶\nIt is generally not thread-safe to access the same iterator object from\nmultiple threads concurrently, and threads may see duplicate or missing\nelements.\n### Single-threaded performance ¶\nThe free-threaded build has additional overhead when executing Python code\ncompared to the default GIL-enabled build.\nThe amount of overhead depends\non the workload and hardware.\nOn the pyperformance benchmark suite, the\naverage overhead ranges from about 1% on macOS aarch64 to 8% on x86-64 Linux\nsystems.\n## Behavioral changes ¶\nThis section describes CPython behavioural changes with the free-threaded\nbuild.\n### Context variables ¶\nIn the free-threaded build, the flag\nis set to true by default which causes threads created with\nto start with a copy of the\nof the caller of\n. In the default GIL-enabled build, the flag\ndefaults to false so threads start with an\nempty `Context()`.\n### Warning filters ¶\nIn the free-threaded build, the flag\nis set to true by default. In the default GIL-enabled build, the flag defaults\nto false. If the flag is true then the\ncontext manager uses a context variable for warning filters. If the flag is\nfalse then `catch_warnings` modifies the global filters list,\nwhich is not thread-safe. See the module for more details.",
        "title": "Python support for free threading — Python 3.14.5 documentation",
        "url": "https://docs.python.org/3/howto/free-threading-python.html",
        "date": null,
        "last_updated": "2026-05-18"
      },
      {
        "snippet": "CPython 3.13 was released two weeks ago and this release is the most\nperformance-oriented in some time.\nAfter a quick read of the release notes, a\nfew things stand out for the impact they can have on the performance:\n- CPython can now run in **free-threaded mode**, with the global interpreter lock (GIL) disabled\n- a brand new **just-in-time** (JIT) compiler has been added\n- CPython now bundles the `mimalloc` allocator out of the box\n...\n## Free-threaded CPython\nFree-threading is an experimental feature in Python 3.13 that allows CPython to\nrun without the Global Interpreter Lock (GIL).\nThe GIL is a mutex preventing\nmultiple threads from executing Python bytecode simultaneously.\nThis design\nchoice has simplified CPython's memory management and made the C API easier to\nwork with.\nHowever, it has also been one of the most significant barriers to\nutilizing modern multi-core processors effectively.\n...\n- As expected the `threading` based implementation is the fastest when running\n**3.13t with no GIL** and the GIL is effectively not limiting the parallel execution of the threads anymore.\n- Still, when running with the free threaded build both **with** and **without** the GIL, we see a significant slowdown for all other implementations.\nThis is mostly because the free-threaded build requires the specializing adaptive interpreter to be disabled, thus clearly decreasing the performance of the other implementations.\nThis overhead should be reduced in the 3.14 release where the specializing adaptive interpreter will be thread-safe and thus will be re-enabled.\n...\nthe same.\nFrom this measurement, we can see that the new free-threaded build of\nCPython 3.13 can have a significant impact on the performance of parallel\napplications, bringing a very relevant alternative to `multiprocessing`.\nStill\nit's experimental and not yet ready for production use because of the overall\nslowdown it introduces, but it's a very promising step in the right direction!",
        "title": "State of Python 3.13 Performance: Free-Threading - CodSpeed",
        "url": "https://codspeed.io/blog/state-of-python-3-13-performance-free-threading",
        "date": "2024-11-05",
        "last_updated": "2026-05-14"
      },
      {
        "snippet": "In this video, I'll discuss how Python 3.13 is revolutionizing performance by making the Global Interpreter Lock (GIL) optional!\nLearn what the GIL is, why it exists, and the potential impacts of its removal on your Python projects.\n...\n{ts:0} the global interpreter log has been holding python back for years that's\n{ts:4} about to change with python 3.30 but there are dangers that you need to be aware of the aim of the global\n{ts:11} interpreter lock or the Gill is to protect python object access by letting only one thread at a time execute python\n{ts:19} bite code with python 3.13 the Gill can be made optional it's an experimental feature and requires a bit of work to\n{ts:27} actually remove the lock I had to download the source code compile it build it from scratch almost seems like\n{ts:34} hio doesn't want me to do this video in any case it's a big change for python but what does it actually mean will it\n{ts:41} have any effect on you I'll show you some examples where it's going to give you a massive performance boost however\n...\n{ts:56} the first place so what is the Gill the Gill was introduced used in Python 1.5 in essence this is a mutex a lock in\n{ts:64} cpython that allows only one thread at a time to execute python bite code and since cpython is an open source project\n...\n{ts:77} course this is all written in C and the interesting thing is that you can also see the actual commit that added the\n...\n{ts:102} code depending on whether the Gill is disabled or not now though cpython the default python interpreter has the Gill\n{ts:109} currently in Python 3.12 there are interpreters like jython that don't the Gill ensures threat safety in Python's\n{ts:117} memory management unfortunately that means that you can't effectively use multiple CPU cores in a multi-threaded\n{ts:124} program for heavy computations that has an effect on performance so why does the default interpreter have this look in\n{ts:132} the early days multi-threaded programs were less common than they are now and single threaded performance was the main\n{ts:138} concern locking The Interpreter was a mechanism to improve the execution time of single threaded code mainly because\n...\n{ts:239} Prim competitions what you can clearly see is that the difference between single-threaded and multi-thread is\n{ts:245} actually pretty minimal and that's because of course the Gill is there so you can't really benefit from the\n...\n{ts:283} faster but it does have some overhead and unfortunately we can't really use multi-threaded programs here because the\n{ts:290} Gill prevents us from doing that so why is the Gill becoming optional now well it's been requested for a long time and\n{ts:300} it's become even more requested with the hype of AI the python Community has been advocating for a solution to the gills\n...\n{ts:333} go over the plan in the short term python version 3.13 or possibly 3.14 which by the way should definitely\n{ts:341} be called piy th the no Gill build is most likely to be in experimental mode meaning that it's going to be on you\n{ts:350} will still have the Gill by default and the main idea is that the developers just want to gain insights into how it's\n{ts:357} being used it's kind of like a trial so really don't rely on that feature in production just yet in the midterm once\n{ts:364} the core team is confident that no Guild builds are more stable it's going to become a supported option but still not\n{ts:370} the default the estimation is that this may take a year or two but of course that could be longer now in the long\n{ts:376} term the goal is for the no Gill build to become the default eliminating the Gill without disrupting backwards\n{ts:383} compatibility the team estimates that this could take up to 5 years to reach this stage throughout this Pro process\n{ts:389} they'll evaluate regularly to ensure that it's moving along while avoiding backward compatibility struggles by the\n...\n{ts:401} Loop the link is down below so what are some of the dangers of disabling the Gill or first many packages rely on it\n{ts:409} being present or at least not having to De manually with memory safety if that goes away those packages might break and\n{ts:416} I can imagine Frameworks like Fast API SE Alchemy Jango are going to be affected by this for example fast API\n...\n{ts:442} the Gill will impact the most let me know in the comments down below another danger of removing the Gill is that it\n{ts:449} can increase increase the complexity of python I mean in the long term it's going to make python more parallel\n{ts:455} friendly however without the Gill you need to be more cautious about threat safety in your programs now I did not\n...\n{ts:483} threaded version is much faster than the single thread version but there's also another interesting thing going on here\n{ts:489} which is that the multiprocessing version is actually slower than in Python 3.12 and single thread is also\n...\n{ts:576} it's going to remove a major limitation which is great however disabling the Gill in Python is an experimental\n{ts:583} feature don't rely on it just yet there are other ways you can optimize the performance of your python code one way\n{ts:589} is to use concurrent programming with the async iio package if you want to learn more about that check out this",
        "title": "How Much FASTER Is Python 3.13 Without the GIL? - YouTube",
        "url": "https://www.youtube.com/watch?v=zWPe_CUR4yU",
        "date": "2024-08-02",
        "last_updated": "2026-03-17"
      },
      {
        "snippet": "",
        "title": "What's New In Python 3.13 — Python 3.14.5 documentation",
        "url": "https://docs.python.org/3/whatsnew/3.13.html",
        "date": null,
        "last_updated": "2026-05-19"
      },
      {
        "snippet": "In Python, the Global Interpreter Lock (GIL) has been a major hurdle in achieving true concurrency.\nHowever, with the upcoming release of Python 3.13, the GIL becomes optional!\nThis experimental feature marks a significant milestone in the evolution of Python’s multithreading capabilities.\n...\n**What’s New in Python 3.13?**\n**Python 3.13** introduces an experimental feature that allows you to disable the GIL altogether!\nThis means that threads can run more concurrently, which can lead to significant performance improvements for certain types of workloads.\nTo take advantage of this new feature, you’ll need to download and install the beta version(rc1) of Python 3.13, which includes a free-threaded build configuration.\nFrom there, you can enable or disable the GIL using environment variables or command-line options.\n...\n**How to Detect and Disable GIL in Python 3.13**\nFree-threaded CPython refers to an experimental feature that allows for full utilization of available processing power by running threads in parallel on available CPU cores.\nThis means that programs designed with threading in mind will run faster on multicore hardware.\n> To enable the free-threaded build, you would need to either compile your own interpreter using the --disable-gil option or install an experimental build that is marked as free-threaded.\nNote that this feature is still under development and may have some bugs and a substantial single-threaded performance hit.\nAdditionally, users can optionally run with the GIL enabled at runtime using the environment variable **PYTHON_GIL** or the command line option **-X gil**.\n...\nWhen we disable the Global Interpreter Lock (GIL), our multi-threaded task finishes remarkably fast — just **1.36 seconds!** This is about **six** times faster than when the GIL is active.\nInterestingly, with Python 3.13 and an active GIL, the results are very similar to those of Python 3.12, which doesn’t support disabling the GIL.",
        "title": "GIL Becomes Optional in Python 3.13: A Game-Changer ...",
        "url": "https://medium.com/@mitesh.singh.jat/gil-becomes-optional-in-python-3-13-a-game-changer-for-multithreading-4c5d28856803",
        "date": "2024-08-14",
        "last_updated": "2025-10-16"
      },
      {
        "snippet": "",
        "title": "Python 3.13: Free Threading and a JIT Compiler",
        "url": "https://realpython.com/python313-free-threading-jit/",
        "date": "2024-09-18",
        "last_updated": "2026-05-18"
      },
      {
        "snippet": "The documentation states:\n> `--disable-gil` enables experimental support for running Python without the Global Interpreter Lock (GIL): free-threading build.\n> (Source: Python 3.13 Configuration)\nIt also mentions that free-threaded execution:\n> allows for full utilization of available CPU cores by running threads in parallel.\nThe mode is experimental, with some expected bugs and a substantial single-threaded performance hit.\nFree-threaded builds support optionally running with the GIL enabled at runtime using the environment variable `PYTHON_GIL` or the command-line option `-X gil`.\n> (Source: What's New in Python 3.13)\n...\nYes, the free-threaded build is experimental including enabling the GIL at runtime.\nThe most important limitation is that you still need to compile C extensions specifically for the free-threaded build.\nLooking at https://peps.python.org/pep-0703/#backwards-compatibility:\n- Refcounting always uses biased refcounting in the free-threaded build, with the potentital associated changes in lifetimes.\n(Some objects may live longer than they would normally. I don't think this is likely to come up very often)\n- Mimalloc is always used so there are still the limitations on the memory allocator mentioned in the PEP\nMember\n...\nTo make an addition to Sam's comment,\nIMO, everything under the `--disable-gil ` build should be considered experimental.\nEvery implementation detail can be changed in a future version, and even behavior details can be changed.",
        "title": "Request for Clarification on Experimental Status of Free-Threaded Builds with GIL in CPython 3.13 · Issue #124287 · python/cpython",
        "url": "https://github.com/python/cpython/issues/124287",
        "date": "2024-09-20",
        "last_updated": "2026-04-16"
      },
      {
        "snippet": "##### Feb 05, 2026 (0:08:53)\nPython 3.13 just made history by making the Global Interpreter Lock (GIL) optional for the first time in 30+ years!\nIn this video, I'll explain what the GIL is, why it existed, and how Python finally removed it through PEP 703.\n...\n- Why Python 3.13's free-threading changes everything\n...\nPEP 703: https://peps.python.org/pep-0703/\nPython 3.13 Docs: https://docs.python.org/3.13/\nFree-Threading Build Guide: https://github.com/roshandec29/PythonGIL/tree/main?tab=readme-ov-file#part-2-python-313-revolution\n...\nAfter that, we'll explore how Python is removing the lock,\n{ts:30} including free threading, sub interpreters, and the real meaning of PEP 703.\n...\nThe\n{ts:148} GIL is a mutex, a single global lock.\nIts only job is to make absolutely sure that only one thread is executing Python\n{ts:157} bite code at any given moment inside a single process.\n...\nThe GL makes this entire process thread safe by default.\nIt prevents two threads from,\n{ts:197} say, trying to change the same reference count at the exact same time and completely corrupting memory.\n...\nThe official proposal to remove the GIL, that's PEP 703, says it right there.\n...\nWhich brings us to today and the absolutely monumental engineering effort to finally make the\n{ts:308} Jill optional.\nAnd let me tell you, this is so much more than just deleting a few lines of code.\nOkay, first things first,\n{ts:315} and this is a really important detail.\nThe Jill isn't just gone.\nIt's optional.\nYou now have to compile a special\n{ts:322} freethreaded version of Python by adding a flag- disable Jill.\nThis is huge for backward compatibility with the entire\n{ts:329} existing Python world.\nSo instead of that one big lock, the new system uses what are called thread states.\nA thread\n{ts:336} has to be in the attached state before it can touch any Python objects.\nBut and this is the whole point now multiple\n{ts:342} threads can be in that attached state at the exact same time.\nThat's the key that unlocks true parallelism.\n...\nTo make any of this possible, the core of\n{ts:355} the interpreter had to be completely rearchitected.\nThat simple reference counting, it's been replaced by much\n{ts:360} more complex systems.\nThere's a whole new stop the world garbage collector that has to pause everything to clean up\n...\nAll of that new machinery\n{ts:391} for thread safety, the new reference counting, the fine grained locks, it all adds overhead.\nRight now, the estimate\n{ts:398} is that it slows down normal singlethreaded code by around 9%.\n...\nThe other massive cost isn't in performance, it's in the ecosystem.\n...\n{ts:416} protect them.\nEvery single one now needs to be checked and likely updated to be safe in this new free threaded world.\n...\nNow that the lock is\n{ts:510} optional, Python is more powerful.\nYes, but it's also more dangerous.",
        "title": "Python's GIL is FINALLY Gone! 🔥 Python 3.13 Free-Threading Explained",
        "url": "https://www.youtube.com/watch?v=fXJ1oveqsR8",
        "date": "2026-02-05",
        "last_updated": "2026-05-15"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

### Custom Response Mappers

Create typed mappers for domain-specific data structures:

<CodeGroup>
  ```python Python theme={null}
  from typing import List, Optional, Dict, Any
  from dataclasses import dataclass
  from perplexity import Perplexity
  from perplexity.types import SearchCreateResponse, SearchResult

  @dataclass
  class SimplifiedSearchResult:
      title: str
      url: str
      snippet: str
      domain: str

  @dataclass
  class SearchSummary:
      query: str
      total_results: int
      results: List[SimplifiedSearchResult]
      domains: List[str]

  class SearchResponseMapper:
      @staticmethod
      def to_simplified(response: SearchCreateResponse, query: str) -> SearchSummary:
          """Convert API response to simplified domain model"""
          simplified_results = []
          domains = set()
          
          for result in response.results:
              if result.title and result.url and result.snippet:
                  # Extract domain from URL
                  try:
                      from urllib.parse import urlparse
                      domain = urlparse(result.url).netloc
                      domains.add(domain)
                      
                      simplified_results.append(SimplifiedSearchResult(
                          title=result.title,
                          url=result.url,
                          snippet=result.snippet,
                          domain=domain
                      ))
                  except Exception:
                      # Skip invalid URLs
                      continue
          
          return SearchSummary(
              query=query,
              total_results=len(simplified_results),
              results=simplified_results,
              domains=list(domains)
          )

  # Usage with type safety
  client = Perplexity()
  query = "PyTorch versus JAX performance benchmarks for large language model training"
  api_response = client.search.create(query=query)
  summary: SearchSummary = SearchResponseMapper.to_simplified(api_response, query)

  print(f"Query: {summary.query}")
  print(f"Results: {summary.total_results}")
  print(f"Unique domains: {len(summary.domains)}")
  ```

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

  interface SimplifiedSearchResult {
      title: string;
      url: string;
      snippet: string;
      domain: string;
  }

  interface SearchSummary {
      query: string;
      totalResults: number;
      results: SimplifiedSearchResult[];
      domains: string[];
  }

  class SearchResponseMapper {
      static toSimplified(response: Perplexity.Search.SearchCreateResponse): SearchSummary {
          const simplifiedResults: SimplifiedSearchResult[] = [];
          const domains = new Set<string>();
          
          for (const result of response.results) {
              if (result.title && result.url && result.snippet) {
                  try {
                      const domain = new URL(result.url).hostname;
                      domains.add(domain);
                      
                      simplifiedResults.push({
                          title: result.title,
                          url: result.url,
                          snippet: result.snippet,
                          domain
                      });
                  } catch {
                      // Skip invalid URLs
                      continue;
                  }
              }
          }
          
          return {
              query: '',
              totalResults: simplifiedResults.length,
              results: simplifiedResults,
              domains: Array.from(domains)
          };
      }
  }

  // Usage with type safety
  const client = new Perplexity();
  const apiResponse: Perplexity.Search.SearchCreateResponse = await client.search.create({ 
      query: "PyTorch versus JAX performance benchmarks for large language model training" 
  });
  const summary: SearchSummary = SearchResponseMapper.toSimplified(apiResponse);

  console.log(`Query: ${summary.query}`);
  console.log(`Results: ${summary.totalResults}`);
  console.log(`Unique domains: ${summary.domains.length}`);
  ```
</CodeGroup>

<Accordion title="Response">
  ````json theme={null}
  {
    "id": "e48a6f66-7d8a-4dfd-aa79-342ae22199b6",
    "results": [
      {
        "snippet": "### Performance\n*In this section, we will explore two main implementations in Machine Learning, one suitable for large datasets, working in a streaming fashion, and another ideal for smaller datasets, which can fully fit in the memory of GPU.*\n**Out-of-the-box implementation (stream-based)**\n|Pytorch|Pytorch lightning|Tensorflow + Keras|JAX|\n|--|--|--|--|\n|232s (180s with native loader)|180s|64s|84s|\nIn this setup, we load data in a streaming fashion, so each image is loaded via a data loader when needed.\nPlenty of ways to tune each setup further, but here, we aim for simple, out-of-the-box implementation.\nOur results show that Tesorflow and JAX are faster, while Pytroch and Pytorch lightning are slower.\nThe reason behind it is straightforward: Pytorch and Pytorch lightning use PIL-based image loading, while Tensorflow and FLAX use TF native implementation.\nWhen experimenting with a custom-defined Dataloader for Pytorch (via torchvision.io.read_image()), it was possible to reduce the processing time by 22% (down to 180s).\nThis is still significantly slower than TF processing (under the hood using highly optimised tf.io.read_file()).\n**All in-memory implementation (memory-based)**\nIn contrast to the previous setup, in this one, we tried a subset of 3/10 classes due to memory limitations) and placed the whole dataset on the GPU (limiting the effect of slower DataLoaders).\nIn this setup, Pytorch seems significantly faster than other solutions, PyTorch Lightning and JAX have similar times, and Tensorflow is the slowest.\nThis might indicate that Pytorch Lightning and Keras might have certain extra overhead due to their additional features.",
        "title": "ML Engineer comparison of Pytorch, TensorFlow, JAX, and ...",
        "url": "https://softwaremill.com/ml-engineer-comparison-of-pytorch-tensorflow-jax-and-flax/",
        "date": "2024-09-24",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "The predictability of pure functions and functional programming unlocks many benefits in JAX, such as Just-In-Time (JIT) compilation, where the XLA compiler can significantly optimize code on GPUs or TPUs, for major speed-ups.\n...\nWith PyTorch, you calculate the gradients with `loss.backward()`, triggering AutoGrad to follow the computation graph from `loss` to compute the gradients.\n...\nThe key takeaway is that the training loops are very similar between PyTorch and JAX/Flax NNX, with most of the differences boiling down to object-oriented versus functional programming.\nAlthough there’s a slight learning curve to functional programming and thinking about gradients of functions, it enables many of the aforementioned benefits in JAX, e.g., JIT compilation and automatic parallelization.\nFor example, just adding the `@nnx.jit` annotations to the above functions speeds up training the model for 500 epochs from 6.25 minutes to just 1.8 minutes with a P100 GPU on Kaggle!\nYou’ll see similar speedups with the same code across CPUs, TPUs, and even non-NVIDIA GPUs.",
        "title": "A guide to JAX for PyTorch developers",
        "url": "https://cloud.google.com/blog/products/ai-machine-learning/guide-to-jax-for-pytorch-developers",
        "date": "2025-01-07",
        "last_updated": "2026-05-22"
      },
      {
        "snippet": "",
        "title": "TensorFlow vs PyTorch vs JAX: Performance Benchmark",
        "url": "https://apxml.com/posts/tensorflow-vs-pytorch-vs-jax-performance-benchmark",
        "date": "2025-03-24",
        "last_updated": "2026-03-18"
      },
      {
        "snippet": "Built on functional programming principles and composable transformations, JAX offers automatic differentiation, just-in-time compilation, and parallel execution, making it particularly well-suited for scalable and efficient model training on modern hardware accelerators.\n...\nJAX, a newer framework, at a high -level is simpler and more flexible than PyTorch for creating high-performance machine learning code.\n...\nComparing the performance and speed of JAX and PyTorch, JAX works well on hardware accelerators such as GPUs and TPUs, leading to potentially faster performance in specific scenarios.\nHowever, PyTorch’s longer tenure and larger community translate to more available resources for optimizing performance.\nFurthermore, automatic differentiation stands as a significant feature in effectively training deep learning models.\nPyTorch’s autograd package offers a straightforward method for computing gradients and adjusting model parameters.\nMeanwhile, JAX builds upon Autograd and elevates automatic differentiation by integrating its XLA (Accelerated Linear Algebra) backend.\n...\n## Critical Points for Pytorch and JAX\n- JAX performance increases when using GPUs to run the code and further the performance increases when using JIT compilation.\nThis provides a greater advantage as GPUs utilize parallelization, which provides faster performance than CPUs.\n- JAX has excellent built-in support for parallelism across multiple devices, surpassing other frameworks commonly utilized for machine learning tasks like PyTorch and TensorFlow.\n- JAX provides Auto differentiation with the grad() function, this function comes in handy while training a deep neural network.\nAs DNN requires backpropagation, JAX utilizes an analytical gradient solver instead of using other sophisticated techniques.\nIt essentially breaks down the function’s structure and applies the chain rule to compute gradients.\n- Pytorch combines Torch’s efficient and adaptable GPU-accelerated backend libraries with a user-friendly Python frontend.\nIt provides prototyping, clear code readability, and extensive support for diverse deep-learning models.\n-\n...\nThey share similarities with NumPy’s ndarrays, with the added capability of GPU acceleration for faster computation.\n...\nThe code below compares the execution time of matrix multiplication using JAX and PyTorch.\nIt generates large matrices of 1000x1000 and measures the time taken to perform the multiplication operation using both libraries.\n...\nstart_time = time.time()\n...\ntorch_execution_time = time.time() - start_time\nprint(\"JAX execution time:\", jax_execution_time, \"seconds\")\nprint(\"PyTorch execution time:\", torch_execution_time, \"seconds\")\n```\nJAX execution time: 0.00592041015625 seconds\nPyTorch execution time: 0.017140865325927734 seconds\n...\nIn conclusion, both PyTorch and JAX offer powerful frameworks for machine learning and developing deep neural networks.\nEach framework comes with its strengths and areas of expertise.\nPyTorch excels in its ease of use, extensive community support, and flexibility for rapid prototyping and experimentation, making it an ideal choice for many deep-learning projects.\nOn the other hand, JAX shines in its performance optimization, functional programming paradigm, and seamless integration with hardware accelerators, making it a preferred framework for high-performance computing and research at scale.\nUltimately, the choice between PyTorch and JAX depends on the project’s specific requirements, balancing ease of development against performance and scalability needs.",
        "title": "Comparing PyTorch and JAX",
        "url": "https://www.digitalocean.com/community/tutorials/pytorch-vs-jax",
        "date": "2024-12-20",
        "last_updated": "2026-05-16"
      },
      {
        "snippet": "",
        "title": "Deep Learning in Practice: A Technical Comparison of ...",
        "url": "https://medium.com/@nijesh-kanjinghat/deep-learning-in-practice-a-technical-comparison-of-pytorch-and-jax-6458a115dcde",
        "date": "2025-09-25",
        "last_updated": "2025-10-22"
      },
      {
        "snippet": "",
        "title": "JAX vs PyTorch 2.0 vs TensorFlow 3.0: Comparison 2026 - Index.dev",
        "url": "https://www.index.dev/skill-vs-skill/ai-pytorch2-vs-tensorflow3-vs-jax",
        "date": null,
        "last_updated": "2026-03-27"
      },
      {
        "snippet": "This blog uses the ViT classification models of varying sizes to benchmark the training performance of PyTorch and JAX versions on the Vertex AI Platform under different machine configurations.\nThe goal is to:\n- Benchmark OSS ViT training for both PyTorch and JAX frameworks.\n- Benchmark OSS ViT L16, H14, g14, and G14 models.\n- Benchmark OSS ViT PyTorch training with A100 GPUs.\n- Benchmark OSS ViT JAX training with A100 GPUs and TPU V3 accelerators.\n...\nFor both the PyTorch and JAX experiments, the following evaluation metrics are\ncollected:\n- Throughput: Images-per-second observed for training.\n- Cost: The training-cost-per-epoch (USD).\n...\nThe following section provides observations and conclusions for these results.\n## Observation and Conclusions\n- Training with JAX TPU V3 POD with 32 cores costs 33% less than the PyTorch GPU\n8 A100-40GBs runs.\n- Training with JAX GPU 8 A100-40GBs costs 23% less than the PyTorch GPU 8\nA100-40GBs runs.\n- JAX TPU V3 POD with 32 cores was 4x faster and slightly more cost-effective\nthan the JAX TPU V3 8 core run for the ViT-large model.\nThis indicates that it\nmight be better to use more cores.\nThe JAX TPU V3 speed scales very well with\nthe number of cores.\n- Cloud TPU VM training speed numbers were the same as the Vertex AI for\nTPU V3 8 cores.\nThe dataset was copied to the docker in both the cases.\n- The training-cost-per-epoch increases with the model size irrespective of the\nframework.",
        "title": "vertex-ai-samples/community-content/vertex_model_garden/benchmarking_reports/jax_vit_benchmarking_report.md at main · GoogleCloudPlatform/vertex-ai-samples",
        "url": "https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/community-content/vertex_model_garden/benchmarking_reports/jax_vit_benchmarking_report.md",
        "date": "2021-05-27",
        "last_updated": "2025-06-05"
      },
      {
        "snippet": "Benchmark scripts for comparing the UvA Deep Learning Tutorials in PyTorch and JAX.\nThe scripts are reduced versions of the tutorials, and save the runtimes of each model in a logging file in the `logs/` directory.\n...\nThe scripts have been executed with PyTorch v1.11 and JAX v0.3.13.\n...\nTo run all benchmarks, simply run `bash eval_all.sh`.\nAfterwards, you can find the evaluated runtimes in the `logs/` folder.\n## Benchmark times\nWe report the runtimes for all models on an NVIDIA RTX3090 GPU with 24-core CPU.\nThe times are averaged over two runs, which commonly have a standard deviation of <5%.\n### Tutorial 5: Inception, ResNet and DenseNet\n|Models|PyTorch|JAX|\n|--|--|--|\n|GoogleNet|53min 50sec|16min 10sec|\n|ResNet|20min 47sec|7min 51sec|\n|Pre-Activation ResNet|20min 57sec|8min 25sec|\n|DenseNet|49min 23sec|20min 1sec|\n### Tutorial 6: Transformers and Multi-Head Attention\n|Models|PyTorch|JAX|\n|--|--|--|\n|Reverse Sequence|0min 26sec|0min 7sec|\n|Anomaly Detection|16min 34sec|3min 45sec|\n### Tutorial 9: Deep Autoencoders\n|Models|PyTorch|JAX|\n|--|--|--|\n|AE - 64 latents|13min 10sec|7min 10sec|\n|AE - 128 latents|13min 11sec|7min 10sec|\n|AE - 256 latents|13min 11sec|7min 11sec|\n|AE - 384 latents|13min 12sec|7min 14sec|\n### Tutorial 11: Normalizing Flows\n|Models|PyTorch|JAX|\n|--|--|--|\n|MNIST Flow - Simple|2hrs 37min 29sec|1hrs 17min 59sec|\n|MNIST Flow - VarDeq|3hrs 25min 10sec|1hrs 36min 56sec|\n|MNIST Flow - Multiscale|2hrs 17min 10sec|57min 57sec|\n### Tutorial 15: Vision Transformer\n|Models|PyTorch|JAX|\n|--|--|--|\n|Vision Transformer|28min 40sec|27min 10sec|",
        "title": "GitHub - phlippe/uvadlc_notebooks_benchmarking: Benchmark scripts for comparing tutorials in PyTorch and JAX",
        "url": "https://github.com/phlippe/uvadlc_notebooks_benchmarking",
        "date": "2022-07-03",
        "last_updated": "2026-04-16"
      },
      {
        "snippet": "So I decided to implement the same model in both and compare.\nHere’s the top level summary:\n**PyTorch gets 1.11 iterations per second and JAX gets 1.24it/s (12% better)** on a Google Colab notebook with a P100.\nIn addition, **JAX is more memory efficient, the PyTorch model OOMs with more than 62 examples at a time and JAX can get up to 79** (at 1.01it/s, or 79.79 examples per second vs PyTorch’s 68.82 with the smaller batch size).\nMeanwhile TPUs are kind of absurd.\nTorch on XLA theoretically exists, but I don’t know of anyone who’s actually gotten it to work.\nWhen I was testing it my code\n*segfaulted*.\nTPUs work very smoothing with JAX though.\nI was accepted in the TPU Research Cloud (formerly TFRC), and a TPUv3-8 can run through 2,591 examples per second with a batch size of 3,032.\n...\nThe model is a simple, byte-level, autoregressive transformer language model trained on enwik9.\n...\nI let the model train for around four days on a TPUv3-8.\nI was surprised by how well it works.",
        "title": "JAX vs PyTorch: A simple transformer benchmark - Echo Nolan's Blog",
        "url": "https://www.echonolan.net/posts/2021-09-06-JAX-vs-PyTorch-A-Transformer-Benchmark.html",
        "date": "2021-09-06",
        "last_updated": "2025-11-03"
      }
    ],
    "server_time": null
  }
  ````
</Accordion>

## IDE Integration

### Enhanced Development Experience

Maximize IDE support with proper type usage:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity
  from perplexity.types import ResponseCreateResponse, SearchCreateResponse

  class EnhancedClient:
      def __init__(self):
          self.client = Perplexity()
      
      def search(self, query: str, **kwargs) -> SearchCreateResponse:
          """
          Perform search with full type hints
          
          Args:
              query: Search query string
              **kwargs: Additional search parameters
              
          Returns:
              SearchCreateResponse: Typed search results
          """
          return self.client.search.create(query=query, **kwargs)
      
      def respond(self, message: str, preset: str = "low") -> ResponseCreateResponse:
          """
          Agent API response with type hints

          Args:
              message: User message
              preset: Research preset to use

          Returns:
              ResponseCreateResponse: Typed Agent API response
          """
          return self.client.responses.create(
              preset=preset,
              input=message
          )

  # Usage with full IDE support
  enhanced_client = EnhancedClient()

  # IDE provides full autocomplete and type checking
  search_result = enhanced_client.search("Python tutorials")
  print(search_result.results[0].title)  # Full intellisense available

  agent_result = enhanced_client.respond("Explain decorators")
  print(agent_result.output_text)
  ```

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

  class EnhancedClient {
      private client: Perplexity;
      
      constructor() {
          this.client = new Perplexity();
      }
      
      /**
       * Perform search with full type hints
       */
      async search(
          query: string, 
          options?: Partial<Perplexity.Search.SearchCreateParams>
      ): Promise<Perplexity.Search.SearchCreateResponse> {
          return this.client.search.create({ 
              query, 
              ...options 
          });
      }
      
      /**
       * Agent API response with inferred types
       */
      async respond(
          message: string, 
          preset: string = "low"
      ) {
          return this.client.responses.create({
              preset,
              input: message
          });
      }
  }

  // Usage with full IDE support
  const enhancedClient = new EnhancedClient();

  // IDE provides full autocomplete and type checking
  const searchResult = await enhancedClient.search("Python tutorials");
  console.log(searchResult.results[0].title); // Full intellisense available

  const agentResult = await enhancedClient.respond("Explain decorators");
  console.log(agentResult.output_text);
  ```
</CodeGroup>

## Type Safety Best Practices

<Steps>
  <Step title="Always use type imports">
    Import and use specific types for better IDE support and error catching.

    <CodeGroup>
      ```python Python theme={null}
      # Good: Specific type imports
      from typing import List
      from perplexity.types import SearchCreateResponse, SearchResult

      def process_search(response: SearchCreateResponse) -> List[str]:
          return [result.title for result in response.results]
      ```

      ```typescript TypeScript theme={null}
      // Good: Use namespace types for type safety
      import Perplexity from '@perplexity-ai/perplexity_ai';

      function processSearch(response: Perplexity.Search.SearchCreateResponse): string[] {
          return response.results.map(result => result.title);
      }
      ```
    </CodeGroup>
  </Step>

  <Step title="Use type guards for runtime safety">
    Implement proper type checking for dynamic data.

    <Warning>
      TypeScript types are compile-time only. Use type guards for runtime validation.
    </Warning>
  </Step>

  <Step title="Leverage generic types">
    Create reusable typed functions and classes for common patterns.

    <Tip>
      Generic types help maintain type safety while providing flexibility.
    </Tip>
  </Step>

  <Step title="Document with types">
    Use type annotations as documentation for better code maintainability.

    <CodeGroup>
      ```python Python theme={null}
      def analyze_search_results(
          response: SearchCreateResponse,
          min_score: float = 0.5
      ) -> Dict[str, Any]:
          """
          Analyze search results with scoring
          
          Args:
              response: Search API response
              min_score: Minimum quality score threshold
              
          Returns:
              Analysis results with scores and recommendations
          """
          # Implementation with type safety
      ```

      ```typescript TypeScript theme={null}
      /**
       * Analyze search results with scoring
       */
      function analyzeSearchResults(
          response: Perplexity.Search.SearchCreateResponse,
          minScore: number = 0.5
      ): { scores: number[]; recommendations: string[] } {
          // Implementation with type safety
      }
      ```
    </CodeGroup>
  </Step>
</Steps>

## Related Resources

<CardGroup>
  <Card title="Error Handling" icon="alert-triangle" href="/docs/sdk/error-handling">
    Type-safe error handling patterns
  </Card>

  <Card title="Best Practices" icon="star" href="/docs/sdk/best-practices">
    Type safety in production code
  </Card>
</CardGroup>


# Perplexity Search SDK
Source: https://docs.perplexity.ai/docs/search-sdk/overview

An agents-first Python SDK that brings Perplexity's Search as Code approach to your applications: composable retrieval primitives that agents orchestrate in code.

## Search as code

Traditional search treats retrieval as a monolith: a model issues a query, the search engine runs a predefined pipeline, and the model consumes the processed results. That contract breaks down for agents working on complex, open-ended tasks — it produces coarse context, wastes the model's domain knowledge, and forces naturally parallel work through a serial interface.

[Search as Code](https://research.perplexity.ai/articles/rethinking-search-as-code-generation) is Perplexity's answer: expose the search stack as composable primitives that agents orchestrate through generated code. The agent controls retrieval, ranking, filtering, fan-out, and rendering directly, keeps intermediate state in the runtime instead of model context, and consumes only the information that matters.

The Perplexity Search SDK brings this approach to your own agents and applications. It provides the [Search API](/docs/search/quickstart)'s real-time ranked web results and query-relevant page snippets as Python primitives, with built-in concurrency, provenance, and checkpointing for retrieval-heavy workflows.

## Built for agents

The SDK is agents-first: it is designed to be driven by coding agents, not learned from prose documentation. The canonical usage reference is the SDK's Agent Skill, which covers installation, authentication, the full method surface, workflow patterns, and known pitfalls:

<Card title="pplx-search-sdk Agent Skill" icon="github" href="https://github.com/perplexityai/api-platform-developers/tree/main/skills/pplx-search-sdk">
  Install this skill into your coding agent and let the agent write the integration.
</Card>

The source lives at [perplexityai/perplexity-search-sdk](https://github.com/perplexityai/perplexity-search-sdk), and the package is published on PyPI as [pplx-srch-sdk](https://pypi.org/project/pplx-srch-sdk/).

## Related products

* If search is one call inside a broader Perplexity integration, use the [Perplexity SDK](/docs/sdk/overview).
* For other languages, or when you want a plain HTTP contract, use the [Search API](/docs/search/quickstart) directly.


# Use Search API with the Anthropic SDK
Source: https://docs.perplexity.ai/docs/search/agent-sdks/anthropic

Register Perplexity's Search API as a tool inside the Anthropic Messages API and run the standard tool-use loop with Claude.

## Overview

This guide shows how to expose Perplexity's [Search API](/docs/search/quickstart) to Claude as a tool. The Anthropic Messages API uses a manual tool-use loop: the model emits a `tool_use` block, you execute the tool (in this case, call `client.search.create`), and you send the result back as a `tool_result`. The loop continues until the model returns a final answer.

## Prerequisites

<CodeGroup>
  ```bash Python theme={null}
  pip install anthropic perplexityai
  export ANTHROPIC_API_KEY="your_anthropic_key"
  export PERPLEXITY_API_KEY="your_perplexity_key"
  ```

  ```bash Typescript theme={null}
  npm install @anthropic-ai/sdk @perplexity-ai/perplexity_ai
  export ANTHROPIC_API_KEY="your_anthropic_key"
  export PERPLEXITY_API_KEY="your_perplexity_key"
  ```
</CodeGroup>

## Tool definition

Claude needs a tool description that tells it when and how to call `web_search`. The description below was tuned for Perplexity's Search API; keep it verbatim — the wording of the description and the parameter guidance is what produces good, short, keyword-style queries.

<CodeGroup>
  ```python Python theme={null}
  WEB_SEARCH_TOOL_DESCRIPTION = """\
  Searches the web for current and factual information to answer user queries, returning relevant results with titles, URLs, and content snippets, similar to Google or Bing. Intended for questions about up-to-date or externally verified information beyond your knowledge cutoff. The tool works best with an array of short, keyword-focused queries. Complex queries that require multi-step reasoning are not supported. Time-sensitive queries are supported if the date is included in the query.

  Best practices for using this tool:
  - Limit the number of queries in each request to a maximum of three to maintain efficiency.
  - For multi-entity questions, break them into separate, single-entity queries:
    - Preferred:
      [
        "Brand A protein powder review",
        "Brand B protein powder review"
      ]
    - Not recommended:
      [
        "Brand A vs Brand B protein powder review"
      ]

  - For simple queries, keep each query straightforward and focused:
    - Preferred: ["inflation rate Canada"]
    - Not recommended: ["What is the inflation rate in Canada?"]

  Each query should be short to ensure optimal tool performance. Make sure all provided examples and generated queries follow this guideline."""

  QUERIES_PARAM_DESCRIPTION = (
      "An array of keyword-based search queries. Each query should be short, "
      "as longer queries may reduce performance. Do not provide more than three "
      "queries to maintain efficiency."
  )

  WEB_SEARCH_TOOL = {
      "name": "web_search",
      "description": WEB_SEARCH_TOOL_DESCRIPTION,
      "input_schema": {
          "type": "object",
          "properties": {
              "queries": {
                  "type": "array",
                  "description": QUERIES_PARAM_DESCRIPTION,
                  "items": {"type": "string"},
                  "minItems": 1,
                  "maxItems": 3,
              },
          },
          "required": ["queries"],
      },
  }
  ```

  ```typescript Typescript theme={null}
  const WEB_SEARCH_TOOL_DESCRIPTION = `Searches the web for current and factual information to answer user queries, returning relevant results with titles, URLs, and content snippets, similar to Google or Bing. Intended for questions about up-to-date or externally verified information beyond your knowledge cutoff. The tool works best with an array of short, keyword-focused queries. Complex queries that require multi-step reasoning are not supported. Time-sensitive queries are supported if the date is included in the query.

  Best practices for using this tool:
  - Limit the number of queries in each request to a maximum of three to maintain efficiency.
  - For multi-entity questions, break them into separate, single-entity queries:
    - Preferred:
      [
        "Brand A protein powder review",
        "Brand B protein powder review"
      ]
    - Not recommended:
      [
        "Brand A vs Brand B protein powder review"
      ]

  - For simple queries, keep each query straightforward and focused:
    - Preferred: ["inflation rate Canada"]
    - Not recommended: ["What is the inflation rate in Canada?"]

  Each query should be short to ensure optimal tool performance. Make sure all provided examples and generated queries follow this guideline.`;

  const QUERIES_PARAM_DESCRIPTION =
    "An array of keyword-based search queries. Each query should be short, " +
    "as longer queries may reduce performance. Do not provide more than three " +
    "queries to maintain efficiency.";

  const WEB_SEARCH_TOOL = {
    name: "web_search",
    description: WEB_SEARCH_TOOL_DESCRIPTION,
    input_schema: {
      type: "object" as const,
      properties: {
        queries: {
          type: "array" as const,
          description: QUERIES_PARAM_DESCRIPTION,
          items: { type: "string" as const },
          minItems: 1,
          maxItems: 3,
        },
      },
      required: ["queries"],
    },
  };
  ```
</CodeGroup>

## Tool handler

The handler is a thin wrapper around `client.search.create`. The Search API natively accepts an array of queries (up to five), so the array Claude emits can be passed straight through.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  perplexity = Perplexity()

  def run_web_search(queries: list[str]) -> str:
      """Call Perplexity Search and format the results for the model."""
      response = perplexity.search.create(query=queries, max_results=5)

      lines = []
      for result in response.results:
          snippet = (result.snippet or "").strip().replace("\n", " ")
          if len(snippet) > 400:
              snippet = snippet[:400] + "…"
          lines.append(f"- {result.title}\n  {result.url}\n  {snippet}")
      return "\n\n".join(lines) if lines else "No results."
  ```

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

  const perplexity = new Perplexity();

  async function runWebSearch(queries: string[]): Promise<string> {
    const response = await perplexity.search.create({
      query: queries,
      max_results: 5,
    });

    const lines = response.results.map((r) => {
      const snippet = (r.snippet ?? "").trim().replace(/\n/g, " ");
      const trimmed = snippet.length > 400 ? `${snippet.slice(0, 400)}…` : snippet;
      return `- ${r.title}\n  ${r.url}\n  ${trimmed}`;
    });
    return lines.length ? lines.join("\n\n") : "No results.";
  }
  ```
</CodeGroup>

## Tool-use loop

Anthropic's Messages API hands you a `stop_reason` of `"tool_use"` and one or more `ToolUseBlock` items inside `response.content`. Run each tool call, build a `tool_result` block per call (paired by `tool_use_id`), and send all results back in a single user message. Loop until `stop_reason` is no longer `"tool_use"`.

<CodeGroup>
  ```python Python theme={null}
  import json
  from anthropic import Anthropic

  claude = Anthropic()

  def chat_with_search(user_prompt: str, model: str = "claude-sonnet-4-6") -> str:
      messages = [{"role": "user", "content": user_prompt}]

      while True:
          response = claude.messages.create(
              model=model,
              max_tokens=1024,
              tools=[WEB_SEARCH_TOOL],
              messages=messages,
          )

          if response.stop_reason != "tool_use":
              # Final answer — pull text blocks out of the assistant message.
              return "".join(
                  block.text for block in response.content if block.type == "text"
              )

          # Append the assistant's tool-call turn to history.
          messages.append({"role": "assistant", "content": response.content})

          # Run every tool call in this turn and pair results by tool_use_id.
          tool_results = []
          for block in response.content:
              if block.type != "tool_use":
                  continue
              if block.name == "web_search":
                  output = run_web_search(block.input["queries"])
              else:
                  output = json.dumps({"error": f"unknown tool: {block.name}"})
              tool_results.append({
                  "type": "tool_result",
                  "tool_use_id": block.id,
                  "content": output,
              })

          messages.append({"role": "user", "content": tool_results})


  if __name__ == "__main__":
      answer = chat_with_search(
          "What were the major AI infrastructure announcements this week?"
      )
      print(answer)
  ```

  ```typescript Typescript theme={null}
  import Anthropic from "@anthropic-ai/sdk";

  const claude = new Anthropic();

  async function chatWithSearch(
    userPrompt: string,
    model = "claude-sonnet-4-6",
  ): Promise<string> {
    const messages: Anthropic.MessageParam[] = [
      { role: "user", content: userPrompt },
    ];

    while (true) {
      const response = await claude.messages.create({
        model,
        max_tokens: 1024,
        tools: [WEB_SEARCH_TOOL],
        messages,
      });

      if (response.stop_reason !== "tool_use") {
        return response.content
          .filter((b): b is Anthropic.TextBlock => b.type === "text")
          .map((b) => b.text)
          .join("");
      }

      messages.push({ role: "assistant", content: response.content });

      const toolResults: Anthropic.ToolResultBlockParam[] = [];
      for (const block of response.content) {
        if (block.type !== "tool_use") continue;
        let output: string;
        if (block.name === "web_search") {
          const input = block.input as { queries: string[] };
          output = await runWebSearch(input.queries);
        } else {
          output = JSON.stringify({ error: `unknown tool: ${block.name}` });
        }
        toolResults.push({
          type: "tool_result",
          tool_use_id: block.id,
          content: output,
        });
      }

      messages.push({ role: "user", content: toolResults });
    }
  }

  (async () => {
    const answer = await chatWithSearch(
      "What were the major AI infrastructure announcements this week?",
    );
    console.log(answer);
  })();
  ```
</CodeGroup>

## Streaming

For streaming responses, use `client.messages.stream(...)` and accumulate `tool_use` blocks from the events. The model emits `input_json_delta` events with partial JSON arguments; the SDK helper accumulates them and exposes the completed `tool_use` block via `stream.get_final_message()` (Python) or `stream.finalMessage()` (TypeScript). The loop structure is otherwise identical to the non-streaming version.

<CodeGroup>
  ```python Python theme={null}
  with claude.messages.stream(
      model="claude-sonnet-4-6",
      max_tokens=1024,
      tools=[WEB_SEARCH_TOOL],
      messages=messages,
  ) as stream:
      for text in stream.text_stream:
          print(text, end="", flush=True)
      final = stream.get_final_message()

  # Inspect final.stop_reason and final.content for tool_use blocks, then
  # resume the loop the same way as in the non-streaming version.
  ```

  ```typescript Typescript theme={null}
  const stream = claude.messages.stream({
    model: "claude-sonnet-4-6",
    max_tokens: 1024,
    tools: [WEB_SEARCH_TOOL],
    messages,
  });

  for await (const chunk of stream) {
    if (chunk.type === "content_block_delta" && chunk.delta.type === "text_delta") {
      process.stdout.write(chunk.delta.text);
    }
  }
  const final = await stream.finalMessage();
  // Inspect final.stop_reason and final.content as in the non-streaming version.
  ```
</CodeGroup>

## Notes

* **Parallel tool calls.** Claude can emit multiple `tool_use` blocks in a single assistant turn. Every block must have a matching `tool_result` in the *same* subsequent user message, paired by `tool_use_id`. To disable, set `tool_choice={"type": "auto", "disable_parallel_tool_use": True}`.
* **Result formatting.** The string returned to `tool_result.content` is what the model reads next. Including the URL alongside the snippet helps the model cite sources when it produces its final answer.
* **Errors.** To signal that a tool call failed, set `"is_error": True` on the `tool_result` block and put a short error message in `content`. The model will see the error and can recover (for example, by reformulating queries).
* **Domains and dates.** Pass `search_domain_filter`, `country`, and other Search API parameters inside `run_web_search` if you want fixed retrieval constraints. See the [Search API quickstart](/docs/search/quickstart) for the full parameter list.

## Next Steps

<CardGroup>
  <Card title="Use with OpenAI SDK" icon="code" href="/docs/search/agent-sdks/openai">
    Wire Search API into the OpenAI Responses API.
  </Card>

  <Card title="Use with Gemini SDK" icon="code" href="/docs/search/agent-sdks/gemini">
    Wire Search API into Google's `google-genai` SDK.
  </Card>

  <Card title="Search API Quickstart" icon="rocket" href="/docs/search/quickstart">
    Full Search API parameter reference.
  </Card>

  <Card title="Search Best Practices" icon="lightbulb" href="/docs/search/best-practices">
    Patterns for production search workloads.
  </Card>
</CardGroup>


# Use Search API with the Google Gemini SDK
Source: https://docs.perplexity.ai/docs/search/agent-sdks/gemini

Register Perplexity's Search API as a function tool inside Google's google-genai SDK and run the tool-call loop with Gemini models.

## Overview

This guide shows how to expose Perplexity's [Search API](/docs/search/quickstart) to Gemini as a function tool through Google's `google-genai` SDK. The model emits a `functionCall` part with `name` and `args`, you execute the tool (in this case, call `client.search.create`), and you send the result back as a `functionResponse` part. The loop continues until the model returns a final text response.

<Info>
  The Python SDK can run the tool-call loop **automatically** if you pass a Python callable directly to `tools=[...]` — the SDK introspects the signature and invokes your function. This page uses the **manual** loop so the pattern matches the [Anthropic](/docs/search/agent-sdks/anthropic) and [OpenAI](/docs/search/agent-sdks/openai) integration pages and so you keep explicit control over the call. The auto-loop variant is shown in [Notes](#notes).
</Info>

## Prerequisites

<CodeGroup>
  ```bash Python theme={null}
  pip install google-genai perplexityai
  export GEMINI_API_KEY="your_gemini_key"
  export PERPLEXITY_API_KEY="your_perplexity_key"
  ```

  ```bash Typescript theme={null}
  npm install @google/genai @perplexity-ai/perplexity_ai
  export GEMINI_API_KEY="your_gemini_key"
  export PERPLEXITY_API_KEY="your_perplexity_key"
  ```
</CodeGroup>

## Tool definition

Gemini accepts a `Tool` containing one or more `FunctionDeclaration` objects. Each declaration takes a `name`, `description`, and a JSON Schema for parameters. The description below was tuned for Perplexity's Search API; keep it verbatim — the wording is what produces good, short, keyword-style queries.

<CodeGroup>
  ```python Python theme={null}
  from google.genai import types

  WEB_SEARCH_TOOL_DESCRIPTION = """\
  Searches the web for current and factual information to answer user queries, returning relevant results with titles, URLs, and content snippets, similar to Google or Bing. Intended for questions about up-to-date or externally verified information beyond your knowledge cutoff. The tool works best with an array of short, keyword-focused queries. Complex queries that require multi-step reasoning are not supported. Time-sensitive queries are supported if the date is included in the query.

  Best practices for using this tool:
  - Limit the number of queries in each request to a maximum of three to maintain efficiency.
  - For multi-entity questions, break them into separate, single-entity queries:
    - Preferred:
      [
        "Brand A protein powder review",
        "Brand B protein powder review"
      ]
    - Not recommended:
      [
        "Brand A vs Brand B protein powder review"
      ]

  - For simple queries, keep each query straightforward and focused:
    - Preferred: ["inflation rate Canada"]
    - Not recommended: ["What is the inflation rate in Canada?"]

  Each query should be short to ensure optimal tool performance. Make sure all provided examples and generated queries follow this guideline."""

  QUERIES_PARAM_DESCRIPTION = (
      "An array of keyword-based search queries. Each query should be short, "
      "as longer queries may reduce performance. Do not provide more than three "
      "queries to maintain efficiency."
  )

  WEB_SEARCH_FUNCTION = types.FunctionDeclaration(
      name="web_search",
      description=WEB_SEARCH_TOOL_DESCRIPTION,
      parameters_json_schema={
          "type": "object",
          "properties": {
              "queries": {
                  "type": "array",
                  "description": QUERIES_PARAM_DESCRIPTION,
                  "items": {"type": "string"},
                  "minItems": 1,
                  "maxItems": 3,
              },
          },
          "required": ["queries"],
      },
  )

  WEB_SEARCH_TOOL = types.Tool(function_declarations=[WEB_SEARCH_FUNCTION])
  ```

  ```typescript Typescript theme={null}
  import { Type } from "@google/genai";
  import type { FunctionDeclaration, Tool } from "@google/genai";

  const WEB_SEARCH_TOOL_DESCRIPTION = `Searches the web for current and factual information to answer user queries, returning relevant results with titles, URLs, and content snippets, similar to Google or Bing. Intended for questions about up-to-date or externally verified information beyond your knowledge cutoff. The tool works best with an array of short, keyword-focused queries. Complex queries that require multi-step reasoning are not supported. Time-sensitive queries are supported if the date is included in the query.

  Best practices for using this tool:
  - Limit the number of queries in each request to a maximum of three to maintain efficiency.
  - For multi-entity questions, break them into separate, single-entity queries:
    - Preferred:
      [
        "Brand A protein powder review",
        "Brand B protein powder review"
      ]
    - Not recommended:
      [
        "Brand A vs Brand B protein powder review"
      ]

  - For simple queries, keep each query straightforward and focused:
    - Preferred: ["inflation rate Canada"]
    - Not recommended: ["What is the inflation rate in Canada?"]

  Each query should be short to ensure optimal tool performance. Make sure all provided examples and generated queries follow this guideline.`;

  const QUERIES_PARAM_DESCRIPTION =
    "An array of keyword-based search queries. Each query should be short, " +
    "as longer queries may reduce performance. Do not provide more than three " +
    "queries to maintain efficiency.";

  const WEB_SEARCH_FUNCTION: FunctionDeclaration = {
    name: "web_search",
    description: WEB_SEARCH_TOOL_DESCRIPTION,
    parametersJsonSchema: {
      type: "object",
      properties: {
        queries: {
          type: "array",
          description: QUERIES_PARAM_DESCRIPTION,
          items: { type: "string" },
          minItems: 1,
          maxItems: 3,
        },
      },
      required: ["queries"],
    },
  };

  const WEB_SEARCH_TOOL: Tool = {
    functionDeclarations: [WEB_SEARCH_FUNCTION],
  };
  ```
</CodeGroup>

## Tool handler

The handler is a thin wrapper around `client.search.create`. The Search API natively accepts an array of queries (up to five), so the array Gemini emits can be passed straight through.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  perplexity = Perplexity()

  def run_web_search(queries: list[str]) -> str:
      """Call Perplexity Search and format the results for the model."""
      response = perplexity.search.create(query=queries, max_results=5)

      lines = []
      for result in response.results:
          snippet = (result.snippet or "").strip().replace("\n", " ")
          if len(snippet) > 400:
              snippet = snippet[:400] + "…"
          lines.append(f"- {result.title}\n  {result.url}\n  {snippet}")
      return "\n\n".join(lines) if lines else "No results."
  ```

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

  const perplexity = new Perplexity();

  async function runWebSearch(queries: string[]): Promise<string> {
    const response = await perplexity.search.create({
      query: queries,
      max_results: 5,
    });

    const lines = response.results.map((r) => {
      const snippet = (r.snippet ?? "").trim().replace(/\n/g, " ");
      const trimmed = snippet.length > 400 ? `${snippet.slice(0, 400)}…` : snippet;
      return `- ${r.title}\n  ${r.url}\n  ${trimmed}`;
    });
    return lines.length ? lines.join("\n\n") : "No results.";
  }
  ```
</CodeGroup>

## Tool-call loop

Disable the automatic loop with `AutomaticFunctionCallingConfig(disable=True)` (Python) — the JS SDK doesn't auto-loop in core APIs to begin with. Then walk `response.function_calls`, execute each call, and send the model a follow-up `Content` array that contains the original `function_call` parts and the matching `function_response` parts.

<CodeGroup>
  ```python Python theme={null}
  import json
  from google import genai
  from google.genai import types

  gemini = genai.Client()

  def chat_with_search(user_prompt: str, model: str = "gemini-2.5-flash") -> str:
      contents: list[types.Content] = [
          types.Content(
              role="user",
              parts=[types.Part.from_text(text=user_prompt)],
          ),
      ]

      config = types.GenerateContentConfig(
          tools=[WEB_SEARCH_TOOL],
          automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True),
      )

      while True:
          response = gemini.models.generate_content(
              model=model,
              contents=contents,
              config=config,
          )

          function_calls = response.function_calls or []

          if not function_calls:
              return response.text

          # Persist the assistant's function_call parts.
          contents.append(response.candidates[0].content)

          # Run each function call and pair results by name (Gemini matches
          # function_response → function_call positionally within the turn).
          response_parts: list[types.Part] = []
          for call in function_calls:
              if call.name == "web_search":
                  queries = call.args.get("queries", [])
                  output = run_web_search(queries)
                  result = {"result": output}
              else:
                  result = {"error": f"unknown tool: {call.name}"}
              response_parts.append(
                  types.Part.from_function_response(name=call.name, response=result)
              )

          contents.append(types.Content(role="user", parts=response_parts))


  if __name__ == "__main__":
      answer = chat_with_search(
          "What were the major AI infrastructure announcements this week?"
      )
      print(answer)
  ```

  ```typescript Typescript theme={null}
  import { GoogleGenAI, type Content, type Part } from "@google/genai";

  const gemini = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });

  async function chatWithSearch(
    userPrompt: string,
    model = "gemini-2.5-flash",
  ): Promise<string> {
    const contents: Content[] = [
      { role: "user", parts: [{ text: userPrompt }] },
    ];

    while (true) {
      const response = await gemini.models.generateContent({
        model,
        contents,
        config: { tools: [WEB_SEARCH_TOOL] },
      });

      const functionCalls = response.functionCalls ?? [];

      if (functionCalls.length === 0) {
        return response.text ?? "";
      }

      // Persist the assistant's function_call parts.
      const candidate = response.candidates?.[0];
      if (candidate?.content) {
        contents.push(candidate.content);
      }

      const responseParts: Part[] = [];
      for (const call of functionCalls) {
        let result: Record<string, unknown>;
        if (call.name === "web_search") {
          const queries = (call.args?.queries as string[]) ?? [];
          result = { result: await runWebSearch(queries) };
        } else {
          result = { error: `unknown tool: ${call.name}` };
        }
        responseParts.push({
          functionResponse: { name: call.name!, response: result },
        });
      }

      contents.push({ role: "user", parts: responseParts });
    }
  }

  (async () => {
    const answer = await chatWithSearch(
      "What were the major AI infrastructure announcements this week?",
    );
    console.log(answer);
  })();
  ```
</CodeGroup>

## Streaming

For streaming, use `generate_content_stream` (Python) or `generateContentStream` (TypeScript). A single `functionCall` part can be split across stream chunks, so accumulate parts before invoking your handler. The loop structure is otherwise identical to the non-streaming version.

<CodeGroup>
  ```python Python theme={null}
  for chunk in gemini.models.generate_content_stream(
      model="gemini-2.5-flash",
      contents=contents,
      config=config,
  ):
      if chunk.text:
          print(chunk.text, end="", flush=True)
      # Accumulate function-call parts across chunks before executing.
  ```

  ```typescript Typescript theme={null}
  const stream = await gemini.models.generateContentStream({
    model: "gemini-2.5-flash",
    contents,
    config: { tools: [WEB_SEARCH_TOOL] },
  });

  for await (const chunk of stream) {
    if (chunk.text) process.stdout.write(chunk.text);
    // Accumulate function-call parts across chunks before executing.
  }
  ```
</CodeGroup>

## Notes

* **Automatic loop (Python only).** The Python SDK can run the tool-call loop for you. Pass a Python callable directly and the SDK will introspect its signature, invoke it, and feed the result back to the model — no manual loop, no `Content` plumbing.

  ```python theme={null}
  def web_search(queries: list[str]) -> str:
      """<paste the verbatim WEB_SEARCH_TOOL_DESCRIPTION here as the docstring>"""
      return run_web_search(queries)

  response = gemini.models.generate_content(
      model="gemini-2.5-flash",
      contents="What were the major AI infrastructure announcements this week?",
      config=types.GenerateContentConfig(tools=[web_search]),
  )
  print(response.text)
  ```

  The auto-loop depth caps at 10 by default — raise it via `AutomaticFunctionCallingConfig(maximum_remote_calls=N)` for long research chains. Auto-mode is convenient but trades visibility for terseness: errors surface through exceptions rather than tool-result content the model can recover from.
* **Parallel calls.** Gemini can emit multiple `function_call` parts in a single response. Build one `function_response` part per call (matched by `name` plus the call's position within the turn) and put them all in one follow-up `Content`.
* **Pair `function_call` and `function_response`.** Both turns must be present in the next `generate_content` call — the model needs to see its own `function_call` part alongside your `function_response` part. Dropping either side produces "missing function response" errors.
* **Domains and dates.** Pass `search_domain_filter`, `country`, and other Search API parameters inside `run_web_search` if you want fixed retrieval constraints. See the [Search API quickstart](/docs/search/quickstart) for the full parameter list.

## Next Steps

<CardGroup>
  <Card title="Use with Anthropic SDK" icon="code" href="/docs/search/agent-sdks/anthropic">
    Wire Search API into the Anthropic Messages API.
  </Card>

  <Card title="Use with OpenAI SDK" icon="code" href="/docs/search/agent-sdks/openai">
    Wire Search API into the OpenAI Responses API.
  </Card>

  <Card title="Search API Quickstart" icon="rocket" href="/docs/search/quickstart">
    Full Search API parameter reference.
  </Card>

  <Card title="Search Best Practices" icon="lightbulb" href="/docs/search/best-practices">
    Patterns for production search workloads.
  </Card>
</CardGroup>


# Use Search API with the OpenAI SDK
Source: https://docs.perplexity.ai/docs/search/agent-sdks/openai

Register Perplexity's Search API as a function tool inside the OpenAI Responses API and run the standard tool-call loop with GPT models.

## Overview

This guide shows how to expose Perplexity's [Search API](/docs/search/quickstart) to an OpenAI model as a function tool. The Responses API uses a manual tool-call loop: the model emits a `function_call` item with a `call_id`, you execute the tool (in this case, call `client.search.create`), and you send the result back as a `function_call_output` item paired by `call_id`. The loop continues until the response no longer contains pending function calls.

<Info>
  This page uses the **Responses API** (`client.responses.create`), the newer OpenAI surface. The tool shape is flat (`{type: "function", name, description, parameters, strict}`) — different from the legacy `chat.completions` function-calling shape that nests under `function: {…}`.
</Info>

## Prerequisites

<CodeGroup>
  ```bash Python theme={null}
  pip install openai perplexityai
  export OPENAI_API_KEY="your_openai_key"
  export PERPLEXITY_API_KEY="your_perplexity_key"
  ```

  ```bash Typescript theme={null}
  npm install openai @perplexity-ai/perplexity_ai
  export OPENAI_API_KEY="your_openai_key"
  export PERPLEXITY_API_KEY="your_perplexity_key"
  ```
</CodeGroup>

## Tool definition

The Responses API takes a flat tool object: `type`, `name`, `description`, `parameters` (JSON Schema), and optional `strict`. The description below was tuned for Perplexity's Search API; keep it verbatim — the wording is what produces good, short, keyword-style queries.

<CodeGroup>
  ```python Python theme={null}
  WEB_SEARCH_TOOL_DESCRIPTION = """\
  Searches the web for current and factual information to answer user queries, returning relevant results with titles, URLs, and content snippets, similar to Google or Bing. Intended for questions about up-to-date or externally verified information beyond your knowledge cutoff. The tool works best with an array of short, keyword-focused queries. Complex queries that require multi-step reasoning are not supported. Time-sensitive queries are supported if the date is included in the query.

  Best practices for using this tool:
  - Limit the number of queries in each request to a maximum of three to maintain efficiency.
  - For multi-entity questions, break them into separate, single-entity queries:
    - Preferred:
      [
        "Brand A protein powder review",
        "Brand B protein powder review"
      ]
    - Not recommended:
      [
        "Brand A vs Brand B protein powder review"
      ]

  - For simple queries, keep each query straightforward and focused:
    - Preferred: ["inflation rate Canada"]
    - Not recommended: ["What is the inflation rate in Canada?"]

  Each query should be short to ensure optimal tool performance. Make sure all provided examples and generated queries follow this guideline."""

  QUERIES_PARAM_DESCRIPTION = (
      "An array of keyword-based search queries. Each query should be short, "
      "as longer queries may reduce performance. Do not provide more than three "
      "queries to maintain efficiency."
  )

  WEB_SEARCH_TOOL = {
      "type": "function",
      "name": "web_search",
      "description": WEB_SEARCH_TOOL_DESCRIPTION,
      "strict": True,
      "parameters": {
          "type": "object",
          "additionalProperties": False,
          "properties": {
              "queries": {
                  "type": "array",
                  "description": QUERIES_PARAM_DESCRIPTION,
                  "items": {"type": "string"},
              },
          },
          "required": ["queries"],
      },
  }
  ```

  ```typescript Typescript theme={null}
  const WEB_SEARCH_TOOL_DESCRIPTION = `Searches the web for current and factual information to answer user queries, returning relevant results with titles, URLs, and content snippets, similar to Google or Bing. Intended for questions about up-to-date or externally verified information beyond your knowledge cutoff. The tool works best with an array of short, keyword-focused queries. Complex queries that require multi-step reasoning are not supported. Time-sensitive queries are supported if the date is included in the query.

  Best practices for using this tool:
  - Limit the number of queries in each request to a maximum of three to maintain efficiency.
  - For multi-entity questions, break them into separate, single-entity queries:
    - Preferred:
      [
        "Brand A protein powder review",
        "Brand B protein powder review"
      ]
    - Not recommended:
      [
        "Brand A vs Brand B protein powder review"
      ]

  - For simple queries, keep each query straightforward and focused:
    - Preferred: ["inflation rate Canada"]
    - Not recommended: ["What is the inflation rate in Canada?"]

  Each query should be short to ensure optimal tool performance. Make sure all provided examples and generated queries follow this guideline.`;

  const QUERIES_PARAM_DESCRIPTION =
    "An array of keyword-based search queries. Each query should be short, " +
    "as longer queries may reduce performance. Do not provide more than three " +
    "queries to maintain efficiency.";

  const WEB_SEARCH_TOOL = {
    type: "function" as const,
    name: "web_search",
    description: WEB_SEARCH_TOOL_DESCRIPTION,
    strict: true,
    parameters: {
      type: "object" as const,
      additionalProperties: false,
      properties: {
        queries: {
          type: "array" as const,
          description: QUERIES_PARAM_DESCRIPTION,
          items: { type: "string" as const },
        },
      },
      required: ["queries"],
    },
  };
  ```
</CodeGroup>

<Warning>
  **Strict mode constraints.** When `strict: true`, the JSON Schema must set `additionalProperties: false` and list every property in `required`. OpenAI rejects `maxItems`/`minItems` and similar constraints in strict mode — enforce the "max three queries" guidance through the description, then truncate defensively in your handler.
</Warning>

## Tool handler

The handler is a thin wrapper around `client.search.create`. The Search API natively accepts an array of queries, so the array the model emits can be passed straight through.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  perplexity = Perplexity()

  def run_web_search(queries: list[str]) -> str:
      """Call Perplexity Search and format the results for the model."""
      # Defensive cap — the description asks for ≤3, but trust nothing.
      queries = queries[:3]

      response = perplexity.search.create(query=queries, max_results=5)

      lines = []
      for result in response.results:
          snippet = (result.snippet or "").strip().replace("\n", " ")
          if len(snippet) > 400:
              snippet = snippet[:400] + "…"
          lines.append(f"- {result.title}\n  {result.url}\n  {snippet}")
      return "\n\n".join(lines) if lines else "No results."
  ```

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

  const perplexity = new Perplexity();

  async function runWebSearch(queries: string[]): Promise<string> {
    const capped = queries.slice(0, 3);

    const response = await perplexity.search.create({
      query: capped,
      max_results: 5,
    });

    const lines = response.results.map((r) => {
      const snippet = (r.snippet ?? "").trim().replace(/\n/g, " ");
      const trimmed = snippet.length > 400 ? `${snippet.slice(0, 400)}…` : snippet;
      return `- ${r.title}\n  ${r.url}\n  ${trimmed}`;
    });
    return lines.length ? lines.join("\n\n") : "No results.";
  }
  ```
</CodeGroup>

## Tool-call loop

The Responses API returns `response.output` as a flat list of items. Walk it for items whose `type` is `"function_call"`, execute each call, and append a paired `function_call_output` item to the running `input` array. Re-call `responses.create` until the response has no more function calls.

<CodeGroup>
  ```python Python theme={null}
  import json
  from openai import OpenAI

  openai_client = OpenAI()

  def chat_with_search(user_prompt: str, model: str = "gpt-5.5") -> str:
      # The Responses API's `input` is an ordered list of items; we append
      # function_call_output items to it as the loop progresses.
      input_items: list[dict] = [{"role": "user", "content": user_prompt}]

      while True:
          response = openai_client.responses.create(
              model=model,
              input=input_items,
              tools=[WEB_SEARCH_TOOL],
          )

          function_calls = [
              item for item in response.output if item.type == "function_call"
          ]

          if not function_calls:
              return response.output_text

          # Persist the assistant's function_call items in the conversation.
          for item in response.output:
              input_items.append(item.model_dump())

          # Run each function call and append a paired function_call_output.
          for call in function_calls:
              args = json.loads(call.arguments)
              if call.name == "web_search":
                  output = run_web_search(args["queries"])
              else:
                  output = json.dumps({"error": f"unknown tool: {call.name}"})
              input_items.append({
                  "type": "function_call_output",
                  "call_id": call.call_id,
                  "output": output,
              })


  if __name__ == "__main__":
      answer = chat_with_search(
          "What were the major AI infrastructure announcements this week?"
      )
      print(answer)
  ```

  ```typescript Typescript theme={null}
  import OpenAI from "openai";

  const openaiClient = new OpenAI();

  async function chatWithSearch(
    userPrompt: string,
    model = "gpt-5.5",
  ): Promise<string> {
    const inputItems: OpenAI.Responses.ResponseInputItem[] = [
      { role: "user", content: userPrompt },
    ];

    while (true) {
      const response = await openaiClient.responses.create({
        model,
        input: inputItems,
        tools: [WEB_SEARCH_TOOL],
      });

      const functionCalls = response.output.filter(
        (item): item is OpenAI.Responses.ResponseFunctionToolCall =>
          item.type === "function_call",
      );

      if (functionCalls.length === 0) {
        return response.output_text;
      }

      // Persist the assistant's function_call items in the conversation.
      inputItems.push(...response.output);

      for (const call of functionCalls) {
        const args = JSON.parse(call.arguments) as { queries: string[] };
        let output: string;
        if (call.name === "web_search") {
          output = await runWebSearch(args.queries);
        } else {
          output = JSON.stringify({ error: `unknown tool: ${call.name}` });
        }
        inputItems.push({
          type: "function_call_output",
          call_id: call.call_id,
          output,
        });
      }
    }
  }

  (async () => {
    const answer = await chatWithSearch(
      "What were the major AI infrastructure announcements this week?",
    );
    console.log(answer);
  })();
  ```
</CodeGroup>

## Streaming

For streaming, use `client.responses.stream(...)`. The SDK emits typed events: `response.output_item.added` when a `function_call` item starts, `response.function_call_arguments.delta` for each chunk of the arguments JSON, and `response.function_call_arguments.done` when the argument string is complete. The loop structure is otherwise identical to the non-streaming version.

<CodeGroup>
  ```python Python theme={null}
  with openai_client.responses.stream(
      model="gpt-5.5",
      input=input_items,
      tools=[WEB_SEARCH_TOOL],
  ) as stream:
      for event in stream:
          if event.type == "response.output_text.delta":
              print(event.delta, end="", flush=True)
      final = stream.get_final_response()

  # Inspect final.output for function_call items, then resume the loop the
  # same way as in the non-streaming version.
  ```

  ```typescript Typescript theme={null}
  const stream = openaiClient.responses.stream({
    model: "gpt-5.5",
    input: inputItems,
    tools: [WEB_SEARCH_TOOL],
  });

  for await (const event of stream) {
    if (event.type === "response.output_text.delta") {
      process.stdout.write(event.delta);
    }
  }
  const final = await stream.finalResponse();
  // Inspect final.output for function_call items as in the non-streaming version.
  ```
</CodeGroup>

## Notes

* **`call_id` pairs requests with results.** Every `function_call_output` item must include the originating `call_id`. Multiple parallel function calls in one assistant turn each get their own paired output.
* **Server-side state.** Instead of resending the whole `input` array on each turn, you can pass `previous_response_id=<id>` and only append new items. This is useful for long agent loops.
* **`output_text` shortcut.** `response.output_text` flattens the assistant text content for you. If you need granular access (annotations, segments), iterate `response.output` and pull `output_text` blocks out of the message item.
* **Domains and dates.** Pass `search_domain_filter`, `country`, and other Search API parameters inside `run_web_search` if you want fixed retrieval constraints. See the [Search API quickstart](/docs/search/quickstart) for the full parameter list.

## Next Steps

<CardGroup>
  <Card title="Use with Anthropic SDK" icon="code" href="/docs/search/agent-sdks/anthropic">
    Wire Search API into the Anthropic Messages API.
  </Card>

  <Card title="Use with Gemini SDK" icon="code" href="/docs/search/agent-sdks/gemini">
    Wire Search API into Google's `google-genai` SDK.
  </Card>

  <Card title="Search API Quickstart" icon="rocket" href="/docs/search/quickstart">
    Full Search API parameter reference.
  </Card>

  <Card title="Search Best Practices" icon="lightbulb" href="/docs/search/best-practices">
    Patterns for production search workloads.
  </Card>
</CardGroup>


# Best Practices
Source: https://docs.perplexity.ai/docs/search/best-practices

Learn best practices for optimizing search queries and implementing efficient async patterns with Perplexity's Search API.

***

## Overview

This guide covers essential best practices for getting the most out of Perplexity's Search API, including query optimization techniques and efficient async usage patterns for high-performance applications.

## Query Optimization

<Steps>
  <Step title="Write specific queries">
    Use highly specific queries for more targeted results. For example, instead of searching for "AI", use a detailed query like "artificial intelligence machine learning healthcare applications 2024".

    <CodeGroup>
      ```python Python theme={null}
      # Better: Specific query
      search = client.search.create(
          query="artificial intelligence medical diagnosis accuracy radiology",
          max_results=10
      )

      # Avoid: Vague query
      search = client.search.create(
          query="AI medical",
          max_results=10
      )
      ```

      ```typescript Typescript theme={null}
      // Better: Specific query
      const search = await client.search.create({
          query: "artificial intelligence medical diagnosis accuracy radiology",
          max_results: 10
      });

      // Avoid: Vague query
      const search = await client.search.create({
          query: "AI medical",
          max_results: 10
      });
      ```
    </CodeGroup>

    <AccordionGroup>
      <Accordion title="Response — artificial intelligence medical diagnosis accuracy radiology">
        ```json theme={null}
        {
          "id": "f7ff7fde-da09-42fb-8fba-93333178d895",
          "results": [
            {
              "snippet": "",
              "title": "The Role of Artificial Intelligence in Diagnostic Radiology - PMC - NIH",
              "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC11582495/",
              "date": "2024-10-23",
              "last_updated": "2026-03-31"
            },
            {
              "snippet": "- **Study shows AI improves performance for some radiologists but worsens it for others.**\n- **Understanding who might benefit from AI and who would not is critical for designing tools that boost human performance.**\n- **The findings underscore the importance of tailored AI-clinician integration over a one-size-fits-all approach.**\nOne of the most touted promises of medical artificial intelligence tools is their ability to augment human clinicians’ performance by helping them interpret images such as X-rays and CT scans with greater precision to make more accurate diagnoses.\nBut the benefits of using AI tools on image interpretation appear to vary from clinician to clinician, according to new research led by investigators at Harvard Medical School, working with colleagues at MIT and Stanford.\n...\nThe study findings suggest that individual clinician differences shape the interaction between human and machine in critical ways that researchers do not yet fully understand.\n...\nIn some instances, the research showed, use of AI can interfere with a radiologist’s performance and interfere with the accuracy of their interpretation.\n“We find that different radiologists, indeed, react differently to AI assistance — some are helped while others are hurt by it,” said co-senior author Pranav Rajpurkar, assistant professor of biomedical informatics in the Blavatnik Institute at HMS.\n“What this means is that we should not look at radiologists as a uniform population and consider just the ‘average’ effect of AI on their performance,” he said.\n...\n“Individual factors and variation would be key in ensuring that AI advances rather than interferes with performance and, ultimately, with diagnosis,” Yu said.\n...\nWhile previous research has shown that AI assistants can, indeed, boost radiologists’ diagnostic performance, these studies have looked at radiologists as a whole without accounting for variability from radiologist to radiologist.\n...\nThe researchers examined how AI tools affected the performance of 140 radiologists on 15 X-ray diagnostic tasks — how reliably the radiologists were able to spot telltale features on an image and make an accurate diagnosis.\n...\nThe effect of AI assistance was inconsistent and varied across radiologists, with the performance of some radiologists improving with AI and worsening in others.\n...\nAI’s effects on human radiologists’ performance varied in often surprising ways.\nFor instance, contrary to what the researchers expected, factors such how many years of experience a radiologist had, whether they specialized in thoracic, or chest, radiology, and whether they’d used AI readers before, did not reliably predict how an AI tool would affect a doctor’s performance.\nAnother finding that challenged the prevailing wisdom: Clinicians who had low performance at baseline did not benefit consistently from AI assistance.\nSome benefited more, some less, and some none at all.\nOverall, however, lower-performing radiologists at baseline had lower performance with or without AI.\nThe same was true among radiologists who performed better at baseline.\nThey performed consistently well, overall, with or without AI.\nThen came a not-so-surprising finding: More accurate AI tools boosted radiologists’ performance, while poorly performing AI tools diminished the diagnostic accuracy of human clinicians.\n...\nThe researchers cautioned that their findings do not provide an explanation for why and how AI tools seem to affect performance across human clinicians differently, but note that understanding why would be critical to ensuring that AI radiology tools augment human performance rather than hurt it.\n...\nApart from improving the accuracy of the AI tools, it’s also important to train radiologists to detect inaccurate AI predictions and to question an AI tool’s diagnostic call, the research team said.\nTo achieve that, AI developers should ensure that they design AI models that can “explain” their decisions.",
              "title": "Does AI Help or Hurt Human Radiologists' Performance? It Depends ...",
              "url": "https://hms.harvard.edu/news/does-ai-help-or-hurt-human-radiologists-performance-depends-doctor",
              "date": "2024-03-19",
              "last_updated": "2026-05-16"
            },
            {
              "snippet": "",
              "title": "Redefining Radiology: A Review of Artificial Intelligence Integration ...",
              "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC10487271/",
              "date": "2023-08-25",
              "last_updated": "2026-05-12"
            },
            {
              "snippet": "",
              "title": "Diagnostic accuracy of artificial intelligence-assisted radiology ...",
              "url": "https://academic.oup.com/bjrai/article/2/1/ubaf016/8322749",
              "date": "2025-01-03",
              "last_updated": "2026-05-18"
            },
            {
              "snippet": "",
              "title": "Revolutionizing Radiology With Artificial Intelligence - PMC - NIH",
              "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC11521355/",
              "date": "2024-10-29",
              "last_updated": "2026-04-05"
            },
            {
              "snippet": "",
              "title": "Diagnostic Accuracy and Clinical Value of a Domain-specific Multimodal Generative AI Model for Chest Radiograph Report Generation | Radiology",
              "url": "https://pubs.rsna.org/doi/10.1148/radiol.241476",
              "date": "2025-03-25",
              "last_updated": "2025-03-25"
            },
            {
              "snippet": "",
              "title": "Diagnostic accuracy of artificial intelligence-assisted radiology ...",
              "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC13045702/",
              "date": "2025-11-13",
              "last_updated": "2026-05-02"
            },
            {
              "snippet": "",
              "title": "Is Artificial Intelligence the Future of Radiology? Accuracy ...",
              "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC11624516/",
              "date": "2024-12-06",
              "last_updated": "2026-05-05"
            },
            {
              "snippet": "Diagnostic accuracy studies that compared radiologists with and without AI-assistance in cancer diagnostic tasks over all imaging modalities were included.\n...\n**\nResults:\n** Thirty-four studies were included of which 23 were included in meta-analysis.\nEight identified cancers on Chest X-rays, 17 on CT, 9 on MRI.\nPooled sensitivity and specificity were 0.67 (95%CI 0.58-0.74) and 0.82 (95%CI 0.75-0.88), respectively, for clinicians and 0.79 (95%CI 0.71-0.88) and 0.87 (95%CI 0.82-0.91) for AI-assistance.\n17 of 34 studies (50%) had concern of bias with QUADAS-C.\nCLAIM assessment highlighted reporting issues in several domains of methodology in a proportion of studies.\n**\nConclusion:\n** Artificial intelligence assistance tools may benefit clinician diagnostic performance in cancer diagnosis.\nUpdated reporting guidelines may help to overcome potential methodological limitations to clarify AI's value in healthcare.",
              "title": "Diagnostic accuracy of artificial intelligence-assisted radiology assessment of cancer: a systematic review - PubMed",
              "url": "https://pubmed.ncbi.nlm.nih.gov/42064000/",
              "date": "2025-11-13",
              "last_updated": "2026-05-02"
            },
            {
              "snippet": "",
              "title": "Artificial Intelligence-Empowered Radiology—Current Status and ...",
              "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC11816879/",
              "date": "2025-01-24",
              "last_updated": "2026-04-07"
            }
          ],
          "server_time": null
        }
        ```
      </Accordion>

      <Accordion title="Response — AI medical">
        ```json theme={null}
        {
          "id": "0b4ab51d-19e1-40f1-91b4-a5604cd5f33d",
          "results": [
            {
              "snippet": "The FDA encourages the development of innovative, safe, and effective medical devices, including devices that incorporate artificial intelligence (AI).\nThe AI-Enabled Medical Device List is a resource intended to identify AI-enabled medical devices that are authorized for marketing in the United States.\nDigital health innovators can refer to this list to gain insights into the current device landscape and regulatory expectations, which can help foster innovation and ensure public safety.\nThis list can also provide transparency for healthcare providers and patients to clearly identify when medical devices use AI technologies.\n...\n- To support transparency in the use of modern AI technologies, the FDA will explore methods to identify and tag medical devices that incorporate foundation models encompassing a wide range of AI systems, from large language models (LLMs) to multimodal architectures.\nThis identification will help innovators, healthcare providers, and patients recognize when LLM-based functionality is present in a medical device.\nTo facilitate the FDA’s development of methods to identify AI-enabled medical devices more easily, including identifying those devices incorporating LLM-based functionality in a future update of this list, sponsors are encouraged to include appropriate information in their public summaries.",
              "title": "Artificial Intelligence-Enabled Medical Devices - FDA",
              "url": "https://www.fda.gov/medical-devices/software-medical-device-samd/artificial-intelligence-enabled-medical-devices",
              "date": "2026-04-03",
              "last_updated": "2026-05-21"
            },
            {
              "snippet": "AI has the potential to help save lives by transforming healthcare and medicine through the creation of more personalized, accessible and effective solutions.\nIn collaboration with healthcare providers, researchers and industry partners, we’ve published research, created open-source tools, and built AI systems that have the potential to positively impact health outcomes for people globally.\n...\nBuilding clinical-grade AI presents a significant challenge: organizations with specialized health data often lack the resources to create foundational models from scratch, while general-purpose models may not meet the standards for safe and reliable use in patient care.\nTo accelerate innovation and foster novel solutions, we’ve released powerful, open-weight models to help developers build AI models for healthcare.\nThis includes MedGemma, our most capable open model for multimodal medical text and image comprehension, and TxGemma, a collection of open models to accelerate the development of therapeutics.\n...\nWe’re imagining ways that AI systems could be useful conversational partners for clinicians and patients.\nArticulate Medical Intelligence Explorer (AMIE) is an experimental system which aims to combine clinical reasoning with conversational empathy.\nAMIE is an exploration into the art of the possible, where our research is testing novel ways for AI to safely support clinicians and patients.\n...\nOur research extends to the future of personalized wellness, exploring how AI can help interpret complex data from wearables and devices.\nThis includes our work on our foundational Large Sensor Model (LSM), trained on the largest dataset of its kind to decode signals like heart rate and activity levels with remarkable accuracy.\nAdditionally, our Personal Health LLM (PH-LLM), a version of the Gemini model fine-tuned for health, aims to empower people to understand their health and wellness data, set goals, and make informed decisions.\n...\nWe’ve developed an AI system to interpret chest X-ray scans for early signs of TB.\nWe’ve been working with Apollo Radiology International over the past few years to validate our AI systems in regions where they can have the most impact.\nOver the next 10 years, Apollo Radiology International will use these models to provide 3 million free AI-powered screenings for TB, lung cancer, and breast cancer — helping hundreds of thousands more people across India access timely care.\n...\nOpen Health Stack is a suite of open-source building blocks built on an interoperable data standard.\nThis suite of components makes it easier for developers to quickly build apps allowing healthcare workers to access the information and insights they need to make informed decisions.",
              "title": "Health AI - Google AI",
              "url": "https://ai.google/health/",
              "date": null,
              "last_updated": "2026-05-02"
            },
            {
              "snippet": "AI Health Main content start Back to Top",
              "title": "AI Health",
              "url": "https://aihealth.stanford.edu",
              "date": null,
              "last_updated": "2026-03-05"
            },
            {
              "snippet": "",
              "title": "The benefits of AI in health care and how doctors are using AI",
              "url": "https://www.youtube.com/watch?v=rfMr35T4vhw",
              "date": "2025-05-12",
              "last_updated": "2026-03-04"
            },
            {
              "snippet": "Redefine GI Cancer Diagnostics with AI\nJapanese Innovation Revolutionizing Medicine World-wide\n...\nAI Medical Service was founded to take on these issues with AI (artificial intelligence), contributing to advances in endoscopic medicine and the elimination of GI cancers through early-stage detection.\n...\nThe journey we are embarked on is to provide the world with unprecedented Japanese AI medical software.\n...\ngastroAI media is a specialized media site for endoscopists.\nUtilizing our connections with endoscopists working on the front lines, we provide information on diagnosis, insertion, and observation know-how for early stage cancer, as well as research information on endoscopic AI.",
              "title": "AI Medical Service Corporation｜Saving Patients Around the World",
              "url": "https://en.ai-ms.com",
              "date": "2026-05-15",
              "last_updated": "2026-05-16"
            },
            {
              "snippet": "",
              "title": "Artificial intelligence in healthcare: transforming the practice of ...",
              "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC8285156/",
              "date": null,
              "last_updated": "2026-05-15"
            },
            {
              "snippet": "",
              "title": "How AI is transforming medicine - Harvard Gazette",
              "url": "https://news.harvard.edu/gazette/story/2025/03/how-ai-is-transforming-medicine-healthcare/",
              "date": "2025-03-20",
              "last_updated": "2026-05-21"
            }
          ],
          "server_time": null
        }
        ```
      </Accordion>
    </AccordionGroup>

    <Tip>
      Specific queries with context, time frames, and precise terminology yield more relevant and actionable results.
    </Tip>
  </Step>

  <Step title="Use multi-query for comprehensive research">
    Break your main topic into related sub-queries to cover all aspects of your research. Use the multi-query search feature to run multiple related queries in a single request for more comprehensive and relevant information.

    <CodeGroup>
      ```python Python theme={null}
      from perplexity import Perplexity

      client = Perplexity()

      # Comprehensive research with related queries
      search = client.search.create(
          query=[
              "artificial intelligence medical diagnosis accuracy 2024",
              "machine learning healthcare applications FDA approval",
              "AI medical imaging radiology deployment hospitals"
          ],
          max_results=5
      )

      # Access results
      for result in search.results:
          print(f"  {result.title}: {result.url}")
      ```

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

      const client = new Perplexity();

      // Comprehensive research with related queries
      const search = await client.search.create({
          query: [
              "artificial intelligence medical diagnosis accuracy 2024",
              "machine learning healthcare applications FDA approval",
              "AI medical imaging radiology deployment hospitals"
          ],
          max_results: 5
      });

      // Access results
      search.results.forEach(result => {
          console.log(`  ${result.title}: ${result.url}`);
      });
      ```
    </CodeGroup>

    <Info>
      You can include up to 5 queries in a single multi-query request for efficient batch processing.
    </Info>
  </Step>

  <Step title="Handle rate limits efficiently">
    Implement exponential backoff for rate limit errors and use appropriate batching strategies.

    <CodeGroup>
      ```python Python theme={null}
      import time
      import random
      from perplexity import Perplexity, RateLimitError

      def search_with_retry(client, query, max_retries=3):
          for attempt in range(max_retries):
              try:
                  return client.search.create(query=query)
              except RateLimitError:
                  if attempt < max_retries - 1:
                      # Exponential backoff with jitter
                      delay = (2 ** attempt) + random.uniform(0, 1)
                      time.sleep(delay)
                  else:
                      raise

      client = Perplexity()

      # Usage
      try:
          search = search_with_retry(client, "AI developments")
          for result in search.results:
              print(f"{result.title}: {result.url}")
      except RateLimitError:
          print("Maximum retries exceeded for search")
      ```

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

      async function searchWithRetry(
          client: Perplexity, 
          query: string, 
          maxRetries: number = 3
      ) {
          for (let attempt = 0; attempt < maxRetries; attempt++) {
              try {
                  return await client.search.create({ query });
              } catch (error) {
                  if (error instanceof Perplexity.RateLimitError && attempt < maxRetries - 1) {
                      // Exponential backoff with jitter
                      const delay = (2 ** attempt) + Math.random();
                      await new Promise(resolve => setTimeout(resolve, delay * 1000));
                  } else {
                      throw error;
                  }
              }
          }
          throw new Error("Max retries exceeded");
      }

      const client = new Perplexity();

      // Usage
      try {
          const search = await searchWithRetry(client, "AI developments");
          search.results.forEach(result => {
              console.log(`${result.title}: ${result.url}`);
          });
      } catch (error) {
          console.log("Maximum retries exceeded for search");
      }
      ```
    </CodeGroup>
  </Step>

  <Step title="Process concurrent searches efficiently">
    Use async for concurrent requests while respecting rate limits.

    <CodeGroup>
      ```python Python theme={null}
      import asyncio
      from perplexity import AsyncPerplexity

      async def batch_search(queries, batch_size=3, delay_ms=1000):
          async with AsyncPerplexity() as client:
              results = []
              
              for i in range(0, len(queries), batch_size):
                  batch = queries[i:i + batch_size]
                  
                  batch_tasks = [
                      client.search.create(query=query, max_results=5)
                      for query in batch
                  ]
                  
                  batch_results = await asyncio.gather(*batch_tasks)
                  results.extend(batch_results)
                  
                  # Add delay between batches
                  if i + batch_size < len(queries):
                      await asyncio.sleep(delay_ms / 1000)
              
              return results

      # Usage
      queries = ["AI developments", "climate change", "space exploration"]
      results = asyncio.run(batch_search(queries))
      print(f"Processed {len(results)} searches")
      ```

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

      async function batchSearch(
          queries: string[],
          batchSize: number = 3,
          delayMs: number = 1000
      ) {
          const client = new Perplexity();
          const results = [];
          
          for (let i = 0; i < queries.length; i += batchSize) {
              const batch = queries.slice(i, i + batchSize);
              
              const batchPromises = batch.map(query =>
                  client.search.create({
                      query,
                      max_results: 5
                  })
              );
              
              const batchResults = await Promise.all(batchPromises);
              results.push(...batchResults);
              
              // Add delay between batches
              if (i + batchSize < queries.length) {
                  await new Promise(resolve => setTimeout(resolve, delayMs));
              }
          }
          
          return results;
      }

      // Usage
      const queries = ["AI developments", "climate change", "space exploration"];
      const results = await batchSearch(queries);
      console.log(`Processed ${results.length} searches`);
      ```
    </CodeGroup>
  </Step>
</Steps>

## Async Usage

For high-performance applications requiring concurrent requests, use the async client:

<CodeGroup>
  ```python Python theme={null}
  import asyncio
  from perplexity import AsyncPerplexity

  async def main():
      async with AsyncPerplexity() as client:
          # Concurrent searches for better performance
          tasks = [
              client.search.create(
                  query="artificial intelligence industry adoption trends across sectors",
                  max_results=5
              ),
              client.search.create(
                  query="machine learning research breakthroughs in deep learning",
                  max_results=5
              ),
              client.search.create(
                  query="deep learning applications across industries",
                  max_results=5
              )
          ]
          
          results = await asyncio.gather(*tasks)
          
          for i, search in enumerate(results):
              print(f"Query {i+1} results:")
              for result in search.results:
                  print(f"  {result.title}: {result.url}")
              print("---")

  asyncio.run(main())
  ```

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

  const client = new Perplexity();

  async function main() {
      // Concurrent searches for better performance
      const tasks = [
          client.search.create({
              query: "artificial intelligence industry adoption trends across sectors",
              max_results: 5
          }),
          client.search.create({
              query: "machine learning research breakthroughs in deep learning",
              max_results: 5
          }),
          client.search.create({
              query: "deep learning applications across industries",
              max_results: 5
          })
      ];
      
      const results = await Promise.all(tasks);
      
      results.forEach((search, i) => {
          console.log(`Query ${i+1} results:`);
          search.results.forEach(result => {
              console.log(`  ${result.title}: ${result.url}`);
          });
          console.log("---");
      });
  }

  main();
  ```

  ```javascript JavaScript theme={null}
  const Perplexity = require('@perplexity-ai/perplexity_ai');

  const client = new Perplexity();

  async function main() {
      // Concurrent searches for better performance
      const tasks = [
          client.search.create({
              query: "artificial intelligence industry adoption trends across sectors",
              max_results: 5
          }),
          client.search.create({
              query: "machine learning research breakthroughs in deep learning",
              max_results: 5
          }),
          client.search.create({
              query: "deep learning applications across industries",
              max_results: 5
          })
      ];
      
      const results = await Promise.all(tasks);
      
      results.forEach((search, i) => {
          console.log(`Query ${i+1} results:`);
          search.results.forEach(result => {
              console.log(`  ${result.title}: ${result.url}`);
          });
          console.log("---");
      });
  }

  main();
  ```
</CodeGroup>

<AccordionGroup>
  <Accordion title="Response — artificial intelligence industry adoption trends across sectors">
    ```json theme={null}
    {
      "id": "9bf13556-1586-4d9e-bfc2-29595af3eac8",
      "results": [
        {
          "snippet": "",
          "title": "AI Adoption Across Industries: Trends You Don't Want to Miss in 2025",
          "url": "https://www.coherentsolutions.com/insights/ai-adoption-trends-you-should-not-miss-2025",
          "date": "2026-04-28",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "",
          "title": "The State of AI: Global Survey 2025 - McKinsey",
          "url": "https://www.mckinsey.com/capabilities/quantumblack/our-insights/the-state-of-ai",
          "date": "2025-11-05",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "Adoption of AI in the U.S. overall is relatively low with only 5% of businesses utilizing the technology currently.\nHowever, the adoption rate varies by industry (Figure 1).\nInformation and Professional, Scientific, and Technical Service sectors lead the way with 18% and 12% of businesses, respectively, reporting current use of AI, whereas Agriculture and Construction are sectors with low AI adoption at 1% each.\nBusinesses report that future use of AI within the next six months is projected to increase across all sectors, though the percentages again vary widely.\nInterestingly, AI adoption patterns across sectors correspond with the occupational impact prediction that white-collar, office jobs will be more impacted by AI than physical, outdoor jobs.\n...\nThe top two applications for future AI utilization in the U.S are marketing automation and data analytics.\nThese trends generally align with the North Carolina data, where 41% of NC businesses planning to use AI reported using it for marketing automation and 28% for data analytics.\nAn examination of U.S. sector-specific data (Figure 2) reveals that numerous industries anticipate using these AI applications.\nFor instance, AI-driven marketing automation is projected not only in sectors such as Real Estate, Retail, and Accommodation and Food Services but also in less obvious sectors like Construction, Education, and Agriculture.\nSimilarly for data analytics, industries such as Utilities, Management, and Transportation and Warehousing are leading in projected AI use.\nHowever, even in sectors like Arts, Entertainment, and Recreation about one in five businesses that report future AI usage, expect to use AI for data analytics by the end of summer.\n...\nAmong U.S. businesses expecting to incorporate AI in the next six months, 88% reported that their total employment levels will remain unchanged.\nFigure 3 shows the industry breakdown of the small percentage of businesses reporting an increase or decrease in total employment.\nThe Information sector, the leading adopter of AI, also tops the list for projected employment increases, with 10% of businesses expecting growth, while only 4% anticipate a decline, placing it among the lowest for employment decreases.\nA similar trend is evident in the Professional, Scientific, and Technical Services sector.\n...\nWhile overall AI adoption remains low, certain sectors like Information and Professional, Scientific, and Technical Services are leading the way.\nThe primary AI applications, marketing automation and data analytics, show broad applicability across various sectors, including some unexpected ones like Construction and Arts, Entertainment, and Recreation.\nAnd finally, while most businesses do not anticipate changes in employment levels, sectors with higher AI adoption rates, such as Information and Professional, Scientific, and Technical Services, may be showing signs of optimism for potential employment growth.",
          "title": "What Industries Are Using AI? Current Use and Future Expectations",
          "url": "https://www.commerce.nc.gov/news/the-lead-feed/what-industries-are-using-ai",
          "date": "2024-06-04",
          "last_updated": "2026-05-03"
        },
        {
          "snippet": "The research shows variation in AI adoption, according to Kristina McElheran, a visiting scholar with the MIT Initiative on the Digital Economy and the paper’s lead author.\nJust 6% of U.S. companies used AI in 2017, the researchers found, and AI use was concentrated in larger companies and in industries such as manufacturing and information technology.\nAdoption was also clustered in some “superstar” cities, such as San Francisco, San Antonio, and Nashville.\n...\nThe finding that just 6% of companies reported using AI in 2017 is still relevant today, McElheran said,  pointing to a November 2023 Census Bureau survey that showed that fewer than 4% of companies use AI to produce goods and services.\nThe initial, in-depth survey showed other early trends:\n- AI use was highest among large companies.\nMore than 50% of companies with more than 5,000 employees were using AI, as were more than 60% of companies with more than 10,000 employees.\n- Use varied among sectors.\nAbout 12% of firms in manufacturing, information services, and health care were using AI, compared with 4% in construction and retail.\n- AI adoption is happening in some superstar cities, but it has also clustered in some unlikely places.\nThese include manufacturing hubs in the Midwest as well as Southern cities with fewer companies overall than tech hubs in Silicon Valley, the Boston area, or New York City.\n“Use of AI in production is happening in different places than just the areas that are inventing and commercializing AI-based technologies,” McElheran said.\n...\nThe researchers found that startups using AI were more likely to have younger, more highly educated, and more highly experienced leaders than startups that were not using AI.\nVenture capital backing and a focus on process innovation were also associated with AI adoption.\n...\nSome of those AI users are in sectors not typically associated with cutting-edge technology, such as manufacturing and health care.\nThe former is closely linked to manufacturing’s use of robotics.",
          "title": "The who, what, and where of AI adoption in America | MIT Sloan",
          "url": "https://mitsloan.mit.edu/ideas-made-to-matter/who-what-and-where-ai-adoption-america",
          "date": "2024-02-07",
          "last_updated": "2026-05-18"
        },
        {
          "snippet": "",
          "title": "The Adoption of Artificial Intelligence in Firms - OECD",
          "url": "https://www.oecd.org/en/publications/the-adoption-of-artificial-intelligence-in-firms_f9ef33c3-en.html",
          "date": "2025-05-02",
          "last_updated": "2025-11-18"
        },
        {
          "snippet": "",
          "title": "AI Adoption by Industry: How Different Sectors Are Using AI at Scale in 2026",
          "url": "https://codewave.com/insights/ai-adoption-industry-trends-insights/",
          "date": "2026-02-26",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "",
          "title": "The Fed - Monitoring AI Adoption in the US Economy",
          "url": "https://www.federalreserve.gov/econres/notes/feds-notes/monitoring-ai-adoption-in-the-u-s-economy-20260403.html",
          "date": "2026-03-04",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "",
          "title": "AI Adoption Statistics Q1 2026: All Figures - Vention",
          "url": "https://ventionteams.com/solutions/ai/adoption-statistics",
          "date": "2024-06-26",
          "last_updated": "2026-05-03"
        },
        {
          "snippet": "",
          "title": "AI Adoption by Industry",
          "url": "https://www.netguru.com/blog/ai-adoption-statistics",
          "date": "2025-12-15",
          "last_updated": "2026-05-21"
        }
      ],
      "server_time": null
    }
    ```
  </Accordion>

  <Accordion title="Response — machine learning research breakthroughs in deep learning">
    ```json theme={null}
    {
      "id": "f22580ab-72a2-4038-bc35-8151455664a7",
      "results": [
        {
          "snippet": "",
          "title": "Timeline of machine learning - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/Timeline_of_machine_learning",
          "date": "2016-06-16",
          "last_updated": "2026-03-09"
        },
        {
          "snippet": "*Twenty years ago, Google started using machine learning, and 10 years ago, it helped spur rapid progress in AI using deep learning.\nJeff Dean and Marian Croak of Google Research take a look at how we’ve innovated on these techniques and applied them in helpful ways, and look ahead to a responsible and inclusive path forward.*\n...\nBut it would be another decade before we had enough computing power to revive a more computationally-intensive machine learning approach called deep learning.\nDeep learning uses neural networks with multiple layers (thus the “deep”), so it can learn not just simple statistical patterns, but can learn subtler patterns of patterns — such as what’s in an image or what word was spoken in some audio.\nOne of our first publications in 2012 was on a system that could find patterns among millions of frames from YouTube videos.\nThat meant, of course, that it learned to recognize cats.\nTo get to the helpful features you use every day — searchable photo albums, suggestions on email replies, language translation, flood alerts, and so on — we needed to make years of breakthroughs on top of breakthroughs, tapping into the best of Google Research in collaboration with the broader research community.\nLet me give you just a couple examples of how we’ve done this.\n**A big moment for image recognition**\nIn 2012, a paper wowed the research world for making a huge jump in accuracy on image recognition using deep neural networks, leading to a series of rapid advances by researchers outside and within Google.\nFurther advances led to applications like Google Photos in 2015, letting you search photos by what’s in them.\nWe then developed other deep learning models to help you find addresses in Google Maps, make sense of videos on YouTube, and explore the world around you using Google Lens.\nBeyond our products, we applied these approaches to health-related problems, such as detecting diabetic retinopathy in 2016, and then cancerous cells in 2017, and breast cancer in 2020.\nBetter understanding of aerial imagery through deep learning let us launch flood forecasting in 2018, now expanded to cover more than 360 million people in 2021.\nIt’s been encouraging to see how helpful these advances in image recognition have been.\nSimilarly, we’ve used deep learning to accelerate language understanding.\nWith sequence-to-sequence learning in 2014, we began looking at how to understand strings of text using deep learning.\nThis led to neural machine translation in Google Translate in 2016, which was a massive leap in quality, particularly for less prevalent languages.\nWe developed neural language models further for Smart Reply in Gmail in 2017, which made it easier and faster for you to knock through your email, especially on mobile.\nThat same year, Google invented Transformers, leading to BERT in 2018, then T5, and in 2021 MUM, which lets you ask Google much more nuanced questions.\nAnd with “sparse” models like GShard, we can dramatically improve on tasks like translation while using less energy.\nWe’ve driven a similar arc in understanding speech.\nIn 2012, Google used deep neural networks to make major improvements to speech recognition on Android.\nWe kept advancing the state of the art with higher-quality, faster, more efficient speech recognition systems.\nBy 2019, we were able to put the entire neural network on-device so you could get accurate speech recognition even without a connection.\nAnd in 2021, we launched Live Translate on the Pixel 6 phone, letting you speak and be translated in 48 languages -- all on-device, while you’re traveling with no Internet.\nProject Relate: A communication tool for people with speech impairments.\nML-based flood forecasting helps equip those in harm’s way with accurate and detailed alerts.\nGoogle Health's AI system helps radiologists identify cancer in mammograms with greater accuracy.\n...\nAs our research goes forward, we’re balancing more immediately applied research with more exploratory fundamental research.\nSo we’re looking at how, for example, AI can aid scientific discovery, with a project like mapping the brain of a fly, which could one day help better understand and treat mental illness in people.\nWe’re also pursuing quantum computing, which will likely take a decade or longer to reach wide-scale applications.\nThis is why we publish nearly 1000 papers a year, including around 200 related to responsible AI, and we’ve given over 6500 grants to external researchers over the past decade and a half.\n...\nOne example is Project Relate, which uses machine learning to help people with speech impairments communicate and use technology more easily.",
          "title": "A decade in deep learning, and what's next - Google Blog",
          "url": "https://blog.google/innovation-and-ai/products/decade-deep-learning-and-whats-next/",
          "date": "2021-11-18",
          "last_updated": "2026-05-02"
        },
        {
          "snippet": "",
          "title": "Deep Learning: A Comprehensive Overview on Techniques ... - PMC",
          "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC8372231/",
          "date": "2021-08-18",
          "last_updated": "2026-05-23"
        },
        {
          "snippet": "At UC San Diego, AI is empowering bold advances in science, education, public safety, health and the arts.\n...\nFrom uncovering hidden disease mechanisms to guiding new therapies and medical technologies, UC San Diego researchers are harnessing AI to propel humanity toward a future in which diseases are mitigated or eradicated.\nWhat was once science fiction is now possible.\nAs a tool, AI speeds diagnoses, offers a better understanding of the human body and enables more innovative treatments.\n...\nA gene once thought to be just a biomarker for Alzheimer’s disease is actually one of its causes, according to the work of UC San Diego bioengineers.\nUsing AI to model the 3D structures of proteins, the team discovered that the gene PHGDH has a hidden “moonlighting” role: It disrupts how brain cells switch genes on and off, a disturbance that can fuel the disease.\n...\nJoe Pogliano, professor, and Kit Pogliano, dean and distinguished professor, both in the School of Biological Sciences, worked with Linnaeus Bioscience and Seattle Children’s Research Institute to develop MycoBCP, a new AI-powered tool that could accelerate the search for TB treatments.\nThe technology builds on the Poglianos’ earlier bacterial cytological profiling method, which quickly shows how antibiotics work.\nBy pairing that method with deep learning, researchers could detect subtle changes in TB cells that would otherwise escape the human eye — revealing how potential drugs act on the pathogen.\n“This is the first time machine learning has been applied this way to bacteria,” says Joe Pogliano.\nThe advance, funded in part by the Gates Foundation, could fast-track the development of urgently needed TB therapies.\n...\nBy recording signals from outside of heart muscle cells and using AI to reconstruct what’s happening inside these cells, engineers were able to monitor heart activity with remarkable accuracy — without invasive methods or physically penetrating the cells.\nThe breakthrough offers safer, faster insights into how heart cells function, communicate and respond to new drugs.\n...\nResearchers have developed advanced deep-learning techniques that could revolutionize treatment planning for breast cancer radiotherapy — making it faster and improving its quality.\nThe approach reduced errors in radiation doses to critical organs, such as the heart and lungs.\n...\nUC San Diego engineers have created a flexible patch — a wireless, skin-mounted ultrasound device — that monitors muscle activity in real time to control a robotic arm, among other uses.\nTo extract additional insights from these muscle signals, the researchers developed an AI algorithm that maps the signals to their corresponding muscle distributions.\nCompact, battery-powered and designed for long-term wear, the technology could open new possibilities in health care monitoring and human-machine interaction.\n...\nIn a unique and long-standing collaboration, UC San Diego electrical engineering graduate students have been embedded with the Jacobs Retina Center at Shiley Eye Institute to develop better computer vision, AI and image-processing tools.\nThese will help physicians diagnose patients with greater speed and accuracy, predict the most effective treatments, and aid in the development of new treatments.\n...\nUC San Diego researchers are using AI to better understand Earth’s changing environment.\nThese innovations provide faster forecasts, actionable insights and tools that help protect communities and the planet.\n...\nRunning global climate simulations can take weeks on supercomputers, limiting the number of scenarios scientists can explore.\nResearchers at UC San Diego and the Allen Institute for AI have developed a new model, Spherical DYffusion, that projects 100 years of climate patterns in just 25 hours.\nBy combining generative AI techniques with physics-based data, the model delivers results 25 times faster than current methods without the need for massive supercomputers.\nThe breakthrough could provide scientists and policymakers with faster and more flexible tools for anticipating the long-term effects of climate change.\n...\nWith a growing network of more than 1,200 natural-hazard monitoring cameras spanning remote mountaintops to wildland-urban interfaces, ALERTCalifornia collects real-time data and utilizes AI that helps emergency managers spot smoke, monitor fires and plan evacuations.\nUC San Diego’s WIFIRE team at the San Diego Supercomputer Center utilizes those camera and sensor feeds to pinpoint wildfire ignition locations and create predictive models that map how a fire will spread.\n...\nThese models are further refined by AI-powered aerial sensing — including infrared imaging — to track fire perimeters through thick smoke and give responders a strategic advantage as wildfires progress.",
          "title": "Nine Breakthroughs Made Possible by AI - UC San Diego Today",
          "url": "https://today.ucsd.edu/story/nine-breakthroughs-made-possible-by-ai",
          "date": "2025-11-21",
          "last_updated": "2026-05-26"
        },
        {
          "snippet": "",
          "title": "Bolder breakthroughs, bigger impact - Google Research 2025",
          "url": "https://research.google/blog/google-research-2025-bolder-breakthroughs-bigger-impact/",
          "date": null,
          "last_updated": "2026-05-25"
        },
        {
          "snippet": "",
          "title": "Review Paper on Machine Learning Breakthroughs",
          "url": "https://www.ijfmr.com/papers/2024/3/22369.pdf",
          "date": null,
          "last_updated": "2025-09-23"
        },
        {
          "snippet": "",
          "title": "A Brief Overview of Deep Learning — Making Things Think - Holloway",
          "url": "https://www.holloway.com/g/making-things-think/sections/a-brief-overview-of-deep-learning",
          "date": "2022-11-02",
          "last_updated": "2026-04-12"
        }
      ],
      "server_time": null
    }
    ```
  </Accordion>

  <Accordion title="Response — deep learning applications across industries">
    ```json theme={null}
    {
      "id": "6c99d1de-cd0c-4795-970a-5b14387c296c",
      "results": [
        {
          "snippet": "Deep learning applications have a broad reach, spanning various fields and industries, and are an important part of artificial intelligence.\nDeep learning even plays a role in some of the products and technologies you likely use daily.\nWith a design inspired by the human brain, deep learning networks can process significant amounts of information, helping to make use of all the data that’s accessible in today's world so companies can improve their product offerings, learn more about consumers, and solve problems.\n...\n## 10 deep learning applications\nDeep learning applications are making an impact across many different industries.\nYou might even already use some of these applications in your everyday life.\nLet’s examine ten examples highlighting deep learning’s broad use to understand it better.\n### 1.\nFraud detection\nDeep learning algorithms can identify security issues to help protect against fraud.\nFor example, deep learning algorithms can detect suspicious attempts to log into your accounts and notify you, as well as inform you if your chosen password isn’t strong enough.\n### 2.\nCustomer service\nYou may have seen or used customer service help online and interacted with a chatbot to help answer your questions or utilized a virtual assistant on your smartphone.\nDeep learning allows these systems to learn over time to respond.\n### 3.\nFinancial services\nSeveral financial services can rely on assistance from deep learning.\nPredictive analytics helps support investment portfolios and trading assets in the stock market, as well as allowing banks to mitigate risk relating to loan approvals.\n### 4.\nNatural language processing\nNatural language processing is an important part of deep learning applications that rely on interpreting text and speech.\nCustomer service chatbots, language translators, and sentiment analysis are all examples of applications benefitting from natural language processing.\n...\n### 5.\nFacial recognition\nAn area of deep learning known as computer vision allows deep learning algorithms to recognize specific features in pictures and videos.\nWith this technique, you can use deep learning for facial recognition, identifying you by your own unique features.\n...\n### 6.\nSelf-driving vehicles\nAutonomous vehicles use deep learning to learn how to operate and handle different situations while driving, and it allows vehicles to detect traffic lights, recognize signs, and avoid pedestrians.\n### 7.\nPredictive analytics\nDeep learning models can analyze large amounts of historical information to make accurate predictions about the future.\nPredictive analytics helps businesses in several aspects, including forecasting revenue, product development, decision-making, and manufacturing.\n### 8.\nRecommender systems\nOnline services often use recommender systems with enhanced capabilities provided by deep learning models.\nWith enough data, these deep learning models can predict the probabilities of certain interactions based on the history of previous interactions.\nIndustries such as streaming services, e-commerce, and social media implement recommender systems.\n### 9.\nHealth care\nDeep learning applications in the health care industry serve multiple purposes.\nNot only can they assist in developing treatment solutions, but deep learning algorithms are also capable of understanding medical images and helping doctors diagnose patients by detecting cancer cells.\n...\n### 10.\nIndustrial\nDeep learning applications in industrial automation help keep workers safe in factories by enabling machines to detect dangerous situations, such as when objects or people are too close to the machines.\n###",
          "title": "10 Examples of Deep Learning Applications | Coursera",
          "url": "https://www.coursera.org/articles/deep-learning-applications",
          "date": "2024-03-22",
          "last_updated": "2026-05-18"
        },
        {
          "snippet": "",
          "title": "Top 25 Deep Learning Applications Used Across Industries",
          "url": "https://www.simplilearn.com/tutorials/deep-learning-tutorial/deep-learning-applications",
          "date": "2020-11-13",
          "last_updated": "2026-03-28"
        },
        {
          "snippet": "",
          "title": "Deep Learning Applications in...",
          "url": "https://www.neuralconcept.com/post/digital-thread-deep-learning-applications-in-engineering",
          "date": "2026-05-21",
          "last_updated": "2026-05-25"
        },
        {
          "snippet": "",
          "title": "Common Deep Learning...",
          "url": "https://builtin.com/artificial-intelligence/deep-learning-applications",
          "date": "2023-05-24",
          "last_updated": "2025-10-29"
        },
        {
          "snippet": "The widespread applications of deep learning span diverse industries, including healthcare, finance, agriculture, and natural language processing, signifying its transformative impact.\n...\nThis article delves into six prevalent applications of deep learning, namely computer vision, natural language processing, healthcare, finance, agriculture, and cybersecurity.\nWe will discuss how deep learning is being used in these fields and the benefits it provides.\n...\nA prominent application of deep learning in NLP is machine translation, where models are trained on extensive datasets of human language to accurately translate text from one language to another.\n...\nDeep learning is a game-changer in healthcare, particularly in enhancing medical imaging such as CT and MRI scans, enabling specialists to formulate more precise and personalized treatment plans.\n...\nDeep learning stands as a formidable force in revolutionizing the financial sector, offering a diverse array of applications that enhance decision-making, risk management, fraud detection, and customer experience.\n...\nA pivotal application lies in crop monitoring, where deep learning models are trained to scrutinize satellite, drone, and other remote sensing data to detect changes in crop health and predict yields.\n...\nDeep learning is a valuable asset in bolstering threat detection and response within cybersecurity.",
          "title": "Top 6 Transformative Applications of Deep Learning Across Industries",
          "url": "https://vngcloud.vn/blog/top-6-transformative-applications-of-deep-learning-across-industries",
          "date": "2024-01-24",
          "last_updated": "2026-04-09"
        },
        {
          "snippet": "Deep learning and neural networks have revolutionized various industries, offering unprecedented data analysis, pattern recognition, and automation capabilities.\nThis blog explores how these technologies are transforming different sectors and what the future might hold.\n### Deep Learning Applications in the Healthcare Industry\n- **Medical Imaging and Diagnostics**\nDeep learning algorithms are increasingly used in medical imaging to improve and enhance the accuracy and speed of diagnostics.\nThese algorithms can interpret medical images such as MRIs, CT scans, and X-rays to detect tumors, abnormalities, and other conditions.\nFor example, convolutional neural networks (CNNs) have been trained to identify early signs of breast cancer in mammograms, sometimes outperforming human radiologists.\nAdditionally, deep learning models assist in segmenting and classifying tissues, making the diagnostic process more efficient.\n- **Drug Discovery**\nIn the pharmaceutical industry, deep learning accelerates drug discovery by analyzing vast datasets of chemical compounds and biological interactions.\nRecurrent neural networks (RNNs) and generative adversarial networks (GANs) can predict the efficacy and potential side effects of new drugs, significantly shortening the research timeline.\nThese models simulate how different compounds interact with targets in the body, aiding in the identification of promising drug candidates.\n- **Personalized Medicine**\nPersonalized medicine leverages deep learning to tailor treatments to the specific needs of patients based on their genetic data.\nBy analyzing individual genetic makeup, neural networks can predict how patients will respond to different treatments, improving outcomes.\nThis approach is particularly valuable in oncology, where personalized treatment plans can be developed based on the genetic profile of a patient’s tumor.\n- **Clinical Documentation**\nNLP models help in transcribing and analyzing clinical notes, making it easier to extract valuable insights and improve patient care.\n- **Virtual Assistants**\nAI-powered virtual assistants can help in patient management by answering queries, scheduling appointments, and providing medical advice based on patient data.\n### Deep Learning Applications in the Finance Industry\n- **Fraud Detection**\nFinancial institutions use deep learning models to detect fraudulent transactions by analyzing patterns in transaction data.\nThese models, often based on deep belief networks (DBNs) and autoencoders, can identify anomalies that may indicate fraud.\nBy continuously learning from new data, these neural networks improve their detection capabilities over time, reducing false negatives and seizing increasingly higher numbers of fraudulent activities.\n- **Algorithmic Trading**\nHigh-frequency and high-volume trading systems are nowadays backed by deep learning algorithms that pore over market data, analyzing them in real-time, identifying patterns, trends, and indicators to execute trades at optimal moments to obtain the highest returns.\nLong short-term memory (LSTM) networks and other RNNs can process vast amounts of financial data, identifying market trends and patterns that human traders might miss.\nThese algorithms are highly reactive and can respond to market changes within milliseconds, capitalizing on opportunities that can be missed within the blink of an eye.\n- **Risk Management**\nNeural networks assess the risk of investments by analyzing historical data and market conditions.\nThis enables financial institutions to make informed decisions and reduce potential losses.\nFor example, deep learning models can predict credit default risks by evaluating a borrower’s financial history and current market trends, leading to more accurate credit scoring and loan approvals.\n### Deep Learning Applications in the Retail Industry\n- **Customer Insights and Personalization**\nRetailers use deep learning to analyze customer behavior and preferences, allowing for highly personalized marketing.\nBy examining purchase history, browsing patterns, and social media activity, neural networks can predict what products customers are likely to buy and tailor recommendations accordingly which has been observed to have a hugely positive impact on customer satisfaction and sales.\n- **Inventory Management**\nDeep learning algorithms help retailers optimize inventory levels by predicting demand for various products.\nThese models, often based on LSTM networks, consider factors like seasonal trends, market conditions, and historical sales data.\nThis ensures that popular items are always in stock while minimizing overstock and reducing storage costs, improving overall efficiency.\n- **Visual Search**\nE-commerce platforms utilize deep learning for visual search capabilities, enabling customers to search for products using images.\nConvolutional neural networks analyze visual features to identify and recommend similar products.\nThis technology enhances the shopping experience by making it easier for customers to find products they are interested in, even if they do not know the exact name.\n### Deep Learning Applications in the Manufacturing Industry\n- **Predictive Maintenance**\nIn manufacturing, deep learning is used for predictive maintenance, which involves predicting when equipment is likely to fail and proactively performing maintenance.\nBy analyzing sensor data from machinery, neural networks can identify patterns that precede breakdowns.\nThis has been observed to reduce downtime, increase equipment lifespan, and lower the cost of maintenance.\n- **Quality Control**\nDeep learning algorithms improve quality control by analyzing images of products to detect defects.\nConvolutional neural networks can identify flaws that are difficult for human inspectors to see, ensuring that only high-quality products reach the market.\nThis not only enhances product reliability but also reduces waste and rework costs.\n- **Supply Chain Optimization**\nDeep learning helps optimize supply chains by analyzing data from various sources, including weather reports, transportation schedules, and market demand.\nThese models, often based on reinforcement learning, enable manufacturers to make informed decisions about production and distribution, improving efficiency and reducing costs.\nFor example, neural networks can predict the optimal time to reorder raw materials based on historical usage patterns and current market conditions.\n### Deep Learning Applications in the Autonomous Driving Industry\n- **Object Detection and Recognition**\nDeep learning is the most crucial for the development of autonomous vehicles.\nConvolutional neural networks enable these vehicles to detect and recognize objects on the road, such as other vehicles, pedestrians, and traffic signs.\nThis is essential for safe and reliable navigation, as the vehicle must accurately interpret its surroundings in real-time.\n- **Path Planning and Navigation**\nNeural networks help autonomous vehicles plan their routes and navigate complex environments.\nBy analyzing real-time data from sensors and cameras, these systems, often utilizing deep reinforcement learning, can make split-second decisions to avoid obstacles and ensure a smooth journey.\nThis involves dynamically adjusting the vehicle’s path based on traffic conditions, road obstacles, and other factors.\n...\nMany modern vehicles are equipped with driver assistance systems powered by deep learning.\nIf the driver deviates from a lane, the deep learning algorithm detects it and provides a warning.\nUnlike traditional cruise control where the speed is unalterable, the Adaptive Cruise Control, a feature powered by deep learning, can modify the speed according to traffic and road conditions.\nIt automatically adjusts the speed to maintain a safe distance from the vehicle ahead.\nAutomatic emergency braking is another feature made possible through deep learning.\nBy processing data from cameras and sensors, neural networks can detect potential hazards and assist the driver in avoiding accidents, enhancing safety and convenience.\n### Deep Learning Applications in the Entertainment Industry\n- **Content Recommendation**\nStreaming services like Netflix and Spotify use deep learning to recommend content to users based on their viewing or listening history and preferences.\nRecurrent neural networks analyze user behavior to suggest movies, TV shows, music, and other content, providing a personalized entertainment experience.\nThis increases user engagement and satisfaction.\n- **Video and Image Enhancement**\nDeep learning algorithms enhance the quality of video and images through techniques such as super-resolution and denoising.\nFor example, GANs can upscale low-resolution videos to higher resolutions, remove noise from images, and even colorize black-and-white footage.\nThis improves the visual experience for users and extends the usability of older content.\n- **Game Development**\nIn game development, deep learning is used to create more realistic and intelligent non-player characters (NPCs).\nThese characters, powered by reinforcement learning algorithms, can learn from player behavior and adapt their actions accordingly, providing a more engaging and challenging gaming experience.\nAdditionally, neural networks are used to generate realistic graphics and procedural content, enhancing the overall quality of games.\n...\nThe applications of deep learning and neural networks are vast and continue to expand across industries.\nThese technologies are driving innovation, improving efficiency, and enhancing the quality of products and services.",
          "title": "Deep Learning and Neural Networks Applications Across ...",
          "url": "https://payodatechnologyinc.medium.com/deep-learning-and-neural-networks-applications-across-industries-c955ce0a8b88",
          "date": "2024-09-30",
          "last_updated": "2025-09-02"
        },
        {
          "snippet": "",
          "title": "Deep Learning Applications & Solutions Across Industries",
          "url": "https://scopicsoftware.com/blog/deep-learning-applications-solutions-across-industries/",
          "date": "2026-03-30",
          "last_updated": "2026-05-16"
        },
        {
          "snippet": "Now, a specific breakthrough in AI — deep learning — is allowing business to use data to teach computers how to learn.\n...\nDeep learning requires vast amounts of data and a huge amount of processing power.\nBut, since industries across the spectrum are generating tons of “Big Data,” i.e. digital data now being produced at an unprecedented rate and massive volumes, there is a clear opportunity for deep learning-powered applications.\nHere are 13 industries that are drawing on innovations pioneered by deep learning to make major advances.\n#### 1.\nHealthcare/genomics\n...\nThis is where deep learning comes in.\nStartup Deep Genomics, which is backed by Bloomberg Beta and True Ventures among others, has fed deep learning machines tons of existing cellular information in order to teach machines to predict outcomes from alterations to the genome, whether naturally occurring or through medical treatment.\nThe technology could provide the most precise understanding of an individual’s specific disease or abnormality and how that person’s wellbeing can best be advanced.\n...\nIf deep learning techniques could look at the wide variety of molecular compounds that have already proven themselves effective and use this information to develop drugs to attack new or established diseases — or identify alternative uses for drugs that are already FDA-approved, it could help fast-track treatments.\n...\nCompanies like Israel-based and Blumberg Capital-backed Deep Instinct aim to use deep learning in order to recognize new threats that have never been detected before and thus keep organizations one step ahead of cyber criminals.\n...\nAmong the oldest and most unpredictable industries, agriculture is becoming increasingly data- and tech-driven.\nMore predictable crop outputs — based on weather forecasting and data-based estimates — could potentially even take some of the uncertainty out of commodities markets.\nNew Mexico-based Descartes Labs aims to make “a living map of all the world’s agriculture” using satellite imagery fed into deep learning machines and lots of computing power, rather than a more traditional focus on surveys and site visits.\nThen, based on patterns over time, the technology is designed to predict crop yields and production.\n...\nRetail/e-commerce\nPinterest — where people often share aspirational images of products — is arguably the leading site for social commerce.\nBut often, these images show a collection of items and don’t necessarily identify where something similar might be purchased.\nNow, using deep learning, the company is turning that repository of images into potential sales by allowing users to zoom in on specific items within an image and be served visually similar pins, some of which could be purchased from retailers’ pins.\nPinterest is using the same deep learning-based discovery technology to surface more relevant videos.\nOther internet publishers might eventually be able to turn every image or video on their site into a kind of high-gloss ad referral.\nThe French company Deepomatic has already used deep learning to develop this kind of tech aimed at web publishers, allowing them to earn revenue off of the visuals within their content.\n...\nThis is why, using deep learning, Drive.ai plans to help the car build up experience through simulations of many kinds of driving conditions.\n...\nNvidia says it has used deep learning to train a car to drive on marked and unmarked roads and along the highway in various weather conditions, without the need to program every possible “if, then, else” statement.\n#### 7.\n...\nSimilarly IBM is using deep learning to help solar and wind companies better predict weather and improve alternative energy production.\n...\nThe insurance industry is beginning to see deep learning as especially useful in managing claims.\nA machine that can recognize patterns in fraud could help these companies ferret out false claims and determine payouts for legitimate claims.\n...\nThe company now sees deep learning as potentially playing a role in claims processing and customer service.\nPwC similarly sees deep learning playing a role in standardized underwriting of common policies, such as auto, home, and commercial insurance, and in using deep learning image analysis to estimate repair costs after a claim has been filed.\nThe startup Tractable is specifically focused on building deep learning systems for auto insurance.\nThe company aims to use images of car damages to teach machines how to estimate future repair costs, potentially bypassing the need to visit the auto body shop and rely on the garage’s assessment.\n...\nNow, a few different companies are using deep learning to help clients — especially enterprise-focused companies — reach out to the right prospects.\n...\nNow it looks like those robots could get even better at their job with the addition of deep learning tech.",
          "title": "Get Smart: 13 Industries Using Deep Learning To Make Huge Leaps Forward",
          "url": "https://www.cbinsights.com/research/industries-disrupted-deep-learning/",
          "date": null,
          "last_updated": "2024-06-22"
        },
        {
          "snippet": "",
          "title": "Top 50 Deep Learning Use Case & Case Studies - AIMultiple",
          "url": "https://aimultiple.com/deep-learning-applications",
          "date": "2026-03-10",
          "last_updated": "2026-05-25"
        },
        {
          "snippet": "Deep learning, a subset of machine learning, has emerged as a powerful technology with transformative applications across various industries.\nIts ability to mimic the human brain's neural networks enables machines to learn from vast datasets and make intelligent decisions.\nIn this article, we explore how deep learning is applied in diverse sectors, revolutionizing processes and driving innovation.\n**Healthcare:** Deep learning is making significant strides in healthcare, aiding in medical image analysis, disease diagnosis, and personalized treatment plans.\nRadiology, pathology, and drug discovery are areas where deep learning is enhancing accuracy and efficiency.\n**Finance:** In the financial sector, deep learning is employed for fraud detection, risk assessment, and algorithmic trading.\nIts ability to analyze patterns and detect anomalies contributes to strengthening security measures and optimizing financial operations.\n**Manufacturing:** Deep learning is optimizing manufacturing processes through predictive maintenance, quality control, and supply chain management.\nPredictive analytics powered by deep learning helps prevent equipment failures and minimize downtime.\n**Retail:** The retail industry leverages deep learning for customer personalization, demand forecasting, and inventory management.\nRecommendation systems based on deep learning algorithms enhance the customer shopping experience.\n**Automotive:** Autonomous vehicles rely on deep learning for image recognition, object detection, and decision-making processes.\nDeep learning algorithms enable vehicles to interpret and respond to their surroundings, ensuring safer and more efficient transportation.\n**Agriculture:** Precision agriculture benefits from deep learning applications in crop monitoring, pest detection, and yield prediction.\nDeep learning contributes to optimizing farming practices and maximizing agricultural output.\n**Education:** Deep learning is transforming education through personalized learning experiences, adaptive assessment systems, and intelligent tutoring.\nTailoring education to individual needs enhances student engagement and comprehension.\n**Entertainment:** Content recommendation platforms in the entertainment industry utilize deep learning to understand user preferences and provide personalized content suggestions.\nDeep learning algorithms enhance the creation and curation of entertainment content.\n**Telecommunications:** Deep learning plays a role in network optimization, predictive maintenance, and customer service within the telecommunications sector.\nThese applications contribute to improving network performance and customer satisfaction.\n**Energy:** Deep learning aids the energy sector in predictive maintenance of equipment, energy grid optimization, and fault detection.\nThese applications enhance the efficiency and reliability of energy production and distribution.\nIn conclusion, the widespread applications of deep learning underscore its transformative impact on various industries.",
          "title": "How Deep Learning is Applied in Various Industries",
          "url": "https://www.analyticsinsight.net/deep-learning/how-deep-learning-is-applied-in-various-industries-2",
          "date": "2023-11-12",
          "last_updated": "2025-07-10"
        }
      ],
      "server_time": null
    }
    ```
  </Accordion>
</AccordionGroup>

### Advanced Async Patterns

#### Rate-Limited Concurrent Processing

For large-scale applications, implement controlled concurrency with rate limiting:

<CodeGroup>
  ```python Python theme={null}
  import asyncio
  from perplexity import AsyncPerplexity

  class SearchManager:
      def __init__(self, max_concurrent=5, delay_between_batches=1.0):
          self.max_concurrent = max_concurrent
          self.delay_between_batches = delay_between_batches
          self.semaphore = asyncio.Semaphore(max_concurrent)
      
      async def search_single(self, client, query):
          async with self.semaphore:
              return await client.search.create(query=query, max_results=5)
      
      async def search_many(self, queries):
          async with AsyncPerplexity() as client:
              tasks = [
                  self.search_single(client, query) 
                  for query in queries
              ]
              
              results = await asyncio.gather(*tasks, return_exceptions=True)
              
              # Filter out exceptions and return successful results
              successful_results = [
                  result for result in results 
                  if not isinstance(result, Exception)
              ]
              
              return successful_results

  # Usage
  async def main():
      manager = SearchManager(max_concurrent=3)
      queries = [
          "AI research 2024",
          "quantum computing advances",
          "renewable energy innovations",
          "biotechnology breakthroughs",
          "space exploration updates"
      ]
      
      results = await manager.search_many(queries)
      print(f"Successfully processed {len(results)} out of {len(queries)} searches")

  asyncio.run(main())
  ```

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

  class SearchManager {
      private maxConcurrent: number;
      private delayBetweenBatches: number;
      
      constructor(maxConcurrent: number = 5, delayBetweenBatches: number = 1000) {
          this.maxConcurrent = maxConcurrent;
          this.delayBetweenBatches = delayBetweenBatches;
      }
      
      async searchMany(queries: string[]) {
          const client = new Perplexity();
          const results = [];
          
          // Process in batches to respect rate limits
          for (let i = 0; i < queries.length; i += this.maxConcurrent) {
              const batch = queries.slice(i, i + this.maxConcurrent);
              
              const batchPromises = batch.map(query =>
                  client.search.create({ query, max_results: 5 })
                      .catch(error => ({ error, query }))
              );
              
              const batchResults = await Promise.all(batchPromises);
              
              // Filter out errors and collect successful results
              const successfulResults = batchResults.filter(
                  result => !('error' in result)
              );
              
              results.push(...successfulResults);
              
              // Add delay between batches
              if (i + this.maxConcurrent < queries.length) {
                  await new Promise(resolve => 
                      setTimeout(resolve, this.delayBetweenBatches)
                  );
              }
          }
          
          return results;
      }
  }

  // Usage
  async function main() {
      const manager = new SearchManager(3, 1000);
      const queries = [
          "AI research 2024",
          "quantum computing advances", 
          "renewable energy innovations",
          "biotechnology breakthroughs",
          "space exploration updates"
      ];
      
      const results = await manager.searchMany(queries);
      console.log(`Successfully processed ${results.length} out of ${queries.length} searches`);
  }

  main();
  ```
</CodeGroup>

#### Error Handling in Async Operations

Implement robust error handling for async search operations:

<CodeGroup>
  ```python Python theme={null}
  import asyncio
  import logging
  from perplexity import AsyncPerplexity, APIStatusError, RateLimitError

  logging.basicConfig(level=logging.INFO)
  logger = logging.getLogger(__name__)

  async def resilient_search(client, query, max_retries=3):
      for attempt in range(max_retries):
          try:
              result = await client.search.create(query=query, max_results=5)
              logger.info(f"Search successful for: {query}")
              return result
              
          except RateLimitError as e:
              if attempt < max_retries - 1:
                  delay = 2 ** attempt
                  logger.warning(f"Rate limited for '{query}', retrying in {delay}s")
                  await asyncio.sleep(delay)
              else:
                  logger.error(f"Max retries exceeded for: {query}")
                  return None
                  
          except APIStatusError as e:
              logger.error(f"API error for '{query}': {e}")
              return None
              
          except Exception as e:
              logger.error(f"Unexpected error for '{query}': {e}")
              return None

  async def main():
      async with AsyncPerplexity() as client:
          queries = ["AI developments", "invalid query", "tech trends"]
          
          tasks = [resilient_search(client, query) for query in queries]
          results = await asyncio.gather(*tasks)
          
          successful_results = [r for r in results if r is not None]
          print(f"Successful searches: {len(successful_results)}/{len(queries)}")

  asyncio.run(main())
  ```

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

  async function resilientSearch(
      client: Perplexity, 
      query: string, 
      maxRetries: number = 3
  ) {
      for (let attempt = 0; attempt < maxRetries; attempt++) {
          try {
              const result = await client.search.create({ query, max_results: 5 });
              console.log(`Search successful for: ${query}`);
              return result;
              
          } catch (error: any) {
              if (error.constructor.name === 'RateLimitError') {
                  if (attempt < maxRetries - 1) {
                      const delay = 2 ** attempt * 1000;
                      console.warn(`Rate limited for '${query}', retrying in ${delay}ms`);
                      await new Promise(resolve => setTimeout(resolve, delay));
                  } else {
                      console.error(`Max retries exceeded for: ${query}`);
                      return null;
                  }
              } else {
                  console.error(`Error for '${query}':`, error.message);
                  return null;
              }
          }
      }
      
      return null;
  }

  async function main() {
      const client = new Perplexity();
      const queries = ["AI developments", "invalid query", "tech trends"];
      
      const tasks = queries.map(query => resilientSearch(client, query));
      const results = await Promise.all(tasks);
      
      const successfulResults = results.filter(r => r !== null);
      console.log(`Successful searches: ${successfulResults.length}/${queries.length}`);
  }

  main();
  ```
</CodeGroup>

## Performance Optimization Tips

<Steps>
  <Step title="Optimize result count">
    Request only the number of results you actually need. More results = longer response times.

    ```python theme={null}
    # Good: Request only what you need
    search = client.search.create(query="AWS re:Invent generative AI announcements", max_results=5)

    # Avoid: Over-requesting results
    search = client.search.create(query="AWS re:Invent generative AI announcements", max_results=50)
    ```

    <Accordion title="Response">
      ```json theme={null}
      {
        "id": "5ef341de-a9cc-48fe-a4e7-37c8b2d03c4f",
        "results": [
          {
            "snippet": "## Amazon Redshift introduces AWS Graviton-based RG instances with an integrated data lake query engine\n...\nAmazon Redshift RG instances, powered by AWS Graviton, run data warehouse and data lake workloads up to 2.4x as fast as RA3 instances at 30% lower price per vCPU.\nIts integrated data lake query engine supports open table formats such as Apache Iceberg.\n## AWS Weekly Roundup: Claude Mythos Preview in Amazon Bedrock, AWS Agent Registry, and more (April 13, 2026)\n...\n## AWS Weekly Roundup: AWS DevOps Agent & Security Agent GA, Product Lifecycle updates, and more (April 6, 2026)\n...\n## Happy New Year!\nAWS Weekly Roundup: 10,000 AIdeas Competition, Amazon EC2, Amazon ECS Managed Instances and more (January 5, 2026)\n...\n## Amazon Bedrock AgentCore adds quality evaluations and policy controls for deploying trusted AI agents\nby on 02 DEC 2025 in\nDeploy AI agents with confidence using new quality evaluations and policy controls—enabling precise boundaries on agent actions, continuous quality monitoring, and experience-based learning while maintaining natural conversation flows.\n## Amazon S3 Vectors now generally available with increased scale and performance\nby on 02 DEC 2025 in\nScale vector storage and querying to new heights with S3 Vectors’ general availability—now supporting up to 1 billion vectors per index, 100ms query latencies, and expanded regional availability, while reducing costs up to 90% compared to specialized databases.\n## Introducing Amazon Nova 2 Lite, a fast, cost-effective reasoning model\nby on 02 DEC 2025 in\nNew fast, cost-effective model supports extended thinking with adjustable reasoning depth, letting you control the balance between speed, intelligence, and cost while building AI applications for everyday workloads.\n## Introducing Amazon Nova Forge: Build your own frontier models using Nova\nby on 02 DEC 2025 in\nNew program gives organizations unprecedented access to Nova model training, enabling them to build custom frontier models that deeply embed domain expertise without the traditional barriers of cost, compute, and time.",
            "title": "Generative AI | AWS News Blog",
            "url": "https://aws.amazon.com/blogs/aws/category/artificial-intelligence/generative-ai/",
            "date": "2026-05-12",
            "last_updated": "2026-05-13"
          },
          {
            "snippet": "Today, Amazon SageMaker AI introduces OpenAI-compatible API support for real-time inference endpoints.\nIf you use the OpenAI SDK, LangChain, or Strands Agents, you can now invoke models on SageMaker AI by changing only your endpoint URL.\n...\nToday, we’re announcing three new capabilities available in SageMaker Python SDK v3.8.0.\n...\nToday, we’re excited to announce the general availability of Claude Platform on AWS.\nClaude Platform on AWS is a new service that gives customers direct access to Anthropic’s native Claude Platform experience through their AWS account, with no separate credentials, contracts, or billing relationships required.\nAWS is the first cloud provider to offer access to the native Claude Platform experience.\n...\nToday, we’re announcing a preview of Amazon Bedrock AgentCore Payments, a new set of features in Amazon Bedrock AgentCore that enables AI agents to instantly access and pay for what they use.\n...\nToday, we’re excited to announce that Amazon SageMaker AI MLflow Apps now support MLflow version 3.10, bringing enhanced capabilities for generative AI development and streamlined experiment tracking to your generative AI workflows.",
            "title": "Announcements | Artificial Intelligence - AWS",
            "url": "https://aws.amazon.com/blogs/machine-learning/category/post-types/announcements/",
            "date": "2026-05-07",
            "last_updated": "2026-05-21"
          },
          {
            "snippet": "",
            "title": "AWS re:Invent 2024 - Generative AI in action - YouTube",
            "url": "https://www.youtube.com/watch?v=aFQFiVOh3P0",
            "date": "2024-12-04",
            "last_updated": "2026-03-05"
          },
          {
            "snippet": "And although generative AI has appeared in previous events, this year we’re taking it to the next level.\nIn addition to several exciting announcements during keynotes, most of the sessions in our track will feature generative AI in one form or another, so we can truly call our track “Generative AI and ML.”",
            "title": "AWS re:Invent | Artificial Intelligence",
            "url": "https://aws.amazon.com/blogs/machine-learning/category/events/reinvent/",
            "date": "2025-11-17",
            "last_updated": "2026-05-03"
          },
          {
            "snippet": "We’ve rounded up the most significant announcements from AWS re:Invent 2025, held Nov. 30-Dec. 4 in Las Vegas.\nThis guide highlights the innovations that will help you build, scale, and transform your business in the cloud.\n...\n(This post was updated 12:57 p.m. PST, Dec. 5, 2025.)\n...\n**AWS Clean Rooms launches privacy-enhancing dataset generation for ML model training**\nTrain ML models on sensitive collaborative data by generating synthetic datasets that preserve statistical patterns while protecting individual privacy through configurable noise levels and protection against re-identification.\n...\n**Introducing Amazon Nova 2 Sonic: Our new speech-to-speech model for conversational AI]\n** Build more natural voice interactions with enhanced speech-to-speech AI—now featuring multilingual conversations, dynamic speech control, crossmodal inputs, and improved telephony integration while maintaining conversation context across tasks.\n**Introducing Amazon Nova 2 Lite, a fast, cost-effective reasoning model\n** Nova 2 Lite offers fast, cost-effective AI for everyday tasks.\nIt features extended thinking capabilities, built-in tools, and a million-token context window.\n**Introducing Amazon Nova Forge: Build your own frontier models using Nova\n** New program gives organizations unprecedented access to Nova model training, so they can build custom frontier models that deeply embed domain expertise without the traditional barriers of cost, compute, and time.\n**Introducing Amazon Nova 2 Omni in Preview**\nOur all-in-one model for multimodal reasoning and image generation supports text, images, video, and speech inputs while generating both text and image outputs.\n**Build reliable AI agents for UI workflow automation with Amazon Nova Act, now generally available\n** New AWS service helps developers build AI agents that automate browser-based tasks like form filling, search & extract, shopping & booking, and QA testing—with over 90% reliability for enterprise deployments.\n**Amazon Bedrock AgentCore adds quality evaluations and policy controls for deploying trusted AI agents**\nNew capabilities help companies deploy agents with enhanced policy controls, quality monitoring, improved memory, and natural conversation abilities—making it easier to confidently scale AI solutions across your organization.\n**Amazon S3 Vectors now generally available with increased scale and performance**\nScale vector storage and querying to new heights with S3 Vectors’ general availability—now supporting up to 2 billion vectors per index, 100ms query latencies, and expanded regional availability, while reducing costs up to 90% compared to specialized databases.\n**Amazon Bedrock adds 18 fully managed open weight models, including the new Mistral Large 3 and Ministral 3 models**\nAccess fully managed foundation models from leading providers like Google, Kimi AI, MiniMax AI, Mistral AI, NVIDIA, OpenAI, and Qwen, including the new Mistral Large 3 and Ministral 3 3B, 8B, and 14B models through Amazon Bedrock.\n**Accelerate AI development using Amazon SageMaker AI with serverless MLflow**\nSimplify AI experimentation with zero-infrastructure MLflow that launches in minutes, scales automatically, and seamlessly integrates with SageMaker’s model customization and pipeline capabilities.\n**Amazon Bedrock adds reinforcement ﬁne-tuning simplifying how developers build smarter, more accurate AI models**\nNew model customization capability uses feedback-driven training to deliver 66% accuracy gains over base models without requiring large labeled datasets or deep ML expertise.\n**Introducing checkpointless and elastic training on Amazon SageMaker HyperPod**\nAccelerate AI model development with new training features that enable instant recovery from failures and automatic scaling based on resource availability.\n...\n**AWS introduces Graviton5—the company’s most powerful and efficient CPU**\n...\n**Introducing AWS AI Factories**\nDeploy fully managed AWS AI infrastructure in your data centers with pre-integrated foundation models, specialized hardware, and AWS services—helping enterprises and governments accelerate AI initiatives while meeting data residency requirements.\n...\n**Amazon FSx for NetApp ONTAP now integrates with Amazon S3 for seamless data access\n** Amazon FSx for NetApp ONTAP now lets you access file system data through Amazon S3, enabling seamless integration with AWS analytics, ML, and generative AI services without moving or copying data.",
            "title": "Top announcements of AWS re:Invent 2025 | AWS News Blog",
            "url": "https://aws.amazon.com/blogs/aws/top-announcements-of-aws-reinvent-2025/",
            "date": "2025-11-30",
            "last_updated": "2026-05-18"
          },
          {
            "snippet": "",
            "title": "AWS re:Invent | Watch on demand",
            "url": "https://aws.amazon.com/events/reinvent/on-demand/",
            "date": "2026-05-13",
            "last_updated": "2026-05-21"
          },
          {
            "snippet": "",
            "title": "Your guide to generative AI and ML at AWS re:Invent 2024",
            "url": "https://aws.amazon.com/blogs/machine-learning/your-guide-to-generative-ai-and-ml-at-aws-reinvent-2024/",
            "date": "2024-11-19",
            "last_updated": "2026-05-17"
          },
          {
            "snippet": "",
            "title": "AWS re:Invent 2024 Highlights: Top takeaways from Swami ...",
            "url": "https://aws.amazon.com/blogs/machine-learning/aws-reinvent-2024-highlights-top-takeaways-from-swami-sivasubramanian-to-help-customers-manage-generative-ai-at-scale/",
            "date": "2024-12-16",
            "last_updated": "2026-04-10"
          },
          {
            "snippet": "News from AWS re:Invent, including all things generative AI, new service announcements, tech demos, and more.\nGenerative artificial intelligence (Gen AI) was again a major focus, with Amazon Web Services (AWS) CEO Matt Garman, AWS Vice President of Data and AI Swami Sivasubramanian, and special guest Amazon CEO Andy Jassy announcing a range of innovations, as well as sharing behind-the-scenes-insights.Here are some of the key announcements from the event:\n## 1.\nAmazon Nova foundation models\nNew Amazon Nova models, available in Amazon Bedrock, can process text, image, and video as prompts.\nCustomers can use Amazon Nova-powered Gen AI applications to understand videos, charts, and documents, or generate multimedia content.\nUsing Amazon Bedrock, customers can easily experiment with and evaluate Amazon Nova models, as well as other foundation models (FMs), to determine the best model for an application.\n## 2.\nNow available: AWS Trainium2 instances\nAWS Trainium2-powered Amazon Elastic Compute Cloud (Amazon EC2)instances, powered by AWS Trainium2 chips, are purpose-built for high-performance deep learning (DL) training of Gen AI models, including large language models (LLMs) and latent diffusion models.\nA single Trn2 instance combines 16 Trainium2 chips interconnected with ultrafast NeuronLink high-bandwidth.Trn2 UltraServers—a completely new EC2 offering—use NeuronLink interconnect to connect four Trn2 servers together into one giant server.\nWith new Trn2 UltraServers, customers can scale up their generative AI workloads across 64 Trainium2 chips.\n...\n## 3.\nTrainium3 chips: designed for high-performance needs of Gen AI workloads\nTrainium3, AWS’s next-generation AI chip, will allow customers to build bigger models faster, and deliver superior real-time performance.\nTrainium3-powered UltraServers are expected to be four times more performant than Trn2 UltraServers.\nThe first Trainium3-based instances will be available in late 2025.\n## 4.\nNew capabilities for Amazon Bedrock and the biggest expansion of models to date\nNew innovations for Amazon Bedrock will give customers greater flexibility and control to build and deploy production-ready Gen AI faster.\nThese include:- The broadest selection of fully managed models from leading AI companies\n- Access to more than 100 popular, emerging, and specialized models with Amazon Bedrock Marketplace\n- New Amazon Bedrock capabilities to help customers more effectively manage prompts at scale\n- Two new capabilities for Amazon Bedrock Knowledge Bases\n- New Amazon Bedrock Data Automation\n## 5.\nAmazon Bedrock strengthened with industry-first AI safeguard, new agent capability, and model customization\nNew capabilities for Amazon Bedrock will help customers prevent factual errors due to hallucinations, orchestrate multiple AI-powered agents for complex tasks, and create smaller, task-specific models that can perform similarly to a large model at a fraction of the cost and latency:- Automated reasoning checks.\nThe first and only Gen AI safeguard that helps prevent factual errors due to hallucinations using logically accurate and verifiable reasoning.\n- Expansion of Amazon Bedrock Agents.\nSupports multi-agent collaboration, empowering customers to easily build and coordinate specialized agents to execute complex workflows.\n- Amazon Bedrock Model Distillation.\nModel distillation is a technique that transfers the knowledge from a large model to a small model, while retaining the latter’s performance characteristics.\nThis usually requires specialized machine learning (ML) expertise, but with Amazon Bedrock Model Distillation, any customer can now distill their own model with no ML expertise required.\n...\n## 6.\nNew Amazon SageMaker AI capabilities\nNew innovations for Amazon SageMaker AI can help customers get started faster with popular publicly available models, maximize training efficiency, lower costs, and use their preferred tools to accelerate Gen AI model development.\nThese include three innovations for Amazon SageMaker HyperPod, which helps customers efficiently scale Gen AI model development across thousands of AI accelerators, reducing time to train foundation models by up to 40%.\n## 7.\nNext generation of Amazon SageMaker to deliver unified platform for data, analytics, and AI\nThe next generation of Amazon Sagemaker now showcases four new features and capabilities: SageMaker Unified Studio, SageMaker Catalog, SageMaker Lakehouse, and Zero-ETL integrations with SaaS applications.\nThis brings together the capabilities customers need for fast Structured Query Language (SQL) analytics, petabyte-scale big data processing, data exploration and integration, machine learning (ML) model development and training, and Gen AI in one integrated platform.\n## 8.\nNew capabilities and continued momentum for Amazon Q Business\nAmazon Q Business is the most capable Gen AI-powered assistant for finding information, gaining insight, and taking action at work.\nThe new capabilities offer customers better insights across Amazon Q Business and Amazon Q in QuickSight, enhance cross-app Gen AI experiences, provide more than 50 actions for popular business applications, and make it easy to automate complex workflows—enabling employees to complete tedious, time-consuming work faster.\n## 9.\nNew enhancements to Amazon Q Developer, the most capable Gen AI assistant for software development\nThese enhancements to Amazon Q Developer include agents that accelerate unit testing, documentation, and code reviews, and an operational capability that helps operators and developers of all experience levels investigate and resolve operational issues across their AWS environment in a fraction of the time.\nAmazon Q Developer can speed up software development tasks by up to 80%, already providing the highest reported code acceptance rate of any coding assistant that suggests multi-line code; code security scanning that outperforms leading publicly benchmarkable tools; and high-performing AI agents that autonomously reason and iterate to achieve complex goals.\n...\n## 10.\nNew database capabilities including Amazon Aurora DSQL, the fastest distributed SQL database\nNew capabilities for Amazon Aurora and Amazon DynamoDB will support customers’ most demanding workloads that need to operate across multiple Regions with strong consistency, low latency, and the highest availability:- Amazon Aurora DSQL.\nhis new serverless, distributed SQL database enables customers to build applications with 99.999% multi-Region availability, strong consistency, PostgreSQL compatibility, four times faster reads and writes compared to other popular distributed SQL databases, virtually unlimited scalability, and zero infrastructure management.\n- Enhancements to Amazon DynamoDB global tables.\nAWS is now using the same underlying technology leveraged by Aurora DSQL to enhance DynamoDB global tables, adding the option of strong consistency to the highest availability, virtually unlimited scalability, and zero infrastructure management already available in DynamoDB global tables, ensuring customers' multi-Region applications are always reading the latest data without having to change any application code.\n## 11.\nNew data center components to support AI, improve energy efficiency, and boost innovation\nAWS expects to begin construction on new data centers with the full set of new components—which combine advances in power, cooling, and hardware—in early 2025 in the U.S. Watch this video and learn more about AWS's new data center components.",
            "title": "11 key announcements from AWS re:Invent 2024 - About Amazon",
            "url": "https://www.aboutamazon.com/news/aws/amazon-nova-ai-canvas-reel-aws-reinvent",
            "date": "2024-12-06",
            "last_updated": "2026-05-21"
          },
          {
            "snippet": "This post is your retroactive field guide to connecting the dots that define the future of the cloud.\nBelow, we'll dive into the biggest announcements from three crucial domains:\n- Applied intelligence, and the promise of agentic AI\n- Trust, and the necessary governance and security to scale safely\n- Enterprise velocity, and keeping pace with the agentic era\n...\nIf one thing was clear in re:Invent’s opening keynote, it’s that builders have more capability than ever to train models, build agents, and provide value by using technologies like AWS Trainium 3 and Amazon Bedrock AgentCore.\n...\nLast year at DASH, we launched LLM Observability, a way to continuously observe, secure, and act on findings from the LLMs you use.\nJust in time for re:Invent, we also launched two features in LLM Observability to help builders see the full picture of their stack: support for Strands Agents and for Amazon Bedrock Agents, both generally available.\nIn order to ensure both safety and security, we released a set of detection rules to help drive down risk in the configuration for Bedrock instances.\nThe AWS commitment to empowering their customers and partners to build safely on their AI platform was also echoed in the release of Bedrock AgentCore Policies, enabling teams to have fine-grained control of identity and access throughout their agentic workflows.\n...\nWhen it comes to AI, builders now have more choice than ever.\nAWS dropped 18 fully managed open weight models for Bedrock—the largest simultaneous model expansion to date—spanning Gemma, Mistral, Qwen, NVIDIA Nemotron, and more.\nPair that with the new serverless model customization capability in SageMaker AI, which lets teams fine-tune with reinforcement learning and direct preference optimization without managing infrastructure, and suddenly the number of variables explodes.\nThis raises a new challenge: How do I tune all of these models for the best results?\nLLM Observability now includes LLM Experiments and Playground, where you can experiment and optimize your LLM applications before pushing to production.\nIn addition to model tuning, we released Prompt Tracking to help monitor performance, latency, and drift across prompt versions.\n...\nBut before that, two major announcements came in the days leading up to re:Invent—or as we call it, pre:Invent:\n- AWS IAM Policy Autopilot: An open source Model Context Protocol (MCP) server and command-line tool that helps your AI coding assistants quickly create baseline IAM policies that you can refine as your application evolves.\nPolicy Autopilot supports all the major languages and IDEs, including Kiro.\n- AWS Security Agent: Launched in preview, this frontier agent is a step toward integrating more agentic application security into build workflows.\nApplied AI and triaging as many findings close to the IDE will certainly save AppSec teams a ton of time.\n...\nWe launched two capabilities that help you understand your larger cloud footprint and prioritize risks using observability context.\n...\nA wave of re:Invent announcements centered on Kiro, AWS's agentic IDE.\nKiro focuses on moving from prototype to production, with AI agents that understand context across large codebases.\nWe launched three integrations to extend Kiro's reach into production, bringing errors, deployments, traces, and incident context directly into the code editor:\n- Datadog MCP Server support in Kiro surfaces errors, deployments, and traces directly in your editor, shortening the feedback loop between code and production.\n...\nAt re:Invent, we released new AI capabilities for Code Security to help developers catch vulnerabilities and fix them without slowing down.\nAI-driven detection and remediation detects code vulnerabilities, intelligently filters out false positives, and helps developers remediate at scale, while Secret Scanning detects and blocks exposed credentials leaked in code.\nWith your code secured, the next question is: How fast can you get it to production?\nAWS announced several capabilities that remove friction across the deployment life cycle:\n- Amazon ECS Express Mode lets you deploy containerized applications with a single command—load balancers, autoscaling, networking, and domains are provisioned automatically.\n- AWS Lambda durable functions bring automatic checkpointing and retries to long-running workflows, with execution that can pause for up to a year and resume exactly where it left off.\n- AWS Lambda Managed Instances removes the tradeoff between serverless simplicity and Amazon EC2 flexibility, allowing you to run Lambda functions on EC2 compute while AWS handles instance life cycle, patching, and scaling.",
            "title": "Highlights from AWS re:Invent 2025: Making sense of applied AI ...",
            "url": "https://www.datadoghq.com/blog/aws-reinvent-2025-recap/",
            "date": "2025-12-11",
            "last_updated": "2026-05-17"
          }
        ],
        "server_time": null
      }
      ```
    </Accordion>
  </Step>

  <Step title="Cache frequently used searches">
    Implement caching for queries that don't need real-time results.

    <CodeGroup>
      ```python Python theme={null}
      import time
      from typing import Dict, Tuple, Optional

      class SearchCache:
          def __init__(self, ttl_seconds=3600):  # 1 hour default
              self.cache: Dict[str, Tuple[any, float]] = {}
              self.ttl = ttl_seconds
          
          def get(self, query: str) -> Optional[any]:
              if query in self.cache:
                  result, timestamp = self.cache[query]
                  if time.time() - timestamp < self.ttl:
                      return result
                  else:
                      del self.cache[query]
              return None
          
          def set(self, query: str, result: any):
              self.cache[query] = (result, time.time())

      # Usage
      cache = SearchCache(ttl_seconds=1800)  # 30 minutes

      def cached_search(client, query):
          cached_result = cache.get(query)
          if cached_result:
              return cached_result
          
          result = client.search.create(query=query)
          cache.set(query, result)
          return result
      ```

      ```typescript Typescript theme={null}
      class SearchCache {
          private cache: Map<string, { result: any; timestamp: number }> = new Map();
          private ttl: number;
          
          constructor(ttlSeconds: number = 3600) {  // 1 hour default
              this.ttl = ttlSeconds * 1000;  // Convert to milliseconds
          }
          
          get(query: string): any | null {
              const cached = this.cache.get(query);
              if (cached) {
                  if (Date.now() - cached.timestamp < this.ttl) {
                      return cached.result;
                  } else {
                      this.cache.delete(query);
                  }
              }
              return null;
          }
          
          set(query: string, result: any): void {
              this.cache.set(query, { result, timestamp: Date.now() });
          }
      }

      // Usage
      const cache = new SearchCache(1800);  // 30 minutes

      async function cachedSearch(client: Perplexity, query: string) {
          const cachedResult = cache.get(query);
          if (cachedResult) {
              return cachedResult;
          }
          
          const result = await client.search.create({ query });
          cache.set(query, result);
          return result;
      }
      ```
    </CodeGroup>
  </Step>
</Steps>

## Related Resources

<CardGroup>
  <Card title="Quickstart" icon="rocket" href="/docs/search/quickstart">
    Get started with basic search functionality
  </Card>

  <Card title="Perplexity SDK" icon="code-circle" href="/docs/sdk/overview">
    Explore the full SDK capabilities for enhanced performance
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/search-post">
    Complete Search API documentation
  </Card>
</CardGroup>


# Search Date and Time Filters
Source: https://docs.perplexity.ai/docs/search/filters/date-time-filters



<Note>
  The `search_after_date_filter` and `search_before_date_filter` parameters allow you to restrict search results to a specific publication date range. Only results with publication dates falling between these dates will be returned.

  The `last_updated_after_filter` and `last_updated_before_filter` parameters allow you to filter by when content was last modified or updated, rather than when it was originally published.

  The `search_recency_filter` parameter provides a convenient way to filter results by predefined time periods (e.g., "hour", "day", "week", "month", "year") relative to the current date.
</Note>

<Info>
  Specific date filters must be provided in the "%m/%d/%Y" format (e.g., "3/1/2025"). Recency filters use predefined values like "hour", "day", "week", "month", or "year". All filters are optional—you may supply either specific dates or recency filters as needed.
</Info>

## Overview

Date and time filters for the Search API allow you to control which search results are returned by limiting them to specific time periods. There are three types of date and time filters available:

### Publication Date Filters

The `search_after_date_filter` and `search_before_date_filter` parameters filter results based on when content was **originally created or published**. This is useful when you need to:

* Find content published within a specific timeframe
* Exclude outdated or overly recent publications
* Focus on content from a particular publication period

### Last Updated Date Filters

The `last_updated_after_filter` and `last_updated_before_filter` parameters filter results based on when content was **last modified or updated**. This is useful when you need to:

* Find recently updated or maintained content
* Exclude stale content that hasn't been updated recently
* Focus on content that has been refreshed within a specific period

### Search Recency Filter

The `search_recency_filter` parameter provides a simple way to filter results by predefined time periods relative to the current date. This is useful when you need to:

* Find content from the past hour, day, week, month, or year
* Get recent results without specifying exact dates
* Quickly filter for timely information

**Available values:**

* `"hour"` - Content from the past hour. Use for real-time data such as breaking news or live events.
* `"day"` - Content from the past 24 hours
* `"week"` - Content from the past 7 days
* `"month"` - Content from the past 30 days
* `"year"` - Content from the past 365 days

**Important:** Publication filters use the original creation/publication date, last updated filters use the modification date, while recency filters use a relative time period from the current date.

To constrain search results by publication date:

```bash theme={null}
"search_after_date_filter": "3/1/2025",
"search_before_date_filter": "3/5/2025"
```

To constrain search results by last updated date:

```bash theme={null}
"last_updated_after_filter": "07/01/2025",
"last_updated_before_filter": "12/30/2025"
```

To constrain search results by recency:

```bash theme={null}
"search_recency_filter": "week"
```

These filters will be applied in addition to any other search parameters.

## Examples

**1. Limiting Results by Publication Date Range**

This example limits search results to content published between March 1, 2025, and March 5, 2025.

**Request Example**

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.search.create(
      query="transformer architecture attention mechanism",
      max_results=10,
      search_after_date_filter="3/1/2025",
      search_before_date_filter="3/5/2025"
  )

  print(response)
  ```

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

  const client = new Perplexity();

  const response = await client.search.create({
    query: "transformer architecture attention mechanism",
    max_results: 10,
    search_after_date_filter: "3/1/2025",
    search_before_date_filter: "3/5/2025"
  });

  console.log(response);
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "transformer architecture attention mechanism",
      "max_results": 10,
      "search_after_date_filter": "3/1/2025",
      "search_before_date_filter": "3/5/2025"
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "5cdd76b9-da5a-4f9f-8c75-61c90a2399a2",
    "results": [
      {
        "snippet": "",
        "title": "What is an attention mechanism?",
        "url": "https://www.ibm.com/think/topics/attention-mechanism",
        "date": "2024-12-05",
        "last_updated": "2026-03-31"
      },
      {
        "snippet": "",
        "title": "Introduction to Transformers and Attention Mechanisms",
        "url": "https://medium.com/@kalra.rakshit/introduction-to-transformers-and-attention-mechanisms-c29d252ea2c5",
        "date": "2024-02-07",
        "last_updated": "2025-10-29"
      },
      {
        "snippet": "",
        "title": "Transformer (deep learning) - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Transformer_(deep_learning)",
        "date": "2019-08-25",
        "last_updated": "2026-05-15"
      },
      {
        "snippet": "",
        "title": "Transformer (deep learning) - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Transformer_(deep_learning_architecture)",
        "date": "2019-08-25",
        "last_updated": "2026-05-19"
      },
      {
        "snippet": "The famous paper “Attention is all you need” by Vaswani et al. presents the transformer architecture.\nThis neural network architecture builds on the attention mechanism and is at the core of current large language models (LLMs) such as ChatGPT, GPT-4, BERT, etc.\n...\nTransformers process sequences of tokens such as (sub-)words in a sentence.\nThe transformer architecture consists of two parts:\n1. The encoder, which processes the tokens of the input sequence and\n2. the decoder, which produces new tokens as output based on the input tokens and the previously produced output tokens.\nThe overall architecture is shown in the figure below with the encoder on the left and the decoder on the right side.\n...\nThe encoder (left side of the figure above), processes the tokens of the input sequence.\nEach token is initially embedded into a *d- * dimensional vector, e.g., using word2vec.\nIt is then processed individually and compared to other tokens in the input.\nThe process works with variable-length sequences.\nAfter embedding the words as vectors, a **positional encoding** is added, which indicates the absolute and relative position of the tokens in the sequence.\nThis is necessary for many tasks, particularly in natural language, since the later parts of the encoder are permutation invariant.\nThis means they do not distinguish the position of the tokens in the sequence.\n...\nAfter positional encoding, follows a **self-attention** block.\nDuring self-attention, the tokens *within the input sequence* are compared to each other, computing *attention weights.\n* A high attention weight for a pair of two tokens indicates that they are syntactically or semantically related.\nThus high weights indicate important tokens that the model should “attend” to.\n...\nFinally, a normal feed-forward neural network follows the attention block and outputs the encoded tokens one by one.\n...\nIn contrast to the encoder, the decoder contains a **cross-attention** block, which compares to the encoded tokens of the input sequence using cross-attention (explained in more detail below).\nThis cross-attention is at the heart of the decoder and helps producing the next output token, taking both the full input and the output produced so far into account.\n...\n## The Attention Mechanism\nThe attention mechanism is at the core of the transformer architecture — thus the paper title “Attention is all you need”.\nIn a transformer, the attention mechanism enables the model to assign different *attention weights/scores* to different tokens in a sequence.\nThis way, the model can give more importance to relevant information, ignore irrelevant information, and effectively capture long-range dependencies in the data.\nThe attention mechanism distinguishes three inputs: The **query Q, the key K, and the value V**.\nEach token in a sequence is a separate input for Q, K, or V.\nThe mechanism compares queries Q with keys K to determine their importance/compatibility to each other, computing attention weights.\nIt then selects corresponding values V with high attention weights.\nThis is an analogy to data bases, hash tables, or Python dictionaries, where we select the values whose keys match a given query best.\n...\n*Self- and cross-attention only differ in which tokens are given as inputs Q, K, and V.* In **self-attention**, the same tokens are used for all three inputs, i.e., each token is used for Q, K, and V.\nIn **cross-attention**, the same tokens are given to K and V, but different tokens are used for Q.\nSelf-attention is applied to the input sequence in the encoder and to the output sequence in the decoder.\nThe decoder’s cross-attention module then uses the encoded input tokens as K and V and the produced output tokens as Q.\nIn either case, attention weights between tokens in Q and in K are calculated using scaled dot-product attention.\nWhile there are other forms of attention such as learned attention weights, scaled dot-product attention is faster and more space efficient.\nIn scaled dot-product attention, attention weights are computed without extra parameters as illustrated in the figure below: Tokens in Q and K are multiplied, scaled, and passed through a softmax function to obtain attention weights.\nThe attention weights are then multiplied with the tokens in V to select values with high corresponding weights.\n...\nMulti-head attention repeats the attention mechanism explained above multiple times (*h * times) in parallel.\nBefore passing the input tokens of dimension *d * into these *h * attention blocks, they projected into smaller embeddings of size* d/h * by using small linear neural networks*.\n* Each of the *h * linear networks has different weights and leads to different projections.\nConsequently, each attention “head” can learn to focus on different aspects, e.g., subject and object of a sentence.\nThe outputs of the *h* heads are then concatenated and passed through another linear neural network.\n...\nOverall, attention is a surprisingly simple yet effective mechanism to emphasize meaningful tokens and ignore less meaningful tokens.\nBased on this mechanism, transformers can take capture the context even in long sequences and produce coherent outputs.",
        "title": "Understanding Transformers and Attention | by Stefan",
        "url": "https://medium.com/@stefanbschneider/understanding-attention-and-transformers-d84b016cd352",
        "date": "2023-11-28",
        "last_updated": "2025-10-27"
      },
      {
        "snippet": "",
        "title": "Attention in transformers, step-by-step | Deep Learning Chapter 6",
        "url": "https://www.youtube.com/watch?v=eMlx5fFNoYc&vl=en",
        "date": "2024-04-07",
        "last_updated": "2026-05-26"
      },
      {
        "snippet": "At the present moment, the dominant models for nearly all natural\nlanguage processing tasks are based on the Transformer architecture.\n...\nThe core idea behind the Transformer model is the *attention mechanism*, an innovation that was originally envisioned as an enhancement for encoder–decoder RNNs applied to sequence-to-sequence applications, such as machine translations ().\nYou might recall that in the first sequence-to-sequence models for machine translation (), the entire input was compressed by the encoder into a single fixed-length vector to be fed into the decoder.\nThe intuition behind attention is that rather than compressing the input, it might be better for the decoder to revisit the input sequence at every step.\nMoreover, rather than always seeing the same representation of the input, one might imagine that the decoder should selectively focus on particular parts of the input sequence at particular decoding steps.\nBahdanau’s attention mechanism provided a simple means by which the decoder could dynamically *attend* to different parts of the input at each decoding step.\nThe high-level idea is that the encoder could produce a representation of length equal to the original input sequence.\nThen, at decoding time, the decoder can (via some control mechanism) receive as input a context vector consisting of a weighted sum of the representations on the input at each time step.\nIntuitively, the weights determine the extent to which each step’s context “focuses” on each input token, and the key is to make this process for assigning the weights differentiable so that it can be learned along with all of the other neural network parameters.\nInitially, the idea was a remarkably successful enhancement to the\n...\nHowever, attention mechanisms soon emerged as more significant concerns,\nbeyond their usefulness as an enhancement for encoder–decoder recurrent\nneural networks and their putative usefulness for picking out salient\ninputs.\nVaswani *et al.* () proposed the Transformer architecture for machine translation, dispensing with recurrent connections altogether, and instead relying on cleverly arranged attention mechanisms to capture all relationships among input and output tokens.",
        "title": "11. Attention Mechanisms and Transformers - Dive into Deep Learning",
        "url": "http://www.d2l.ai/chapter_attention-mechanisms-and-transformers/index.html",
        "date": null,
        "last_updated": "2026-03-12"
      },
      {
        "snippet": "",
        "title": "The self-attention mechanism",
        "url": "https://www.codecademy.com/article/transformer-architecture-self-attention-mechanism",
        "date": "2025-09-19",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "",
        "title": "How Attention Mechanism Works in Transformer Architecture",
        "url": "https://www.youtube.com/watch?v=KMHkbXzHn7s",
        "date": "2025-03-08",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "",
        "title": "Transformer (deep learning architecture) - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Grouped-query_attention",
        "date": "2025-03-14",
        "last_updated": "2025-03-15"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

**2. Filtering with a Single Publication Date Parameter**

If you only wish to restrict the results to those published on or after a specific date, include just the `search_after_date_filter`:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.search.create(
      query="tech industry layoffs at major technology companies",
      max_results=10,
      search_after_date_filter="3/1/2025"
  )

  print(response)
  ```

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

  const client = new Perplexity();

  const response = await client.search.create({
    query: "tech industry layoffs at major technology companies",
    max_results: 10,
    search_after_date_filter: "3/1/2025"
  });

  console.log(response);
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "tech industry layoffs at major technology companies",
      "max_results": 10,
      "search_after_date_filter": "3/1/2025"
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "de495208-dca3-4c87-b69a-6f2eecea26dc",
    "results": [
      {
        "snippet": "114,173 tech employees laid off ∙ 148 tech companies w/ layoffs ∙",
        "title": "Layoffs.fyi - Tech and Startup Layoff Tracker",
        "url": "https://layoffs.fyi",
        "date": "2026-02-03",
        "last_updated": "2026-05-20"
      },
      {
        "snippet": "",
        "title": "Tech Layoffs: US Companies With Job Cuts In 2024, 2025 and 2026",
        "url": "https://news.crunchbase.com/startups/tech-layoffs/",
        "date": "2026-05-14",
        "last_updated": "2026-05-15"
      },
      {
        "snippet": "Meta to Cut 10% of Workforce in Latest AI-Driven Tech Layoffs - NerdWallet\n...\nIn 2026, tech layoffs are surging, with major companies citing AI development as a key driver.\n...\nUpdated April 23.\nSo far in 2026, roughly 98 tech companies have laid off over 92,000 workers.\nSeveral major companies have explicitly pointed to investments in AI research and development as the driving force behind recent job cuts.\n- Amazon announced on Jan. 28 it would cut about 16,000 more roles across the company, following an October trim of 14,000 jobs.\n- In February, Block — led by Twitter co-founder Jack Dorsey — cut 4,000 jobs, or about 40% of its staff.\n- On March 11, Atlassian laid off 1,600 workers.\n- On March 16, Dell said it reduced its global staff by 10%, or nearly 11,000 workers.\n- On April 6, Oracle laid off 30,000 workers to fund its AI infrastructure initiatives.\n- On April 23, Meta said it would cut 10% of its workforce — about 8,000 jobs — and close 6,000 open roles as it zeroes in on AI development.\n...\nSo far in 2026, roughly 98 tech companies have laid off more than 92,000 workers.\n...\n## What tech layoffs happened in 2025?\nThe total number of tech layoffs in 2025 was 122,549 across 257 companies according to layoffs.fyi., which tracks job cuts in the tech industry.\nThat’s down from 152,922 employees laid off from 551 companies in 2024, according to layoffs.fyi.\nCompanies that announced layoffs in waves of more than 10,000 workers included some of the biggest names in tech: Intel, Amazon, Tesla, Google, Meta and Microsoft.\n...\nThe majority of layoffs at the beginning of 2022 came from startups, according to Lee.\nBut in late 2022 and early 2023 it started to creep into bigger tech, as well.\nLee also said that “Big Tech” layoffs like those seen at Meta and Twitter “present a unique opportunity to recruit a caliber of talent that would've previously been impossible to attract.”",
        "title": "Meta to Cut 10% of Workforce in Latest AI-Driven Tech Layoffs",
        "url": "https://www.nerdwallet.com/finance/learn/tech-layoffs",
        "date": "2022-12-01",
        "last_updated": "2026-05-22"
      },
      {
        "snippet": "",
        "title": "Companies that announced Major Layoffs and Hiring Freezes",
        "url": "https://intellizence.com/insights/layoff-downsizing/major-companies-that-announced-mass-layoffs/",
        "date": "2026-05-11",
        "last_updated": "2026-05-18"
      },
      {
        "snippet": "",
        "title": "Major tech layoffs: An updated tracker - InformationWeek",
        "url": "https://www.informationweek.com/it-leadership/tech-company-layoffs-the-covid-tech-bubble-bursts-sep-14",
        "date": "2026-01-05",
        "last_updated": "2026-05-26"
      },
      {
        "snippet": "Layoffs are making headlines, and most seem to be centered on one job sector -- tech.\nJanuary layoffs were the highest they've been since 2009, according to a report from Challenger, Gray & Christmas, including 22,291 job cuts in the tech sector.\nThe bulk of these came from a round of Amazon layoffs that cut 16,000 jobs, disproportionately affecting tech roles, including AWS.\nGoogle and Pinterest also announced cuts in January.\nIn 2025, 271 tech companies laid off more than 124,201 employees, according to Layoffs.fyi, compared to 152,922 employees in 2024 and 264,320 in 2023.\nUnlike previous layoff surges during and after the COVID-19 crisis, layoffs are now more focused on restructuring driven by AI and slow market growth, rather than emergency cost-cutting.\nTech roles have accounted for a large share of recent layoffs due to AI integration and AI-related job consolidation, but roles affected by layoffs go far beyond tech.\nHowever, in a high-volume sector, tech layoffs tend to have more visibility because a small percentage of layoffs still translates to thousands of people losing their jobs.\nThere are several factors contributing to tech layoffs, including uncertain macroeconomic conditions, market instability and the scaling of AI.\n...\nAI is now the top influence on layoff decisions, cited more frequently by HR leaders than industry or market trends, according to a CareerMinds report.\n...\nAI was cited as the reason for nearly 55,000 layoffs in 2025, according to Challenger, Gray & Christmas.\nIn the coming year, 32% of companies expect a decrease in workforce size due to AI, according to a McKinsey report.\n...\nThis has led to layoffs due to role redesigns that move away from administrative, repetitive tasks and toward high-level oversight of automated processes and technology.\n...\nIn 2025, 55% of companies conducting layoffs cited economic uncertainty, according to a Resume.org survey.\nSix in 10 companies plan to conduct layoffs in 2026.\n...\nPepsiCo announced job cuts and plant closures, as well as slashing 20% of its products, in relation to an agreement with Elliott Investment Management to improve operational efficiency and cut costs.\n...\nTech layoffs may also result from the industry maturing or becoming more stable after rapid growth.\nDuring the pandemic and into the AI boom, tech companies saw rapid expansions both in operations and hiring.\nNow, many companies are conducting layoffs to stabilize and correct unsustainable growth.\nTech companies may not be on pace to acquire as many new customers as they have already adopted their services.\nInstead, tech companies may be looking beyond growth and into diversifying products or expanding globally.\nOrganizations are also prioritizing workforce consolidation and operational discipline to accommodate market shifts and slower revenue growth.\n...\nMany companies are also laying off workers due to shifts in skill demands.\nAI skills are splitting the market, creating a gap between AI-skilled and non-AI-skilled workers.\n...\nIn September 2025, Accenture's CEO announced layoff plans, targeting employees who couldn't reskill on AI, resulting in 11,000 job cuts.\n...\nDepending on the size of the company, large layoffs may range from a few hundred to tens of thousands, which can be a large percentage of its workforce.\nSome big tech companies -- such as Amazon and Meta -- have announced large layoffs in waves.\nIn October 2025, Amazon announced 14,000 job cuts.\nIn January 2026, they cut 16,000 more jobs.\nSalesforce eliminated more than 4,000 customer support roles in June 2025.\nIts CEO Marc Benioff cited AI, saying that it was already doing 30-50% of the work at the company.\nIn April 2025, Intel cut 20% of its workforce, more than 21,000 roles in a restructuring under new executive leadership.\nHP announced plans to cut 6,000 roles by the end of the 2028 fiscal year in an AI-focused restructuring.\nLayoffs are still rampant across the tech sector in 2026.\nAs of this writing, 35,650 tech employees from 50 tech companies have been laid off, according to Layoffs.fyi.",
        "title": "Tech sector layoffs explained: What you need to know - TechTarget",
        "url": "https://www.techtarget.com/whatis/feature/Tech-sector-layoffs-explained-What-you-need-to-know",
        "date": "2026-03-06",
        "last_updated": "2026-05-23"
      },
      {
        "snippet": "",
        "title": "Tech Companies That Have Made Layoffs from 2022 to 2026",
        "url": "https://tech.co/news/tech-companies-layoffs",
        "date": "2023-02-27",
        "last_updated": "2026-05-22"
      },
      {
        "snippet": "",
        "title": "A comprehensive list of 2025 tech layoffs | TechCrunch",
        "url": "https://techcrunch.com/2025/12/22/tech-layoffs-2025-list/",
        "date": "2025-12-22",
        "last_updated": "2026-05-26"
      },
      {
        "snippet": "",
        "title": "2026 Tech Layoffs Tracker - SkillSyncer",
        "url": "https://skillsyncer.com/layoffs-tracker",
        "date": null,
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "Big Tech companies laid off hundreds of employees in recent days, commanding headlines and confronting workers across the economy with a question: Am I next?\nAmazon and Google each imposed cuts, with Apple shutting down a 121-person team in San Diego, Calif., telling workers they must either transfer to Texas or leave the company, Bloomberg reported.\nIn all, the tech sector has laid off nearly 8,000 workers so far this year, according to layoffs.fyi, a site that tracks tech-sector employment.\nThe job cuts stem in large part from an ongoing staff reevaluation specific to the tech industry, since sales have retreated from the blistering pace attained during the pandemic, analysts said, noting comparatively scant layoffs across the wider workforce.\nHowever, the recent cutbacks in tech also are due to the rise of artificial intelligence and the persistence of high interest rates, some analysts said, foretelling similar risks for workers across major swathes of the economy.MORE: Bank overdraft fees may soon plummet.\nHere's what to know.\n...\nEven the job cuts in tech are relatively small compared with tens of thousands of employees laid off at the outset of last year.\n...\nLayoffs at Google, for instance, affected hundreds of workers focused on the company's well-known products, such as Google Assistant, as well as Google-owned YouTube.\nThe cuts came in part from the company's priority shift toward AI, according to an internal memo from CEO Sundar Pichai, confirmed to ABC News by a Google spokesperson.\n...\n\"Tech companies are hiring and firing on a small scale very often because they're still experimenting with how to commercialize and scale AI,\" Daniel Keum, a professor of management at the Columbia University Business School, told ABC News.\n...\nReluctant to overstate the risk, however, Kayes downplayed the recent job cuts in tech.\n\"These are fairly small layoffs,\" he said.",
        "title": "Big Tech layoffs are back. Are other workers at risk?",
        "url": "https://abcnews.go.com/amp/Business/big-tech-layoffs-back-workers-risk/story?id=106476154",
        "date": "2024-01-18",
        "last_updated": "2025-03-07"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

**3. Filtering by Last Updated Date Range**

This example limits search results to content that was last updated between July 1, 2025, and December 30, 2025. This is useful for finding recently maintained or refreshed content.

**Request Example**

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.search.create(
      query="machine learning interpretability research methods",
      max_results=10,
      last_updated_after_filter="07/01/2025",
      last_updated_before_filter="12/30/2025"
  )

  print(response)
  ```

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

  const client = new Perplexity();

  const response = await client.search.create({
    query: "machine learning interpretability research methods",
    max_results: 10,
    last_updated_after_filter: "07/01/2025",
    last_updated_before_filter: "12/30/2025"
  });

  console.log(response);
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "machine learning interpretability research methods",
      "max_results": 10,
      "last_updated_after_filter": "07/01/2025",
      "last_updated_before_filter": "12/30/2025"
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "43425e11-87b1-4ba6-82f6-d399c308f4a6",
    "results": [
      {
        "snippet": "### Model-agnostic interpretability methods\n\nSeveral important model-agnostic interpretability methods exist, and while none of them are perfect, they can help researchers interpret the results of even very complex ML models.\n\nFor demonstration purposes, let’s consider a small time-series dataset. A time series is simply a series of data points indexed in time order. It is the most common type of data in the financial industry. A frequent goal of quantitative research is to identify trends, seasonal variations, and correlation in financial time series data using statistical and machine learning methods.\n\n…\n\n#### Method 1: Partial Dependence Plot (PDP)\n\nThe first method we’ll examine is Partial Dependence Plot or PDP, which was invented decades ago, and shows the marginal effect that one or two features have on the predicted outcome of a machine learning model.\n\nIt helps researchers determine what happens to model predictions as various features are adjusted.\n\nHere in this plot, the x-axis represents the value of feature f0, and the y-axis represents the predicted value. The solid line in the shaded area shows how the average prediction varies as the value of f0 changes.\nPDP is very intuitive and easy to implement, but because it only shows the average marginal effects, **heterogeneous effects might be hidden**.^1^ For example, one feature might show a positive relationship with prediction for half of the data, but a negative relationship for the other half. The plot of the PDP will simply be a horizontal line.\n\n…\n\n##### PDP vs. ICE vs. Feature Importance\n\nAll three of the methods above are intuitive and easy to implement.\n\nPDP shows global effects, while hiding heterogeneous effects. ICE can uncover heterogeneous effects, but makes it hard to see the average.\n\nFeature importance provides a concise way to understand the model’s behavior. The use of error ratio (instead of the error) makes the measurements comparable across different problems. And it automatically takes into account all interactions with other features.\nHowever, the interactions are not additive. Adding up feature importance does not result in a total drop in performance. Shuffling the features adds randomness, so the results may be different each time. Also, the shuffling requires access to true outcomes, which is impossible for many scenarios.\n\nBesides, all three methods assume the independence of the features, so if features are correlated, unlikely data points will be created and the interpretation can be biased by these unrealistic data points.\n\n#### Method 4: Global Surrogate\n\nThe global surrogate method takes a different approach. In this case, an interpretable model is trained to approximate the prediction of a black box model.\n\nThe process is simple. First you get predictions on a dataset with the trained black box model, and then train an interpretable model on this dataset and predictions. The trained interpretable model now becomes a surrogate of the original model, and all we need to do is to interpret the surrogate model. Note, the surrogate model could be any interpretable model: linear model, decision tree, human defined rules, etc.\n\n…\n\nFirst the image on the left is divided into interpretable components. LIME then generates a dataset of perturbed instances by turning some of the interpretable components “off” (in this case, making them gray).\n\nFor each perturbed instance, one can use the trained model to get the probability that a tree frog is in the image, and then learn a locally weighted linear model on this dataset.\n\n…\n\n##### Global vs. Local Surrogate Methods\n\nBoth the global and local surrogate methods have advantages and disadvantages.\n\nGlobal surrogate cares about explaining the whole logic of the model, while local surrogate is only interested in understanding specific predictions.\n\nWith the global surrogate method, any interpretable model can be used as surrogate, and the closeness of the surrogate models to the black box models can easily be measured.\nHowever, since the surrogate models are trained only on the predictions of the black box model instead of the real outcome, they can only interpret the model, and not the data. Besides, the surrogate models, which are simpler than the black box model in a lot of cases, may only be able to give good explanations to part of the data, instead of the entire dataset.\nThe local surrogate method, on the other hand, does not share these shortcomings. In addition, the local surrogate method is model-agnostic: If you need to try a different black box model for your problem, you can still use the same surrogate models for interpretations. And compared with interpretations given by global surrogate methods, the interpretations from local surrogate methods are often short, contrastive, and human-friendly.\nHowever, local surrogate has its own issues.\n\nFirst, LIME uses a kernel to define the area within which data points are considered for local explanations, but it is difficult to find the proper kernel setting for a task. The way sampling is done in LIME can lead to unrealistic data points, and the local interpretation can be biased towards those data points.\nAnother concern is the instability of the explanations. Two very close points could lead to two very different explanations.\n\n…\n\n##### Shapley Value vs. LIME\n\nAs data scientist Christoph Molnar points out in* Interpretable Machine Learning*, the Shapley Value might be the only method to deliver a full interpretation, and it is the explanation method with the strongest theoretical basis.\n\nThere are, however, trade-offs. Calculating the Shapley Value is computationally expensive. The recently developed kernel SHAP method does a fast kernel approximation to solve this problem, but for large background data, it still costs a lot of computation.\n\n…\n\n- **Application-grounded** evaluation requires a human to perform experiments within a real-life application.^4^ For example, to evaluate an interpretation on diagnosing a certain disease, the best way is for the doctor to perform diagnoses.\n- **Human-grounded** evaluation is about conducting simpler human-subject experiments. For example, humans are presented with pairs of explanations, and must choose the one that they find to be of higher quality.",
        "title": "Interpretability Methods in Machine Learning: A Brief Survey",
        "url": "https://www.twosigma.com/articles/interpretability-methods-in-machine-learning-a-brief-survey/",
        "date": "2019-06-25",
        "last_updated": "2026-04-01"
      },
      {
        "snippet": "",
        "title": "2 Interpretability – Interpretable Machine Learning",
        "url": "https://christophm.github.io/interpretable-ml-book/interpretability.html",
        "date": null,
        "last_updated": "2026-05-16"
      },
      {
        "snippet": "## Type 3 interpretability: unraveled rules and laws\n\nWith this type of interpretability, we seek to discover “rules” and “laws” learned by the machine model. These can be in the form of decision rules, or even “counterfactual” explanations in the form of “What if?” question-answer pairs that describe the smallest adjustment to the patient’s features that would change the model’s prediction to a predefined output. For example, a clinician could use this type of interpretability to establish the smallest difference in tumor size that would change the model’s prediction for a patient with cancer.\n\n…\n\nUsing five familiar data sets from the UCI repository and two familiar machine learning algorithms, we demonstrate that our algorithm produces global interpretations that are both faithful (highly accurate) and parsimonious (involve a small number of terms). Our interpretations permit easy understanding of the relative importance of features and feature interactions. Our interpretation algorithm represents a leap forward from the previous state of the art.\n\n…\n\nThrough this rigorous formalism, we derive (1) two metrics to measure the robustness of any interpretability method with respect to the model symmetry group; (2) theoretical robustness guarantees for some popular interpretability methods and (3) a systematic approach to increase the invariance of any interpretability method with respect to a symmetry group. By empirically measuring our metrics for explanations of models associated with various modalities and symmetry groups, we derive a set of 5 guidelines that we present in-depth to allow users and developers of interpretability methods to produce robust explanations.\n\n### Evaluating the Robustness of Interpretability Methods through Explanation Invariance and Equivariance\n\nJonathan Crabbé, Mihaela van der Schaar\n\n*NeurIPS 202*3\n\n**Abstract**\n\nInterpretability methods are valuable only if their explanations faithfully describe the explained model. In this work, we consider neural networks whose predictions are invariant under a specific symmetry group. This includes popular architectures, ranging from convolutional to graph neural networks.\nAny explanation that faithfully explains this type of model needs to be in agreement with this invariance property. We formalize this intuition through the notion of explanation invariance and equivariance by leveraging the formalism from geometric deep learning. Through this rigorous formalism, we derive (1) two metrics to measure the robustness of any interpretability method with respect to the model symmetry group; (2) theoretical robustness guarantees for some popular interpretability methods and (3) a systematic approach to increase the invariance of any interpretability method with respect to a symmetry group.\nBy empirically measuring our metrics for explanations of models associated with various modalities and symmetry groups, we derive a set of 5 guidelines to allow users and developers of interpretability methods to produce robust explanations.",
        "title": "Interpretable machine learning - van der Schaar Lab",
        "url": "https://www.vanderschaar-lab.com/interpretable-machine-learning/",
        "date": "2024-05-31",
        "last_updated": "2026-02-02"
      },
      {
        "snippet": "This taxonomy focuses on the purpose that these methods were created to serve and the ways through which they accomplish this purpose. As a result, according to the presented taxonomy, four major categories for interpretability methods are identified: methods for explaining complex black-box models, methods for creating white-box models, methods that promote fairness and restrict the existence of discrimination, and, lastly, methods for analysing the sensitivity of model predictions.\n\n…\n\nIn order to address this issue, after introducing a quality criterion for neuron-wise signal estimators in order to evaluate existing methods and ultimately obtain estimators that optimize towards this criterion, the authors propose two interpretation methods that are are theoretically sound for linear models, PatternNet and PatternAtrribution. The former is used to estimate the correct direction, improving upon the DeConvNet[32] and Guided BackPropagation[31] visualizations, while the latter to identify how much the different signal dimensions contribute to the output through the network layers.\n\n…\n\nIn order to address these issues, they proposed an improved faster, model agnostic technique for finding explainable counterfactual explanations of classifier predictions. This novel method incorporates class prototypes, constructed using either an encoder or class specific k-d trees, in the cost function to enable the perturbations to converge much faster to an interpretable counterfactual, hence removing the computational bottleneck and making the method more suitable for practical applications.\nIn order to illustrate the effectiveness of their approach and the quality of the produced counterfactuals, the authors introduced two new metrics focusing on local interpretability at the instance level. By conducting experiments on both image data (MNIST dataset) and tabular data (Wisconsin Breast Cancer dataset), they showed that prototypes help to produce counterfactuals of superior quality.",
        "title": "Explainable AI: A Review of Machine Learning Interpretability Methods",
        "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC7824368/",
        "date": "2020-12-25",
        "last_updated": "2026-03-27"
      },
      {
        "snippet": "In particular, it is unclear how the wide array of proposed interpretation methods are related and what common concepts can be used to evaluate them. We aim to address these concerns by defining interpretability in the context of machine learning and introducing the predictive, descriptive, relevant (PDR) framework for discussing interpretations. The PDR framework provides 3 overarching desiderata for evaluation: predictive accuracy, descriptive accuracy, and relevancy, with relevancy judged relative to a human audience.\n\n…\n\nIn this paper, we attempt to address these concerns. To do so, we first define interpretability in the context of machine learning and place it within a generic data science life cycle. This allows us to distinguish between 2 main classes of interpretation methods: model based* and post hoc. We then introduce the predictive, descriptive, relevant (PDR) framework, consisting of 3 desiderata for evaluating and constructing interpretations: predictive accuracy, descriptive accuracy, and relevancy, where relevancy is judged by a human audience. Using these terms, we categorize a broad range of existing methods, all grounded in real-world examples.\n\n…\n\n### Interpretation Methods within the PDR Framework.\n\nIn the framework described above, our definition of interpretable ML focuses on methods in either the modeling or post hoc analysis stages. We call interpretability in the modeling stage model-based interpretability (\n\n*Section 5*). This part of interpretability is focused upon the construction of models that readily provide insight into the relationships they have learned. To provide this insight, model-based interpretability techniques must generally use simpler models, which can result in lower predictive accuracy. Consequently, model-based interpretability is best used when the underlying relationship is sufficiently simple that model-based techniques can achieve reasonable predictive accuracy or when predictive accuracy is not a concern.\n\n…\n\n## 5. Model-Based Interpretability\n\nWe now discuss how interpretability considerations come into play in the modeling stage of the data–science life cycle (Fig. 1). At this stage, the practitioner constructs an ML model from the collected data. We define model-based interpretability as the construction of models that readily provide insight into the relationships they have learned. Different model-based interpretability methods provide different ways of increasing descriptive accuracy by constructing models which are easier to understand, sometimes resulting in lower predictive accuracy. The main challenge of model-based interpretability is to come up with models that are simple enough to be easily understood by the audience, while maintaining high predictive accuracy.\nIn selecting a model to solve a domain problem, the practitioner must consider the entirety of the PDR framework. The first desideratum to consider is predictive accuracy. If the constructed model does not accurately represent the underlying problem, any subsequent analysis will be suspect (29, 30). Second, the main purpose of model-based interpretation methods is to increase descriptive accuracy. Finally, the relevancy of a model’s output must be considered and is determined by the context of the problem, data, and audience. We now discuss some common types of model-based interpretability methods.\n\n…\n\n### B. Model Based.\n\nNow that we have discussed the general problem of evaluating interpretations, we highlight important challenges for the 2 main subfields of interpretable machine learning: model-based and post hoc interpretability. Whenever model-based interpretability can achieve reasonable predictive accuracy and relevancy, by virtue of its high descriptive accuracy it is preferable to fitting a more complex model and relying upon post hoc interpretability. Thus, the main focus for model-based interpretability is increasing its range of possible use cases by increasing its predictive accuracy through more accurate models and transparent feature engineering. It is worth noting that sometimes a combination of model-based and post hoc interpretations is ideal.",
        "title": "Definitions, methods, and applications in interpretable machine learning | PNAS",
        "url": "https://www.pnas.org/doi/10.1073/pnas.1900654116",
        "date": "2019-10-29",
        "last_updated": "2025-03-08"
      },
      {
        "snippet": "",
        "title": "[PDF] An Overview of Interpretability of Machine Learning - arXiv",
        "url": "https://arxiv.org/pdf/1806.00069.pdf",
        "date": null,
        "last_updated": "2026-05-06"
      },
      {
        "snippet": "In particular, it is unclear how the wide array of proposed interpretation methods are related and what common concepts can be used to evaluate them. We aim to address these concerns by defining interpretability in the context of machine learning and introducing the predictive, descriptive, relevant (PDR) framework for discussing interpretations. The PDR framework provides 3 overarching desiderata for evaluation: predictive accuracy, descriptive accuracy, and relevancy, with relevancy judged relative to a human audience.\n\n…\n\nIn this paper, we attempt to address these concerns. To do so, we first define interpretability in the context of machine learning and place it within a generic data science life cycle. This allows us to distinguish between 2 main classes of interpretation methods: model based and post hoc. We then introduce the predictive, descriptive, relevant (PDR) framework, consisting of 3 desiderata for evaluating and constructing interpretations: predictive accuracy, descriptive accuracy, and relevancy, where relevancy is judged by a human audience.\n\n…\n\n### Interpretation Methods within the PDR Framework.\n\nIn the framework described above, our definition of interpretable ML focuses on methods in either the modeling or post hoc analysis stages. We call interpretability in the modeling stage model-based interpretability (*Section 5*). This part of interpretability is focused upon the construction of models that readily provide insight into the relationships they have learned. To provide this insight, model-based interpretability techniques must generally use simpler models, which can result in lower predictive accuracy. Consequently, model-based interpretability is best used when the underlying relationship is sufficiently simple that model-based techniques can achieve reasonable predictive accuracy or when predictive accuracy is not a concern.\n\n…\n\nIn selecting a model to solve a domain problem, the practitioner must consider the entirety of the PDR framework. The first desideratum to consider is predictive accuracy. If the constructed model does not accurately represent the underlying problem, any subsequent analysis will be suspect (29, 30). Second, the main purpose of model-based interpretation methods is to increase descriptive accuracy. Finally, the relevancy of a model’s output must be considered and is determined by the context of the problem, data, and audience. We now discuss some common types of model-based interpretability methods.",
        "title": "Definitions, methods, and applications in interpretable ...",
        "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC6825274/",
        "date": "2019-10-16",
        "last_updated": "2026-02-02"
      },
      {
        "snippet": "Within this framework, methods are organized into two classes: model-based and post-hoc. To provide guidance in selecting and evaluating interpretation methods, we introduce three desiderata: predictive accuracy, descriptive accuracy, and relevancy. Using our framework, we review existing work, grounded in real-world studies which exemplify our desiderata, and suggest directions for future work. \\authorcontributionsW.M., C.S., K.K., R.A., and B.Y. helped identify important concepts and provided feedback on the paper.\n\n…\n\nWe aim to address these concerns by defining interpretability in the context of machine learning and introducing the Predictive, Descriptive, Relevant (PDR) framework for discussing interpretations. The PDR framework provides three overarching desiderata for evaluation: predictive accuracy, descriptive accuracy and relevancy, with relevancy judged relative to a human audience.\n\n…\n\n### 2.1 Interpretation methods within the PDR framework\n\nIn the framework described above, most interpretation methods fall either in the modeling or post hoc analysis stages. We call interpretability in the modeling stage model-based interpretability (Sec 4). This part of interpretability is focused upon constraining the form of ML models so that they readily provide useful information about the uncovered relationships. As a result of these constraints, the space of potential models is smaller, which can result in lower predictive accuracy. Consequently, model-based interpretability is best used when the underlying relationship is relatively simple.\n\n…\n\nIn selecting a model to solve a domain problem, the practitioner must consider the entirety of the PDR  framework. The first desideratum to consider is predictive accuracy. If the constructed model does not accurately represent the underlying problem, any subsequent analysis will be suspect (28, 29). Second, the main purpose of model-based interpretation methods is to increase descriptive accuracy. Finally, the relevancy of a model’s output must be considered, and is determined by the context of the problem, data, and audience. We now discuss some widely useful types of model-based interpretability methods.\n\n…\n\nMost widely useful post hoc interpretation methods fall into two main categories: prediction-level and dataset-level interpretations, which are sometimes referred to as local and global interpretations, respectively. Prediction-level interpretation methods focus on explaining individual predictions made by models, such as what features and/or interactions led to the particular prediction. Dataset-level approaches focus on the global relationships the model has learned, such as what visual patterns are associated with a predicted response. These two categories have much in common (in fact, dataset-level approaches often yield information at the prediction-level), but we discuss them separately, as methods at different levels are meaningfully different.\n\n…\n\n### 6.2 Model-based\n\nNow that we have discussed the general problem of evaluating interpretations, we highlight important challenges for the two main sub-fields of interpretable machine learning: model-based and post hoc interpretability. Whenever model-based interpretability can achieve reasonable predictive accuracy and relevancy, by virtue of its high descriptive accuracy it is preferable to fitting a more complex model, and relying upon post hoc interpretability. Thus, the main focus for model-based interpretability is increasing its range of possible use cases by increasing its predictive accuracy through more accurate models and transparent feature engineering. It is worth noting that sometimes a combination of model-based and post hoc interpretations is ideal.",
        "title": "Interpretable machine learning: definitions, methods, and applications",
        "url": "https://ar5iv.labs.arxiv.org/html/1901.04592",
        "date": "2011-02-07",
        "last_updated": "2026-03-14"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

**4. Using Search Recency Filter**

The `search_recency_filter` provides a convenient way to filter results by predefined time periods without specifying exact dates:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.search.create(
      query="transformer architecture attention mechanism",
      max_results=10,
      search_recency_filter="week"
  )

  print(response)
  ```

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

  const client = new Perplexity();

  const response = await client.search.create({
    query: "transformer architecture attention mechanism",
    max_results: 10,
    search_recency_filter: "week"
  });

  console.log(response);
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "transformer architecture attention mechanism",
      "max_results": 10,
      "search_recency_filter": "week"
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "5cdd76b9-da5a-4f9f-8c75-61c90a2399a2",
    "results": [
      {
        "snippet": "",
        "title": "What is an attention mechanism?",
        "url": "https://www.ibm.com/think/topics/attention-mechanism",
        "date": "2024-12-05",
        "last_updated": "2026-03-31"
      },
      {
        "snippet": "",
        "title": "Introduction to Transformers and Attention Mechanisms",
        "url": "https://medium.com/@kalra.rakshit/introduction-to-transformers-and-attention-mechanisms-c29d252ea2c5",
        "date": "2024-02-07",
        "last_updated": "2025-10-29"
      },
      {
        "snippet": "",
        "title": "Transformer (deep learning) - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Transformer_(deep_learning)",
        "date": "2019-08-25",
        "last_updated": "2026-05-15"
      },
      {
        "snippet": "",
        "title": "Transformer (deep learning) - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Transformer_(deep_learning_architecture)",
        "date": "2019-08-25",
        "last_updated": "2026-05-19"
      },
      {
        "snippet": "The famous paper “Attention is all you need” by Vaswani et al. presents the transformer architecture.\nThis neural network architecture builds on the attention mechanism and is at the core of current large language models (LLMs) such as ChatGPT, GPT-4, BERT, etc.\n...\nTransformers process sequences of tokens such as (sub-)words in a sentence.\nThe transformer architecture consists of two parts:\n1. The encoder, which processes the tokens of the input sequence and\n2. the decoder, which produces new tokens as output based on the input tokens and the previously produced output tokens.\nThe overall architecture is shown in the figure below with the encoder on the left and the decoder on the right side.\n...\nThe encoder (left side of the figure above), processes the tokens of the input sequence.\nEach token is initially embedded into a *d- * dimensional vector, e.g., using word2vec.\nIt is then processed individually and compared to other tokens in the input.\nThe process works with variable-length sequences.\nAfter embedding the words as vectors, a **positional encoding** is added, which indicates the absolute and relative position of the tokens in the sequence.\nThis is necessary for many tasks, particularly in natural language, since the later parts of the encoder are permutation invariant.\nThis means they do not distinguish the position of the tokens in the sequence.\n...\nAfter positional encoding, follows a **self-attention** block.\nDuring self-attention, the tokens *within the input sequence* are compared to each other, computing *attention weights.\n* A high attention weight for a pair of two tokens indicates that they are syntactically or semantically related.\nThus high weights indicate important tokens that the model should “attend” to.\n...\nFinally, a normal feed-forward neural network follows the attention block and outputs the encoded tokens one by one.\n...\nIn contrast to the encoder, the decoder contains a **cross-attention** block, which compares to the encoded tokens of the input sequence using cross-attention (explained in more detail below).\nThis cross-attention is at the heart of the decoder and helps producing the next output token, taking both the full input and the output produced so far into account.\n...\n## The Attention Mechanism\nThe attention mechanism is at the core of the transformer architecture — thus the paper title “Attention is all you need”.\nIn a transformer, the attention mechanism enables the model to assign different *attention weights/scores* to different tokens in a sequence.\nThis way, the model can give more importance to relevant information, ignore irrelevant information, and effectively capture long-range dependencies in the data.\nThe attention mechanism distinguishes three inputs: The **query Q, the key K, and the value V**.\nEach token in a sequence is a separate input for Q, K, or V.\nThe mechanism compares queries Q with keys K to determine their importance/compatibility to each other, computing attention weights.\nIt then selects corresponding values V with high attention weights.\nThis is an analogy to data bases, hash tables, or Python dictionaries, where we select the values whose keys match a given query best.\n...\n*Self- and cross-attention only differ in which tokens are given as inputs Q, K, and V.* In **self-attention**, the same tokens are used for all three inputs, i.e., each token is used for Q, K, and V.\nIn **cross-attention**, the same tokens are given to K and V, but different tokens are used for Q.\nSelf-attention is applied to the input sequence in the encoder and to the output sequence in the decoder.\nThe decoder’s cross-attention module then uses the encoded input tokens as K and V and the produced output tokens as Q.\nIn either case, attention weights between tokens in Q and in K are calculated using scaled dot-product attention.\nWhile there are other forms of attention such as learned attention weights, scaled dot-product attention is faster and more space efficient.\nIn scaled dot-product attention, attention weights are computed without extra parameters as illustrated in the figure below: Tokens in Q and K are multiplied, scaled, and passed through a softmax function to obtain attention weights.\nThe attention weights are then multiplied with the tokens in V to select values with high corresponding weights.\n...\nMulti-head attention repeats the attention mechanism explained above multiple times (*h * times) in parallel.\nBefore passing the input tokens of dimension *d * into these *h * attention blocks, they projected into smaller embeddings of size* d/h * by using small linear neural networks*.\n* Each of the *h * linear networks has different weights and leads to different projections.\nConsequently, each attention “head” can learn to focus on different aspects, e.g., subject and object of a sentence.\nThe outputs of the *h* heads are then concatenated and passed through another linear neural network.\n...\nOverall, attention is a surprisingly simple yet effective mechanism to emphasize meaningful tokens and ignore less meaningful tokens.\nBased on this mechanism, transformers can take capture the context even in long sequences and produce coherent outputs.",
        "title": "Understanding Transformers and Attention | by Stefan",
        "url": "https://medium.com/@stefanbschneider/understanding-attention-and-transformers-d84b016cd352",
        "date": "2023-11-28",
        "last_updated": "2025-10-27"
      },
      {
        "snippet": "",
        "title": "Attention in transformers, step-by-step | Deep Learning Chapter 6",
        "url": "https://www.youtube.com/watch?v=eMlx5fFNoYc&vl=en",
        "date": "2024-04-07",
        "last_updated": "2026-05-26"
      },
      {
        "snippet": "At the present moment, the dominant models for nearly all natural\nlanguage processing tasks are based on the Transformer architecture.\n...\nThe core idea behind the Transformer model is the *attention mechanism*, an innovation that was originally envisioned as an enhancement for encoder–decoder RNNs applied to sequence-to-sequence applications, such as machine translations ().\nYou might recall that in the first sequence-to-sequence models for machine translation (), the entire input was compressed by the encoder into a single fixed-length vector to be fed into the decoder.\nThe intuition behind attention is that rather than compressing the input, it might be better for the decoder to revisit the input sequence at every step.\nMoreover, rather than always seeing the same representation of the input, one might imagine that the decoder should selectively focus on particular parts of the input sequence at particular decoding steps.\nBahdanau’s attention mechanism provided a simple means by which the decoder could dynamically *attend* to different parts of the input at each decoding step.\nThe high-level idea is that the encoder could produce a representation of length equal to the original input sequence.\nThen, at decoding time, the decoder can (via some control mechanism) receive as input a context vector consisting of a weighted sum of the representations on the input at each time step.\nIntuitively, the weights determine the extent to which each step’s context “focuses” on each input token, and the key is to make this process for assigning the weights differentiable so that it can be learned along with all of the other neural network parameters.\nInitially, the idea was a remarkably successful enhancement to the\n...\nHowever, attention mechanisms soon emerged as more significant concerns,\nbeyond their usefulness as an enhancement for encoder–decoder recurrent\nneural networks and their putative usefulness for picking out salient\ninputs.\nVaswani *et al.* () proposed the Transformer architecture for machine translation, dispensing with recurrent connections altogether, and instead relying on cleverly arranged attention mechanisms to capture all relationships among input and output tokens.",
        "title": "11. Attention Mechanisms and Transformers - Dive into Deep Learning",
        "url": "http://www.d2l.ai/chapter_attention-mechanisms-and-transformers/index.html",
        "date": null,
        "last_updated": "2026-03-12"
      },
      {
        "snippet": "",
        "title": "The self-attention mechanism",
        "url": "https://www.codecademy.com/article/transformer-architecture-self-attention-mechanism",
        "date": "2025-09-19",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "",
        "title": "How Attention Mechanism Works in Transformer Architecture",
        "url": "https://www.youtube.com/watch?v=KMHkbXzHn7s",
        "date": "2025-03-08",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "",
        "title": "Transformer (deep learning architecture) - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Grouped-query_attention",
        "date": "2025-03-14",
        "last_updated": "2025-03-15"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

This example will return only content from the past 7 days, automatically calculated from the current date.

**5. Different Recency Filter Options**

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Get content from the past hour (real-time: breaking news or live events)
  hour_response = client.search.create(
      query="Apollo 11 moon landing mission overview",
      max_results=5,
      search_recency_filter="hour"
  )

  # Get content from the past day
  day_response = client.search.create(
      query="history of the printing press",
      max_results=5,
      search_recency_filter="day"
  )

  # Get content from the past month
  month_response = client.search.create(
      query="AI research developments",
      max_results=10,
      search_recency_filter="month"
  )

  # Get content from the past year
  year_response = client.search.create(
      query="major technology trends",
      max_results=15,
      search_recency_filter="year"
  )
  ```

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

  const client = new Perplexity();

  // Get content from the past hour (real-time: breaking news or live events)
  const hourResponse = await client.search.create({
    query: "Apollo 11 moon landing mission overview",
    max_results: 5,
    search_recency_filter: "hour"
  });

  // Get content from the past day
  const dayResponse = await client.search.create({
    query: "history of the printing press",
    max_results: 5,
    search_recency_filter: "day"
  });

  // Get content from the past month
  const monthResponse = await client.search.create({
    query: "AI research developments",
    max_results: 10,
    search_recency_filter: "month"
  });

  // Get content from the past year
  const yearResponse = await client.search.create({
    query: "major technology trends",
    max_results: 15,
    search_recency_filter: "year"
  });
  ```

  ```bash cURL theme={null}
  # Get content from the past hour (real-time: breaking news or live events)
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "Apollo 11 moon landing mission overview",
      "max_results": 5,
      "search_recency_filter": "hour"
    }' | jq

  # Get content from the past day
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "history of the printing press",
      "max_results": 5,
      "search_recency_filter": "day"
    }' | jq

  # Get content from the past month
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "AI research developments",
      "max_results": 10,
      "search_recency_filter": "month"
    }' | jq
  ```
</CodeGroup>

<AccordionGroup>
  <Accordion title="Response — Apollo 11 moon landing mission overview">
    ```json theme={null}
    {
      "id": "1aebf3c7-ed3b-4e2c-9366-ce8ede12cec3",
      "results": [
        {
          "snippet": "",
          "title": "Apollo 11 - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/Apollo_11",
          "date": "2001-09-24",
          "last_updated": "2026-05-22"
        },
        {
          "snippet": "The primary objective of Apollo 11 was to complete a national goal set by President John F. Kennedy on May 25, 1961: perform a crewed lunar landing and return to Earth.\nAdditional flight objectives included scientific exploration by the lunar module, or LM, crew; deployment of a television camera to transmit signals to Earth; and deployment of a solar wind composition experiment, seismic experiment package and a Laser Ranging Retroreflector.\nDuring the exploration, the two astronauts were to gather samples of lunar-surface materials for return to Earth.\nThey also were to extensively photograph the lunar terrain, the deployed scientific equipment, the LM spacecraft, and each other, both with still and motion picture cameras.\nThis was to be the last Apollo mission to fly a “free-return” trajectory, which would enable a return to Earth with no engine firing, providing a ready abort of the mission at any time prior to lunar orbit insertion.\n...\nApollo 11 launched from Cape Kennedy on July 16, 1969, carrying Commander Neil Armstrong, Command Module Pilot Michael Collins and Lunar Module Pilot Edwin “Buzz” Aldrin into an initial Earth-orbit of 114 by 116 miles.\nAn estimated 650 million people watched Armstrong’s televised image and heard his voice describe the event as he took “…one small step for a man, one giant leap for mankind” on July 20, 1969.\nTwo hours, 44 minutes and one-and-a-half revolutions after launch, the S-IVB stage reignited for a second burn of five minutes, 48 seconds, placing Apollo 11 into a translunar orbit.\nThe command and service module, or CSM, Columbia separated from the stage, which included the spacecraft-lunar module adapter, or SLA, containing the lunar module, or LM, Eagle.\n...\nPartially piloted manually by Armstrong, the Eagle landed in the Sea of Tranquility in Site 2 at 0 degrees, 41 minutes, 15 seconds north latitude and 23 degrees, 26 minutes east longitude.\n...\nAfter a flight of 195 hours, 18 minutes, 35 seconds – about 36 minutes longer than planned – Apollo 11 splashed down in the Pacific Ocean, 13 miles from the recovery ship USS Hornet.\nBecause of bad weather in the target area, the landing point was changed by about 250 miles.\nApollo 11 landed 13 degrees, 19 minutes north latitude and 169 degrees, nine minutes west longitude July 24, 1969.\n**Crew**\nNeil Armstrong, Commander\nEdwin E.\n“Buzz” Aldrin Jr., Lunar Module Pilot\nMichael Collins, Command Module Pilot\n**Backup Crew**\nJames A. Lovell, Commander\nFred W. Haise Jr., Lunar Module Pilot\nWilliam A. Anders, Command Module Pilot\n**Payload**",
          "title": "Apollo 11 Mission Overview - NASA",
          "url": "https://www.nasa.gov/history/apollo-11-mission-overview/",
          "date": "2015-04-17",
          "last_updated": "2026-05-13"
        },
        {
          "snippet": "The primary objective of Apollo 11 was to complete a national goal set by President John F. Kennedy on May 25, 1961: perform a crewed lunar landing and return to Earth.\nMission Type\nLunar Landing\nastronauts\nNeil Armstrong, Buzz Aldrin, Michael Collins\nLaunch\nJuly 16, 1969\nSPLASHDOWN\nJuly 24, 1969\n...\n**First human to set foot on the Moon.**\nNeil A. Armstrong is probably best known as the commander for the Apollo 11 mission.\n...\nWatch highlights from the Apollo 11 mission including the launch on July 16, 1969, the landing of the lunar module, Neil Armstrong's first steps on the Moon, splashdown, and more.\n...\n20 July 1969—Astronaut Edwin E. Aldrin Jr., lunar module pilot, walks on the surface of the moon near the leg of the Lunar Module (LM) “Eagle” during the Apollo 11 extravehicular activity (EVA).\n...\nJOHNSON SPACE CENTER, HOUSTON, TEXAS – With a half-Earth in the background, the Lunar Module ascent stage with Moon-walking astronauts Neil Armstrong and Edwin Aldrin Jr. approaches for a rendezvous with the Apollo Command Module manned by Michael Collins.\nThe Apollo 11 liftoff from the Moon came early, ending a 22-hour stay on the Moon by Armstrong and Aldrin.\n...\nNeil Armstrong was the first person to walk on the moon.\nHe was an astronaut.\nHe flew on two space missions.\nOne was Apollo 11.\nThat mission landed on the moon.",
          "title": "Apollo 11 - NASA",
          "url": "https://www.nasa.gov/mission/apollo-11/",
          "date": "2023-03-08",
          "last_updated": "2026-05-15"
        },
        {
          "snippet": "Apollo 11, the first space mission to put people on the Moon, was launched on July 16, 1969.\nAlmost every major aspect of the flight of Apollo 11 was witnessed via television by hundreds of millions of people in nearly every part of the globe, until splashdown in the Pacific Ocean on July 24.\n...\nApollo 11’s mission objective was to land astronauts on the Moon and return them safely back to Earth.\nIt succeeded in its objective by landing Neil Armstrong and Buzz Aldrin on the Moon on July 20, 1969.\n...\nApollo 11’s crew members were commander Neil Armstrong, lunar module pilot Buzz Aldrin, and command module pilot Michael Collins.\n...\nThe lunar module *Eagle* of the Apollo 11 mission landed on the Moon on July 20, 1969.\nNeil Armstrong and Buzz Aldrin became the first people to land on the Moon and walk on the lunar surface.\n...\nThe fastest speed Apollo 11 achieved was 39,715 kilometers (24,678 miles) per hour when the command module reentered Earth’s atmosphere on July 24, 1969.\n**\n**Apollo 11**, U.S. spaceflight during which commander Neil Armstrong and lunar module pilot Edwin (“Buzz”) Aldrin, Jr., on July 20, 1969, became the first people to land on the Moon and walk the lunar surface.\nApollo 11 was the culmination of the Apollo program and a massive national commitment by the United States to beat the Soviet Union in putting people on the Moon.\nAll told, 24 Apollo astronauts visited the Moon and 12 of them walked on its surface.\nAdditional NASA astronauts are scheduled to return to the Moon by 2025 as part of the Artemis space program.\n...\nSplashdown of Apollo 11 occurred in the Pacific Ocean about 1,400 km (900 miles) west of Hawaii on July 24.",
          "title": "Apollo 11 | History, Mission, Landing, Astronauts ... - Britannica",
          "url": "https://www.britannica.com/topic/Apollo-11",
          "date": "2026-05-25",
          "last_updated": "2026-05-26"
        },
        {
          "snippet": "**On July 20, 1969, humans walked on the Moon for the first time.**\n**We look back at the legacy of our first small steps on the Moon and look forward to the next giant leap.**\n...\nThe Soviet Union launched the first human, Yuri Gagarin, into space on April 12, 1961.\nWithin days of the Soviet achievement, President John F. Kennedy asked Vice President Lyndon Johnson to identify a “space program which promises dramatic results in which we could win.”\nA little over a month later, on May 25, 1961, Kennedy stood before a joint session of Congress and called for human exploration to the Moon.\n...\nJuly 16, 1969\n## Liftoff!\nA Saturn V rocket carrying the three Apollo 11 astronauts blasted off from Cape Kennedy.\nOver a million spectators, including Vice President Spiro Agnew and former President Lyndon Johnson, came to watch the lift off.\nJuly 20, 1969\n## \"The Eagle has landed!\"\nAfter four days traveling to the Moon, the Lunar Module *Eagle*, carrying Neil Armstrong and Buzz Aldrin landed on the Moon.\nNeil Armstrong exited the spacecraft and became the first human to walk on the moon.\nAs an estimated 650 million people watched, Armstrong proclaimed \"That's one small step for man, one giant leap for mankind.\"\nMichael Collins stayed aboard the Command Module *Columbia*, serving as a communications link and photographing the lunar surface.\n...\n## The Sea of Tranquility | Mare Tranquillitatis\n**00.67408° N latitude, 23.47297° E longitude**\nFor the first lunar landing, the Sea of Tranquility (Mare Tranquilitatis) was the site chosen because it is a relatively smooth and level area.\nIt does, however, have some craters and in the last minutes before landing, Neil Armstrong had to manually pilot the lunar module to avoid a sharp-rimmed ray crater measuring some 180 meters across and 30 meters deep known as West.\nThe lunar module landed safely some 6 km from the originally intended landing site, approximately 400 meters west of West crater and 20km south-southwest of the crater Sabine D in the southwestern part of Mare Tranquilitatis.\nThe lunar surface at the landing site consisted of fragmental debris ranging in size from fine particles to blocks about 0.8 meter wide.\n...\nAfter approximately two and half hours on the Moon, Armstrong and Aldrin returned to the lunar module to begin the journey home.\nThe three astronauts splashed down in Hawaii on July 24, 1969.\nFrom there they quarantined for three weeks as a precaution against bringing contagion back from the Moon, before the festivities welcoming them home commenced.\n...\n## Buzz Aldrin\nLunar Module Pilot\n## Michael Collins\nCommand Module Pilot\n...\nThree astronauts were selected as backups for the crew: James A. Lovell, commander; William A. Anders, command module pilot; and Fred W. Haise, lunar module pilot.\nAll three backup crew members would eventually fly on Apollo missions.\n...\nOn July 20th, across the world, people gathered in front of televisions to watch the moon landing.\nAn estimated 650 million viewers were watching.\nIn the United States, 93% of televisions tuned in to see Neil Armstrong walk on the Moon.",
          "title": "Technology",
          "url": "https://airandspace.si.edu/explore/stories/apollo-11-moon-landing",
          "date": "2021-07-29",
          "last_updated": "2026-05-26"
        },
        {
          "snippet": "Apollo 11 was launched on July 16, 1969, at 8:32 AM Central Daylight Time (CDT) with the goal of performing the first human landing on the Moon.\nCommander Neil Armstrong, Command Module Pilot Michael Collins, and Lunar Module Pilot Edwin “Buzz” Aldrin entered lunar orbit on the afternoon of July 19.\nThe following day, Armstrong and Aldrin begin their descent to the lunar surface in the Lunar Module, Eagle.\nThe planned landing site in the Sea of Tranquility was selected as a flat, safe location and had been surveyed by Apollo 10 at an elevation of 10 miles above the Moon.\nHowever, a navigation error earlier in the mission caused Eagle to be about 7 kilometers beyond the planned landing location.\nDuring the 12.6-minute-long powered descent, there were a total of five unexpected computer alarms.\nThese alarms all indicated that Eagle’s computer system was overloaded, but in each case, Mission Control concluded that it was safe to continue the landing.\nThe last of these alarms occurred less than three minutes before landing, when the crew was less than 500 meters above the surface.\nBecause of the navigation error, the computer was guiding the spacecraft towards an unsafe touchdown point in the rugged, boulder-filled ejecta field surrounding West Crater.\nArmstrong took manual control and flew to a safe landing spot beyond the crater.\nAt 3:17 PM CDT, he announced their safe landing, “Houston, Tranquility Base.\nThe Eagle has landed.”\nAt the time of landing, Mission Control thought that the spacecraft had just 17 seconds of fuel left in the descent stage.\nHowever, post mission analysis showed that sloshing in the fuel tank during Armstrong’s search for a safe landing site caused the fuel gauge to give an inaccurate reading.\nEagle actually had about 45 seconds of fuel left when it touched down.\nAfter a checkout of Eagle’s systems, Armstrong and Aldrin prepared for their moonwalk.\nAt 9:56 PM CDT, Armstrong set foot on the lunar surface, “That’s one small step for man, one giant leap for mankind.”\nAldrin followed a short while later.\nThe duration of this first ever moonwalk was limited to just 2 hours and 31 minutes and the crew remained within 60 meters of Eagle.\nArmstrong and Aldrin collected 21.6 kilograms of samples and deployed a seismometer to measure moonquakes, a laser retroreflector to enable precise measurements of the distance between Earth and the Moon, and a device to collect a sample of the solar wind.\nThey also performed ceremonial duties, including setting up a United States flag, unveiling a commemorative plaque on the lunar module, and having a brief conversation with President Richard Nixon.\nDuring the moon landing, Collins remained in lunar orbit in the command module, Columbia.\nAfter just 21.6 hours on the Moon, Eagle’s ascent stage returned to lunar orbit and rejoined Columbia.\nAltogether, Apollo 11 spent 2.5 days in lunar orbit, circling the Moon 31 times.\nThe crew returned safely to Earth on July 24, landing in the Pacific Ocean southwest of Hawaii, after a flight of 8 days and 3 hours.\nAlthough scientists considered it unlikely that the Moon had life on it, the crew was kept in a biological quarantine for 21 days.\nPost-mission analysis showed that the Apollo 11 samples consisted of two primary rock types.\nBasalt is formed by the solidification of molten magma.\nThe Apollo 11 basalts formed 3.6 to 3.9 billion years ago and are unusually rich in the element titanium.\nBreccias are composed of fragments of other rocks.\nOn the Moon, breccias formed from rocks that are broken up by impacting objects.\nAnalysis of the lunar samples also confirmed that they were indeed lifeless and showed no evidence of water.",
          "title": "Lunar - Missions - Apollo 11 Mission",
          "url": "https://www.lpi.usra.edu/lunar/missions/apollo/apollo_11/",
          "date": null,
          "last_updated": "2025-07-28"
        },
        {
          "snippet": "Apollo 11 was the first mission to land humans on the Moon.\nIt fulfilled a 1961 goal set by President John F. Kennedy to send American astronauts to the surface and return them safely to Earth before the end of the decade.\nOn 21 July 1969 at 02:56:15 UTC, Neil Armstrong pressed his left foot onto the Moon and said, \"That's one small step for [a] man, one giant leap for mankind,\" as 530 million people watched live on television.\nThe mission returned 20 kilograms of rock and soil to Earth, and paved the way for 5 additional Moon landings that greatly advanced the field of lunar science.\nNeil Armstrong, Buzz Aldrin, and Michael Collins began their journey\nwith a launch aboard a Saturn V rocket on the morning of 16 July 1969.\nThree hours later, their rocket's upper stage blasted them out of Earth\norbit towards the Moon.\nThey arrived 3 days later on 19 July and entered\nan initial lunar orbit of 111 by 306 kilometers.\nA second engine burn\nlowered their orbit to 100 by 113 kilometers.\nOn 20 July, Armstrong and Aldrin boarded their lunar module, nicknamed Eagle, and undocked it from the command module, where Collins remained.\nAlmost the same as in the Apollo 10 rehearsal 2 months earlier, the astronauts fired Eagle’s descent engine, dropping to an orbit with a low point of 14.5 kilometers.\nRoughly an hour later, as the duo approached the Sea of Tranquility, they began a final powered descent to the surface.\n...\nThe official touchdown time was 20:17:39 UTC on 20 July 1969.\n...\nArmstrong and Aldrin's single moonwalk lasted two and a half hours.\nDuring that time, they deployed science and engineering experiments, photographed their surroundings, displayed an American flag, read an inscription plaque, collected rock and soil samples for return to Earth, and spoke with President Richard Nixon.\nThe astronauts verbally described their surroundings and progress for geologists, while cameras mounted inside and outside the lunar module documented some of their activities.\n...\nThe Apollo 11 lunar module landing coordinates are 0.67416 degrees N, 23.47314 E.",
          "title": "Apollo 11 | The Planetary Society",
          "url": "https://www.planetary.org/space-missions/apollo-11",
          "date": "2019-05-31",
          "last_updated": "2026-03-31"
        },
        {
          "snippet": "Apollo 11 (CSM Columbia and LM Eagle)\nSaturn V\nJuly 16-24, 1969\nNeil A. Armstrong\nMichael Collins\nEdwin E.\n\"Buzz\" Aldrin, Jr.\n08 days, 03 hours, 18 minutes\nFirst manned lunar landing mission and lunar\nsurface EVA.\n\"HOUSTON, TRANQUILITY BASE HERE.\nTHE EAGLE HAS LANDED.\"--July 20,\nLanding site: Sea of Tranquility.\nLanding Coordinates: 0.67409 degrees North, 23.47298 degrees East\n(Source: National Space Science Data Center); LROC QuickMap\n1 EVA of 02 hours, 31 minutes.\nFlag and instruments deployed; unveiled plaque on the LM descent stage with inscription: \"Here Men From Planet Earth First Set Foot Upon the Moon.\nJuly 1969 A.D.\nWe Came In Peace For All Mankind.\"\nLunar surface stay time 21.6 hours; 59.5 hours in lunar orbit, with 30 orbits.\nLM ascent stage left in lunar orbit.\n20 kg (44 lbs) of material gathered.",
          "title": "Apollo 11 Lunar Surface Journal : Mission Overview",
          "url": "https://www.nasa.gov/history/alsj/a11/a11ov.html",
          "date": null,
          "last_updated": "2025-10-25"
        },
        {
          "snippet": "",
          "title": "Apollo 11 Mission Overview | NASA+",
          "url": "https://plus.nasa.gov/video/apollo-11-mission-overview/",
          "date": "2024-07-12",
          "last_updated": "2026-05-17"
        },
        {
          "snippet": "Overview of the Apollo 11 spaceflight in which U.S. astronauts became the first people to walk on the Moon.\n...\nThe mission that took U.S. astronauts to the Moon was Apollo 11, NASA’s fifth crewed Apollo mission.\nThe astronauts on board the spacecraft were Neil Armstrong, Edwin (“Buzz”) Aldrin, Jr., and Michael Collins.\nOn the morning of July 20, Armstrong and Aldrin crawled from the command module, Columbia, through a tunnel to the lunar module, Eagle.\nArmstrong and Aldrin piloted Eagle to the lunar surface, touching down in the Sea of Tranquility.\nAt 4:17 PM U.S. Eastern Daylight Time (EDT), Armstrong radioed, “Houston, Tranquility Base here.\nThe Eagle has landed.”\nAt 10:56 PM EDT on July 20, Armstrong stepped out onto the lunar soil with the words, “That’s one small step for [a] man, one giant leap for mankind.”\n(In the excitement of the moment, Armstrong skipped the “a” in the statement that he had prepared.)\nArmstrong and Aldrin set up a device to measure the composition of the solar wind reaching the Moon, a device to receive laser beams from astronomical observatories on Earth to determine the exact distance of the two bodies from one each other, and a passive seismometer to measure moonquakes and meteor impacts.\nThey also took about 23 kg (50 pounds) of rock and soil samples, took many photographs, and maintained constant communication with mission control in Houston, Texas.\nAfter 21 hours 38 minutes on the Moon’s surface, the astronauts used Eagle’s ascent stage to launch it back into lunar orbit.\nSplashdown of Apollo 11 occurred in the Pacific Ocean about 1,400 km (900 miles) southwest of Hawaii on July 24.\nAfter their return, the astronauts were quarantined for 21 days from the time Eagle had left the Moon.\nThey were checked for any diseases they might have brought back from the Moon.",
          "title": "Apollo 11's Incredible Journey to the Moon | Britannica",
          "url": "https://www.britannica.com/video/Just-the-facts-Apollo-11-moon-landing/-246490",
          "date": "2023-12-06",
          "last_updated": "2025-08-25"
        }
      ],
      "server_time": null
    }
    ```
  </Accordion>

  <Accordion title="Response — history of the printing press">
    ```json theme={null}
    {
      "id": "23f6db05-6316-4a0f-af87-55873840f369",
      "results": [
        {
          "snippet": "",
          "title": "Printing press - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/Printing_press",
          "date": "2001-10-14",
          "last_updated": "2026-05-18"
        },
        {
          "snippet": "Printing presses push paper against inked movable type materials to transfer text and images from the type onto the paper.\nMedieval presses used a handle to turn a wooden screw that moved the platen on which the paper was mounted; the platen squeezed the paper against the type, which was locked in place in a frame, or form.\nMetal presses, developed late in the 18th century, used steam to drive a cylinder press.\nFlatbed presses, emerging early in the 19th century, used flat beds to hold the type and either a reciprocating platen or a cylinder to hold paper.\n...\nMovable type and paper were invented in China, and printing with movable type was undertaken in Korea by the 14th century, if not earlier.\nThe printing press first became mechanized in Europe.\nThe earliest mention of a printing press in Europe appears in a lawsuit in Strasbourg in 1439.\nIt reveals construction of a press for Johannes Gutenberg and his associates.\nThe earliest European printing presses owed much to the medieval paper press, which was in turn modeled after the ancient wine-and-olive press of the Mediterranean area.\n**printing press**, machine by which text and images are transferred from movable type to paper or other media by means of ink.\nMovable type and paper were invented in China, and the oldest known extant book printed from movable type was created in Korea in the 14th century.\nPrinting first became mechanized in Europe during the 15th century.\nThe earliest mention of a mechanized printing press in Europe appears in a lawsuit in Strasbourg in 1439; it reveals construction of a press for Johannes Gutenberg and his associates.\nGutenberg’s press and others of its era in Europe owed much to the medieval paper press, which was in turn modeled after the ancient wine-and-olive press of the Mediterranean area.\n...\nGutenberg used his press to print an edition of the Bible in 1455; this Bible is the first complete extant book in the West, and it is one of the earliest books printed from movable type.\n(*Jikji*, a book of the teachings of Buddhist priests, was printed by hand from movable type in Korea in 1377.)\nIn its essentials, the wooden press used by Gutenberg reigned supreme for more than 300 years, with a hardly varying rate of 250 sheets per hour printed on one side.\nMetal presses began to appear late in the 18th century, at about which time the advantages of the cylinder were first perceived and the application of steam power was considered.\nBy the mid-19th century Richard M. Hoe of New York had perfected a power-driven cylinder press in which a large central cylinder carrying the type successively printed on the paper of four impression cylinders, producing 8,000 sheets an hour in 2,000 revolutions.\nThe rotary press came to dominate the high-speed newspaper field, but the flatbed press, having a flat bed to hold the type and either a reciprocating platen or a cylinder to hold the paper, continued to be used for job printing.\nA significant innovation of the late 19th century was the offset press, in which the printing (blanket) cylinder runs continuously in one direction while paper is impressed against it by an impression cylinder.\nOffset printing is especially valuable for colour printing, because an offset press can print multiple colours in one run.\nOffset lithography—used for books, newspapers, magazines, business forms, and direct mail—continued to be the most widely used printing method at the start of the 21st century, though it was challenged by ink-jet, laser, and other printing methods.\n...\nApart from the introduction of electric power, advances in press design between 1900 and the 1950s consisted of a great number of relatively minor mechanical modifications designed to improve the speed of the operation.\nAmong these changes were better paper feed, improvements in plates and paper, automatic paper reels, and photoelectric control of colour register.\nThe introduction of computers in the 1950s revolutionized printing composition, with more and more steps in the print process being replaced by digital data.\nAt the end of the 20th century a new electronic printing method, print-on-demand, began to compete with offset printing, though it—and printing generally—came under increasing pressure in developed countries as publishers, newspapers, and others turned to online means of distributing what they had previously printed on paper.",
          "title": "Printing press | Invention, Definition, History, Gutenberg, & Facts",
          "url": "https://www.britannica.com/technology/printing-press",
          "date": "2026-04-28",
          "last_updated": "2026-05-20"
        },
        {
          "snippet": "The exact date of the first printing press invention is unknown, however, printed materials date as far back as 868 A.D.\nHere is a general timeline of the printing press invention.\nClick on each section to learn more.\n1. Block Printing: Pre 868 A.D.\n2. Moveable Type: Between 970 - 1051 A.D.\n3. Wood Type Updated: 1297\n4. The Gutenberg Press: 1450\n5. The Spread of Printing in Europe: 1465 - 1495\n6. Industrial Printing Press Invention: 1800 - 1843\n7. Modern Printing Processes: Offset and Digital Printing\n...\nEven though many people believe that the first printing press was invented by Johannes Gutenberg, people in China were actually using a process known as block printing to create printed text many centuries before the Gutenberg press.\nBlock printing involves using panels of wooden blocks that have been hand-carved in reverse.\nThe ink was then applied to these blocks and they were pressed onto paper to form the printed text.\nIt is unclear how long ago this process was developed (possibly as long ago as the 6th century), however, the oldest known printed book that used this method is called The Diamond Sutra, a Buddhist book from Dunhuang China dated 868 A.D.\nOther examples of block printing have also survived including:\n...\n- A calendar dating 877 A.D.\nBlock printing was also used during this time period in both Japan and Korea.\n...\nMoveable type replaced block printing around 970 A.D.\nThe first version of this type of printing involved carving individual letters into clay blocks and then baking them until they were hard.\nThese blocks were then arranged onto an iron frame which was pressed against an iron plate.\nThe great advantage of the moveable type was that you could re-use the letters for different texts.\nThis process was created by Bi Sheng who lived in Yingshan, Hubei, China from about 970 to 1051 A.D.\n...\nThe process of using wood type made a comeback in 1297 when a Chinese magistrate called Wang Zhen improved on the technique.\nHe developed a way of making the wood more precise and durable thus giving you a better-finished product.\nHe also created a type of revolving table that the typesetters were able to use to organize the type more efficiently.\nHis process greatly sped up the printing process.\nThe book Nung Shu was printed using this process and is considered to be the world's first mass-produced book.\n...\nJohannes Gutenberg started experimenting with printing while he was exiled from Germany in Strasbourg France in 1440.\nBy 1450, he had developed a printing machine that was ready to be used commercially.\nGutenberg's printing press used metal pieces instead of wood.\nEach letter was made to uniformly fit together so that the resulting print would be in perfectly straight lines and columns.\nHe also created a special ink that would stick to metal.\nIn addition, he figured out a way to flatten the printing paper to give a better finished product by using a winepress that had previously been used to press grapes and olives.\nGutenberg used his printing press invention to print the famous Gutenberg Bible.\nHe made about 180 copies of the Bible each containing 1.300 pages.\n...\nThe invention of the Gutenberg press meant that books could finally be mass-produced and at a fraction of the cost of previous printing methods.\nThe printing press invention is credited with contributing to the growth of literacy, education, and the availability of uniform information for the common person.\n...\nMany workers who had helped Gutenberg perfect his printing process became printers themselves in Germany.\nThe printing press was later brought to Italy in 1465 and in 1470, German printers were asked to set up printing presses in Sorbonne Paris.\nSpain and Portugal invited German printers to set up in their countries in 1473 and 1495 respectively.\nFinally, the printing press was brought to England in 1476 by William Caxton.\nCaxton was an Englishman who had gone to cologne to learn how to print in 1471.\n...\nEven though the essential workings of the Gutenberg press remained intact, the invention of mechanical printing presses made the printing process much more efficient.\nIn 1800, Lord Stanhope built a press that was completely made of cast iron, with double the printed area, and that was able to produce 480 pages per hour thus doubling the production of the previous presses.\nThe steam-powered rotary printing press, which Richard M. Hoe invented in the United States in 1843 made the printing process even faster, producing millions of copies of a page in one day.",
          "title": "Digital Printing",
          "url": "https://jhfrench.com/blog/the-printing-press-invention-history-important-dates-amp-facts",
          "date": "2022-03-02",
          "last_updated": "2026-05-19"
        },
        {
          "snippet": "In 1436 Johaness Gutenberg, a German goldsmith, began designing a machine capable of producing pages of text at an incredible speed—a product that he hoped would offset losses from a failed attempt to sell metal mirrors.\nBy 1440 Gutenberg had established the basics of his printing press including the use of a mobile, reusable set of type, and within ten years he had constructed a working prototype of the press.\nIn 1454 Gutenberg put his press to commercial use, producing thousands of indulgences for the Church.\nThe following year he printed his famous 42-line Bible, the first book printed on a moveable type press in the West.\n1\nGutenberg's press was the combined effort of several discoveries and inventions.\nThe printing press was built around the traditional screw press, a precursor to today's drill press, with an added matrix on which individually-cast letters and symbols could be arranged to form the desired text.\nThis moveable type design allowed pages of text to be quickly assembled from a pre-cast selection of letters and symbols rather than laboriously carved from a block of wood as in the\n*block printing method*.\nGutenberg also created a unique oil-based ink which transferred from his metal type to the printing substrate much more effectively than the water-based inks that other printers of the era used.\nIn order to print a page, Gutenberg would arrange the necessary letters on the matrix and coat them in his ink.\nThe matrix was then mounted on the contact end of the modified screw press and lowered until it struck the paper underneath.\nThe process, while labor intensive, allowed Gutenberg to print pages at a much greater rate than printers using the block printing method or those doing manuscript work.\n...\nJohannes Gutenberg's moveable type press marked the beginning of the Printing Revolution in the western world, a colossal moment in the history of information and learning.\nWith access to printing presses, scientists, philosophers, politicians, and religious officials could replicate their ideas quickly and make them available to large audiences.",
          "title": "The Gutenberg Press",
          "url": "https://scarc.library.oregonstate.edu/omeka/exhibits/show/mcdonald/incunabula/gutenberg/",
          "date": null,
          "last_updated": "2025-05-09"
        },
        {
          "snippet": "",
          "title": "History of printing - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/History_of_printing",
          "date": "2007-05-02",
          "last_updated": "2026-05-13"
        },
        {
          "snippet": "",
          "title": "A Short History of The Printing Press, by Robert Hoe—A Project ...",
          "url": "https://www.gutenberg.org/files/63545/63545-h/63545-h.htm",
          "date": null,
          "last_updated": "2026-03-21"
        },
        {
          "snippet": "",
          "title": "Printing - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/Printing",
          "date": "2002-03-17",
          "last_updated": "2026-03-30"
        },
        {
          "snippet": "",
          "title": "Gutenberg, Printing Press, Revolution | Britannica",
          "url": "https://www.britannica.com/topic/printing-publishing/The-Gutenberg-press",
          "date": "2025-09-05",
          "last_updated": "2025-10-15"
        },
        {
          "snippet": "The 15th century is a particularly interesting period in our history.\nIt is the last century of the Middle Ages and the Dark Ages, and at the same time, the bridge between the Late Middle Ages, the Early Renaissance, and the Modern Age.\nIt is also known as \"The Century of Innovations.\"\nOne of the most important innovations, and one that marked a milestone in human history, was undoubtedly the invention of the printing press.\nAt that time, reading was reserved for a select few, primarily the clergy and nobility.\nIt is estimated that only about 12% of the European population could read.\nThe few books that existed, produced by hand and copied by hand, were kept mainly in monasteries.\nThe church was the main source of information, transmitted orally.\nThe arrival of the printing press would revolutionize the world.\nSuddenly, people had access to a vast amount of information, which also gave rise to critical thinking.\nThis was not welcomed by those who, throughout history, have sought to control information and thought.\nAlthough the first printed book was a Bible, as early as 1559, Pope Paul IV established an Index Librorum Prohibitorum, a list of all books prohibited to Catholics.\nSince then, the Church and various governments have censored, banned, and burned thousands of books.\n...\nThe person responsible for this information revolution in the 15th Century was the son of a patrician from the city of Mainz, Germany.\nHis name was Johann Gensfleisch zur Laden zum Gutenberg, better known as Johannes Gutenberg.\nSome of the elements of his invention were movable type, an oil ink that soaked into metal and then transferred easily to paper, as well as a new printing press, probably adapted from those used for winemaking.\nLike every endeavor, Gutenberg’s was not without financial problems.\nA wealthy financier, Johann Fust, invested in his project, but later won a lawsuit against Gutenberg, which allowed him to use the invention as his own, continuing to produce Bibles and Gutenberg’s second masterpiece, a psalter.\nIn 1465, the Archbishop of Mainz granted Gutenberg a pension, granting him an annual ration of grain, wine, and clothing.\nShortly thereafter, in 1468, Gutenberg died in his native Mainz.\nThe establishment of the printing press in Mexico, the first in the Americas, is also an interesting story.\nJuan Cromberger, a German printer established in Seville and owner of a prestigious publishing house with capital to establish a branch in the New Spain, entrusted Juan Pablos, whom he trusted as a copyist or typesetter, to found a printing press in the New World.\nJuan Pablos, of Italian origin and whose name, Giovanni Paoli, we know now in Spanish, arrived in Mexico City with his wife Gerónima Gutiérrez, between September and October 1539.\nWith the support of his sponsors, Juan Pablos established the “House of Juan Cromberger” workshop in the “Casa de las Campanas”, Bishop Zumárraga’s house, located on the southwest corner of Moneda and Santa Teresa la Antigua streets, now known as Licenciado Verdad, across the street from the former archbishopric.\nThe workshop opened its doors around April 1540.\nThe world has evolved at an immense speed since the 15th and 16th centuries.\nToday, nearly 4 million book titles are produced annually worldwide.",
          "title": "The history of the printing press - International Publishers Association",
          "url": "https://internationalpublishers.org/the-history-of-the-printing-press/",
          "date": "2025-05-12",
          "last_updated": "2026-03-27"
        },
        {
          "snippet": "The printing press has always been a marvel of human invention, and the printing of newspapers occupies a unique course in the history of printing machines.\nAs demands grew for more pages, more news, and faster delivery, newspapers had to achieve greater speeds and higher efficiency.\nNewspapers started on Gutenberg presses – individual type pieces arranged backwards by hand, secured in a flat bed, inked by hand, and a great leverage force applied to create the impression.\nThe machine did one part of the job, and newspapers were often printed once a week as one, large, single-sided page called a broadside.\nThe force required to get a good image was considerable, the wood that made up the printing press would crack or break over time, and the metal type would wear down.\nFrom the 1440s, the mechanics of the printing press were practically unchanged for 300 years!\nThe first improvements to the press were to replace some of the wooden parts with iron and improve the lever used to press the paper to type.\nThe first printing press made entirely out of iron appeared around 1800 in England and is attributed to Charles Mahon, the third Earl of Stanhope.\nThe power and durability of the Stanhope press allowed printers to get 200 pulls per hour – each ‘pull’ being a pressed side of a paper.\n200 pulls would be 100 issues of a double-sided broadsheet.\nThe Columbian press by George Clymer was the first entirely metal press in the United States, emerging in the 1810s.\nWhile other iron presses emerged in a variety of sizes, these two were the first big names in successful manufacturing companies.\nOne of the biggest jumps in newspaper press development at this time was from the flat-bed hand press (like the Columbian) to the rotary press – a machine run by steam, horses, or manpower that incorporated rotating cylinders in the printing process that skyrocketed production speeds.\nWhile methods of printing with cylinders can be found as far back as 1616, it wasn’t until the 1810s that a practical method was manufactured.\nFrederick Koenig and Andreas Bauer, German immigrants in England, patented a machine that obtained an impression not by pressing but by rolling paper attached to a cylinder over the bed of type.\nMade first for the London Times’ November 29, 1814 issue, this steam powered press could produce 1,100 sheets per hour.\nThe more cylinders the press had, the more pages it could print at once.\nIt even had a cylinder to automatically roll ink onto the type, but it still only printed single sided sheets which were fed into and taken off of the machine by hand.\n...\nCarried on by his son Richard in the 1840s, R.\nHoe developed the type-revolving printing presses nicknamed “lightning presses.”\nInstead of paper on a cylinder, the type pieces were wedge-shaped in order to be secured tightly into the surface of a cylinder and rolled onto paper.\n...\nThe 1860s saw American press factories develop two major improvements for printing newspapers: the stereotype plates and the paper web.\nThe stereotype is a thin piece of metal that has been cast from a mold of the composed type.\nThe thin metal is curved to fit around a rotating cylinder in the printing press, thus eliminating type from the actual printing process for the first time.\nThe stereotype process was developed over the course of the 1840s but did not enter the printing scene at-large until the 1860s.\nThe stereos, as they were called, would remain an integral piece in the printing process until the 1970s.\n...\nIn 1865, William Bullock of Philadelphia collaborated with papermakers to design a web – a continuous roll of paper – to run through his rotary presses and be cut to size in the printing process.\nHis rotary press also set the new standard for “perfecting” the paper – printing on both sides of the page.\nBullock’s early rotary press could get 8,000 – 10,000 copies per hour according to the New-York Tribune.\n...\nThe final touch was mechanized folding of the finished newspaper.\nEnglishman George Ashley Wilson is credited with designing the Victory printing and folding machine combined.\nOther companies like R.\nHoe created separate machines that could be hand-fed finished sheets or attached to the end of one of their existing presses.\nFolding would go on to become a standard function of large presses.\nBy the 1880s, newspaper presses achieved their highest speeds yet.\nCountless individual inventions followed by small adjustments, innovations, and tricks fill printing history, but these “headliners” would consistently be the standard for almost one hundred more years of newspaper printing.",
          "title": "Printing Newspapers: 1400-1900",
          "url": "https://blogs.loc.gov/headlinesandheroes/2022/04/printing-newspapers-1400-1900/",
          "date": "2022-04-21",
          "last_updated": "2026-03-11"
        }
      ],
      "server_time": null
    }
    ```
  </Accordion>

  <Accordion title="Response — AI research developments">
    ```json theme={null}
    {
      "id": "4942a8e3-b0e6-40cc-8e86-ab60e6e4567c",
      "results": [
        {
          "snippet": "# Our latest research breakthroughs\n### Gemini for Science: AI experiments and tools for a new era of discovery\nGoogle Labs\nGoogle DeepMind\nGoogle Research\n### Empirical Research Assistance (ERA): From Nature publication to catalyzing Computational Discovery\nGoogle Research\n### Co-Scientist: A multi-agent AI partner to accelerate research\nGoogle DeepMind\nGoogle Cloud\nGoogle Labs\nGoogle Research\n### Gemini Robotics ER 1.6: Powering real-world robotics tasks through enhanced embodied reasoning\nGoogle DeepMind\n### From games to biology and beyond: 10 years of AlphaGo’s impact\nGoogle DeepMind\n### How AI can improve breast cancer detection in the UK\nGoogle Research\n### How we’re helping preserve the genetic information of endangered species with AI\nGoogle Research\n### WeatherNext 2: Our most advanced weather forecasting model\nGoogle DeepMind\nGoogle Research\n### SIMA 2: An agent that plays, reasons, and learns with you in virtual 3D worlds\nGoogle DeepMind\n### Quantum Echoes algorithm is a big step toward practical applications for quantum computing\nGoogle Research\n### How a Gemma model helped discover a new potential cancer therapy pathway\nGoogle DeepMind\nGoogle Research\n### DeepSomatic: Using AI to identify genetic variants in tumors\nGoogle Research\n### Teaching Gemini to spot exploding stars with just a few examples\nGoogle Research\n### Coral NPU: A full-stack platform for Edge AI\nGoogle Research\n### Using AI to perceive the universe in greater depth\nGoogle DeepMind\n### Genie 3: A general purpose world model that can generate a diversity of interactive environments\nGoogle DeepMind\n### Advanced version of Gemini with Deep Think officially achieves gold-medal standard at the International Mathematical Olympiad\nGoogle DeepMind\n### FireSat: First images of wildfires detected by the new satellite constellation\nGoogle Research\n### SensorLM: Learning the language of wearable sensors\nGoogle Research\n### Aeneas transforms how historians connect the past\nGoogle DeepMind\n### ZAPBench: One of the most ambitious datasets in brain activity research\nGoogle Research\n### AlphaProteo: Generate novel proteins for health research\nGoogle DeepMind\n### AlphaFold: Accelerating breakthroughs in biology with AI\nGoogle DeepMind\nSee more research from across Google",
          "title": "Breakthrough AI research - Google AI",
          "url": "https://ai.google/research/",
          "date": null,
          "last_updated": "2026-05-20"
        },
        {
          "snippet": "",
          "title": "The future of AI: trends shaping the next 10 years - IBM",
          "url": "https://www.ibm.com/think/insights/artificial-intelligence-future",
          "date": "2024-10-11",
          "last_updated": "2026-05-03"
        },
        {
          "snippet": "",
          "title": "AI Research Trends",
          "url": "https://ai100.stanford.edu/2016-report/section-i-what-artificial-intelligence/ai-research-trends",
          "date": null,
          "last_updated": "2026-04-28"
        },
        {
          "snippet": "",
          "title": "Agentic AI News + AI Breakthroughs + AI Developments | 2026",
          "url": "https://www.crescendo.ai/news/latest-ai-news-and-updates",
          "date": "2026-05-18",
          "last_updated": "2026-05-20"
        },
        {
          "snippet": "# Pioneering research on the path to AGI\nWe believe our research will eventually lead to artificial general intelligence, a system that can solve human-level problems.\nBuilding safe and beneficial AGI is our mission.\n...\n### We use Deep Learning to leverage large amounts of data and advanced reasoning to train AI systems for task completion.\n...\nOpenAI’s GPT series models are fast, versatile, and cost-efficient AI systems designed to understand context, generate content, and reason across text, images, and more.\n...\nOpenAI’s o series models are advanced reasoning AI systems that use chain-of-thought processes to solve complex STEM problems through logical, step-by-step analysis.\n...\nOur text models are advanced language processing tools that can generate, classify, and summarize text with high levels of coherence and accuracy.\n...\nOur research on generative modeling for images has led to representation models like CLIP, which makes a map between text and images that an AI can read, and DALL-E, a tool for creating vivid images from text descriptions.\n...\n### Audio\nOur research on applying AI to audio processing and audio generation has led to developments in automatic speech recognition and original musical compositions.\n...\n> “Safely aligning powerful AI systems is one of the most important unsolved problems for our mission.\nTechniques like learning from human feedback are helping us get closer, and we are actively researching new techniques to help us fill the gaps.”\n...\nView research index",
          "title": "Research - OpenAI",
          "url": "https://openai.com/research/",
          "date": "2025-08-07",
          "last_updated": "2026-03-29"
        },
        {
          "snippet": "",
          "title": "Artificial Intelligence News",
          "url": "https://www.sciencedaily.com/news/computers_math/artificial_intelligence/",
          "date": "2026-05-21",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "*The Artificial Intelligence R&D (AI R&D) Interagency Working Group (IWG) coordinates Federal AI R&D and supports activities tasked by both the NSTC Select Committee on AI and the Subcommittee on Machine Learning and Artificial Intelligence.\nThis vital work promotes U.S. leadership and global competitiveness in AI R&D and its applications.\nThe AI IWG reports investments to the AI R&D Program Component Area.*\n...\nThe Artificial Intelligence R&D Interagency Working Group (AI R&D IWG) was formed in 2018 to coordinate Federal AI R&D across 32 participating agencies and to support activities tasked by both the NSTC Select Committee on AI and the Subcommittee on Machine Learning and Artificial Intelligence (MLAI).\nThrough the NITRD Subcommittee, the AI IWG will coordinate AI activities to advance the mission of the National AI Initiative Office (NAIIO).\n...\nThis dashboard illustrates the Federal budget for nondefense AI R&D investments across several fiscal years.\nIt provides both an overall budget rollup, as well as breakdowns of investments by agency and by NITRD Program Component Areas (PCAs), major subject areas for Federal IT R&D.\n*Learn more about Federal Agencies investments in AI R&D which shows sustained investments in key priority R&D areas*: AI R&D Federal Investments Dashboard.\n...\nThe National AI Initiative Office was established in January 2021 to oversee and implement the National AI Initiative Act (NAIIA).\nThe NAIIO along with the NITRD Subcommittee directs the NITRD AI R&D IWG to coordinate Federal R&D investment in AI.",
          "title": "Artificial Intelligence Research and Development - NITRD",
          "url": "https://www.nitrd.gov/coordination-areas/ai/",
          "date": "2025-12-08",
          "last_updated": "2026-05-17"
        },
        {
          "snippet": "Artificial Intelligence has leapt to the forefront of global discourse, garnering increased attention from practitioners, industry leaders, policymakers, and the general public.\nThe diversity of opinions and debates gathered from news articles this year illustrates just how broadly AI is being investigated, studied, and applied.\nHowever, the field of AI is still evolving rapidly and even experts have a hard time understanding and tracking progress across the field.\n...\nThis chapter explores trends in AI research and development, beginning with an analysis of AI publications, patents, and notable AI systems.\nThe Technical Performance section of this year’s AI Index provides a comprehensive overview of AI advancements in 2024.\nArtificial intelligence is now deeply integrated into nearly every aspect of our lives.\nIt is reshaping sectors like education, finance, and healthcare, where algorithm-driven insights guide critical decisions.\n...\nAI’s advancing capabilities have captured policymakers’ attention, leading to an increase in AI-related policies worldwide.\nAI has entered the public consciousness through generative AI’s impact on work...\nAs AI continues to permeate broad swaths of society, it is becoming increasingly important to understand public sentiment around the technology.\n...\nIn 2023, researchers introduced new benchmarks—MMMU, GPQA, and SWE-bench—to test the limits of advanced AI systems.\nJust a year later, performance sharply increased: scores rose by 18.8, 48.9, and 67.3 percentage points on MMMU, GPQA, and SWE-bench, respectively.\nBeyond benchmarks, AI systems made major strides in generating high-quality video, and in some settings, language model agents even outperformed humans in programming tasks with limited time budgets.\nFrom healthcare to transportation, AI is rapidly moving from the lab to daily life.\nIn 2023, the FDA approved 223 AI-enabled medical devices, up from just six in 2015.\nOn the roads, self-driving cars are no longer experimental: Waymo, one of the largest U.S. operators, provides over 150,000 autonomous rides each week, while Baidu’s affordable Apollo Go robotaxi fleet now serves numerous cities across China.\nIn 2024, U.S. private AI investment grew to $109.1 billion—nearly 12 times China’s $9.3 billion and 24 times the U.K.’s $4.5 billion.\nGenerative AI saw particularly strong momentum, attracting $33.9 billion globally in private investment—an 18.7% increase from 2023.\nAI business usage is also accelerating: 78% of organizations reported using AI in 2024, up from 55% the year before.\nMeanwhile, a growing body of research confirms that AI boosts productivity and, in most cases, helps narrow skill gaps across the workforce.\nIn 2024, U.S.-based institutions produced 40 notable AI models, significantly outpacing China’s 15 and Europe’s three.\nWhile the U.S. maintains its lead in quantity, Chinese models have rapidly closed the quality gap: performance differences on major benchmarks such as MMLU and HumanEval shrank from double digits in 2023 to near parity in 2024.\nMeanwhile, China continues to lead in AI publications and patents.\nAt the same time, model development is increasingly global, with notable launches from regions such as the Middle East, Latin America, and Southeast Asia.\nAI-related incidents are rising sharply, yet standardized RAI evaluations remain rare among major industrial model developers.\nHowever, new benchmarks like HELM Safety, AIR-Bench, and FACTS offer promising tools for assessing factuality and safety.\nAmong companies, a gap persists between recognizing RAI risks and taking meaningful action.\nIn contrast, governments are showing increased urgency: In 2024, global cooperation on AI governance intensified, with organizations including the OECD, EU, U.N., and African Union releasing frameworks focused on transparency, trustworthiness, and other core responsible AI principles.\nIn countries like China (83%), Indonesia (80%), and Thailand (77%), strong majorities see AI products and services as more beneficial than harmful.\nIn contrast, optimism remains far lower in places like Canada (40%), the United States (39%), and the Netherlands (36%).\nStill, sentiment is shifting: since 2022, optimism has grown significantly in several previously skeptical countries—including Germany (+10%), France (+10%), Canada (+8%), Great Britain (+8%), and the United States (+4%).\nDriven by increasingly capable small models, the inference cost for a system performing at the level of GPT-3.5 dropped over 280-fold between November 2022 and October 2024.\nAt the hardware level, costs have declined by 30% annually, while energy efficiency has improved by 40% each year.\nOpen-weight models are also closing the gap with closed models, reducing the performance difference from 8% to just 1.7% on some benchmarks in a single year.\nTogether, these trends are rapidly lowering the barriers to advanced AI.\nIn 2024, U.S. federal agencies introduced 59 AI-related regulations—more than double the number in 2023—and issued by twice as many agencies.\nGlobally, legislative mentions of AI rose 21.3% across 75 countries since 2023, marking a ninefold increase since 2016.\nAlongside growing attention, governments are investing at scale: Canada pledged $2.4 billion, China launched a $47.5 billion semiconductor fund, France committed €109 billion, India pledged $1.25 billion, and Saudi Arabia’s Project Transcendence represents a $100 billion initiative.\nTwo-thirds of countries now offer or plan to offer K–12 CS education—twice as many as in 2019—with Africa and Latin America making the most progress.\nIn the U.S., the number of graduates with bachelor’s degrees in computing has increased 22% over the last 10 years.\nYet access remains limited in many African countries due to basic infrastructure gaps like electricity.\nIn the U.S., 81% of K–12 CS teachers say AI should be part of foundational CS education, but less than half feel equipped to teach it.\nNearly 90% of notable AI models in 2024 came from industry, up from 60% in 2023, while academia remains the top source of highly cited research.\nModel scale continues to grow rapidly—training compute doubles every five months, datasets every eight, and power use annually.\nYet performance gaps are shrinking: the score difference between the top and 10th-ranked models fell from 11.9% to 5.4% in a year, and the top two are now separated by just 0.7%.\nThe frontier is increasingly competitive—and increasingly crowded.\nAI’s growing importance is reflected in major scientific awards: two Nobel Prizes recognized work that led to deep learning (physics), and to its application to protein folding (chemistry), while the Turing Award honored groundbreaking contributions to reinforcement learning.\nAI models excel at tasks like International Mathematical Olympiad problems but still struggle with complex reasoning benchmarks like PlanBench.\nThey often fail to reliably solve logic tasks even when provably correct solutions exist, limiting their effectiveness in high-stakes settings where precision is critical.",
          "title": "The 2025 AI Index Report | Stanford HAI",
          "url": "https://hai.stanford.edu/ai-index/2025-ai-index-report",
          "date": "2024-09-10",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "### Building AI models that understand chemical principles\nConnor Coley works at the interface of chemistry and machine learning, to discover and design new drug compounds.\n...\n### Justin Solomon appointed associate dean of engineering education\nMIT faculty member in electrical engineering and computer science to focus on innovation in engineering education and new pedagogical approaches.\n...\n### Two from MIT named 2026 Knight-Hennessy Scholars\nThe prestigious fellowship funds graduate studies at Stanford University.\n...\n### Q&A: Expanding MIT’s global reach through Universal Learning\nDimitris Bertsimas and Megan Mitchell discuss the motivation behind Universal Learning, and what sets the new MIT Open Learning educational initiative apart.\n...\n### Universal AI is “a pathway to AI fluency that’s accessible and approachable to anyone, anywhere”\nNew AI education program from MIT Open Learning debuts with AI-powered personalization and a free introductory course for learners everywhere.\n...\n### Study: Firms often use automation to control certain workers’ wages\nMIT economists found US companies tend to target employees earning a “wage premium,” which increases inequality but not necessarily productivity.\n...\n### Games people — and machines — play: Untangling strategic reasoning to advance AI\nAssistant Professor Gabriele Farina mines the foundations of decision-making in complex multi-agent scenarios.\n...\n### Beacon Biosignals is mapping the brain during sleep\nFounded by Jake Donoghue PhD ’19 and former MIT researcher Jarrett Revels, the company is creating an AI-driven platform to help diagnose and treat disease.\n...\nMIT senior Olivia Honeycutt investigates how the ways we communicate can shape our views of the world.\n...\nPresident Sally Kornbluth spoke in front of a packed crowd about growing challenges to the U.S. research ecosystem as funding for America’s top research universities becomes increasingly strained.\n...\n### Solving the “Whac-a-mole dilemma”: A smarter way to debias AI vision models\nA new debiasing technique called WRING avoids creating or amplifying biases that can occur with existing debiasing approaches.\n...\n### The MIT-IBM Computing Research Lab launches to shape the future of AI and quantum computing\nBuilding on a long-standing MIT–IBM collaboration, the new lab will chart the convergence of AI, algorithms, and quantum computing.\n...\n### Enabling privacy-preserving AI training on everyday devices\nA new method could bring more accurate and efficient AI models to high-stakes applications like health care and finance, even in under-resourced settings.\n...\n### A faster way to estimate AI power consumption\nThe “EnergAIzer” method generates reliable results in seconds, enabling data center operators to efficiently allocate resources and reduce wasted energy.\n...\n### MIT scientists build the world’s largest collection of Olympiad-level math problems, and open it to everyone\nNew dataset of 30,000-plus competition math problems from 47 countries gives AI researchers a harder test — and students worldwide a better training ground.",
          "title": "Artificial intelligence | MIT News | Massachusetts Institute of ...",
          "url": "https://news.mit.edu/topic/artificial-intelligence2",
          "date": "2026-05-20",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "The rise of artificial intelligence has already transformed every facet of our lives at a remarkable speed.\nAt UC San Diego, AI is empowering bold advances in science, education, public safety, health and the arts.\n...\nFrom uncovering hidden disease mechanisms to guiding new therapies and medical technologies, UC San Diego researchers are harnessing AI to propel humanity toward a future in which diseases are mitigated or eradicated.\nWhat was once science fiction is now possible.\nAs a tool, AI speeds diagnoses, offers a better understanding of the human body and enables more innovative treatments.\n...\nA gene once thought to be just a biomarker for Alzheimer’s disease is actually one of its causes, according to the work of UC San Diego bioengineers.\nUsing AI to model the 3D structures of proteins, the team discovered that the gene PHGDH has a hidden “moonlighting” role: It disrupts how brain cells switch genes on and off, a disturbance that can fuel the disease.\n...\nJoe Pogliano, professor, and Kit Pogliano, dean and distinguished professor, both in the School of Biological Sciences, worked with Linnaeus Bioscience and Seattle Children’s Research Institute to develop MycoBCP, a new AI-powered tool that could accelerate the search for TB treatments.\n...\nBy pairing that method with deep learning, researchers could detect subtle changes in TB cells that would otherwise escape the human eye — revealing how potential drugs act on the pathogen.\n...\nBy recording signals from outside of heart muscle cells and using AI to reconstruct what’s happening inside these cells, engineers were able to monitor heart activity with remarkable accuracy — without invasive methods or physically penetrating the cells.\nThe breakthrough offers safer, faster insights into how heart cells function, communicate and respond to new drugs.\n...\nResearchers have developed advanced deep-learning techniques that could revolutionize treatment planning for breast cancer radiotherapy — making it faster and improving its quality.\nThe approach reduced errors in radiation doses to critical organs, such as the heart and lungs.\n...\nUC San Diego engineers have created a flexible patch — a wireless, skin-mounted ultrasound device — that monitors muscle activity in real time to control a robotic arm, among other uses.\nTo extract additional insights from these muscle signals, the researchers developed an AI algorithm that maps the signals to their corresponding muscle distributions.\nCompact, battery-powered and designed for long-term wear, the technology could open new possibilities in health care monitoring and human-machine interaction.\n...\nIn a unique and long-standing collaboration, UC San Diego electrical engineering graduate students have been embedded with the Jacobs Retina Center at Shiley Eye Institute to develop better computer vision, AI and image-processing tools.\nThese will help physicians diagnose patients with greater speed and accuracy, predict the most effective treatments, and aid in the development of new treatments.\n...\nUC San Diego researchers are using AI to better understand Earth’s changing environment.\nThese innovations provide faster forecasts, actionable insights and tools that help protect communities and the planet.\n...\nResearchers at UC San Diego and the Allen Institute for AI have developed a new model, Spherical DYffusion, that projects 100 years of climate patterns in just 25 hours.\nBy combining generative AI techniques with physics-based data, the model delivers results 25 times faster than current methods without the need for massive supercomputers.\nThe breakthrough could provide scientists and policymakers with faster and more flexible tools for anticipating the long-term effects of climate change.\n...\nWith a growing network of more than 1,200 natural-hazard monitoring cameras spanning remote mountaintops to wildland-urban interfaces, ALERTCalifornia collects real-time data and utilizes AI that helps emergency managers spot smoke, monitor fires and plan evacuations.\nUC San Diego’s WIFIRE team at the San Diego Supercomputer Center utilizes those camera and sensor feeds to pinpoint wildfire ignition locations and create predictive models that map how a fire will spread.\n...\nThese models are further refined by AI-powered aerial sensing — including infrared imaging — to track fire perimeters through thick smoke and give responders a strategic advantage as wildfires progress.",
          "title": "Nine Breakthroughs Made Possible by AI - UC San Diego Today",
          "url": "https://today.ucsd.edu/story/nine-breakthroughs-made-possible-by-ai",
          "date": "2025-11-21",
          "last_updated": "2026-05-20"
        }
      ],
      "server_time": null
    }
    ```
  </Accordion>

  <Accordion title="Response — major technology trends">
    ```json theme={null}
    {
      "id": "b21a4380-b32c-418a-ba52-960c9fc3f15b",
      "results": [
        {
          "snippet": "## As technology innovation and adoption accelerate, five trends reveal how successful organizations are moving from experimentation to impact\nArticle\n...\nThe question used to be “What can we do with AI?”\nNow it’s “How do we move from experimentation to impact?”\n...\nFor 17 years, Tech Trends has explored emerging technologies poised to reshape business in the next 18 to 24 months.\nOur research is based on trend sensing from conversations with Deloitte subject matter experts and external technology leaders, as well as Deloitte’s proprietary research on emerging technologies.\nThis year, the data reveals five interconnected forces.\n## AI goes physical: Navigating the convergence of AI and roboticstiAmazon deployed its millionth robot, and its DeepFleet AI coordinates the entire robot fleet, improving travel efficiency within warehouses by 10%.^5^ BMW’s factories have cars driving themselves through kilometer-long production routes.^6^ Intelligence isn’t confined to screens anymore; it’s embodied, autonomous, and solving real problems in the physical world.\n## The agentic reality check: Preparing for a silicon-based workforceorOnly 11% of organizations have agents in production, despite 38% piloting them.\nThe gap between pilot to production tells you everything.\nForty-two percent are still developing their strategy, while 35% have no strategy at all.^7^ Gartner predicts that 40% of agentic projects will fail by 2027^8^—not because the technology doesn’t work, but because organizations are automating broken processes instead of redesigning operations.\nHPE’s chief financial officer captured what works: “We wanted to select an end-to-end process where we could truly transform, not just solve for a single pain point.”^9^ Redesign, don’t automate.\nThat’s the pattern separating success from failure.\n## The AI infrastructure reckoning: Optimizing compute strategy in the age of inference economicsmiToken costs have dropped 280-fold in two years;^10^ yet some enterprises are seeing monthly bills in the tens of millions.\nUsage exploded faster than costs declined.\nOrganizations are discovering their existing infrastructure strategies aren't designed to scale AI to production-scale deployment.\nThey're shifting from cloud-first to strategic hybrid: cloud for elasticity, on-premises for consistency, and edge for immediacy.\n## The great rebuild: Architecting an AI-native tech organizationtiAI is restructuring tech organizations, making them leaner, faster, and more strategic.\nOnly 1% of IT leaders surveyed by Deloitte reported that no major operating model changes were underway.^11^ Leaders are shifting from incremental IT management to orchestrating human-agent teams, with CIOs becoming AI evangelists.\nSuccess requires bold reimagination: modular architectures, embedded governance, and perpetual evolution as core capabilities.\n## The AI dilemma: Securing and leveraging AI for cyber defenseenThe technology meant to give businesses an advantage is becoming the target used against them.\nAT&T’s chief information security officer captured the challenge: “What we’re experiencing today is no different than what we’ve experienced in the past.\nThe only difference with AI is speed and impact.”^12^ Organizations must secure AI across four domains—data, models, applications, and infrastructure—but they also have the opportunity to use AI-powered defenses to fight threats operating at machine speed.",
          "title": "Tech Trends 2026 | Deloitte Insights",
          "url": "https://www.deloitte.com/us/en/insights/topics/technology-management/tech-trends.html",
          "date": "2025-12-10",
          "last_updated": "2026-05-24"
        },
        {
          "snippet": "",
          "title": "McKinsey Technology Trends Outlook 2025",
          "url": "https://www.mckinsey.com/capabilities/tech-and-ai/our-insights/the-top-trends-in-tech",
          "date": "2025-07-22",
          "last_updated": "2026-05-27"
        },
        {
          "snippet": "",
          "title": "The new Essential Eight technology trends: PwC",
          "url": "https://www.pwc.com/us/en/tech-effect/emerging-tech/essential-eight-technologies.html",
          "date": "2023-11-15",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "### The year of truth for AI\nAI becomes the backbone of the digital economy, shifting from isolated proofs of concept to coherent, adaptive, and trusted value systems.\nThis transformation demands not just technology, but governance and cultural readiness to embed AI into the very fabric of enterprise decision-making.\n### AI is eating software\nThe paradigm moves from “writing code” to “expressing intent.”\nDevelopers articulate desired outcomes, and AI autonomously delivers, integrating and maintaining systems behind the scenes.\nAs software becomes self-assembling and self-healing, the competitive edge will hinge on mastering orchestration and governance rather than manual coding.\n### Cloud 3.0: all flavors of cloud\nCloud is entering its next evolution.\nAfter a decade focused on migration and cost efficiency, cloud is now becoming the operational backbone for AI and AI assisted apps.\nAI cannot scale only on the classical public cloud architectures.\nThe need to fine-tune models on proprietary data, manage data sensitivity, and deploy low-latency inference is pushing organizations toward hybrid, private, multi and sovereign cloud models, and not by exception.\nCloud ceases to be a passive infrastructure layer and becomes an active enabler of AI-driven architectures, ensuring portability, sovereignty.\n### The rise of intelligent ops\nMonolithic enterprise backbones evolve into living ecosystems of intelligent, modular, and continuously learning applications, blending human oversight with autonomous AI agents and putting the process back at the core.\nThis shift turns operations into adaptive engines of value creation, where resilience and agility become structural rather than aspirational.\nIntelligent operations position enterprises not just to run better, but to reinvent themselves continuously.\n### The borderless paradox of tech sovereignty\nTech sovereignty returns to at the top of the agenda, but the race is now for resilient interdependence—balancing open collaboration with strategic self-reliance.\nSuccess will depend on designing systems that remain globally connected yet controllable, embedding sovereignty principles into architecture rather than isolationist strategies.\n...\n### What are the Top Tech Trends to watch in 2026?\n*TechnoVision 2026* highlights **five transformative trends that will shape the technology landscape**.\nFirst, **the Year of Truth for AI** signals a shift from hype to measurable impact, as organizations focus on trust and enterprise-wide adoption.\nSecond, **AI is Eating Software**, meaning artificial intelligence is redefining the software lifecycle by moving from traditional coding to intent-driven development and autonomous maintenance.\nThird, **Cloud 3.0: All Flavors of Cloud** introduces a diversified ecosystem of hybrid, multi-cloud, and sovereign architectures to support AI scalability and resilience.\nFourth, **the Rise of Intelligent Ops** marks the evolution of enterprise systems into adaptive engines powered by AI agents for smarter operations.\nFinally, **the Borderless Paradox of Tech Sovereignty** reflects the challenge of balancing global interdependence with strategic control over critical technology stacks.\n...\nIn 2025, we highlighted five major trends—generative AI agents, AI-driven cybersecurity, autonomous robotics, the resurgence of nuclear energy to power computing, and supply chain reinvention—that reached a pivotal moment last year and continue to shape the landscape in 2026.\nWhile artificial Intelligence (AI) and generative AI (Gen AI) remain central, their influence now extends across software development, cloud architectures, and enterprise operations.\n...\nAfter years of fragmented pilots and inflated expectations, 2026 marks the shift from proof-of-concept to **proof-of-impact**.\n...\nThe upcoming year will see AI become the backbone of enterprise architecture, reshape software lifecycle development, and redefine cloud consumption.",
          "title": "Top Tech Trends 2026: AI Backbone, Intelligent Apps ... - Capgemini",
          "url": "https://www.capgemini.com/insights/research-library/top-tech-trends-of-2026/",
          "date": "2026-01-12",
          "last_updated": "2026-05-27"
        },
        {
          "snippet": "",
          "title": "Here are the top 10 trends in tech - The World Economic Forum",
          "url": "https://www.weforum.org/stories/2022/07/top-10-trends-in-tech/",
          "date": "2022-07-27",
          "last_updated": "2026-04-16"
        },
        {
          "snippet": "",
          "title": "Top 25 New Technology Trends in 2025 - GeeksforGeeks",
          "url": "https://www.geeksforgeeks.org/blogs/top-new-technology-trends/",
          "date": "2022-04-12",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "",
          "title": "25 New Technology Trends for 2025",
          "url": "https://www.simplilearn.com/top-technology-trends-and-jobs-article",
          "date": "2018-08-08",
          "last_updated": "2026-03-28"
        },
        {
          "snippet": "The question used to be “What can we do with AI?”\nNow it’s “How do we move from experimentation to impact?”\nThe focus has moved from endless pilots to real business value, and there’s a sense of urgency behind it all.\nNot because the technology is getting better—though it is—but because the pace of change itself has accelerated.\nThe numbers tell the story (figure 1).\nThe telephone took 50 years to reach 50 million users.\nThe internet took seven years.\nA leading generative AI tool reached about twice that many in two months.\n1 As of this writing, that tool has over 800 million weekly users—roughly 10% of the planet’s population.\n2\nBut rapid adoption is only the surface.\nInnovation is compounding; forces aren’t simply additive, but multiplicative.\nThink of it as a flywheel: Better technology enables more applications.\nMore applications generate more data.\nMore data attracts more investment.\nMore investment builds better infrastructure.\nBetter infrastructure reduces costs.\nLower costs enable more experimentation.\nEach improvement simultaneously accelerates all the others.\nIt’s why AI startups scale from US$1 million to US$30 million in revenue five times faster than SaaS companies did.\n3 It’s why the knowledge half-life in AI has shrunk to months from years.\n4 And it’s why one chief information officer (CIO) told me, “The time it takes us to study a new technology now exceeds that technology’s relevance window.”\n...\nFor 17 years, Tech Trends has explored emerging technologies poised to reshape business in the next 18 to 24 months.\nOur research is based on trend sensing from conversations with Deloitte subject matter experts and external technology leaders, as well as Deloitte’s proprietary research on emerging technologies.\nThis year, the data reveals five interconnected forces.\nAmazon deployed its millionth robot, and its DeepFleet AI coordinates the entire robot fleet, improving travel efficiency within warehouses by 10%.\n5 BMW’s factories have cars driving themselves through kilometer-long production routes.\n6 Intelligence isn’t confined to screens anymore; it’s embodied, autonomous, and solving real problems in the physical world.\nOnly 11% of organizations have agents in production, despite 38% piloting them.\nThe gap between pilot to production tells you everything.\nForty-two percent are still developing their strategy, while 35% have no strategy at all.\n7 Gartner predicts that 40% of agentic projects will fail by 2027 8—not because the technology doesn’t work, but because organizations are automating broken processes instead of redesigning operations.\nHPE’s chief financial officer captured what works: “We wanted to select an end-to-end process where we could truly transform, not just solve for a single pain point.”\n9 Redesign, don’t automate.\nThat’s the pattern separating success from failure.\nToken costs have dropped 280-fold in two years;\n10 yet some enterprises are seeing monthly bills in the tens of millions.\nUsage exploded faster than costs declined.\nOrganizations are discovering their existing infrastructure strategies aren't designed to scale AI to production-scale deployment.\nThey're shifting from cloud-first to strategic hybrid: cloud for elasticity, on-premises for consistency, and edge for immediacy.\nAI is restructuring tech organizations, making them leaner, faster, and more strategic.\nOnly 1% of IT leaders surveyed by Deloitte reported that no major operating model changes were underway.\n11 Leaders are shifting from incremental IT management to orchestrating human-agent teams, with CIOs becoming AI evangelists.\nSuccess requires bold reimagination: modular architectures, embedded governance, and perpetual evolution as core capabilities.\nThe technology meant to give businesses an advantage is becoming the target used against them.\nAT&T’s chief information security officer captured the challenge: “What we’re experiencing today is no different than what we’ve experienced in the past.\nThe only difference with AI is speed and impact.”\n12 Organizations must secure AI across four domains—data, models, applications, and infrastructure—but they also have the opportunity to use AI-powered defenses to fight threats operating at machine speed.\n...\nIt’s not just that AI is powerful.\nIt’s that the S-curves are compressing.\nThe distance between emerging and mainstream is collapsing.\nOrganizations built for sequential improvement can’t compete with those operating in continuous learning loops.\n...\nThat assumption no longer holds.",
          "title": "Tech Trends 2026",
          "url": "https://www.deloitte.com/us/en/insights/topics/technology-management/tech-trends.html?icid=disubnav_tech-trends",
          "date": "2025-12-10",
          "last_updated": "2025-12-11"
        },
        {
          "snippet": "Generative AI (gen AI) has rightly seized leaders’ attention in recent years.\nBut is it also eclipsing adjacent or lower-profile digital imperatives?\nQuantumBlack and the McKinsey Technology Council identified 15 most significant technology trends unfolding today, grouped into five broader categories: the AI revolution, building the digital future, compute and connectivity frontiers, cutting-edge engineering, and a sustainable world.",
          "title": "Top 15 technology trends unfolding today - McKinsey & Company",
          "url": "https://www.mckinsey.com/featured-insights/themes/top-15-technology-trends-unfolding-today",
          "date": "2024-08-10",
          "last_updated": "2025-09-20"
        },
        {
          "snippet": "## As technology innovation and adoption accelerate, five trends reveal how successful organizations are moving from experimentation to impact\nArticle\n...\nThe question used to be “What can we do with AI?”\n...\nFor 17 years, Tech Trends has explored emerging technologies poised to reshape business in the next 18 to 24 months.\nOur research is based on trend sensing from conversations with Deloitte subject matter experts and external technology leaders, as well as Deloitte’s proprietary research on emerging technologies.\nThis year, the data reveals five interconnected forces.\n## AI goes physical: Navigating the convergence of AI and robotics\nAmazon deployed its millionth robot, and its DeepFleet AI coordinates the entire robot fleet, improving travel efficiency within warehouses by 10%.^5^ BMW’s factories have cars driving themselves through kilometer-long production routes.^6^ Intelligence isn’t confined to screens anymore; it’s embodied, autonomous, and solving real problems in the physical world.\n## The agentic reality check: Preparing for a silicon-based workforce\nOnly 11% of organizations have agents in production, despite 38% piloting them.\nThe gap between pilot to production tells you everything.\nForty-two percent are still developing their strategy, while 35% have no strategy at all.^7^ Gartner predicts that 40% of agentic projects will fail by 2027^8^—not because the technology doesn’t work, but because organizations are automating broken processes instead of redesigning operations.\n...\nThat’s the pattern separating success from failure.\n## The AI infrastructure reckoning: Optimizing compute strategy in the age of inference economics\nToken costs have dropped 280-fold in two years;^10^ yet some enterprises are seeing monthly bills in the tens of millions.\nUsage exploded faster than costs declined.\nOrganizations are discovering their existing infrastructure strategies aren't designed to scale AI to production-scale deployment.\nThey're shifting from cloud-first to strategic hybrid: cloud for elasticity, on-premises for consistency, and edge for immediacy.\n## The great rebuild: Architecting an AI-native tech organization\nAI is restructuring tech organizations, making them leaner, faster, and more strategic.\nOnly 1% of IT leaders surveyed by Deloitte reported that no major operating model changes were underway.^11^ Leaders are shifting from incremental IT management to orchestrating human-agent teams, with CIOs becoming AI evangelists.\nSuccess requires bold reimagination: modular architectures, embedded governance, and perpetual evolution as core capabilities.\n## The AI dilemma: Securing and leveraging AI for cyber defense\nThe technology meant to give businesses an advantage is becoming the target used against them.\nAT&T’s chief information security officer captured the challenge: “What we’re experiencing today is no different than what we’ve experienced in the past.\nThe only difference with AI is speed and impact.”^12^ Organizations must secure AI across four domains—data, models, applications, and infrastructure—but they also have the opportunity to use AI-powered defenses to fight threats operating at machine speed.",
          "title": "Tech Trends 2025 | Deloitte Insights",
          "url": "https://www.deloitte.com/us/en/insights/topics/technology-management/tech-trends.html?icid=disidenav_tech-trends",
          "date": "2025-12-10",
          "last_updated": "2026-03-05"
        }
      ],
      "server_time": null
    }
    ```
  </Accordion>
</AccordionGroup>

## Parameter Reference

### `search_after_date_filter`

* **Type**: String
* **Format**: "%m/%d/%Y" (e.g., "3/1/2025")
* **Description**: Filters search results to only include content published after this date
* **Optional**: Yes
* **Example**: `"search_after_date_filter": "1/1/2025"`

### `search_before_date_filter`

* **Type**: String
* **Format**: "%m/%d/%Y" (e.g., "3/1/2025")
* **Description**: Filters search results to only include content published before this date
* **Optional**: Yes
* **Example**: `"search_before_date_filter": "12/31/2025"`

### `last_updated_after_filter`

* **Type**: String
* **Format**: "%m/%d/%Y" (e.g., "07/01/2025")
* **Description**: Filters search results to only include content last updated after this date
* **Optional**: Yes
* **Example**: `"last_updated_after_filter": "07/01/2025"`

### `last_updated_before_filter`

* **Type**: String
* **Format**: "%m/%d/%Y" (e.g., "12/30/2025")
* **Description**: Filters search results to only include content last updated before this date
* **Optional**: Yes
* **Example**: `"last_updated_before_filter": "12/30/2025"`

### `search_recency_filter`

* **Type**: String
* **Allowed Values**: "hour", "day", "week", "month", "year"
* **Description**: Filters search results to content from the specified time period relative to the current date
* **Optional**: Yes
* **Example**: `"search_recency_filter": "week"`

## Best Practices

**Date Format**

* Strict Format: Dates must match the "%m/%d/%Y" format exactly. For example, "3/1/2025" or "03/01/2025" is acceptable.
* Consistency: Use one or both date filters consistently based on your search needs. Combining both provides a clear range.

**Filter Selection**

* Choose the Right Filter Type: Use publication date filters (`search_after_date_filter`/`search_before_date_filter`) when you care about when content was originally created. Use last updated filters (`last_updated_after_filter`/`last_updated_before_filter`) when you need recently maintained content. Use recency filters (`search_recency_filter`) for quick, relative time filtering.
* Recency vs. Exact Dates: Use `search_recency_filter` for convenience when you want recent content (e.g., "past week"). Use specific date filters when you need precise control over the time range.
* Combining Filters: You can use both publication and last updated filters together to find content that meets both criteria (e.g., published in 2024 but updated recently). Note that `search_recency_filter` cannot be combined with specific date filters (`search_after_date_filter`/`search_before_date_filter` or `last_updated_after_filter`/`last_updated_before_filter`).

**Client-Side Validation**

* Regex Check: Validate date strings on the client side using a regex such as:

<CodeGroup>
  ```bash theme={null}
  date_regex='^(0?[1-9]|1[0-2])/(0?[1-9]|[12][0-9]|3[01])/[0-9]{4}$'
  ```

  ```python theme={null}
  date_regex = r'^(0?[1-9]|1[0-2])/(0?[1-9]|[12]\d|3[01])/\d{4}$'
  ```
</CodeGroup>

This ensures that dates conform to the required format before sending the request.

**Performance Considerations**

* Narrowing the Search: Applying date range filters typically reduces the number of results, which may improve response times and result relevance.
* Avoid Over-Restriction: Ensure that the date range is neither too narrow (limiting useful results) nor too broad (defeating the purpose of the filter).

## Advanced Usage Patterns

**Finding Breaking News**

Use the `search_recency_filter` with `"hour"` for live events, or `"day"` for the most recent breaking news:

```python theme={null}
# Live events and real-time data
response = client.search(
    query="Apollo 11 moon landing mission overview",
    max_results=5,
    search_recency_filter="hour"
)

# Breaking news from the past 24 hours
response = client.search(
    query="breaking news technology",
    max_results=5,
    search_recency_filter="day"
)
```

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "1d212bdd-e54b-44de-8b21-b902c7dbf82b",
    "results": [
      {
        "snippet": "The primary objective of Apollo 11 was to complete a national goal set by President John F. Kennedy on May 25, 1961: perform a crewed lunar landing and return to Earth.\nAdditional flight objectives included scientific exploration by the lunar module, or LM, crew; deployment of a television camera to transmit signals to Earth; and deployment of a solar wind composition experiment, seismic experiment package and a Laser Ranging Retroreflector.\nDuring the exploration, the two astronauts were to gather samples of lunar-surface materials for return to Earth.\nThey also were to extensively photograph the lunar terrain, the deployed scientific equipment, the LM spacecraft, and each other, both with still and motion picture cameras.\nThis was to be the last Apollo mission to fly a “free-return” trajectory, which would enable a return to Earth with no engine firing, providing a ready abort of the mission at any time prior to lunar orbit insertion.\n...\nApollo 11 launched from Cape Kennedy on July 16, 1969, carrying Commander Neil Armstrong, Command Module Pilot Michael Collins and Lunar Module Pilot Edwin “Buzz” Aldrin into an initial Earth-orbit of 114 by 116 miles.\nAn estimated 650 million people watched Armstrong’s televised image and heard his voice describe the event as he took “…one small step for a man, one giant leap for mankind” on July 20, 1969.\nTwo hours, 44 minutes and one-and-a-half revolutions after launch, the S-IVB stage reignited for a second burn of five minutes, 48 seconds, placing Apollo 11 into a translunar orbit.\nThe command and service module, or CSM, Columbia separated from the stage, which included the spacecraft-lunar module adapter, or SLA, containing the lunar module, or LM, Eagle.\n...\nPartially piloted manually by Armstrong, the Eagle landed in the Sea of Tranquility in Site 2 at 0 degrees, 41 minutes, 15 seconds north latitude and 23 degrees, 26 minutes east longitude.\n...\nAfter a flight of 195 hours, 18 minutes, 35 seconds – about 36 minutes longer than planned – Apollo 11 splashed down in the Pacific Ocean, 13 miles from the recovery ship USS Hornet.\nBecause of bad weather in the target area, the landing point was changed by about 250 miles.\nApollo 11 landed 13 degrees, 19 minutes north latitude and 169 degrees, nine minutes west longitude July 24, 1969.\n**Crew**\nNeil Armstrong, Commander\nEdwin E.\n“Buzz” Aldrin Jr., Lunar Module Pilot\nMichael Collins, Command Module Pilot\n**Backup Crew**\nJames A. Lovell, Commander\nFred W. Haise Jr., Lunar Module Pilot\nWilliam A. Anders, Command Module Pilot\n**Payload**",
        "title": "Apollo 11 Mission Overview - NASA",
        "url": "https://www.nasa.gov/history/apollo-11-mission-overview/",
        "date": "2015-04-17",
        "last_updated": "2026-05-13"
      },
      {
        "snippet": "The primary objective of Apollo 11 was to complete a national goal set by President John F. Kennedy on May 25, 1961: perform a crewed lunar landing and return to Earth.\nMission Type\nLunar Landing\nastronauts\nNeil Armstrong, Buzz Aldrin, Michael Collins\nLaunch\nJuly 16, 1969\nSPLASHDOWN\nJuly 24, 1969\n...\n**First human to set foot on the Moon.**\nNeil A. Armstrong is probably best known as the commander for the Apollo 11 mission.\n...\nWatch highlights from the Apollo 11 mission including the launch on July 16, 1969, the landing of the lunar module, Neil Armstrong's first steps on the Moon, splashdown, and more.\n...\n20 July 1969—Astronaut Edwin E. Aldrin Jr., lunar module pilot, walks on the surface of the moon near the leg of the Lunar Module (LM) “Eagle” during the Apollo 11 extravehicular activity (EVA).\n...\nJOHNSON SPACE CENTER, HOUSTON, TEXAS – With a half-Earth in the background, the Lunar Module ascent stage with Moon-walking astronauts Neil Armstrong and Edwin Aldrin Jr. approaches for a rendezvous with the Apollo Command Module manned by Michael Collins.\nThe Apollo 11 liftoff from the Moon came early, ending a 22-hour stay on the Moon by Armstrong and Aldrin.\n...\nNeil Armstrong was the first person to walk on the moon.\nHe was an astronaut.\nHe flew on two space missions.\nOne was Apollo 11.",
        "title": "Apollo 11 - NASA",
        "url": "https://www.nasa.gov/mission/apollo-11/",
        "date": "2023-03-08",
        "last_updated": "2026-05-15"
      },
      {
        "snippet": "",
        "title": "Apollo 11 - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Apollo_11",
        "date": "2001-09-24",
        "last_updated": "2026-05-18"
      },
      {
        "snippet": "Apollo 11 was launched on July 16, 1969, at 8:32 AM Central Daylight Time (CDT) with the goal of performing the first human landing on the Moon.\nCommander Neil Armstrong, Command Module Pilot Michael Collins, and Lunar Module Pilot Edwin “Buzz” Aldrin entered lunar orbit on the afternoon of July 19.\nThe following day, Armstrong and Aldrin begin their descent to the lunar surface in the Lunar Module, Eagle.\nThe planned landing site in the Sea of Tranquility was selected as a flat, safe location and had been surveyed by Apollo 10 at an elevation of 10 miles above the Moon.\nHowever, a navigation error earlier in the mission caused Eagle to be about 7 kilometers beyond the planned landing location.\nDuring the 12.6-minute-long powered descent, there were a total of five unexpected computer alarms.\nThese alarms all indicated that Eagle’s computer system was overloaded, but in each case, Mission Control concluded that it was safe to continue the landing.\n...\nBecause of the navigation error, the computer was guiding the spacecraft towards an unsafe touchdown point in the rugged, boulder-filled ejecta field surrounding West Crater.\nArmstrong took manual control and flew to a safe landing spot beyond the crater.\nAt 3:17 PM CDT, he announced their safe landing, “Houston, Tranquility Base.\nThe Eagle has landed.”\nAt the time of landing, Mission Control thought that the spacecraft had just 17 seconds of fuel left in the descent stage.\nHowever, post mission analysis showed that sloshing in the fuel tank during Armstrong’s search for a safe landing site caused the fuel gauge to give an inaccurate reading.\nEagle actually had about 45 seconds of fuel left when it touched down.\nAfter a checkout of Eagle’s systems, Armstrong and Aldrin prepared for their moonwalk.\nAt 9:56 PM CDT, Armstrong set foot on the lunar surface, “That’s one small step for man, one giant leap for mankind.”\nAldrin followed a short while later.\nThe duration of this first ever moonwalk was limited to just 2 hours and 31 minutes and the crew remained within 60 meters of Eagle.\nArmstrong and Aldrin collected 21.6 kilograms of samples and deployed a seismometer to measure moonquakes, a laser retroreflector to enable precise measurements of the distance between Earth and the Moon, and a device to collect a sample of the solar wind.\nThey also performed ceremonial duties, including setting up a United States flag, unveiling a commemorative plaque on the lunar module, and having a brief conversation with President Richard Nixon.\nDuring the moon landing, Collins remained in lunar orbit in the command module, Columbia.\nAfter just 21.6 hours on the Moon, Eagle’s ascent stage returned to lunar orbit and rejoined Columbia.\nAltogether, Apollo 11 spent 2.5 days in lunar orbit, circling the Moon 31 times.\nThe crew returned safely to Earth on July 24, landing in the Pacific Ocean southwest of Hawaii, after a flight of 8 days and 3 hours.\nAlthough scientists considered it unlikely that the Moon had life on it, the crew was kept in a biological quarantine for 21 days.\nPost-mission analysis showed that the Apollo 11 samples consisted of two primary rock types.\nBasalt is formed by the solidification of molten magma.\nThe Apollo 11 basalts formed 3.6 to 3.9 billion years ago and are unusually rich in the element titanium.\nBreccias are composed of fragments of other rocks.\nOn the Moon, breccias formed from rocks that are broken up by impacting objects.\nAnalysis of the lunar samples also confirmed that they were indeed lifeless and showed no evidence of water.",
        "title": "Lunar - Missions - Apollo 11 Mission",
        "url": "https://www.lpi.usra.edu/lunar/missions/apollo/apollo_11/",
        "date": null,
        "last_updated": "2025-07-28"
      },
      {
        "snippet": "Apollo 11, the first space mission to put people on the Moon, was launched on July 16, 1969.\nAlmost every major aspect of the flight of Apollo 11 was witnessed via television by hundreds of millions of people in nearly every part of the globe, until splashdown in the Pacific Ocean on July 24.\n...\nApollo 11’s mission objective was to land astronauts on the Moon and return them safely back to Earth.\nIt succeeded in its objective by landing Neil Armstrong and Buzz Aldrin on the Moon on July 20, 1969.\n...\nApollo 11’s crew members were commander Neil Armstrong, lunar module pilot Buzz Aldrin, and command module pilot Michael Collins.\n...\nThe lunar module *Eagle* of the Apollo 11 mission landed on the Moon on July 20, 1969.\nNeil Armstrong and Buzz Aldrin became the first people to land on the Moon and walk on the lunar surface.\n...\nThe fastest speed Apollo 11 achieved was 39,715 kilometers (24,678 miles) per hour when the command module reentered Earth’s atmosphere on July 24, 1969.\n**\n**Apollo 11**, U.S. spaceflight during which commander Neil Armstrong and lunar module pilot Edwin (“Buzz”) Aldrin, Jr., on July 20, 1969, became the first people to land on the Moon and walk the lunar surface.\nApollo 11 was the culmination of the Apollo program and a massive national commitment by the United States to beat the Soviet Union in putting people on the Moon.\nAll told, 24 Apollo astronauts visited the Moon and 12 of them walked on its surface.\n...\nAt 10:56 pm EDT on July 20, Armstrong stepped out onto the lunar soil with the words, “That’s one small step for [a] man, one giant leap for mankind.”\n...\nAfter 21 hours 38 minutes on the Moon’s surface, the astronauts used *Eagle*’s ascent stage to launch it back into lunar orbit.\n...\nSplashdown of Apollo 11 occurred in the Pacific Ocean about 1,400 km (900 miles) west of Hawaii on July 24.",
        "title": "अपोलो 11 | इतिहास, मिशन, लैंडिंग, अंतरिक्ष यात्री, चित्र ...",
        "url": "https://www.britannica.com/topic/Apollo-11",
        "date": "2026-04-04",
        "last_updated": "2026-04-06"
      },
      {
        "snippet": "**On July 20, 1969, humans walked on the Moon for the first time.**\n**We look back at the legacy of our first small steps on the Moon and look forward to the next giant leap.**\n...\nThe Soviet Union launched the first human, Yuri Gagarin, into space on April 12, 1961.\nWithin days of the Soviet achievement, President John F. Kennedy asked Vice President Lyndon Johnson to identify a “space program which promises dramatic results in which we could win.”\nA little over a month later, on May 25, 1961, Kennedy stood before a joint session of Congress and called for human exploration to the Moon.\n...\nJuly 16, 1969\n## Liftoff!\nA Saturn V rocket carrying the three Apollo 11 astronauts blasted off from Cape Kennedy.\nOver a million spectators, including Vice President Spiro Agnew and former President Lyndon Johnson, came to watch the lift off.\nJuly 20, 1969\n## \"The Eagle has landed!\"\nAfter four days traveling to the Moon, the Lunar Module *Eagle*, carrying Neil Armstrong and Buzz Aldrin landed on the Moon.\nNeil Armstrong exited the spacecraft and became the first human to walk on the moon.\nAs an estimated 650 million people watched, Armstrong proclaimed \"That's one small step for man, one giant leap for mankind.\"\nMichael Collins stayed aboard the Command Module *Columbia*, serving as a communications link and photographing the lunar surface.\n...\n## The Sea of Tranquility | Mare Tranquillitatis\n**00.67408° N latitude, 23.47297° E longitude**\nFor the first lunar landing, the Sea of Tranquility (Mare Tranquilitatis) was the site chosen because it is a relatively smooth and level area.\nIt does, however, have some craters and in the last minutes before landing, Neil Armstrong had to manually pilot the lunar module to avoid a sharp-rimmed ray crater measuring some 180 meters across and 30 meters deep known as West.\nThe lunar module landed safely some 6 km from the originally intended landing site, approximately 400 meters west of West crater and 20km south-southwest of the crater Sabine D in the southwestern part of Mare Tranquilitatis.\nThe lunar surface at the landing site consisted of fragmental debris ranging in size from fine particles to blocks about 0.8 meter wide.\n...\nAfter approximately two and half hours on the Moon, Armstrong and Aldrin returned to the lunar module to begin the journey home.\nThe three astronauts splashed down in Hawaii on July 24, 1969.\nFrom there they quarantined for three weeks as a precaution against bringing contagion back from the Moon, before the festivities welcoming them home commenced.\n...\n## Michael Collins\n...\nThree astronauts were selected as backups for the crew: James A. Lovell, commander; William A. Anders, command module pilot; and Fred W. Haise, lunar module pilot.\nAll three backup crew members would eventually fly on Apollo missions.\n...\nOn July 20th, across the world, people gathered in front of televisions to watch the moon landing.\nAn estimated 650 million viewers were watching.\nIn the United States, 93% of televisions tuned in to see Neil Armstrong walk on the Moon.",
        "title": "Technology",
        "url": "https://airandspace.si.edu/explore/stories/apollo-11-moon-landing",
        "date": "2021-07-29",
        "last_updated": "2026-05-20"
      },
      {
        "snippet": "Apollo 11 (CSM Columbia and LM Eagle)\nSaturn V\nJuly 16-24, 1969\nNeil A. Armstrong\nMichael Collins\nEdwin E.\n\"Buzz\" Aldrin, Jr.\n08 days, 03 hours, 18 minutes\nFirst manned lunar landing mission and lunar\nsurface EVA.\n\"HOUSTON, TRANQUILITY BASE HERE.\nTHE EAGLE HAS LANDED.\"--July 20,\nLanding site: Sea of Tranquility.\nLanding Coordinates: 0.67409 degrees North, 23.47298 degrees East\n(Source: National Space Science Data Center); LROC QuickMap\n1 EVA of 02 hours, 31 minutes.\nFlag and instruments deployed; unveiled plaque on the LM descent stage with inscription: \"Here Men From Planet Earth First Set Foot Upon the Moon.\nJuly 1969 A.D.\nWe Came In Peace For All Mankind.\"\nLunar surface stay time 21.6 hours; 59.5 hours in lunar orbit, with 30 orbits.\nLM ascent stage left in lunar orbit.\n20 kg (44 lbs) of material gathered.",
        "title": "Apollo 11 Lunar Surface Journal : Mission Overview",
        "url": "https://www.nasa.gov/history/alsj/a11/a11ov.html",
        "date": null,
        "last_updated": "2025-10-25"
      },
      {
        "snippet": "Apollo 11 was the first mission to land humans on the Moon.\nIt fulfilled a 1961 goal set by President John F. Kennedy to send American astronauts to the surface and return them safely to Earth before the end of the decade.\nOn 21 July 1969 at 02:56:15 UTC, Neil Armstrong pressed his left foot onto the Moon and said, \"That's one small step for [a] man, one giant leap for mankind,\" as 530 million people watched live on television.\nThe mission returned 20 kilograms of rock and soil to Earth, and paved the way for 5 additional Moon landings that greatly advanced the field of lunar science.\nNeil Armstrong, Buzz Aldrin, and Michael Collins began their journey\nwith a launch aboard a Saturn V rocket on the morning of 16 July 1969.\nThree hours later, their rocket's upper stage blasted them out of Earth\norbit towards the Moon.\nThey arrived 3 days later on 19 July and entered\nan initial lunar orbit of 111 by 306 kilometers.\nA second engine burn\nlowered their orbit to 100 by 113 kilometers.\nOn 20 July, Armstrong and Aldrin boarded their lunar module, nicknamed Eagle, and undocked it from the command module, where Collins remained.\nAlmost the same as in the Apollo 10 rehearsal 2 months earlier, the astronauts fired Eagle’s descent engine, dropping to an orbit with a low point of 14.5 kilometers.\nRoughly an hour later, as the duo approached the Sea of Tranquility, they began a final powered descent to the surface.\n...\nThe official touchdown time was 20:17:39 UTC on 20 July 1969.\n...\nArmstrong and Aldrin's single moonwalk lasted two and a half hours.\nDuring that time, they deployed science and engineering experiments, photographed their surroundings, displayed an American flag, read an inscription plaque, collected rock and soil samples for return to Earth, and spoke with President Richard Nixon.\nThe astronauts verbally described their surroundings and progress for geologists, while cameras mounted inside and outside the lunar module documented some of their activities.\n...\nThe Apollo 11 lunar module landing coordinates are 0.67416 degrees N, 23.47314 E.",
        "title": "Apollo 11 | The Planetary Society",
        "url": "https://www.planetary.org/space-missions/apollo-11",
        "date": "2019-05-31",
        "last_updated": "2026-03-31"
      },
      {
        "snippet": "",
        "title": "Apollo 11 Mission Overview | NASA+",
        "url": "https://plus.nasa.gov/video/apollo-11-mission-overview/",
        "date": "2024-07-12",
        "last_updated": "2026-05-17"
      },
      {
        "snippet": "Overview of the Apollo 11 spaceflight in which U.S. astronauts became the first people to walk on the Moon.\n...\nThe mission that took U.S. astronauts to the Moon was Apollo 11, NASA’s fifth crewed Apollo mission.\nThe astronauts on board the spacecraft were Neil Armstrong, Edwin (“Buzz”) Aldrin, Jr., and Michael Collins.\nOn the morning of July 20, Armstrong and Aldrin crawled from the command module, Columbia, through a tunnel to the lunar module, Eagle.\nArmstrong and Aldrin piloted Eagle to the lunar surface, touching down in the Sea of Tranquility.\nAt 4:17 PM U.S. Eastern Daylight Time (EDT), Armstrong radioed, “Houston, Tranquility Base here.\nThe Eagle has landed.”\nAt 10:56 PM EDT on July 20, Armstrong stepped out onto the lunar soil with the words, “That’s one small step for [a] man, one giant leap for mankind.”\n(In the excitement of the moment, Armstrong skipped the “a” in the statement that he had prepared.)\nArmstrong and Aldrin set up a device to measure the composition of the solar wind reaching the Moon, a device to receive laser beams from astronomical observatories on Earth to determine the exact distance of the two bodies from one each other, and a passive seismometer to measure moonquakes and meteor impacts.\nThey also took about 23 kg (50 pounds) of rock and soil samples, took many photographs, and maintained constant communication with mission control in Houston, Texas.\nAfter 21 hours 38 minutes on the Moon’s surface, the astronauts used Eagle’s ascent stage to launch it back into lunar orbit.\nSplashdown of Apollo 11 occurred in the Pacific Ocean about 1,400 km (900 miles) southwest of Hawaii on July 24.\nAfter their return, the astronauts were quarantined for 21 days from the time Eagle had left the Moon.\nThey were checked for any diseases they might have brought back from the Moon.",
        "title": "Apollo 11's Incredible Journey to the Moon | Britannica",
        "url": "https://www.britannica.com/video/Just-the-facts-Apollo-11-moon-landing/-246490",
        "date": "2023-12-06",
        "last_updated": "2025-08-25"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

**Historical Research**

Use specific date ranges to research historical events or trends:

```python theme={null}
response = client.search(
    query="AI developments",
    max_results=20,
    search_after_date_filter="1/1/2023",
    search_before_date_filter="12/31/2023"
)
```

**Finding Recently Maintained Content**

Use last updated filters to find content that has been refreshed or maintained recently:

```python theme={null}
response = client.search(
    query="React best practices",
    max_results=10,
    last_updated_after_filter="07/01/2025"
)
```

**Trend Analysis**

Compare different time periods by making multiple searches:

```python theme={null}
# Recent trends
recent = client.search(
    query="machine learning trends",
    search_recency_filter="month"
)

# Older trends for comparison
older = client.search(
    query="machine learning trends",
    search_after_date_filter="1/1/2023",
    search_before_date_filter="1/31/2023"
)
```

## Error Handling

When using date filters, ensure proper error handling for invalid date formats:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity
  import re

  def validate_date_format(date_string):
      pattern = r'^(0?[1-9]|1[0-2])/(0?[1-9]|[12]\d|3[01])/\d{4}$'
      return bool(re.match(pattern, date_string))

  def search_with_date_filter(query, after_date=None, before_date=None):
      client = Perplexity()
      
      # Validate date formats
      if after_date and not validate_date_format(after_date):
          raise ValueError(f"Invalid date format: {after_date}")
      if before_date and not validate_date_format(before_date):
          raise ValueError(f"Invalid date format: {before_date}")
      
      try:
          response = client.search(
              query=query,
              search_after_date_filter=after_date,
              search_before_date_filter=before_date
          )
          return response
      except Exception as e:
          print(f"Search failed: {e}")
          return None
  ```

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

  function validateDateFormat(dateString: string): boolean {
    const pattern = /^(0?[1-9]|1[0-2])\/(0?[1-9]|[12]\d|3[01])\/\d{4}$/;
    return pattern.test(dateString);
  }

  async function searchWithDateFilter(
    query: string, 
    afterDate?: string, 
    beforeDate?: string
  ) {
    const client = new Perplexity();
    
    // Validate date formats
    if (afterDate && !validateDateFormat(afterDate)) {
      throw new Error(`Invalid date format: ${afterDate}`);
    }
    if (beforeDate && !validateDateFormat(beforeDate)) {
      throw new Error(`Invalid date format: ${beforeDate}`);
    }
    
    try {
      const response = await client.search.create({
        query,
        search_after_date_filter: afterDate,
        search_before_date_filter: beforeDate
      });
      return response;
    } catch (error) {
      console.error('Search failed:', error);
      return null;
    }
  }
  ```
</CodeGroup>


# Search Domain Filter
Source: https://docs.perplexity.ai/docs/search/filters/domain-filter



<Note>
  The `search_domain_filter` parameter allows you to limit search results to specific domains or exclude certain domains from search results. This supports domain-level filtering for precise content control.
</Note>

<Warning>
  You can add a maximum of 20 domains to the `search_domain_filter` list. The filter works in either allowlist mode (include only) or denylist mode (exclude), but not both simultaneously.
</Warning>

<Info>
  Domain filters allow you to specify which domains to include or exclude in search results. You can filter by specific domains, top-level domains (TLDs), or domain parts. You can specify up to 20 domains per request. Domains should be provided without the protocol (e.g., "nature.com" not "[https://nature.com](https://nature.com)").
</Info>

## Overview

The domain filter for the Search API allows you to control which sources appear in your search results by limiting them to specific domains or excluding certain domains. This is particularly useful when you need to:

* Focus research on authoritative or trusted sources
* Filter out specific domains from search results
* Search within specific publication networks or organizations
* Build domain-specific search applications
* Conduct competitive research within specific industry domains

The `search_domain_filter` parameter accepts an array of domain strings. The filter operates in two modes:

* **Allowlist mode**: Include only the specified domains (no `-` prefix)
* **Denylist mode**: Exclude the specified domains (use `-` prefix)

```bash theme={null}
# Allowlist: Only search these domains
"search_domain_filter": ["nature.com", "science.org", "cell.com"]

# Denylist: Exclude these domains
"search_domain_filter": ["-reddit.com", "-pinterest.com", "-quora.com"]
```

## Filtering Capabilities

Domain filters support flexible matching across different domain components:

### Root Domain Filtering

Specify a root domain to match all content from that domain and its subdomains:

```bash theme={null}
"search_domain_filter": ["wikipedia.org"]
```

This will match:

* `en.wikipedia.org`
* `fr.wikipedia.org`
* `de.wikipedia.org`
* Any other Wikipedia language subdomain

### Top-Level Domain (TLD) Filtering

Filter by top-level domain to target specific categories of sites:

```bash theme={null}
"search_domain_filter": [".gov"]
```

This will match all government domains:

* `nasa.gov`
* `cdc.gov`
* `irs.gov`
* Any other `.gov` domain

<Tip>
  TLD filtering is particularly useful for targeting specific types of organizations, such as `.gov` for government sites, `.edu` for educational institutions, or country-specific TLDs like `.uk` or `.ca`.
</Tip>

### Path Filtering

Add a path after a domain to limit (or exclude) results to one section of a site. The path is matched against the start of the URL's path segments:

```bash theme={null}
"search_domain_filter": ["nature.com/articles"]
```

This will match:

* `nature.com/articles`
* `nature.com/articles/d41586-024-001`
* the same path on any subdomain (e.g. `blog.nature.com/articles`)

It will **not** match:

* `nature.com/news`

Path filtering works in both allowlist and denylist mode. Prefix a path-qualified value with `-` to exclude a section of a site while still searching the rest of it:

```bash theme={null}
# Only this section
"search_domain_filter": ["reddit.com/r/MachineLearning"]

# Everything on the site except this section
"search_domain_filter": ["-reddit.com/r/all"]
```

<Note>
  Path filtering matches on path-segment boundaries, so `"example.com/docs"` matches `/docs` and `/docs/intro` but not `/documentation`. Query strings are allowed after the path boundary (`/docs?x=1` matches).
</Note>

### Domain Part Filtering

Any part of a domain can be used as a filter. The system will match domains containing that component.

## Examples

**1. Allowlist Specific Domains**

This example limits search results to authoritative academic publishers:

**Request Example**

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.search.create(
      query="IPCC AR6 synthesis report key findings",
      max_results=10,
      search_domain_filter=[
          "nature.com",
          "science.org",
          "cell.com"
      ]
  )

  for result in response.results:
      print(f"{result.title}: {result.url}")
  ```

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

  const client = new Perplexity();

  const response = await client.search.create({
    query: "IPCC AR6 synthesis report key findings",
    max_results: 10,
    search_domain_filter: [
      "nature.com",
      "science.org",
      "cell.com"
    ]
  });

  for (const result of response.results) {
    console.log(`${result.title}: ${result.url}`);
  }
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "IPCC AR6 synthesis report key findings",
      "max_results": 10,
      "search_domain_filter": [
        "nature.com",
        "science.org",
        "cell.com"
      ]
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "75c39a4e-a46c-4850-bf27-4c061186ece6",
    "results": [
      {
        "snippet": "",
        "title": "10 Big Findings from the 2023 IPCC Report on Climate Change",
        "url": "https://www.wri.org/insights/2023-ipcc-ar6-synthesis-report-climate-change-findings",
        "date": "2023-03-20",
        "last_updated": "2026-05-15"
      },
      {
        "snippet": "",
        "title": "AR6 Synthesis Report",
        "url": "https://www.ipcc.ch/report/ar6/syr/",
        "date": null,
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "",
        "title": "[PDF] Climate Change 2023 Synthesis Report",
        "url": "https://www.ipcc.ch/report/ar6/syr/downloads/report/IPCC_AR6_SYR_LongerReport.pdf",
        "date": null,
        "last_updated": "2026-05-18"
      },
      {
        "snippet": "The Synthesis Report is based on the content of the three Working Groups Assessment Reports:* WGI – The Physical Science Basis, WGII – Impacts, Adaptation and Vulnerability, WGIII – Mitigation of Climate Change*, and the three Special Reports: *Global Warming of 1.5°C*, *Climate Change and Land*, *The Ocean and Cryosphere in a Changing Climate*.\n...\nThe SYR outline agreed at the 52^nd^ Panel Session of the IPCC consists of an introduction and three main sections arranged by timeframes.\nThe first section, ‘Current Status and Trends’, covers the historical and present period.\nThe second section, ‘Long-term Climate and Development Futures’, addresses projected futures up to 2100 and beyond.\nThe final section is ‘Near-term Responses in a Changing Climate’, considers current international policy timeframes, and the time interval between now and 2030-2040.\nThis structure, substantially different to what was adopted for AR5 SYR, enables a holistic framing that integrates across the Working Groups, better enabling the SYR to cover different aspects of climate change.",
        "title": "AR6 Synthesis Report: Climate Change 2023 — IPCC",
        "url": "https://www.ipcc.ch/report/sixth-assessment-report-cycle/",
        "date": null,
        "last_updated": "2026-05-12"
      },
      {
        "snippet": "",
        "title": "[PDF] IPCC_AR6_SYR_FullVolume.pdf",
        "url": "https://www.ipcc.ch/report/ar6/syr/downloads/report/IPCC_AR6_SYR_FullVolume.pdf",
        "date": null,
        "last_updated": "2026-05-20"
      },
      {
        "snippet": "",
        "title": "Summary for Policymakers",
        "url": "https://www.ipcc.ch/report/ar6/syr/summary-for-policymakers/",
        "date": null,
        "last_updated": "2026-05-20"
      },
      {
        "snippet": "",
        "title": "SYR Longer Report - Intergovernmental Panel on Climate Change",
        "url": "https://www.ipcc.ch/report/ar6/syr/longer-report/",
        "date": null,
        "last_updated": "2026-03-21"
      },
      {
        "snippet": "",
        "title": "IPCC Secretariat",
        "url": "https://www.ipcc.ch/site/assets/uploads/2023/03/Doc5_Adopted_AR6_SYR_Longer_Report.pdf",
        "date": null,
        "last_updated": "2024-02-26"
      },
      {
        "snippet": "",
        "title": "IPCC AR6 Working Group 1: Technical Summary",
        "url": "https://www.ipcc.ch/report/ar6/wg1/chapter/technical-summary/",
        "date": null,
        "last_updated": "2026-03-18"
      },
      {
        "snippet": "",
        "title": "IPCC_AR6_SYR_SPM.pdf",
        "url": "https://www.ipcc.ch/report/ar6/syr/downloads/report/IPCC_AR6_SYR_SPM.pdf",
        "date": null,
        "last_updated": "2026-05-21"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

**2. Tech News Sources**

Search across major technology news websites:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.search.create(
      query="enterprise AI adoption trends in financial services",
      max_results=10,
      search_domain_filter=[
          "techcrunch.com",
          "theverge.com",
          "arstechnica.com",
          "wired.com"
      ]
  )

  for result in response.results:
      print(f"{result.title}")
      print(f"Source: {result.url}")
      print(f"Date: {result.date}")
      print("---")
  ```

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

  const client = new Perplexity();

  const response = await client.search.create({
    query: "enterprise AI adoption trends in financial services",
    max_results: 10,
    search_domain_filter: [
      "techcrunch.com",
      "theverge.com",
      "arstechnica.com",
      "wired.com"
    ]
  });

  for (const result of response.results) {
    console.log(`${result.title}`);
    console.log(`Source: ${result.url}`);
    console.log(`Date: ${result.date}`);
    console.log("---");
  }
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "enterprise AI adoption trends in financial services",
      "max_results": 10,
      "search_domain_filter": [
        "techcrunch.com",
        "theverge.com",
        "arstechnica.com",
        "wired.com"
      ]
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "3c32332e-256e-42f6-94c8-f9435d547e2a",
    "results": [
      {
        "snippet": "",
        "title": "The future of banking: How AI is reshaping the industry - PwC",
        "url": "https://www.pwc.com/us/en/industries/financial-services/library/how-ai-is-reshaping-banking.html",
        "date": "2025-10-16",
        "last_updated": "2026-05-26"
      },
      {
        "snippet": "### 1.\nMoving from pilot to scale as access expandsexEnterprise AI adoption grows\nWorker access to AI rose by 50% in 2025, and expectations for scale are high: the number of companies with ≥40% projects in production is set to double in six months.\n...\nAI is delivering on efficiency and productivity, and twice as many leaders as last year are reporting transformative impact.\nBut just 34% are truly reimagining the business.\n### 3.\nAI fluency over role redesignroAI workforce impact remains low\nThe AI skills gap is seen as the biggest barrier to integration, and education—not role or workflow redesign—was the No. 1 way companies adjusted their talent strategies due to AI.\n...\nSovereign AI is when a country—and companies within it—deploy AI under their own laws, infrastructure, and data.\nIt's not just about ownership.\nIt's about strategic independence.\n### 5.\nAI agents outpace their guardrailspaThe oncoming surge in agentic AI\nAgentic AI usage is poised to rise sharply in the next two years, but oversight is lagging: Only one in five companies has a mature model for governance of autonomous AI agents.\n### 6.\nPhysical AI's fast-growing footprint fGaining traction by 22 percentage points in two years\nMore than half of companies (58%) report at least limited use of physical AI today, and that figure is set to reach 80% in two years—with Asia Pacific leading in early implementation.\n### 7.\n...\nCompared to last year, more companies (42%) believe their strategy is highly prepared for AI adoption—but they feel less prepared in terms of infrastructure, data, risk, and talent.\n## What's top of mind when it comes to AI in the enterprise?itAs they turn the corner to scale, leaders are asking about ROI, safe and ethical practices, workforce readiness, and tactical, go-to-market moves.\n...\nDigital transformation with AI can yield a variety of benefits for businesses, from cost savings to service delivery.\nImproving productivity and efficiency top the list of benefits achieved from enterprise AI adoption so far, with two-thirds (66%) of organizations reporting gains.\nOther benefits organizations reported achieving include:\n- Enhancing insights and decision-making (53%)\n- Reducing costs (40%)\n- Enhancing client/customer relationships (38%)\n- Improving products/services and fostering innovation (20%)\n- Increasing revenue (20%)\nRevenue growth largely remains an aspiration, with 74% of organizations hoping to grow revenue through their AI initiatives in the future compared to just 20% that are already doing so.\n...\nOne-third (34%) of surveyed organizations are starting to use AI to deeply transform—creating new products and services or reinventing core processes or business models.\nAnother third (30%) are redesigning key processes around AI.\nThe remaining third (37%) are using AI at a more surface level, with little or no change to existing processes.\nWhile each are capturing productivity and efficiency gains, only the first group are truly reimagining their businesses rather than optimizing what already exists.\nAdditionally, different types of AI technologies yield different expectations for impact.\n**Generative AI (GenAI):** The areas of GenAI that leaders believe will have the most impactful effects on their industries are:\n- Search and knowledge management\n- Virtual assistants/chatbots\n- Content generation\n**Agentic AI:** While agentic AI is expected to have the highest impact in customer support, use cases for supply chain management, R&D, knowledge management, and cybersecurity are also seen as having high potential.\nThe enterprises we interviewed are already deploying autonomous AI agents across diverse functions:\n- A financial services company is building agentic workflows to automatically capture meeting actions from video conferences, draft communications to remind participants of their commitments, and track follow-through.\n- An air carrier is using AI agents to help customers complete the most common transactions, such as rebooking a flight or rerouting bags, freeing up time for human agents to address more complex matters.\n- A manufacturer is using AI agents to support new product development initiatives, leveraging AI to find the optimal balance between competing objectives such as cost and time-to-market.\n- In the public sector, AI agents are being used to cover workforce shortages, partnering with human workers to complete key processes.\n**Physical AI:** Physical AI applications span a wide range of industrial and commercial settings.\nCommon use cases for physical AI include:\n- collaborative robots (cobots) on assembly lines\n- Inspection drones with automated response capabilities\n- Robotic picking arms\n- Autonomous forklifts\nAdoption is especially advanced in manufacturing, logistics, and defense, where robotics, autonomous vehicles, and drones are already reshaping operations.\n...\nAccording to the leaders surveyed, insufficient worker skills are the biggest barrier to integrating AI into existing workflows.\nThese are the top ways organizations are adjusting AI talent strategy:\n- Educating the broader workforce to raise overall AI fluency (53%)\n- Designing and implementing upskilling and reskilling strategies (48%)\n- Assessing target talent acquisition levels and hiring specialized talent to drive AI initiatives (36%)\n- Redesigning career paths and career mobility strategies (33%)\n- Assessing changes to the anticipated supply and demand of skills (30%)\n- Providing performance-based incentives for leveraging AI (30%)\n- Combining or reimagining organizations based on new patterns resulting from AI usage (30%)\n- Measuring worker trust and engagement (30%)\n- Changing the balance between full-time, contract, and gig workers (19%)\n...\nTrends and insights about AI in the enterprise vary from sector to sector, company to company.\nGet a tailored snapshot of your industry to understand where AI is making the biggest impact in your industry.\n...\n### Financial ServicesuDownload",
        "title": "The State of AI in the Enterprise - 2026 AI report | Deloitte US",
        "url": "https://www.deloitte.com/us/en/what-we-do/capabilities/applied-artificial-intelligence/content/state-of-ai-in-the-enterprise.html",
        "date": null,
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "The banking industry stands at a critical inflection point.\nAs we advance through 2025, artificial intelligence has evolved from experimental technology to a strategic imperative reshaping how financial institutions operate, serve customers, and manage risk.\n...\nThe numbers tell a compelling story.\nAccording to McKinsey's latest Global Survey on AI, [78% of organizations now use AI in at least one business function](https://www.mckinsey.com/capabilities/mckinsey-digital/our-insights/superagency-in-the-workplace-empowering-people-to-unlock-ais-full-potential-at-work), up from 72% in early 2024 and 55% a year earlier.\nMeanwhile, the financial services industry invested an estimated [$35 billion in AI](https://www.statista.com/statistics/1446366/leading-banks-in-ai-adoption-worldwide/) in 2023, with banking accounting for approximately $21 billion.\nThis investment is expected to generate substantial returns, [with AI contributing $2 trillion](https://www.statista.com/topics/7083/artificial-intelligence-ai-in-finance/) to the global economy through innovative investment strategies, better customer insights, and improved operational efficiency.\n...\nBased on nCino's experience with over 2,700 customers, including community banks, credit unions, independent mortgage banks, and the largest financial entities globally, three key priorities are driving AI adoption in 2025 and beyond:\n#### 1.\nOperational Efficiency: AI Shifts from Broad Automation to Workflow-Level Impact\nIn 2025, banks are moving past generic automation goals.\nThe focus now is on applying AI to specific, high-friction workflows — especially in lending, onboarding, and document-heavy processes.\nEfficiency is no longer about reducing headcount.\nIt’s about speeding up what still takes too long.\n#### Targeted AI Replaces One-Size-Fits-All Automation\nInstead of general-purpose tools, banks are deploying AI tuned to their internal workflows.\nThese applications help teams move faster with fewer manual steps.\nExamples:\n- Parsing tax returns or balance sheets to pre-fill borrower profiles\n- Prioritizing credit files based on deal complexity or risk level\n- Drafting loan memos from financial and historical deal data\n#### Queue Optimization Becomes a Strategic Advantage\nCycle time is still a pain point — and AI is helping by automating file assignment, surfacing bottlenecks, and routing based on business value.\nExamples:\n- Auto-assigning stalled deals to available underwriters\n- Flagging missing documentation before an analyst starts a review\n- Dynamically re-prioritizing workloads as queues shift\n...\n#### 2.\nRisk Management: AI as Strategic Defense\nAI revolutionizes risk management by transforming how institutions identify, assess, and mitigate threats.\nKey applications include:\n- **Fraud Detection:** Real-time transaction pattern analysis identifies anomalies with unprecedented accuracy and speed.\n- **Credit Risk Assessment:** Machine learning models predict defaults by analyzing customer behavior and transaction patterns more accurately than traditional methods.\n- **Cybersecurity:** In 2023, financial services experienced over 20,000 cyberattacks resulting in $2.5 billion in losses.\nAI-powered security systems detect and respond to threats in real-time.\n...\nBy strengthening these risk management capabilities, banks can confidently offer personalized financial products and services, knowing they have robust safeguards in place to protect both the institution and individual customers from evolving threats.\n#### 3.\nCustomer Experience: Personalizing Services at Scale\n[77% of banking leaders say personalization leads to boosted customer retention](https://dovetail.com/ux/customer-experience-in-banking-trends/), with AI enabling the personalized experiences that drive customer satisfaction and loyalty.\nAI enables personalized service delivery, 24/7 customer support through chatbots, predictive analytics for proactive solutions, and streamlined digital experiences.\nDespite these impressive stats, only 26% of companies have developed the necessary set of capabilities to move beyond proofs of concept and generate tangible value, [according to new research by Boston Consulting Group (BCG)](https://www.bcg.com/press/24october2024-ai-adoption-in-2024-74-of-companies-struggle-to-achieve-and-scale-value).\nSuccess requires strategic implementation focusing on four key factors:\n- **Risk-proportionate governance** that matches oversight intensity to actual risk levels, from low-risk internal automation requiring 1-2 day approvals to high-risk automated decisions demanding comprehensive review\n- **Accelerated implementation timelines** where leading institutions follow streamlined roadmaps from governance foundation through production deployment\n- **Human-in-the-loop design** that maintains human oversight as a core principle while capturing efficiency benefits\n- **Executive leadership engagement** that significantly reduces approval timeframes by providing necessary decision-making authority for rapid implementation.\nTogether, these strategic approaches enable banks to deploy AI solutions that can analyze customer data, predict needs, and deliver personalized experiences at the scale and speed required to compete in today's digital banking landscape.\n...\n75% of banks with over $100 billion in assets are expected to fully integrate AI strategies by 2025.\nEmerging trends include agentic AI for complex tasks, multimodal AI processing multiple data types, and federated learning for privacy-preserving collaboration.\nRegulatory evolution will bring more specific AI requirements focusing on algorithmic transparency, standardized risk frameworks, and enhanced consumer protection.\nTo fully embrace these opportunities, financial institutions must:\n- **Develop a Comprehensive AI Strategy:** Start with clear business objectives aligned with efficiency, risk management, or customer experience priorities.\n...\nThe AI transformation of banking is accelerating rapidly.\nThis growth will contribute $2 trillion to the global economy through innovative strategies and improved efficiency.\nFinancial institutions that embrace AI responsibly and rapidly – with proper governance, risk management, and customer focus – will thrive in the digital future.",
        "title": "AI Trends in Banking 2025 - nCino",
        "url": "https://www.ncino.com/blog/ai-accelerating-these-trends",
        "date": "2025-06-30",
        "last_updated": "2026-05-22"
      },
      {
        "snippet": "",
        "title": "Top 10 trends in AI adoption for enterprises in 2025 - Glean",
        "url": "https://www.glean.com/perspectives/enterprise-insights-from-ai",
        "date": "2025-10-30",
        "last_updated": "2026-05-26"
      },
      {
        "snippet": "Discover how autonomous frontier technologies, like agentic AI, driverless vehicles, and humanoid robotics, are poised to transform the insurance industry.\nFive priorities for winning with GenAI in wealth and asset management\nWealth and asset managers have the opportunity to reimagine their business models and transform their operations with GenAI.",
        "title": "AI in financial services: adoption across sectors | EY - US",
        "url": "https://www.ey.com/en_us/ai-in-financial-services",
        "date": "2025-09-22",
        "last_updated": "2026-05-10"
      },
      {
        "snippet": "The 2026 survey identifies key AI trends being adopted by financial institutions around the world.\n...\nThis year’s results reveal the trends, challenges, and opportunities that define the state of AI in financial services in 2026.",
        "title": "State of AI in Financial Services Survey Report from NVIDIA.",
        "url": "https://www.nvidia.com/en-us/industries/finance/ai-financial-services-report/",
        "date": "2026-01-22",
        "last_updated": "2026-05-26"
      },
      {
        "snippet": "In financial services, AI is no longer a futuristic idea — it’s part of daily business.\nBy 2027, the sector is expected to spend nearly $100B on AI.\nBut this excitement is tempered by legacy systems, governance requirements, and hard-to-measure ROI.\nA new wave of startups is emerging to overcome these hurdles while preserving the control, compliance, and precision that financial institutions require.\n...\n## Broadly bullish, but ROI remains uncertain and hard to quantify\nFinancial institutions are excited about AI, but the ROI is hard to measure, and leaders expect clearer results:\n> *“There’s a healthy amount of skepticism around how much efficiency AI can truly deliver.\nThe potential productivity gains are real, but it’s my job to separate substance from noise to determine what will actually deliver impact.”\n*\n*— Jennifer Charters, EVP and CIO at Lincoln Financial*\nMost now view AI as a useful tool that can create leverage in targeted areas, but not a universal fix.\nSo, firms are increasingly selective in their approach and prioritizing companies that can show measurable ROI.\n## AI push is both top-down and bottom-up\nBoards and senior executives see peers touting AI initiatives at conferences and earnings calls, and public markets are rewarding firms that can show credible strategies.\nNo one wants to be left behind, so the top-down push toward AI has become as much about optics as efficiency.\nHowever, the push isn’t just top-down.\nEmployees want tools that reduce manual work, putting real pressure on procurement and IT teams to move quickly:\n> *“Front-line teams are pushing for automation to make their lives easier while leadership pushes for AI strategy.\nThe two forces have started to reinforce to drive real AI adoption.*”\n*— Dan Zinkin, former CIO Global Investment & Corporate Banking at J.P.\nMorgan & Head of AI and Data at InvestCloud*\nThe result is a rare alignment across the org chart — many want AI, even if for different reasons.\n## Main AI use cases today are productivity-oriented\n### Investment knowledge management\nFor investment and research teams, AI is chipping away at the hunt for information.\nAnalysts and portfolio managers typically spend hours gathering documents and parsing filings.\nStill, firms are now deploying internal search and summarization tools that surface relevant content — from research notes and client decks to compliance filings and meeting transcripts.\nPlatforms like Rogo, Metal, and Reflexivity make proprietary knowledge searchable in natural language rather than buried in disparate drives.\n### Developer efficiency\nAI is changing how developers write and maintain code, from boilerplate generation to code conversion and documentation.\nMore AI-suggested code now reaches production, which is particularly useful in financial services, where many systems still rely on Common Business-Oriented Language (COBOL) and mainframes maintained by a shrinking pool of experts.\nAs a result, modernization is slow and risky.\nSwimm* and CoreStory help teams understand the business logic of code inside legacy systems.\n### Customer service\nAI is speeding up customer support by giving Agents access to internal documents, past interactions, and policy information, replacing time-consuming searches through PDFs and emails.\nLeaders say these tools don’t replace humans but make service faster and more consistent.\nWonderful*, for example, uses Agents to power voice and text support and is seeing early success in financial services, while Glia* applies AI to automate and analyze customer interactions across banks and credit unions.\nJump is vertically focused on financial advisors and uses AI to manage client conversations across onboarding and ongoing relationship needs.\n## Agentic adoption is early but expanding\nComfort with AI Agents varies, but many firms are exploring them.\nSome, like BNY, are running dozens of agentic workflows in production:\n> *“We have over 100 agentic digital employees doing everything from enhancing code to validating payment instructions.\nThis AI workforce allows for a different level of collaboration and productivity.”\n...\n*— Julie Gerdeman, Global Head of Data and Analytics at BNY*\nSome firms are piloting Agents internally but avoiding client-facing use, while more conservative institutions are holding back altogether due to regulatory concerns and Agent unpredictability.\nCrewAI*, Relevance AI*, and Tavily* all enable the orchestration and deployment of AI Agents.\nDespite differing comfort levels, Agents are now seen as the next phase of enterprise AI, and even hesitant firms are laying the groundwork for future use.\n## Business units drive strategy while the central org enables\nAcross most institutions, AI strategy is business-led, centrally governed.\nBusiness units identify use cases and set priorities, while the central technology teams manage vendors, negotiate contracts, and ensure firmwide standards are met:\n> *“Ideas need sponsorship from the business unit.\nEvery AI use case requires a clear business owner who partners with the central tech team to drive execution and implementation.”*\n*— Ericson Chan, CIO at Zurich Insurance*\nThis structure creates a necessary balance.\nIt gives front-line teams the ability to move quickly while keeping AI aligned with enterprise risk frameworks.\n...\nThe human side of AI adoption can sometimes prove harder than the technical one.\nDespite AI’s potential to streamline work, many employees don’t trust the tools, creating cultural resistance:\n...\nLeaders are responding with internal training, documentation, and AI literacy initiatives designed to show the goal of enhancing, not eliminating, human work.\n...\nCounterintuitively, the pace of AI innovation has made some technology leaders cautious.\nFirms worry about adopting a solution, embedding it across the organization, only to realize it’s obsolete just months later.\nAs a result, teams are wary of tools that create vendor lock-in and are piloting more options to avoid becoming dependent on any single provider.\n...\nFinancial institutions still lack the pipes to unify data across different systems:\n...\nMany banks still keep large volumes of untagged or on-premise data, meaning only a small share is truly AI-ready.\nData cleanup is time-consuming, and rising data volumes make the problem worse, paving the way for improvements throughout the data organization.\n...\nMany leaders now view stronger data hygiene as the essential prerequisite for unlocking AI’s potential.\n...\nFinancial institutions operate under heavy regulatory scrutiny, and uncertainty around LLM behavior makes compliance teams uneasy.\nBecause these systems are inherently nondeterministic, they don’t align easily with workflows that require consistent, auditable results.\nMost firms still lack standardized frameworks to assess accuracy, trace model reasoning, or measure performance against regulatory expectations.\nFiddler* and Arize improve transparency and auditability across AI/ML models.\nCymphony helps companies monitor how employees use data and tools, enabling them to prevent internal security risks as they adopt AI.\nAnd tools like Harmony provide proactive, intelligent IT management with built-in compliance controls, helping firms maintain auditable workflows as they use AI.\nUntil clearer rules and stronger control mechanisms emerge, governance will continue to define the speed and scope of AI adoption.\nAs AI becomes embedded in financial services, the real opportunity belongs to companies that can deliver practical, governed, and measurable value to institutions.",
        "title": "AI in financial services is here: How firms are adopting and where ...",
        "url": "https://www.insightpartners.com/ideas/ai-in-financial-services/",
        "date": "2025-12-12",
        "last_updated": "2026-05-19"
      },
      {
        "snippet": "",
        "title": "How artificial intelligence is reshaping the financial services industry",
        "url": "https://www.ey.com/en_gr/insights/financial-services/how-artificial-intelligence-is-reshaping-the-financial-services-industry",
        "date": "2024-11-12",
        "last_updated": "2026-05-19"
      },
      {
        "snippet": "",
        "title": "Top AI Trends Transforming Financial Services for 2026 - Keyrus",
        "url": "https://keyrus.com/us/en/insights/top-ai-trends-transforming-financial-services-for-2026",
        "date": null,
        "last_updated": "2026-05-24"
      },
      {
        "snippet": "",
        "title": "[PDF] Artificial Intelligence in Financial Services",
        "url": "https://reports.weforum.org/docs/WEF_Artificial_Intelligence_in_Financial_Services_2025.pdf",
        "date": null,
        "last_updated": "2026-05-17"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

**3. Government and Educational Sources (TLD Filtering)**

Use top-level domain filtering to search across all government or educational institutions:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Search all .gov and .edu domains
  response = client.search.create(
      query="climate change policy research",
      max_results=15,
      search_domain_filter=[
          ".gov",
          ".edu"
      ]
  )

  for result in response.results:
      print(f"{result.title}")
      print(f"Source: {result.url}")
      print("---")
  ```

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

  const client = new Perplexity();

  // Search all .gov and .edu domains
  const response = await client.search.create({
    query: "climate change policy research",
    max_results: 15,
    search_domain_filter: [
      ".gov",
      ".edu"
    ]
  });

  for (const result of response.results) {
    console.log(`${result.title}`);
    console.log(`Source: ${result.url}`);
    console.log("---");
  }
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "climate change policy research",
      "max_results": 15,
      "search_domain_filter": [
        ".gov",
        ".edu"
      ]
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "79bfb4ae-dc85-4d01-899b-bf241b9e6bb9",
    "results": [
      {
        "snippet": "*Climate Policy* aims to make high-quality research accessible and relevant to academics, and also to policymakers and practitioners.\nOur objective is to provide a platform for new ideas, innovative approaches and research-based insights that can help advance an effective response to climate change in practice.\nTo do so, the journal particularly seeks to highlight the policy implications of emergent research and analysis.\nAs an interdisciplinary journal, *Climate Policy* encourages submissions from all academic fields, but with a requirement that papers are written in an accessible style.\n*Climate Policy* welcomes submissions across a broad range of areas, including:\n· Mitigation and adaptation (beyond a focus on climate impacts alone) to climate change, loss and damage, climate change laws, technologies and innovations, institutions and governance at different scales, and climate finance\n· Design of climate-relevant policies and policy packages, implementation and evaluation of their impact on the ground, especially ex-post empirical assessment.\n· International climate negotiations and related international processes relevant to global climate governance, including linkages to geopolitics, trade and finance\n· Linkages to broader processes of structural change and transformation at regional, national and local levels, including low-emissions and climate-resilient development, sectoral transitions, and just transitions.\n· Please also look at the more detailed substantive criteria for consideration by\n*Climate Policy*.\n...\nTo promote independent commentary and debate,\n*Climate Policy* publishes papers in the following formats, all of which are peer reviewed and eligible for open access (see more information here):\n· Research articles present the latest research on all aspects of climate change policy (7,000 words)\n· Synthesis articles review the state of knowledge in key areas of interest (8,000 words).\n· Policy Analysis articles put forward evidence-based objective analysis of particular policy approaches (5,000 words)\n· Viewpoint articles offer rigorous insights and commentary on contemporary climate debates, including from practitioners and policymakers (3,000 words)\n...\nProspective authors are welcome to send short summaries of their work to the Editorial office for an opinion on its suitability for\n*Climate Policy*.\nThe Editorial Office may be contacted at editor@climatepolicyjournal.org.",
        "title": "Climate Policy | Journal | Taylor & Francis Online",
        "url": "https://www.tandfonline.com/journals/tcpo20",
        "date": "2025-08-04",
        "last_updated": "2025-08-05"
      },
      {
        "snippet": "Brazil, UNESCO and the UN have joined forces to strengthen research to counter narratives that are delaying and derailing urgently needed climate action.",
        "title": "ClimateChange - the United Nations",
        "url": "https://www.un.org/en/climatechange",
        "date": "2026-04-07",
        "last_updated": "2026-03-31"
      },
      {
        "snippet": "EPA is taking action to address some of our nation’s largest sources of both climate- and health-harming pollution, such as the transportation, oil and natural gas, and power sectors.\nEPA will continue to update this information as we move forward with new regulatory actions.\n...\nThe American Innovation and Manufacturing (AIM) Act of 2020 directs EPA to address HFCs by providing new authorities to phase down the production and consumption of listed HFCs, manage these HFCs and their substitutes, and facilitate the transition to next-generation technologies that do not rely on HFCs.\nOn September 23, 2021, EPA issued a final rule establishing the HFC Allocation program that will phase down the U.S. production and consumption of HFCs by 85% from historic levels by 2036, as mandated by the AIM Act.\nA global phasedown of HFCs is expected to avoid up to 0.5°C of global warming by 2100.\nThe Emissions Reduction & Reclamation program to manage HFCs and substitutes was established in October 2024.\nThe Technology Transitions program issued its first rule putting in place restrictions on HFCs in over 40 subsectors in October 2023.\n...\nOn December 20, 2021, EPA finalized federal greenhouse gas emissions standards for passenger cars and light trucks for Model Years (MY) 2023 through 2026.\nThe final standards leverage advances in clean car technology to unlock $190 billion in net benefits to Americans, including reducing climate pollution, improving public health, and saving drivers money at the pump.\nThese standards are the strongest vehicle emissions standards ever established for the light-duty vehicle sector, and are based on sound science and grounded in a rigorous assessment of current and future technologies.\nThe updated standards will result in avoiding more than 3 billion tons of GHG emissions through 2050.\n...\nEPA is implementing CO~2~ emission standards for airplanes used in commercial aviation and for large business jets.\n...\nEPA is also responsible for implementing the Renewable Fuels Standard Program, a national policy that requires a certain volume of renewable fuel to replace petroleum-based transportation fuel.\n...\nIn May 2024, EPA published final carbon pollution standards for power plants that set carbon dioxide (CO~2~) limits for new gas-fired combustion turbines and CO~2~ emission guidelines for existing coal, oil and gas-fired steam generating units, securing important climate benefits and protecting public health.",
        "title": "Climate Change Regulatory Actions and Initiatives | US EPA",
        "url": "https://www.epa.gov/climate-change/climate-change-regulatory-actions-and-initiatives",
        "date": "2021-06-11",
        "last_updated": "2026-03-31"
      },
      {
        "snippet": "Addressing the urgent challenges of climate change requires a concerted, coordinated effort among governments at the sub-national, national, regional, and global levels.\nIt also demands technological innovation to and understanding mitigation policies based on the latest research.\nIn addition, these innovations and cooperative global initiatives* * must be economically feasible.\nAll of which means that today’s leaders in government, industry, and other fields must develop policies that effectively blend insights into the science, economics, and politics of climate change.\n*Climate Change Policy: Economics and Politics * is an online executive program developed by Harvard Kennedy School faculty to address these challenges.\nLed by Faculty Chair Robert Stavins, Director of the Harvard Environmental Economics Program and the Harvard Project on Climate Agreements, this five-day interactive program is designed for managers, analysts, and leaders both inside and outside governments.\nTogether with a global cohort, you will explore the latest research, analytical tools, and conceptual frameworks to better understand climate-related policies.",
        "title": "Climate Change Policy: Economics and Politics",
        "url": "https://www.hks.harvard.edu/educational-programs/executive-education/climate-change-policy-economics-and-politics",
        "date": null,
        "last_updated": "2026-05-09"
      },
      {
        "snippet": "",
        "title": "A review of the global climate change impacts, adaptation ... - PMC",
        "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC8978769/",
        "date": "2022-04-04",
        "last_updated": "2026-03-30"
      },
      {
        "snippet": "",
        "title": "Climate policy conflict in the U.S. states: a critical review and way ...",
        "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC8853238/",
        "date": "2022-02-16",
        "last_updated": "2026-03-18"
      },
      {
        "snippet": "",
        "title": "Environmental justice and climate change policies - PMC - NIH",
        "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC9391311/",
        "date": "2022-04-30",
        "last_updated": "2026-04-18"
      },
      {
        "snippet": "- Climatic Change\nClimatic Change is an international, interdisciplinary journal dedicated to the totality of the problem of climatic variability and change - its descriptions, causes, implications and interactions among these.\n- Climate Policy\nA leading international peer-reviewed academic journal, publishing on all aspects of climate change policy, including adaptation and mitigation, governance and negotiations, policy design, implementation and impact, and the full range of economic, social and political issues at stake in responding to climate change.\n- Environmental Research Letters\nCovers all areas of environmental science, providing a coherent and integrated approach including research articles, perspectives and review articles.\n- Nature\nWeekly international journal publishing peer-reviewed research in all fields of science and technology.\nNature also provides news and interpretation of topical and coming trends affecting science, scientists and the wider public.\n- WIREs Climate Change\nA forum to promote cross-disciplinary discussion of a global phenomenon with long-term societal implications, and and provides an important new encyclopedic reference for climate change scholarship and research.\n...\nThese books and many more are available at the Dag Hammarskjöld Library.\n...\nThis report analyzes international experience to identify effective pathways to coherent policy packages that harness synergies and manage tensions between climate mitigation and air-quality management.",
        "title": "Research Guides: Climate Change - A Global Issue: Books & Journals",
        "url": "https://research.un.org/en/climate-change/books",
        "date": "2014-08-19",
        "last_updated": "2026-03-28"
      },
      {
        "snippet": "## Why is it important?\niPolicymakers need to be informed about the state of the climate, how human activity is affecting it, and the possible future outcomes that we might experience.\nRigorous policymaking requires a robust scientific evidence base, which climate scientists can help to deliver.\n## What are we doing?haOur work helps to ensure that policymakers have access to up-to-date scientific evidence and expertise on the Earth’s climate system and how humans are impacting it.\nThis includes the latest understanding on: the level of greenhouse gases in the atmosphere; how this will affect global temperatures; what impacts are likely to occur in future (such as extreme weather and sea level rise); and the extent to which human-caused climate change is already making extreme weather more likely and intense.\n...\n### Policy briefing: Earth Systems Insights SThis policy briefing draws on work from six projects: ESM2025, ClimTip, TipESM, OptimESM, nextGEMS, and RESCUE, which\nall conduct policy-relevant climate change research using Earth Systems Models, in particular in relation to the Paris Agreement.\n...\nContact:\nJenny Bird\nCampaign Manager\nj.bird@imperial.ac.uk\n## Further resources",
        "title": "Climate science for policymakers - Imperial College London",
        "url": "https://www.imperial.ac.uk/grantham/policy/climate-science-for-policymakers/",
        "date": "2024-08-27",
        "last_updated": "2026-05-09"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

**4. Wikipedia Across Languages (Subdomain Matching)**

Search across all Wikipedia language editions by specifying the root domain:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Matches en.wikipedia.org, fr.wikipedia.org, de.wikipedia.org, etc.
  response = client.search.create(
      query="quantum mechanics fundamentals",
      max_results=10,
      search_domain_filter=["wikipedia.org"]
  )

  for result in response.results:
      print(f"{result.title}")
      print(f"URL: {result.url}")
      print("---")
  ```

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

  const client = new Perplexity();

  // Matches en.wikipedia.org, fr.wikipedia.org, de.wikipedia.org, etc.
  const response = await client.search.create({
    query: "quantum mechanics fundamentals",
    max_results: 10,
    search_domain_filter: ["wikipedia.org"]
  });

  for (const result of response.results) {
    console.log(`${result.title}`);
    console.log(`URL: ${result.url}`);
    console.log("---");
  }
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "quantum mechanics fundamentals",
      "max_results": 10,
      "search_domain_filter": ["wikipedia.org"]
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "dd3d8ff9-e837-4413-9628-80a1c8dba4f6",
    "results": [
      {
        "snippet": "",
        "title": "Quantum mechanics - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Quantum_mechanics",
        "date": "2001-11-14",
        "last_updated": "2026-05-20"
      },
      {
        "snippet": "Quantum mechanics is the field of physics that explains how extremely small objects simultaneously have the characteristics of both particles (tiny pieces of matter) and waves (a disturbance or variation that transfers energy).\nPhysicists call this the “wave-particle duality.”\nThe particle portion of the wave-particle duality involves how objects can be described as “quanta.”\nA quanta is the smallest discrete unit (such as a particle) of a natural phenomenon in a system where the units are in a bound state.\nFor example, a quanta of electromagnetic radiation, or light, is a photon.\nA bound state is one where the particles are trapped.\nOne example of a bound state is the electrons, neutrons, and protons that are in an atom.\nTo be “quantized” means the particles in a bound state can only have discrete values for properties such as energy or momentum.\nFor example, an electron in an atom can only have very specific energy levels.\nThis is different from our world of macroscopic particles, where these properties can be any value in a range.\nA baseball can have essentially any energy as it is thrown, travels through the air, gradually slows down, then stops.\nAt the same time, tiny quantized particles such as electrons can also be described as waves.\nLike a wave in the ocean in our macroscopic world – the world we can see with our eyes -- waves in the quantum world are constantly shifting.\nIn quantum mechanics, scientists talk about a particle’s “wave function.”\nThis is a mathematical representation used to describe the probability that a particle exists at a certain location at a certain time with a certain momentum.\nThe world of quantum mechanics is very different from how we usually see our macroscopic world, which is controlled by what physicists call classical mechanics.\n...\n- Many subatomic particles, including the proton, have angular momentum, which is often referred to as “spin.”\nMedical experts use this property in MRI imaging devices.\n- Smartphones contain billions of transistors that work based on the wave nature of electrons, which scientists understand through quantum mechanics.\n- Quantum computers and quantum networks are new applications of quantum mechanics that use the quantized nature of particles to store and transfer information.",
        "title": "DOE Explains...Quantum Mechanics - Department of Energy",
        "url": "https://www.energy.gov/science/doe-explainsquantum-mechanics",
        "date": "2026-05-14",
        "last_updated": "2026-05-18"
      },
      {
        "snippet": "",
        "title": "Introduction to quantum mechanics - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Introduction_to_quantum_mechanics",
        "date": "2005-09-29",
        "last_updated": "2026-05-18"
      },
      {
        "snippet": "",
        "title": "The Basics of Quantum Mechanics",
        "url": "https://thequantumlaend.de/basic-tutorial/",
        "date": null,
        "last_updated": "2026-05-26"
      },
      {
        "snippet": "## Quantum mechanics explores the fundamental nature of matter and energy at the smallest scales.\nKey concepts include quantised particles and probabilistic wave functions, as governed by the Schrödinger equation.\nNotable principles of quantum mechanics, such as wave-particle duality and the uncertainty principle, challenge classical physics.\nQuantum phenomena like tunnelling and entanglement enable groundbreaking technologies, including quantum computing and cryptography.\nThe origins of quantum theory can be traced back to pivotal contributions by Max Planck, Albert Einstein, and others.\n...\nQuantum physics, the branch of science that investigates the behaviour of matter and energy at the smallest scales, introduces a groundbreaking framework where classical mechanics no longer apply.\nAt the core of this field lies the concept of quantisation, where particles such as electrons are described by discrete packets referred to as quanta.\nThese quantum objects are governed by probabilistic wave functions and the Schrödinger equation, allowing them to exist in multiple states simultaneously—an idea recognised as superposition.\nOne of the intriguing phenomena in quantum physics is quantum tunnelling, where particles pass through potential barriers that would be insurmountable in classical physics.\n...\nQuantum decoherence describes the process by which a quantum system loses its superposition state due to interaction with its environment, shifting it to a classical state.\nThis phenomenon is a significant challenge in the development of quantum computing, where maintaining coherence is essential for performing calculations that far exceed the capabilities of classical computers.\nQuantum teleportation, another fascinating concept, involves the transfer of quantum information between particles over distance, leveraging the phenomenon of entanglement.\n...\nThese collective efforts culminated in the formulation of quantum mechanics, a probabilistic framework that profoundly altered our understanding of particle behaviour and interactions at the microscopic level.\n...\nOne of the most intriguing aspects of quantum mechanics is wave-particle duality, which posits that particles such as electrons exhibit both wave-like and particle-like properties.\nThis concept challenges the classical physics paradigm by demonstrating that particles can exhibit wave characteristics, such as interference patterns, a phenomenon traditionally attributed solely to waves.\n...\nSuperposition and entanglement are cornerstones of quantum mechanics.\nThey present phenomena that defy classical intuition and underpin the field’s most revolutionary advancements.\nIn quantum physics, superposition refers to the ability of quantum particles to exist in multiple states simultaneously.\nThis property is pivotal in quantum computing, where quantum bits, or qubits, harness superposition to perform complex computations in parallel, leading to exponential speedups in solving certain problems compared to classical computers.\nQuantum entanglement, another fundamental concept, occurs when particles become interconnected in such a way that the state of one particle instantly influences the state of another, regardless of the distance separating them.\nThis phenomenon, known as quantum entanglement, is instrumental in the development of quantum communication and quantum information processing.\n...\nThe Schrödinger Equation stands as a cornerstone in quantum mechanics, offering a profound mathematical framework for understanding the dynamic behaviour of quantum systems.\n...\nAt the heart of the Schrödinger Equation is the concept of the wave function.\n...\nThe Uncertainty Principle, a cornerstone of quantum mechanics formulated by Werner Heisenberg, delineates the fundamental limitations in simultaneously measuring certain pairs of complementary properties, such as a particle’s position and momentum, with arbitrary precision.\nThis principle underscores the quantum uncertainty inherent in particle dynamics, challenging the classical physics notion that such properties can be measured with exactitude.\nHeisenberg’s principle asserts that the more precisely one knows a particle’s position, the less precisely one can know its momentum, and vice versa.\n...\nConsequently, any attempt to measure one property with high precision inevitably disturbs the other, introducing an intrinsic quantum uncertainty.\nAt its core, the Uncertainty Principle fundamentally alters our understanding of predictability and measurability at the quantum level.\nIt implies that there is a limit to the precision with which we can simultaneously know a particle’s position and momentum.\nThis limit is not due to experimental imperfections but a fundamental property of nature itself, rooted in the principles of quantum mechanics.\n...\nQuantum physics fundamentally challenges classical conceptions of reality by introducing phenomena such as superposition, wave-particle duality, and probabilistic behaviour.",
        "title": "Exploring the key concepts of quantum mechanics",
        "url": "https://www.innovationnewsnetwork.com/exploring-the-key-concepts-of-quantum-mechanics/51254/",
        "date": "2024-10-14",
        "last_updated": "2026-02-18"
      },
      {
        "snippet": "Quantum mechanics was developed in just two years, 1925 and 1926 (see here if you want to know why).\nThere were initially two versions, one formulated by Werner Heisenberg and one by Erwin Schrödinger.\n...\nDe Broglie figured that\nwhat goes for light might go for matter too: perhaps tiny\nbuilding blocks of matter, such as electrons, might also suffer from this\n*wave particle duality*.\n...\nOrdinary waves, such as those that can travel down a piece of\nstring, can be described mathematically.\nYou can formulate a\n*wave\nequation*, which describes how a particular wave\nchanges over space and time.\nA solution to that equation is a *wave\nfunction*, which describes the shape of the wave at every point in\ntime.\n...\nA solution to Schrödinger's equation is called a\n*wave\nfunction*.\nIt tells you things about the *quantum system* you\nare considering.\n...\nAs an example, imagine a single particle moving around in a closed box.\nSolving the wave equation which\ndescribes this system, you get the corresponding wave function.\nOne\nthing the wave function doesn't tell you is where exactly the particle\nwill be at each point in time of its journey.\n...\nWhat the wave function does give you is a number (generally a\n*complex number*) for each\npoint *x* in the box at each point *t* in time of the particle's journey.\nIn\n1926 the physicist Max Born came up with an interpretation of this\nnumber: after a slight modification, it gives you the probability of\nfinding the particle at the point *x* at time *t*.\nWhy\na probability?\nBecause unlike an ordinary billiard ball, which obeys the\nclassical laws of physics, our particle doesn't have a clearly defined trajectory that leads it to a particular point.\nWhen we open the box and look, we *will*\nfind it at one particular point, but there's no way of predicting in\nadvance which one it is.\nAll we have are probabilities.\nThat's the\nfirst strange prediction of the theory: the world, at bottom, is not\nas certain as our everyday experience of billiard balls has us\nbelieve.\nA second strange prediction follows straight on from the first.\nIf we don't open the box and spot the particle in a particular location, then where is it?\nThe answer is that it's in all the places we could have potentially seen it in at once.\n...\nSuppose you have found a wave function that is a solution to Schrödinger's\nequation and describes our particle being in some location in the box.\nNow there might be another wave function\nwhich is also a solution to the same equation, but describes the\nparticle being in another part of the box.\nAnd here's the thing: if\nyou add these two different wave functions, the sum is also a\nsolution!\nSo, if the particle being in one place is a solution and the\nparticle being in another place is a solution, then the particle being in the first place and the second place is also a solution.\nIn this sense, the particle can\nbe said to be in several places at once.\nIt's called\n*quantum\nsuperposition* (and it's the inspiration for Schrödinger's famous thought experiment involving a cat).\n...\nAs we have seen, it's impossible to\npredict where\nour particle in the box is going be when we measure\nit.\nThe same goes for any other thing you might want to measure about the particle, for example its momentum: all you can do is work out the probability that the momentum takes each of several possible values.\nTo work out from the wave function what those possible values of position and momentum are, you need mathematical objects called\n*operators*.\n...\nWhen we have performed the measurement, say of position, the particle is most\ndefinitely in a single place.\nThis means that its wave function has\nchanged (collapsed) to a wave function describing a particle that is\ndefinitely in one particular place with 100% certainty.\n...\nIf you were to measure momentum and position simultaneously, and get certain answers for both, then the two eigenstates corresponding to position and momentum would have to be the same.\nIt's a mathematical fact, however, that the eigenstates of these two operators never do coincide.\nJust as 3+2 will never make 27, so don't the mathematical operators corresponding to position and momentum behave in a way that would allow them to have coinciding eigenstates.\nTherefore, position and momentum can never be measured simultaneously with arbitrary accuracy.\n(For those familiar with some of the technicalities, the eigenstates cannot be the same because the operators don't commute.)\nAs we know from experience, superposition disappears when we look\nat a particle.\nNobody has ever directly seen a single particle in several places at once.\n...\nAnother thing that comes straight out of the maths of Schrödinger's equation is\nHeisenberg's famous\n*uncertainty principle*.\nThe principle says that\nyou can never, ever measure both the position and the momentum of\na quantum object, like our particle in a box, with arbitrary precision.\nThe\nmore precise you are about the one, the less you can say about the\nother.\nThis isn't because your measurement tools aren't good enough —\nit's a fact of nature.\n...\nPosition and momentum aren't the only\n*observables* that\ncan't be measured simultaneously with arbitrary accuracy.\nTime and\nenergy are another pair: the more precise you are about the time span\nsomething happens in the less precise you can be about the energy of\nthat something and vice versa.\nFor this reason, particles can acquire\nenergy from out of nowhere for very brief moments of time, something\nthat's impossible in ordinary life — it's called *quantum\n...\nAnd here's another quantum strangeness arising from the wave\nfunction:\n*entanglement*.\nA wave function can also describe a\nsystem of many particles.\nSometimes it is impossible to decompose the\nwave function into components that correspond to the individual\nparticles.\nWhen that happens, the particles become inextricably\nlinked, even if they move far away from each other.\nWhen something happens to one of the entangled particles, a corresponding thing happens to its distant partner, a phenomenon Einstein described as \"spooky action at a distance\".",
        "title": "Introduction to Quantum Mechanics",
        "url": "https://plus.maths.org/content/ridiculously-brief-introduction-quantum-mechanics",
        "date": "2025-01-01",
        "last_updated": "2026-02-28"
      },
      {
        "snippet": "",
        "title": "Quantum Physics Full Course | Quantum Mechanics Course",
        "url": "https://www.youtube.com/watch?v=hyctIDPRSqY",
        "date": "2021-10-21",
        "last_updated": "2026-03-26"
      },
      {
        "snippet": "In this chapter we summarize the main elements of non-relativistic quantum mechanics.\nWe will do so through a list of postulates and principles that can be followed for the\napplication of the quantum mechanical formalism to specific problems.\n...\n1.1.1 First Postulate\nAt a given time t, the physical state of a system is described by a ket |ψ (t)⟩(using\n…\nd3x ϕ∗(x) χ (x) ,\n(1.2)\nwhere ∗stands for complex conjugation.\nSecond, to the ket |r⟩is associated a Dirac\ndistribution\n|r⟩⇐⇒δ (x −r) ,\n(1.3)\nsuch that\n⟨r | ψ (t)⟩\n=\n�∞\n−∞\nd3x δ (x −r) ψ (x, t)\n≡\nψ (r, t)\n(1.4)\n1\n…\n...\n.\n(1.5)\n1.1.2 Second Postulate\nFor every measurable physical quantity A corresponds an operator ˆA, and this operator\n…\n(1.7)\nwith ˆA† the adjoint of ˆA and, by definition, (|ψ⟩)† = ⟨ψ|.\n1.1.3 Third Postulate\nThe outcome of the measurement of a physical quantity A must be an eigenvalue of the\ncorresponding observable ˆA.\n…\n...\n1.1.4 Fourth Postulate\nThe ket, say |ψ (t)⟩, specifying the state of a system is assumed normalized to unity.\nThat is,\n⟨ψ (t) | ψ (t)⟩= 1.\n(1.10)\n…\n...\ndefinitions, we can state the fourth postulate of quantum mechanics as follows:\nIn measuring the physical quantity A on a system in the state |ψ⟩, the probability of\nobtaining the (possibly degenerate) eigenvalue “a” of the corresponding observable is\nP (a) =\ngn\n�\n…\n...\nThis postulate\nsimply ensures that the new ket (or wave function) describing the system after a mea-\nsurement is suitably normalized to unity.\n...\nAlthough it is possible to give a “derivation” of the Schrödinger equation, it is sufficient\nfor our purposes to introduce it as the sixth, and last, postulate of quantum mechanics:\nThe time evolution of the state vector of a system is dictated by the Schrödinger equa-\ntion\niℏd\ndt |ψ (t)⟩= ˆH (t) |ψ (t)⟩,\n(1.52)\nwhere ˆH (t) is the Hamiltonian of the system, i.e., the observable associated with the\nenergy of the system.\nIn most cases, we will be dealing with a time-independent Hamiltonian that has so-\ncalled stationary states whose norms do not change as a function of time (see below).\n...\nA few principles need to be added to the previous postulates in order to use the formalism\nof quantum mechanics to make predictions on experiments, and to ensure that it is\n...\n1.2.1 The Principle of Superposition\nWe already know that the state of a quantum mechanical system is entirely contained\nwithin a ket, say, ϕ1, which can be a function of time.\nIt may be the case, however,\nthat several different states ϕj, with j = 1, 2, . . . , n, are available for the system.\nThe\nPrinciple of Superposition then states that\nIf several states are available for a quantum mechanical system, then it can also be in\nany possible linear combinations of them.\nIn mathematical terms this means that the most general form for the state ψ of the\nsystem is given by\nψ =\nn\n�\nj=1\ncj |ϕj⟩\n(1.60)\nwhere cj = ⟨ϕj | ψ⟩are complex coefficients.\n...\nThe superposition of states is responsible for the presence of interference (and coherence)\nin quantum mechanical systems.\nThis experimental fact can be understood if one accepts\n...\nThis was\nfirst made explicit by Bohr when he enunciated his Principle of Complementarity,\nwhich can be stated as follows1\nIt is not possible to describe physical observables simultaneously and completely in terms\nof particles and waves.\nWhat this principle implies is that attempts to acquire knowledge on the state of a\nsystem (e.g., the path a particle takes) cannot be accomplished without disturbing it\nand changing its state.\nIn other word, the interference that would be detected for the\nundisturbed system (i.e., the wave-like behaviour) will be affected by the act of acquiring\ninformation on its state.\n...\nAlthough the picture of the microscopic world provided by quantum mechanics is often\ncompletely at odds with what we would expect on large scales with classical mechanics, it\nmust be that the two realms are consistent with one another and come to an agreement\n...\nImportantly, predictions made with quantum mechanics\nmust agree with those of classical mechanics in conditions where the applicability of the\nlatter is warranted.\nThis requirement is formulated through Bohr’s Correspondence\nPrinciple\nQuantum mechanical physical quantities should tend to the classical mechanical coun-\nterparts in the macroscopic limit.\nMathematically, the macroscopic limit is reached when the Planck constant h is negli-\ngible compared to the action of the system2.\nIn such cases, quantum mechanical effects\nand phenomena have no consequence on the behaviour of the system.\n...\nWe therefore find the fundamental result that the action of the momentum operator in\nthe position basis {|r⟩} is represented by\nˆp ⇒−iℏ∇.",
        "title": "[PDF] 1 Fundamentals of Quantum Mechanics",
        "url": "https://physics.uwo.ca/~mhoude2/courses/PDF%20files/physics9203/Ch1-Fundamentals.pdf",
        "date": null,
        "last_updated": "2026-04-12"
      },
      {
        "snippet": "1st Edition\n# Quantum Mechanics Fundamentals\nBy Kurt Gottfried Copyright 1974\n528 Pages\nby CRC Press\n...\nThis book contains discussions of radiation theory, quantum statistics and the many-body problem, and more advanced topics in collision theory.\nIt is intended as a text for a first-year graduate quantum mechanics course.",
        "title": "Quantum Mechanics: Fundamentals",
        "url": "https://www.routledge.com/Quantum-Mechanics-Fundamentals/Gottfried/p/book/9780201406337",
        "date": null,
        "last_updated": "2024-08-02"
      },
      {
        "snippet": "",
        "title": "[PDF] Fundamentals of Quantum Mechanics",
        "url": "http://iht.knu.ua/Kolezhuk/SelChapPhys/Tang.pdf",
        "date": null,
        "last_updated": "2026-04-22"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

**5. Filter to a Section of a Site**

Restrict results to a specific path on a domain — useful for documentation sites, subreddits, blogs, or news sections:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Only results under nature.com/articles
  response = client.search.create(
      query="CRISPR base editing clinical results",
      max_results=10,
      search_domain_filter=["nature.com/articles"]
  )

  for result in response.results:
      print(f"{result.title}: {result.url}")
  ```

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

  const client = new Perplexity();

  // Only results under nature.com/articles
  const response = await client.search.create({
    query: "CRISPR base editing clinical results",
    max_results: 10,
    search_domain_filter: ["nature.com/articles"]
  });

  for (const result of response.results) {
    console.log(`${result.title}: ${result.url}`);
  }
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "CRISPR base editing clinical results",
      "max_results": 10,
      "search_domain_filter": ["nature.com/articles"]
    }' | jq
  ```
</CodeGroup>

**6. Denylist Specific Domains**

This example shows how to exclude specific domains from search results by prefixing the domain name with a minus sign (`-`):

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Exclude social media and Q&A sites from search results
  response = client.search.create(
      query="renewable energy capacity additions and grid storage breakthroughs",
      max_results=10,
      search_domain_filter=[
          "-pinterest.com",
          "-reddit.com",
          "-quora.com"
      ]
  )

  for result in response.results:
      print(f"{result.title}: {result.url}")
  ```

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

  const client = new Perplexity();

  // Exclude social media and Q&A sites from search results
  const response = await client.search.create({
    query: "renewable energy capacity additions and grid storage breakthroughs",
    max_results: 10,
    search_domain_filter: [
      "-pinterest.com",
      "-reddit.com",
      "-quora.com"
    ]
  });

  for (const result of response.results) {
    console.log(`${result.title}: ${result.url}`);
  }
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "renewable energy capacity additions and grid storage breakthroughs",
      "max_results": 10,
      "search_domain_filter": [
        "-pinterest.com",
        "-reddit.com",
        "-quora.com"
      ]
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "5764c1f5-c71d-4e0f-94cb-d02f7c2f1af8",
    "results": [
      {
        "snippet": "U.S. power plant developers and operators plan to add 86 gigawatts (GW) of new utility-scale electric generating capacity to the U.S. power grid in 2026 in our latest Preliminary Monthly Electric Generator Inventory report, a record if realized.\nSolar power makes up 51% of the planned 2026 capacity additions, followed by battery storage at 28% and wind at 14%.\nIn 2025, 53 GW of new capacity was added to the grid, the largest capacity installation in a single year since 2002.\nSolar.\nWe expect 2026 to be another big year for solar additions, similar to the record utility-scale solar capacity added to the U.S. grid in 2024 (30.8 GW) and in 2025 (27.2 GW).\nDevelopers plan to add 43.4 GW of new utility-scale solar capacity in 2026, a 60% increase in capacity additions from last year if realized.\nMore than half of the new utility-scale solar capacity is planned for four states: Texas (40%), Arizona (6%), California (6%), and Michigan (5%).\nA new project, Tehuacana Creek 1 Solar and BESS, adding 837 megawatts (MW) in Texas, is the largest solar photovoltaic project expected to come online in 2026; it will also offer an additional 418 MW in battery energy storage capacity.\nBattery storage.\nDevelopers plan to add 24 GW of utility-scale battery storage to the grid this year, compared with a record 15 GW added in 2025.\nU.S. battery storage capacity has grown exponentially over the last five years with more than 40 GW added to the grid during this period.\nProjects in three states make up the bulk of planned battery storage capacity in 2026, accounting for about 80% of the new U.S. battery storage capacity: 53%, or 12.9 GW, in Texas; 14%, or 3.4 GW, in California; and 13%, or 3.2 GW, in Arizona.\nThree of the four largest battery storage projects scheduled to come online in 2026 are in Texas:\nWind.\nAnnual U.S. wind capacity additions have slowed, following record additions of more than 14 GW in both 2020 and 2021.\nBut wind capacity addition could rise in 2026 with 11.8 GW planned to be added to the grid, more than double the capacity added last year.\nNew Mexico, Texas, Illinois, and Wyoming combined will account for almost 60% of 2026 wind capacity additions.\nTwo large offshore wind plants, the 800-MW Vineyard Wind 1 in Massachusetts and the 715-MW Revolution Wind in Rhode Island, which the companies now plan to bring online in 2026 after delays.\nThe 3,650-MW SunZia Wind project in New Mexico is also expected to start commercial operations this year and will be the largest onshore wind project in the United States.",
        "title": "New U.S. electric generating capacity expected to reach a record high in ...",
        "url": "https://www.eia.gov/todayinenergy/detail.php?id=67205",
        "date": "2026-05-21",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "",
        "title": "[PDF] Progress in Grid Energy Storage",
        "url": "https://www.energy.gov/sites/prod/files/Presentation%20to%20the%20EAC%20-%20Progress%20in%20Grid%20Energy%20Storage%20-%20Imre%20Gyuk.pdf",
        "date": null,
        "last_updated": "2026-03-11"
      },
      {
        "snippet": "We expect 63 gigawatts (GW) of new utility-scale electric-generating capacity to be added to the U.S. power grid in 2025 in our latest Preliminary Monthly Electric Generator Inventory report.\nThis amount represents an almost 30% increase from 2024 when 48.6 GW of capacity was installed, the largest capacity installation in a single year since 2002.\nTogether, solar and battery storage account for 81% of the expected total capacity additions, with solar making up over 50% of the increase.\nSolar.\nIn 2024, generators added a record 30 GW of utility-scale solar to the U.S. grid, accounting for 61% of capacity additions last year.\nWe expect this trend will continue in 2025, with 32.5 GW of new utility-scale solar capacity to be added.\nTexas (11.6 GW) and California (2.9 GW) will account for almost half of the new utility-scale solar capacity addition in 2025.\nWe expect five other states (Indiana, Arizona, Michigan, Florida, and New York) each to account for more than 1 GW of added solar capacity in 2025 and collectively account for 7.8 GW of planned solar capacity additions.\nBattery storage.\nIn 2025, capacity growth from battery storage could set a record as we expect 18.2 GW of utility-scale battery storage to be added to the grid.\nU.S. battery storage already achieved record growth in 2024 when power providers added 10.3 GW of new battery storage capacity.\nThis growth highlights the importance of battery storage when used with renewable energy, helping to balance supply and demand and improve grid stability.\n...\nWind.\nIn 2025, we expect 7.7 GW of wind capacity to be added to the U.S. grid.\nLast year, only 5.1 GW was added, the smallest wind capacity addition since 2014.\nTexas, Wyoming, and Massachusetts will account for almost half of 2025 wind capacity additions.\nTwo large offshore wind plants are expected to come online this year: the 800-megawatt (MW) Vineyard Wind 1 in Massachusetts and the 715-MW Revolution Wind in Rhode Island.",
        "title": "Solar, battery storage to lead new U.S. generating capacity additions ...",
        "url": "https://www.eia.gov/todayinenergy/detail.php?id=64586",
        "date": "2026-05-14",
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "# US$ 1.2 trillion in battery storage investments needed to support global renewable buildoutt\nGrid-forming battery technology emerges as critical solution for US$5 trillion global renewable energy integration\n...\nInvestments of US$1.2 trillion in battery energy storage systems (BESS) will be required to support the installation of over 5,900 GW (Gigawatt) of new wind and solar capacity globally through 2034, according to Wood Mackenzie.\nThe deployment of grid-forming technology (GFM) needs to accelerate over the next decade to facilitate the projected $5 trillion global expansion of renewable energy.\nUnlike traditional grid-following systems that simply respond to grid conditions, grid-forming battery energy storage systems can actively create and maintain grid stability.\nThis capability becomes essential as renewable energy becomes the dominant source of power generation globally.\n“Grid-forming battery energy storage systems represent a critical breakthrough for renewable energy integration,” said Robert Liew, research director at Wood Mackenzie.\n“As global power demand is projected to surge 55% by 2034, with variable renewable energy comprising over 80% of new capacity additions, GFM BESS provides the technological bridge between renewable abundance and grid stability requirements.”\n...\nAccording to a recent Wood Mackenzie report, the global power sector faces a capacity gap of 1,400 GW for additional battery energy storage installations utilising GFM for grid stability between 2024 to 2034.\n...\nWhile grid-forming capabilities add an estimated 15% to overall system costs largely due to upgraded inverters, controls, and software, these cost hurdles are becoming more manageable as average battery energy storage prices have declined between 10% and 40% across global markets in the past year, according to Wood Mackenzie.\n...\nWith global electricity demand forecast to grow at a compound annual rate of 3% through 2040, according to Wood Mackenzie, grid-forming batteries are emerging as a practical replacement for conventional synchronous generators.\nTheir ability to provide voltage and frequency stability is positioning them as a foundational technology for high-renewable power systems.\n“We’re seeing a convergence of key factors, declining battery costs, stronger clean energy targets, supportive policy developments, and proven pilot projects, that are accelerating the adoption of grid-forming technology,” said Liew.\n“With global battery capacity expected to triple by 2035, grid-forming capabilities will likely become a baseline requirement for new storage deployments.\nThis will be essential not only for grid reliability, but also for unlocking the full value of renewable energy investments at scale.”",
        "title": "US$ 1.2 trillion in battery storage investments needed to support ...",
        "url": "https://www.woodmac.com/press-releases/bess-opportunity/",
        "date": "2025-07-02",
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "According to data from the Federal Energy Regulatory Commission, renewable energy sources will account for 99% of all new electricity generating capacity added to the American grid in 2026, marking what industry experts describe as a fundamental restructuring of the nation’s power infrastructure.\nThis near-total dominance of clean energy in new capacity additions represents a dramatic acceleration from previous years and signals that the transition away from fossil fuel generation has moved beyond policy aspirations into market reality.\nSlashdot reported that solar power alone will contribute 76.9 gigawatts of new capacity, while wind energy will add another 15.2 gigawatts, with battery storage systems providing an additional 33.8 gigawatts to support grid stability.\n...\nNatural gas, which once represented the bridge fuel to a cleaner energy future, will account for merely 1% of new capacity additions this year, with a paltry 1.1 gigawatts of new plants coming online.\n...\nThe shift toward renewable dominance stems primarily from fundamental economics rather than regulatory mandates.\nSolar panel costs have plummeted approximately 90% since 2010, while wind turbine efficiency has improved dramatically through technological advances in blade design and tower height.\nBattery storage costs have followed a similar trajectory, dropping roughly 80% over the past decade, making it economically viable to pair intermittent renewable sources with storage systems that can dispatch power when the sun isn’t shining or wind isn’t blowing.\n...\nThe rapid expansion of variable renewable energy sources has forced grid operators to fundamentally rethink how they manage electricity supply and demand.\n...\nBattery storage systems have emerged as the critical technology enabling this transition.\nThe 33.8 gigawatts of storage capacity being added in 2026 will provide grid operators with unprecedented flexibility to absorb excess renewable generation during periods of high production and release that stored energy during peak demand periods.\n...\nIndustry analysts project that renewable energy’s dominance of new capacity additions will continue and likely intensify in coming years.\n...\nThe United States is in the midst of the most significant transformation of its electricity infrastructure since the original grid buildout in the early twentieth century, and renewable energy has emerged as the dominant force shaping that transformation.",
        "title": "How Renewable Energy Seized 99% of New Capacity ...",
        "url": "https://www.webpronews.com/americas-grid-transformation-how-renewable-energy-seized-99-of-new-capacity-additions-in-2026/",
        "date": "2026-02-02",
        "last_updated": "2026-02-24"
      },
      {
        "snippet": "New Delhi: Global investment of $1.2 trillion will be required in\nbattery energy storage systems\n(BESS) over the next decade to support the addition of 5,900 gigawatts (GW) of new wind and solar capacity worldwide, energy consultancy Wood Mackenzie said in its latest analysis.\nThe report forecasts a 55 per cent increase in\nglobal power demand by 2034\n, with more than 80 per cent of new capacity additions expected to come from variable renewable energy sources.\n'Grid-forming battery energy storage systems represent a critical breakthrough for\nrenewable energy integration\n,' Robert Liew, Research Director at Wood Mackenzie, said.\n'As global power demand is projected to surge 55 per cent by 2034, with variable renewable energy comprising over 80 per cent of new capacity additions, GFM BESS provides the technological bridge between renewable abundance and\ngrid stability requirements\n.'\nGrid-forming battery systems differ from traditional grid-following systems by actively supporting voltage and frequency stability, which is essential as the share of intermittent renewable sources increases.\nAccording to the report, the power sector faces a 1,400 GW capacity gap for\ngrid-forming battery storage\ninstallations between 2024 and 2034. This shortfall highlights the need for large-scale deployment of storage systems to ensure grid reliability.\n...\nWhile grid-forming capabilities add about 15 per cent to system costs, primarily due to advanced inverters and software, battery prices have declined by 10–40 per cent across global markets over the past year. The report said this has improved the economic feasibility of such installations.\nHybrid utility-scale solar and battery storage systems are already cost-competitive with onshore wind, and projections suggest that battery systems will undercut coal and gas power generation costs in several non-US markets by 2040.\n...\n'Increasing\nclean energy targets\n, policy developments, and proven pilot projects are accelerating the adoption of grid-forming technology,' Liew added. 'With global battery capacity expected to triple by 2035, grid-forming capabilities will likely become a baseline requirement for new storage deployments.'",
        "title": "$1.2 trillion needed for grid-forming battery storage to support global renewable push: Report",
        "url": "https://energy.economictimes.indiatimes.com/news/renewable/1-2-trillion-needed-for-grid-forming-battery-storage-to-support-global-renewable-push-report/122195907",
        "date": "2025-07-02",
        "last_updated": "2025-07-02"
      },
      {
        "snippet": "# $1.2 trillion needed for grid-forming battery storage to support global renewable push: Report\n...\nNew Delhi: Global investment of $1.2 trillion will be required in battery energy storage systems (BESS) over the next decade to support the addition of 5,900 gigawatts (GW) of new wind and solar capacity worldwide, energy consultancy Wood Mackenzie said in its latest analysis.\n...\n“Grid-forming battery energy storage systems represent a critical breakthrough for renewable energy integration,” Robert Liew, Research Director at Wood Mackenzie, said.\n“As global power demand is projected to surge 55 per cent by 2034, with variable renewable energy comprising over 80 per cent of new capacity additions, GFM BESS provides the technological bridge between renewable abundance and grid stability requirements.”\nGrid-forming battery systems differ from traditional grid-following systems by actively supporting voltage and frequency stability, which is essential as the share of intermittent renewable sources increases.\nAccording to the report, the power sector faces a 1,400 GW capacity gap for grid-forming battery storage installations between 2024 and 2034.\nThis shortfall highlights the need for large-scale deployment of storage systems to ensure grid reliability.\n...\n“With global battery capacity expected to triple by 2035, grid-forming capabilities will likely become a baseline requirement for new storage deployments.”",
        "title": "$1.2 trillion needed for grid-forming battery storage to support global renewable push: Report - ET EnergyWorld",
        "url": "https://energy.economictimes.indiatimes.com/amp/news/renewable/1-2-trillion-needed-for-grid-forming-battery-storage-to-support-global-renewable-push-report/122195907",
        "date": "2025-07-02",
        "last_updated": "2025-07-11"
      },
      {
        "snippet": "The United States is experiencing an unprecedented acceleration in utility-scale battery storage deployment, a critical development that immediately enhances the power grid’s ability to manage intermittent renewable energy.\nThis surge means that wind and solar power can be reliably dispatched when needed, effectively turning variable generation into firm capacity.\nThe most significant indicator of this shift is the projected installation of **74 gigawatts (GW)** of new storage capacity between 2024 and 2028.\n...\nThis rapid deployment is a direct result of two converging forces: supportive federal policy and clear market demand.\nThe federal Investment Tax Credit (ITC) for standalone storage has made these projects financially viable on their own, decoupling them from solar farms.\n...\nThink of grid batteries like a shock absorber for the power system: they instantly absorb excess power when generation is high and release it just as quickly when demand spikes, smoothing out the volatility inherent in renewable sources.\n...\n- **Projected Capacity Addition** → 74 GW.\nThe expected new utility-scale storage capacity to be installed in the US between 2024 and 2028.\n- **Operational Capacity (July 2024)** → 20.7 GW.\nThe total utility-scale battery storage capacity already operating on the US grid as of mid-2024.\n- **Record Quarterly Addition** → 3,806 MW.\nThe amount of new utility-scale storage capacity added in the US during the record-setting third quarter of 2024.\n...\nThe next critical indicator will be the pace of long-duration energy storage (LDES) projects moving from pilot to final investment decision.\nWhile current batteries handle four to eight hours of storage, the long-term stability of a deeply decarbonized grid requires solutions that can store power for days or weeks.\nWatch for major finance announcements for non-lithium technologies like iron-air or compressed air storage, which will signal the next phase of grid resilience.\n**The US grid is rapidly transforming, with battery storage now a primary, bankable asset for securing a reliable, high-renewable power system.**",
        "title": "US Grid Battery Storage Boom Secures Massive Renewable Energy ...",
        "url": "https://news.sustainability-directory.com/energy/us-grid-battery-storage-boom-secures-massive-renewable-energy-future/",
        "date": "2025-12-01",
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "The US power sector is planning a record 86 gigawatts (GW) of new electric generating capacity additions for 2026, signaling a fundamental shift in resource procurement where variable renewables and storage are now the dominant development focus for the grid.\nThis means the grid is rapidly evolving to rely on intermittent sources that require immediate co-location with storage to provide reliable power.\nThe single most important data point is that solar power alone accounts for 51% of all planned 2026 capacity additions, followed by battery storage at 28%.\n...\nThis massive planned build is caused by the sustained economic advantage of solar photovoltaic technology combined with the rapidly falling cost and increasing duration of battery storage, making them the cheapest and fastest-to-deploy options for adding net new power.\nThe core dynamic is that solar provides cheap energy when the sun shines, and batteries provide the necessary “firming” capacity → the ability to dispatch power when needed → to make that solar reliable for the grid.\nThink of grid batteries like a water tower for electricity: they capture the excess solar energy during the day and release it during evening peak demand, directly replacing the need for traditional gas or coal plants to ramp up.\n...\n- **Total Planned Capacity** → 86 gigawatts (GW) – The total planned addition of new utility-scale electric generating capacity for 2026\n...\n**The US energy system is now fundamentally structured around deploying solar power paired with battery storage as the primary engine for all new electricity capacity.**",
        "title": "Record US Power Build Signals Solar and Storage Grid Dominance",
        "url": "https://news.sustainability-directory.com/energy/record-us-power-build-signals-solar-and-storage-grid-dominance/",
        "date": "2026-03-18",
        "last_updated": "2026-05-09"
      },
      {
        "snippet": "The U.S. utility-scale battery storage market is experiencing a massive, policy-driven surge, setting a record for new capacity additions.\nThis development fundamentally changes the power grid’s operational dynamics, shifting it to a system where intermittent solar and wind can be stored and dispatched on demand, thereby enhancing reliability.\nThe scale of this transition is underscored by the forecast of **74 gigawatts** of new storage capacity expected to be installed between 2024 and 2028.\n...\nThis explosive growth is a direct cause-and-effect outcome of state-level clean energy mandates and the falling cost of battery technology.\nStates like California and Texas have set aggressive procurement targets, creating a clear, stable demand signal for investors.\nThis market shift has turned batteries into a “non-wires alternative,” meaning they can solve grid congestion and reliability issues more cheaply and quickly than building new power lines or fossil fuel plants.\nThink of grid batteries like a water tower for electricity: they store excess power when supply is high, such as midday solar, and release it instantly when demand peaks, smoothing out the variability of renewables and providing essential grid services like frequency response.\n...\n- **Projected New Capacity** → 74 GW (Gigawatts).\nThe total utility-scale battery storage capacity forecast to be installed across the U.S. between 2024 and 2028, showing the massive scale of the near-term market.\n- **Operational Capacity** → 20.7 GW (Gigawatts).\nThe approximate utility-scale battery storage capacity operational in the U.S. as of Q3 2024.\n- **Record Quarter** → 3,806 MW (Megawatts).\nThe record amount of new utility-scale storage capacity added to the U.S. grid in the third quarter of 2024.\n...\nThe next thing to watch is the continued commercialization of long-duration energy storage technologies, which can store power for 8 to 100 hours.\nThis will show if the grid can move beyond daily solar-shifting to multi-day resilience, which is the final technical hurdle for a truly decarbonized, 24/7 clean power system.\n**Grid-scale batteries are no longer a niche technology; they are the core infrastructure enabling the next phase of the clean energy transition.**",
        "title": "US Grid Battery Storage Deployment Surges, Enabling Massive ...",
        "url": "https://news.sustainability-directory.com/energy/us-grid-battery-storage-deployment-surges-enabling-massive-renewable-growth/",
        "date": "2026-01-06",
        "last_updated": "2026-05-19"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

**7. Combining Domain Filter with Other Filters**

Domain filters work seamlessly with other search parameters for precise control:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Combine domain filter with date and language filters
  response = client.search.create(
      query="quantum computing hardware breakthroughs",
      max_results=20,
      search_domain_filter=[
          "nature.com",
          "science.org",
          "arxiv.org"
      ],
      search_recency_filter="month",
      search_language_filter=["en"]
  )

  for result in response.results:
      print(f"{result.title}")
      print(f"URL: {result.url}")
      print(f"Date: {result.date}")
      print("---")
  ```

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

  const client = new Perplexity();

  // Combine domain filter with date and language filters
  const response = await client.search.create({
    query: "quantum computing hardware breakthroughs",
    max_results: 20,
    search_domain_filter: [
      "nature.com",
      "science.org",
      "arxiv.org"
    ],
    search_recency_filter: "month",
    search_language_filter: ["en"]
  });

  for (const result of response.results) {
    console.log(`${result.title}`);
    console.log(`URL: ${result.url}`);
    console.log(`Date: ${result.date}`);
    console.log("---");
  }
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "quantum computing hardware breakthroughs",
      "max_results": 20,
      "search_domain_filter": [
        "nature.com",
        "science.org",
        "arxiv.org"
      ],
      "search_recency_filter": "month",
      "search_language_filter": ["en"]
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "2e8b1795-66a6-4cb5-978e-e21db62d3907",
    "results": [
      {
        "snippet": "- U.S. National Science Foundation funding drives breakthroughs that are enabling new quantum technologies while providing specialized training and education for American scientists and engineers.\n...\nThis combination of superposition and entanglement enables quantum computers to perform numerous calculations in parallel, dramatically increasing computing power and making them potentially capable of solving problems that are far too complex for classical computers.\n...\nIts full potential depends on a connected ecosystem of quantum computers to perform calculations, quantum networks to transmit information, and quantum sensors that capture precise details from their surroundings.\n...\nQuantum computing is in an experimental stage and requires highly specialized equipment, extremely cold temperatures and extraordinary precision.\nDespite remarkable progress, qubit-based computing is fragile and prone to errors, making it difficult to scale systems to hundreds or thousands of qubits while maintaining reliable performance.\nIn addition, developing algorithms that can fully harness quantum hardware and integrating quantum and classical systems adds another layer of complexity.\nYet, NSF-funded research is steadily overcoming these obstacles by advancing error correction, developing new qubit technologies and training next-generation quantum scientists and engineers — bringing the promise of practical quantum computing closer to reality.\n...\nNSF has been at the center of quantum computing breakthroughs for decades.\nIn the mid-1980s, NSF-funded researchers demonstrated that quantum tunneling, previously seen only in subatomic particles, could occur in a superconducting electrical circuit visible to the naked eye.\nThis showed that circuits could behave as quantum objects, opening the door to engineered quantum computers and later earning the 2025 Nobel Prize in physics.\nAbout a decade later, NSF-supported researchers advanced the field again by creating the first Bose-Einstein condensate, a state of matter where thousands of atoms act as a single \"superatom.\"\nThis breakthrough made it possible to study quantum phenomena on a macroscopic scale, unlocking new ways to understand quantum behavior and earning the 2001 Nobel Prize in physics.\nIn the early 2000s, NSF helped launch research into topological materials, whose unique properties can help keep quantum information intact.\nThis work was a key step in the ongoing work to create materials-based quantum computers, including Microsoft's Majorana-1 chip that debuted in 2025.\nNSF researchers are chipping away at long-standing challenges in quantum computing, like error correction and scalability.\nIn 2025, research groups at two NSF Physics Frontiers Centers made significant strides: One group created a new system that can detect and remove errors below a key performance threshold, a sign that practical error correction may finally be within reach.\nAnother group created a record-setting array of 6,100 neutral-atom qubits held in a grid by lasers.\nThey even moved these atoms across the grid while maintaining superposition, a key capability that makes neutral-atom systems especially promising for efficient error correction.\nTogether, these advances bring practical, powerful quantum computers closer to reality.\n...\nToday, NSF continues to drive the field forward through a range of programs.\nThe NSF Quantum Leap Challenge Institutes, established in 2020, fund large, collaborative projects to develop the essential components and functional pieces needed for reliable, scalable quantum computers, while training the next generation of quantum scientists and engineers.\nThe NSF National Quantum Virtual Laboratory is designing prototypes of future quantum infrastructure to give researchers across the country access to cutting-edge quantum hardware, software and algorithms, making it easier to test ideas and turn discoveries into technology.\nNSF boosts early-stage innovation through America's Seed Fund, supporting startups that are building everything from new qubit technologies to software and hardware subsystems.\nAt the same time, NSF fosters partnerships across universities, government labs, and industry to push forward hybrid classical-quantum systems, improve error correction, and explore emerging applications in artificial intelligence, cryptography, biotechnology and beyond.\nFrom theory to application, NSF's continued investments are enabling new methods, hardware and software with unparalleled capabilities.\nThese breakthroughs are laying the groundwork for a future where quantum computers can help us seize enormous opportunities — revolutionizing scientific discoveries, fortifying national security and strengthening economic competitiveness.\n...\nThis center develops key technologies for creating the first error-corrected local and global quantum networks, enabling nationwide access to quantum computing.",
        "title": "Quantum computing: Expanding what's possible",
        "url": "https://www.nsf.gov/science-matters/quantum-computing-expanding-whats-possible",
        "date": "2026-01-21",
        "last_updated": "2026-05-15"
      },
      {
        "snippet": "While quantum computing might seem like technology for the distant future, the breakthroughs from the collaboration between Fermilab’s Superconducting Quantum Materials and Systems (SQMS) Center, the National Institute of Standards and Technology (NIST), and several other government, university, and industrial partners, could reshape industries and daily life in the near future.\n...\nScientists from NIST’s Communications Technology Laboratory (CTL) and the Physical Measurement Laboratory (PML) are leading the SQMS Center’s Nanofabrication Taskforce, a joint effort aimed at enhancing the performance of superconducting quantum bits (qubits) — the building blocks of quantum computers.\n...\nUnder his guidance, the team has pioneered breakthroughs in qubit fabrication techniques, such as encapsulating the surface of qubits made from the chemical element niobium, a superconducting metal, to reduce material losses and extend qubit coherence times significantly.\n...\nThe taskforce is tackling one of the biggest challenges in quantum computing: improving qubit coherence.\nLonger coherence times mean qubits can maintain their quantum states longer, leading to more powerful and reliable quantum computers.\n...\n### Key Technical Breakthroughs\nRecent innovations by the SQMS Nanofabrication Taskforce have led to a systematic improvement in qubit coherence, with the best-performing qubits now reaching coherence times of up to 0.6 milliseconds, a significant leap for superconducting quantum technology.\nThis achievement is driven by optimized qubit designs and enhanced readout resonators, which improve qubit stability and coherence.\nAdditionally, researchers have tackled qubit loss mechanisms by encapsulating niobium surfaces with gold or tantalum to prevent the formation of lossy niobium oxide, a major source of decoherence.\nEfforts are also underway to explore alternative materials for Josephson junctions, addressing losses caused by aluminum oxide tunnel barriers, while recognizing that other material interfaces and sapphire substrates currently limit coherence times to approximately 1 millisecond.\nTo push the boundaries of performance even further, the taskforce is investigating new superconducting materials, while also refining Josephson tunnel junction fabrication techniques.\nIn addition to the advancements in materials, nanofabrication process optimizations, such as reducing processing steps and developing sidewall capping techniques, are enhancing the reliability and scalability of quantum hardware, paving the way for next-generation quantum computing.\n...\nThe breakthroughs from the SQMS Nanofabrication Taskforce bring quantum research closer to the ultimate goal: building scalable, fault-tolerant quantum computers.\nBy tackling the fundamental challenges of qubit fabrication and coherence, NIST scientists from CTL and PML help to ensure the U.S. remains a leader in this transformative field.",
        "title": "Quantum Breakthroughs: NIST & SQMS Lead the Way",
        "url": "https://www.nist.gov/news-events/news/2025/04/quantum-breakthroughs-nist-sqms-lead-way",
        "date": "2025-04-04",
        "last_updated": "2026-03-09"
      },
      {
        "snippet": "IBM delivers the most performant and reliable quantum hardware, backed by industry-leading production processes.\nQuantum devices (<100q)\n60\nSince 2016\nQuantum computers (>100q)\n30+\nSince 2022\nAvailable qubits\n2300+\nCircuits ran\n3.9T+\nAvailability (% uptime)\n97%\nOur qubits are made using state-of-the-art 300mm semiconductor chip fabrication technologies.\nBy putting semi-automated tooling to work in new ways, we are accelerating our development cycles.\nTo date, we have cut the time needed to build each new processor by at least half, while enabling multiple designs to be researched and explored in parallel.\n...\nFrom multi-layer wiring to tunable couplers, we’ve fine-tuned our signal delivery and packaging techniques to ensure qubit control scales with processor complexity.\nWe are also developing a new low-loss wiring layer to enable the distant qubit connections required for our qLDPC error-correcting code.\nWe are pioneering inter-module communication with l-couplers, enabling computation across chips, modules, and systems.\nThese microwave cables extend processing power in multi-QPU systems and soon fault-tolerant architectures.\nBuilding systems that can run billions of gates requires modular components that create a single cryogenic environment.\nFrom componentized fridge design to flex wiring, we continue to drive scalability and affordability.\nWe are also developing cryogenic CMOS control electronics, reducing system complexity and improving reliability.\n...\nThe cryostat demo offers a detailed look inside an IBM quantum computing system.\nOur quantum processors need to be very cold—about a hundredth of a degree above absolute zero.\nThis complex array of components creates the required ultra-cold environment.\nFrom top to bottom:\nA tightly-sealed plate protects the flexible input wiring as it passes into the ultra-high vacuum fridge\nThis device provides initial cooling, down to temperatures of 4 kelvin.\nThat’s -452.47° Fahrenheit, or -269.15° Celsius.\nFlexible printed circuit boards carry microwave signals into and out of this ultra-cold environment in an inexpensive, low-crosstalk manner.\nThese low-noise amplifiers take the weak readout signals from the qubits and make them large enough that they are not swamped by the electronic noise from the room temperature world outside the fridge.\nThese cables send signals to and from qubits, like a coaxial line for a cable television.\nThe superconducting lines are zero-loss, meaning they can transmit information without losing energy.\nElectromagnetic signals like those from your phone create noise in a quantum system.\nThis shield protects our systems from the interference of this kind of radiation.\nIt’s particularly effective at the ultra-low temperatures in which we operate.\nQuantum-limited amplifiers (QLAs) boost the faint readout signals that come from sensitive quantum processors while adding the minimum amount of noise allowed by the laws of quantum mechanics.\nIBM Quantum Heron is a 156-qubit processor designed for performance and the basis of our plan to scale quantum computers.\nHeron contains the qubit and gate technology that forms the foundation of our development roadmap.\nAt 127 qubits, the Eagle processor features breakthrough packaging technologies for enhanced qubit control and scalability.\nWith 133 or 156 fixed-frequency qubits and tunable couplers, the Heron family of processors is our highest-performing yet and the core of our System Two architecture.\nThe next evolution of our chip architecture, Nighthawk features 120 qubits on a square lattice, with four-degree connectivity to scale workload complexity.\nWith 133 or 156 fixed-frequency qubits and tunable couplers, the Heron family of processors is our highest-performing yet and the core of our System Two architecture.\nIBM Quantum System Two is the cornerstone of quantum-centric supercomputing.\nIts flexible design allows multiple QPUs to be linked in a data center environment.\nThese systems combine scalable cryogenic infrastructure and classical runtime servers with modular qubit control electronics to facilitate hybrid architectures.\nIBM Quantum partners are doing real science with quantum.\nOur new reference architecture shows how to bring those capabilities to any HPC research center.",
        "title": "IBM Quantum Computing | Hardware and roadmap",
        "url": "https://www.ibm.com/quantum/hardware",
        "date": null,
        "last_updated": "2026-05-23"
      },
      {
        "snippet": "",
        "title": "10 quantum computing milestones | Network World",
        "url": "https://www.networkworld.com/article/3618098/10-quantum-computing-milestones-of-2024.html",
        "date": "2024-12-16",
        "last_updated": "2026-05-24"
      },
      {
        "snippet": "Quantum computing just crossed a threshold nobody saw coming.\nFrom Amazon’s first superconducting chip Ocelot, to IBM’s modular Quantum System Two, and Microsoft’s Majorana One prototype redefining stability itself—2025 has become the year quantum hardware finally starts looking like real, scalable computing.\nIn this video, you’ll discover nine groundbreaking developments that are reshaping how scientists, engineers, and entire industries think about computation.\nLearn how circuit knitting lets small chips solve massive problems, how Google’s Willow processor achieved unheard-of stability, and how quantum spin echoes are unlocking molecular secrets classical computers can’t touch.\nThese milestones aren’t just academic—they’re the foundation of the next technological revolution.\nCloud giants, research labs, and startups are proving that quantum computing is shifting from laboratory demos to practical tools for chemistry, finance, and materials science.\nThe race isn’t about qubit counts anymore—it’s about reliability, scalability, and who can make the quantum future actually usable.\n...\nBut in 2025, they quietly took a significant\n{ts:46} step that puts them in the same competitive conversation as IBM and Google in an entirely different arena.\n{ts:54} Quantum computing AWS introduced a superconducting quantum chip called Ocelot, marking Amazon's first\n{ts:62} proprietary quantum processor.\nFor years, Amazon's quantum platform called Bracket allowed scientists and\n{ts:69} researchers to run experiments on hardware manufactured by other companies like ion, Reetti, and Xanadu.\nNow they\n{ts:77} have their own processor sitting inside their research labs.\n...\nBut what genuinely matters\n{ts:90} here is that a major cloud computing provider is now building physical quantum hardware instead of just renting\n{ts:96} access to someone else's technology.\n...\nQuantum chips available\n{ts:138} today are genuinely powerful for specific tasks, but they're not huge by the standards needed for solving the\n...\nInstead of waiting patiently for a thousand cubit machines\n{ts:165} to be developed over the next decade, researchers started using something called circuit knitting.\nIt sounds\n...\n{ts:177} intelligently cut it into smaller, manageable pieces, run those pieces simultaneously on multiple separate\n{ts:183} quantum chips, and then let classical computers stitch all the results together mathematically.\nIn 2025, this\n{ts:190} approach stopped being purely theoretical research and turned into real practical tools that scientists can\n{ts:196} actually use.\nPlatforms like KisKit, CIRC, and AWS Bracket now support circuit knitting natively in their\n{ts:202} software.\nEarly demonstrations successfully showed that molecular energy calculations that used to be\n{ts:208} completely too large for a single quantum chip can now run distributed across multiple devices.\nIt's definitely\n{ts:215} slower than running everything on one massive processor would be, but it works reliably.\nMore importantly, it helps\n{ts:222} researchers test real quantum algorithms on actual hardware today rather than waiting potentially years for\n{ts:228} significantly larger processors to arrive from manufacturers.\n...\nIn 2025, Google pushed its 105 cubit Willow processor through extensive longduration\n{ts:258} repeated stress tests to determine if it could maintain stability under demanding conditions.\n...\n{ts:282} The chip successfully held quantum coherence through extended sequences of operations and thousands of experimental\n{ts:289} cycles without collapsing.\nThis represents genuinely important progress because early quantum processors often\n{ts:296} lost accuracy catastrophically when computational tasks became complicated or lengthy.\nWith Willow, researchers\n{ts:303} successfully ran quantum simulations for physics experiments and tested quantum machine learning models without the chip\n{ts:311} falling apart mid-run and losing all data.\n...\nWillow's test results demonstrated that superconducting cubits can handle real\n{ts:336} repeated work, which represents a critical step toward more reliable quantum hardware.\n...\n{ts:356} Quantum system 2 is a full modular setup featuring multiple cryogenic refrigerators, specialized racks for\n{ts:363} quantum chips, fast classical control servers, and networking infrastructure built into one integrated platform.\n...\nIn late 2024 and\n...\n{ts:462} It represents one of the first serious attempts to transform quantum hardware into something that operates like an\n{ts:469} actual computing cluster, not a single experimental device that requires constant babysitting by PhD physicists.\n{ts:477} Noise represents the biggest enemy of quantum hardware performance.\n...\nIBM's Heron processor was engineered\n{ts:490} specifically to solve exactly that challenge.\nIt contains 133 superconducting cubits and the key\n{ts:496} distinguishing feature is something called tunable couplers.\nThese couplers precisely control which cubits\n{ts:502} communicate with each other and when they remain isolated and quiet.\nEarly testing demonstrated Heron can deliver\n{ts:509} roughly three to five times better performance than IBM's previous generation processors because the\n{ts:515} quantum signals are dramatically cleaner.\nLess cross talk directly translates to fewer errors during\n{ts:521} execution of complex algorithms.\nHeron is also specifically designed for modular systems so multiple processors\n...\n{ts:556} Instead of building progressively larger chips following the same superconducting architecture everyone else uses,\n{ts:563} Microsoft is pursuing a fundamentally different approach.\nTheir Majorana 1 chip is based on topological cubits\n{ts:570} which use exotic quantum states that are theoretically more stable than ordinary cubits.\nThe underlying idea is that\n{ts:578} these cubits are naturally protected from certain types of noise because of the mathematical way quantum information\n{ts:584} is stored in the system.\nThe major one device is a small prototype, not a huge processor, but the architecture matters\n{ts:592} enormously for the future.\n...\nMicrosoft's approach aims to dramatically shrink that gap.\nMajorana 1\n{ts:620} will not replace existing quantum platforms overnight, but it demonstrates a viable path towards stable cubits that\n{ts:626} hold their quantum state considerably longer, which remains one of the biggest technical challenges in quantum\n{ts:632} computing.\n...\nIn 2025, researchers demonstrated a\n{ts:646} new technique using quantum manybody nuclear spin echoes functioning as a kind of molecular ruler.\nThe idea is to\n{ts:654} measure the precise geometry of molecules with extremely high accuracy.\nClassical methods including spectroscopy\n{ts:661} and electron microscopy can struggle with certain molecular structures because the signals overlap or the\n{ts:667} sample size is too small.\nQuantum spin echoes can probe interactions inside a molecule in ways classical sensors\n{ts:675} physically cannot.\nThis doesn't mean quantum computers replace chemistry laboratories, but it expands\n{ts:681} dramatically what scientists can measure.\n...\nIt's a quiet breakthrough that doesn't generate mainstream\n{ts:693} headlines, but it shows that quantum technology is not limited to computing tasks.",
        "title": "9 NEW Quantum Computing Breakthroughs That Redefine What’s Possible!",
        "url": "https://www.youtube.com/watch?v=hA8plV8m9Gg",
        "date": "2025-11-15",
        "last_updated": "2025-11-17"
      },
      {
        "snippet": "",
        "title": "Breakthroughs in Quantum Computing - Wevolver",
        "url": "https://www.wevolver.com/article/breakthroughs-in-quantum-computing",
        "date": "2024-08-19",
        "last_updated": "2026-05-25"
      },
      {
        "snippet": "",
        "title": "Top 15 New Quantum Computing Breakthroughs That Will Change Everything",
        "url": "https://www.youtube.com/watch?v=8JRJxsvJdRs",
        "date": "2026-03-16",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "",
        "title": "Top quantum breakthroughs of 2025 | Network World",
        "url": "https://www.networkworld.com/article/4088709/top-quantum-breakthroughs-of-2025.html",
        "date": "2025-11-13",
        "last_updated": "2026-05-15"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

## Parameter Reference

### `search_domain_filter`

* **Type**: Array of strings
* **Format**:
  * Domain names without protocol, optionally with a path (e.g., "example.com" or "example.com/blog")
  * Prefix with `-` for denylisting (e.g., "-reddit.com" or "-reddit.com/r/all")
* **Description**: Filters search results to include or exclude content from specified domains
* **Optional**: Yes
* **Maximum**: 20 domains per request
* **Modes**:
  * Allowlist mode: Include only specified domains (no `-` prefix)
  * Denylist mode: Exclude specified domains (use `-` prefix)
* **Example**:
  * Allowlist: `"search_domain_filter": ["nature.com", "science.org", "arxiv.org/abs"]`
  * Denylist: `"search_domain_filter": ["-reddit.com", "-pinterest.com", "-quora.com/topic"]`

## Domain Format Guidelines

**Correct Domain Formats:**

* `"nature.com"` - Root domain (matches nature.com and all subdomains)
* `"blog.example.com"` - Specific subdomain
* `"nature.com/articles"` - Domain + path prefix (matches that section and its subpaths)
* `"arxiv.org"` - Root domain (matches all subdomains)
* `".gov"` - Top-level domain (matches all .gov sites)
* `".edu"` - Top-level domain (matches all .edu sites)
* `".uk"` - Country-code TLD (matches all .uk sites)
* `"wikipedia.org"` - Matches en.wikipedia.org, fr.wikipedia.org, etc.
* `"-reddit.com"` - Exclude entire domain and all subdomains
* `"-pinterest.com"` - Exclude entire domain and all subdomains
* `"-.gov"` - Exclude all .gov domains

**Incorrect Domain Formats:**

* ❌ `"https://nature.com"` - Don't include protocol
* ❌ `"www.nature.com"` - Avoid www prefix (use root domain)

## Best Practices

### Domain Selection Strategy

* **Use Root Domains for Broad Coverage**: Specify root domains (e.g., "wikipedia.org") to match all subdomains automatically, including different language versions and regional sites.
* **Use TLDs for Categorical Filtering**: Target specific organization types with TLD filters like `.gov` for government, `.edu` for education, or `.org` for non-profits.
* **Be Specific When Needed**: Choose specific domains that are directly relevant to your search query to ensure high-quality results.
* **Quality Over Quantity**: Using fewer, highly relevant domains often produces better results than maximizing the 20-domain limit.
* **Consider Domain Authority**: Prioritize authoritative sources in your field for more reliable information.
* **Choose Your Mode**: Use either allowlist mode (include only) OR denylist mode (exclude), but not both in the same request. Denylisting is useful when you want broad search coverage but need to exclude specific low-quality or irrelevant sources.

### Locale and Regional Targeting

While domain filters don't directly filter by user location, you can target specific locales using:

* **Country-code TLDs**: Use filters like `.uk`, `.ca`, `.de`, `.jp` to target country-specific domains
* **Subdomain matching**: Specify regional subdomains when available (e.g., "uk.domain.com")
* **Combined approach**: Mix country TLDs with specific trusted domains for precise regional filtering

<Tip>
  For international research, combine TLD filtering with the `search_language_filter` parameter to refine results by both location and language.
</Tip>

### Domain Selection

* **Use Trusted Sources**: Select a specific set of trusted sources you want to search within (e.g., academic research, official documentation).
* **Leverage TLD Filtering**: When researching topics that span many sites of the same type, use TLD filters to cast a wider net (e.g., `.gov` for policy research).
* **Focus on Quality**: Choose authoritative domains that consistently provide reliable information relevant to your queries.

### Client-Side Validation

Validate domain formats on the client side before sending requests:

<CodeGroup>
  ```python Python theme={null}
  import re

  def validate_domain(domain):
      """Validate domain format including TLD filters."""
      # TLD filter (e.g., .gov, .edu)
      if domain.startswith('.'):
          tld_pattern = r'^\.[a-zA-Z]{2,}$'
          return bool(re.match(tld_pattern, domain))
      
      # Standard domain validation pattern
      pattern = r'^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$'
      return bool(re.match(pattern, domain))

  def validate_domain_filter(domains):
      """Validate domain filter array."""
      if len(domains) > 20:
          raise ValueError("Maximum 20 domains allowed")

      for domain in domains:
          if not validate_domain(domain):
              raise ValueError(f"Invalid domain format: {domain}")

      return True

  # Usage examples
  try:
      # Mix of regular domains and TLD filters
      domains = ["nature.com", "science.org", ".gov", ".edu"]
      validate_domain_filter(domains)

      response = client.search.create(
          query="CRISPR gene editing clinical trial outcomes for sickle cell disease",
          search_domain_filter=domains
      )
  except ValueError as e:
      print(f"Validation error: {e}")
  ```

  ```typescript Typescript theme={null}
  function validateDomain(domain: string): boolean {
    // TLD filter (e.g., .gov, .edu)
    if (domain.startsWith('.')) {
      const tldPattern = /^\.[a-zA-Z]{2,}$/;
      return tldPattern.test(domain);
    }
    
    // Standard domain validation pattern
    const pattern = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
    return pattern.test(domain);
  }

  function validateDomainFilter(domains: string[]): void {
    if (domains.length > 20) {
      throw new Error("Maximum 20 domains allowed");
    }

    for (const domain of domains) {
      if (!validateDomain(domain)) {
        throw new Error(`Invalid domain format: ${domain}`);
      }
    }
  }

  // Usage examples
  try {
    // Mix of regular domains and TLD filters
    const domains = ["nature.com", "science.org", ".gov", ".edu"];
    validateDomainFilter(domains);

    const response = await client.search.create({
      query: "CRISPR gene editing clinical trial outcomes for sickle cell disease",
      search_domain_filter: domains
    });
  } catch (error) {
    console.error("Validation error:", error.message);
  }
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "7bd7e5d8-68c3-433d-b78e-50fea0df5f61",
    "results": [
      {
        "snippet": "Today, the U.S. Food and Drug Administration approved two milestone treatments, Casgevy and Lyfgenia, representing the first cell-based gene therapies for the treatment of sickle cell disease (SCD) in patients 12 years and older.\nAdditionally, one of these therapies, Casgevy, is the first FDA-approved treatment to utilize a type of novel genome editing technology, signaling an innovative advancement in the field of gene therapy.\n...\nCasgevy, a cell-based gene therapy, is approved for the treatment of sickle cell disease in patients 12 years of age and older with recurrent vaso-occlusive crises.\nCasgevy is the first FDA-approved therapy utilizing CRISPR/Cas9, a type of genome editing technology.\nPatients’ hematopoietic (blood) stem cells are modified by genome editing using CRISPR/Cas9 technology.\n...\n**Data Supporting Casgevy**\nThe safety and effectiveness of Casgevy were evaluated in an ongoing single-arm, multi-center trial in adult and adolescent patients with SCD.\nPatients had a history of at least two protocol-defined severe VOCs during each of the two years prior to screening.\nThe primary efficacy outcome was freedom from severe VOC episodes for at least 12 consecutive months during the 24-month follow-up period.\nA total of 44 patients were treated with Casgevy.\nOf the 31 patients with sufficient follow-up time to be evaluable, 29 (93.5%) achieved this outcome.\nAll treated patients achieved successful engraftment with no patients experiencing graft failure or graft rejection.\nThe most common side effects were low levels of platelets and white blood cells, mouth sores, nausea, musculoskeletal pain, abdominal pain, vomiting, febrile neutropenia (fever and low white blood cell count), headache and itching.\n**Data Supporting Lyfgenia**\nThe safety and effectiveness of Lyfgenia is based on the analysis of data from a single-arm, 24-month multicenter study in patients with sickle cell disease and history of VOEs between the ages of 12- and 50- years old.\nEffectiveness was evaluated based on complete resolution of VOEs (VOE-CR) between 6 and 18 months after infusion with Lyfgenia.\nTwenty-eight (88%) of 32 patients achieved VOE-CR during this time period.\nThe most common side effects included stomatitis (mouth sores of the lips, mouth, and throat), low levels of platelets, white blood cells, and red blood cells, and febrile neutropenia (fever and low white blood cell count), consistent with chemotherapy and underlying disease.\nHematologic malignancy (blood cancer) has occurred in patients treated with Lyfgenia.\nA black box warning is included in the label for Lyfgenia with information regarding this risk.\nPatients receiving this product should have lifelong monitoring for these malignancies.\nBoth the Casgevy and Lyfgenia applications received Priority Review, Orphan Drug, Fast Track and Regenerative Medicine Advanced Therapy designations.",
        "title": "FDA Approves First Gene Therapies to Treat Patients with Sickle ...",
        "url": "https://www.fda.gov/news-events/press-announcements/fda-approves-first-gene-therapies-treat-patients-sickle-cell-disease",
        "date": "2023-12-08",
        "last_updated": "2026-05-23"
      },
      {
        "snippet": "",
        "title": "CRISPR Clinical Trials: A 2024 Update - Innovative Genomics Institute",
        "url": "https://innovativegenomics.org/news/crispr-clinical-trials-2024/",
        "date": "2024-03-13",
        "last_updated": "2025-07-16"
      },
      {
        "snippet": "",
        "title": "CRISPR/Cas9 in the treatment of sickle cell disease (SCD) and its ...",
        "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC11444630/",
        "date": "2024-08-14",
        "last_updated": "2026-03-26"
      },
      {
        "snippet": "",
        "title": "CRISPR/Cas9 gene editing for curing sickle cell disease - PMC",
        "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC8049447/",
        "date": "2021-01-10",
        "last_updated": "2026-03-29"
      },
      {
        "snippet": "",
        "title": "Sickle Cell Gene Therapy Using CRISPR - Synthego",
        "url": "https://www.synthego.com/crispr-sickle-cell-disease/",
        "date": "2025-08-05",
        "last_updated": "2026-05-16"
      },
      {
        "snippet": "# Gene Editing Therapy Shows Success Against Severe Sickle Cell Disease\nNearly all patients have achieved a functional cure\n## Media Contact\n...\nNew results from a clinical trial show promising outcomes for a gene-edited treatment for severe sickle cell disease, a genetic blood disorder with few curative options.\nConducted as part of the multicenter RUBY Trial, researchers published their latest findings in the New England Journal of Medicine.\nRemarkably, 27 out of 28 patients did not have any painful sickle cell crises after treatment, achieving what physicians call a \"functional cure.\"\nIn the trial, patients were treated with an experimental one-time gene editing cell therapy – Renizgamglogene autogedtemcel (reni-cel) – that modifies a patient’s own blood-forming stem cells to correct the mutation responsible for sickle cell disease.\nThe novel therapy increases levels of fetal hemoglobin – which prevents red blood cells from forming into sickle-shaped cells – and improves overall hemoglobin levels, reducing complications from the disease.\n“We have seen that a benefit of this CRISPR/Cas12a gene-editing technology is that there is no rejection, so it's different from traditional bone marrow transplants, which is standard treatment for sickle cell patients currently,” says Rabi Hanna, M.D., lead author and chair of the Pediatric Hematology – Oncology & Blood and Bone Marrow Transplant Division at Cleveland Clinic Children’s.\n“Our aim has been to achieve a functional cure to help prevent any future damage caused by sickle cell disease, and these latest results are compelling.”\n...\nThe results showed that most patients saw key blood cells recover within a month after treatment and by six months, average total hemoglobin levels rose to 13.8 g/dL, up from 9.8 g/dL before treatment – a level closer to what is seen in people without sickle cell disease.\nThe average level of fetal hemoglobin (HbF) was 48.1%, and these levels remained stable over time.",
        "title": "Gene Editing Therapy Shows Success Against Severe ...",
        "url": "https://newsroom.clevelandclinic.org/2026/04/01/gene-editing-therapy-shows-success-against-severe-sickle-cell-disease",
        "date": "2026-04-01",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "Researchers Publish Final Results of Key Clinical Trial for Gene Therapy for Sickle Cell Disease\n...\nIn a landmark study, an international consortium led by researchers at Children’s Hospital of Philadelphia (CHOP) published the final results of a key clinical trial of the gene therapy CASGEVY (exagamglogene autotemcel) for the treatment of sickle cell disease in patients 12 years and older with recurrent vaso-occlusive crises (VOCs).\nThe study found that 96.7% of patients in the study did not have any vaso-occlusive crises (VOCs) – a blockage that results in lack of oxygen and painful episodes – for at least one year, and 100% were able to remain hospitalization-free for the same length of time.\nThe findings, published today in the *New England Journal of Medicine*, provide the complete details of the critical clinical trial that led to the FDA approval of CASGEVY™ for the treatment of sickle cell disease in December 2023.\n...\nResearchers have been studying the use of gene therapy and CRISPR technology to edit portions of DNA in people with inherited or genetic disorders, like sickle cell disease.\nIn the case of sickle cell disease, the CASGEVY process edits DNA within the patient’s own cells and enables the patient to produce a different form of hemoglobin in their red blood cells.\nClinical trials at CHOP and other sites have shown that successful gene editing can prevent cells from developing the distinctive crescent shape apparent in sickle cell disease and have eliminated pain episodes in almost all patients.\nCASGEVY was the first FDA-approved therapy developed with CRISPR technology.\n“In this clinical trial, sickle cell patients who were having significant issues with their disease began to see their problems resolve within months and improve their quality of life significantly,” said senior study author Stephan A. Grupp, MD, PhD, Section Chief of the Cellular Therapy and Transplant Section, Inaugural Director of the Susan S. and Stephen P. Kelly Center for Cancer Immunotherapy, and Medical Director of the Cell and Gene Therapy Laboratory at CHOP.\nGrupp was also one of the principal investigators in the clinical trials that led to the approval of CASGEVY and the leader of the study’s steering committee.\nThe researchers conducted the CLIMB SCD-121 trial, a phase 3, single-arm, open-label study of exa-cel in patients between 12 and 35 years old with sickle cell disease and at least two severe VOCs in each of the two years before screening.\nThe key primary endpoint of the study was a proportion of patients without severe VOCs for at least 12 consecutive months, with a secondary endpoint of patients who were free from inpatient hospitalization for severe VOCs for at least 12 consecutive months.\nA total of 44 patients received exa-cel with a median follow up of 19.3 months.\nIn a total of 30 patients with sufficient follow-up data to be evaluated, 29 (96.7%) were free of VOCs for at least 12 consecutive months.\nThis information is an update for the US Prescribing Information for CASGEVY, which includes an evaluation of 31 patients resulting in a response rate of 93.5%.\nThe safety of treatment was comparable to treatment with hematopoietic and progenitor stem cells, and no malignancies were reported as a result of treatment.\n...\nAdditionally, the results of a clinical trial on the efficacy of exa-cel for the treatment of β-thalassemia were also published today in the *New England Journal of Medicine*.\nThe preliminary results of the trial led to the FDA approval of CASGEVY for transfusion-dependent β-thalassemia in January 2024.\n...\n215-590-3025\n...\n267-426-0762",
        "title": "Researchers Publish Final Results of Key Clinical Trial for Gene ...",
        "url": "https://www.chop.edu/news/researchers-publish-final-results-key-clinical-trial-gene-therapy-sickle-cell-disease",
        "date": "2024-04-24",
        "last_updated": "2026-05-11"
      },
      {
        "snippet": "",
        "title": "Other Gene Editing...",
        "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC12599223/",
        "date": "2025-11-06",
        "last_updated": "2026-04-20"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

### Performance Considerations

* **Result Availability**: Narrowing to specific domains may reduce the number of available results. Be prepared to handle cases where fewer results are returned than requested.
* **Domain Coverage**: Ensure the domains you specify actually contain content relevant to your query. Overly restrictive filters may return zero results.
* **Combination Effects**: Domain filters combined with other restrictive filters (date, language) can significantly reduce result counts.

<Tip>
  For best results, combine domain filtering with other filters like `search_recency_filter` or `search_language_filter` to narrow down your search to highly relevant, timely content from your target sources. Use TLD filters like `.gov` or `.edu` when you need broad coverage across an entire category of authoritative sites.
</Tip>


# Search Language Filter
Source: https://docs.perplexity.ai/docs/search/filters/language-filter



<Note>
  The `search_language_filter` parameter allows you to filter search results by language using ISO 639-1 language codes. Only results in the specified languages will be returned.
</Note>

<Info>
  Language codes must be valid 2-letter ISO 639-1 codes (e.g., "en", "ru", "fr"). You can filter by up to 10 languages per request.
</Info>

## Overview

The language filter for the Search API allows you to control which search results are returned by limiting them to specific languages. This is particularly useful when you need to:

* Search for content in specific languages
* Conduct multilingual research across multiple languages
* Focus on regional content in local languages
* Build language-specific applications or features

The `search_language_filter` parameter accepts an array of ISO 639-1 language codes and returns only results that match those languages.

To filter search results by language:

```bash theme={null}
"search_language_filter": ["en", "fr", "de"]
```

This filter will be applied in addition to any other search parameters.

## Examples

**1. Single Language Filter**

This example limits search results to English language content only.

**Request Example**

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.search.create(
      query="OpenAI API release history and developer features",
      max_results=10,
      search_language_filter=["en"]
  )

  for result in response.results:
      print(f"{result.title}: {result.url}")
  ```

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

  const client = new Perplexity();

  const response = await client.search.create({
    query: "OpenAI API release history and developer features",
    max_results: 10,
    search_language_filter: ["en"]
  });

  for (const result of response.results) {
    console.log(`${result.title}: ${result.url}`);
  }
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "OpenAI API release history and developer features",
      "max_results": 10,
      "search_language_filter": ["en"]
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ````json theme={null}
  {
    "id": "4a713b10-40e7-4d2a-9e7b-fdd9870702e8",
    "results": [
      {
        "snippet": "",
        "title": "Changelog | OpenAI API",
        "url": "https://developers.openai.com/api/docs/changelog",
        "date": null,
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "All latest OpenAI models support text and image input, text output, multilingual capabilities, and vision.\nModels are available via the Responses API and our Client SDKs.",
        "title": "Models | OpenAI API",
        "url": "https://developers.openai.com/api/docs/models",
        "date": null,
        "last_updated": "2026-05-07"
      },
      {
        "snippet": "June 11, 2020\n...\nWe’re releasing an API for accessing new AI models developed by OpenAI.\nUnlike most AI systems which are designed for one use-case, the API today provides a general-purpose “text in, text out” interface, allowing users to try it on virtually any English language task.\nYou can now request access in order to integrate the API into your product, develop an entirely new application, or help us explore the strengths and limits of this technology.\nGiven any text prompt, the API will return a text completion, attempting to match the pattern you gave it.\nYou can “program” it by showing it just a few examples of what you’d like it to do; its success generally varies depending on how complex the task is.\nThe API also allows you to hone performance on specific tasks by training on a dataset (small or large) of examples you provide, or by learning from human feedback provided by users or labelers.\n...\nToday the API runs models with weights from the GPT‑3⁠(opens in a new window) family with many speed and throughput improvements.",
        "title": "OpenAI API",
        "url": "https://openai.com/index/openai-api/",
        "date": "2020-06-11",
        "last_updated": "2026-03-29"
      },
      {
        "snippet": "",
        "title": "OpenAI Just Changed Everything (Responses API Walkthrough)",
        "url": "https://www.youtube.com/watch?v=0pGxoubWI6s",
        "date": "2025-03-13",
        "last_updated": "2026-03-31"
      },
      {
        "snippet": "",
        "title": "Call to bring back the rigor in API Development and ...",
        "url": "https://community.openai.com/t/call-to-bring-back-the-rigor-in-api-development-and-production-grade-slas-for-api-improvements/1357192",
        "date": "2025-09-09",
        "last_updated": "2026-05-04"
      },
      {
        "snippet": "Announced Open Responses: an open-source spec for building multi-provider, interoperable LLM interfaces built on top of the original OpenAI Responses API.\nJan 14\nFeature\ngpt-5.2-codex\nv1/responses\nReleased\n```\ngpt-5.2-codex\n```\nto the Responses API.\nGPT-5.2-Codex is a version of GPT-5.2 optimized for agentic coding tasks in Codex or similar environments.\nRead more here.\n...\nUpdated the gpt-realtime-mini and gpt-audio-mini slugs to point to the 2025-12-15 snapshots.\n...\nUpdated the sora-2 slug to point to\n```\nsora-2-2025-12-08\n```\n...\ngpt-image-1.5\nchatgpt-image-latest\nAdded\n```\ngpt-image-1.5\n```\nand\n```\nchatgpt-image-latest\n```\nto the Responses API image generation tool.\n...\ngpt-image-1.5\nchatgpt-image-latest\nReleased gpt-image-1.5 and chatgpt-image-latest, our latest and most advanced models for image generation.\nRead more here.\n...\nReleased four new dated audio snapshots.\nThese updates deliver reliability, quality, and voice fidelity improvements for real-time, voice-driven applications.\nRead more here.\n...\nThis launch also includes support for Custom voices for eligible customers.\n...\nReleased GPT-5.2, the newest flagship model in the GPT-5 model family.\nGPT-5.2 shows improvements over the previous GPT-5.1 in:\n- General intelligence\n...\nFor long-running conversations with the Responses API, you can use the\n```\n...\n```\n...\nReleased GPT-5.1, the newest flagship model in the GPT-5 model family.\n...\nReleased enhanced role-based access controls (RBAC).\nRole-based access control (RBAC) lets you decide who can do what across your organization and projects—both through the API and in the Dashboard.\n...\nExtended prompt cache retention keeps cached prefixes active for longer, up to a maximum of 24 hours.\nExtended Prompt Caching works by offloading the key/value tensors to GPU-local storage when memory is full, significantly increasing the storage capacity available for caching.\n...\nReleased gpt-5-pro, a version of GPT-5 that uses more compute to think harder and provide consistently better answers.\nReleased gpt-realtime-mini and gpt-audio-mini for more cost-efficient speech to speech performance.\nReleased gpt-image-1-mini for more cost-efficient image generation and editing.\nLaunched v1/videos for rich, detailed, and dynamic video generation and remixing with our latest Sora 2 and Sora 2 Pro models.\nLaunched Agent Builder for visually creating custom multi-agent workflows.\nLaunched ChatKit, an embeddable chat interface for deploying agents.\n...\n- Released the Responses API, a new API for creating and using agents and tools.\n- Released a set of built-in tools for the Responses API: web search, file search, and computer use.\n...\n- Announced plans to bring all Assistants API features to the easier to use Responses API, with an anticipated sunset date for Assistants in 2026 (after achieving full feature parity).",
        "title": "Changelog | OpenAI API",
        "url": "https://platform.openai.com/docs/changelog",
        "date": "2025-01-31",
        "last_updated": "2026-01-21"
      },
      {
        "snippet": "",
        "title": "API Platform",
        "url": "https://openai.com/api/",
        "date": "2026-04-09",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "### June, 2025Jun 13featurev1/responses\n- New reusable prompts are now available in the dashboard and Responses API.\nVia API, you can now reference templates created in the dashboard via the\n`prompt`parameter (with a prompt\n`id`, optional\n`version`) and supply dynamic\n`variables`that can include strings, images, or file inputs.\nReusable prompts are not available in Chat Completions.\nLearn more.\n- Released o3-pro, a version of the o3 reasoning model that uses more compute to answer hard problems with better reasoning and consistency.\nPrices for the o3 model have also been reduced for all API requests, including batch and flex processing.\n- Added fine-tuning support with direct preference optimization for the models\n`gpt-4.1-2025-04-14`,\n`gpt-4.1-mini-2025-04-14`, and\n`gpt-4.1-nano-2025-04-14`.\n- New model snapshots available for gpt-4o-audio-preview and gpt-4o-realtime-preview.\nReleased Agents SDK for TypeScript.\n### May, 2025May 20featurev1/responses\n- Added support for new built-in tools in the Responses API, including remote MCP servers and code interpreter.\nLearn more about tools.\n- Added support for using\n`strict`mode for tool schemas when using parallel tool calling with non-fine-tuned models.\n- Added new schema features, including string validation for\n- Launched codex-mini-latest in the API, optimized for use with the Codex CLI.\n...\n- Launched support for reinforcement fine-tuning.\nLearn about available fine-tuning methods.\ngpt-4.1-nano is now available for fine-tuning.\n=======\n...\n### April, 2025Apr 23featurev1/images/generationsv1/images/edits\n- Added a new image generation model,\n`gpt-image-1`.\nThis model sets a new standard for image generation, with improved quality and instruction following.\n- Updated the Image Generation and Edit endpoints to support new parameters specific to the\n`gpt-image-1`model.\n- Added two new o-series reasoning models,\n`o3`and\n`o4-mini`.\nThey set a new standard for math, science, and coding, visual reasoning tasks, and technical writing.\n- Launched Codex, our code generation CLI tool.\n- Added\n`gpt-4.1`,\n`gpt-4.1-mini`, and\n`gpt-4.1-nano`models to the API.\nThese new models feature improved instruction following, coding, and a larger context window (up to 1M tokens).\n`gpt-4.1`and\n`gpt-4.1-mini`are available for supervised fine-tuning.\nAnnounced deprecation of\n`gpt-4.5-preview`.\n### March, 2025Mar 20updatev1/audio\n- Added\n`gpt-4o-mini-tts`,\n`gpt-4o-transcribe`,\n`gpt-4o-mini-transcribe`, and\n`whisper-1`models to the Audio API.\n- Released o1-pro, a version of the o1 reasoning model that uses more compute to answer hard problems with better reasoning and consistency.\nReleased several new models and tools and a new API for agentic workflows:\nReleased the Responses API, a new API for creating and using agents and tools.\nReleased a set of built-in tools for the Responses API: web search, file search, and computer use.\nReleased the Agents SDK, an orchestration framework for designing, building, and deploying agents.\nAnnounced new models:\n`gpt-4o-search-preview`,\n`gpt-4o-mini-search-preview`,\n`computer-use-preview`.\nAnnounced plans to bring all Assistants API features to the easier to use Responses API, with an anticipated sunset date for Assistants in 2026 (after achieving full feature parity).\n- Added\n`metadata`field support to fine-tuning jobs.\n### February, 2025Feb 27featuregpt-4.5v1/chat/completionsv1/assistantsv1/batch\n- Released a research preview of GPT-4.5—our largest and most capable chat model yet.\nGPT-4.5's high \"EQ\" and understanding of user intent make it better at creative tasks and agentic planning.\n### January, 2025Jan 31featureo3-minio3-mini-2025-01-31v1/chat/completions\n- Launched o3-mini, a new small reasoning model that is optimized for science, math, and coding tasks.\n### December, 2024Dec 18feature\nLaunched Admin API Key Rotations, enabling customers to programmatically rotate their admin api keys.\nUpdated Admin API Invites, enabling customers to programmatically invite users to projects at the same time they are invited to organizations.\nAdded new models for o1, gpt-4o-realtime, gpt-4o-audio and more.\nAdded WebRTC connection method for the Realtime API.\nAdded\n...\nAdded\n`developer`message role for o1 model.\nNote that o1-preview and o1-mini do not support system or developer messages.\nLaunched Preference Fine-tuning using Direct Preference Optimization (DPO).\nLaunched beta SDKs for Go and Java.\nLearn more.\nAdded Realtime API support in the Python SDK.\n- Launched Usage API, enabling customers to programmatically query activities and spending across OpenAI APIs.\n### November, 2024Nov 20Updatev1/chat/completions\n- Released gpt-4o-2024-11-20, our newest model in the gpt-4o series.\n- Released Predicted Outputs, which greatly reduces latency for model responses where much of the response is known ahead of time.\nThis is most common when regenerating the content of documents and code files with only minor changes.\n...\n- Released new\n`gpt-4o-audio-preview`model for chat completions, which supports both audio inputs and outputs.\nUses the same underlying model as the Realtime API.\nReleased several new features at OpenAI DevDay in San Francisco:\n...\n- Released\nnew\n`omni-moderation-latest`moderation model, which supports both images and text (for some categories), supports two new text-only harm categories, and has more accurate scores.\n- Released o1-preview and o1-mini, new large language models trained with reinforcement learning to perform complex reasoning tasks.",
        "title": "Changelog - OpenAI API",
        "url": "https://platform.openai.com/docs/changelog/changelog",
        "date": "2025-01-31",
        "last_updated": "2025-06-20"
      },
      {
        "snippet": "",
        "title": "Model Release Notes | OpenAI Help Center",
        "url": "https://help.openai.com/en/articles/9624314-model-release-notes",
        "date": "2025-12-18",
        "last_updated": "2026-04-01"
      },
      {
        "snippet": "### February, 2025Feb 27featuregpt-4.5v1/chat/completionsv1/assistantsv1/batch\n- Released a research preview of GPT-4.5—our largest and most capable chat model yet.\nGPT-4.5's high \"EQ\" and understanding of user intent make it better at creative tasks and agentic planning.\n### January, 2025Jan 31featureo3-minio3-mini-2025-01-31v1/chat/completions\n- Launched o3-mini, a new small reasoning model that is optimized for science, math, and coding tasks.\n### December, 2024Dec 18feature\nLaunched Admin API Key Rotations, enabling customers to programmatically rotate their admin api keys.\nUpdated Admin API Invites, enabling customers to programmatically invite users to projects at the same time they are invited to organizations.\nAdded new models for o1, gpt-4o-realtime, gpt-4o-audio and more.\nAdded WebRTC connection method for the Realtime API.\nAdded\n`reasoning_effort`parameter for o1 models.\nAdded\n`developer`message role for o1 model.\nNote that o1-preview and o1-mini do not support system or developer messages.\nLaunched Preference Fine-tuning using Direct Preference Optimization (DPO).\nLaunched beta SDKs for Go and Java.\nLearn more.\nAdded Realtime API support in the Python SDK.\n- Launched Usage API, enabling customers to programmatically query activities and spending across OpenAI APIs.\n### November, 2024Nov 20Updatev1/chat/completions\n- Released gpt-4o-2024-11-20, our newest model in the gpt-4o series.\n- Released Predicted Outputs, which greatly reduces latency for model responses where much of the response is known ahead of time.\nThis is most common when regenerating the content of documents and code files with only minor changes.\n### October, 2024Oct 30featuregpt-4o-realtime-previewgpt-4o-audio-previewv1/chat/completions\n- Added five new voice types in the Realtime API and Chat Completions API.\n- Released new\n`gpt-4o-audio-preview`model for chat completions, which supports both audio inputs and outputs.\nUses the same underlying model as the Realtime API.\nReleased several new features at OpenAI DevDay in San Francisco:\nRealtime API: Build fast speech-to-speech experiences into your applications using a WebSockets interface.\nModel distillation: Platform for fine-tuning cost-efficient models with your outputs from a large frontier model.\nImage fine-tuning: Fine-tune GPT-4o with images and text to improve vision capabilities.\nEvals: Create and run custom evaluations to measure model performance on specific tasks.\nPrompt caching: Discounts and faster processing times on recently seen input tokens.\nGenerate in playground: Easily generate prompts, function definitions, and structured output schemas in the playground using the Generate button.\n### September, 2024Sep 26featureomni-moderation-latestv1/moderations\n- Released\nnew\n`omni-moderation-latest`moderation model, which supports both images and text (for some categories), supports two new text-only harm categories, and has more accurate scores.\n- Released o1-preview and o1-mini, new large language models trained with reinforcement learning to perform complex reasoning tasks.\n### August, 2024Aug 29featurev1/assistants\n- Assistants API now supports including file search results used by the file search tool, and customizing ranking behavior.\n- GA release for\n`gpt-4o-2024-08-06`fine-tuning—all API users can now fine-tune the latest GPT-4o model.\n- Released dynamic model for\n`chatgpt-4o-latest`—this model will point to the latest GPT-4o model used by ChatGPT.\n- Launched Structured Outputs—model outputs now reliabilty adhere to developer supplied JSON Schemas.\n- Released gpt-4o-2024-08-06, our newest model in the gpt-4o series.\n- Launched Admin and Audit Log APIs, allowing customers to programmatically administer their organization and monitor changes using the audit logs.\nAudit logging must be enabled within settings.\n### July, 2024Jul 24Update\n- Launched self-serve SSO configuration, allowing Enterprise customers on custom and unlimited billing to set up authentication against their desired IDP.\n- Launched fine-tuning for GPT-4o mini, enabling even higher performance for specific use cases.\n- Released GPT-4o mini, our affordable an intelligent small model for fast, lightweight tasks.\n- Released Uploads to upload large files in multiple parts.\n### June, 2024Jun 06Update\n- Parallel function calling\ncan be disabled in Chat Completions and the Assistants API by passing\n`parallel_tool_calls=false`.\n- .NET SDK launched in Beta.\n- Added support for file search customizations .\n### May, 2024May 15Update\n- Added support for archiving projects . Only organization owners can access this functionality.\n- Added support for setting cost limits on a per-project basis for pay as you go customers.\n- Released GPT-4o in the API.\nGPT-4o is our fastest and most affordable flagship model.\n- Added support for image inputs to the Assistants API.\n- Added support for fine-tuned models to the Batch API .\n- Added\n`stream_options: {\"include_usage\": true}`parameter to the Chat Completions and Completions APIs.\nSetting this gives developers access to usage stats when using streaming.\n- Added a new endpoint to delete a message from a thread in the Assistants API.\n### April, 2024Apr 29Update\n- Added a new\nfunction calling option\n`tool_choice: \"required\"`to the Chat Completions and Assistants APIs.\n- Added a guide for the Batch API and Batch API support for embeddings models\n- Introduced a series of updates to the Assistants API , including a new file search tool allowing up to 10,000 files per assistant, new token controls, and support for tool choice.\n- Introduced project based hierarchy for organizing work by projects, including the ability to create API keys and manage rate and cost limits on a per-project basis (cost limits available only for Enterprise customers).\n- Released Batch API\n- Released GPT-4 Turbo with Vision in general availability in the API\n- Added support for seed in the fine-tuning API\n...\n- Added support for temperature and assistant message creation in the Assistants API\n- Added support for streaming in the Assistants API\n...\n- Added\n`timestamp_granularities`parameter to the Audio API\n### January, 2024Jan 25Update\n- Released embedding V3 models and an updated GPT-4 Turbo preview\n- Added\n`dimensions`parameter to the Embeddings API\n...\n### November, 2023Nov 30Update\n- Released OpenAI Deno SDK\n- Released GPT-4 Turbo Preview , updated GPT-3.5 Turbo, GPT-4 Turbo with Vision, Assistants API, DALL·E 3 in the API, and text-to-speech API\n- Deprecated the Chat Completions\n...\n- Released OpenAI Python SDK V1.0\n...\n- Added function calling support to the Fine-tuning API",
        "title": "OpenAI Platform",
        "url": "https://platform.openai.com/docs/changelog/dec-15th-2023",
        "date": "2025-01-31",
        "last_updated": "2025-03-01"
      }
    ],
    "server_time": null
  }
  ````
</Accordion>

**2. Multiple Language Filter**

Search across multiple languages to gather diverse perspectives or multilingual content:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Search for content in English, French, and German
  response = client.search.create(
      query="Système d'échange de quotas d'émission de l'Union européenne: conception du dispositif et historique du prix du carbone",
      max_results=15,
      search_language_filter=["en", "fr", "de"]
  )

  for result in response.results:
      print(f"{result.title}: {result.url}")
  ```

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

  const client = new Perplexity();

  // Search for content in English, French, and German
  const response = await client.search.create({
    query: "Système d'échange de quotas d'émission de l'Union européenne: conception du dispositif et historique du prix du carbone",
    max_results: 15,
    search_language_filter: ["en", "fr", "de"]
  });

  for (const result of response.results) {
    console.log(`${result.title}: ${result.url}`);
  }
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "Système d\u0027échange de quotas d\u0027émission de l\u0027Union européenne: conception du dispositif et historique du prix du carbone",
      "max_results": 15,
      "search_language_filter": ["en", "fr", "de"]
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "fbe2ad33-45df-46bf-953d-ea32cf70ef10",
    "results": [
      {
        "snippet": "",
        "title": "Système d'Echange de Quotas d'Emission",
        "url": "https://www.ecologie.gouv.fr/politiques-publiques/systeme-dechange-quotas-demission",
        "date": "2016-10-12",
        "last_updated": "2026-04-07"
      },
      {
        "snippet": "",
        "title": "Marchés du carbone - SEQE-UE",
        "url": "https://www.ecologie.gouv.fr/politiques-publiques/marches-du-carbone-seqe-ue",
        "date": "2023-10-10",
        "last_updated": "2026-05-04"
      },
      {
        "snippet": "",
        "title": "Marchés du carbone - SEQE-UE 2",
        "url": "https://www.ecologie.gouv.fr/politiques-publiques/marches-du-carbone-seqe-ue-2",
        "date": "2026-02-16",
        "last_updated": "2026-05-22"
      },
      {
        "snippet": "",
        "title": "Système d'échange de quotas d'émission de l'Union européenne — Wikipédia",
        "url": "https://fr.wikipedia.org/wiki/Syst%C3%A8me_d'%C3%A9change_de_quotas_d'%C3%A9mission_de_l'Union_europ%C3%A9enne",
        "date": "2005-12-24",
        "last_updated": "2026-05-22"
      },
      {
        "snippet": "",
        "title": "FR",
        "url": "https://www.europarl.europa.eu/RegData/docs_autres_institutions/commission_europeenne/com/2020/0740/COM_COM(2020)0740_FR.pdf",
        "date": null,
        "last_updated": "2025-09-06"
      },
      {
        "snippet": "",
        "title": "Questions et réponses – Échange de quotas d'émission – Mettre un prix",
        "url": "https://ec.europa.eu/commission/presscorner/api/files/document/print/fr/qanda_21_3542/QANDA_21_3542_FR.pdf",
        "date": null,
        "last_updated": "2025-09-23"
      },
      {
        "snippet": "",
        "title": "Commission européenne - Questions et réponses",
        "url": "https://ec.europa.eu/commission/presscorner/api/files/document/print/fr/qanda_21_3542/QANDA_21_3542_FR.pdf&rut=0b54d265a7ec0a40fb6d973db812b879e90058194a9daf2881bfe68aec33a06b",
        "date": null,
        "last_updated": "2025-06-05"
      },
      {
        "snippet": "",
        "title": "Marché du carbone : quota et bourse, droit à polluer, acteurs",
        "url": "https://www.connaissancedesenergies.org/fiche-pedagogique/marches-du-carbone",
        "date": "2011-09-14",
        "last_updated": "2026-03-04"
      },
      {
        "snippet": "###\nLe marché du carbone est un mécanisme permettant l’**échange de droits d’émission de gaz à effet de serre (GES)**.\nIl s’agit d’une des mesures incitatives prévues par le Protocole de Kyoto signé en 1997 pour encourager les États à réduire leurs émissions polluantes et opter pour de nouvelles technologies à moindre coût.\nCe dispositif doit **faciliter la réalisation des objectifs climatiques** **collectifs**.\nAu sein d'un marché du carbone, un **plafond ** d'émissions est fixé à un niveau plus bas que le niveau d'émission réel.\nDes **quotas ** sont ensuite attribués aux responsables d'émissions de GES (pays, entreprises) :\n- si le pollueur réduit ses émissions en-dessous des quotas dont il dispose, il peut **revendre son droit à émettre non utilisé** ;\n- celui qui, au contraire, a pollué au-delà de son nombre de quotas doit en acheter à d'autres exploitants (ceux qui ne les ont pas tous utilisés).\nPour plus de flexibilité, les quotas peuvent être **empruntés** ou **épargnés**.\nLe système est **incitatif ** car le coût pour réduire les émissions est inférieur au prix du quota sur le marché.\nLe prix du quota dépend du niveau du plafond, qui est fixé en fonction des objectifs à atteindre et **abaissé chaque année**, afin de privilégier les efforts de réduction d'émissions.\n###\nSi plusieurs marchés régionaux s’établissent progressivement, l'un des plus importants est le marché du carbone de l'Union européenne (UE).\nIl couvre les émissions de GES de plusieurs secteurs (énergie, industrie lourde, trafic aérien...).\nMis en place par l’UE en 2005, le **système européen d’échange de quotas d’émissions de gaz à effet de serre (SEQE-UE)** vise à inciter les investissements dans des systèmes plus performants et plus écologiques, afin d'atteindre les objectifs climatiques de l'Union.\nLe marché européen du carbone a connu plusieurs phases, au cours desquelles de nouveaux secteurs ont successivement été intégrés (ex : le secteur de l'aviation, en 2012), tandis que le plafond annuel de quotas diminue chaque année.\nEn 2008, la crise économique a provoqué une chute du prix du carbone du fait de la baisse de l'activité économique, entraînant mécaniquement un surplus de quotas.\nDevenu moins incitatif, le SEQE-UE a fait l’objet de révisions permettant de retirer les quotas excédentaires, jusqu'à l’actuelle **phase 4 (2021-2030)**.\nOutre le système européen, la **Chine**,** premier émetteur mondial de GES**, a également mis en place un marché du carbone en **2021**.",
        "title": "Qu'est-ce que le marché du carbone ou système d'échanges de ...",
        "url": "https://www.vie-publique.fr/fiches/274841-quest-ce-que-le-marche-du-carbone-ou-systeme-dechanges-de-quotas",
        "date": "2020-06-26",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "",
        "title": "Marché des quotas carbone — Wikipédia",
        "url": "https://fr.wikipedia.org/wiki/March%C3%A9_des_quotas_carbone",
        "date": "2007-08-15",
        "last_updated": "2026-03-14"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

**3. Regional Language Search**

Focus on content from specific regions by using their local languages:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Search for Asian market news in Chinese, Japanese, and Korean
  response = client.search.create(
      query="Apple WWDC 基調講演で発表されたオンデバイスAI機能",
      max_results=10,
      search_language_filter=["zh", "ja", "ko"]
  )

  # Search for European tech news in multiple European languages
  eu_response = client.search.create(
      query="Lo más destacado del programa Y Combinator W26",
      max_results=10,
      search_language_filter=["en", "de", "fr", "es", "it"]
  )
  ```

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

  const client = new Perplexity();

  // Search for Asian market news in Chinese, Japanese, and Korean
  const response = await client.search.create({
    query: "Apple WWDC 基調講演で発表されたオンデバイスAI機能",
    max_results: 10,
    search_language_filter: ["zh", "ja", "ko"]
  });

  // Search for European tech news in multiple European languages
  const euResponse = await client.search.create({
    query: "Lo más destacado del programa Y Combinator W26",
    max_results: 10,
    search_language_filter: ["en", "de", "fr", "es", "it"]
  });
  ```

  ```bash cURL theme={null}
  # Search for Asian market news
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "Apple WWDC 基調講演で発表されたオンデバイスAI機能",
      "max_results": 10,
      "search_language_filter": ["zh", "ja", "ko"]
    }' | jq
  ```
</CodeGroup>

<AccordionGroup>
  <Accordion title="Response — Apple WWDC 基調講演で発表されたオンデバイスAI機能">
    ```json theme={null}
    {
      "id": "5e873edb-6a76-4b00-8088-07b7350be1cc",
      "results": [
        {
          "snippet": "今年の基調講演では、iPhone、iPad、Macの中心で生成モデルのパワーとユーザーの個人的な背景を組み合わせて、驚くほど有用で関連性のあるインテリジェンスを提供するパーソナルインテリジェンスシステムであるApple Intelligenceを発表しました。\n...\n**Apple、Apple Intelligenceを発表**\nApple Intelligenceは、Appleシリコンのパワーを活用して、言語や画像を理解して生成したり、複数のアプリにわたってアクションを実行したり、ユーザーの個人的な背景にもとづいて、日々のタスクをシンプルにしてよりすばやくこなせるようにします。\nApple Intelligenceの基礎はデバイス上の処理で、ユーザーのデータを収集することなくパーソナルインテリジェンスを提供します。Private Cloud ComputeはAIにおけるプライバシーの新しい基準を打ち立て、デバイス上の処理から、専用のAppleシリコン搭載のサーバ上で実行する、より大規模なサーバベースのモデルにまで、演算能力を柔軟に拡張できます。\n...\nApple IntelligenceはAppleシリコンとNeural Engineのパワーを最大限に活用し、Mシリーズチップを搭載したすべてのMacで利用できるようになります。",
          "title": "WWDC24のハイライト",
          "url": "https://www.apple.com/jp/newsroom/2024/06/wwdc24-highlights/",
          "date": "2024-03-26",
          "last_updated": "2025-01-20"
        },
        {
          "snippet": "",
          "title": "Apple Intelligence - Apple（日本）",
          "url": "https://www.apple.com/jp/apple-intelligence/",
          "date": null,
          "last_updated": "2026-03-28"
        },
        {
          "snippet": "# Apple製デバイス全体に及ぶ新機能により、Apple Intelligenceがさらにパワフルになります\nデベロッパは、Apple Intelligenceのデバイス上の基盤モデルにアクセスして、プライバシーを保護し、インテリジェントな体験をアプリに組み込めるようになります\n**カリフォルニア州クパティーノ**Appleは本日、iPhone、iPad、Mac、Apple Watch、Apple Vision Proのユーザー体験を向上させるApple Intelligenceの新機能を発表しました。\nApple Intelligenceが実現する新たな方法によって、ユーザーはライブ翻訳のような機能を利用してコミュニケーションをとったり、ビジュアルインテリジェンスのアップデートによって画面上に表示されているものに対してより多くのことをしたり、強化されたImage Playgroundやジェン文字を使用して自分自身を表現したりできるようになります\n1。さらに、ショートカットでApple Intelligenceを直接利用できるようになったほか、デベロッパがApple Intelligenceの中核にあるデバイス上の大規模言語モデルにアクセスできるようになります。そのため、デベロッパは、パワフルかつ高速で、プライバシーが組み込まれ、ユーザーがオフラインの時にも使えるインテリジェンスに、直接アクセスできるようになります。\nこれらのApple Intelligenceの機能は、本日よりテスト用に提供され、対応するデバイスで対応する言語に設定しているユーザーは今秋から利用できるようになります。\n...\nそのため、パワフルかつ高速で、プライバシーが組み込まれ、ユーザーがオフラインの時にも使えるインテリジェンスを活用できるようになります。これにより、ユーザーが日々活用しているアプリでまったく新しいインテリジェントな体験を次々に生み出せるようになると考えています。\n...\nユーザーの前に言語の壁が立ち塞がった時は、ライブ翻訳を利用すれば、メッセージの送信や会話の際に言語をまたいでコミュニケーションをとることができます。この体験は、メッセージ、FaceTime、電話に組み込まれるもので、Appleが構築した完全にデバイス上で動作するモデルによって実現するため、ユーザーの個人的な会話のプライバシーが保たれます。\n...\n2。FaceTimeでは、話し手の声を聞きながら、翻訳されたライブキャプションによって会話についていくことができます。また、電話の通話では、会話の全体を通して、翻訳が音声で読み上げられます 3。\n...\nジェン文字とImage Playgroundは、ユーザーにさらに多くの自己表現の方法を提供します。テキストによる説明をジェン文字に変換するだけでなく、絵文字を取り入れ、それらを説明と組み合わせることによって、新しいものを作り出せるようになります。\n...\nApple Intelligenceを基盤とするビジュアルインテリジェンスがユーザーのiPhoneの画面に拡張され、ユーザーはあらゆるアプリで、画面上に表示しているものを検索し操作できます。\nビジュアルインテリジェンスはすでに、ユーザーがiPhoneのカメラを使用して周囲の対象物や場所について学ぶのに役立っていますが、これからはiPhoneの画面上に表示されているものについて、より多くのことを、より速く実行できるようになります。\n...\nビジュアルインテリジェンスは、イベントが表示されていることを認識してカレンダーへの追加を提案し\n...\nWorkout Buddyは、Apple Intelligenceを利用した、ほかに類を見ないApple Watchのワークアウト体験で、ユーザーのワークアウトのデータとフィットネス履歴を取り込み、パーソナライズされた、モチベーションを高める洞察をセッション中に生成します\n5。\n...\nAppleは、Apple Intelligenceの中核にあるデバイス上の基盤モデルをどのアプリからでも直接利用できるようにしました。\nFoundation Modelフレームワークを利用すれば、アプリのデベロッパはApple Intelligenceをベースに、無料のAI推論を利用して、インテリジェントで、オフラインでも利用でき、プライバシーが保護される新たな体験をユーザーに提供できるようになります。\n...\nショートカットがこれまで以上にパワフルで賢くなります。ユーザーは、Apple Intelligenceによって実現したまったく新しい一連のショートカットであるインテリジェントなアクションを利用することができます。作文ツールによるテキストの要約や、Image Playgroundによる画像の生成などの機能に対応する専用のアクションが提供されます。\nユーザーはデバイス上で、またはプライベートクラウドコンピューティングによって、Apple Intelligenceのモデルを直接利用し、ショートカット内で利用される情報のプライバシーを保ったまま、ほかのショートカットに送るレスポンスを生成できるようになります。\n...\nあらゆる段階でユーザーのプライバシーを保護するように設計されたApple Intelligenceは、デバイス上の処理を使用しているため、それを動かすモデルの多くは完全にデバイス上で実行されます。\n...\nこれらの新機能はすべて、本日よりdeveloper.apple.com/jpでApple Developer Programを通じてテスト用に提供されます。パブリックベータ版は来月、beta.apple.com/jaでApple Beta Software Programを通じて提供されます。対応するデバイスでApple Intelligenceを有効にし、対応言語に設定しているユーザーは、今秋からアクセスできるようになります。\n対応するデバイスにはiPhone 16の全モデル、iPhone 15 Pro、iPhone 15 Pro Max、iPad mini（A17 Pro）、M1以降を搭載したiPadとMacのモデルが含まれます。Siriとデバイスの言語は同じ対応言語に設定する必要があります。\n...\n- 電話とFaceTimeのライブ翻訳は、一対一の通話の場合に、英語（米国、英国）、フランス語（フランス）、ドイツ語、ポルトガル語（ブラジル）、スペイン語（スペイン）に対応しています。\n- ビジュアルインテリジェンスでイベントをカレンダーに追加する機能は、iPhone 16の全モデル、iPhone 15 Pro、iPhone 15 Pro Maxで、英語で利用できます。",
          "title": "Apple製デバイス全体に及ぶ新機能により、Apple Intelligenceが ...",
          "url": "https://www.apple.com/jp/newsroom/2025/06/apple-intelligence-gets-even-more-powerful-with-new-capabilities-across-apple-devices/",
          "date": "2025-09-06",
          "last_updated": "2025-11-28"
        },
        {
          "snippet": "衛星経由でのSMSメッセージにも 対応します 次は、もう一つの通信アプリである メールについてです 受信したEメールを管理するための オンデバイスのカテゴリー分け機能が 年内に登場します メッセージ",
          "title": "基調講演 - WWDC24 - ビデオ - Apple Developer",
          "url": "https://developer.apple.com/jp/videos/play/wwdc2024/101/",
          "date": null,
          "last_updated": "2026-05-12"
        },
        {
          "snippet": "今回のWWDCでは、Apple Intelligenceのアップデートもアナウンスされた。\nWWDC 2025における“目玉”の1つとして、\n**アプリ開発者に対するApple Intelligenceで使っているAIモデルの開放**が挙げられる。\nApple Intelligenceは、複数のAIモデルを組み合わせているが、特に完全オンデバイスのモデルを利用できるようになることで「応答時間の削減」「オフライン動作の保証」「プライバシー保護」を実現できる。\nAIモデルは「Foundation Modelsフレームワーク」を通して利用可能で、開発者は自分のアプリにAI機能を統合しやすくなる。\nWWDC 2024では、Apple Intelligenceの特徴として「\n**プライベートクラウドコンピューティング**」が発表された。これはより大規模なAIモデルが必要とされる場合に使われるもので、「暗号化」「匿名化」そして「一時的な処理」という3つの原則を徹底していることが特徴だ。\n...\nプライベートクラウドによるAI処理は、「Automation（オートメーション）」や新しい「Spotlight（スポットライト：検索機能）」から明示的に利用可能になる。\nWWDC 2025で発表された各OSには、その場で逐次通訳／翻訳を行う「\n**Live Translate（ライブ翻訳）**」という機能が加わる。\nライブ翻訳機能の実装に当たっては「音声認識」「自然言語処理」「音声合成」という複数のAI技術を統合し、各アプリの機能として実装している。\n例えば「Message（メッセージ）アプリ」では、会話スレッド全体の履歴から文脈を考慮した上で適切な翻訳を提供する。「FaceTimeアプリ」のリアルタイム翻訳キャプションは、オンデバイスならではの低レイテンシーを維持しながら、高精度な翻訳を動画コミュニケーションの中で実現する。\nそして「電話アプリ」での音声読み上げは、自分が発話した言葉を相手の言語でリピート発話する機能で（逆方向も可）、相手の話し方のニュアンスを文脈で保持しながら逐次通訳してくれる。",
          "title": "WWDC 2025基調講演から見るAppleの“進む道” 「UIデザイン ...",
          "url": "https://www.itmedia.co.jp/pcuser/articles/2506/10/news090_2.html",
          "date": "2025-06-11",
          "last_updated": "2025-10-21"
        },
        {
          "snippet": "",
          "title": "オンデバイス基盤モデルのためのプロンプトの設計と安全性 ...",
          "url": "https://developer.apple.com/jp/videos/play/wwdc2025/248/",
          "date": "2025-06-09",
          "last_updated": "2026-05-05"
        },
        {
          "snippet": "**Apple Intelligence**（アップル インテリジェンス）は、Appleが独自開発している人工知能プラットフォームである。2024年6月10日にWWDC2024の基調講演で、オンデバイス（小規模言語モデル）をベースとして自社サーバでの処理（Private Cloud Compute、大規模言語モデル）を組み合わせたシステムとして発表された。\n2024年10月28日からアメリカ英語での一部機能のベータテストとして、iOS 18.1, iPadOS 18.1, macOS Sequoia 15.1以降に統合され、アメリカ英語では各OSのバージョン18.2で正式にリリースされた。\n...\nOpenAIとの提携により、iOS 18.2, iPadOS 18.2, macOS Sequoia 15.2からはApple IntelligenceベースのSiriから外部のChatGPTをユーザが任意で呼び出して利用できる機能が実装されている。\n...\n2024年6月11日（日本時間）、WWDC2024にて、プライバシー保護に配慮し、パーソナルコンテキストを理解する、独自開発した生成モデルを据えるパーソナルインテリジェンスシステム（人工知能プラットフォーム）として、iOS 18、iPadOS 18、macOS Sequoiaでの全面採用と応用した多数の機能が発表された。\n...\n|18.1|15.1|2024年10月28日|- 作文ツール（校正、要約、書き換えのみ） - Siri (新しい外観、Siriに入力、文脈の改善) - スマートな返信 - 通知の概要 - 写真のクリーンアップとメモリメーカー - 割り込みを減らすフォーカスモード|\n|18.2|15.2|2024年12月11日|- さらに作文ツール強化（ChatGPTで作成、説明変更） - Image Playground - Image Wand - Siri (ChatGPT統合) - メールの分類(iPhone) - Genmoji (iPhoneとiPadのみ) - Visual Intelligence (iPhone 16/16 Pro/16 Pro Maxに対応)|\n|18.4|15.4|2025年3月31日|- 言語サポート追加（中国語、英語（インド）、英語（シンガポール）、フランス語、ドイツ語、イタリア語、日本語、韓国語、ポルトガル語、スペイン語、ベトナム語） - 優先通知 - メールの分類 (iPadとMac) - Image Playgroundスケッチ - Visual Intelligence (iPhone 15 Pro/Pro MaxとiPhone 16eに対応)|\n|26.1|26.1|2025年11月3日|ライブ翻訳- メッセージː 日本語、中国語（簡体字）、英語（英国、米国）、フランス語（フランス）、ドイツ語、イタリア語、韓国語、ポルトガル語（ブラジル）、スペイン語（スペイン） - 電話とFaceTimeː 英語（英国、米国）、フランス語（フランス）、ドイツ語、ポルトガル語（ブラジル）、スペイン語（スペイン）|\n...\n- これまでの会話内容を理解していることで、代名詞などでも文を理解する事が可能になる。また、画面上の物事についても理解する事が可能となる。個人の機密情報を検索する際であっても、オンデバイス（デバイス内での）処理となるため、機密情報が外に漏れることはなく、外部と共有する際には事前にユーザの同意が必要となる仕組みである。\n...\nApple Intelligenceを活用し、自動でアルバムを生成したり、音楽と共にスライドショーを作成する機能の機能向上とより一層複雑な検索キーワードに対応した検索機能や、意図しない写り込みを除去してくれる機能などが搭載される。\n...\nApple Intelligenceは、ユーザのプライバシーを保護するため基本的にオンデバイスで実行され、個人情報を収集することなく、情報を認識するよう設計されている。\nしかし、オンデバイスでの処理に適さない場合には、Private Cloud Computeと呼ばれるAppleシリコンによるサーバベースのデータセンターを利用し、必要最小限の情報のみを利用し、匿名化と暗号化でプライバシーを保護しながら、ユーザの提供したデータは一時利用のみで保管せず、より複雑なリクエストを処理する。",
          "title": "Apple Intelligence - Wikipedia",
          "url": "https://ja.wikipedia.org/wiki/Apple_Intelligence",
          "date": "2024-06-11",
          "last_updated": "2026-05-22"
        },
        {
          "snippet": "",
          "title": "Platforms State of the Union - WWDC24 - ビデオ - Apple Developer",
          "url": "https://developer.apple.com/jp/videos/play/wwdc2024/102/?time=2408",
          "date": null,
          "last_updated": "2026-04-07"
        },
        {
          "snippet": "# アップルの「Apple Intelligence」で新機能、あらゆるアプリがオンデバイスAIモデルへアクセスできるように\n...\n今回、新機能として、新しいFoundation Modeles frameworkにより、あらゆるアプリが、オンデバイスの大規模言語モデルにアクセスできるようになる。\nこれにより、Apple Intellgenceが利用できるアプリがサードパーティ製アプリにまで、セキュリティを担保した形で大幅に拡充される見込みだ。",
          "title": "あらゆるアプリがオンデバイスAIモデルへアクセスできるように",
          "url": "https://k-tai.watch.impress.co.jp/docs/news/2021215.html",
          "date": "2025-06-10",
          "last_updated": "2026-03-21"
        },
        {
          "snippet": "今回、新機能として、新しいFoundation Modeles frameworkにより、あらゆるアプリが、オンデバイスの大規模言語モデルにアクセスできるようになる。\nこれにより、Apple Intellgenceが利用できるアプリがサードパーティ製アプリにまで、セキュリティを担保した形で大幅に拡充される見込みだ。",
          "title": "アップルの「Apple Intelligence」で新機能、あらゆるアプリがオンデバイスAIモデルへアクセスできるように - ライブドアニュース",
          "url": "https://news.livedoor.com/article/detail/28928262/",
          "date": "2025-06-10",
          "last_updated": "2025-08-16"
        }
      ],
      "server_time": null
    }
    ```
  </Accordion>

  <Accordion title="Response — Lo más destacado del programa Y Combinator W26">
    ```json theme={null}
    {
      "id": "5ba2613b-32d0-4dd0-ac13-b5584566180c",
      "results": [
        {
          "snippet": "Didit entra en YC W26 tras recaudar ~$2M y crecer +20% MoM.\n...\n**Didit forma parte oficialmente del batch Winter 2026 de Y Combinator.**",
          "title": "Didit recauda $2M y entra en Y Combinator (W26)",
          "url": "https://didit.me/es/blog/didit-enters-y-combinator/",
          "date": "2025-12-02",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "So what have we learned about this batch so far?\n- 64% of the batch are B2B startups, with many building products across productivity, the stack for engineers and infrastructure tools.\n- The consumer category is barely represented in this batch, with only about 5% of startups building within the category.\n- Healthcare is gaining momentum, making up nearly 10% of the batch.\nNotable areas include wearable technologies and drug discovery.\n- The legal tech category is also heating up.\nThis may be driven by the rapid success of platforms like Legora (a YC company) and Harvey, both of which reached unicorn status shortly after founding.\nIt’s therefore not surprising that around 4% of this batch is building in the legal category.\n...\nIn under three weeks, over 180 startups from the latest Y Combinator batch will present to investors at the Winter ‘26 Demo Day, and this may be the strongest batch yet.\n...\nMeet the 180+ startups from YC’s latest batch who are building across the following categories:",
          "title": "Y Combinator W26: The Full Batch - by Ollie Forsyth - New Economies",
          "url": "https://www.neweconomies.co/p/yc-w26-batch",
          "date": "2026-03-05",
          "last_updated": "2026-05-24"
        },
        {
          "snippet": "",
          "title": "Ranking the Best and Worst Y Combinator W26 Companies - YouTube",
          "url": "https://www.youtube.com/watch?v=DtHP5jLgshk",
          "date": "2026-02-02",
          "last_updated": "2026-05-24"
        },
        {
          "snippet": "El **Demo Day Winter 2026 de Y Combinator (YC)** puso en vitrina 16 startups consideradas las más disruptivas de esta edición.\nLos sectores abordados son diversos, desde soluciones de **IA aplicada**, **robótica humana**, hasta plataformas para optimizar experiencias digitales y resolver problemas cotidianos.\nStartups como **LiftAI**, que ayuda a evitar el 'doomscrolling' con IA personalizada, o **NeuroDynamiX**, enfocada en el entrenamiento de robots humanoides, ejemplifican la variedad y profundidad tecnológica que YC fomenta.\n...\nLos proyectos de esta edición señalan una clara aceleración en **aplicaciones prácticas de IA** y una fuerte apuesta por la automatización de procesos empresariales.\n...\nEl Demo Day de YC Winter 2026 muestra que la innovación tecnológica sigue un ritmo acelerado, con soluciones de alto impacto que marcan tendencia para el ecosistema global.",
          "title": "Startups destacadas del YC W'26 Demo Day: análisis y tendencias",
          "url": "https://ecosistemastartup.com/startups-destacadas-del-yc-w26-demo-day-analisis-y-tendencias/",
          "date": "2026-03-26",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "**Captain** es una startup del batch **Winter 2026 de Y Combinator** que automatiza los pipelines de **Retrieval-Augmented Generation (RAG)** para archivos y datos no estructurados.\nSu propuesta central es sencilla pero poderosa: conectar tus repositorios de archivos y obtener búsquedas de conocimiento con una precisión radicalmente superior a la del RAG tradicional, pasando de un promedio del **78% al 95%** de exactitud, con citas verificables en cada resultado.\n...\nLa diferencia que Captain defiende es su enfoque en la **automatización completa del pipeline** y la mejora medible de precisión (78% → 95%) como métrica central y verificable.\n**Garry Tan**, CEO de **Y Combinator**, calificó públicamente este salto de precisión como un *step function increase* respecto al RAG estándar, lo que da credibilidad institucional al claim técnico.\n...\n**Captain (YC W26)** llega a resolver uno de los problemas más frustrantes del stack de IA moderno: construir sistemas RAG que funcionen bien en producción, no solo en demos.\nSu apuesta por la automatización total del pipeline, la mejora verificable de precisión del **78% al 95%** y una integración simple vía **API REST** lo posicionan como una herramienta relevante para cualquier founder que esté construyendo sobre datos no estructurados.",
          "title": "Captain YC W26: RAG automatizado con 95% de precisión",
          "url": "https://ecosistemastartup.com/captain-yc-w26-rag-automatizado-con-95-de-precision/",
          "date": "2026-03-13",
          "last_updated": "2026-03-26"
        },
        {
          "snippet": "# Las 16 startups más interesantes de YC en el Demo Day W26\nDesde la automatización en la arquitectura hasta la detección de drones, estas 16 startups presentaron propuestas únicas en el reciente Demo Day de Y Combinator, destacando en diversas industrias.\n...\n**AI** fue nuevamente la palabra de moda en esta última edición del **Demo Day** de **Y Combinator** (YC).\n...\nEn lugar de eso, se revisaron las 190 startups que presentaron y se dedicó el día a ver las presentaciones de las más intrigantes, para luego seleccionar las 16 que se destacaron como las más interesantes de esta abarrotada clase de YC.\n**ARC Prize Foundation**\n**Qué hace:** Crea referencias para ayudar a medir el progreso hacia la **AGI**.\n...\nEs un evento donde las startups que participan en el programa de aceleración de Y Combinator presentan sus productos e ideas a inversores y medios.\n...\n**ARC Prize Foundation**, que busca medir el progreso hacia la inteligencia artificial general (AGI).",
          "title": "Las 16 startups más interesantes de YC en el Demo Day W26",
          "url": "https://www.cadena3.com/noticia/tecnologia/las-16-startups-mas-interesantes-de-yc-en-el-demo-day-w26_534171",
          "date": "2026-03-27",
          "last_updated": "2026-05-08"
        },
        {
          "snippet": "La \"Lista de Deseos para Startups\" de Y Combinator para la primavera de 2026 enfatiza el potencial transformador de la IA en diez sectores poco explorados.\nLa incubadora destaca el cambio de la IA como generadora de contenido a una herramienta para resolver problemas complejos y remodelar industrias.\nLas áreas clave de enfoque incluyen fondos de cobertura nativos de IA, que buscan revolucionar las estrategias de inversión aprovechando la IA para un análisis de mercado integral, y empresas de servicios impulsadas por IA que mejoran la eficiencia y la escalabilidad en industrias tradicionalmente intensivas en mano de obra.\nLa lista también subraya el potencial de los servicios financieros derivados de stablecoins, ofreciendo un puente entre las finanzas tradicionales y DeFi, y la modernización de los sistemas industriales mediante la planificación de producción impulsada por IA.\nAdemás, Y Combinator ve oportunidades en mejoras de IA para operaciones gubernamentales, orientación en tiempo real con IA para trabajos físicos y el desarrollo de grandes modelos espaciales para mejorar la comprensión del mundo físico por parte de la IA.\nEstas iniciativas reflejan una tendencia más amplia de integración de la IA en diversos sectores, prometiendo avances y eficiencias significativas.",
          "title": "RFS 2026 de Y Combinator: IA transformará 10 sectores clave",
          "url": "https://phemex.com/es/news/article/y-combinators-spring-2026-rfs-highlights-ais-role-in-transforming-10-key-sectors-59256",
          "date": "2026-02-09",
          "last_updated": "2026-03-11"
        },
        {
          "snippet": "El reciente Demo Day de Y Combinator, correspondiente a la cohorte de invierno del 2026, ha traído consigo una ola de innovaciones tecnológicas, con cerca de 190 startups presentándose ante un público ávido de nuevas ideas.\nEntre ellas, se destacan 16 startups que no solo llamaron la atención, sino que prometen revolucionar diversas industrias como la salud, el transporte y el derecho.\n...\nUna de las temáticas más recurrentes ha sido la inteligencia artificial, que sigue siendo un foco de interés y desarrollo.\nCon proyectos que abarcan desde la formación de humanoides hasta herramientas que optimizan el trabajo en oficinas de arquitectura, estas startups ilustran el potencial transformador de la IA.\n...\nEntre las ofertas innovadoras, Asimov resalta por su enfoque en recopilar datos sobre movimientos humanos que pueden servir para entrenar robots humanoides, una tendencia interesante que va más allá de la simple automatización y busca incorporar elegancia en la manera en que estas máquinas realizan tareas.\n...\nPor último, CodeWisp se diferencia al permitir que cualquiera pueda crear juegos utilizando inteligencia artificial, democratizando así el desarrollo de videojuegos y abriendo las puertas a nuevas formas de expresión creativa.\nEl Demo Day de YC W26 ha demostrado una vez más que la innovación está en constante evolución, ofreciendo un vistazo al futuro donde la tecnología y la creatividad se entrelazan para generar soluciones efectivas y emocionantes.",
          "title": "Innovaciones del Demo Day: 16 Startups Fascinantes de YC",
          "url": "https://www.newstory.tips/es/articles/858/innovaciones-del-demo-day-16-startups-fascinantes-de-yc",
          "date": "2026-03-30",
          "last_updated": "2026-04-20"
        }
      ],
      "server_time": null
    }
    ```
  </Accordion>
</AccordionGroup>

**4. Combining with Other Filters**

Language filters work seamlessly with other search parameters for precise control:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Combine language filter with date and domain filters
  response = client.search.create(
      query="IPCC AR6 synthesis report key findings",
      max_results=20,
      search_language_filter=["en", "de"],
      search_domain_filter=["nature.com", "science.org"],
      search_recency_filter="month"
  )

  for result in response.results:
      print(f"{result.title}")
      print(f"URL: {result.url}")
      print(f"Date: {result.date}")
      print("---")
  ```

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

  const client = new Perplexity();

  // Combine language filter with date and domain filters
  const response = await client.search.create({
    query: "IPCC AR6 synthesis report key findings",
    max_results: 20,
    search_language_filter: ["en", "de"],
    search_domain_filter: ["nature.com", "science.org"],
    search_recency_filter: "month"
  });

  for (const result of response.results) {
    console.log(`${result.title}`);
    console.log(`URL: ${result.url}`);
    console.log(`Date: ${result.date}`);
    console.log("---");
  }
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "IPCC AR6 synthesis report key findings",
      "max_results": 20,
      "search_language_filter": ["en", "de"],
      "search_domain_filter": ["nature.com", "science.org"],
      "search_recency_filter": "month"
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "75c39a4e-a46c-4850-bf27-4c061186ece6",
    "results": [
      {
        "snippet": "",
        "title": "10 Big Findings from the 2023 IPCC Report on Climate Change",
        "url": "https://www.wri.org/insights/2023-ipcc-ar6-synthesis-report-climate-change-findings",
        "date": "2023-03-20",
        "last_updated": "2026-05-15"
      },
      {
        "snippet": "",
        "title": "AR6 Synthesis Report",
        "url": "https://www.ipcc.ch/report/ar6/syr/",
        "date": null,
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "",
        "title": "[PDF] Climate Change 2023 Synthesis Report",
        "url": "https://www.ipcc.ch/report/ar6/syr/downloads/report/IPCC_AR6_SYR_LongerReport.pdf",
        "date": null,
        "last_updated": "2026-05-18"
      },
      {
        "snippet": "The Synthesis Report is based on the content of the three Working Groups Assessment Reports:* WGI – The Physical Science Basis, WGII – Impacts, Adaptation and Vulnerability, WGIII – Mitigation of Climate Change*, and the three Special Reports: *Global Warming of 1.5°C*, *Climate Change and Land*, *The Ocean and Cryosphere in a Changing Climate*.\n...\nThe SYR outline agreed at the 52^nd^ Panel Session of the IPCC consists of an introduction and three main sections arranged by timeframes.\nThe first section, ‘Current Status and Trends’, covers the historical and present period.\nThe second section, ‘Long-term Climate and Development Futures’, addresses projected futures up to 2100 and beyond.\nThe final section is ‘Near-term Responses in a Changing Climate’, considers current international policy timeframes, and the time interval between now and 2030-2040.\nThis structure, substantially different to what was adopted for AR5 SYR, enables a holistic framing that integrates across the Working Groups, better enabling the SYR to cover different aspects of climate change.",
        "title": "AR6 Synthesis Report: Climate Change 2023 — IPCC",
        "url": "https://www.ipcc.ch/report/sixth-assessment-report-cycle/",
        "date": null,
        "last_updated": "2026-05-12"
      },
      {
        "snippet": "",
        "title": "[PDF] IPCC_AR6_SYR_FullVolume.pdf",
        "url": "https://www.ipcc.ch/report/ar6/syr/downloads/report/IPCC_AR6_SYR_FullVolume.pdf",
        "date": null,
        "last_updated": "2026-05-20"
      },
      {
        "snippet": "",
        "title": "Summary for Policymakers",
        "url": "https://www.ipcc.ch/report/ar6/syr/summary-for-policymakers/",
        "date": null,
        "last_updated": "2026-05-20"
      },
      {
        "snippet": "",
        "title": "SYR Longer Report - Intergovernmental Panel on Climate Change",
        "url": "https://www.ipcc.ch/report/ar6/syr/longer-report/",
        "date": null,
        "last_updated": "2026-03-21"
      },
      {
        "snippet": "",
        "title": "IPCC Secretariat",
        "url": "https://www.ipcc.ch/site/assets/uploads/2023/03/Doc5_Adopted_AR6_SYR_Longer_Report.pdf",
        "date": null,
        "last_updated": "2024-02-26"
      },
      {
        "snippet": "",
        "title": "IPCC AR6 Working Group 1: Technical Summary",
        "url": "https://www.ipcc.ch/report/ar6/wg1/chapter/technical-summary/",
        "date": null,
        "last_updated": "2026-03-18"
      },
      {
        "snippet": "",
        "title": "IPCC_AR6_SYR_SPM.pdf",
        "url": "https://www.ipcc.ch/report/ar6/syr/downloads/report/IPCC_AR6_SYR_SPM.pdf",
        "date": null,
        "last_updated": "2026-05-21"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

## Parameter Reference

### `search_language_filter`

* **Type**: Array of strings
* **Format**: ISO 639-1 language codes (2 lowercase letters)
* **Description**: Filters search results to only include content in the specified languages
* **Optional**: Yes
* **Maximum**: 10 language codes per request
* **Example**: `"search_language_filter": ["en", "fr", "de"]`

## Common Language Codes

Here's a comprehensive list of frequently used ISO 639-1 language codes:

| Language   | Code | Language   | Code |
| ---------- | ---- | ---------- | ---- |
| English    | `en` | Portuguese | `pt` |
| Spanish    | `es` | Dutch      | `nl` |
| French     | `fr` | Polish     | `pl` |
| German     | `de` | Swedish    | `sv` |
| Italian    | `it` | Norwegian  | `no` |
| Russian    | `ru` | Danish     | `da` |
| Chinese    | `zh` | Finnish    | `fi` |
| Japanese   | `ja` | Czech      | `cs` |
| Korean     | `ko` | Hungarian  | `hu` |
| Arabic     | `ar` | Greek      | `el` |
| Hindi      | `hi` | Turkish    | `tr` |
| Bengali    | `bn` | Hebrew     | `he` |
| Indonesian | `id` | Thai       | `th` |
| Vietnamese | `vi` | Ukrainian  | `uk` |

<Tip>
  For a complete list of ISO 639-1 language codes, see the [ISO 639-1 standard](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes).
</Tip>

## Best Practices

### Language Code Validation

* **Use Valid Codes**: Always use valid 2-letter ISO 639-1 codes. Invalid codes will result in an API error.
* **Lowercase Only**: Language codes must be lowercase (e.g., "en" not "EN").
* **Client-Side Validation**: Validate language codes on the client side using a regex pattern:

<CodeGroup>
  ```python Python theme={null}
  import re

  def validate_language_code(code):
      pattern = r'^[a-z]{2}$'
      return bool(re.match(pattern, code))

  def validate_language_filters(codes):
      if len(codes) > 10:
          raise ValueError("Maximum 10 language codes allowed")
      
      for code in codes:
          if not validate_language_code(code):
              raise ValueError(f"Invalid language code: {code}")
      
      return True

  # Usage
  try:
      codes = ["en", "fr", "de"]
      validate_language_filters(codes)
      
      response = client.search.create(
          query="Apple WWDC 基調講演で発表されたオンデバイスAI機能",
          search_language_filter=codes
      )
  except ValueError as e:
      print(f"Validation error: {e}")
  ```

  ```typescript Typescript theme={null}
  function validateLanguageCode(code: string): boolean {
    const pattern = /^[a-z]{2}$/;
    return pattern.test(code);
  }

  function validateLanguageFilters(codes: string[]): void {
    if (codes.length > 10) {
      throw new Error("Maximum 10 language codes allowed");
    }
    
    for (const code of codes) {
      if (!validateLanguageCode(code)) {
        throw new Error(`Invalid language code: ${code}`);
      }
    }
  }

  // Usage
  try {
    const codes = ["en", "fr", "de"];
    validateLanguageFilters(codes);
    
    const response = await client.search.create({
      query: "Apple WWDC 基調講演で発表されたオンデバイスAI機能",
      search_language_filter: codes
    });
  } catch (error) {
    console.error("Validation error:", error.message);
  }
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "5e873edb-6a76-4b00-8088-07b7350be1cc",
    "results": [
      {
        "snippet": "今年の基調講演では、iPhone、iPad、Macの中心で生成モデルのパワーとユーザーの個人的な背景を組み合わせて、驚くほど有用で関連性のあるインテリジェンスを提供するパーソナルインテリジェンスシステムであるApple Intelligenceを発表しました。\n...\n**Apple、Apple Intelligenceを発表**\nApple Intelligenceは、Appleシリコンのパワーを活用して、言語や画像を理解して生成したり、複数のアプリにわたってアクションを実行したり、ユーザーの個人的な背景にもとづいて、日々のタスクをシンプルにしてよりすばやくこなせるようにします。\nApple Intelligenceの基礎はデバイス上の処理で、ユーザーのデータを収集することなくパーソナルインテリジェンスを提供します。Private Cloud ComputeはAIにおけるプライバシーの新しい基準を打ち立て、デバイス上の処理から、専用のAppleシリコン搭載のサーバ上で実行する、より大規模なサーバベースのモデルにまで、演算能力を柔軟に拡張できます。\n...\nApple IntelligenceはAppleシリコンとNeural Engineのパワーを最大限に活用し、Mシリーズチップを搭載したすべてのMacで利用できるようになります。",
        "title": "WWDC24のハイライト",
        "url": "https://www.apple.com/jp/newsroom/2024/06/wwdc24-highlights/",
        "date": "2024-03-26",
        "last_updated": "2025-01-20"
      },
      {
        "snippet": "",
        "title": "Apple Intelligence - Apple（日本）",
        "url": "https://www.apple.com/jp/apple-intelligence/",
        "date": null,
        "last_updated": "2026-03-28"
      },
      {
        "snippet": "# Apple製デバイス全体に及ぶ新機能により、Apple Intelligenceがさらにパワフルになります\nデベロッパは、Apple Intelligenceのデバイス上の基盤モデルにアクセスして、プライバシーを保護し、インテリジェントな体験をアプリに組み込めるようになります\n**カリフォルニア州クパティーノ**Appleは本日、iPhone、iPad、Mac、Apple Watch、Apple Vision Proのユーザー体験を向上させるApple Intelligenceの新機能を発表しました。\nApple Intelligenceが実現する新たな方法によって、ユーザーはライブ翻訳のような機能を利用してコミュニケーションをとったり、ビジュアルインテリジェンスのアップデートによって画面上に表示されているものに対してより多くのことをしたり、強化されたImage Playgroundやジェン文字を使用して自分自身を表現したりできるようになります\n1。さらに、ショートカットでApple Intelligenceを直接利用できるようになったほか、デベロッパがApple Intelligenceの中核にあるデバイス上の大規模言語モデルにアクセスできるようになります。そのため、デベロッパは、パワフルかつ高速で、プライバシーが組み込まれ、ユーザーがオフラインの時にも使えるインテリジェンスに、直接アクセスできるようになります。\nこれらのApple Intelligenceの機能は、本日よりテスト用に提供され、対応するデバイスで対応する言語に設定しているユーザーは今秋から利用できるようになります。\n...\nそのため、パワフルかつ高速で、プライバシーが組み込まれ、ユーザーがオフラインの時にも使えるインテリジェンスを活用できるようになります。これにより、ユーザーが日々活用しているアプリでまったく新しいインテリジェントな体験を次々に生み出せるようになると考えています。\n...\nユーザーの前に言語の壁が立ち塞がった時は、ライブ翻訳を利用すれば、メッセージの送信や会話の際に言語をまたいでコミュニケーションをとることができます。この体験は、メッセージ、FaceTime、電話に組み込まれるもので、Appleが構築した完全にデバイス上で動作するモデルによって実現するため、ユーザーの個人的な会話のプライバシーが保たれます。\n...\n2。FaceTimeでは、話し手の声を聞きながら、翻訳されたライブキャプションによって会話についていくことができます。また、電話の通話では、会話の全体を通して、翻訳が音声で読み上げられます 3。\n...\nジェン文字とImage Playgroundは、ユーザーにさらに多くの自己表現の方法を提供します。テキストによる説明をジェン文字に変換するだけでなく、絵文字を取り入れ、それらを説明と組み合わせることによって、新しいものを作り出せるようになります。\n...\nApple Intelligenceを基盤とするビジュアルインテリジェンスがユーザーのiPhoneの画面に拡張され、ユーザーはあらゆるアプリで、画面上に表示しているものを検索し操作できます。\nビジュアルインテリジェンスはすでに、ユーザーがiPhoneのカメラを使用して周囲の対象物や場所について学ぶのに役立っていますが、これからはiPhoneの画面上に表示されているものについて、より多くのことを、より速く実行できるようになります。\n...\nビジュアルインテリジェンスは、イベントが表示されていることを認識してカレンダーへの追加を提案し\n...\nWorkout Buddyは、Apple Intelligenceを利用した、ほかに類を見ないApple Watchのワークアウト体験で、ユーザーのワークアウトのデータとフィットネス履歴を取り込み、パーソナライズされた、モチベーションを高める洞察をセッション中に生成します\n5。\n...\nAppleは、Apple Intelligenceの中核にあるデバイス上の基盤モデルをどのアプリからでも直接利用できるようにしました。\nFoundation Modelフレームワークを利用すれば、アプリのデベロッパはApple Intelligenceをベースに、無料のAI推論を利用して、インテリジェントで、オフラインでも利用でき、プライバシーが保護される新たな体験をユーザーに提供できるようになります。\n...\nショートカットがこれまで以上にパワフルで賢くなります。ユーザーは、Apple Intelligenceによって実現したまったく新しい一連のショートカットであるインテリジェントなアクションを利用することができます。作文ツールによるテキストの要約や、Image Playgroundによる画像の生成などの機能に対応する専用のアクションが提供されます。\nユーザーはデバイス上で、またはプライベートクラウドコンピューティングによって、Apple Intelligenceのモデルを直接利用し、ショートカット内で利用される情報のプライバシーを保ったまま、ほかのショートカットに送るレスポンスを生成できるようになります。\n...\nあらゆる段階でユーザーのプライバシーを保護するように設計されたApple Intelligenceは、デバイス上の処理を使用しているため、それを動かすモデルの多くは完全にデバイス上で実行されます。\n...\nこれらの新機能はすべて、本日よりdeveloper.apple.com/jpでApple Developer Programを通じてテスト用に提供されます。パブリックベータ版は来月、beta.apple.com/jaでApple Beta Software Programを通じて提供されます。対応するデバイスでApple Intelligenceを有効にし、対応言語に設定しているユーザーは、今秋からアクセスできるようになります。\n対応するデバイスにはiPhone 16の全モデル、iPhone 15 Pro、iPhone 15 Pro Max、iPad mini（A17 Pro）、M1以降を搭載したiPadとMacのモデルが含まれます。Siriとデバイスの言語は同じ対応言語に設定する必要があります。\n...\n- 電話とFaceTimeのライブ翻訳は、一対一の通話の場合に、英語（米国、英国）、フランス語（フランス）、ドイツ語、ポルトガル語（ブラジル）、スペイン語（スペイン）に対応しています。\n- ビジュアルインテリジェンスでイベントをカレンダーに追加する機能は、iPhone 16の全モデル、iPhone 15 Pro、iPhone 15 Pro Maxで、英語で利用できます。",
        "title": "Apple製デバイス全体に及ぶ新機能により、Apple Intelligenceが ...",
        "url": "https://www.apple.com/jp/newsroom/2025/06/apple-intelligence-gets-even-more-powerful-with-new-capabilities-across-apple-devices/",
        "date": "2025-09-06",
        "last_updated": "2025-11-28"
      },
      {
        "snippet": "衛星経由でのSMSメッセージにも 対応します 次は、もう一つの通信アプリである メールについてです 受信したEメールを管理するための オンデバイスのカテゴリー分け機能が 年内に登場します メッセージ",
        "title": "基調講演 - WWDC24 - ビデオ - Apple Developer",
        "url": "https://developer.apple.com/jp/videos/play/wwdc2024/101/",
        "date": null,
        "last_updated": "2026-05-12"
      },
      {
        "snippet": "今回のWWDCでは、Apple Intelligenceのアップデートもアナウンスされた。\nWWDC 2025における“目玉”の1つとして、\n**アプリ開発者に対するApple Intelligenceで使っているAIモデルの開放**が挙げられる。\nApple Intelligenceは、複数のAIモデルを組み合わせているが、特に完全オンデバイスのモデルを利用できるようになることで「応答時間の削減」「オフライン動作の保証」「プライバシー保護」を実現できる。\nAIモデルは「Foundation Modelsフレームワーク」を通して利用可能で、開発者は自分のアプリにAI機能を統合しやすくなる。\nWWDC 2024では、Apple Intelligenceの特徴として「\n**プライベートクラウドコンピューティング**」が発表された。これはより大規模なAIモデルが必要とされる場合に使われるもので、「暗号化」「匿名化」そして「一時的な処理」という3つの原則を徹底していることが特徴だ。\n...\nプライベートクラウドによるAI処理は、「Automation（オートメーション）」や新しい「Spotlight（スポットライト：検索機能）」から明示的に利用可能になる。\nWWDC 2025で発表された各OSには、その場で逐次通訳／翻訳を行う「\n**Live Translate（ライブ翻訳）**」という機能が加わる。\nライブ翻訳機能の実装に当たっては「音声認識」「自然言語処理」「音声合成」という複数のAI技術を統合し、各アプリの機能として実装している。\n例えば「Message（メッセージ）アプリ」では、会話スレッド全体の履歴から文脈を考慮した上で適切な翻訳を提供する。「FaceTimeアプリ」のリアルタイム翻訳キャプションは、オンデバイスならではの低レイテンシーを維持しながら、高精度な翻訳を動画コミュニケーションの中で実現する。\nそして「電話アプリ」での音声読み上げは、自分が発話した言葉を相手の言語でリピート発話する機能で（逆方向も可）、相手の話し方のニュアンスを文脈で保持しながら逐次通訳してくれる。",
        "title": "WWDC 2025基調講演から見るAppleの“進む道” 「UIデザイン ...",
        "url": "https://www.itmedia.co.jp/pcuser/articles/2506/10/news090_2.html",
        "date": "2025-06-11",
        "last_updated": "2025-10-21"
      },
      {
        "snippet": "",
        "title": "オンデバイス基盤モデルのためのプロンプトの設計と安全性 ...",
        "url": "https://developer.apple.com/jp/videos/play/wwdc2025/248/",
        "date": "2025-06-09",
        "last_updated": "2026-05-05"
      },
      {
        "snippet": "**Apple Intelligence**（アップル インテリジェンス）は、Appleが独自開発している人工知能プラットフォームである。2024年6月10日にWWDC2024の基調講演で、オンデバイス（小規模言語モデル）をベースとして自社サーバでの処理（Private Cloud Compute、大規模言語モデル）を組み合わせたシステムとして発表された。\n2024年10月28日からアメリカ英語での一部機能のベータテストとして、iOS 18.1, iPadOS 18.1, macOS Sequoia 15.1以降に統合され、アメリカ英語では各OSのバージョン18.2で正式にリリースされた。\n...\nOpenAIとの提携により、iOS 18.2, iPadOS 18.2, macOS Sequoia 15.2からはApple IntelligenceベースのSiriから外部のChatGPTをユーザが任意で呼び出して利用できる機能が実装されている。\n...\n2024年6月11日（日本時間）、WWDC2024にて、プライバシー保護に配慮し、パーソナルコンテキストを理解する、独自開発した生成モデルを据えるパーソナルインテリジェンスシステム（人工知能プラットフォーム）として、iOS 18、iPadOS 18、macOS Sequoiaでの全面採用と応用した多数の機能が発表された。\n...\n|18.1|15.1|2024年10月28日|- 作文ツール（校正、要約、書き換えのみ） - Siri (新しい外観、Siriに入力、文脈の改善) - スマートな返信 - 通知の概要 - 写真のクリーンアップとメモリメーカー - 割り込みを減らすフォーカスモード|\n|18.2|15.2|2024年12月11日|- さらに作文ツール強化（ChatGPTで作成、説明変更） - Image Playground - Image Wand - Siri (ChatGPT統合) - メールの分類(iPhone) - Genmoji (iPhoneとiPadのみ) - Visual Intelligence (iPhone 16/16 Pro/16 Pro Maxに対応)|\n|18.4|15.4|2025年3月31日|- 言語サポート追加（中国語、英語（インド）、英語（シンガポール）、フランス語、ドイツ語、イタリア語、日本語、韓国語、ポルトガル語、スペイン語、ベトナム語） - 優先通知 - メールの分類 (iPadとMac) - Image Playgroundスケッチ - Visual Intelligence (iPhone 15 Pro/Pro MaxとiPhone 16eに対応)|\n|26.1|26.1|2025年11月3日|ライブ翻訳- メッセージː 日本語、中国語（簡体字）、英語（英国、米国）、フランス語（フランス）、ドイツ語、イタリア語、韓国語、ポルトガル語（ブラジル）、スペイン語（スペイン） - 電話とFaceTimeː 英語（英国、米国）、フランス語（フランス）、ドイツ語、ポルトガル語（ブラジル）、スペイン語（スペイン）|\n...\n- これまでの会話内容を理解していることで、代名詞などでも文を理解する事が可能になる。また、画面上の物事についても理解する事が可能となる。個人の機密情報を検索する際であっても、オンデバイス（デバイス内での）処理となるため、機密情報が外に漏れることはなく、外部と共有する際には事前にユーザの同意が必要となる仕組みである。\n...\nApple Intelligenceを活用し、自動でアルバムを生成したり、音楽と共にスライドショーを作成する機能の機能向上とより一層複雑な検索キーワードに対応した検索機能や、意図しない写り込みを除去してくれる機能などが搭載される。\n...\nApple Intelligenceは、ユーザのプライバシーを保護するため基本的にオンデバイスで実行され、個人情報を収集することなく、情報を認識するよう設計されている。\nしかし、オンデバイスでの処理に適さない場合には、Private Cloud Computeと呼ばれるAppleシリコンによるサーバベースのデータセンターを利用し、必要最小限の情報のみを利用し、匿名化と暗号化でプライバシーを保護しながら、ユーザの提供したデータは一時利用のみで保管せず、より複雑なリクエストを処理する。",
        "title": "Apple Intelligence - Wikipedia",
        "url": "https://ja.wikipedia.org/wiki/Apple_Intelligence",
        "date": "2024-06-11",
        "last_updated": "2026-05-22"
      },
      {
        "snippet": "",
        "title": "Platforms State of the Union - WWDC24 - ビデオ - Apple Developer",
        "url": "https://developer.apple.com/jp/videos/play/wwdc2024/102/?time=2408",
        "date": null,
        "last_updated": "2026-04-07"
      },
      {
        "snippet": "# アップルの「Apple Intelligence」で新機能、あらゆるアプリがオンデバイスAIモデルへアクセスできるように\n...\n今回、新機能として、新しいFoundation Modeles frameworkにより、あらゆるアプリが、オンデバイスの大規模言語モデルにアクセスできるようになる。\nこれにより、Apple Intellgenceが利用できるアプリがサードパーティ製アプリにまで、セキュリティを担保した形で大幅に拡充される見込みだ。",
        "title": "あらゆるアプリがオンデバイスAIモデルへアクセスできるように",
        "url": "https://k-tai.watch.impress.co.jp/docs/news/2021215.html",
        "date": "2025-06-10",
        "last_updated": "2026-03-21"
      },
      {
        "snippet": "今回、新機能として、新しいFoundation Modeles frameworkにより、あらゆるアプリが、オンデバイスの大規模言語モデルにアクセスできるようになる。\nこれにより、Apple Intellgenceが利用できるアプリがサードパーティ製アプリにまで、セキュリティを担保した形で大幅に拡充される見込みだ。",
        "title": "アップルの「Apple Intelligence」で新機能、あらゆるアプリがオンデバイスAIモデルへアクセスできるように - ライブドアニュース",
        "url": "https://news.livedoor.com/article/detail/28928262/",
        "date": "2025-06-10",
        "last_updated": "2025-08-16"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

### Strategic Language Selection

* **Be Specific**: Choose languages that are most relevant to your research or application needs.
* **Consider Your Audience**: Select languages that match your target audience's preferences.
* **Regional Relevance**: Combine language filters with geographic filters (`country` parameter) for better regional targeting.
* **Content Availability**: Some topics may have limited content in certain languages. Start broad and narrow down as needed.

### Performance Considerations

* **Filter Size**: While you can specify up to 10 languages, using fewer languages may improve response times.
* **Result Quality**: More languages mean a broader search scope, which can dilute result relevance. Be strategic about which languages to include.
* **Combination Effects**: Language filters combined with other restrictive filters (domain, date) may significantly reduce the number of results.

## Advanced Usage Patterns

### Multilingual Research

Conduct comprehensive research by searching across multiple languages:

```python theme={null}
from perplexity import Perplexity

client = Perplexity()

# Research a global topic in multiple languages
languages = [
    ["en"],           # English-speaking countries
    ["zh", "ja"],     # East Asia
    ["es", "pt"],     # Latin America and Iberia
    ["fr", "de", "it"] # Western Europe
]

results_by_region = {}

for lang_group in languages:
    response = client.search.create(
        query="Avances de los Objetivos de Desarrollo Sostenible",
        max_results=10,
        search_language_filter=lang_group
    )
    results_by_region[", ".join(lang_group)] = response.results

# Analyze results by language/region
for region, results in results_by_region.items():
    print(f"Results in {region}: {len(results)} found")
```

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "3271f393-084f-4e71-80de-c6f919001e21",
    "results": [
      {
        "snippet": "Naciones Unidas Informe ODS 2024 Naciones Unidas (en inglés) Informe ODS 2023 Naciones Unidas Informe ODS 2022 Naciones Unidas Informe ODS 2021 Naciones Unidas Europa Informe ODS 2024 en Europa Informe ODS 2023 en Europa Resumen Ejecutivo ODS 2023\nEuropa Informe ODS 2022 Europa Resumen Ejecutivo ODS 2022 Europa Informe ODS 2021 Europa Resumen Ejecutivo ODS 2021 Europa SDS & Me España Examen Nacional Voluntario 2024 Informe de Progreso 2023 España Informe de Progreso 2022 España Informe de Progreso 2021 España",
        "title": "Avance de los ODS en el mundo - Agenda 2030 Castilla-La Mancha",
        "url": "https://agenda2030.castillalamancha.es/avance-de-los-ods-en-el-mundo",
        "date": "2025-01-01",
        "last_updated": "2025-10-19"
      },
      {
        "snippet": "",
        "title": "Agenda 2030 y ODS - ODS UAM - Universidad Autónoma de Madrid",
        "url": "https://ods.uam.es/agenda-2030-y-ods/",
        "date": "2026-04-29",
        "last_updated": "2026-05-25"
      },
      {
        "snippet": "**A falta de seis años para cumplir con la** ** Agenda 2030** **, sólo el 17% de las 169 metas que contienen los ** **17 Objetivos de Desarrollo Sostenible (ODS)** ** de la Agenda 2030 están en camino de conseguirse, ** advierte el Informe sobre ODS 2024 de las Naciones Unidas.\n...\nDesde su lanzamiento, los Objetivos de Desarrollo Sostenible han sido la guía hacia un futuro sostenible y equitativo y un marco de acción prioritario para las empresas y estados.\nSin embargo, **el progreso de estos Objetivos está siendo desigual y enfrenta obstáculos**.\n**El informe de la ONU revela que sólo el 17% de las metas de los ODS están avanzando, la mitad muestra un progreso mínimo o moderado y más de un tercio está estancado o retrocediendo.\n** El aún vigente impacto de la COVID-19, los conflictos y tensiones geopolíticas y el caos climático son algunas de las causas que frenan este progreso.\n...\n- **Aumenta la brecha de financiación de los ODS (** **ODS 17** **): ** la deuda externa de países en desarrollo continúa increíblemente alta y los países desarrollados encaran una brecha de 4 trillones de dólares de inversión para alcanzar los ODS.\n### ODS para mantener la esperanza\nA pesar de los datos abrumadores a nivel global, el informe muestra algunos progresos registrados en ciertos ámbitos de los ODS.\nEn concreto:\n- **Reducción de la pobreza (** **ODS 1** ** y ** **ODS 10** **)**: Asia central y meridional redujeron la pobreza laboral en un 6,9% y la pobreza continua disminuyendo en los países de medianos y altos ingresos.\n- **Mejora de la nutrición (** **ODS 2** **): ** se ha reducido el porcentaje de niños menores de 5 años afectados por el retraso del crecimiento 22,3% y ha aumentado el gasto gubernamental en agricultura.\n- **Avances en salud (** **ODS 3** **): ** se ha reducido a más de la mitad las nuevas infecciones de VIH y ha aumentado al 86% la asistencia de calidad al parto.\n- **Desarrollo en educación (** **ODS 4** **): ** en muchas regiones, las niñas han alcanzado o superado la paridad en la finalización de la escuela y se ha incrementado la tasa de finalización de la educación superior.\n- **Progresos en igualdad de género (** **ODS 5** **): ** desciende a un 20% el porcentaje de niñas que contraen matrimonio en comparación con el 25% de hace 25 años.\n- **Aumenta la producción de energía sostenible (** **ODS 7** **):** la generación de energía renovables ha incrementado un 8,1% anualmente en los pasados cinco años.\n- **Aceleración del empleo (** **ODS 8** **):** el desempleo ha caído a un histórico 5% en 2023.\n- **Aumento de la financiación climática (** **ODS 13** **):** la financiación climática aumentó un 30% desde 2021 desde 2021 alcanzando el objetivo y el 60% se asignó a la mitigación.\n- **Más protección para el océano (** **ODS 14** **):** la cobertura de áreas marinas protegidas se ha multiplicado por diez y la proporción de peces dentro de niveles biológicamente sostenibles aumentó más de una cuarta parte en las principales zonas de pesca.\n- **Progresos en tecnología y datos (** **ODS 17** **):** el acceso a internet ha aumentado un 70% en sólo ocho años y, frente a 2019, 29 nuevos países informaron tener legislación estadística que cumple con los principios.",
        "title": "¿En qué situación se encuentran los ODS de la Agenda 2030?",
        "url": "https://www.pactomundial.org/noticia/en-que-situacion-se-encuentran-los-ods-de-la-agenda-2030/",
        "date": "2025-04-15",
        "last_updated": "2026-05-25"
      },
      {
        "snippet": "> “Como Estados miembros reconocidos en la Cumbre de los ODS celebrada el pasado septiembre, los esfuerzos mundiales llevados a cabo hasta la fecha han sido insuficientes para lograr el cambio que necesitamos, lo que pone en riesgo el compromiso de la Agenda con las generaciones actuales y futuras.\n...\nEn el **Informe de los Objetivos de Desarrollo Sostenible (ODS)**, de periodicidad anual, se proporciona un panorama general de los esfuerzos realizados hasta la fecha para su aplicación en todo el mundo, subrayando las esferas de progreso y las esferas en las que se deben tomar más medidas para garantizar que nadie se quede atrás.\nCuando se cumplen cinco años de la adopción de los Objetivos de Desarrollo Sostenible, el **Informe sobre los Objetivos de Desarrollo Sostenible de 2020** (disponible en inlglés) destaca los progresos que se han logrado en el mundo en algunos ámbitos como la mejora de la salud maternoinfantil, la ampliación del acceso a la electricidad y el aumento de la representación de las mujeres en el Gobierno.\nAun así, estos avances se han visto contrarrestados en todo el mundo por la creciente inseguridad alimentaria, el deterioro del entorno natural y las persistentes desigualdades dominantes.\nAhora, en muy poco tiempo, la pandemia de COVID-19 ha desatado una crisis sin precedentes que obstaculiza aún más el progreso de los ODS, lo que afecta en mayor medida a las personas más pobres y vulnerables del mundo.\nCon base en los datos y las estimaciones más recientes, este informe anual de situación sobre el progreso en los 17 Objetivos revela que las personas más vulnerables (incluidos los niños, ancianos, discapacitados, migrantes y refugiados) son las más gravemente afectadas por la pandemia de COVID-19.\nLas mujeres también están sufriendo las peores consecuencias de la pandemia.\n...\n- Se estima que aproximadamente 71 millones de personas volverán a caer en la extrema pobreza en 2020, lo que supondría el primer aumento de la pobreza mundial desde 1998.\n...\n- Los cierres de las escuelas han afectado al 90 % de los estudiantes de todo el mundo (1.570 millones) y han provocado que más de 370 millones de niños se salten comidas escolares de las que dependen.\n...\n- A medida que más familias caen en la extrema pobreza, los niños de las comunidades pobres y desfavorecidas corren un riesgo mucho mayor de verse involucrados en el trabajo infantil, el matrimonio infantil y el tráfico infantil.\nDe hecho, es probable que los progresos logrados a nivel mundial en la reducción del trabajo infantil se vean invertidos por primera vez en 20 años.\n...\nLos informes anuales ofrecen una descripción general de los esfuerzos mundiales de implementación hasta la fecha, haciendo hincapié en los ámbitos de progreso y aquellos en los que es necesario tomar más medidas.",
        "title": "Informe sobre los progresos en el cumplimiento de los ODS",
        "url": "https://www.un.org/sustainabledevelopment/es/progress-report/",
        "date": "2020-07-15",
        "last_updated": "2026-03-22"
      },
      {
        "snippet": "",
        "title": "Objetivos de Desarrollo Sostenible | Naciones Unidas",
        "url": "https://www.un.org/es/impacto-acad%C3%A9mico/page/objetivos-de-desarrollo-sostenible",
        "date": null,
        "last_updated": "2026-03-26"
      },
      {
        "snippet": "",
        "title": "¿Qué son los Objetivos de Desarrollo Sostenible?",
        "url": "https://www.undp.org/es/sustainable-development-goals",
        "date": null,
        "last_updated": "2026-05-26"
      },
      {
        "snippet": "La **Agenda 2030 para el Desarrollo Sostenible** se compone de 17 objetivos y 169 metas.\nPara su seguimiento, se diseñaron 234 indicadores que pueden medirse a través de los datos estadísticos que aquí se recogen.\nLa actualización de estos indicadores, que constituyen una operación estadística recogida en el Programa anual vigente, es continua e incluye información tanto del INE como de otras fuentes oficiales que se irán incorporando de forma progresiva.",
        "title": "Indicadores de la Agenda 2030 para el Desarrollo Sostenible - INE",
        "url": "https://www.ine.es/dyngs/ODS/es/index.htm",
        "date": null,
        "last_updated": "2026-05-18"
      },
      {
        "snippet": "",
        "title": "Edición especial",
        "url": "https://unstats.un.org/sdgs/report/2023/The-Sustainable-Development-Goals-Report-2023_Spanish.pdf",
        "date": null,
        "last_updated": "2024-07-14"
      },
      {
        "snippet": "",
        "title": "La Agenda para el Desarrollo Sostenible",
        "url": "https://www.un.org/sustainabledevelopment/es/development-agenda/",
        "date": "2023-09-13",
        "last_updated": "2026-03-17"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

### Content Localization Research

Find examples and references in target languages for localization projects:

```python theme={null}
# Find product reviews in target markets
target_languages = ["ja", "ko", "zh"]  # Asian markets

response = client.search.create(
    query="iPhone 17 Pro Testbericht Fazit",
    max_results=15,
    search_language_filter=target_languages,
    search_recency_filter="month"
)
```

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "75adaf83-38af-4111-b4f7-d6462cdf80f9",
    "results": [
      {
        "snippet": "Bei der Ausstattung muss sich das iPhone 17 Pro keinesfalls hinter den Top-Modellen der Android-Sparte verstecken.\nHier bieten sich ein flottes USB-C-3 zur Datenübertragung sowie ein moderner Funkverkehr über Wi-Fi 7, 5G, Bluetooth 6.0 sowie NFC zum kontaktlosen Bezahlen etwa via Apple Pay an.\nMit dem integrierten Ultrabreitband-Chip lassen sich AirTags oder AirPods wie über ein Radar in der Nähe aufspüren.\nFür Sicherheit sorgt wie gewohnt die Gesichtserkennung mittels Face ID.\nAuf einen Fingerabdrucksensor verzichtet Apple weiterhin.\nEbenfalls gerne gesehen sind die Unfallerkennung sowie der Notruf über Satellit, sollte mal kein Handynetz gegeben sein.\nUm dieses zu erreichen, lässt sich anders als beim iPhone Air auch eine physische Nano-SIM im Gehäuse unterbringen.\nEinzeln oder im Dual-SIM-Betrieb können wir aber auch bis zu zwei eSIM-Verträge registrieren.\nObgleich das rund 204 Gramm schwere Aluminiumgehäuse nicht gerade ein Federgewicht ist, liegt das iPhone 17 Pro sehr gut in der Hand.\nDas ist einerseits seinem vergleichsweise handlichen Format, andererseits aber auch den hochwertig verarbeiteten Materialien zu verdanken.\nDie Kamerainsel mag nun deutlich breiter sein, stört uns im Test aber auch nicht mehr als in den Vorjahren oder bei den Modellen anderer Hersteller.\nDas iPhone 17 Pro ist mit den KI-Funktionen der ' Apple Intelligence ' kompatibel.\nDiese berechnet zwar mehr Aufgaben lokal oder auf privaten Servern als die Konkurrenz um Samsung oder Google, doch die Ergebnisse fallen auch meist ernüchternder aus als im Android-Lager.\nDas gilt speziell für den miserablen Objektradierer bei der Fotobearbeitung.\nWer bislang ohnehin nur iPhones kannte, wird die KI aber auch nicht vermissen.\nImmerhin ist Siri dank der Integration von ChatGPT inzwischen deutlich smarter.",
        "title": "Das beste Pro-Smartphone seit Jahren: Apple iPhone 17 Pro im Test",
        "url": "https://www.chip.de/test/Apple-iPhone-17-Pro-im-Test_186266683.html",
        "date": "2025-09-23",
        "last_updated": "2025-09-23"
      },
      {
        "snippet": "",
        "title": "Das habe ich nicht erwartet: Apple iPhone 17 Pro & Pro Max Review (Deutsch) | SwagTab",
        "url": "https://www.youtube.com/watch?v=XJYJxL4zuiA",
        "date": "2025-09-28",
        "last_updated": "2026-05-06"
      },
      {
        "snippet": "## iPhone 17 Pro im Test: Kurzfazit und Wertung\n**hervorragend ausgestattetes Smartphone mit Top-Kamera und ohne größere Schwächen**.\nDieses Jahr gibt es obendrauf ein grundlegend neues iPhone-Design, das mir persönlich sehr gut gefällt, allerdings durchaus polarisiert.\nZwei der größten Verbesserungen fliegen etwas unter dem Radar: die beeindruckende Akkulaufzeit und das schnellere Aufladen.\nInsgesamt fallen die Neuerungen umfangreicher aus als in den meisten Jahren – ein guter Zeitpunkt für ein Upgrade.\n...\nAuch ohne Test war eigentlich klar: Das iPhone 17 Pro besitzt ein **fantastisches 6,3-Zoll-Display**.\n...\nDie **48-MP-Hauptkamera produziert bei unterschiedlichsten Lichtbedingungen tolle Bilder** mit schönen Farben und vielen Details.\n...\nVon 3582 mAh beim bereits wirklich ausdauernder Vorgänger ist die Akkukapazität auf 3988 mAh gestiegen.\nUnd das macht sich bemerkbar: Im Alltagstest konnte ich für das iPhone 17 Pro eine **exzellente Akkulaufzeit von rund 26,5 Stunden** ermitteln.\n...\nFür eine komplette Aufladung benötigte das iPhone 17 Pro im Test knapp 1 Stunde und 20 Minuten.\n...\n### Preise für das iPhone 17 Pro (UVP)\n- **256 GB:** 1299 Euro\n- **512 GB:** 1549 Euro\n- **1 TB:** 1799 Euro\n...\nDas ab 949 Euro (UVP) erhältliche Standardmodell bietet ein deutlich besseres Preis-Leistungs-Verhältnis.\n...\n- Sehr schnell\n- Sehr gute Akkulaufzeit\n- Schnelleres Aufladen\n- Top-Kamera\n- Top-Display\n- Kratzeranfälig\n- Teuer",
        "title": "iPhone 17 Pro im Langzeit-Test: Drei Monate mit dem Apple ...",
        "url": "https://curved.de/reviews/iphone-17-pro-test-783263",
        "date": "2025-12-24",
        "last_updated": "2026-03-05"
      },
      {
        "snippet": "Das iPhone 17 Pro ist kein kleines Upgrade – Apple spricht vom leistungsstärksten iPhone, das sie je gebaut haben.\nMit größeren Kamerasensoren, mehr Zoom, längerer Akkulaufzeit und einem neuen Design will es im Premium-Segment ganz vorne mitspielen.\n...\nHier ist unser ehrliches Fazit nach einem ausgiebigen Test.\n...\n**Vorteile:**\n+ Kraftvoller A19 Pro Chip mit innovativer Dampfkammer\n+ Erstklassige Kamera mit herausragendem Zoom\n+ Center Stage Frontkamera bietet mehr Flexibilität\n+ Super helles Display\n+ Extrem ausdauernder Akku\n**Nachteile:**\n- Sperriges Kameradesign\n- Kleine Farbauswahl\n- Ladevorgang weiterhin nicht so schnell wie bei der Konkurrenz\n...\nApple verspricht beim iPhone 17 Pro eine **spürbar längere Akkulaufzeit**, was wir in unserem Test auch direkt festgestellt haben.\n...\nUnterm Strich liefert das iPhone 17 Pro in Sachen Akkulaufzeit ein zuverlässiges Gesamtpaket – kein Ausdauer-Wunder, aber deutlich alltagstauglicher als viele Vorgängermodelle.\n...\n## Unser Fazit: starkes Upgrade mit Zukunftssicherheit\nDas iPhone 17 Pro **zeigt in unserem Test viele Stärken**: Das neue Design ist erfrischend anders, der A19 Pro Chip sorgt für spürbar mehr Leistung und die Kamera überzeugt mit flexiblem Tele-Zoom sowie Profi-Videofunktionen.\nAuch die längere Akkulaufzeit und der faire Speicher-Einstieg ab 256 GB sind klare Pluspunkte.\n**Natürlich gibt es auch Kritik:** Das Display ist hell und farbstark, erreicht aber nicht ganz die Klasse mancher Android-Flaggschiffe.\nUnd beim Laden bleibt Apple konservativ – schnell, aber kein Spitzenwert.\nUnterm Strich ist das iPhone 17 Pro ein rundes High-End-Smartphone, das **vor allem für Nutzer mit älteren iPhones ein echtes Upgrade** darstellt.\nWer bereits ein 16 Pro besitzt, bekommt keine Revolution, aber ein spürbar besseres Gesamtpaket – und eines der zukunftssichersten Geräte auf dem Markt.",
        "title": "Das iPhone 17 Pro im Test - Apple - Sparhandy",
        "url": "https://www.sparhandy.de/info/test/iphone-17-pro",
        "date": "2025-06-04",
        "last_updated": "2026-05-23"
      },
      {
        "snippet": "",
        "title": "Lohnt sich das iPhone 17 Pro (Max) immer noch? - Langzeittest nach 4 Monaten Nutzung (Deutsch)",
        "url": "https://www.youtube.com/watch?v=HzEl5acsmoY",
        "date": "2026-01-11",
        "last_updated": "2026-05-02"
      },
      {
        "snippet": "Zunächst fallen die geänderte Bauform mit dem Kamerabuckel und die abgerundeten Kanten auf, die zu einer verbesserten Haptik führen.\nDie Handhabung hat sich im Vergleich zum direkten Vorgänger, dem iPhone 16 Pro, allerdings nicht geändert.\nSo lässt sich das iPhone weiterhin gut mit einer Hand bedienen und über den Kamerataster sind Einstellungen wie Blende, Stile und Belichtungskorrektur möglich.\n...\nDas neue Design schafft Platz für eine aktive Kühlung mit Dampfelement sowie für einen größeren Akku.\nDie Sensoren wurden überarbeitet: Alle drei rückseitigen Kameras verfügen jetzt über 48 Megapixel, einschließlich der Telekamera.\nZiel war eine verbesserte Low-Light-Performance.\nStandardmäßig werden die 48 Megapixel mithilfe von Pixel-Binning auf 12 Megapixel reduziert.\nUnterstützt werden die Kameras dabei von der Photonic Engine, die für die Bildverarbeitung verantwortlich ist.\n...\nDie drei sogenannten Fusion-Kameras bestehen aus einer Hauptkamera mit 1,78/24 mm, einem Ultraweitwinkel mit 2,2/13 mm sowie einem neuen Tele mit 2,8/100 mm.\nHaupt- und Telekamera sind zusätzlich mit einer optischen Bildstabilisierung per Sensorverschiebung ausgestattet.\nDank dieser Kombination decken die Kameras kleinbildäqivalente Brennweiten von 13 mm (0,5x), 24 mm (1x), 28 mm (1,2x), 35 mm (1,5x), 48 mm (2x), 100 mm (4x) und 200 mm (8x) sowie Makro-Aufnahmen ab.\n...\nIn den Einstellungen wird dies entsprechend angezeigt.\nApropos Einstellungen: Hier lässt sich das Dateiformat von HEIF auf JPEG umstellen und Raw aktivieren.\nDadurch kann man in der Kamera-App später direkt zwischen zwei Dateiformaten sowie zwischen 24 und 48 Megapixeln wechseln.\nAber auch die Frontkamera wurde überarbeitet: Sie bietet nun 18 Megapixel auf einem quadratischen Sensor und sorgt damit für gleichbleibende Qualität im Hoch- und Querformat.\n...\nDie Kameras des neuen iPhone 17 Pro liefern die erwartete Steigerung der Bildqualität.\nIn der Mehrzahl der Aufnahmen stimmt die Belichtung sehr gut, ebenso die lebhaften, aber nicht übersättigten Farben.\nAuch der Weißabgleich ist überzeugend.\nDas zeigt sich besonders bei Porträtaufnahmen: Hauttöne wirken natürlich, und die Hintergrundtrennung gelingt selbst bei feinen Haarstrukturen präzise.\nHaare und Fell werden detailreich wiedergegeben und wirken nur bei niedriger Auflösung leicht überschärft.\nEin zentrales Kriterium ist das Rauschverhalten, das deutlich verbessert wurde.\nIn den Schattenbereichen sind jetzt mehr Details sichtbar.\n...\nAuch das Ultraweitwinkel wurde verbessert: Es zeigt nun weniger Verzeichnungen und mehr Details bis zum Rand – besonders sichtbar bei Landschafts- und Gruppenaufnahmen.\n...\nDie Pro-iPhones gehören zu den beliebtesten Videokameras – auch, weil sie ProRes im Log-Format aufzeichnen können, auf Wunsch sogar direkt auf externe Laufwerke.\n...\n## Fazit: iPhone 17 Pro – Evolution statt Revolution\nEs sind nicht die großen Sprünge, die Apple Jahr für Jahr mit einer neuen iPhone-Generation vollzieht.\nAuch das iPhone 17 Pro ist ist „nur“ wieder ein Stück besser geworden.\nAm deutlichsten merkt man dies beim Teleobjektiv, das nun eine wesentlich höhere Auflösung liefert und damit nicht mehr gegenüber den beiden anderen Kameras abfällt.\nVerbesserungen zeigen sich auch bei Porträtaufnahmen und beim Einsatz der Blendensteuerung für kreative Fotos.\nDie Bokeh-Übergänge sind so harmonisch, dass sie Aufnahmen einer Kompaktkamera mit größerem Sensor sehr nahekommen.\nAuch das HDR wirkt jetzt deutlich natürlicher.\nSelbst die HEIF-Bilder sind schon sehr überzeugend, doch das Umschalten in den Pro-Modus mit Raw-Format holt das Maximum aus dem iPhone heraus.\nDamit verringert sich der Qualitätsabstand zu einer Kompaktkamera spürbar.\nDas iPhone 17 Pro schließt somit zu den starken Mitbewerbern aus dem Android-Lager auf und gehört erneut zu den Smartphones mit den besten Kamerasystemen.\nSeine großen Pluspunkte bleiben die enge Software-Integration und das professionelle Zubehör.",
        "title": "iPhone 17 Pro im Test – was Fotografen begeistert - fotoMAGAZIN",
        "url": "https://www.fotomagazin.de/smartphone/iphone-17-pro-im-test-gute-wahl-zum-fotografieren/",
        "date": "2025-12-02",
        "last_updated": "2026-05-19"
      },
      {
        "snippet": "",
        "title": "Apple iPhone 17 Pro im Test - Smartzone",
        "url": "https://www.smartzone.de/apple-iphone-17-pro-im-test/",
        "date": "2025-10-19",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "### Testfazit\nApples iPhone 17 hinterlässt im Test einen starken Eindruck.\nEs hat ein schönes 6,3 Zoll großes OLED-Display mit geschmeidiger Bildwiederholrate und Always-on-Funktion.\nInhalte machen nicht zuletzt dank satter Farben und hoher Schärfe eine gute Figur.\nAuch die Akkulaufzeit des iPhone 17 ist klasse: Mit eingeschaltetem Display hält es in unserem Akkutest über 19 Stunden durch.\nNach 30 Minuten am Stecker lässt es sich schon fast wieder für 13 Stunden verwenden.\nDer A19-Prozessor sorgt nicht nur für eine hohe Energieeffizienz, sondern auch für eine flotte Performance, selbst bei anspruchsvollen Apps.\nDie Dual-Kamera liefert sowohl bei Tageslicht als auch in schwach beleuchteten Umgebungen sehr schöne Fotos und Videos mit vielen Details und realitätsnahen Farben.\nEin Telezoom bleibt dem Standard-iPhone aber weiterhin verwehrt.\nWi-Fi 7, 5G-Mobilfunk, NFC und Dual-eSIM-Funktionalität sind mit dabei.\nDas iPhone 17 unterstützt die „Apple Intelligence“-KI, die zwar durch mehr Privatsphäre, jedoch nicht qualitativ gegenüber Google und Co. punkten kann.\nFace ID, der frei belegbare Actionbutton, die Kamerasteuerung und die Dynamic Island bleiben Teil der iPhone-DNA.\nEbenso wie ein recht hoher Preis.\n...\n### Testfazit\nMit dem iPhone 17 Pro liefert Apple ein fast kompromisslos starkes High-End-Smartphone, das vor allem durch seine enorme Ausdauer überzeugt.\nIn unserem Test erreichte es eine beeindruckende Dauerlaufzeit von über 21 Stunden – so kommen wir problemlos durch einen ganzen Tag.\nBereits 30 Minuten am Kabel reichen für über 13 Stunden Nutzung.\nEiner der Hauptgründe dürfte Apples-Prozessor A19 Pro sein.\nEr arbeitet effizient und bietet jederzeit Leistung auf höchstem Niveau – ohne dabei das Gehäuse bedeutend zu erhitzen.\nDie Triple-Kamera mit drei 48-Megapixel-Sensoren liefert großartige Fotos.\nSie sind gestochen scharf, farbkräftig und kontrastreich.\nEin achtfacher optischer Zoom und 4K-Videos mit 120 Bildern pro Sekunde runden das System ab, während die neue Selfie-Kamera unter anderem mit flexibler Formatwahl und verbesserter Stabilisierung punktet.\nDas 6,3 Zoll große OLED-Display begeistert mit hoher Helligkeit, satten Farben und weicher Bildwiederholrate von 120 Hertz, könnte aber etwas stärker entspiegelt sein.\n...\nDie lokalen KI-Funktionen von Apple bieten mehr Datenschutz, hinken bei der Qualität und Kompetenz jedoch noch hinterher.",
        "title": "iPhone 17 oder iPhone 17 Pro? Für wen sich das Upgrade wirklich ...",
        "url": "https://www.chip.de/test-kaufberatung/iphone-vergleich/iphone-17-oder-iphone-17-pro-fuer-wen-sich-das-upgrade-wirklich-lohnt_fab1a16a-cf5d-4b1d-a167-90a31be5f7aa.html",
        "date": "2026-01-20",
        "last_updated": "2026-05-24"
      },
      {
        "snippet": "Das iPhone 17 Pro präsentiert sich, auch ohne echte Innovationssprünge, als konsequente Weiterentwicklung seines Vorgängers.\nApple hat viele Details verbessert: das neue OLED-Display ist heller und farbtreuer, der Akku größer und ausdauernder, und der A19-Pro-Chip sorgt zusammen mit 12 GB RAM für eine herausragende Systemleistung.\nAuch bei der Kamera gibt es Fortschritte, insbesondere beim Teleobjektiv und bei der Frontkamera, die nun vielseitiger und technisch ausgereifter ist.\nIn der Praxis überzeugt das Smartphone mit starker Performance und einer der besten Akkulaufzeiten seiner Klasse.\n...\nTrotzdem bleibt ein zwiespältiger Eindruck: Der Wechsel von Titan zu Aluminium wirkt wie ein Rückschritt, zumal die Oberfläche laut Nutzerberichten anfälliger für Kratzer ist.\nDie Fotoqualität liegt zwar auf Spitzenniveau, doch der Ultraweitwinkel bleibt schwach und bei schlechtem Licht stößt der Zoom-Sensor an seine Grenzen.\nAuch das Display, so brillant es ist, nutzt weiterhin PWM mit niedriger Frequenz, was empfindliche Nutzer stören kann.\nDazu kommen kleine, aber ärgerliche Einschränkungen: kein High-Res-Audio über Bluetooth, kein Auracast, und einige neue iOS-26-Funktionen sind in der EU noch immer gesperrt.\n### Pro\n+ hohe Performance\n+ gutes Kamera-Setup\n+ sehr gute Akkulaufzeiten\n+ USB 3.2, UWB und Wi-Fi 7\n…\nDas Design wurde beim iPhone 17 Pro sichtbar überarbeitet, der Akku wächst deutlich und es gibt ein neues Zoom-Objektiv sowie eine neue Frontkamera.\nAuch die Ladegeschwindigkeiten ziehen an, das Display leuchtet heller und selbstverständlich hat auch das SoC ein Upgrade erhalten.\n...\nWenn auch diese bei vollflächiger Weißdarstellung unverändert bleibt, klettert sie bei einer verkleinerten Weißfläche auf bis zu 3.044 cd/m² (APL18) und bei der HDR-Wiedergabe sind es 2.997 cd/m².",
        "title": "Test Apple iPhone 17 Pro – Schneller, länger, weiter. Reicht das?",
        "url": "https://www.notebookcheck.com/Test-Apple-iPhone-17-Pro-Schneller-laenger-weiter-Reicht-das.1139984.0.html",
        "date": "2025-10-17",
        "last_updated": "2026-05-23"
      },
      {
        "snippet": "Apple traut sich was.\nAusgerechnet für die umsatzstarken Modelle der Pro-Reihe bietet das Unternehmen die bisher beliebteste Farbe nicht mehr an: Schwarz.\nStattdessen gibt es die Topmodelle jetzt in einem knalligen Orange.\nDer Umstieg auf Aluminium macht es möglich, mit neuen Farben zu spielen.\n...\nEine Neuerung, die alle Modelle betrifft: Sie haben dieselbe 48-Megapixel-Weitwinkelkamera im Rücken.\nAllerdings ist sie beim iPhone Air die einzige Kamera, beim iPhone 17 wird sie von einer Ultraweitwinkelkamera mit ebenfalls 48 Megapixeln begleitet.\nDie beiden Pro-Modelle haben zusätzlich eine Telekamera, auch mit 48 Megapixeln.\n...\nDass die Telekamera beim iPhone 17 Pro und Pro Max dennoch spürbar bessere Aufnahmen macht als die der Vorgänger, liegt daran, dass ihr Fotosensor 56 Prozent größer ist.\nDas erhöht unter anderem die Lichtempfindlichkeit, sorgt vor allem aber für ein natürliches Bokeh, so nennt man den Effekt, wenn Vorder- oder Hintergrund des Motivs unscharf erscheinen.\n...\nEine weitere Neuerung, die alle Modelle betrifft und schon daher viel mehr Menschen berühren wird, ist die neue Selfiekamera.\nSie hat einen Fotosensor mit 24 Megapixeln, der insofern besonders ist, als er quadratisch statt rechteckig ist.\nApple nutzt das ungewohnte Format für eine Funktion, die bisher niemand vermisst hat, von der man sich nach ein paar Tagen aber fragt, warum es sie erst jetzt gibt: Center Stage.\n...\nNur wer solche Funktionen benötigt, hat einen Grund, die neue maximale Speicherausstattung von zwei Terabyte (TB) zu wählen.\n...\nDie für das iPhone 17 wichtigste Neuerung: Erstmals hat auch das Einstiegsmodell einen sogenannten ProMotion-Bildschirm, der seine Bildwiederholrate dynamisch zwischen 1 und 120 Bildern pro Sekunde variieren kann.\n...\n### Fazit\nSelten hat Apple seine iPhones derart stark überarbeitet wie in diesem Jahr.\nStatt einfach Pro- und Nicht-Pro-Modelle mit unterschiedlichen Chips und Bildschirmen anzubieten, hat der Konzern jetzt vier ausgesprochen unterschiedliche iPhone-Varianten im Angebot, die sehr unterschiedliche Stärken und Schwächen haben.\nMit dem iPhone 17 räumt das Unternehmen endlich die beiden großen Makel bisheriger Basismodelle aus dem Weg, bestückt es mit genug Speicher und einem schnellen Bildschirm.\nVollkommen irre: Verglichen mit einem gleich ausgestatteten Google Pixel 10 kostet es 150 Euro weniger.\nDie iPhones 17 Pro und Pro Max hingegen sind mit Preisen ab 1299 Euro alles andere als günstig.\nDafür bieten sie mehr als genug Leistung und sehr gute Kameras, bei denen insbesondere die neue Telekamera glänzt.\nDas neue Design, größere Batterien und die verbesserte Kühlung machen sie stressresistent und ermöglichen stattliche Laufzeiten.\nIm Test musste das Pro Max nur jeden zweiten Tag aufgeladen werden, aber verlässliche Aussagen dazu lassen sich erst nach längeren Tests als dieser knappen Woche machen.\n...\nDas iPhone Air wiederum ist der Anfang einer neuen Ära für Apple.\n...\nDank seines A19 Pro liefert es Leistung satt, aber nicht Ausdauer ohne Ende.\nWer den Look wichtiger findet als mehrere Kameras und lange Laufzeiten, kann sich damit einen Ausblick in die Zukunft sichern, zu Preisen ab 1199 Euro.",
        "title": "Apples Generation 17 im Test: Das können die neuen iPhones",
        "url": "https://www.spiegel.de/netzwelt/gadgets/iphone-air-iphone-17-iphone-17-pro-und-pro-max-im-test-das-koennen-die-neuen-geraete-a-25db6c44-7701-4567-af6a-61e24737e4fc",
        "date": "2025-09-17",
        "last_updated": "2026-05-26"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

### Academic Research Across Languages

Access scholarly content in different languages:

```python theme={null}
# Search for research papers in multiple languages
response = client.search.create(
    query="Algorithmes d'informatique quantique",
    max_results=20,
    search_language_filter=["en", "de", "fr", "ru"],
    search_domain_filter=["arxiv.org", "nature.com", "science.org"]
)
```

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "d98fe101-dee7-4aac-a502-c0b0d5c1b03b",
    "results": [
      {
        "snippet": "",
        "title": "Algorithme quantique — Wikipédia",
        "url": "https://fr.wikipedia.org/wiki/Algorithme_quantique",
        "date": "2025-10-25",
        "last_updated": "2026-04-27"
      },
      {
        "snippet": "La logique quantique permet en principe de réaliser certains calculs de façon plus rapide \nque ne le font les ordinateurs classiques.\nNous en donnons ici trois exemples, correspondant \nà la résolution de problèmes posés sous forme logique simple.\nDe façon générale, on classe les problèmes de calcul en distinguant ceux qui sont\n...\nLa logique quantique, exploitant les superpositions de qubits et leur intrication permet de \ntransformer certains problèmes classiquement difficiles en problèmes quantiquement\nfaciles.\nL’algorithme de Shor décrit par exemple un procédé de factorisation demandant \nun temps croissant de façon polynomiale avec le nombre de bits du nombre à factoriser.\nNous n’aborderons pas dans cette introduction la description de cet algorithme, mais nous \n...\nNous allons montrer que le passage du calcul classique au calcul quantique transforme \ncertains oracles classiques difficiles en oracles quantiques faciles.\nDans d’ autres cas, le \nproblème quantique reste  difficile, mais moins que le problème classique (croissance toujours\nexponentielle du nombre d ’opérations, mais avec un exposant plus petit que classiquement ).\n...\nL ’Algorithme quantique de Deutsch-Josza\nf(x) constante ou \nbalancée ?\nH1.H2….Hn\n| {0} >A\n| 0>B\nN\nH\nLe registre d’entrée A (n qubits) est préparé (par application de la transformation de\nHadamard H sur chaque qubit) dans la superposition symétrique des 2 n états | x > possibles.\nLe registre de sortie B (1 qubit) est inversé par N, puis préparé par H dans (1/21/2) [| 0 > −| 1 >]\n>]\n>]\n>] .\n(1/2n/2) Σx |            x >\n(1/21/2) [| 0 > −| 1 >]\n>]\n...\n>]\n...\nOn applique à nouveau H à tous les qubits.\n...\nsi f(x ) est constante, un état orthogonal si f(x) est balancée →au moins un des qubits\ndoit alors être 1.\nOn le vérifie en mesurant les qubits finals de A.\nLa réponse nécessite au plus 3n+2 opérations à un qubit (2n + 1 opérations H,  une \nopération de bascule (N) et au plus mesure de n qubits (on peut arrêter dès qu’on\n…\n...\nL’ avantage de l’ algorithme quantique n’existe que si on cherche une réponse \ncertaine.\nSi on s’ autorise une probabilité finie ε        d’ erreur, aussi petite soit-elle,\n...\nCeci diminue considérablement l ’intérêt de l ’algorithme \nquantique puisqu’ il faut être sûr de pouvoir l ’effectuer sans aucune décohérence\npour qu ’il soit avantageux par rapport à la version classique.\nAlgorithme de recherche quantique (Grover)\nf (x) = δ (x-x0)\nx0?\n...\nx0?\n...\ndans [ 0, 1] est réalisée par un oracle agissant sur la superposition symétrique des N = 2 n\nqubits de A et sur le qubit B préparé par les opérations N et H dans l ’état (1/21/2) [| 0 > −| 1 >]\n...\nFinalement, l ’algorithme de recherche de Grover \ndemande donc un nombre d ’opérations en √N log2 N , \ninférieur à celui exigé classiquement (en N).\n...\nLes algorithmes de Deutsch et de Grover peuvent se décrire comme des processus\nd’ interférence quantique à 2 n chemins : Les H1.H2….Hn jouent le rôle de « lames \nséparatrices » qui décomposent et recombinent les états du registre  A.\nL ’oracle O est \nl ’analogue d ’une lame déphasante qui modifie les phases relatives des états.\nDans Grover,\nchaque symétrie Us combine «en sandwich» deux lames séparatrices avec une lame \ndéphasante.\nDans les deux «interféromètres», l’effet recherché est de favoriser dans l’état final \nun état ( analogue d’ une «frange brillante» ) dont la mesure finale fournit la réponse voulue.\n...\nUne mesure répétée ~ n fois de A va alors nous permettre de déterminer s\n…\n...\nUne mesure des qubits individuels donne une suite  y1a , y2a , y3a ,…..yna de valeurs 0 et 1\nqui satisfait la condition: \nΣ i si yia = 0 (modulo 2).\nOn recommence n fois l ’opération et on obtient ainsi, en général, n relations \nindépendantes  (si par hasard deux mesures donnent le même vecteur, on recommence \nune fois de plus):\nΣ i si yia = 0\nΣ i si yib = 0\n. . . . . . . . \nΣ i si yin = 0\nLa résolution de ce système d ’équations donne s.\nLe processus requiert  ≅4n2 opérations.\nLe problème est donc quantiquement facile.\nDe plus, il tolère des erreurs puisqu ’on peut \ntoujours vérifier le résultat en comparant f ( x ) et f (x ⊕s) une fois s obtenu.",
        "title": "Les algorithmes quantiques",
        "url": "https://www.college-de-france.fr/media/serge-haroche/UPL55031_SHaroche_260202.pdf",
        "date": null,
        "last_updated": "2025-12-13"
      },
      {
        "snippet": "",
        "title": "Comprendre l'informatique quantique – algorithmes et ...",
        "url": "https://www.oezratty.net/wordpress/2018/comprendre-informatique-quantique-algorithmes-et-applications/",
        "date": "2018-07-20",
        "last_updated": "2025-12-25"
      },
      {
        "snippet": "",
        "title": "Comprendre l'informatique quantique – algorithmes et ...",
        "url": "https://www.frenchweb.fr/comprendre-linformatique-quantique-algorithmes-et-applications/332659",
        "date": "2019-07-05",
        "last_updated": "2025-09-07"
      },
      {
        "snippet": "",
        "title": "Zoo des Algorithmes Quantiques",
        "url": "https://quantumalgorithmzoo.org/FrenchV1_8.html",
        "date": "2024-01-13",
        "last_updated": "2025-08-29"
      },
      {
        "snippet": "Essentiels en informatique, on les retrouve notamment en Data Science et dans le Machine Learning.Un algorithme est en fait une procédure par étapes.\nC’est **un ensemble de règles** à suivre pour accomplir une tâche ou résoudre un problème.\n...\nDans le domaine de la programmation informatique, les algorithmes sont des ensembles de règles qui\n**indiquent à l’ordinateur comment effectuer une tâche**.\nEn réalité, un programme informatique est un algorithme indiquant à l’ordinateur quelles étapes exécuter et dans quel ordre pour accomplir une tâche spécifique.\nIls sont **écrits à l’aide d’un langage de programmation**.\n...\nEn mécanique quantique, la manière de faire change profondément.\nTrois aspects de la mécanique quantique offrent la possibilité de faire de l’informatique quantique :\n**la dualité onde-corpuscule**, ** la superposition d’états **et ** l’intrication**.\nDe par leur nature onde-corpuscule, les particules quantiques sont décrites par des probabilités qui évoluent dans le temps et dans l’espace.\nElles ont aussi la capacité de se trouver dans un état qu’on appelle\n**« superposé » : un peu 0 et un peu 1**.\nAinsi, un qubit, la version quantique du bit traditionnel, possède deux états « d’existence », nommés **|0>** et **|1>**, prononcés : **ket 0** et **ket 1**.\nAlors qu’un bit classique est numérique et a toujours pour valeur soit 0 soit 1, l’état d’un qubit est une superposition quantique linéaire de ses deux états de base, il vaut en même temps |0> et |1>.\nNéanmoins, si on cherche à l’observer, on va alors trouver soit un 0 ou un 1 : **l’observation aura changé l’état de la particule** en choisissant entre les deux.\n...\nAvec un registre de n qubits, on a donc en même temps 2n valeurs, qui peuvent toutes être stockées simultanément (là où l’informatique classique ne peut stocker qu’une valeur à la fois).\nSi on arrive à faire des calculs avec de tels supports, on arrive en quelque sorte à\n**faire tous les calculs en même temps**, comme si on réalisait 2n calculs « en parallèle ».\nPar exemple, si n=3, un ordinateur quantique aura la possibilité de traiter 8 états quantiques différents, et donc 8 calculs en même temps.\nSi chaque calcul durait une seconde, un ordinateur quantique n’aurait donc besoin que de **1 seconde pour les réaliser**, là où un ordinateur classique aurait eu besoin de 8 secondes, puisqu’il aurait dû traiter chaque calcul l’un après l’autre.\nÀ la fin, il se peut qu’il n’y ait qu’un seul de ces calculs qui ait réussi, et c’est son résultat qui nous intéresse.\n**La difficulté, c’est de l’isoler**.\nC’est précisément le rôle des algorithmes quantiques : effacer de façon judicieuse tous les calculs qui n’ont pas abouti.\n...\nComme nous l’avons vu en informatique classique, un algorithme est un programme qui suit une suite logique d’instructions.\nEn informatique quantique,\n**la nature du traitement des instructions est changée**, elle devient aussi quantique.\nComme la lecture du registre ne fournit qu’une valeur 0 ou 1 pour chaque bit (pour rappel, un qubit observé se fige dans un état donné et se comporte comme un bit classique), soit un des états de base du registre, tout l’art de l’algorithmique quantique consiste à concentrer\n**l’évolution vers les états qui donnent la solution au problème étudié**.\nUn ordinateur quantique n’est donc pas une machine qui résoudrait tous les problèmes plus rapidement qu’un ordinateur conventionnel.\nIl s’agit plutôt d’une machine capable de résoudre efficacement certains problèmes hors de portée des machines conventionnelles.\nL’exercice consiste donc à comparer la complexité d’un problème d’un point de vue classique et d’un point de vue quantique.\nSi un algorithme peut être résolu de manière classique avec une complexité bien définie, il peut aussi l’être dans le modèle quantique avec\n**une complexité équivalente ou moindre**.\nLes capacités de l’algorithmique quantique sont reliées au nombre de qubits, mais augmenter leur nombre ne sert que si « l’environnement » quantique est maintenu malgré les inévitables processus de décohérence.\nUne autre particularité du qubit par rapport à un bit classique est qu’\n**il ne peut pas être dupliqué** en raison des lois de la physique quantique.\n...\nLes algorithmes quantiques ont le potentiel de\n**révolutionner de nombreux domaines**, dont la cryptographie, la chimie computationnelle, la recherche opérationnelle et même l’intelligence artificielle.\nL’un des exemples les plus marquants est **l’algorithme de factorisation de Shor**, qui menace les systèmes de cryptographie à base de factorisation et met en lumière la nécessité de développer des méthodes de chiffrement quantique plus robustes.\nEn ce qui concerne la Data Science, les algorithmes quantiques représentent\n**un grand potentiel **dans ce domaine.\nIls pourraient accélérer des tâches complexes telles que l’optimisation, l’apprentissage automatique et la simulation moléculaire.\nDe plus, ils pourraient améliorer la sécurité des données grâce à la cryptographie quantique.\nCependant, leur utilisation en data science est encore en développement en raison des défis technologiques actuels.\nMalgré cela, leur capacité à résoudre des problèmes difficiles rapidement offre des opportunités prometteuses pour l’avenir de l’analyse de données.\n**l’intérêt d’un algorithme quantique**dans notre société et dans le domaine de la data science.\nLes algorithmes quantiques ouvrent la voie à une nouvelle ère de calcul puissant et d’applications révolutionnaires.",
        "title": "Algorithme quantique : qu'est-ce que c'est ? Comment s'en ...",
        "url": "https://datascientest.com/algorithme-quantique-tout-savoir",
        "date": "2023-11-09",
        "last_updated": "2025-10-09"
      },
      {
        "snippet": "Algorithmes simples\n1\nCalcul de fonctions\n`A chaque fonction f : X →Y on peut associer une op´eration unitaire\nF |x⟩|y⟩:= |x⟩|y ⊕f(x)⟩\nclairement F = F †, FF = I et\nF |x⟩|0⟩:= |x⟩|f(x)⟩\nSi f est une fonction binaire, on peut aussi d´efinir\nF ′ |x⟩:= (−1)f(x) |x⟩\nencore une fois F ′ = F ′† et F ′F ′ = I.\n2\nCalcul de fonctions\n`A partir de F, on peut construire F ′ en utilisant un qubit\nsuppl´ementaire dans l’´etat\n1\n√\n2(|0⟩−|1⟩)\nF |x⟩1\n√\n2(|0⟩−|1⟩)\n=\n|x⟩1\n√\n2(|f(x)⟩−\n���f(x)\n�\n)\n=\n|x⟩(−1)f(x) 1\n√\n2(|0⟩−|1⟩)\n=\n(−1)f(x) |x⟩1\n√\n2(|0⟩−|1⟩)\n=\nF ′ |x⟩1\n√\n2(|0⟩−|1⟩)\n3\nAlgorithme de Grover\nSoit f : {0, 1}2 →{0, 1} avec la promesse qu’il existe x0 tel que\nf(x0) = 1 et si x ̸= x0 alors f(x) = 0.\nSoit l’op´eration unitaire U d´efinie par:\nU |00⟩\n=\n1\n2(−|00⟩+ |01⟩+ |10⟩+ |11⟩)\nU |01⟩\n=\n1\n2(+ |00⟩−|01⟩+ |10⟩+ |11⟩)\nU |10⟩\n=\n1\n2(+ |00⟩+ |01⟩−|10⟩+ |11⟩)\nU |11⟩\n=\n1\n2(+ |00⟩+ |01⟩+ |10⟩−|11⟩)\n4\nAlgorithme de Grover\nAlgorithme de Grover(f)\n• |ψ⟩= U†F ′H⊗2 |00⟩\n• m = Mesure(|ψ⟩)\n• retourne m\nClassique: 3 requˆetes `a f.\nQuantique: 1 requˆete `a f.\n5\n...\nAlgorithme de Deutsch\nProbl`eme de Deutsch (version de R.\nCleve et A.\nTapp): ´Etant donn´e\nf : {0, 1} →{0, 1}, d´ecider si f(0) = f(1).\nAlgorithme Deutsch(f)\n• |ψ⟩= HF ′H |0⟩\n• m = Mesure(|ψ⟩)\n• si m = 0 r´epond CONSTANTE sinon ´EQUILIBR´EE\nClassique: deux requˆetes `a f.\nQuantique: une requˆete `a f.\n7\n...\nOn obtient donc f(0) ⊕f(1) avec certitude.\nSi f(0) ⊕f(1) = 0 alors la\nfonction est constante, (f(0) = f(1)) sinon la fonction est ´equilibr´ee\n(f(0) ̸= f(1)).\n...\nAlgorithme de Deutsch-Josza\nProbl`eme de Deutsch-Josza: ´Etant donn´e f : {0, 1}n →{0, 1} d´ecider si\nf est constante (∀x, y, f(x) = f(y)) ou ´equilibr´ee (|f−1(0)| = |f−1(1)|).\nAlgorithme Deutsch-Josza(f)\n• |ψ⟩= H⊗nF ′H⊗n |0⟩\n• m = Mesure(|ψ⟩)\n• si m = 0 r´epond CONSTANTE sinon ´EQUILIBR´EE\nClassique: 2n−1 + 1 requˆetes `a f.\nQuantique: une requˆete `a f.\n10\n...\nAlgorithme de Simon\n´Etant donn´e f : {0, 1}n →{0, 1}n−1 telle qu’il existe s non nul avec la\npropri´et´e que ∀x ̸= y : f(x) = f(y) ⇔x = y ⊕s, trouver s.\nAlgorithme Simon(f)\n• S = {}\n• tant que |S| < n −1\n•\n|ψ⟩= (H⊗n ⊗I2n−1)F(H⊗n ⊗I2n−1) |0⟩|0⟩\n•\n(m, y) = Mesure(|ψ⟩)\n•\nsi m est ind´ependant de S alors S ←S ∪{m}\n• fin du tant que\n• d´eduire s de S.\nClassique: Ω(2(1/2−ϵ)n) requˆetes `a f mˆeme avec probabilit´e de succ`es\nconstante.\nQuantique: Esp´erance de O(n) requˆetes `a f.\n14\n...\n`A chaque it´eration, la probabilit´e de succ`es est donc au moins 1/2, ce\nqui nous donne un nombre d’it´erations esp´er´e dans O(n).\n...\nPour tout ´etat |ψ⟩∈HABC on peut mesurer le sous-espace B.\nPour un sous-espace B de dimension d et un ´etat\n|ψ⟩= �d−1\ni=0 αi |ai⟩|i⟩|ci⟩on obtient le r´esultat classique i avec\nprobabilit´e |αi|2 et l’´etat devient |ai⟩|i⟩|ci⟩.",
        "title": "[PDF] Informatique quantique IFT6155 Algorithmes simples",
        "url": "https://www.iro.umontreal.ca/~tappa/pages/cours/IFT6155/algorithmes1.pdf",
        "date": null,
        "last_updated": "2025-11-28"
      },
      {
        "snippet": "",
        "title": "[PDF] À la découverte des algorithmes quantiques - Ion Nechita",
        "url": "https://ion.nechita.net/wp-content/uploads/2019/06/Projet-S2-Fresse-Colson-Da-Rocha-Balauze.pdf",
        "date": null,
        "last_updated": "2026-02-26"
      },
      {
        "snippet": "",
        "title": "Informatique quantique — Wikipédia",
        "url": "https://fr.wikipedia.org/wiki/Informatique_quantique",
        "date": "2005-09-30",
        "last_updated": "2026-05-22"
      },
      {
        "snippet": "",
        "title": "Informatique quantique : Algorithmes, modèles, défis et applications",
        "url": "https://geekflare.com/fr/ai/guide/quantum-computing/",
        "date": "2024-05-14",
        "last_updated": "2024-10-29"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

### News Monitoring by Language

Track news stories across different language regions:

```python theme={null}
# Monitor breaking news in different languages
news_queries = {
    "English": ["en"],
    "Chinese": ["zh"],
    "Spanish": ["es"],
    "Arabic": ["ar"]
}

for region, langs in news_queries.items():
    response = client.search.create(
        query="Misión y descubrimientos de la sonda Voyager 1",
        max_results=5,
        search_language_filter=langs,
        search_recency_filter="day"
    )
    print(f"{region} News: {len(response.results)} articles")
```

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "6ff356eb-a05a-4d1f-be99-f23b5951266f",
    "results": [
      {
        "snippet": "",
        "title": "Voyager 1 - Wikipedia, la enciclopedia libre",
        "url": "https://es.wikipedia.org/wiki/Voyager_1",
        "date": "2003-09-05",
        "last_updated": "2026-03-21"
      },
      {
        "snippet": "Lanzadas en 1977, las sondas gemelas Voyager son la misión de operación más larga de la NASA y las únicas naves espaciales que ha explorado el espacio interestelar.\n...\nSin embargo, las Voyagers se mantienen a la vanguardia de la exploración espacial.\nAdministradas y operadas por el Laboratorio de Propulsión a Chorro (JPL, por sus siglas en inglés) de la NASA, en el sur de California, son las únicas sondas que han explorado el espacio interestelar, el océano galáctico por el que viajan nuestro Sol y sus planetas.\nEl Sol y los planetas residen en la heliosfera, una burbuja protectora creada por el campo magnético del Sol y el flujo hacia afuera del viento solar (partículas cargadas del Sol).\nLos investigadores, algunos de ellos más jóvenes que las dos naves espaciales distantes, están combinando las observaciones de las Voyagers con datos de misiones más nuevas para obtener una imagen más completa de nuestro Sol y cómo la heliosfera interactúa con el espacio interestelar.\n...\n“Durante los últimos 45 años, las misiones Voyager han sido integrales para proporcionar este conocimiento y han ayudado a cambiar nuestra comprensión del Sol y su influencia de una manera que ninguna otra nave espacial puede”.\n...\nVoyager 2 se lanzó el 20 de agosto de 1977, seguida rápidamente por Voyager 1 el 5 de septiembre.\nAmbas sondas viajaron a Júpiter y Saturno, con Voyager 1 moviéndose más rápido y alcanzándolos primero.\nJuntas, las sondas revelaron mucho sobre los dos planetas más grandes del sistema solar y sus lunas.\nVoyager 2 también se convirtió en la primera y única nave espacial en volar cerca de Urano (en 1986) y Neptuno (en 1989), ofreciendo a la humanidad vistas extraordinarias e información sobre estos mundos distantes.\nMientras Voyager 2 realizaba estos sobrevuelos, Voyager 1 se dirigía hacia el límite de la heliosfera.\nAl salir de ella en 2012, Voyager 1 descubrió que la heliosfera bloquea el 70% de los rayos cósmicos o partículas energéticas creadas por estrellas en explosión.\nVoyager 2, después de completar sus exploraciones planetarias, continuó hasta el límite de la heliosfera y salió en 2018.\nLos datos combinados de las naves espaciales gemelas de esta región han desafiado las teorías anteriores sobre la forma exacta de la heliosfera.\n“Hoy, mientras ambas Voyager exploran el espacio interestelar, están brindando a la humanidad observaciones de un territorio desconocido”, dijo Linda Spilker, científica adjunta del proyecto Voyager en JPL.\n“Esta es la primera vez que hemos podido estudiar directamente cómo una estrella, nuestro Sol, interactúa con las partículas y los campos magnéticos fuera de nuestra heliosfera, ayudando a los científicos a comprender el vecindario local entre las estrellas, cambiando algunas de las teorías sobre esta región y proporcionando información clave para futuras misiones”.\n...\n“Las Voyagers han continuado haciendo descubrimientos sorprendentes, inspirando a una nueva generación de científicos e ingenieros”, dijo Suzanne Dodd, gerente de proyectos de Voyager en JPL.",
        "title": "Voyager, la misión más longeva de la NASA, cumple 45 años en el ...",
        "url": "https://ciencia.nasa.gov/sistema-solar/voyager-cumple-45-en-el-espacio/",
        "date": "2022-08-19",
        "last_updated": "2026-05-23"
      },
      {
        "snippet": "",
        "title": "Lo que descubrió la Voyager 1 en el borde del sistema solar",
        "url": "https://www.youtube.com/watch?v=LQ8SYzg1Rgc",
        "date": "2026-02-07",
        "last_updated": "2026-05-20"
      },
      {
        "snippet": "La **Voyager 1** ye una sonda espacial robótica de 722 kilogramos, llanzada'l 5 de setiembre de 1977, dende Cabu Cañaveral, Florida.\nSigue operativa na actualidá, prosiguiendo la so misión estendida que ye alcontrar y estudiar les llendes del sistema solar, incluyendo'l petrina de Kuiper y más allá, según esplorar l'espaciu interestelar inmediatu, hasta fin de misión.\nEl 25 d'agostu de 2012, a pocu más de 19 000 millones de quilómetros del Sol o 122 UA, la sonda dexó tras la heliopausa, siendo la primera n'algamar l'espaciu interestelar.\nLa so misión orixinal yera visitar Xúpiter y Saturnu.\nFoi la primer sonda n'apurrir imáxenes detallaes de los satélites d'esos planetes.\nA una distancia de 135 AU (2.02×10^10^ km) del Sol, en xunu de 2016, ye la nave espacial más alloñada de la Tierra y la única nel espaciu interestelar, pero entá ensin salir del sistema solar, quedándo-y unos 17 702 años aproximao pa salir a la nube d'Oort.\nVa Entrar nesta nunos 300 años aproximao.\nLa Voyager 1 ye anguaño l'oxetu fechu pol humanu más alloñáu de la Tierra, viaxando a una velocidá relativa de la Tierra y el Sol mayor que la de nenguna otra sonda espacial.\n...\nVoyager 1 tien una trayeutoria hiperbólica, y algamó velocidá d'escape, lo que significa que la so órbita nun va tornar al sistema solar interior.\nXunto cola Pioneer 10, Pioneer 11, Voyager 2 y la New Horizons, Voyager 1 ye una sonda interestelar.\n...\nA pesar de ser llanzada dempués de la so ximielga Voyager 2, la Voyager 1 algamó Jupiter dos meses primero que la so compañera, y, siguiendo una trayeutoria más rápida, llegó nueve meses antes a Saturno.\nVoyager 1 realizó les sos primeres fotografíes de Xúpiter en xineru de 1979 y algamó el so máximu acercamientu'l 5 de marzu de 1979 a una distancia de 278 000 km.\nNa so misión a Xúpiter realizó 19 000 fotografíes, nun periodu que duró hasta abril.\nPor cuenta de el máximu resolución dexáu por tal acercamientu, la mayor parte de les observaciones alrodiu de los satélites, aniellos, campu magnético y condiciones de radiación de Xúpiter fueron tomaes nun periodu de 48 hores alredor de dichu acercamientu.\n...\nAverar a 18 640 km del satélite Io de Xúpiter y pudo reparar per primer vegada actividá volcánica fuera de la Tierra, daqué que pasó inalvertíu pa les Pioneer 10 y 11.\nEl descubrimientu foi realizáu pola inxeniera de navegación Linda A. Morabito mientres un exame d'una fotografía delles hores dempués del sobrevuelu.\nAcelerada pel campu gravitatoriu de Xúpiter, algamó Saturnu el 12 de payares de 1980, averándose a una distancia de 124 200 km.\nNesta ocasión afayó estructures complexes nel sistema d'aniellos del planeta y consiguió datos de l'atmósfera de Saturnu y del so mayor satélite natural, Titán, del que pasó a menos de 6500 km.\nDebíu al descubrimientu d'atmósfera nesti satélite, el controladores de la misión decidieron que la Voyager 1 fixera un mayor aproximamientu a esta lluna, sacrificando asina les siguientes etapes del so viaxe, Uranu y Neptunu, que fueron visitaes pola so ximielga Voyager 2.\nEsti segundu acercamientu a Titan aumentó l'impulsu gravitatoriu de la sonda, alloñar del planu de la eclíptica y poniendo fin a la so misión planetaria.\n...\nD'esta manera, la Voyager 1 convertir nel primer oxetu creáu pol humanu en superar la heliopausa y enfusase nel espaciu interestelar.\n...\nEl 23 de febreru de 2017 a 20 916 millones de quilómetros (137,747 UA, esto ye, 38 h 14 min hores-lluz de la Tierra), la sonda dirixir al centru de la nuesa galaxa, la Vía Láctea, dexando l'espaciu apoderáu pola influencia del nuesu Sol dende'l 25 d'agostu de 2012 y entrando asina nel espaciu ente les estrelles, l'espaciu interestelar.",
        "title": "Voyager 1 - Wikipedia",
        "url": "https://ast.wikipedia.org/wiki/Voyager_1",
        "date": "2018-02-10",
        "last_updated": "2025-10-18"
      },
      {
        "snippet": "",
        "title": "Lo que encontró la Voyager 1 en el borde del sistema solar",
        "url": "https://www.youtube.com/watch?v=1QOXR4UV-_M",
        "date": "2026-01-28",
        "last_updated": "2026-04-20"
      },
      {
        "snippet": "",
        "title": "Voyager 1 - No Sólo Sputnik",
        "url": "https://nosolosputnik.com/el-planeta-jupiter/exploracion-de-jupiter/voyager-1/",
        "date": "2026-05-10",
        "last_updated": "2026-05-10"
      },
      {
        "snippet": "",
        "title": "Viajar 1",
        "url": "https://es.frwiki.wiki/wiki/Voyager_1",
        "date": null,
        "last_updated": "2024-05-04"
      },
      {
        "snippet": "# La Voyager 1, la primera nave en el espacio interestelar, puede haber perdido contacto para siempre con la humanidad\n## La sonda lanzada hace 46 años, que pasó cerca de Júpiter y Saturno em sus primeros años e inspiró a los terrícolas con imágenes del planeta como un “punto azul pálido”, no ha enviado datos en meses\n- 7 minutos de lectura'\nNUEVA YORK.-** Cuando la Voyager 1 se lanzó en 1977, los científicos esperaban que pudiera hacer aquello para lo que fue construida** y tomar imágenes de cerca de Júpiter y Saturno.\n**Hizo eso y mucho más.**\nLa Voyager 1 descubrió volcanes activos, lunas y anillos planetarios, demostrando en el camino que **la Tierra y toda la humanidad podían reducirse a un solo píxel en una fotografía, un “punto azul pálido”**, como lo llamó el astrónomo Carl Sagan.\nAlargó una misión de cuatro años hasta el día de hoy, embarcándose en **el viaje más profundo jamás realizado al espacio.**\n...\nLa Voyager 1, el objeto creado por humanos que llego más lejos en el espacio, **no ha enviado datos coherentes a la Tierra desde noviembre**.\n...\nLa nave espacial encontró una falla en una de sus computadoras que eliminó su capacidad de enviar datos de ingeniería y ciencia a la Tierra.\nLa pérdida de la Voyager 1 pondría** fin a décadas de avances científicos y señalaría el principio del fin de una misión que ha dado forma a la ambición más lejana de la humanidad e inspirado a generaciones a mirar al cielo.**\n...\nLa Voyager 1 es la mitad de la misión Voyager.\n...\nLanzados en 1977, **fueron construidos principalmente para un viaje de cuatro años a Júpiter y Saturno**, ampliando los sobrevuelos anteriores de las sondas Pioneer 10 y 11.\nLa misión Voyager aprovechó una rara alineación de los planetas exteriores (una vez cada 175 años), lo que permitió a las sondas visitar los cuatro.\nUtilizando la gravedad de cada planeta, la nave espacial Voyager podría pasar al siguiente, según la NASA.\n**La misión a Júpiter y Saturno fue un éxito.** Los sobrevuelos de la década de 1980 produjeron varios descubrimientos nuevos, incluidos nuevos conocimientos sobre la llamada gran mancha roja de Júpiter, los anillos alrededor de Saturno y las numerosas lunas de cada planeta.\nLa Voyager 2 también exploró Urano y Neptuno, convirtiéndose en 1989 en la única nave espacial en explorar los cuatro planetas exteriores.\nMientras tanto, **la Voyager 1 había fijado rumbo hacia el espacio profundo**, utilizando su cámara para fotografiar los planetas que iba dejando atrás en el camino.\nLa Voyager 2 comenzaría más tarde su propio viaje al espacio profundo.\n“Cualquiera que esté interesado en el espacio está interesado en las cosas que la Voyager descubrió sobre los planetas exteriores y sus lunas”, dijo Kate Howells, especialista en educación pública de la Planetary Society, una organización cofundada por Sagan para promover la exploración espacial.\n...\nEl día de San Valentín de 1990, la Voyager 1, que se alejaba 6000 millones de kilómetros del Sol hacia los confines exteriores del sistema solar,** se dio la vuelta y tomó una fotografía de la Tierra que Sagan y otros entendieron como un humilde autorretrato de la humanidad.**\n...\nIncluso cuando se lanzaron sondas más avanzadas desde la Tierra, la Voyager 1 continuó enriqueciendo de manera confiable nuestra comprensión del espacio.\nEn 2012, se convirtió en **el primer objeto creado por el hombre en salir de la heliosfera**, el espacio alrededor del sistema solar influenciado directamente por el sol.\nExiste un debate técnico entre los científicos sobre si la Voyager 1 realmente abandonó el sistema solar, pero, aun así, se volvió interestelar, atravesando el espacio entre las estrellas.\nEsto trazó un nuevo camino para la heliofísica, que analiza cómo el Sol influye en el espacio que lo rodea.\nEn 2018, la Voyager 2 siguió a su gemela entre las estrellas.\nAntes de la Voyager 1, los datos científicos sobre los gases y el material del Sol procedían únicamente de los confines de la heliosfera, según Jamie Rankin, científico adjunto del proyecto Voyager.\n...\n**Las Voyager 1 y 2 son las únicas naves espaciales de este tipo.** Antes de desconectarse, la Voyager 1 había estado estudiando una perturbación anómala en el campo magnético y las partículas de plasma en el espacio interestelar.\n...\nIncluso si la misión interestelar Voyager está cerca de su fin,** al viaje aún le queda mucho por recorrer.**\nPodría decirse que la Voyager 1 y su gemela, cada una a 40.000 años de distancia de la siguiente estrella más cercana, permanecerán en una misión indefinida.\n...\nCada nave espacial lleva un disco fonográfico bañado en oro cargado con una variedad de grabaciones de sonido e imágenes que representan la riqueza de la humanidad, sus diversas culturas y la vida en la Tierra.",
        "title": "La Voyager 1, la primera nave en el espacio interestelar ... - La Nación",
        "url": "https://www.lanacion.com.ar/el-mundo/la-voyager-1-la-primera-nave-en-el-espacio-interestelar-puede-haber-perdido-contacto-para-siempre-nid07032024/",
        "date": "2024-03-07",
        "last_updated": "2026-05-20"
      },
      {
        "snippet": "",
        "title": "Voyager 1 - Wikiwand",
        "url": "https://www.wikiwand.com/es/articles/Voyager_1",
        "date": "2023-11-14",
        "last_updated": "2025-08-06"
      },
      {
        "snippet": "",
        "title": "PDF Voyager 1 se acerca al espacio interestelar",
        "url": "https://ia800309.us.archive.org/25/items/Voyager1SeAcercaAlEspacioInterestelar/Voyager%201%20se%20acerca%20al%20espacio%20interestelar.pdf",
        "date": null,
        "last_updated": "2025-11-28"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

## Error Handling

When using language filters, implement proper error handling for validation issues:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity, BadRequestError

  client = Perplexity()

  def safe_language_search(query, languages):
      """
      Perform a language-filtered search with error handling.
      """
      try:
          # Validate language codes
          if not isinstance(languages, list):
              raise ValueError("Languages must be provided as a list")
          
          if len(languages) > 10:
              raise ValueError("Maximum 10 language codes allowed")
          
          # Validate each code format
          for lang in languages:
              if not isinstance(lang, str) or len(lang) != 2 or not lang.islower():
                  raise ValueError(f"Invalid language code format: {lang}")
          
          # Perform search
          response = client.search.create(
              query=query,
              search_language_filter=languages,
              max_results=10
          )
          
          return response
          
      except ValueError as e:
          print(f"Validation error: {e}")
          return None
      except BadRequestError as e:
          print(f"API error: {e.message}")
          return None
      except Exception as e:
          print(f"Unexpected error: {e}")
          return None

  # Usage
  results = safe_language_search(
      "artificial intelligence",
      ["en", "fr", "de"]
  )

  if results:
      print(f"Found {len(results.results)} results")
  ```

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

  const client = new Perplexity();

  async function safeLanguageSearch(
    query: string,
    languages: string[]
  ): Promise<any | null> {
    try {
      // Validate language codes
      if (!Array.isArray(languages)) {
        throw new Error("Languages must be provided as an array");
      }
      
      if (languages.length > 10) {
        throw new Error("Maximum 10 language codes allowed");
      }
      
      // Validate each code format
      for (const lang of languages) {
        if (typeof lang !== 'string' || 
            lang.length !== 2 || 
            lang !== lang.toLowerCase()) {
          throw new Error(`Invalid language code format: ${lang}`);
        }
      }
      
      // Perform search
      const response = await client.search.create({
        query,
        search_language_filter: languages,
        max_results: 10
      });
      
      return response;
      
    } catch (error) {
      if (error instanceof Perplexity.BadRequestError) {
        console.error("API error:", error.message);
      } else if (error instanceof Error) {
        console.error("Error:", error.message);
      }
      return null;
    }
  }

  // Usage
  const results = await safeLanguageSearch(
    "artificial intelligence",
    ["en", "fr", "de"]
  );

  if (results) {
    console.log(`Found ${results.results.length} results`);
  }
  ```
</CodeGroup>

<Tip>
  For best results, combine language filtering with other filters like `search_domain_filter` or `search_recency_filter` to narrow down your search to highly relevant, timely content in your target languages.
</Tip>


# People Search
Source: https://docs.perplexity.ai/docs/search/filters/people-search



<Note>
  The `search_type` parameter switches the Search API between general web search and specialized search modes. Set `search_type="people"` to invoke People Search and retrieve professional information about individuals such as names, job titles, and companies.
</Note>

## Overview

People Search lets you query Perplexity's index for professionals, employees, and public figures. Use it when your application needs to:

* Look up a specific person's professional background
* Find employees at a company by role or title
* Identify professionals in a particular field or location
* Research leadership teams or organizational structures

Pass `search_type="people"` on a standard Search API request to route the query through the People Search backend. All other Search API parameters (e.g., `max_results`, `max_tokens_per_page`) continue to apply.

## Request Example

The example below finds engineering leadership at a specific company.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.search.create(
      query="Stripe VP of Engineering",
      search_type="people",
      max_results=10
  )

  for result in response.results:
      print(f"{result.title}: {result.url}")
  ```

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

  const client = new Perplexity();

  const response = await client.search.create({
      query: "Stripe VP of Engineering",
      search_type: "people",
      max_results: 10
  });

  for (const result of response.results) {
      console.log(`${result.title}: ${result.url}`);
  }
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "Stripe VP of Engineering",
      "search_type": "people",
      "max_results": 10
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "719f1f3c-d01b-4430-8ee4-cd9c1b836083",
    "results": [
      {
        "snippet": "We are a brand new team, working quickly to accelerate Stripes engineering productivity by effectively deploying LLM agents and tools to automate large swaths of the engineering workflow.\nWe’re a cross-continent team, spanning North America and Europe, filled with high agency engineers with strong product perspectives.\n...\nWe are looking for a hands-on Manager who can effectively lead and guide a team high agency engineers to move quickly on a rapidly growing tech space.\nThey will help set the product direction in a field with a nearly endless possible solution space.\nFolks passionate about great products, user experience and with a strong opinion about how engineers do good work will excel in this role.\nPrior experience with deploying AI developer tools isn’t necessary, but is interesting.\nYou will:\n- Lead a senior, cross-continent team of engineers to move rapidly to deploy and exploit the latest in AI devtools.\n- Deliver compelling user and product experiences for internal users.\n- Work across the company to redefine how software engineers at Stripe work.\n- Keep up with an incredibly fast paced technology environment.\n- Dig deep into the data on how engineers use AI tools to seek out every bit of benefit, and help Stripe accelerate.\n...\n### Minimum requirements\n- 2+ years managing high performing engineering teams, and at least 5+ years of experience as a software engineer.\n- Proven success in recruiting and building great teams.\n- A repeated history of delivering great, innovative product experiences - either for internal or external users.\n- Effective cross-functional collaboration, with the ability to think rigorously, communicate clearly, and make or coordinate difficult decisions and trade-offs.\n- Thrives with high autonomy and responsibility in an ambiguous environment.\n- Ability to foster a healthy, inclusive, challenging, and supportive work environment.\n### Preferred qualifications\n- Experience Tech leading, mentoring and managing a team that shipped products to engineers.\n- Experience building tools and products, ideally for technical audiences - either as internal or external customers.\n- Deep curiosity and opinionation about the use of AI in software engineering.\n- Strong written and verbal communication skills for various audiences, including leadership, users, and company-wide.\nThis role is available either in an office or a remote location (35+ miles or 56+ km from a Stripe office).\n...\nA remote location is defined as being 35 miles (56 kilometers) or more from one of our offices.\n...\nThe annual US base salary range for this role is $214,600 - $321,800.\nFor sales roles, the range provided is the role’s On Target Earnings (\"OTE\") range, meaning that the range includes both the sales commissions/sales bonuses target and annual base salary for the role.\nThis salary range may be inclusive of several career levels at Stripe and will be narrowed during the interview process based on a number of factors, including the candidate’s experience, qualifications, and location.\nApplicants interested in this role and who are not located in the US may request the annual salary range for their location during the interview process.\nAdditional benefits for this role may include: equity, company bonus or sales commissions/bonuses; 401(k) plan; medical, dental, and vision benefits; and wellness stipends.\nOffice locations\nSeattle, or South San Francisco HQ\nRemote locations\nRemote in United States\nTeam\nInfrastructure & Corporate Tech\nJob type\nFull time",
        "title": "Engineering Manager, Developer Productivity AI",
        "url": "https://stripe.com/jobs/listing/engineering-manager-developer-productivity-ai/7736943",
        "date": null,
        "last_updated": "2026-05-26"
      },
      {
        "snippet": "# Head of Engineering, Identity Graph\n•San Francisco / Remote\n**Job type**\nFull-time\n**Role**\nEngineering, Backend\n**Experience**\n11+ years\n**Visa**\nWill sponsor\n**Skills**\nJava\n...\nWe’re looking for an experienced engineering leader to lead our technical strategy in building a graph of identities and inferences that enriches Stripe’s product portfolio by knowing our users deeply and enhances the user experience that enables users to establish trust, accelerate globalization, and open up new market opportunities quickly with just a few lines of code.\nYou’ll manage and grow a strong team of backend and machine learning developers, build relationships with customers and other teams at Stripe, and work on something trajectory altering for Stripe.\n...\nYou will:\nWork with engineers, product, and design to build new customer-facing APIs and products, while maintaining the quality and improving the experience of existing products\nWork with marketing and developer relations teams to explain our products by preparing demos for user-facing events\nCoordinate with other teams at Stripe, both on the problem domain of how payment systems really work and on our shared infrastructure\nEmpower the engineering team to achieve a high level of technical productivity and quality\nManage an excellent team of engineers, helping to develop their careers with stretch projects and excellent feedback\nRecruit a diverse team of engineers that are amongst the best in the industry, from outreach to closing\nContribute to engineering-wide initiatives as part of the engineering management team\nWe’re looking for someone who has:\nExperience working in large graph-based systems\nDomain expertise in the fraud and/or financial risk space\nAn excitement for collaborating with teammates across engineering, operations, and data science\nThe ability to thrive with a high level of autonomy and responsibility\nExperience managing engineering teams with a strong record of shipping\nStrong recruiting skills, with a track record of hiring new team members who are extremely effective over the long term",
        "title": "Head of Engineering, Identity Graph at Stripe",
        "url": "https://www.ycombinator.com/companies/stripe/jobs/yaLKuLq-head-of-engineering-identity-graph",
        "date": "2021-10-07",
        "last_updated": "2026-05-25"
      },
      {
        "snippet": "# Stripe poaches Google’s Vice President of Engineering\nSilicon Valley-based startup Stripe has reportedly hired Google’s Vice President of Engineering as the head of its own engineering department, with news having first been reported by\n*Axios*.\nWith Stripe looking to continue its expansion, Singleton has been brought in largely due to his experience in both leadership roles and innovative product development.\n...\nIn his current position at Google, Singleton has been playing a leading role within the company’s Android Wear and Google Fit teams, becoming renowned as one of the key figures behind Google’s smartwatch products.\nHe has largely specialised in engineering since he joined Google in May 2006, having initially been appointed as a Software Engineer for the company.\n*Axios* also revealed that Singleton will now relocate to San Francisco for his new role with Stripe, with Engineering talent currently in high demand in the Silicon Valley area.",
        "title": "Stripe poaches Google's Vice President of Engineering",
        "url": "https://businesschief.com/leadership-and-strategy/stripe-poaches-googles-vice-president-engineering-1",
        "date": "2020-05-19",
        "last_updated": "2025-07-03"
      },
      {
        "snippet": "Ryan Liu is an accomplished technology leader with extensive experience in engineering management, having served as Vice President of Engineering at Stripe from January 2017 to February 2024.\nIn this role, Ryan successfully oversaw the engineering organization by driving strategic initiatives, fostering innovation, and ensuring infrastructure scalability.\nPreviously, Ryan held key positions at Stripe, including Head of Engineering and Director of Engineering, focusing on aligning engineering efforts with company objectives and enhancing collaboration across teams.",
        "title": "Ryan Liu - VP Of Engineering at Stripe",
        "url": "https://theorg.com/org/stripe/org-chart/ryan-liu",
        "date": "2025-10-07",
        "last_updated": "2025-12-30"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

## Query Tips

For best results, include identifying details in the query:

| Approach            | Example query                              |
| ------------------- | ------------------------------------------ |
| **Name + company**  | "Find John Smith who works at Google"      |
| **Role + company**  | "Head of Design at Figma"                  |
| **Role + location** | "Marketing directors in San Francisco"     |
| **Role + field**    | "Machine learning researchers at Stanford" |

<Tip>
  For agentic workflows that need the model to autonomously decide when to look up people, use the [`people_search` tool](/docs/agent-api/tools/people-search) with the Agent API instead. To wire People Search into a third-party agent SDK, see [Use as an agent tool](#use-as-an-agent-tool) below.
</Tip>

## Use as an agent tool

People Search can be exposed to a third-party agent SDK as a `people_search` function tool — useful when you want the model to autonomously decide when to look up individuals. The plumbing below mirrors the [`web_search` Agent SDK integrations](/docs/search/agent-sdks/anthropic); wire `people_search` into the same tool-call loop alongside or in place of `web_search`.

### Tool description

Keep the description verbatim — its wording is what produces good, focused queries and prevents the model from picking People Search for general-knowledge questions.

<CodeGroup>
  ```python Python theme={null}
  PEOPLE_SEARCH_TOOL_DESCRIPTION = """\
  Searches a dedicated index for individual profiles and employee data. Returns information including names, job titles, companies, and profile URLs. Use this tool ONLY when the user specifically wants individual employee lookups, career history, or people who match work-related criteria (e.g., listing employees at a company by location). For general questions about executives, leadership teams, or public figures, prefer search_web instead as it returns richer curated results.

  Best practices:
  - Include the person's name and/or company for targeted results.
  - Add job title or role keywords to narrow results.
  - Use both abbreviations AND full titles for better coverage (e.g., query for both "CTO" and "Chief Technology Officer").
  - Use multiple distinct query variations for broader coverage, varying by role, department, company name, or location.
  - Use up to five queries for complex requests.

  Examples:
    - ["John Smith software engineer Google"]
    - ["CTO Stripe", "Chief Technology Officer Stripe"]
    - ["Perplexity AI engineer SF", "Perplexity product manager", "Perplexity AI designer San Francisco"]
    - ["machine learning researcher Stanford"]"""

  PEOPLE_QUERIES_PARAM_DESCRIPTION = (
      "An array of keyword-based people search queries. Each query should "
      "include names, titles, or companies."
  )
  ```

  ```typescript Typescript theme={null}
  const PEOPLE_SEARCH_TOOL_DESCRIPTION = `Searches a dedicated index for individual profiles and employee data. Returns information including names, job titles, companies, and profile URLs. Use this tool ONLY when the user specifically wants individual employee lookups, career history, or people who match work-related criteria (e.g., listing employees at a company by location). For general questions about executives, leadership teams, or public figures, prefer search_web instead as it returns richer curated results.

  Best practices:
  - Include the person's name and/or company for targeted results.
  - Add job title or role keywords to narrow results.
  - Use both abbreviations AND full titles for better coverage (e.g., query for both "CTO" and "Chief Technology Officer").
  - Use multiple distinct query variations for broader coverage, varying by role, department, company name, or location.
  - Use up to five queries for complex requests.

  Examples:
    - ["John Smith software engineer Google"]
    - ["CTO Stripe", "Chief Technology Officer Stripe"]
    - ["Perplexity AI engineer SF", "Perplexity product manager", "Perplexity AI designer San Francisco"]
    - ["machine learning researcher Stanford"]`;

  const PEOPLE_QUERIES_PARAM_DESCRIPTION =
    "An array of keyword-based people search queries. Each query should " +
    "include names, titles, or companies.";
  ```
</CodeGroup>

### Tool registration

The tool registration shape varies per SDK. The schema allows up to five queries (vs. three for `web_search`).

<Tabs>
  <Tab title="Anthropic">
    <CodeGroup>
      ```python Python theme={null}
      PEOPLE_SEARCH_TOOL = {
          "name": "people_search",
          "description": PEOPLE_SEARCH_TOOL_DESCRIPTION,
          "input_schema": {
              "type": "object",
              "properties": {
                  "queries": {
                      "type": "array",
                      "description": PEOPLE_QUERIES_PARAM_DESCRIPTION,
                      "items": {"type": "string"},
                      "minItems": 1,
                      "maxItems": 5,
                  },
              },
              "required": ["queries"],
          },
      }
      ```

      ```typescript Typescript theme={null}
      const PEOPLE_SEARCH_TOOL = {
        name: "people_search",
        description: PEOPLE_SEARCH_TOOL_DESCRIPTION,
        input_schema: {
          type: "object" as const,
          properties: {
            queries: {
              type: "array" as const,
              description: PEOPLE_QUERIES_PARAM_DESCRIPTION,
              items: { type: "string" as const },
              minItems: 1,
              maxItems: 5,
            },
          },
          required: ["queries"],
        },
      };
      ```
    </CodeGroup>
  </Tab>

  <Tab title="OpenAI">
    <CodeGroup>
      ```python Python theme={null}
      PEOPLE_SEARCH_TOOL = {
          "type": "function",
          "name": "people_search",
          "description": PEOPLE_SEARCH_TOOL_DESCRIPTION,
          "strict": True,
          "parameters": {
              "type": "object",
              "additionalProperties": False,
              "properties": {
                  "queries": {
                      "type": "array",
                      "description": PEOPLE_QUERIES_PARAM_DESCRIPTION,
                      "items": {"type": "string"},
                  },
              },
              "required": ["queries"],
          },
      }
      ```

      ```typescript Typescript theme={null}
      const PEOPLE_SEARCH_TOOL = {
        type: "function" as const,
        name: "people_search",
        description: PEOPLE_SEARCH_TOOL_DESCRIPTION,
        strict: true,
        parameters: {
          type: "object" as const,
          additionalProperties: false,
          properties: {
            queries: {
              type: "array" as const,
              description: PEOPLE_QUERIES_PARAM_DESCRIPTION,
              items: { type: "string" as const },
            },
          },
          required: ["queries"],
        },
      };
      ```
    </CodeGroup>

    <Warning>
      **Strict mode constraints.** When `strict: true`, the JSON Schema must set `additionalProperties: false` and list every property in `required`. OpenAI rejects `maxItems`/`minItems` in strict mode — enforce the five-query cap through the description and truncate defensively in your handler.
    </Warning>
  </Tab>

  <Tab title="Gemini">
    <CodeGroup>
      ```python Python theme={null}
      from google.genai import types

      PEOPLE_SEARCH_FUNCTION = types.FunctionDeclaration(
          name="people_search",
          description=PEOPLE_SEARCH_TOOL_DESCRIPTION,
          parameters_json_schema={
              "type": "object",
              "properties": {
                  "queries": {
                      "type": "array",
                      "description": PEOPLE_QUERIES_PARAM_DESCRIPTION,
                      "items": {"type": "string"},
                      "minItems": 1,
                      "maxItems": 5,
                  },
              },
              "required": ["queries"],
          },
      )

      PEOPLE_SEARCH_TOOL = types.Tool(function_declarations=[PEOPLE_SEARCH_FUNCTION])
      ```

      ```typescript Typescript theme={null}
      import type { FunctionDeclaration, Tool } from "@google/genai";

      const PEOPLE_SEARCH_FUNCTION: FunctionDeclaration = {
        name: "people_search",
        description: PEOPLE_SEARCH_TOOL_DESCRIPTION,
        parametersJsonSchema: {
          type: "object",
          properties: {
            queries: {
              type: "array",
              description: PEOPLE_QUERIES_PARAM_DESCRIPTION,
              items: { type: "string" },
              minItems: 1,
              maxItems: 5,
            },
          },
          required: ["queries"],
        },
      };

      const PEOPLE_SEARCH_TOOL: Tool = {
        functionDeclarations: [PEOPLE_SEARCH_FUNCTION],
      };
      ```
    </CodeGroup>
  </Tab>
</Tabs>

### Handler

The handler is identical across SDKs — call Search API with `search_type="people"`:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  perplexity = Perplexity()

  def run_people_search(queries: list[str]) -> str:
      """Call Perplexity People Search and format the results for the model."""
      response = perplexity.search.create(
          query=queries, search_type="people", max_results=10
      )

      lines = []
      for result in response.results:
          snippet = (result.snippet or "").strip().replace("\n", " ")
          if len(snippet) > 400:
              snippet = snippet[:400] + "…"
          lines.append(f"- {result.title}\n  {result.url}\n  {snippet}")
      return "\n\n".join(lines) if lines else "No results."
  ```

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

  const perplexity = new Perplexity();

  async function runPeopleSearch(queries: string[]): Promise<string> {
    const response = await perplexity.search.create({
      query: queries,
      search_type: "people",
      max_results: 10,
    });

    const lines = response.results.map((r) => {
      const snippet = (r.snippet ?? "").trim().replace(/\n/g, " ");
      const trimmed = snippet.length > 400 ? `${snippet.slice(0, 400)}…` : snippet;
      return `- ${r.title}\n  ${r.url}\n  ${trimmed}`;
    });
    return lines.length ? lines.join("\n\n") : "No results.";
  }
  ```
</CodeGroup>

### Tool-call loop

The tool-call loop is identical to the `web_search` pattern in each SDK's guide. Wire `people_search` into the same loop, either alongside `web_search` or on its own, and dispatch on the tool name when handling tool calls.

<CardGroup>
  <Card title="Anthropic SDK" icon="code" href="/docs/search/agent-sdks/anthropic">
    Messages API tool-use loop.
  </Card>

  <Card title="OpenAI SDK" icon="code" href="/docs/search/agent-sdks/openai">
    Responses API tool-call loop.
  </Card>

  <Card title="Gemini SDK" icon="code" href="/docs/search/agent-sdks/gemini">
    `google-genai` SDK function calling.
  </Card>
</CardGroup>


# Perplexity Search API
Source: https://docs.perplexity.ai/docs/search/quickstart

Access real-time web search results with Perplexity's Search API. Get ranked results, domain filtering, multi-query search, and content extraction for developers.

## Overview

Perplexity's Search API returns real-time, ranked web results as structured data, with controls for domains, languages, regions, and extracted content.

Use the Search API when you need raw results for your own processing. For an LLM-generated answer with citations, use the [Agent API](/docs/agent-api/quickstart).

## Add Perplexity Search to your agent

Ask your agent to install the Perplexity Search skill:

```text wrap theme={null}
Read https://github.com/perplexityai/api-platform-developers/blob/main/skills/pplx-cli/SKILL.md and install this skill.
```

You can also [try Perplexity Search in the interactive Playground](https://console.perplexity.ai/group/playground/search) with no API key required.

<Tip>
  You can now run Perplexity Search straight from your terminal.
  The [Perplexity CLI](/docs/cli/overview) returns the same ranked results as JSON, ready for shell pipelines and agent tool calls, with no code to write.
</Tip>

## Installation

Install one of our [official SDKs](/docs/sdk/overview) for a convenient, type-safe integration:

<CodeGroup>
  ```bash Python theme={null}
  pip install perplexityai
  ```

  ```bash Typescript theme={null}
  npm install @perplexity-ai/perplexity_ai
  ```
</CodeGroup>

## Authentication

Set your API key as an environment variable. The official SDKs read it automatically, but you can also pass it explicitly:

<Tabs>
  <Tab title="macOS/Linux">
    ```bash theme={null}
    export PERPLEXITY_API_KEY="your_api_key_here"
    ```
  </Tab>

  <Tab title="Windows">
    ```powershell theme={null}
    setx PERPLEXITY_API_KEY "your_api_key_here"
    ```
  </Tab>
</Tabs>

## Basic Usage

Start with a basic search query to get relevant web results. `max_results` accepts values from 1 to 20 and defaults to 10. See the [API Reference](/api-reference/search-post) for all parameters and [pricing](/docs/getting-started/pricing) for search costs.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  search = client.search.create(
      query="GPT-5.5 release announcement details",
      max_results=5,
      search_context_size="high"
  )

  for result in search.results:
      print(f"{result.title}: {result.url}")
  ```

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

  const client = new Perplexity();

  const search = await client.search.create({
      query: "GPT-5.5 release announcement details",
      max_results: 5,
      search_context_size: "high"
  });

  for (const result of search.results) {
      console.log(`${result.title}: ${result.url}`);
  }
  ```

  ```javascript JavaScript theme={null}
  const Perplexity = require('@perplexity-ai/perplexity_ai');

  const client = new Perplexity();

  async function main() {
      const search = await client.search.create({
          query: "GPT-5.5 release announcement details",
          max_results: 5,
          search_context_size: "high"
      });

      for (const result of search.results) {
          console.log(`${result.title}: ${result.url}`);
      }
  }

  main();
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "GPT-5.5 release announcement details",
      "max_results": 5,
      "search_context_size": "high"
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "results": [
      {
        "title": "2024: A year of extraordinary progress and advancement in AI - Google Blog",
        "url": "https://blog.google/technology/ai/2024-ai-extraordinary-progress-advancement/",
        "snippet": "## Relentless innovation in models, products and technologies\n\n2024 was a year of experimenting, fast shipping, and putting our latest technologies in the hands of developers.\n\nIn December 2024, we released the first models in our Gemini 2.0 experimental series — AI models designed for the agentic era. First out of the gate was Gemini 2.0 Flash, our workhorse model, followed by prototypes from the frontiers of our agentic research including: an updated Project Astra, which explores the capabilities of a universal AI assistant; Project Mariner, an early prototype capable of taking actions in Chrome as an experimental extension; and Jules, an AI-powered code agent. We're looking forward to bringing Gemini 2.0’s powerful capabilities to our flagship products — in Search, we've already started testing in AI Overviews, which are now used by over a billion people to ask new types of questions.\n\nWe also released Deep Research, a new agentic feature in Gemini Advanced that saves people hours of research work by creating and executing multi-step plans for finding answers to complicated questions; and introduced Gemini 2.0 Flash Thinking Experimental, an experimental model that explicitly shows its thoughts.\n\nThese advances followed swift progress earlier in the year, from incorporating Gemini's capabilities into more Google products to the release of Gemini 1.5 Pro and Gemini 1.5 Flash — a model optimized for speed and efficiency. 1.5 Flash's compact size made it more cost-efficient to serve, and in 2024 it became our most popular model for developers.... ## The architecture of intelligence: advances in robotics, hardware and computing\n\nAs our multimodal models become more capable and gain a better understanding of the world and its physics, they are making possible incredible new advances in robotics and bringing us closer to our goal of ever-more capable and helpful robots.\n\nWith ALOHA Unleashed, our robot learned to tie a shoelace, hang a shirt, repair another robot, insert a gear and even clean a kitchen.\n\nAt the beginning of the year, we introduced AutoRT, SARA-RT and RT-Trajectory, extensions of our Robotics Transformers work intended to help robots better understand and navigate their environments, and make decisions faster. We also published ALOHA Unleashed, a breakthrough in teaching robots on how to use two robotic arms in coordination, and DemoStart, which uses a reinforcement learning algorithm to improve real-world performance on a multi-fingered robotic hand by using simulations.\n\nRobotic Transformer 2 (RT-2) is a novel vision-language-action model that learns from both web and robotics data.\n\nBeyond robotics, our AlphaChip reinforcement learning method for accelerating and improving chip floorplanning is transforming the design process for chips found in data centers, smartphones and more. To accelerate adoption of these techniques, we released a pre-trained checkpoint to enable external parties to more easily make use of the AlphaChip open source release for their own chip designs. And we made Trillium, our sixth-generation and most performant TPU to date, generally available to Google Cloud customers. Advances in computer chips have accelerated AI. And now, AI can return the favor.... We are exploring how machine learning can help medical fields struggling with access to imaging expertise, such as radiology, dermatology and pathology. In the past year, we released two research tools, Derm Foundation and Path Foundation, that can help develop models for diagnostic tasks, image indexing and curation and biomarker discovery and validation. We collaborated with physicians at Stanford Medicine on an open-access, inclusive Skin Condition Image Network (SCIN) dataset. And we unveiled CT Foundation, a medical imaging embedding tool used for rapidly training models for research.\n\nWith regard to learning, we explored new generative AI tools to support educators and learners. We introduced LearnLM, our new family of models fine-tuned for learning and used it to enhance learning experiences in products like Search, YouTube and Gemini; a recent report showed LearnLM outperformed other leading AI models. We also made it available to developers as an experimental model in AI Studio. Our new conversational learning companion, LearnAbout, uses AI to help you dive deeper into any topic you're curious about, while Illuminate lets you turn content into engaging AI-generated audio discussions.\n\nIn the fields of disaster forecasting and preparedness, we announced several breakthroughs. We introduced GenCast, our new high-resolution AI ensemble model, which improves day-to-day weather and extreme events forecasting across all possible weather trajectories. We also introduced our NeuralGCM model, able to simulate over 70,000 days of the atmosphere in the time it would take a physics-based model to simulate only 19 days. And GraphCast won the 2024 MacRobert Award for engineering innovation.",
        "date": "2025-01-23",
        "last_updated": "2025-09-25"
      },
      {
        "title": "The 2025 AI Index Report | Stanford HAI",
        "url": "https://hai.stanford.edu/ai-index/2025-ai-index-report",
        "snippet": "Read the translation\n\nIn 2023, researchers introduced new benchmarks—MMMU, GPQA, and SWE-bench—to test the limits of advanced AI systems. Just a year later, performance sharply increased: scores rose by 18.8, 48.9, and 67.3 percentage points on MMMU, GPQA, and SWE-bench, respectively. Beyond benchmarks, AI systems made major strides in generating high-quality video, and in some settings, language model agents even outperformed humans in programming tasks with limited time budgets.\n\nFrom healthcare to transportation, AI is rapidly moving from the lab to daily life. In 2023, the FDA approved 223 AI-enabled medical devices, up from just six in 2015. On the roads, self-driving cars are no longer experimental: Waymo, one of the largest U.S. operators, provides over 150,000 autonomous rides each week, while Baidu's affordable Apollo Go robotaxi fleet now serves numerous cities across China.\n\nIn 2024, U.S. private AI investment grew to $109.1 billion—nearly 12 times China's $9.3 billion and 24 times the U.K.'s $4.5 billion. Generative AI saw particularly strong momentum, attracting $33.9 billion globally in private investment—an 18.7% increase from 2023. AI business usage is also accelerating: 78% of organizations reported using AI in 2024, up from 55% the year before. Meanwhile, a growing body of research confirms that AI boosts productivity and, in most cases, helps narrow skill gaps across the workforce.... In 2024, U.S.-based institutions produced 40 notable AI models, significantly outpacing China's 15 and Europe's three. While the U.S. maintains its lead in quantity, Chinese models have rapidly closed the quality gap: performance differences on major benchmarks such as MMLU and HumanEval shrank from double digits in 2023 to near parity in 2024. Meanwhile, China continues to lead in AI publications and patents. At the same time, model development is increasingly global, with notable launches from regions such as the Middle East, Latin America, and Southeast Asia.\n\nAI-related incidents are rising sharply, yet standardized RAI evaluations remain rare among major industrial model developers. However, new benchmarks like HELM Safety, AIR-Bench, and FACTS offer promising tools for assessing factuality and safety. Among companies, a gap persists between recognizing RAI risks and taking meaningful action. In contrast, governments are showing increased urgency: In 2024, global cooperation on AI governance intensified, with organizations including the OECD, EU, U.N., and African Union releasing frameworks focused on transparency, trustworthiness, and other core responsible AI principles.\n\nIn countries like China (83%), Indonesia (80%), and Thailand (77%), strong majorities see AI products and services as more beneficial than harmful. In contrast, optimism remains far lower in places like Canada (40%), the United States (39%), and the Netherlands (36%). Still, sentiment is shifting: since 2022, optimism has grown significantly in several previously skeptical countries—including Germany (+10%), France (+10%), Canada (+8%), Great Britain (+8%), and the United States (+4%).... Driven by increasingly capable small models, the inference cost for a system performing at the level of GPT-3.5 dropped over 280-fold between November 2022 and October 2024. At the hardware level, costs have declined by 30% annually, while energy efficiency has improved by 40% each year. Open-weight models are also closing the gap with closed models, reducing the performance difference from 8% to just 1.7% on some benchmarks in a single year. Together, these trends are rapidly lowering the barriers to advanced AI.\n\nIn 2024, U.S. federal agencies introduced 59 AI-related regulations—more than double the number in 2023—and issued by twice as many agencies. Globally, legislative mentions of AI rose 21.3% across 75 countries since 2023, marking a ninefold increase since 2016. Alongside growing attention, governments are investing at scale: Canada pledged $2.4 billion, China launched a $47.5 billion semiconductor fund, France committed €109 billion, India pledged $1.25 billion, and Saudi Arabia's Project Transcendence represents a $100 billion initiative.\n\nTwo-thirds of countries now offer or plan to offer K–12 CS education—twice as many as in 2019—with Africa and Latin America making the most progress. In the U.S., the number of graduates with bachelor's degrees in computing has increased 22% over the last 10 years. Yet access remains limited in many African countries due to basic infrastructure gaps like electricity. In the U.S., 81% of K–12 CS teachers say AI should be part of foundational CS education, but less than half feel equipped to teach it.",
        "date": "2024-09-10",
        "last_updated": "2025-09-25"
      }
    ],
    "id": "e38104d5-6bd7-4d82-bc4e-0a21179d1f77"
  }
  ```
</Accordion>

## Regional Web Search

Set `country` to an ISO 3166-1 alpha-2 code such as `US`, `GB`, `DE`, or `JP` to get more geographically relevant results. This is useful for local news, regulations, and other region-specific queries:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Search for results from a specific country
  search = client.search.create(
      query="government policies on renewable energy",
      country="US",  # ISO country code
      max_results=5
  )

  for result in search.results:
      print(f"{result.title}: {result.url}")
  ```

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

  const client = new Perplexity();

  // Search for results from a specific country
  const search = await client.search.create({
      query: "government policies on renewable energy",
      country: "US", // ISO country code
      max_results: 5
  });

  for (const result of search.results) {
      console.log(`${result.title}: ${result.url}`);
  }
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "government policies on renewable energy",
      "country": "US",
      "max_results": 5
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "5ca855c3-14f9-4863-8027-9375087aec4a",
    "results": [
      {
        "snippet": "EPA's\n*State Energy and Environment* Guide to Action offers real-world best practices to help states design and implement policies that reduce emissions associated with electricity generation and energy consumption.\nThe *Guide *is a comprehensive EPA resource designed to help state officials draw insights from other states' implementation experiences and policy innovations to help meet their own state's climate, environment, and energy goals.\n...\nDSIRE is a comprehensive source of information on the status of state programs and incentives promoting renewable energy, including information on financial incentives and net metering policies, as well as related awareness and investment programs.\n...\nThe Distributed Renewable Energy Finance and Policy Toolkit describes the many financing options available to state energy offices, municipal governments, and other energy agencies for utilizing public funds for clean energy project support.\nThe report analyzes their strengths and weaknesses and identifies best practices.\nOne key finding is that the use of these tools as a portfolio of approaches creates the most robust, effective programs.\n...\nEPA's Green Power Partnership provides an overview of REC tracking systems, including a map of the regional tracking systems that have been developed in the United States.",
        "title": "State Renewable Energy: Policies | US EPA",
        "url": "https://www.epa.gov/statelocalenergy/state-renewable-energy-policies",
        "date": "2026-01-05",
        "last_updated": "2026-01-27"
      },
      {
        "snippet": "As environmental challenges grow more urgent, government policies on renewable energy have become essential in shaping the future.\nThese policies not only combat climate change but also drive sustainable energy solutions for communities worldwide.\nThe transition to renewable energy requires more than technological advancements—it is driven by clear and supportive policies.\nGovernments are instrumental in providing the incentives, infrastructure and regulations needed to accelerate renewable energy adoption.\n...\nEnergy policy involves guidelines and regulations that govern the production, distribution and use of energy.\nIt plays a crucial role in supporting economic growth, social well-being and environmental sustainability.\nEffective energy policy addresses issues like energy security, renewable energy and climate change, using mechanisms such as laws, incentives and regulations.\n...\nGovernments worldwide are playing an increasingly critical role in advancing renewable energy adoption through strategic policies.\nThese policies, though diverse, aim to accelerate the transition toward sustainable energy and meet global climate goals.\n- Europe leads by example with the European Union’s Renewable Energy Directive, which mandates that member states meet specific renewable energy targets by 2030.\nThis directive not only fosters cooperation across the EU but also encourages investment in green energy.\n- Countries such as Germany have pioneered successful mechanisms like feed-in tariffs, guaranteeing fixed payments for renewable energy producers, which has significantly boosted solar power installations across the country.\n- In Southeast Asia, governments are increasingly turning to renewable energy policies to address growing energy demands and sustainability goals.\nFor instance, the Philippines enacted the Renewable Energy Act of 2008 (Republic Act 9513), which provides fiscal incentives such as tax holidays and zero-percent VAT for renewable energy developers.\nThese policies have enabled the development of numerous renewable energy projects in the Philippines, helping the country reduce its dependence on fossil fuels.\nThrough these examples, it becomes clear that government policies are essential in accelerating the adoption of renewable energy technologies, fostering innovation and promoting sustainability on a global scale.\n...\nThe growth of renewable energy relies heavily on government policies that promote clean energy adoption.\nThese policies help reduce the risks and costs associated with renewable energy projects, making them more attractive to investors and developers.\nWithout favorable policies, the transition to renewables would likely be slower and less comprehensive.\nThere are several ways in which policy supports renewable energy development.\nFinancial incentives, such as subsidies, tax credits and grants, lower the upfront costs of renewable energy technologies, encouraging widespread adoption.\nFeed-in tariffs and renewable energy certificates (RECs) also help by ensuring stable income for renewable energy producers.\nThese policies reduce financial uncertainty and create long-term economic viability for green energy projects.\nAnother key aspect is the establishment of clear targets and standards.\nGovernments that commit to ambitious renewable energy goals, such as achieving a certain percentage of clean energy by a specific year, encourage innovation and competition within the industry.\nThis, in turn, accelerates the development of new technologies and solutions.\n...\nGovernment policies play a crucial role in advancing renewable energy technology by providing the necessary financial support, research funding and tax incentives.\nThese policies create an environment that encourages companies to innovate, reducing the financial risks typically associated with investing in cutting-edge technologies.\n...\nIn the Philippines, renewable energy policies have played a critical role in shaping the country’s energy landscape.\nThe Renewable Energy Act of 2008 (Republic Act 9513) marked a turning point in the Philippines’ journey toward a sustainable future.\nThis law established a comprehensive framework to promote the development of renewable energy projects in the Philippines, offering incentives such as tax holidays, zero-percent VAT and feed-in tariffs.\n...\nGovernment policies play a pivotal role in advancing renewable energy, shaping the future of clean energy development, and ensuring its widespread adoption.",
        "title": "The role of government policies in advancing renewable energy",
        "url": "https://www.acenrenewables.com/2025/08/renewable-energy-policies/",
        "date": "2025-08-13",
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "New research suggests U.S. states with clean energy policies provide benefits to their neighbors, including states without their own renewable energy policies.\n...\nWhile the U.S. federal government has clean energy targets, they are not binding.\nMost economically developed countries have mandatory policies designed to bolster renewable electricity production.\nBecause the U.S. lacks an enforceable federal mandate for renewable electricity, individual states are left to develop their own regulations.\n...\nBrown, Solomon, and Zhou examined a common clean energy policy tool: the Renewable Portfolio Standard (RPS).\nAdopted by more than half of U.S. states, RPSs are regulations requiring a state’s utility providers to generate a certain percentage of their electricity from renewable resources, such as wind or solar.\nMany of these standards are mandatory, with utility companies facing fines if they fail to reach targets within a given time.\n...\nThe team found that the amount of renewable electricity generation in a state is not only influenced by whether that state has its own RPS, but also by the RPS policies of neighboring states.\n“We also learned that the stronger a neighboring state’s RPS policy is, the more likely a given state is to generate more renewable electricity,” Brown said.\n“It’s all a very interactive web with many co-benefits.”",
        "title": "Renewable Energy Policies Provide Benefits Across State Lines",
        "url": "https://news.gatech.edu/news/2024/08/15/renewable-energy-policies-provide-benefits-across-state-lines",
        "date": "2024-08-15",
        "last_updated": "2026-03-10"
      },
      {
        "snippet": "# Regulations, Standards, and Incentivesd There are a number of laws that address renewable energy.\nSome of the major laws that primarily focus on renewable energy are listed on this page.\nHowever, there many more laws, regulations, and incentives that address renewable energy or specific types of energy sources.\nTo find proposed U.S. federal laws and statutes and U.S. state bills related to renewable energy, use the following resources.\n...\nThe official website of the current presidential administration.\nSearch or browse for initiatives, plans, and priorities related to renewable energy or clean energy.\n...\n## Renewable Energy Legislation LFederal, state, regional and international agreements, policies, and laws impact the renewable energy industries from manufacturing to distribution.\nSome government and intergovernmental decisions impact other industries by regulating the energy source or amount of energy used.\nBelow are some specific examples.\n...\n- Energy Independence and Security Act of 2007 (P.L. 110-140) (PDF, 901 KB)\nAn act to move the United States toward greater energy independence and security, to increase the production of clean renewable fuels, to protect consumers, to increase the efficiency of products, buildings, and vehicles, to promote research on and deploy greenhouse gas capture and storage options, and to improve the energy performance of the Federal Government, and for other purposes.\n- Energy Policy Act of 2005 (P.L. 109-58) (PDF, 3.2 MB)\nAn act to ensure jobs for our future with secure, affordable, and reliable energy.\nAdditionally, the U.S. Office of Energy Efficiency & Renewable Energy summarizes the requirement that the Federal Government must consume at least 7.5 percent of its total electricity from renewable sources.\n...\nAn act to provide authority for the Federal Government to purchase and insure certain types of troubled assets for the purposes of providing stability to and preventing disruption in the economy and financial system and protecting taxpayers, to amend the Internal Revenue Code of 1986 to provide incentives for energy production and conservation, to extend certain expiring provisions, to provide individual income tax relief, and for other purposes.\n...\n## Renewable Portfolio StandardsioMost states set renewable portfolio standards (RPS), which requires a certain percentage of their energy to come from renewable energy sources over a specific time frame.\nThis amount can be measured as a percentage of total energy demand or as the amount of energy produced (in MWh).\n...\n## Incentives# In addition to policies and mandates, federal, state, and local governments offer financial incentives to encourage investment in renewable energies.\nSome are compliance markets, while others are voluntary carbon markets.\n...\nFind state government and utility requirements and incentives for renewable energy.",
        "title": "Regulations, Standards, and Incentives - Renewable Energy ...",
        "url": "https://guides.loc.gov/renewable-energy/regulations",
        "date": "2026-05-12",
        "last_updated": "2026-03-08"
      },
      {
        "snippet": "Recent policy shifts at the federal level have introduced significant variability to the US renewable energy sector.\nWhile demand for clean energy continues to grow, executive orders, regulatory changes, and evolving legislative priorities are reshaping the landscape for project development and investment.\nIn this Insight based on our Earth Day webinar series we outline some of the key federal developments affecting renewables in 2025, including changes to permitting and National Environmental Policy Act (NEPA) implementation, vehicle emissions standards, the future of Inflation Reduction Act (IRA) tax incentives, and additional considerations for clean energy project developers, and highlight how legal and regulatory changes are being implemented and what to watch in the months ahead.\n### RENEWABLE INFRASTRUCTURE PERMITTINGUCThe administration’s early executive orders have sent strong signals that it intends to prioritize domestic fossil fuel production over renewable energy development.\nThe implications for project permitting are particularly acute.\n...\nThree major executive actions will reshape the permitting landscape:\n- **National Energy Emergency Declaration:** Defines “energy” to include fossil fuels but excludes solar and wind, directs agencies to invoke emergency powers under the Defense Production Act to accelerate fossil fuel projects, and provides specific instructions for expediting Clean Water Act permitting and Endangered Species Act reviews for such projects.\n- **Unleashing American Energy:** Directs agencies to revise or repeal regulations that hinder fossil fuel development, rescinds multiple Biden-era environmental orders, and instructs the Council on Environmental Quality (CEQ) to withdraw NEPA regulations and issue new permitting guidance.\n- **Offshore Wind Leasing Halt:** Suspends new offshore wind leases, raising concerns about the reliability of federal permitting for renewables.\nCollectively, these measures have introduced uncertainty and additional risk for clean energy projects across the country.\n...\nThe rescission of the CEQ’s NEPA regulations represents a particularly significant change in federal policy for the renewables sector.\nThe interim final rule removes the governmentwide framework for environmental reviews, replacing it with a directive that agencies craft their own NEPA regulations.\n...\nThe administration has stated that permitting should continue without delay, however, the absence of consistent guidance combined with pending litigation and shifting agency procedures has introduced notable uncertainty, making it more difficult for developers to predict permitting timelines or requirements.\n...\nThe current administration is now working to unwind those efforts, and a budget reconciliation bill currently making its way through the US Congress includes provisions to revise or repeal the programs discussed below.\n...\nUnder the Unleashing American Energy executive order, agencies have been instructed to revise or suspend rules that limit consumer vehicle choice.\nThe US Environmental Protection Agency (EPA) has stated its intent to revise these tailpipe standards and the 2022 nitrogen oxide rules for trucks, which also incentivized manufacturers toward EVs.\nThe previous administration’s rules technically remain in effect and litigation over them is paused, but they are providing little to no incentive for EV adoptions as their compliance deadlines remain years away and the industry anticipates that they will soon be repealed and replaced.\n...\nCorporate Average Fuel Economy (CAFE) standards, overseen by the US Department of Transportation’s National Highway Traffic Safety Administration (NHTSA), have received less public attention but also face revision.\n...\nNHTSA is now reconsidering these standards, with litigation held in abeyance pending agency action.\n...\nIn May 2025, Congress passed resolutions under the Congressional Review Act (CRA) to nullify EPA waivers granted to California for its Advanced Clean Cars II and Advanced Clean Trucks programs along with related nitrogen oxide standards.\nThese waivers issued under the Clean Air Act have long allowed California to set more stringent vehicle emissions rules.\nMore than a dozen states follow these stricter standards, collectively representing roughly half of the US auto market.\nThis action by Congress followed earlier determinations by the Senate parliamentarian and the Government Accountability Office that such waivers do not constitute “rules” under the CRA and are therefore not subject to its provisions.\nThe resolutions now await the president’s signature.\nCalifornia officials, including Governor Gavin Newsom and Attorney General Rob Bonta, have announced intentions to challenge the revocation in court, arguing that it undermines the state’s longstanding authority under the Clean Air Act to protect public health and the environment.\n...\n### INFLATION REDUCTION ACT INCOME TAX BENEFITSCOThe IRA fundamentally reshaped the US clean energy economy by introducing and expanding tax credits across the energy supply chain and for deployment and the way these credits could be monetized.\nWhile these benefits remain in place, they face political headwinds.\n...\nThe IRA enhanced or introduced federal income tax credits for renewable electricity, energy storage, clean hydrogen and other clean fuel, and carbon capture utilization and storage facilities, among other technologies.\nIt introduced credit-enhancing “adders” for meeting certain labor standards, using domestic content, “energy community” location, and investing in low-income communities.\nThe IRA also introduced the advanced manufacturing credit for US production of clean tech equipment and critical minerals.\nCritically, the IRA enacted two new ways to monetize these tax credits, transferability and direct payment.\nThese provisions opened the market to new investors and financing structures, significantly expanding participation in the clean energy economy.\n...\nWith a Republican trifecta now in place for control of the US House of Representatives, Senate, and presidency, the future of these tax benefits is unclear.\nGuidance on IRA tax provisions has largely halted.\nA regulatory freeze was imposed shortly after the new administration took office.\nAdditionally, lawmakers are pursuing a budget reconciliation bill that seeks to extend the 2017 tax cuts and enact other tax cuts, and limitation and accelerated sunset of IRA tax benefits and transferability monetization are being proposed as offsetting revenue raisers.\n...\nWhile renewable energy demand remains strong, the policy landscape in 2025 has so far been defined by legal uncertainty and administrative changes.\nExecutive orders, rescinded regulations, stalled guidance, and legislative developments are forcing developers and investors to rethink strategies, assess new risks, and act decisively to protect the viability of current and future projects.",
        "title": "Renewables Under the New Administration - Morgan Lewis",
        "url": "https://www.morganlewis.com/pubs/2025/06/renewables-under-the-new-administration-navigating-an-uncertain-roadmap",
        "date": "2025-06-06",
        "last_updated": "2026-03-22"
      },
      {
        "snippet": "Federal, state, and local governments and electric utilities encourage investing in and using renewable energy and, in some cases, require it.\nThis is an overview of the major programs and incentives available for renewable energy production and use in the United States.\nThe Database of State Incentives for Renewables & Efficiency® (DSIRE) is a comprehensive source of detailed information on government and utility requirements and incentives for renewable energy.\n...\n### Government financial incentivestiSeveral federal government tax credits, grants, and loan programs are available for qualifying renewable energy technologies and projects.\nThe federal tax incentives, or credits, for qualifying renewable energy projects and equipment include the Renewable Electricity Production Tax Credit (PTC), the Investment Tax Credit (ITC), the Residential Energy Credit, and the Modified Accelerated Cost-Recovery System (MACRS).\nGrant and loan programs may be available from several government agencies, including the U.S. Department of Agriculture, the U.S. Department of Energy (DOE), and the U.S. Department of the Interior.\nMost states also provide financial incentives to encourage renewable energy production and use.\n### Renewable portfolio standards or goalsgoA renewable portfolio standard (RPS) typically requires that a percentage of the electric power sales in a state comes from renewable energy sources.\nSome states have specific requirements, and some have voluntary goals, within a specified time frame, for the share of electricity generation or sales in a state that come from renewable energy.\nCompliance with RPS policies may require or allow utilities to trade *renewable energy certificates*.\n### Renewable energy certificates or creditsedFinancial products are available for sale, purchase, or trade that allow a purchaser to pay for renewable energy production without directly producing or purchasing the renewable energy.\nThe most widely available products are renewable energy certificates, or credits (RECs).\nThese products may also be called *green tags*, *green energy certificates*, or *tradable renewable certificates*, depending on the entity that markets them.\nElectric utilities can use RECS to comply with state renewable energy portfolio standards.\nMany companies use RECS or similar products to meet their voluntary targets or goals to reduce greenhouse gas emissions in their operations.\n### Net meteringerNet metering allows electric utility customers to install qualifying renewable energy systems on their properties and to connect them to an electric utility's distribution system (or *grid*).\nThese mainly state-based programs vary, but in general, electric utilities bill their net metering customers for the net electricity their customers use during a defined period.\n...\nAccording to the DSIRE website (as of 12/27/2022), 44 states and the District of Columbia have some form of state net metering policy.\nTwo states (Idaho and Texas) do not have statewide rules, but several utilities in those states allow net metering.\n...\n### Feed-in tariffs (FITs)FISeveral states and individual electric utilities have established special rates for purchasing electricity from certain types of renewable energy systems.\nThese rates, sometimes known as *feed-in tariffs* (FITs), are generally higher than electricity rates otherwise available to the generator.\nFITs are intended to encourage new projects for specific types of renewable energy technologies.\n### Consumer options for purchasing electricity generated with renewable energy sourcesurNearly every electricity consumer in the United States, by default, uses some electricity generated with renewable sources because of the interconnected nature of the U.S. electricity system.\nFor consumers who want to purchase electricity solely produced with renewable energy, many states have the option to choose electricity providers, and some of the participating electricity providers may sell electricity specifically generated with renewable energy.\nAvailability of these programs depends on state regulations for retail electric power markets.\nConsumers can also voluntarily purchase *green power*, even if retail electricity choice is not available.\nMost of these voluntary programs generally involve contractual *accounting* for renewable electricity generation rather the physical or contractual *delivery* of the electricity to the customer or utility.\n### Biofuels and other fuels for vehiclesicSeveral federal and state requirements and incentives are in effect for producing, selling, and using biofuels and other alternative vehicle fuels.\nFederal law requires the use of biofuels, or qualifying substitutes, in the U.S. transportation fuel supply.\nThe U.S. Environmental Protection Agency sets annual volume requirements for these fuels.\nOther federal programs provide financial support for biofuels producers.\nMany states have their own programs that support or promote biofuels.\n...\n### Renewables research and developmentveThe U.S. Department of Energy (DOE) and other federal government agencies fund research and development for renewable energy technologies.\nThe DOE's national laboratories carry out or manage most of this research and development in collaboration with academic institutions and private companies.\nThe availability of these programs depends on annual appropriations from the U.S. Congress.",
        "title": "Renewable energy explained - incentives - EIA",
        "url": "https://www.eia.gov/energyexplained/renewable-sources/incentives.php",
        "date": "2026-03-26",
        "last_updated": "2026-03-31"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

## Multi-Query Web Search

Pass up to five related queries in one request to explore different angles of a topic. Each query is processed independently:

<Info>
  A successful multi-query request is billed as one Search API request, while rate limiting counts each query in the array. For example, a request with five queries is one billing unit and consumes five rate-limit units. See [pricing](/docs/getting-started/pricing#search-api-pricing) and [Search API rate limits](/docs/admin/rate-limits-usage-tiers#search-api-rate-limits) for details.
</Info>

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  search = client.search.create(
      query=[
          "artificial intelligence trends 2024",
          "machine learning breakthroughs recent",
          "AI applications in healthcare"
      ],
      max_results=5
  )

  # Access results
  for result in search.results:
      print(f"  {result.title}: {result.url}")
  ```

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

  const client = new Perplexity();

  const search = await client.search.create({
      query: [
          "artificial intelligence trends 2024",
          "machine learning breakthroughs recent", 
          "AI applications in healthcare"
      ],
      max_results: 5
  });

  // Access results
  search.results.forEach(result => {
      console.log(`  ${result.title}: ${result.url}`);
  });
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": [
        "artificial intelligence trends 2024",
        "machine learning breakthroughs recent",
        "AI applications in healthcare"
      ],
      "max_results": 5
    }' | jq
  ```
</CodeGroup>

## Domain Filtering for Search Results

The `search_domain_filter` parameter allows you to limit search results to specific domains (allowlist) or exclude certain domains (denylist) for focused research. The filter works in two modes:

* **Allowlist mode**: Include only specified domains (no `-` prefix)
* **Denylist mode**: Exclude specified domains (use `-` prefix)

You can also append a path to restrict results to a section of a site (e.g., `"nature.com/articles"`). See the [domain filter guide](/docs/search/filters/domain-filter) for path filtering and advanced patterns.

**Note**: You can use either allowlist or denylist mode, but not both simultaneously in the same request.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  search = client.search.create(
      query="IPCC AR6 synthesis report key findings",
      search_domain_filter=[
          "science.org",
          "pnas.org",
          "cell.com"
      ],
      max_results=10
  )

  for result in search.results:
      print(f"{result.title}: {result.url}")
      print(f"Published: {result.date}")
      print("---")
  ```

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

  const client = new Perplexity();

  const search = await client.search.create({
      query: "IPCC AR6 synthesis report key findings",
      search_domain_filter: [
          "science.org",
          "pnas.org",
          "cell.com"
      ],
      max_results: 10
  });

  for (const result of search.results) {
      console.log(`${result.title}: ${result.url}`);
      console.log(`Published: ${result.date}`);
      console.log("---");
  }
  ```

  ```javascript JavaScript theme={null}
  const Perplexity = require('@perplexity-ai/perplexity_ai');

  const client = new Perplexity();

  async function main() {
      const search = await client.search.create({
          query: "IPCC AR6 synthesis report key findings",
          search_domain_filter: [
              "science.org",
              "pnas.org",
              "cell.com"
          ],
          max_results: 10
      });

      for (const result of search.results) {
          console.log(`${result.title}: ${result.url}`);
          console.log(`Published: ${result.date}`);
          console.log("---");
      }
  }

  main();
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "IPCC AR6 synthesis report key findings",
      "search_domain_filter": [
        "science.org",
        "pnas.org",
        "cell.com"
      ],
      "max_results": 10
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "75c39a4e-a46c-4850-bf27-4c061186ece6",
    "results": [
      {
        "snippet": "",
        "title": "10 Big Findings from the 2023 IPCC Report on Climate Change",
        "url": "https://www.wri.org/insights/2023-ipcc-ar6-synthesis-report-climate-change-findings",
        "date": "2023-03-20",
        "last_updated": "2026-05-15"
      },
      {
        "snippet": "",
        "title": "AR6 Synthesis Report",
        "url": "https://www.ipcc.ch/report/ar6/syr/",
        "date": null,
        "last_updated": "2026-05-21"
      },
      {
        "snippet": "",
        "title": "[PDF] Climate Change 2023 Synthesis Report",
        "url": "https://www.ipcc.ch/report/ar6/syr/downloads/report/IPCC_AR6_SYR_LongerReport.pdf",
        "date": null,
        "last_updated": "2026-05-18"
      },
      {
        "snippet": "The Synthesis Report is based on the content of the three Working Groups Assessment Reports:* WGI – The Physical Science Basis, WGII – Impacts, Adaptation and Vulnerability, WGIII – Mitigation of Climate Change*, and the three Special Reports: *Global Warming of 1.5°C*, *Climate Change and Land*, *The Ocean and Cryosphere in a Changing Climate*.\n...\nThe SYR outline agreed at the 52^nd^ Panel Session of the IPCC consists of an introduction and three main sections arranged by timeframes.\nThe first section, ‘Current Status and Trends’, covers the historical and present period.\nThe second section, ‘Long-term Climate and Development Futures’, addresses projected futures up to 2100 and beyond.\nThe final section is ‘Near-term Responses in a Changing Climate’, considers current international policy timeframes, and the time interval between now and 2030-2040.\nThis structure, substantially different to what was adopted for AR5 SYR, enables a holistic framing that integrates across the Working Groups, better enabling the SYR to cover different aspects of climate change.",
        "title": "AR6 Synthesis Report: Climate Change 2023 — IPCC",
        "url": "https://www.ipcc.ch/report/sixth-assessment-report-cycle/",
        "date": null,
        "last_updated": "2026-05-12"
      },
      {
        "snippet": "",
        "title": "[PDF] IPCC_AR6_SYR_FullVolume.pdf",
        "url": "https://www.ipcc.ch/report/ar6/syr/downloads/report/IPCC_AR6_SYR_FullVolume.pdf",
        "date": null,
        "last_updated": "2026-05-20"
      },
      {
        "snippet": "",
        "title": "Summary for Policymakers",
        "url": "https://www.ipcc.ch/report/ar6/syr/summary-for-policymakers/",
        "date": null,
        "last_updated": "2026-05-20"
      },
      {
        "snippet": "",
        "title": "SYR Longer Report - Intergovernmental Panel on Climate Change",
        "url": "https://www.ipcc.ch/report/ar6/syr/longer-report/",
        "date": null,
        "last_updated": "2026-03-21"
      },
      {
        "snippet": "",
        "title": "IPCC Secretariat",
        "url": "https://www.ipcc.ch/site/assets/uploads/2023/03/Doc5_Adopted_AR6_SYR_Longer_Report.pdf",
        "date": null,
        "last_updated": "2024-02-26"
      },
      {
        "snippet": "",
        "title": "IPCC AR6 Working Group 1: Technical Summary",
        "url": "https://www.ipcc.ch/report/ar6/wg1/chapter/technical-summary/",
        "date": null,
        "last_updated": "2026-03-18"
      },
      {
        "snippet": "",
        "title": "IPCC_AR6_SYR_SPM.pdf",
        "url": "https://www.ipcc.ch/report/ar6/syr/downloads/report/IPCC_AR6_SYR_SPM.pdf",
        "date": null,
        "last_updated": "2026-05-21"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

<Warning>
  You can add a maximum of 20 domains to the `search_domain_filter` list. The filter works in either allowlist mode (include only) or denylist mode (exclude), but not both simultaneously. See the [domain filter guide](/docs/search/filters/domain-filter) for advanced usage patterns.
</Warning>

### Denylisting Example

You can also exclude specific domains from search results:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Exclude social media sites from search results
  search = client.search.create(
      query="Système d'échange de quotas d'émission de l'Union européenne: conception du dispositif et historique du prix du carbone",
      search_domain_filter=[
          "-pinterest.com",
          "-reddit.com",
          "-quora.com"
      ],
      max_results=10
  )

  for result in search.results:
      print(f"{result.title}: {result.url}")
  ```

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

  const client = new Perplexity();

  // Exclude social media sites from search results
  const search = await client.search.create({
      query: "Système d'échange de quotas d'émission de l'Union européenne: conception du dispositif et historique du prix du carbone",
      search_domain_filter: [
          "-pinterest.com",
          "-reddit.com",
          "-quora.com"
      ],
      max_results: 10
  });

  for (const result of search.results) {
      console.log(`${result.title}: ${result.url}`);
  }
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "Système d\u0027échange de quotas d\u0027émission de l\u0027Union européenne: conception du dispositif et historique du prix du carbone",
      "search_domain_filter": [
        "-pinterest.com",
        "-reddit.com",
        "-quora.com"
      ],
      "max_results": 10
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "fbe2ad33-45df-46bf-953d-ea32cf70ef10",
    "results": [
      {
        "snippet": "",
        "title": "Système d'Echange de Quotas d'Emission",
        "url": "https://www.ecologie.gouv.fr/politiques-publiques/systeme-dechange-quotas-demission",
        "date": "2016-10-12",
        "last_updated": "2026-04-07"
      },
      {
        "snippet": "",
        "title": "Marchés du carbone - SEQE-UE",
        "url": "https://www.ecologie.gouv.fr/politiques-publiques/marches-du-carbone-seqe-ue",
        "date": "2023-10-10",
        "last_updated": "2026-05-04"
      },
      {
        "snippet": "",
        "title": "Marchés du carbone - SEQE-UE 2",
        "url": "https://www.ecologie.gouv.fr/politiques-publiques/marches-du-carbone-seqe-ue-2",
        "date": "2026-02-16",
        "last_updated": "2026-05-22"
      },
      {
        "snippet": "",
        "title": "Système d'échange de quotas d'émission de l'Union européenne — Wikipédia",
        "url": "https://fr.wikipedia.org/wiki/Syst%C3%A8me_d'%C3%A9change_de_quotas_d'%C3%A9mission_de_l'Union_europ%C3%A9enne",
        "date": "2005-12-24",
        "last_updated": "2026-05-22"
      },
      {
        "snippet": "",
        "title": "FR",
        "url": "https://www.europarl.europa.eu/RegData/docs_autres_institutions/commission_europeenne/com/2020/0740/COM_COM(2020)0740_FR.pdf",
        "date": null,
        "last_updated": "2025-09-06"
      },
      {
        "snippet": "",
        "title": "Questions et réponses – Échange de quotas d'émission – Mettre un prix",
        "url": "https://ec.europa.eu/commission/presscorner/api/files/document/print/fr/qanda_21_3542/QANDA_21_3542_FR.pdf",
        "date": null,
        "last_updated": "2025-09-23"
      },
      {
        "snippet": "",
        "title": "Commission européenne - Questions et réponses",
        "url": "https://ec.europa.eu/commission/presscorner/api/files/document/print/fr/qanda_21_3542/QANDA_21_3542_FR.pdf&rut=0b54d265a7ec0a40fb6d973db812b879e90058194a9daf2881bfe68aec33a06b",
        "date": null,
        "last_updated": "2025-06-05"
      },
      {
        "snippet": "",
        "title": "Marché du carbone : quota et bourse, droit à polluer, acteurs",
        "url": "https://www.connaissancedesenergies.org/fiche-pedagogique/marches-du-carbone",
        "date": "2011-09-14",
        "last_updated": "2026-03-04"
      },
      {
        "snippet": "###\nLe marché du carbone est un mécanisme permettant l’**échange de droits d’émission de gaz à effet de serre (GES)**.\nIl s’agit d’une des mesures incitatives prévues par le Protocole de Kyoto signé en 1997 pour encourager les États à réduire leurs émissions polluantes et opter pour de nouvelles technologies à moindre coût.\nCe dispositif doit **faciliter la réalisation des objectifs climatiques** **collectifs**.\nAu sein d'un marché du carbone, un **plafond ** d'émissions est fixé à un niveau plus bas que le niveau d'émission réel.\nDes **quotas ** sont ensuite attribués aux responsables d'émissions de GES (pays, entreprises) :\n- si le pollueur réduit ses émissions en-dessous des quotas dont il dispose, il peut **revendre son droit à émettre non utilisé** ;\n- celui qui, au contraire, a pollué au-delà de son nombre de quotas doit en acheter à d'autres exploitants (ceux qui ne les ont pas tous utilisés).\nPour plus de flexibilité, les quotas peuvent être **empruntés** ou **épargnés**.\nLe système est **incitatif ** car le coût pour réduire les émissions est inférieur au prix du quota sur le marché.\nLe prix du quota dépend du niveau du plafond, qui est fixé en fonction des objectifs à atteindre et **abaissé chaque année**, afin de privilégier les efforts de réduction d'émissions.\n###\nSi plusieurs marchés régionaux s’établissent progressivement, l'un des plus importants est le marché du carbone de l'Union européenne (UE).\nIl couvre les émissions de GES de plusieurs secteurs (énergie, industrie lourde, trafic aérien...).\nMis en place par l’UE en 2005, le **système européen d’échange de quotas d’émissions de gaz à effet de serre (SEQE-UE)** vise à inciter les investissements dans des systèmes plus performants et plus écologiques, afin d'atteindre les objectifs climatiques de l'Union.\nLe marché européen du carbone a connu plusieurs phases, au cours desquelles de nouveaux secteurs ont successivement été intégrés (ex : le secteur de l'aviation, en 2012), tandis que le plafond annuel de quotas diminue chaque année.\nEn 2008, la crise économique a provoqué une chute du prix du carbone du fait de la baisse de l'activité économique, entraînant mécaniquement un surplus de quotas.\nDevenu moins incitatif, le SEQE-UE a fait l’objet de révisions permettant de retirer les quotas excédentaires, jusqu'à l’actuelle **phase 4 (2021-2030)**.\nOutre le système européen, la **Chine**,** premier émetteur mondial de GES**, a également mis en place un marché du carbone en **2021**.",
        "title": "Qu'est-ce que le marché du carbone ou système d'échanges de ...",
        "url": "https://www.vie-publique.fr/fiches/274841-quest-ce-que-le-marche-du-carbone-ou-systeme-dechanges-de-quotas",
        "date": "2020-06-26",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "",
        "title": "Marché des quotas carbone — Wikipédia",
        "url": "https://fr.wikipedia.org/wiki/March%C3%A9_des_quotas_carbone",
        "date": "2007-08-15",
        "last_updated": "2026-03-14"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

## Language Filtering for Web Search

The `search_language_filter` parameter allows you to filter search results by language using ISO 639-1 language codes:

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Search for English, French, and German language results
  search = client.search.create(
      query="explanation of how large language models are trained: pretraining, supervised fine-tuning, and reinforcement learning from human feedback",
      search_language_filter=["en", "fr", "de"],
      max_results=10
  )

  for result in search.results:
      print(f"{result.title}: {result.url}")
  ```

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

  const client = new Perplexity();

  // Search for English, French, and German language results
  const search = await client.search.create({
      query: "explanation of how large language models are trained: pretraining, supervised fine-tuning, and reinforcement learning from human feedback",
      search_language_filter: ["en", "fr", "de"],
      max_results: 10
  });

  for (const result of search.results) {
      console.log(`${result.title}: ${result.url}`);
  }
  ```

  ```javascript JavaScript theme={null}
  const Perplexity = require('@perplexity-ai/perplexity_ai');

  const client = new Perplexity();

  async function main() {
      // Search for English, French, and German language results
      const search = await client.search.create({
          query: "explanation of how large language models are trained: pretraining, supervised fine-tuning, and reinforcement learning from human feedback",
          search_language_filter: ["en", "fr", "de"],
          max_results: 10
      });

      for (const result of search.results) {
          console.log(`${result.title}: ${result.url}`);
      }
  }

  main();
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "explanation of how large language models are trained: pretraining, supervised fine-tuning, and reinforcement learning from human feedback",
      "search_language_filter": ["en", "fr", "de"],
      "max_results": 10
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "59261fd2-1c4f-4439-88b0-24df4e941a69",
    "results": [
      {
        "snippet": "",
        "title": "Fine-tune large language models with reinforcement ...",
        "url": "https://aws.amazon.com/blogs/machine-learning/fine-tune-large-language-models-with-reinforcement-learning-from-human-or-ai-feedback/",
        "date": "2025-04-04",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "",
        "title": "LLM Training: The Process, Stages, and Fine-Tuning Gritty Details",
        "url": "https://itrexgroup.com/blog/llm-training/",
        "date": "2025-06-02",
        "last_updated": "2026-05-24"
      },
      {
        "snippet": "In situations where a model capable of performing a specific task is required, fine-tuning a large pre-trained language model becomes a more efficient approach.\nFine-tuning consumes considerably less time and computing power compared to the extensive requirements of training a model from scratch.\nUnlike starting from scratch, fine-tuning doesn’t involve training every parameter from scratch; instead, it refines the already-established parameters to suit the demands of a particular use case.\nLet’s dive in to pre-training and fine-tuning of Large Language Models.\n...\nPre-training a large language model is done in a self-supervised way, meaning it is trained with unlabeled data which is just text from the internet.\nThere is no need to assign labels on the dataset.\nWhile training, model learns to internalize the patterns and structures present in the language.\nBut internet is filled with biased, incorrect and misspelled text, therefore there needs to be a filter to remove the unnecessary data from the dataset.\nBecause these type of data would only hinder the model’s performance rather than improving it.\nLet’s call this a data quality filter.\nAfter filtering the dirty data, the training can be started.\nThere are three variances of a transformer model and each of them are trained with a different objective: encoder-only, decoder-only and encoder-decoder.\nWhichever transformer model is being trained, the first step is the same.\nThe encoder generates embedding for the tokens.\nEmbeddings are vectors that represent the token’s semantic information.\nAfter that, the training steps diverge.\nAs I said before, there are three variances of a transformer model.\nEven though objectives of these model’s trainings are different, the main intuition is similar.\nMask a word in a sentence and then try to guess the word.\nPretty simple right?\n1. **Autoencoding models:** Autoencoding models consist only of an encoder.\nAutoencoding models predict the masked word from the every preceding and following words in the sentence, therefore it is bi-directional.\nSo the model has the knowledge of the entire context.\nThat’s why autoencoding models are best for tasks like sentence classification, sentiment analysis and named entity recognition.\n2. **Autoregressive models:** Autoregressive models consist only of a decoder.\nAutoregressive models predict the masked word from the preceding words.\nThus autoregressive models are great at autocompleting a sentence, which is what happens in text generation models.\n3. **Sequence-to-sequence models:** Seq2Seq models consist of both the encoder and decoder.\nIn training random sequences of input(not just one word!) are masked, then replaced with a unique token sentinel.\nThe output is the sentinel token followed by the predicted tokens.\nIn summary, seq2seq models both need to understand the context and generate a text.\nSo they are great at tasks like summarization, language translation and question-answering.\nThese are the three variances and their training objectives.\nAs we can see there is no effort for input labeling, but the training requires a lot of text data consisting of trillion words.\nSo training a large language model takes a lot of time and computing power, for these reasons alone training a large language model should only be done if it is absolutely necessary.\n...\nFine-tuning is the training continuation of general large model to make the model capable of a specific task.\nPre-trained models are not application ready models, they are more like general purpose models, fine-tuning must be done to make the model specialized on a of specific use case.\nIf we use an analogy, a pre-trained model is like a PCP and fine-tuned model is like a cardiologist.\n...\nOkay, we understood why we need to fine-tune a model.\nBut how do we fine-tune a model?\nFine-tuning a large language model is very different from pre-training an LLM.\nFine-tuning uses supervised learning unlike pre-training.\nTherefore the features require a label.\nFor instance, if we are trying to build a model that answers history questions, a fine-tuning data would look like this:\nUnlike pre-training an LLM, fine-tuning does not need billions of data.\nIt only requires a few thousand in most cases, since the model already has the general knowledge of the language, it only needs to learn to do the specific task.\nEven though the main intuition of fine-tuning an LLM is as I have explained, there are three different ways to fine-tune an LLM:\n1. Instruction fine-tuning\n2. Parameterized efficient fine-tuning(PEFT)\n3. Reinforcement learning human feedback(RLHF)\n### 1.\nInstruction fine-tuning\nThe training dataset for fine-tuning consists of prompt-completion pairs.\nSo we create a dataset with the question or prompts and the answer we want from the LLM which is also called ground truth.\nThe model predicts an answer and the answer is compared to the ground truth to calculate some kind of loss(evaluation metrics will be explained in the next article).\nFrom the loss, the algorithm calculates the gradient of loss to weights and then updates the weights.\nSo it is a simple neural network training procedure.\nLet’s study an example to understand the process a little bit better.\nOur example is fine-tuning a model for sentiment analysis.\nThe model predicts whether the review is positive, neutral or negative.\n1. Firstly after preparing the prompt-completion pair dataset.\nWe divide the dataset to create both training and test dataset.\n2. During fine-tuning, we give prompts to LLM which then generates a completion\n3. Then we compare the result with the ground truth(in our example the LLM gave a wrong answer)\n4. Remember that the output of an LLM is a probability distribution across tokens.\nSo you can compare the distribution of the completion and that of the training label and use the standard cross-entropy function to calculate loss.\n5. And then we use the loss to update the model weights\nAs it can be seen, it is a very simple and effective process.\n...\nTo solve this issue, the model can be trained in multiple tasks.\nWe just need a dataset containing prompt-completion pairs for multiple tasks.\n...\nIn contrast to instruction fine-tuning, parameterized efficient fine-tuning only updates a small section of weights.\nSo it is less prune to catastrophic forgetting and also requires much less computing power.\nThere are three ways to do fine tuning with parameterized efficient fine-tuning:\n**a.\nSelective methods:**\nSelective methods fine-tune only a subset of the original LLM parameters.\n**b.\nReparameterization:**\nReparameterization reduces the number of parameters to train by creating low rank transformations of the original network weights.\nLoRA can be given as example.\n**c.\nAdditive:**\n- adapters: keeps all the original LLM weights frozen and add new trainable components\n- soft prompts: keep the original LLM weights frozen and focus on manipulating the input to achieve better performance\nAs it can be seen some techniques freeze most of the model weights and updates only a small section of it and some don’t even touch the original model at all and add new parameters or layers to train.\n...\nAnother great thing about PEFT is that you can train multiple layers for different tasks and these layers can be swapped during inference.\nThus achieving a multi-task model.\n...\nReinforcement learning human feedback(RLHF)\nA popular method to fine-tune a model using human feedback is called reinforcement learning human feedback.\nRLHF utilizes reinforcement learning which is one of the three techniques of machine learning alongside supervised and unsupervised learning.\nRL is a problem-solving method based on the assumption that an agent must learn the best behavior to achieve a task via trial-and-error interactions with a dynamic and unpredictable environment.\n...\nNow that we understood the main idea of reinforcement learning, we can not look into reinforcement learning human feedback in large language models.\nWith RLHF, the agent is the LLM model.\nThe action that the model will take, meaning which token it will choose next, depends on the prompt text in the context and the probability distribution over the vocabulary space.\nThe reward is assigned based on how closely the completions align with human preferences.\nThe LLM weights are then updated iteratively to maximize the reward obtained from the human classifier, enabling the model to generate non-toxic completions.\nYou can use two techniques to calculate reward:\n- human expert\n- additional model called reward model to classify outputs of the LLM\n## Conclusion\nIn conclusion, the integration of Large Language Models (LLMs) into applications involves critical decisions, particularly regarding whether to use existing pre-trained models or to embark on the resource-intensive process of training a model from scratch.\nPre-training lays the foundation for LLMs, involving self-supervised learning on vast amounts of unlabeled data.\nThe three variants of transformer models — autoencoding, autoregressive, and sequence-to-sequence — serve distinct purposes and are trained with different objectives.\nHowever, fine-tuning becomes crucial to tailor these general-purpose models to specific tasks.\nUnlike pre-training, fine-tuning utilizes supervised learning with labeled data, and various approaches, such as instruction fine-tuning, parameterized efficient fine-tuning (PEFT), and reinforcement learning with human feedback (RLHF), offer different strategies for this process.\nThe choice between pre-training and fine-tuning depends on the specific application requirements, considering factors such as computational resources, task complexity, and the need for domain-specific expertise.",
        "title": "Everything to learn about Large Language Models(Part 2/3 ...",
        "url": "https://medium.com/@aydinKerem/everything-to-learn-about-large-language-models-part-2-3-pre-training-and-fine-tuning-5fc68700701a",
        "date": "2023-12-02",
        "last_updated": "2026-05-19"
      },
      {
        "snippet": "",
        "title": "Illustrating Reinforcement Learning from Human Feedback (RLHF)",
        "url": "https://huggingface.co/blog/rlhf",
        "date": "2022-12-09",
        "last_updated": "2026-05-22"
      },
      {
        "snippet": "",
        "title": "How Developers Steer Language Model Outputs: Large ... - CSET",
        "url": "https://cset.georgetown.edu/article/how-developers-steer-language-model-outputs-large-language-models-explained-part-2/",
        "date": "2024-03-08",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "",
        "title": "How Large Language Models (LLMs) are Trained ? | Pre-Training | Supervised Fine Tuning (SFT) | RLHF",
        "url": "https://www.youtube.com/watch?v=vEqaew-D28U",
        "date": "2026-04-25",
        "last_updated": "2026-05-26"
      },
      {
        "snippet": "",
        "title": "What Are Large Language Models (LLMs)?",
        "url": "https://www.ibm.com/think/topics/large-language-models",
        "date": "2021-10-06",
        "last_updated": "2026-03-31"
      },
      {
        "snippet": "",
        "title": "LLM Training Explained Pretraining SFT RLHF BERT Fine Tuning Part 2",
        "url": "https://www.youtube.com/watch?v=kbwO5o2Fk0I",
        "date": "2026-03-27",
        "last_updated": "2026-05-07"
      },
      {
        "snippet": "",
        "title": "Reinforcement learning from human feedback - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Reinforcement_learning_from_human_feedback",
        "date": "2023-03-04",
        "last_updated": "2026-04-13"
      },
      {
        "snippet": "# Supervised Fine-Tuning\nFor supervised fine-tuning (SFT) — as well as for any of the following alignment methods — the model is pretrained for next token prediction on a massive, unlabeled dataset.\nThis alone is not enough to ensure helpful responses.\nAfter pretraining, SFT uses a dataset of prompt-response pairs.\nThe responses are **written by human labelers** and should represent the alignment values (honesty, helpfulness, etc.) to act as the ground truth for supervised learning.\nWith only a few thousand examples, the dataset for SFT is is much smaller than the massive amounts of unlabeled text data used during pretraining.\nFor example, for the SFT stage of InstructGPT, only 11,295 data points were used.\nDespite this, the responses generated by the fine-tuned model consistently outperform the ones of the pretrained model in human preference ratings.\nIn supervised fine-tuning the model learns to imitate responses preferred by humans.\nHowever, the quality of results heavily depends on the quality of human-written responses.\nAn idea to improve generalization, one approach is to train a reward model that quantifies how much a given response aligns with human preferences.\n...\nReinforcement learning (RL) is a powerful technique to go beyond simple imitation by encouraging exploration during the training process.\nA core component of RL is the **reward function**, which guides learning by assigning a score to outputs.\nHowever in the context of large language models, it is not trivial to define a reward function that accurately represents human values.\nIn reinforcement learning from human feedback (RLHF), the reward function is approximated by training a **reward model **(RM)** **on human-labeled data.\nFirst, a dataset is created by generating multiple responses to a given prompt and having a human rank their overall quality against each other.\nEach datapoint consists of a prompt and a set of responses ordered by human preference.\nThe RM is then trained supervised on pairs of responses: prompt + response_i + response_j for all i≠j using a cross-entropy loss.\nSecond, the LLM is fine-tuned via reinforcement learning.\nThe scalar output of the RM (the reward) represents how well the model’s output aligns with human preferences, based on the rankings collected in step one.\nUsually **proximal policy optimization** (PPO) is the algorithm used for RL applications due to its simplicity and stability.\n...\nRLHF is used to fine-tune language models **after a supervised fine-tuning (SFT) stage** as described in the previous section.\nIt further outperforms the pretrained model, as well as the SFT-only model on human preference ratings significantly.\n...\nThe idea of Direct Preference Optimization (DPO) is to eliminate the need to train a reward model for reinforcement learning by directly incorporating preference information in the loss function.\nThe gathering of preference data works the same as for RLHF with one minor difference: for each prompt, exactly two responses are generated and ranked in DPO, while in RLHF the number of responses can vary.\n...\nWith this understanding of log-likelihoods, it becomes clear how DPO eliminates the need for a separate reward model.\nFor each datapoint — consisting of a prompt, the human-preferred response and the human-rejected response — both log-likelihoods are calculated.\nDPO then “pushes” the LLM towards the better response by applying a binary cross-entropy loss:\nIn addition to the log-likelihoods of the LLM being fine-tuned, the loss function makes use of the log-likelihoods of a reference model.\nThe reference model is the original LLM used to generate the dataset (LLM_theta_0).\nIncluding the reference model helps ensure that the fine-tuned responses don’t drift too far from the original model’s behavior, maintaining helpfulness.\nDuring fine-tuning the LLM does not generate any more outputs.\nInstead, the training relies on the log-likelihoods of already existing responses.\n...\nBoth RLHF and DPO rely on human-generated rankings of LLM outputs to either train a reward model or to optimize likelihood-based objectives.\n...\nReinforcement learning from AI-feedback (RLAIF) addresses this issue by replacing human labelers with a **feedback model**.\nThis enables more efficient creation of preference data.\nThe Constitutional AI approach by **Anthropic** uses RLAIF to fine-tune the large language models.\nInstead of relying on human labelers, it uses a pretrained LLM — specifically Claude — as the feedback model to collect the rankings.\nAfter generating two responses, A and B, for a given prompt, Claude is prompted to compare the two and select the one that aligns better with a set of principles.\n...\nThe resulting preference is then used as training data for a reward model.\nApart from how the preference data is gathered, the fine-tuning pipeline of RLAIF is identical to that of reinforcement learning from human feedback (RLHF), as described above.\n...\nA more **explicit** approach of aligning an LLM is to define a set of rules and principles the LLM should represent and have it learn to follow those rules.\n...\nInstead of showing an LLM thousands of human-preferred responses to guide it towards generating high-quality outputs, a different approach is to have the LLM self-critique and revise the generated responses according to a set of rules and principles — the “constitution”.\nA practical approach of constitution-based alignment is Constitutional AI by Anthropic.\nHere, a supervised fine-tuned LLM (see above: SFT) is used to generate additional high-quality responses, which are then used to improve the model through further supervised learning.\nFor a given prompt, the LLM generates a response.\nThe response is then combined with the constitution to form a **critique request**.\nA typical critique request looks like this:\n\u0060\u0060\u0060\nCritique Request: Identify specific ways in which the assistant’slast response is harmful, unethical, racist, sexist, toxic,dangerous, or illegal.\n...\nThe original response and the critique request are fed back into the LLM to generate a critique.\nThe critique is then combined with the original output and a **revision request** to produce a revised version of the original output that is better aligned with the rules in the constitution.\n...\nThis step of self-critique and revision can be repeated multiple times before the final revision is used as the ground truth for further supervised fine-tuning.\nAfter incorporating the rules and values of the constitution into the LLM through repeated self-critique and revision, the next step is to further refine the model using Reinforcement Learning from AI-Feedback (RLAIF).\n...\n# Summary\nIn this article, we explored the core ideas of **training-based** strategies for aligning large language models.\nWe began with **supervised fine-tuning **(SFT), where human-written responses are used as the ground truth to guide the model’s behavior.\nThen we looked at **reinforcement learning from human feedback** (RLHF), which involves training a **reward model** on human preference rankings of responses to use in reinforcement learning.\nBuilding on RLHF, we discussed three evolutions of the approach:\n- **Direct preference optimization** (DPO) removes the need for a reward model by using a cleverly designed loss function with the help of log-likelihoods.\n- **Reinforcement learning from AI-feedback** (RLAIF) removes the need for human ranking of responses by using a pretrained, off-the-shelf LLM — such as Claude — to create the rankings.\n- Last, we talked about **constitution-based alignment**, specifically Constitutional AI.\nInstead of **implicitly** showing the LLM human-preferred outputs, a **constitution** of **explicit** rules and principles is defined.\nThe LLM then learns to follow the constitution by repeated self-critique and revisions.",
        "title": "Alignment of Large Language Models Through Training: SFT, RLHF, DPO and More",
        "url": "https://medium.com/@leander.heine/alignment-of-large-language-models-through-training-sft-rlhf-dpo-and-more-472e2e0d9695",
        "date": "2025-07-01",
        "last_updated": "2025-07-29"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

<Warning>
  Language codes must be valid 2-letter ISO 639-1 codes (e.g., "en", "ru", "fr"). You can add a maximum of 10 language codes per request. See the [language filter guide](/docs/search/filters/language-filter) for the complete list of supported codes.
</Warning>

## Budget Control

To choose how much content is extracted from result pages, use the `search_context_size` parameter. The following values are supported:

* `low` — short passages most relevant to the query.
* `medium` — a balanced amount of content per document.
* `high` (default) — detailed content relevant to the query.

Use `search_context_size: "low"` for lightweight previews or to minimize downstream token usage.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  search = client.search.create(
      query="AI news headlines",
      max_results=10,
      search_context_size="low"
  )

  for result in search.results:
      print(f"{result.title}: {result.snippet[:100]}...")
  ```

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

  const client = new Perplexity();

  const search = await client.search.create({
      query: "AI news headlines",
      max_results: 3,
      search_context_size: "low"
  });

  for (const result of search.results) {
      console.log(`${result.title}: ${result.snippet.substring(0, 100)}...`);
  }
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "AI news headlines",
      "max_results": 3,
      "search_context_size": "low"
    }' | jq
  ```
</CodeGroup>

### Manual Token Budgets

Use `max_tokens` and `max_tokens_per_page` when you need manual control over exact content limits for response size, total tokens returned, evaluations, or downstream context-window and cost management.

* `max_tokens` caps the total webpage content returned across all results. Allows up to 1,000,000 tokens.
* `max_tokens_per_page` caps content extracted from each result page.

Higher values return more extracted content; lower values keep the returned content shorter for tighter response-size, downstream context-window, or token-cost budgets.

`search_context_size` and explicit budgets interact as follows:

* If neither `search_context_size` nor budgets are specified, the default `search_context_size` is applied.
* If both `max_tokens` and `max_tokens_per_page` are specified without `search_context_size`, those budgets are used.
* If only one of `max_tokens` or `max_tokens_per_page` is specified without `search_context_size`, the other falls back to the value from the default `search_context_size`.
* `search_context_size` cannot be combined with `max_tokens` or `max_tokens_per_page` in the same request.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  # Higher token budget = more content in snippets
  detailed_search = client.search.create(
      query="renewable energy technologies",
      max_results=10,
      max_tokens=50000,  # Total content budget across all results
      max_tokens_per_page=4096  # Per-result limit
  )

  # Lower token budget = shorter snippets
  brief_search = client.search.create(
      query="S&P 500 historical closing levels and US equity index performance",
      max_results=5,
      max_tokens=5000
  )

  for result in detailed_search.results:
      print(f"{result.title}: {len(result.snippet)} chars")
  ```

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

  const client = new Perplexity();

  // Higher token budget = more content in snippets
  const detailedSearch = await client.search.create({
      query: "renewable energy technologies",
      max_results: 10,
      max_tokens: 50000,  // Total content budget across all results
      max_tokens_per_page: 4096  // Per-result limit
  });

  // Lower token budget = shorter snippets
  const briefSearch = await client.search.create({
      query: "S&P 500 historical closing levels and US equity index performance",
      max_results: 5,
      max_tokens: 5000
  });

  for (const result of detailedSearch.results) {
      console.log(`${result.title}: ${result.snippet.length} chars`);
  }
  ```

  ```bash cURL theme={null}
  # Higher token budget for detailed content
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "renewable energy technologies",
      "max_results": 10,
      "max_tokens": 50000,
      "max_tokens_per_page": 4096
    }' | jq

  # Lower token budget for brief snippets
  curl -X POST 'https://api.perplexity.ai/search' \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
      "query": "S&P 500 historical closing levels and US equity index performance",
      "max_results": 5,
      "max_tokens": 5000
    }' | jq
  ```
</CodeGroup>

<AccordionGroup>
  <Accordion title="Response — renewable energy technologies">
    ```json theme={null}
    {
      "id": "58a969d2-452f-4950-97df-7cd74977d479",
      "results": [
        {
          "snippet": "EPA evaluated the following renewable energy technologies for this analysis.\nThey represent the most common types of renewable energy facilities being used as of 2021.\nThis is not an inclusive list of all renewable energy technologies; new technologies continue to be developed, while established technologies are refined.\n...\nSolar resource at a given location is typically characterized by the amount of solar energy striking a panel tilted up from the horizontal at an angle equal to the local latitude over a given area and reported as a daily average.\nSolar radiation is measured in kilowatt-hours per square meter per day (kWh/m2/day).\nPV cells convert the sun’s light energy directly into electricity.\nPV technology is scalable; the amount of electricity generated is directly related to the number and efficiency of installed panels.\nIt can technically be sited anywhere, though the economics may make a project unfeasible in lower resource areas.\n...\nWind energy is captured by wind turbines with propeller-like blades mounted on a tower.\nThe force of the wind causes the rotor to spin, and the turning shaft spins a turbine to generate electricity.\nWind technology is scalable; based on site conditions, different turbines designs can be used to meet different electricity needs.\n...\nBiomass energy, or “bioenergy,” is generated from organic feedstocks.\nWood is the most abundant and commonly used biomass energy resource; other sources of biomass include food crops, grassy and woody plants, residues from agriculture or forestry and the organic component of municipal and industrial wastes.\nThese feedstocks can be used as a solid fuel, or converted into liquid or gaseous forms, for the production of electric power, heat, chemicals or fuels.\nA biopower facility burns biomass resources to produce heat, which is used to boil water for a conventional steam-turbine generator to produce electricity.\nBiopower facilities use cumulative biomass resources that can include residues from forests, primary and secondary mills and urban wood waste.\nA biorefinery facility integrates biomass conversion processes and equipment to produce fuels, power and chemicals from biomass.\nThe technology uses cumulative crop residues that can include residues from crops or forests, primary and secondary mills and urban wood waste.\n...\nEnergy can also be generated by capturing methane and other emissions from landfills.\nSee EPA’s Landfill Methane Outreach Program for more information about landfill gas energy technologies.\n## Geothermal\nGeothermal resource is typically characterized by temperature at a given depth, availability of water resources and permeability of geologic layers.\nA geothermal heat pump (GHP) system exchanges heat in the shallow subsurface.\nIn most locations without permafrost, the upper 10 feet of the Earth maintains a nearly constant temperature between 50° and 60°F (10°–16°C).\nGHPs take advantage of this resource to heat and cool buildings and heat water.\nGHPs consist of three parts: the ground loop heat exchanger, the heat pump unit and the air delivery system (ductwork).\nThe ground loop heat exchanger is a system of pipes buried in the shallow ground near the building, or in a vertical well if land for a horizontal loop is limited.\nWater source heat pumps work on the same principle as ground source systems, but they use an adjacent body of water as the heat sink.\nA fluid (usually water or a mixture of water and antifreeze) circulates through the loop to absorb or reject heat from the ground.\nGHPs use much less energy than conventional heating systems since they draw heat from the ground, avoiding the high and low swings of ambient air temperatures.\nGHPs typically serve a single property, though they may also be viable for use in multi-tenant applications, such as integrated district heating systems.",
          "title": "Appendix B: Renewable Energy Technology Basics",
          "url": "https://www.epa.gov/re-powering/appendix-b-renewable-energy-technology-basics",
          "date": "2025-07-24",
          "last_updated": "2025-10-16"
        },
        {
          "snippet": "Renewable energy is energy derived from natural sources that are replenished at a higher rate than they are consumed.\nSunlight and wind, for example, are such sources that are constantly being replenished.\nRenewable energy sources are plentiful and all around us.\n...\n## Here are a few common sources of renewable energy:\n...\nSolar energy is the most abundant of all energy resources and can even be harnessed in cloudy weather.\nThe rate at which solar energy is intercepted by the Earth is about 10,000 times greater than the rate at which humankind consumes energy.\nSolar technologies can deliver heat, cooling, natural lighting, electricity, and fuels for a host of applications.\nSolar technologies convert sunlight into electrical energy either through photovoltaic panels or through mirrors that concentrate solar radiation.\n...\nWind energy harnesses the kinetic energy of moving air by using large wind turbines located on land (onshore) or in sea- or freshwater (offshore).\nWind energy has been used for millennia, but onshore and offshore wind energy technologies have evolved over the last few years to maximize the electricity produced - with taller turbines and larger rotor diameters.\n...\nGeothermal energy utilizes the accessible thermal energy from the Earth’s interior.\nHeat is extracted from geothermal reservoirs using wells or other means.\nReservoirs that are naturally sufficiently hot and permeable are called hydrothermal reservoirs, whereas reservoirs that are sufficiently hot but that are improved with hydraulic stimulation are called enhanced geothermal systems.\nOnce at the surface, fluids of various temperatures can be used to generate electricity.\nThe technology for electricity generation from hydrothermal reservoirs is mature and reliable, and has been operating for more than 100 years.\n...\nHydropower harnesses the energy of water moving from higher to lower elevations.\nIt can be generated from reservoirs and rivers.\nReservoir hydropower plants rely on stored water in a reservoir, while run-of-river hydropower plants harness energy from the available flow of the river.\nHydropower reservoirs often have multiple uses - providing drinking water, water for irrigation, flood and drought control, navigation services, as well as energy supply.\nHydropower currently is the largest source of renewable energy in the electricity sector.\n...\nOcean energy derives from technologies that use the kinetic and thermal energy of seawater - waves or currents for instance -  to produce electricity or heat.\nOcean energy systems are still at an early stage of development, with a number of prototype wave and tidal current devices being explored.\nThe theoretical potential for ocean energy easily exceeds present human energy requirements.\n...\nBioenergy is produced from a variety of organic materials, called biomass, such as wood, charcoal, dung and other manures for heat and power production, and agricultural crops for liquid biofuels.\nMost biomass is used in rural areas for cooking, lighting and space heating, generally by poorer populations in developing countries.\nModern biomass systems include dedicated crops or trees, residues from agriculture and forestry, and various organic waste streams.\nEnergy created by burning biomass creates greenhouse gas emissions, but at lower levels than burning fossil fuels like coal, oil or gas.",
          "title": "What is renewable energy? | United Nations",
          "url": "https://www.un.org/en/climatechange/what-is-renewable-energy",
          "date": null,
          "last_updated": "2026-04-30"
        },
        {
          "snippet": "Renewable energy sources are playing an increasingly pivotal role in the global shift towards sustainability management and green energy systems.\nBy harnessing inexhaustible resources such as sunlight, wind, and water, renewable technologies are not only enhancing energy efficiency but also driving significant environmental and economic benefits.\nAdvances in solar photovoltaics, wind turbines, and bioenergy are leading to higher energy conversion efficiencies and reduced greenhouse gas emissions.\n...\nRenewable energy sources have a profound impact on energy efficiency and sustainability, reshaping the global energy landscape.\nBy leveraging inexhaustible resources such as sunlight, wind, and water, renewable energy technologies significantly enhance energy efficiency.\nFor instance, solar photovoltaic (PV) systems and wind turbines generate electricity closer to the point of consumption, reducing transmission and distribution losses that plague conventional power systems.\nAdvances in these technologies have led to higher energy conversion efficiencies, with modern solar panels achieving efficiencies of over 22%, up from about 15% a decade ago.\n...\nRenewable sources produce little to no greenhouse gas emissions during operation, which is critical for mitigating climate change.\nReplacing fossil fuel-based power plants with wind, solar, and other renewables can drastically cut carbon dioxide emissions, fostering a cleaner environment.\nMoreover, renewables rely on natural processes that are naturally replenishing, ensuring a sustainable energy supply.\n...\nBelow are some innovations and breakthroughs in three different renewable energy sources – wind, ocean, and bioenergy.\n...\nOne innovation in wind energy has been the development of floating offshore wind turbines.\nThese turbines are anchored to the seabed using cables and can be placed in deeper waters where traditional turbines are not a feasible option.\nFloating offshore wind turbines increase energy production efficiency since stronger and more consistent winds can be found further offshore.\n...\nMoving on from floating offshore wind turbines, we have also witnessed more advanced blade designs for wind turbines.\n...\nOceans are the world’s largest untapped source of renewable energy and it is believed that by 2050, ocean energy can offer 10 percent of Europe’s current electricity demand.\nAn impressive innovation in ocean energy has been the creation of tidal stream generators.\nThese underwater turbines harness the kinetic energy of tidal currents.\nThey offer a reliable and predictable source of renewable energy due to the regularity of tidal cycles.\nThe MeyGen Project in Scotland, one of the biggest tidal energy installations in the world, is demonstrating the potential of tidal stream technology at a commercial scale.\nWave energy is another type of ocean energy that captures the movement of ocean and sea waves and uses it to create electricity.\nA useful innovation we have witnessed in the area of wave energy has been wave energy converters.\nDevices like oscillating water columns and point absorbers transform the energy from surface waves into electricity.\nThese technologies are advancing with more efficient conversion mechanisms and energy capture, increasing energy yield and reducing costs.\n...\nBioenergy is a type of renewable energy created when we burn biomass fuel.\nBiomass fuels come from organic materials like purpose-grown crops, organic waste, and harvest residues.\nAn innovation in bioenergy has been the creation of advanced biofuels.\nSecond and third-generation biofuels are created from non-food biomass and algae, respectively.\nThese biofuels provide higher energy yields and lower greenhouse gas emissions compared to first-generation biofuels made from food crops.\nAnother innovation has been biogas upgrading technologies.\nNew processes like membrane separation and pressure swing adsorption enhance the purity and efficiency of biogas upgrading.\nThese technologies enhance the quality of biogas, making it suitable for injection into natural gas grids and use as vehicle fuel.\n...\nThe development and deployment of advanced energy storage systems, such as lithium-ion batteries, solid-state batteries, and flow batteries.\nEnhanced energy storage capabilities will address the intermittent nature of renewable sources like solar and wind, ensuring a stable and reliable energy supply.\n...\nIncreased focus on producing hydrogen using renewable energy, known as green hydrogen.\n...\nThe transformation towards renewable energy is reshaping the global energy landscape, offering substantial gains in energy efficiency and sustainability.\nInnovations such as floating offshore wind turbines, tidal stream generators, and advanced biofuels are setting new benchmarks for energy production and environmental stewardship.\nAs we look to the future, advancements in energy storage, green hydrogen production, AI integration, and floating solar farms are expected to drive further progress.\nEmbracing these technologies not only ensures a cleaner environment but also bolsters energy security and stimulates economic growth.",
          "title": "Renewable energy sources: Future innovations and breakthroughs",
          "url": "https://instituteofsustainabilitystudies.com/insights/lexicon/the-future-of-renewable-energy-innovations-and-breakthroughs/",
          "date": "2024-06-26",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "",
          "title": "Renewable energy - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/Renewable_energy",
          "date": "2001-07-31",
          "last_updated": "2026-05-18"
        },
        {
          "snippet": "",
          "title": "Chapter 7 - Renewable Energy Technologies",
          "url": "https://www.undp.org/sites/g/files/zskgke326/files/publications/chapter7.pdf",
          "date": null,
          "last_updated": "2025-04-13"
        },
        {
          "snippet": "",
          "title": "Overview on Renewable Energy Technology",
          "url": "https://www.osce.org/files/f/documents/2/b/41338.pdf",
          "date": null,
          "last_updated": "2024-10-30"
        },
        {
          "snippet": "Renewable energy is derived from resources that are replenished naturally on a human timescale.\nSuch resources include biomass, geothermal heat, sunlight, water, and wind.\nAll of these sources have their strengths and weaknesses.\nSome are more suited to certain locations than others, for instance.\nSome only produce electricity intermittently (when the sun is shining in the case of solar), though they can be paired with energy storage solutions to provide reliable electricity 24 hours a day throughout the year.\nOthers, such as biomass, hydropower, and geothermal, can be used as baseload generation, producing a constant, predictable supply of electricity.\nNone of these sources can meet all of our electricity needs effectively.\nBut, together, they can completely displace fossil fuels without increasing the cost of electricity.\nBelow you will find a quick overview of the different renewable energy technologies, with links to more in-depth information.\nImplementing all of these renewable energy technologies, in addition to energy efficiency measures, not only leads to fewer greenhouse gases and other air and water pollutants, but also leads to overall cost savings and enhanced energy security.\n### Bioenergy (biofuels and biomass)\nBiomass (plant or animal material) can be used to produce electricity, thermal energy, or transportation fuels.\nEvery region has its own locally generated biomass feedstocks from agriculture, forest, and urban sources.\n### Hydrogen Fuel Cells\nHydrogen fuel cells are a clean, reliable, quiet, and efficient source of high-quality electric power.\nThey use hydrogen as a fuel to drive an electrochemical process that produces electricity, with water and heat as the only by-products.\n### Hydropower and Other Water Technologies\nWater technologies can be used for electricity or thermal energy all across the country.\nAlthough there are few, if any, appropriate sites left to build large dams in the United States, there are many opportunities to expand energy production at dams without turbines and by using newer technologies in both rivers and oceans.\n### Wind\nWind energy can be used to generate electricity for utilities or individual buildings.\nThe best U.S. resources for utility-scale wind farms are in the Midwest, Texas and the West, as well as on offshore sites in the Great Lakes and off the Atlantic Coast.\n### Geothermal\nGeothermal energy, or the heat below the earth's surface, can be used for electricity or thermal energy.\nGeothermal heat pumps, which heat and cool buildings, are effective in all regions.\nGeothermal power plants, however, require more active geothermal sources that, in the United States, are primarily located in the West.\n### Solar\nSolar energy systems use the sun's rays for electricity or thermal energy.\nIn the United States, utility-scale solar power plants are located primarily in the Southwest.\nHowever, smaller scale rooftop photovoltaic cells and hot water systems are effective in all regions.",
          "title": "Geothermal",
          "url": "https://www.eesi.org/topics/renewable-energy/description",
          "date": null,
          "last_updated": "2026-04-16"
        },
        {
          "snippet": "Renewable energy is energy that comes from a source that won’t run out.\nThey are natural and self-replenishing, and usually have a low- or zero-carbon footprint.\nExamples of renewable energy sources include wind power, solar power, bioenergy (organic matter burned as a fuel) and hydroelectric, including tidal energy.\n...\nThere are four main sources of renewable energy used in the UK and US:\n...\nWind power is the largest producer of renewable electricity in both the UK and the US.\n**Onshore and offshore wind farms** generate electricity by spinning the blades of **wind turbines**.\nThe turbines convert the kinetic energy of the spinning blades into electric energy by turning a drive shaft and gear box, which is connected to a generator.\nElectricity is then converted into higher voltages and fed into the national grid.\n...\nSunlight is one of the planet’s most freely available energy resources, which you’d assume would make it the number one source of renewable energy.\n...\n**Solar power** generates electricity by capturing sunlight on solar panels in a joint chemical and physical reaction, known as the ‘photovoltaic effect’ (or PV).\n### Hydroelectric\nHydro power is created using the movement of flowing or falling water.** ** Hydroelectric power plants are found at dams and generate electricity through underwater turbines that turn a generator.\nHydro power also encompasses wave and tidal power, which rely on ocean forces to generate electricity at the mouths of large bodies of water, using similar technology.\n### Bioenergy\nElectricity can be generated when **organic matter is burned as a fuel source**.\nThese fuels are known as biomass and include anything from plants to timber to food waste.\nCarbon dioxide (CO~2~) is emitted when bioenergy is made, but these fuel sources are considered renewable because they can be regrown and absorb as much carbon as they emit across their lifespans.",
          "title": "What are the different types of renewable energy? - National Grid",
          "url": "https://www.nationalgrid.com/stories/energy-explained/what-are-different-types-renewable-energy",
          "date": null,
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "# Description of renewable energy technologies\n#### Solar photovoltaic\nPhotovoltaic (PV) solar panels convert sunlight directly into electricity.\nThe panels are made up of a number of solar cells that contain the photovoltaic materials.\nThese systems have no moving parts, which distinguishes them from other renewable technologies.\nInstead, the photons from sunlight are captured within the solar cells, which excite electrons to generate an electric current.\nThe lower costs, compactness, and low maintenance make solar PV systems one of the most widely dispersed renewable energy technologies.\n#### CSP parabolic trough\nParabolic trough systems consist of many parabola-shaped mirrors that direct heat from sunlight toward tubes full of flowing fluid or steam.\nThis fluid reaches an industrial steam generator to produce electricity.\nWith storage capacity for the heated substance, this technology has the potential to produce electricity when the sun goes down.\n#### CSP parabolic dish\nParabolic dish systems are mirrored dishes that look similar to a satellite dish.\nThey reflect the sunlight to central points in front of each dish, where the heat is transferred to a liquid or gas.\nThe heated fluid or gas then powers a generator to create electricity.\nSterling engine designs used to generate electricity beneficial due to their size and the fact that they use no water.\nEach parabolic dish’s generating capacity ranges from 10 kW to 25 kW.\n#### CSP power tower\nPower towers consist of a multitude of moving mirrors surrounding a large tower.\nThe mirrors focus the solar heat toward a center point at the top of the tower where either molten salt or water is heated and cycled down to a generator to produce electricity.\nMolten salt can be stored, allowing for the production of electricity after the sun goes down.\n#### Wind turbines\nWind turbines use the kinetic energy from the wind to generate electricity.\nThere are variations in size and design but they function similarly.\nThe wind causes the blades and rotor to spin, which drives gears that powers a generator within the turbine and generates electricity.\nThe most widely used turbines have a horizontal axis and can be up to 500 feet high.\n#### Geothermal\nGeothermal electricity production taps into the natural heat generated in the earth’s crust.\nThere are a number of designs to utilize the heat in order to produce steam.\nThis steam is then captured at geothermal power plants to power thermal generators and produce electricity.\n#### Biogas power plants\nBiogas electricity generation is electricity generated from gases produced by organic material.\nGas is produced from organic matter, agricultural waste, aquatic plants, vegetative waste, and wood waste or animal and human waste through anaerobic digestion, oxidization, or gasification.\nThe resulting gas, similar to natural gas, is burned to produce steam and power a generator to create electricity.\n#### Hydroelectric\nHydroelectric generation captures energy from the flow of water.\nWater is stored behind a dam in a reservoir, then passes through an enclosed area where it turns a turbine that generates electricity.\nHydroelectricity has been utilized for many years.\n#### Biomass electricity\nBiomass electricity generation produces electricity by burning any raw or processed organic plant matter.\nThis technology essentially uses the same process as a coal or natural gas plant but instead burns biomass.\nIt is considered renewable if the biomass source continues to grow back.",
          "title": "Description of Renewable Energy Technologies | Clean Energy Research and Education",
          "url": "https://in.nau.edu/clean-energy-research/renewable-energy-technologies/",
          "date": null,
          "last_updated": "2025-07-26"
        },
        {
          "snippet": "",
          "title": "renewable energy technology: Topics by Science.gov",
          "url": "https://www.science.gov/topicpages/r/renewable+energy+technology",
          "date": null,
          "last_updated": "2026-05-16"
        }
      ],
      "server_time": null
    }
    ```
  </Accordion>

  <Accordion title="Response — S&P 500 historical closing levels and US equity index performance">
    ```json theme={null}
    {
      "id": "0d468d29-d3dc-4f60-85e9-a1bbd1530a58",
      "results": [
        {
          "snippet": "Observations\n2026-05-22: 7,473.47 |\nIndex, Not Seasonally Adjusted |\nDaily,\nClose\nUpdated: May 22, 2026 7:01 PM CDT\n...\n|2026-05-22:|7,473.47|\n|--|--|\n|2026-05-21:|7,445.72|\n|2026-05-20:|7,432.97|\n|2026-05-19:|7,353.61|\n|2026-05-18:|7,403.05|",
          "title": "S&P 500 (SP500) | FRED | St. Louis Fed",
          "url": "https://fred.stlouisfed.org/series/SP500",
          "date": "2026-05-22",
          "last_updated": "2026-05-23"
        },
        {
          "snippet": "|6,471.54|6,444.73|6,471.73|6,440.98|+0.08%|\n|--|--|--|--|--|\n|6,466.58|6,462.67|6,480.28|6,445.02|+0.32%|\n|6,445.76|6,395.17|6,446.55|6,385.76|+1.13%|\n|6,373.45|6,389.67|6,407.25|6,364.06|-0.25%|\n|6,389.45|6,355.22|6,395.16|6,355.22|+0.78%|\n|6,340.00|6,374.32|6,389.71|6,310.32|-0.08%|\n|6,345.06|6,309.30|6,352.83|6,301.11|+0.73%|\n|6,299.19|6,336.63|6,346.00|6,289.37|-0.49%|\n|6,329.94|6,271.71|6,330.69|6,271.71|+1.47%|\n|6,238.01|6,287.28|6,287.28|6,212.69|-1.60%|\n|6,339.39|6,427.02|6,427.02|6,327.64|-0.37%|\n|6,362.90|6,381.23|6,396.54|6,336.38|-0.12%|\n|6,370.86|6,405.62|6,409.26|6,363.92|-0.30%|\n|6,389.77|6,397.69|6,401.07|6,375.79|+0.02%|\n|6,388.64|6,370.01|6,395.82|6,368.53|+0.40%|\n|6,363.35|6,368.60|6,381.31|6,360.57|+0.07%|\n|6,358.91|6,326.90|6,360.64|6,317.49|+0.78%|\n|6,309.62|6,306.60|6,316.12|6,281.71|+0.06%|\n|6,305.60|6,304.74|6,336.08|6,303.79|+0.14%|\n|6,296.79|6,312.95|6,315.61|6,285.27|-0.01%|\n|6,297.36|6,263.40|6,304.69|6,262.27|+0.54%|\n|6,263.70|6,254.50|6,268.12|6,201.59|+0.32%|\n|6,243.76|6,295.29|6,302.04|6,241.68|-0.40%|\n|6,268.56|6,255.15|6,273.31|6,239.22|+0.14%|",
          "title": "S&P 500 Historical Data (SPX) - Investing.com",
          "url": "https://www.investing.com/indices/us-spx-500-historical-data",
          "date": "2025-08-13",
          "last_updated": "2025-08-14"
        },
        {
          "snippet": "A linear chart of the S&P 500 daily closing values from January 3, 1950, to February 19, 2016\nA logarithmic chart of the S&P 500 index daily closing values from January 3, 1950, to February 19, 2016\nA daily volume chart of the S&P 500 index from January 3, 1950, to February 19, 2016\n...\nSince its inception in 1926, the index's compound annual growth rate—including dividends—has been approximately 9.8% (6% after inflation), with the standard deviation of the return, calculated on a monthly basis, over the same time period being 20.81%.\nWhile the index has declined in several years by over 30%, it has posted annual increases 70% of the time, with 5% of all trading days resulting in record highs.",
          "title": "S&P 500 - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/S&P_500",
          "date": "2003-01-19",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "This article is a summary of the **closing milestones of the S&P 500 Index**, a United States stock market index.\n...\nThe subsequent stock market crash on October 19, 1987 (Black Monday) saw the index lose 20.47% of its value, its highest daily percentage loss to date.\nFalling to 230.30 by November 1987, the index took until July 26, 1989, to recover to its pre-crash high of 336.77.\nClosing above 500 for the first time on March 24, 1995, the dot-com bubble of the late 1990s fueled increased market growth through the turn of the millennium, with the S&P 500 surpassing 800 on February 12, 1997, and 1,000 on February 2, 1998, with an intraday high of 1,552.87 on March 24, 2000.\nAs a result of the 2002 stock market downturn, the index fell to 768.83 by October 10, 2002, and took until October 11, 2007, to surpass its March 2000 intraday trading high.\nWhile a brief bull market in 2007 led to the index achieving new record closures of 1,530.23 on May 30 through to 1,565.15 on October 9, the bursting of the 2000s United States housing bubble led to the subprime mortgage crisis, the 2008 financial crisis, and the Great Recession.\nThese events, including the bankruptcy of Lehman Brothers, caused substantial market volatility that resulted in the S&P 500 closing up or down 3 percent or more 29 times in the fourth quarter of 2008.\nThis included an increase of 11.6% on October 13, 2008, the index's highest daily percentage gain to date.\nIn the year since its record closure of 1,565.15 in October 2007, the index fell by over 50% to 752.44 on November 20, 2008, its lowest point since March 1997.\nClosing the year at 903.25—a yearly loss of 38.5%—the index continued to decline in the first quarter of 2009, with the 2007–2009 bear market reaching a trough of 666 on March 6, 2009.\nThe drawdown from the high in October 2007 to the low in March 2009 was 56.8%, the largest since World War II.\nDespite this, the index recovered substantially in the following year, closing at 822.92 on March 23, 2009, and at 1,115.10 by the end of the year, making 2009 the index's second-best year of the decade.\nOn April 14, 2010, the index closed at 1,210.65, its first close above 1,200 since August 2008.\n...\nWhile this period of volatility continued into 2012 amid electoral and fiscal uncertainty and round 3 of quantitative easing, the index closed the year at 1,426.19, an annual gain of 13% and its biggest gain in 3 years.\nOn March 28 and April 10, 2013, the index's October 2007 closing and intraday trading highs, respectively, were surpassed for the first time, recovering all losses incurred during the Great Recession.\nThe index surpassed 2,000 for the first time on August 26, 2014, reaching an all-time closing high of 2,130.82 on May 21, 2015.\nIt was not surpassed until July 11, 2016, due to a market decline precipitated by the 2015–2016 stock market selloff and 2015–2016 Chinese stock market turbulence.\nThe index surpassed 2,500 on September 25, 2017, finishing the year up 19.4%, its best since 2013.\n...\nHigh market growth in the next two quarters reversed the prior year's losses by April 2019, with the index surpassing 3,000 on July 10.\nThe index closed the year with a growth rate of 28.9%, among its best to date.\nWhile the index reached a new closing peak of 3,386.15 on February 19, 2020, the onset of the COVID-19 pandemic and recession saw it lose 10% of its value in the next six trading days, its fastest drop from a new peak to date.\n...\nThe index reached a new record high of 3,756.07 by the end of the year, closing above 4,000 for the first time on April 1, 2021.\nBy the end of the year the index closed 70 of the year's 252 trading days at new record closing prices, the second highest to date behind the 77 recorded in 1995.\n2021 also marked the first year since 2005 when the S&P 500 beat the other two closely watched U.S. stock indices: the Dow Jones Industrial Average and the Nasdaq Composite.\n...\n### Milestone highs\n- February 2, 1998: The S&P 500 index reaches 1,000 points, closing at 1001.27.\n- March 24, 2000: The S&P 500 index reaches an all-time intraday high of 1552.87 during the dot-com bubble.\nIt hit this level again on July 13, 2007.\n- October 9, 2007: The index closes at a record high of 1565.15, the highest prior to the 2008 financial crisis.\nTwo days later, the index hit an intraday record high of 1576.09.\nIt did not regain this closing level until April 10, 2013.\n- August 26, 2014: The S&P 500 index reaches 2,000 points, closing at 2,000.02.\n- July 12, 2019: The S&P 500 index reaches 3,000 points, closing at 3,013.77.\n- February 19, 2020: The S&P 500 index reached its highest point in the bull market that started from the low point on March 9, 2009, closing at 3386.15.\n- August 18, 2020: The S&P 500 index closed at a record high of 3389.78 amid the ongoing COVID-19 pandemic in the United States.\n- April 1, 2021: The S&P 500 index reaches 4,000 points, closing at 4,019.87.\n- February 9, 2024: The S&P 500 index reaches 5,000 points, closing at 5,026.61.\n- November 11, 2024: The S&P 500 index reaches 6,000 points, closing at 6,001.35.\n- April 15, 2026: The S&P 500 index reaches 7,000 points, closing at 7,022.95.\n...\n- March 9, 2009: S&P 500 closed at 676.53 (it hit a 666.79 intraday low on March 6), its closing low after the onset of the 2008 financial crisis and the bankruptcy of Lehman Brothers.\n...\n- June 8, 2023: The S&P 500 advanced 26.41 points, or 0.6%, to end at 4,293.93 Thursday, its highest closing level since Aug. 16, 2022, according to Dow Jones Market Data.\n...\n|Category|All-time highs|All-time highs|All-time lows|All-time lows|\n...\n|Closing|7,519.12|Tuesday, May 26, 2026|16.66|Tuesday, January 3, 1950|\n...\nThe total return index takes dividends into account.\n...\n|Closing|16,748.21|Thursday, May 14, 2026|\n|Intraday|16,782.55|Thursday, May 14, 2026|",
          "title": "Closing milestones of the S&P 500 - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/Closing_milestones_of_the_S&P_500",
          "date": "2013-05-14",
          "last_updated": "2026-05-26"
        },
        {
          "snippet": "|6,388.64|6,370.01|6,395.82|6,368.53|+0.40%|\n|--|--|--|--|--|\n|6,363.35|6,368.60|6,381.31|6,360.57|+0.07%|\n|6,358.91|6,326.90|6,360.64|6,317.49|+0.78%|\n|6,309.62|6,306.60|6,316.12|6,281.71|+0.06%|\n|6,305.60|6,304.74|6,336.08|6,303.79|+0.14%|\n|6,296.79|6,312.95|6,315.61|6,285.27|-0.01%|\n|6,297.36|6,263.40|6,304.69|6,262.27|+0.54%|\n|6,263.70|6,254.50|6,268.12|6,201.59|+0.32%|\n|6,243.76|6,295.29|6,302.04|6,241.68|-0.40%|\n|6,268.56|6,255.15|6,273.31|6,239.22|+0.14%|\n|6,259.75|6,255.68|6,269.44|6,237.60|-0.33%|\n|6,280.46|6,266.80|6,290.22|6,251.44|+0.27%|\n|6,263.26|6,243.33|6,269.16|6,231.43|+0.61%|\n|6,225.52|6,234.03|6,242.70|6,217.75|-0.07%|\n|6,229.98|6,259.04|6,262.07|6,201.00|-0.79%|\n|6,279.35|6,246.46|6,284.65|6,246.46|+0.83%|\n|6,227.42|6,193.88|6,227.60|6,188.29|+0.47%|\n|6,198.01|6,187.25|6,210.78|6,177.97|-0.11%|\n|6,204.95|6,193.36|6,215.08|6,174.97|+0.52%|",
          "title": "S&P 500 Historical Rates - Investing.com Canada",
          "url": "https://ca.investing.com/indices/us-spx-500-historical-data",
          "date": "2025-07-25",
          "last_updated": "2025-07-28"
        },
        {
          "snippet": "# S&P 500 (DISCONTINUED) (I:SP500NY)\n6845.50 USD for 2025\n...\nS&P 500 is at a current level of 6845.50, up from 5881.63 one year ago.\nThis is a change of 16.39% from one year ago.\n...\n|Notes|Annual closing price of the S&P 500.|\n### Historical Data\n|Date|Value|\n|--|--|\n|December 31, 2025|6845.50|\n|December 31, 2024|5881.63|\n|December 31, 2023|4769.83|\n|December 31, 2022|3839.50|\n|December 31, 2021|4766.18|\n|December 31, 2020|3756.07|\n|December 31, 2019|3230.78|\n|December 31, 2018|2506.85|\n|December 31, 2017|2673.61|\n|December 31, 2016|2238.83|\n|December 31, 2015|2043.94|\n|December 31, 2014|2058.90|\n|December 31, 2013|1848.36|\n|December 31, 2012|1426.19|\n|Date|Value|\n|--|--|\n|December 31, 2011|1257.60|\n|December 31, 2010|1257.64|\n|December 31, 2009|1115.10|\n|December 31, 2008|903.25|\n|December 31, 2007|1468.36|\n|December 31, 2006|1418.30|\n|December 31, 2005|1248.29|\n|December 31, 2004|1211.92|\n|December 31, 2003|1111.92|\n|December 31, 2002|879.82|\n|December 31, 2001|1148.08|\n|December 31, 2000|1320.28|\n|December 31, 1999|1469.25|\n|December 31, 1998|1229.23|",
          "title": "S&P 500 (DISCONTINUED) (Yearly) - United States - YCharts",
          "url": "https://ycharts.com/indicators/sp_500_annual",
          "date": "2026-01-05",
          "last_updated": "2026-05-26"
        }
      ],
      "server_time": null
    }
    ```
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup>
  <Card title="Best Practices" icon="star" href="/docs/search/best-practices">
    Optimize your queries and implement async patterns
  </Card>

  <Card title="Pricing" icon="receipt" href="/docs/getting-started/pricing">
    Review per-request pricing; Search has no additional token charges
  </Card>
</CardGroup>

## Explore More

<CardGroup>
  <Card title="API Reference" icon="book" href="/api-reference/search-post">
    Complete API documentation for the Perplexity Search API
  </Card>

  <Card title="Perplexity SDK" icon="code-circle" href="/docs/sdk/overview">
    Type-safe SDK for Python and Typescript
  </Card>

  <Card title="Date & Time Filters" icon="calendar" href="/docs/search/filters/date-time-filters">
    Filter search results by recency and date ranges
  </Card>

  <Card title="Domain Filtering Guide" icon="globe" href="/docs/search/filters/domain-filter">
    Advanced domain allowlist and denylist patterns
  </Card>

  <Card title="Agent API" icon="code-circle" href="/docs/agent-api/quickstart">
    Third-party models from OpenAI, Anthropic, Google, and more with presets and web search tools.
  </Card>

  <Card title="Search Evals" icon="chart-bar" href="https://github.com/perplexityai/search_evals">
    Benchmark Perplexity Search against other web search APIs across multiple evaluation suites, and explore our latest results.
  </Card>
</CardGroup>


# Core Features
Source: https://docs.perplexity.ai/docs/sonar/features

Streaming and structured outputs for the Sonar API

<SonarDeprecationNotice />

## Overview

The Sonar API provides powerful features for building production-ready applications. This guide covers two core capabilities: streaming responses for real-time output and structured outputs for consistent data formats. For prompting guidance, see the [Prompt Guide](/docs/sonar/prompt-guide).

## Streaming Responses

Streaming allows you to receive partial responses from the Sonar API as they are generated, rather than waiting for the complete response. This is particularly useful for real-time user experiences, long responses, and interactive applications.

<Info>
  Streaming is supported across all Sonar models.
</Info>

### How Streaming Works

When streaming, you receive:

1. **Content chunks** which arrive progressively in real-time
2. **Search results** (delivered in the final chunk(s))
3. **Usage stats** and other metadata

<Warning>
  Search results and metadata are delivered in the **final chunk(s)** of a streaming response, not progressively during the stream.
</Warning>

### Example

```python theme={null}
from perplexity import Perplexity

client = Perplexity()

# Create streaming completion
stream = client.chat.completions.create(
    model="sonar",
    messages=[{"role": "user", "content": "Explain the architecture of retrieval-augmented generation (RAG) and the tradeoffs vs fine-tuning for domain adaptation."}],
    stream=True
)

# Process streaming response
content = ""
for chunk in stream:
    if chunk.choices[0].delta.content:
        content_piece = chunk.choices[0].delta.content
        content += content_piece
        print(content_piece, end="", flush=True)
    
    # Collect metadata from final chunks
    if hasattr(chunk, 'search_results') and chunk.search_results:
        search_results = chunk.search_results
    
    if hasattr(chunk, 'usage') and chunk.usage:
        usage_info = chunk.usage
```

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "d85813fc-9af2-4ded-b192-bb58f1bc1c76",
    "choices": [
      {
        "delta": {
          "content": "",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "index": 0,
        "message": {
          "content": "Retrieval-augmented generation (RAG) is an architecture that pairs an LLM with an external knowledge source and a retrieval system, so the model can “look things up” at inference time instead of relying only on what’s in its weights.\n\nBelow is a compact walkthrough of the architecture and then a comparison with fine‑tuning for domain adaptation: when to use which, and why.\n\n---\n\n## 1. RAG Architecture\n\nConceptually, RAG has two big pieces:\n\n1. **Retrieval** – Find relevant information from external data sources.\n2. **Generation** – Use the LLM to answer, grounded in that retrieved information.\n\nA typical RAG pipeline looks like this:\n\n### 1.1 Data Ingestion & Indexing (Offline)\n\nBefore any user queries, you prepare your knowledge base.\n\n1. **Source data**\n   - Documents, PDFs, wikis, tickets, APIs, databases, etc.\n\n2. **Preprocessing**\n   - Cleaning (strip boilerplate, remove duplicates).\n   - **Chunking** into passages (e.g., 200–1,000 tokens) with overlap so context isn’t cut mid‑section.\n   - Optional: enrich with metadata (titles, timestamps, doc type, permissions).\n\n3. **Embedding & Indexing**\n   - Use an **embedding model** to convert each chunk into a vector.\n   - Store vectors + metadata in a **vector database** (Pinecone, FAISS, Chroma, Azure AI Search, etc.).\n   - Often combined with **hybrid search**:\n     - Vector similarity (semantic)\n     - Keyword / BM25\n     - Optionally “semantic ranking” to re-rank results using an LLM or specialized ranker.\n\nResult: a searchable index that maps queries to relevant text chunks.\n\n---\n\n### 1.2 Retrieval (Online, per query)\n\nWhen a user asks something:\n\n1. **Query understanding**\n   - (Optional) LLM reformulates or expands the query (e.g., agentic retrieval, multi-query).\n   - Convert the query to an embedding vector.\n\n2. **Search**\n   - Retrieve top‑k chunks from the index via:\n     - Vector similarity (cosine, dot product, etc.).\n     - Possibly hybrid scoring (combine lexical + vector + metadata filters).\n\n3. **Context selection**\n   - Filter / re-rank results.\n   - Trim to fit within the **context window** budget.\n   - Possibly structure as:\n     - “Context blocks” with citations.\n     - Grouped by document or section.\n\nOutput: a set of relevant passages plus metadata that will be given to the LLM.\n\n---\n\n### 1.3 Augmentation & Generation\n\n1. **Prompt construction (“augmentation”)**\n   - Build a prompt with:\n     - System / instruction message (e.g., “Answer only using the context; if unknown, say so.”)\n     - User query.\n     - Retrieved context (often with explicit separators and IDs for citations).\n\n2. **LLM response generation**\n   - The LLM reads the augmented prompt and generates an answer.\n   - Good prompts make the LLM:\n     - Prefer retrieved facts over prior knowledge.\n     - Use citations / references.\n     - Refuse to guess when context is insufficient.\n\n3. **Post-processing (optional)**\n   - Add citations from retrieved chunks.\n   - Apply formatting, guardrails, or validation.\n   - Possibly store conversation state or retrieved info in a **memory** store for future turns.\n\n---\n\n### 1.4 Variants / Architectures\n\nBeyond “simple RAG”, there are common extensions:\n\n- **Classic single‑query RAG**  \n  One query → one retrieval → one generation. Simple orchestration.\n\n- **Agentic / multi‑step RAG**\n  - LLM decomposes a complex query into sub‑queries.\n  - Runs multiple retrieval calls (possibly across different tools/indices/APIs).\n  - Synthesizes a final answer from multiple sources.\n\n- **RAG with short‑term memory**\n  - Stores conversation history / past retrieved items.\n  - Uses them as additional context in subsequent turns.\n\n- **Advanced fusion strategies**\n  - **Fusion‑in‑Decoder (FiD)** style: LLM encodes separate retrieved passages and fuses them during decoding for better grounding.\n\n---\n\n## 2. Fine‑Tuning for Domain Adaptation\n\n**Fine‑tuning** changes the model’s weights using domain-specific examples. Types:\n\n- **Instruction / supervised fine‑tuning (SFT)**  \n  Train on (input, output) pairs showing desired behavior in your domain (e.g., “Given a contract section, extract obligations as JSON”).\n\n- **Continued pretraining / domain-adaptive pretraining**  \n  Train the model further on large volumes of *unlabeled* domain text to align its internal representations with domain language.\n\nResults: the model “bakes in” the domain style, terminology, and typical answers into its parameters.\n\n---\n\n## 3. RAG vs Fine‑Tuning for Domain Adaptation: Tradeoffs\n\n### 3.1 What they each do best\n\n**RAG is strongest for:**\n\n- **Fresh, changing information**\n  - Policies, prices, inventories, knowledge bases that change weekly/daily.\n- **Large proprietary corpora**\n  - Millions of documents that you can’t feasibly bake into weights.\n- **Traceability & compliance**\n  - Need to show *where* an answer came from (citations).\n- **Access control**\n  - Different users see different subsets of data; you can filter retrieval by permissions.\n\n**Fine‑tuning is strongest for:**\n\n- **Capability and behavior adaptation**\n  - New tasks or formats: classification, structured extraction, reasoning patterns.\n  - Domain style, tone, “how to talk like us.”\n- **Low-latency, low-dependency deployments**\n  - No retrieval infrastructure; just the model.\n\n---\n\n### 3.2 Data and maintenance\n\n**RAG:**\n\n- **Data requirements**\n  - Mostly raw text; no labels required.\n  - Basic cleaning and chunking needed.\n- **Maintenance**\n  - Update index when docs change.\n  - Swap or improve embedding model, retriever, ranker without retraining the LLM.\n- **Scalability of updates**\n  - Adding a new manual or policy: just ingest and re-index.\n\n**Fine‑tuning:**\n\n- **Data requirements**\n  - High‑quality labeled examples (for SFT).\n  - Larger unlabeled corpora (for continued pretraining).\n- **Maintenance**\n  - When domain changes, you may need more fine‑tuning.\n  - Updating knowledge in weights is slower and more expensive than updating an index.\n\n---\n\n### 3.3 Cost and complexity\n\n**RAG:**\n\n- **Inference cost**\n  - Extra cost for:\n    - Vector search / retrieval.\n    - Larger prompts (context tokens).\n  - But can reuse a *single* base model across many domains.\n- **Infrastructure complexity**\n  - Requires:\n    - Vector DB or search engine.\n    - Ingestion pipelines.\n    - Orchestrator / application layer.\n- **Training cost**\n  - Very low; mostly retrieval configuration (no or minimal model training).\n\n**Fine‑tuning:**\n\n- **Training cost**\n  - GPU time, engineering, and experimentation for each domain/task.\n- **Inference cost**\n  - Similar or slightly higher per token vs base model; no retrieval overhead.\n  - If fine‑tuned model is smaller, can *reduce* inference cost vs using a big general model + RAG.\n- **Operational simplicity**\n  - Serving a single model endpoint is simple; but you might end up with many specialized models.\n\n---\n\n### 3.4 Accuracy, hallucinations, and robustness\n\n**RAG:**\n\n- **Accuracy on factual, document‑answerable queries**\n  - Often higher, because the model is explicitly grounded in the correct passages.\n- **Hallucination**\n  - Substantially reduced if:\n    - Retrieval is high‑quality.\n    - Prompts enforce “answer only from context”.\n  - Still possible if retrieval returns wrong/irrelevant chunks.\n- **Robustness to domain shifts**\n  - If docs are up to date, RAG answers stay current; no retraining needed.\n\n**Fine‑tuning:**\n\n- **Accuracy**\n  - Great when:\n    - The domain is stable.\n    - The task is repeatable and captured in training data.\n  - But knowledge is “fuzzy” inside weights; the model may still fabricate details.\n- **Hallucinations**\n  - Not eliminated; model may confidently invent facts if training didn’t cover specific items or if they changed.\n- **Robustness to domain shifts**\n  - Degrades as real-world domain diverges from training data; needs fresh fine‑tuning.\n\n---\n\n### 3.5 Latency and UX\n\n**RAG:**\n\n- Additional network hops (search + LLM).\n- Index size and retrieval strategy affect speed.\n- Can often be optimized (caching, pre‑fetching, approximate nearest neighbor search), but still higher latency than “model‑only” in many setups.\n\n**Fine‑tuning:**\n\n- Single call to the model → lower baseline latency.\n- Useful for low-latency scenarios where a retrieval step is too slow or too brittle.\n\n---\n\n### 3.6 Security and governance\n\n**RAG:**\n\n- **Pros**\n  - Data stays in your controlled stores; you can:\n    - Enforce row‑level, document‑level access.\n    - Log exactly which documents influenced an answer.\n  - Easier to comply with “right to be forgotten” (remove/alter docs and re-index).\n- **Cons**\n  - Need to secure search infrastructure and any caching layers.\n  - Must integrate authorization into retrieval (e.g., filter by user permissions).\n\n**Fine‑tuning:**\n\n- **Pros**\n  - After fine‑tuning, no need to expose live databases to the model.\n- **Cons**\n  - Hard to remove specific facts once baked into weights.\n  - Harder to prove what data influenced which answer.\n\n---\n\n## 4. When to Use RAG, Fine‑Tuning, or Both\n\n### Use RAG primarily when:\n\n- Your knowledge changes frequently (support docs, product specs, policies).\n- You care about traceability, citations, and grounding.\n- You have lots of text but little or no labeled data.\n- Different users should see different slices of the knowledge base.\n\n### Use fine‑tuning primarily when:\n\n- You need **new capabilities / tasks** rather than just access to new facts:\n  - E.g., extract structured fields, follow complex internal workflows, reason in a specific way.\n- Domain is **relatively stable** and you can collect representative training data.\n- Latency and simplicity of runtime stack matter more than dynamic knowledge.\n\n### Combine both (common in production systems):\n\n- **RAG + fine‑tuned model**:\n  - Fine‑tune for:\n    - Domain style, tone, and task formats.\n    - Better adherence to instructions and constraints.\n  - Use RAG for:\n    - Live, fine‑grained factual grounding.\n    - Access to large knowledge bases.\n- This often gives:\n  - Better reasoning + better grounding than either alone.\n\n---\n\n## 5. Practical heuristic\n\nFor “domain adaptation” specifically:\n\n- If your main need is:  \n  “The model must accurately answer questions based on our docs and stay up to date” → **Start with RAG.**\n- If your main need is:  \n  “The model must perform a specialized task or format complex outputs that we can demonstrate via examples” → **Add fine‑tuning.**\n- As your system matures:  \n  “We already have RAG, but answers are stylistically off / brittle on tricky tasks” → **Fine‑tune the model that sits behind your RAG pipeline.**\n\nIf you share your concrete domain (e.g., legal, medical, customer support) and constraints (latency, budget, data volume), I can outline a recommended architecture and whether to invest first in RAG, fine‑tuning, or both.",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "finish_reason": "stop"
      }
    ],
    "created": 1779391571,
    "model": "sonar-pro",
    "citations": [
      "https://humanloop.com/blog/rag-architectures",
      "https://learn.microsoft.com/en-us/azure/search/retrieval-augmented-generation-overview",
      "https://aws.amazon.com/what-is/retrieval-augmented-generation/",
      "https://www.geeksforgeeks.org/nlp/rag-architecture/",
      "https://www.youtube.com/watch?v=fZM3oX4xEyg",
      "https://www.databricks.com/blog/what-is-retrieval-augmented-generation",
      "https://www.ibm.com/think/topics/retrieval-augmented-generation",
      "https://www.k2view.com/what-is-retrieval-augmented-generation",
      "https://www.nvidia.com/en-us/glossary/retrieval-augmented-generation/"
    ],
    "object": "chat.completion",
    "search_results": [
      {
        "title": "8 Retrieval Augmented Generation (RAG) Architectures You Should ...",
        "url": "https://humanloop.com/blog/rag-architectures",
        "date": "2025-02-01",
        "last_updated": "2026-05-19",
        "snippet": "Unlike traditional models that rely solely on their pre-trained knowledge, RAG allows models to search external databases or documents during ...",
        "source": "web"
      },
      {
        "title": "RAG and Generative AI - Azure AI Search - Microsoft Learn",
        "url": "https://learn.microsoft.com/en-us/azure/search/retrieval-augmented-generation-overview",
        "date": "2026-01-15",
        "last_updated": "2026-03-19",
        "snippet": "Retrieval-augmented generation (RAG) is a pattern that extends LLM capabilities by grounding responses in your proprietary content. While ...",
        "source": "web"
      },
      {
        "title": "What is RAG? - Retrieval-Augmented Generation AI Explained - AWS",
        "url": "https://aws.amazon.com/what-is/retrieval-augmented-generation/",
        "date": "2026-05-13",
        "last_updated": "2026-05-17",
        "snippet": "RAG is the process of optimizing the output of a large language model, so it references an authoritative knowledge base outside of its training data sources ...",
        "source": "web"
      },
      {
        "title": "RAG Architecture - GeeksforGeeks",
        "url": "https://www.geeksforgeeks.org/nlp/rag-architecture/",
        "date": "2026-05-09",
        "last_updated": "2026-05-19",
        "snippet": "Retrieval-Augmented Generation (RAG) is an architecture that enhances LLMs by combining them with external knowledge sources, ...",
        "source": "web"
      },
      {
        "title": "Introduction To Undertsanding RAG(Retrieval-Augmented Generation)",
        "url": "https://www.youtube.com/watch?v=fZM3oX4xEyg",
        "date": "2025-08-31",
        "last_updated": "2026-05-21",
        "snippet": "Retrieval-Augmented Generation (RAG) is the process of optimizing the output of a large language model, so it references an authoritative ...",
        "source": "web"
      },
      {
        "title": "What is Retrieval Augmented Generation (RAG)? | Databricks",
        "url": "https://www.databricks.com/blog/what-is-retrieval-augmented-generation",
        "date": "2023-10-18",
        "last_updated": "2026-05-20",
        "snippet": "Retrieval augmented generation is an AI pattern that improves large language model answers by first retrieving relevant documents from external data sources ...",
        "source": "web"
      },
      {
        "title": "What is RAG (Retrieval Augmented Generation)? - IBM",
        "url": "https://www.ibm.com/think/topics/retrieval-augmented-generation",
        "date": "2024-10-21",
        "last_updated": "2026-04-24",
        "snippet": "RAG is an architecture for optimizing the performance of an artificial intelligence (AI) model by connecting it with external knowledge bases.",
        "source": "web"
      },
      {
        "title": "What is Retrieval-Augmented Generation (RAG)? A Practical Guide",
        "url": "https://www.k2view.com/what-is-retrieval-augmented-generation",
        "date": null,
        "last_updated": "2026-04-18",
        "snippet": "RAG is a Generative AI (GenAI) architecture that augments a Large Language Model (LLM) with fresh, trusted data retrieved from authoritative internal knowledge ...",
        "source": "web"
      },
      {
        "title": "What is Retrieval-Augmented Generation (RAG)? | NVIDIA Glossary",
        "url": "https://www.nvidia.com/en-us/glossary/retrieval-augmented-generation/",
        "date": "2026-03-16",
        "last_updated": "2026-05-21",
        "snippet": "RAG is an AI technique where an external data source is connected to a large language model (LLM) to generate domain-specific or the most up-to-date responses ...",
        "source": "web"
      }
    ],
    "status": null,
    "type": null,
    "usage": {
      "completion_tokens": 2538,
      "cost": {
        "input_tokens_cost": 8e-05,
        "output_tokens_cost": 0.03807,
        "total_cost": 0.04415,
        "citation_tokens_cost": null,
        "reasoning_tokens_cost": null,
        "request_cost": 0.006,
        "search_queries_cost": null
      },
      "prompt_tokens": 27,
      "total_tokens": 2565,
      "citation_tokens": null,
      "num_search_queries": null,
      "reasoning_tokens": null,
      "search_context_size": "low"
    }
  }
  ```
</Accordion>

## Structured Outputs

Structured outputs enable you to enforce specific response formats from Perplexity's models, ensuring consistent, machine-readable data that can be directly integrated into your applications without manual parsing.

We support **JSON Schema** structured outputs. To enable structured outputs, add a `response_format` field to your request with the following structure:

```json theme={null}
{
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "schema": { /* your JSON schema object */ }
    }
  }
}
```

<Tip>
  **Improve Schema Compliance**: Give the LLM hints about the output format in your prompts to improve adherence to the structured format. Include phrases like "Please return the data as a JSON object with the following structure..."
</Tip>

<Info>
  The first request with a new JSON Schema may incur a delay on the first token (typically 10-30 seconds) as the schema is prepared. Subsequent requests will not see this delay.
</Info>

### Example: Financial Analysis

```python theme={null}
from perplexity import Perplexity
from typing import List, Optional
from pydantic import BaseModel

class FinancialMetrics(BaseModel):
    company: str
    quarter: str
    revenue: float
    net_income: float
    eps: float
    revenue_growth_yoy: Optional[float] = None
    key_highlights: Optional[List[str]] = None

client = Perplexity()

completion = client.chat.completions.create(
    model="sonar-pro",
    messages=[
        {
            "role": "user",
            "content": "Summarize Apple's most recent annual 10-K filing: revenue by segment, gross margin trend, and operating cash flow."
        }
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "schema": FinancialMetrics.model_json_schema()
        }
    }
)

metrics = FinancialMetrics.model_validate_json(completion.choices[0].message.content)
print(f"Revenue: ${metrics.revenue}B")
```

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "3edb88c4-495d-4767-ae43-c38d21c7ad30",
    "choices": [
      {
        "delta": {
          "content": "",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "index": 0,
        "message": {
          "content": "Apple’s **most recent annual 10-K** in the search results is the **fiscal 2024 Form 10-K** for the year ended **September 28, 2024**.[2][3]\n\n- **Revenue by segment:** Apple reported **net sales by reportable segment** of **Americas: $112.0B**, **Europe: $101.3B**, **Greater China: $66.9B**, **Japan: $25.0B**, and **Rest of Asia Pacific: $32.1B** in fiscal 2024.[2]\n- **Gross margin trend:** Gross margin rose from **$169.1B in fiscal 2023** to **$180.7B in fiscal 2024**; as a percentage of net sales, that is **~44.1%** in 2024 versus **~44.1%** in 2023, so the *level* increased but the margin rate was essentially flat year over year.[2]\n- **Operating cash flow:** Apple generated **$118.3B** of **net cash from operating activities** in fiscal 2024, up from **$110.5B** in fiscal 2023.[2]\n\nIf you want, I can also break this down into a compact table with **three-year trends** from the 10-K.",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "finish_reason": "stop"
      }
    ],
    "created": 1779895999,
    "model": "sonar-pro",
    "citations": [
      "https://www.apple.com/newsroom/pdfs/fy2025-q2/FY25_Q2_Consolidated_Financial_Statements.pdf",
      "https://www.sec.gov/Archives/edgar/data/320193/000032019324000123/aapl-20240928.htm",
      "https://investor.apple.com/sec-filings/sec-filings-details/default.aspx?FilingId=17933082",
      "https://investor.apple.com/sec-filings/default.aspx",
      "https://investor.apple.com/investor-relations/default.aspx",
      "https://www.annualreports.com/Company/apple-inc",
      "https://www.sec.gov/Archives/edgar/data/320193/000119312515356351/d17062d10k.htm"
    ],
    "object": "chat.completion",
    "search_results": [
      {
        "title": "[PDF] Consolidated Financial Statements - Apple",
        "url": "https://www.apple.com/newsroom/pdfs/fy2025-q2/FY25_Q2_Consolidated_Financial_Statements.pdf",
        "date": null,
        "last_updated": "2025-08-29",
        "snippet": "(1) Net sales by reportable segment: Americas. $. 40,315 $. 37,273 $. 92,963 $. 87,703. Europe. 24,454. 24,123. 58,315. 54,520. Greater China. 16,002. 16,372.",
        "source": "web"
      },
      {
        "title": "aapl-20240928 - SEC.gov",
        "url": "https://www.sec.gov/Archives/edgar/data/320193/000032019324000123/aapl-20240928.htm",
        "date": "2024-09-28",
        "last_updated": "2026-03-30",
        "snippet": "Operating income for each segment consists of net sales to third parties, related cost of sales, and operating ... Apple Inc. | 2024 Form 10-K | 57.",
        "source": "web"
      },
      {
        "title": "SEC Filings Details - Apple Investor Relations",
        "url": "https://investor.apple.com/sec-filings/sec-filings-details/default.aspx?FilingId=17933082",
        "date": "2024-11-01",
        "last_updated": "2026-05-15",
        "snippet": "SEC Filings · Leadership and Governance · Our Values · FAQ · Contact. SEC Filings Details. Form 10-K. Nov 01, 2024. Annual Report. HTML Format ...",
        "source": "web"
      },
      {
        "title": "SEC Filings - Apple Investor Relations",
        "url": "https://investor.apple.com/sec-filings/default.aspx",
        "date": null,
        "last_updated": "2026-05-15",
        "snippet": "SEC Filings. SEC Groupings. All Filings, Annual Filings, Quarterly Filings, Current Reports, Proxy Filings, Registration Statements, Section 16 Filings ...",
        "source": "web"
      },
      {
        "title": "Investor Relations - Apple",
        "url": "https://investor.apple.com/investor-relations/default.aspx",
        "date": null,
        "last_updated": "2026-04-17",
        "snippet": "2024 10-K · 2023 10-K · 2022 10-K. Additional Reports. Net Sales by Category. Reclassification of FY18 net sales ... Green Bond Report. Annual green bond impact ...",
        "source": "web"
      },
      {
        "title": "Apple Inc. - AnnualReports.com",
        "url": "https://www.annualreports.com/Company/apple-inc",
        "date": "2024-01-01",
        "last_updated": "2025-12-16",
        "snippet": "Apple Inc. MOST RECENT 2024 Annual Report and Form 10K. View PDF View Form 10K (HTML).",
        "source": "web"
      },
      {
        "title": "Form 10-K - SEC.gov",
        "url": "https://www.sec.gov/Archives/edgar/data/320193/000119312515356351/d17062d10k.htm",
        "date": "2010-09-25",
        "last_updated": "2026-03-08",
        "snippet": "The following table shows net sales by operating segment and net sales and unit sales ... Includes sales of Apple TV, Apple Watch, Beats products, iPod and ...",
        "source": "web"
      }
    ],
    "status": null,
    "type": null,
    "usage": {
      "completion_tokens": 282,
      "cost": {
        "input_tokens_cost": 8e-05,
        "output_tokens_cost": 0.00423,
        "total_cost": 0.01031,
        "citation_tokens_cost": null,
        "reasoning_tokens_cost": null,
        "request_cost": 0.006,
        "search_queries_cost": null
      },
      "prompt_tokens": 27,
      "total_tokens": 309,
      "citation_tokens": null,
      "num_search_queries": null,
      "reasoning_tokens": null,
      "search_context_size": "low"
    }
  }
  ```
</Accordion>

<Warning>
  **Links in JSON Responses**: Requesting links as part of a JSON response may not always work reliably. Use the links returned in the `citations` or `search_results` fields from the API response instead.
</Warning>

## Next Steps

<CardGroup>
  <Card title="Sonar Prompt Guide" icon="book" href="/docs/sonar/prompt-guide">
    Sonar-specific prompting caveats and best practices.
  </Card>

  <Card title="Pro Search for Sonar Pro" icon="bolt" href="/docs/sonar/pro-search/quickstart">
    Enhanced search with automated tools, multi-step reasoning, and real-time thought streaming.
  </Card>

  <Card title="Sonar API Search Filters" icon="filter" href="/docs/sonar/filters">
    Learn how to control search behavior with filters and parameters.
  </Card>

  <Card title="Sonar API Media Attachments" icon="photo" href="/docs/sonar/media">
    Send and receive images, videos, and files with the Sonar API.
  </Card>
</CardGroup>


# Search Filters
Source: https://docs.perplexity.ai/docs/sonar/filters

Control and customize Sonar API search results with filters

<SonarDeprecationNotice />

Control which websites appear in search results, filter by date and location, target specific languages, and fine-tune search behavior using Sonar API filters.

## Domain Filters

Control which websites are included or excluded from search results using `search_domain_filter`. Supports both domain-level and URL-level filtering.

**Key parameters:**

* `search_domain_filter`: Array of domains or URLs (max 20)
* **Allowlist mode**: Include only specified domains (no prefix)
* **Denylist mode**: Exclude domains (prefix with `-`)

```python theme={null}
from perplexity import Perplexity

client = Perplexity()

# Allowlist: Only search specific domains
completion = client.chat.completions.create(
    model="sonar",
    messages=[{"role": "user", "content": "Explain how LIGO detects gravitational waves and summarize the GW150914 binary black hole merger detection."}],
    search_domain_filter=["nasa.gov", "wikipedia.org", "space.com"]
)

# Denylist: Exclude specific domains
completion = client.chat.completions.create(
    model="sonar",
    messages=[{"role": "user", "content": "Explain the dominant grid-scale battery storage chemistries (lithium-ion, vanadium flow, sodium-ion): operating principle, typical use case, and cost dimensions."}],
    search_domain_filter=["-reddit.com", "-pinterest.com"]
)
```

<AccordionGroup>
  <Accordion title="Response — Explain how LIGO detects gravitational waves and summarize the GW150914 binary black ho...">
    ```json theme={null}
    {
      "id": "f5e40c51-a377-4599-bde4-851660e90515",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "LIGO has detected gravitational waves by using exquisitely sensitive laser interferometers, and its first major success was the observation of GW150914, a merger of two stellar-mass black holes. Here’s a concise explanation of both parts.\n\n---\n\n## 1. How LIGO detects gravitational waves\n\n### Basic idea: measure tiny changes in length\n\nA passing gravitational wave stretches space in one direction and squeezes it in the perpendicular direction. LIGO measures this as a tiny change in the relative lengths of two perpendicular arms using **laser interferometry**.\n\n**Core setup (Michelson interferometer):**\n\n- A very stable laser produces a beam of light.\n- A **beam splitter** divides the beam into two equal parts that travel down two **perpendicular 4 km arms**.\n- At the end of each arm, a highly polished, extremely isolated **test mass (mirror)** reflects the light back.\n- The returning beams recombine at the beam splitter and are sent to a **photodetector**.\n\nBecause the arms are tuned so that the two beams are normally **out of phase**, they destructively interfere and the detector sees almost *no light* (“dark fringe”).\n\n### What a gravitational wave does\n\nWhen a gravitational wave passes:\n\n- One arm is stretched while the other is squeezed; the roles then oscillate as the wave passes.\n- This changes the distance the light travels in each arm by about **10⁻¹⁸ m** (roughly ten‑thousandth the width of a proton for a 4 km arm).\n- That tiny difference makes the two light beams **no longer perfectly out of phase**.\n- The recombined light intensity **flickers** at the photodetector.\n\nLIGO’s computers continuously monitor this intensity:\n\n- The signal is a time-varying pattern of light intensity.\n- Data analysis looks for specific oscillatory patterns (“chirps”) predicted by **general relativity** for systems like orbiting and merging black holes or neutron stars.\n\n### Key technologies that make this possible\n\n- **Long arms and optical cavities**: Light bounces back and forth ~300 times between mirrors in each arm, effectively increasing the path length to hundreds of km, amplifying the effect of a given strain.\n- **Ultra-stable laser**: Single, well-defined wavelength so the “ruler” doesn’t change (otherwise the interference pattern would be meaningless).\n- **Vibration isolation**: Test mass mirrors are suspended in multi-stage pendulum systems and isolated from ground vibrations, seismic noise, and thermal noise, so they “feel” almost like they’re floating in space.\n- **Two detectors**: Twin observatories (Hanford, WA and Livingston, LA) separated by ~3000 km. A true gravitational-wave signal:\n  - Arrives at both with a time delay up to ~10 ms.\n  - Shows a consistent pattern in both instruments.\n  - This helps distinguish real astrophysical signals from local noise or glitches.\n\n---\n\n## 2. The GW150914 binary black hole merger\n\n**Event name:** GW150914  \n**Date of detection:** 2015-09-14, at 09:50:45 UTC  \n**Published/announced:** February 2016  \n\nThis was **the first direct detection of gravitational waves** and the **first direct observation of a binary black hole merger**.\n\n### What LIGO observed\n\n- A short signal, lasting about **0.2 seconds** in the LIGO band.\n- The frequency and amplitude increased over time in a characteristic **“chirp”**:\n  - Frequency swept from ~35 Hz up to ~150 Hz (and beyond) as the black holes spiraled together and merged.\n- The signal was observed in **both** LIGO detectors (Hanford and Livingston) with a time delay of about **7 ms**, consistent with a wavefront crossing Earth at the speed of light.\n\n### What produced the waves\n\nBy matching the observed waveform with general-relativistic models:\n\n- The source was identified as a **binary black hole system**:\n  - One black hole: ~36 solar masses\n  - The other: ~29 solar masses\n- They orbited each other at relativistic speeds and, in the last few orbits:\n  - Reached **fraction-of-light-speed** orbital velocities.\n  - Produced rapidly increasing gravitational waves as they spiraled inward.\n\nAt the moment of merger:\n\n- They formed a single black hole of about **62 solar masses**.\n- The mass difference (~3 solar masses) was converted almost entirely into **gravitational-wave energy**, according to \\(E = mc^2\\).\n- Peak power output was briefly greater than the combined luminosity of all the stars in the observable universe, but carried away as gravitational waves.\n\n### Distance and scale\n\n- The source was located about **1.3 billion light-years** away.\n- By the time the waves reached Earth, the strain in spacetime they produced at LIGO was about:\n  - **h ~ 10⁻²¹**, corresponding to:\n  - A change in a 4 km arm length of about **4 × 10⁻¹⁸ m**.\n- That’s roughly **10,000 times smaller than an atomic nucleus**.\n\n### Why GW150914 was historic\n\n- **First direct detection** of gravitational waves, confirming a major prediction of Einstein’s general relativity from 1916.\n- **First direct evidence** that:\n  - Stellar-mass black hole binaries exist.\n  - They can merge within the age of the universe.\n- Demonstrated that gravitational-wave astronomy is feasible, opening an entirely new way to observe the universe, complementary to telescopes that detect light (electromagnetic waves).\n\nIf you’d like, I can also summarize how the waveform carries information about the black holes’ masses and spins, or how data analysis separates such a tiny signal from noise.",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779391555,
      "model": "sonar-pro",
      "citations": [
        "https://news.mit.edu/2016/ligo-first-detection-gravitational-waves-0211",
        "https://www.ligo.caltech.edu/page/ligo-technology",
        "https://www.nasa.gov/universe/nsfs-ligo-has-detected-gravitational-waves/",
        "https://www.youtube.com/watch?v=o7D8h_53jOM",
        "https://www.youtube.com/watch?v=XJ-lgnkovMc",
        "https://www.ligo.caltech.edu/page/what-are-gw",
        "https://www.ligo.caltech.edu/video/ligo20171016v8",
        "https://en.wikipedia.org/wiki/LIGO",
        "https://pressbooks.howardcc.edu/jrip1/chapter/ligo-analysis-direct-detection-of-gravitational-waves/"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "Scientists make first direct detection of gravitational waves | MIT News",
          "url": "https://news.mit.edu/2016/ligo-first-detection-gravitational-waves-0211",
          "date": "2016-02-11",
          "last_updated": "2026-05-16",
          "snippet": "Now LIGO has made the first direct observation of gravitational waves with an instrument on Earth. The researchers detected the gravitational ...",
          "source": "web"
        },
        {
          "title": "LIGO Technology | LIGO Lab | Caltech",
          "url": "https://www.ligo.caltech.edu/page/ligo-technology",
          "date": null,
          "last_updated": "2026-05-18",
          "snippet": "LIGO detects gravitational waves by generating a laser beam, splitting it in half, and sending each half down an arm of the interferometer. Inside each arm ...",
          "source": "web"
        },
        {
          "title": "NSF's LIGO Has Detected Gravitational Waves - NASA",
          "url": "https://www.nasa.gov/universe/nsfs-ligo-has-detected-gravitational-waves/",
          "date": "2016-02-11",
          "last_updated": "2026-05-15",
          "snippet": "LIGO is sensitive to gravitational waves within the range of 10 to 1,000 cycles per second (10 to 1,000 Hz). A space-based system would be able ...",
          "source": "web"
        },
        {
          "title": "How LIGO Detects Gravitational Waves - YouTube",
          "url": "https://www.youtube.com/watch?v=o7D8h_53jOM",
          "date": "2022-04-04",
          "last_updated": "2026-05-18",
          "snippet": "Share your videos with friends, family, and the world.",
          "source": "web"
        },
        {
          "title": "Laser Interferometer Gravitational-Wave Observatory (LIGO) Explained",
          "url": "https://www.youtube.com/watch?v=XJ-lgnkovMc",
          "date": "2025-02-14",
          "last_updated": "2026-03-31",
          "snippet": "Jonathan Richardson, an experimental physicist at UC Riverside who works on gravitational wave detection, explains what gravitational waves ...",
          "source": "web"
        },
        {
          "title": "What are Gravitational Waves? | LIGO Lab | Caltech",
          "url": "https://www.ligo.caltech.edu/page/what-are-gw",
          "date": null,
          "last_updated": "2026-05-19",
          "snippet": "In fact, by the time gravitational waves from LIGO's first detection reached us, the amount of space-time wobbling they generated was 10,000 times smaller than ...",
          "source": "web"
        },
        {
          "title": "Video | Ripples of Gravity, Flashes of Light | LIGO Lab | Caltech",
          "url": "https://www.ligo.caltech.edu/video/ligo20171016v8",
          "date": "2017-10-16",
          "last_updated": "2026-04-15",
          "snippet": "On Aug. 17, 2017, the Laser Interferometer Gravitational-wave Observatory (LIGO) and Virgo detected, for the first time, gravitational waves ...",
          "source": "web"
        },
        {
          "title": "LIGO - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/LIGO",
          "date": "2002-09-06",
          "last_updated": "2026-05-18",
          "snippet": "The Laser Interferometer Gravitational-Wave Observatory (LIGO) is a large-scale physics experiment and observatory designed to detect cosmic gravitational ...",
          "source": "web"
        },
        {
          "title": "LIGO Analysis: Direct Detection of Gravitational Waves",
          "url": "https://pressbooks.howardcc.edu/jrip1/chapter/ligo-analysis-direct-detection-of-gravitational-waves/",
          "date": "2018-05-03",
          "last_updated": "2026-03-04",
          "snippet": "The LIGO team used a Michelson interferometer, in which a laser beam is split into two identical beams at a 90-degree angle. Each beam travels through a 2.5- ...",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 1206,
        "cost": {
          "input_tokens_cost": 6e-05,
          "output_tokens_cost": 0.01809,
          "total_cost": 0.02415,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 21,
        "total_tokens": 1227,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>

  <Accordion title="Response — Explain the dominant grid-scale battery storage chemistries (lithium-ion, vanadium flow...">
    ```json theme={null}
    {
      "id": "8de4a06d-4fef-4236-a1dd-36496785d4e5",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "Here’s a concise overview of the **dominant grid-scale battery storage chemistries**—**lithium-ion, vanadium flow, and sodium-ion**—focused on **how they work, where they’re used, and what drives their cost**.\n\n## 1) Lithium-ion (Li-ion)\n**Operating principle**\n- Stores energy by moving **lithium ions** between a **cathode** and **anode** through an electrolyte during charge/discharge.\n- Common grid variants include **LFP (lithium iron phosphate)** and **NMC/NCA** types.\n- In grid storage, it’s favored for its **high power density**, **high round-trip efficiency**, and fast response.\n\n**Typical use case**\n- Best for **short-duration storage**: typically **1–4 hours**.\n- Used for:\n  - frequency regulation\n  - peak shaving\n  - renewable smoothing\n  - short backup / bridging power\n- It currently **dominates grid-scale BESS deployments**.\n\n**Cost dimensions**\n- **Capex:** often lower upfront than many alternatives at small-to-medium durations, but strongly dependent on commodity prices.\n- **Duration penalty:** cost rises as you extend storage time because you need more cells/capacity.\n- **Lifecycle cost:** impacted by **degradation**, thermal management, and replacements over time.\n- **Supply chain cost:** exposed to **lithium**, and sometimes **nickel/cobalt** (less so for LFP), plus manufacturing scale and recycling economics.\n- **Operational cost:** relatively efficient, but cooling and system controls add overhead.\n\n## 2) Vanadium redox flow batteries (VRFBs)\n**Operating principle**\n- Energy is stored in **liquid electrolytes** containing vanadium ions in different oxidation states.\n- The electrolyte is kept in **external tanks** and pumped through a **cell stack** where redox reactions occur.\n- Because **power and energy are decoupled**, you scale:\n  - **power** by enlarging the stack\n  - **energy** by enlarging the tanks\n\n**Typical use case**\n- Best for **long-duration, stationary storage**, typically **4–12+ hours**.\n- Good for:\n  - renewable shifting\n  - microgrids\n  - industrial/grid backup\n  - applications needing lots of daily cycling and long calendar life\n- Particularly attractive where **cycle life and safety** matter more than compactness.\n\n**Cost dimensions**\n- **Capex:** usually higher upfront than Li-ion for short durations because of pumps, tanks, membranes, and the electrolyte.\n- **Duration advantage:** economics improve as storage duration increases, since energy capacity is mainly tank size, not more battery stacks.\n- **Material cost:** heavily affected by **vanadium electrolyte price**, which can be a major cost swing factor.\n- **Lifecycle cost:** often favorable because of **long service life** and less degradation-sensitive operation.\n- **Opex:** pumps and balance-of-plant add parasitic loads and maintenance costs.\n\n## 3) Sodium-ion (Na-ion)\n**Operating principle**\n- Works similarly to Li-ion, but uses **sodium ions** instead of lithium ions.\n- During charge/discharge, sodium ions move between the electrodes through an electrolyte.\n- Designed to use more abundant and lower-cost materials than Li-ion.\n\n**Typical use case**\n- Emerging option for **grid storage** and some stationary applications.\n- Often positioned for:\n  - cost-sensitive storage\n  - moderate-duration storage\n  - deployments where **resource availability** and supply-chain security matter\n- Not yet as mature or widespread as Li-ion.\n\n**Cost dimensions**\n- **Capex potential:** promising because **sodium is abundant** and generally cheaper than lithium.\n- **Materials advantage:** can reduce reliance on constrained or expensive battery minerals.\n- **Energy density tradeoff:** typically lower energy density than Li-ion, which can affect system footprint and packaging costs.\n- **Maturity cost:** current systems may still be pricier than expected at scale because manufacturing is less mature and supply chains are still developing.\n- **Lifecycle:** still being validated at scale; durability and bankability are key economic questions.\n\n---\n\n## Quick comparison\n\n| Chemistry | Main advantage | Main limitation | Best-fit duration | Main cost driver |\n|---|---|---|---|---|\n| **Lithium-ion** | High efficiency, mature, compact | Degradation, material price volatility, shorter duration economics | 1–4 h | Cells/materials, replacements, cooling |\n| **Vanadium flow** | Long life, scalable energy capacity, safe | Higher upfront complexity and footprint | 4–12+ h | Vanadium electrolyte, tanks, stack/BOP |\n| **Sodium-ion** | Lower-cost, abundant materials, supply-chain security | Lower maturity, lower energy density | Short to moderate duration | Manufacturing scale, performance validation |\n\n## Bottom line\n- **Li-ion** is the current default for grid batteries because it’s the most mature and commercially deployed.\n- **Vanadium flow** is attractive for **longer-duration storage** where lifetime and scalability matter.\n- **Sodium-ion** is a strong **cost-and-supply-chain alternative** that could grow if manufacturing scale and performance improve.\n\nIf you want, I can also turn this into a **one-page executive summary** or a **side-by-side table with typical round-trip efficiency, lifespan, and footprint**.",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779391762,
      "model": "sonar-pro",
      "citations": [
        "https://www.batterypowertips.com/what-battery-chemistries-are-used-in-grid-scale-energy-storage-faq/",
        "https://energyanalytics.org/the-battery-storage-delusion/",
        "https://advanced.onlinelibrary.wiley.com/doi/10.1002/adma.202516590",
        "https://en.wikipedia.org/wiki/Grid_energy_storage",
        "https://www.fortunebusinessinsights.com/industry-reports/grid-scale-battery-market-101304",
        "https://eticaag.com/best-battery-types-for-energy-storage-guide/"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "What battery chemistries are used in grid-scale energy storage?",
          "url": "https://www.batterypowertips.com/what-battery-chemistries-are-used-in-grid-scale-energy-storage-faq/",
          "date": "2022-06-05",
          "last_updated": "2026-04-14",
          "snippet": "Li-ion batteries currently dominate the grid-scale BESSs needed to support FTM installations (Figure 1). In the longer term, that is not expected to be ...",
          "source": "web"
        },
        {
          "title": "The Battery Storage Delusion: Utility-Scale Batteries Are No Silver ...",
          "url": "https://energyanalytics.org/the-battery-storage-delusion/",
          "date": "2025-12-03",
          "last_updated": "2026-05-15",
          "snippet": "Most lithium-ion batteries—currently the dominant chemistry for utility-scale systems—last for 10 to 13 years and degrade by 3% to 7% annually.",
          "source": "web"
        },
        {
          "title": "Batteries for Grid‐Scale Energy Storage Applications - Zhang - 2025",
          "url": "https://advanced.onlinelibrary.wiley.com/doi/10.1002/adma.202516590",
          "date": "2025-09-17",
          "last_updated": null,
          "snippet": "For grid-scale applications, battery performance requirements differ from those of portable electronics or electric vehicles. Key metrics ...",
          "source": "web"
        },
        {
          "title": "Grid energy storage - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/Grid_energy_storage",
          "date": "2005-03-25",
          "last_updated": "2026-05-05",
          "snippet": "As of 2023 , the largest form of grid storage is pumped-storage hydroelectricity, with utility-scale batteries and behind-the-meter batteries coming second and ...",
          "source": "web"
        },
        {
          "title": "Grid Scale Battery Market Size, Share | Growth Report [2034]",
          "url": "https://www.fortunebusinessinsights.com/industry-reports/grid-scale-battery-market-101304",
          "date": null,
          "last_updated": "2026-05-19",
          "snippet": "Which is the dominating battery chemistry segment in the market? The lithium-ion segment is anticipated to dominate the market during the forecast period.",
          "source": "web"
        },
        {
          "title": "Battery Chemistries for Energy Storage Systems: Safety ... - EticaAG",
          "url": "https://eticaag.com/best-battery-types-for-energy-storage-guide/",
          "date": "2025-02-18",
          "last_updated": "2026-05-09",
          "snippet": "Lithium-ion batteries are the dominant choice for modern Battery Energy Storage ... grid storage, renewable energy integration, and large-scale ...",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 1125,
        "cost": {
          "input_tokens_cost": 0.00011,
          "output_tokens_cost": 0.01688,
          "total_cost": 0.02298,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 36,
        "total_tokens": 1161,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

<Warning>
  You can add a maximum of 20 domains or URLs. Use either allowlist OR denylist mode, not both simultaneously.
</Warning>

## Date & Time Filters

Filter search results by publication date, last updated date, or recency using date range parameters.

**Key parameters:**

* `search_after_date_filter`: Filter by publication date (format: `%m/%d/%Y`)
* `search_before_date_filter`: Filter by publication date (format: `%m/%d/%Y`)
* `last_updated_after_filter`: Filter by last updated date
* `last_updated_before_filter`: Filter by last updated date
* `search_recency_filter`: Predefined periods (`"hour"`, `"day"`, `"week"`, `"month"`, `"year"`)

```python theme={null}
from perplexity import Perplexity

client = Perplexity()

# Publication date range
completion = client.chat.completions.create(
    model="sonar",
    messages=[{"role": "user", "content": "Summarize current trends in enterprise software adoption from major technology industry analysis publications."}],
    search_after_date_filter="3/1/2025",
    search_before_date_filter="3/5/2025"
)

# Last updated date range
completion = client.chat.completions.create(
    model="sonar-pro",
    messages=[{"role": "user", "content": "Explain how OpenAI's API documentation is organized: Models, API reference, and Cookbook sections."}],
    last_updated_after_filter="3/1/2025",
    last_updated_before_filter="3/5/2025"
)

# Recency filter for real-time results (breaking news or live events)
completion = client.chat.completions.create(
    model="sonar-pro",
    messages=[{"role": "user", "content": "What economic indicators do investors most commonly watch (CPI, jobs report, FOMC decisions), and why?"}],
    search_recency_filter="hour"
)

# Recency filter (convenient relative dates)
completion = client.chat.completions.create(
    model="sonar-pro",
    messages=[{"role": "user", "content": "What are the major categories of machine learning, and what are the most common applications of each?"}],
    search_recency_filter="week"
)
```

<AccordionGroup>
  <Accordion title="Response — Summarize current trends in enterprise software adoption from major technology industry...">
    ```json theme={null}
    {
      "id": "1f0b28de-6c93-4dcc-b509-c191e53ec625",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "Enterprise software adoption is being shaped by three dominant forces: near-universal **cloud and SaaS**, rapid but uneven **AI (especially generative AI) integration**, and a shift from tool experimentation to **measurable business impact and ROI**.[1][3][5]\n\nKey current trends from major industry analyses (Gartner, McKinsey, Deloitte, SVB, etc.):\n\n1. **Cloud- and SaaS‑first is now the default, moving toward strategic hybrid**  \n   - Around **94% of enterprises use cloud services**, and about **67% of enterprise infrastructure is cloud‑based**, signaling that cloud is no longer a differentiator but table stakes for enterprise software adoption.[1]  \n   - As AI workloads grow, organizations are shifting from “cloud‑first” to **strategic hybrid** architectures—using cloud for elasticity, on‑prem for consistency and cost control, and edge for low‑latency use cases.[5]  \n   - This is driving adoption of **cloud‑native ERP, CRM, collaboration and digital workplace platforms**, with cloud ERP and collaboration tools among the fastest-growing categories.[1]\n\n2. **AI and generative AI are embedded everywhere—and buyers now demand ROI, not pilots**  \n   - Major analyses describe a pivot from “What can we do with AI?” to “How do we get **impact** from AI?”[5] Enterprises are moving from endless proofs of concept to **production deployments** tied to clear business cases (productivity, revenue growth, cost reduction).[5]  \n   - **GenAI adoption** is accelerating in software development, IT service management, and knowledge work, but many organizations still lack the **training, governance and integration** needed for consistent value and ROI.[2]  \n   - Venture and product trends show AI is no longer optional: **AI-native enterprise software** is attracting the majority of new investment. In 2025, **65% of US enterprise software VC funding went to AI startups**, and AI capability is a core expectation in new enterprise platforms.[3]  \n   - Deloitte notes only **11%** of organizations have agentic (AI agent) systems in full production, despite many pilots, highlighting a gap between experimentation and scalable adoption.[5]\n\n3. **Digital transformation is mainstream; adoption is driven by process optimization and agility**  \n   - Around **65% of organizations increased digital transformation investments** post‑2020.[1]  \n   - Enterprises adopt new software primarily to **optimize processes (68%)**, **improve employee performance (63%)**, **increase agility (59%)**, and **reduce costs (51%)**, according to surveys cited by PwC and others.[1]  \n   - Communication/collaboration platforms, **digital workplace** suites, **ERP**, and **CRM** systems are widely deployed to support hybrid/remote work and modern operating models.[1]\n\n4. **Digital workplace, collaboration, and “enterprise OS” platforms continue to consolidate**  \n   - The global **team collaboration software** market is projected to reach about **$40B by 2028**, with strong double‑digit growth.[1]  \n   - Roughly **60% of organizations** have a formal **digital workplace strategy**, often centered on integrated suites (productivity, communication, content, and workflows) rather than point tools.[1]  \n   - This is pushing adoption of platforms that act as a **hub**—integrating messaging, meetings, knowledge, workflows, and increasingly AI assistants—rather than stand‑alone apps.\n\n5. **User adoption, skills, and change management are now recognized as critical bottlenecks**  \n   - More than **40% of businesses** cite **lack of user adoption** as the biggest barrier to realizing value from new enterprise software.[1]  \n   - Around **70% of employees** are reported to lack necessary digital skills, while only **30%** of organizations have formal digital training programs.[1]  \n   - In response, enterprises are increasing use of **e‑learning and blended learning** (used by about **73%** of organizations) and **microlearning** (used by ~**58%**) to support ongoing adoption.[1]  \n   - Despite this, over **40% of IT leaders don’t measure user satisfaction** with software adoption—suggesting a growing focus area for mature organizations.[1]\n\n6. **Architectures are becoming modular, composable, and API‑first**  \n   - Analyst and consulting reports emphasize a move toward **modular, composable architectures** and **API‑first** design for enterprise systems, enabling faster change and easier integration across SaaS and legacy landscapes.[5][9]  \n   - Composable, API‑based approaches are forecast to account for a substantial share of new enterprise applications in the next few years, supporting faster experimentation with AI services and microservices‑based backends.[9]  \n   - This trend supports “AI-native” organizations, where AI models, data services, and business capabilities can be recomposed rapidly around new use cases.[5]\n\n7. **Cost, security, and governance are reshaping enterprise AI/software strategies**  \n   - Enterprises are encountering **AI infrastructure and inference cost shocks**—some see monthly AI bills in the tens of millions, prompting a reevaluation of infrastructure and model choices.[5]  \n   - Deloitte and other analysts describe an **“AI infrastructure reckoning”**, with organizations optimizing model size, deployment patterns, and using hybrid/cloud/edge combinations to balance performance and cost.[5]  \n   - At the same time, AI introduces new **security and compliance** concerns: organizations must secure data, models, applications, and infrastructure while also using AI to enhance cyber defense capabilities.[5]  \n   - This is leading to adoption of **governance frameworks, model risk management, and AI observability tools** as standard parts of the enterprise software stack.\n\n8. **Market dynamics: AI‑native vendors, M&A, and platform consolidation**  \n   - The enterprise software market remains robust, with strong growth tied to **Industry 4.0, digitization, robotics, and connected devices** driving demand for advanced software in manufacturing and operations.[7]  \n   - There are now **hundreds of enterprise software unicorns**, with more than **75 new enterprise AI unicorns** emerging in the past year according to SVB data, illustrating sustained investor belief in AI‑centric enterprise software models.[3]  \n   - About **46% of enterprise software M&A deals** involved a US VC‑backed buyer, often using acquisitions to acquire **AI capabilities and talent** and to become more “AI‑native.”[3]  \n   - This M&A and investment activity accelerates **feature convergence and platform consolidation**, where leading vendors incorporate adjacent capabilities (analytics, automation, AI assistants) rather than ceding them to niche tools.\n\n9. **Human‑AI collaboration and operating model changes accompany software adoption**  \n   - Deloitte’s research finds that **only 1% of IT leaders** report no major operating‑model changes; most are restructuring around **human‑agent teams**, modular architectures, and continuous evolution.[5]  \n   - Successful adopters focus on **business problems first**, involve end users in solution design, and treat change as continuous rather than periodic.[5]  \n   - This shifts enterprise software buying criteria: organizations increasingly evaluate vendors on **ability to support ongoing change**, embedded governance, AI‑readiness, and end‑user experience—not just feature lists.\n\n10. **Persistent gap between technology capability and organizational readiness**  \n    - Major publications converge on a pattern: technology (especially AI and cloud) is advancing faster than **organizational readiness** in data, governance, skills, and process redesign.[2][5]  \n    - Generative AI tools are broadly available, but **engagement and sustained usage are inconsistent** without proper integration into workflows and clear accountability for outcomes.[2]  \n    - Organizations that succeed tend to have **high‑quality, well‑structured data**, repeatable workflows, and strong cross‑functional governance, enabling measurable productivity and revenue impact from new software.[2]\n\nIf you share your specific context (industry, size, or region), I can narrow this down to the trends and adoption patterns most relevant to your environment and point to the most pertinent analyst angles (e.g., CIO priorities vs. VC/market-structure views).",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779896019,
      "model": "sonar-pro",
      "citations": [
        "https://lemonlearning.com/blog/infographic-enterprise-software-key-figures",
        "https://www.alpha-sense.com/resources/reports/enterprise-software-assessing-ai-adoption-trends/",
        "https://www.svb.com/trends-insights/reports/state-of-enterprise-software/",
        "https://kms-technology.com/blog/enterprise-software-trends/",
        "https://www.deloitte.com/us/en/insights/topics/technology-management/tech-trends.html",
        "https://www.bain.com/insights/six-trends-shaping-the-future-of-enterprise-technology/",
        "https://www.grandviewresearch.com/industry-analysis/enterprise-software-market",
        "https://www.bacancytechnology.com/blog/enterprise-software-trends",
        "https://www.integrate.io/blog/data-integration-adoption-rates-enterprises/"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "Enterprise Software: Key Figures for 2026 - Lemon Learning",
          "url": "https://lemonlearning.com/blog/infographic-enterprise-software-key-figures",
          "date": "2021-10-25",
          "last_updated": "2026-05-26",
          "snippet": "CRM: The CRM market is projected to grow to $128 billion by 2028, driven by increasing demand for AI-driven customer engagement (Fortune Business Insights).",
          "source": "web"
        },
        {
          "title": "Enterprise Software: Assessing AI Adoption Trends - AlphaSense",
          "url": "https://www.alpha-sense.com/resources/reports/enterprise-software-assessing-ai-adoption-trends/",
          "date": "2025-04-24",
          "last_updated": "2026-03-28",
          "snippet": "This report examines where genAI is driving real, positive business outcomes and what separates successful enterprise-scale efforts from those that stall.",
          "source": "web"
        },
        {
          "title": "Enterprise Software Report 2026: AI & VC trends - Silicon Valley Bank",
          "url": "https://www.svb.com/trends-insights/reports/state-of-enterprise-software/",
          "date": null,
          "last_updated": "2026-05-25",
          "snippet": "356 US VC-backed enterprise software unicorns now exist. More than 75 new unicorns have entered the stable since 2025, as record capital has poured in targeting ...",
          "source": "web"
        },
        {
          "title": "Key Trends Shaping The Future of Enterprise Software Development",
          "url": "https://kms-technology.com/blog/enterprise-software-trends/",
          "date": "2025-12-12",
          "last_updated": null,
          "snippet": "New trends like machine learning, generative AI, distributed systems, and CI/CD will transform how enterprise applications function. As ...",
          "source": "web"
        },
        {
          "title": "Tech Trends 2026 | Deloitte Insights",
          "url": "https://www.deloitte.com/us/en/insights/topics/technology-management/tech-trends.html",
          "date": "2025-12-10",
          "last_updated": "2026-05-24",
          "snippet": "As technology innovation and adoption accelerate, five trends reveal how successful organizations are moving from experimentation to impact.",
          "source": "web"
        },
        {
          "title": "Six Trends Shaping the Future of Enterprise Technology",
          "url": "https://www.bain.com/insights/six-trends-shaping-the-future-of-enterprise-technology/",
          "date": "2022-08-04",
          "last_updated": "2026-05-25",
          "snippet": "No sooner has cloud computing become mainstream than questions arise about new trends and buzzwords such as web3, the metaverse, hyperautomation, and quantum ...",
          "source": "web"
        },
        {
          "title": "Enterprise Software Market Size | Industry Report, 2033",
          "url": "https://www.grandviewresearch.com/industry-analysis/enterprise-software-market",
          "date": null,
          "last_updated": "2026-05-10",
          "snippet": "Key industry trends such as Industry 4.0, digitization, modern manufacturing, robotics, and the rise of connected devices are driving the demand for advanced ...",
          "source": "web"
        },
        {
          "title": "Top 10 Enterprise Software Trends to Catch Up in 2026",
          "url": "https://www.bacancytechnology.com/blog/enterprise-software-trends",
          "date": "2026-01-01",
          "last_updated": "2026-05-27",
          "snippet": "Emerging trends like Artificial Intelligence (AI), Machine Learning (ML), and Robotic Process Automation (RPA) are becoming more and more popular.",
          "source": "web"
        },
        {
          "title": "Data Integration Adoption Rates in Enterprises – 45 Statistics Every ...",
          "url": "https://www.integrate.io/blog/data-integration-adoption-rates-enterprises/",
          "date": "2026-01-10",
          "last_updated": "2026-05-27",
          "snippet": "Composable architecture adoption reaches 30% of new applications by 2027. McKinsey predicts modular, API-first approaches will reshape ...",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 1727,
        "cost": {
          "input_tokens_cost": 5e-05,
          "output_tokens_cost": 0.02591,
          "total_cost": 0.03196,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 17,
        "total_tokens": 1744,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>

  <Accordion title="Response — Explain how OpenAI's API documentation is organized: Models, API reference, and Cookboo...">
    ```json theme={null}
    {
      "id": "6ba86d34-0390-4db2-9667-f94751e4fcfc",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "OpenAI’s API documentation is organized into three complementary pieces: **Models**, **API reference**, and the **Cookbook**. Each serves a different purpose:\n\n- **Models**: *What* you can call  \n- **API reference**: *How* to call it, parameter‑by‑parameter  \n- **Cookbook**: *Practical examples* and “recipes” for real tasks  \n\n---\n\n### 1. Models section – what’s available and when to use it\n\nThe **Models** part of the docs focuses on the **available model families**, their capabilities, and typical use cases.[6]\n\nYou’ll generally find:\n\n- **Model catalog**  \n  - Lists major models (for text, chat, images, audio, embeddings, etc.).  \n  - Notes capabilities like reasoning, multimodality, speed, and context length.[6]\n\n- **Use‑case guidance**  \n  - Which models are recommended for:  \n    - chat/assistants  \n    - structured outputs / tools  \n    - code  \n    - embeddings / search  \n    - image or audio tasks  \n\n- **Limits and behavior**  \n  - Context window, rate limits, and any model‑specific constraints.[6]\n\nYou use the Models section to **choose the right model name** (e.g., for the `model` field in your API call) and understand trade‑offs (price, speed, quality).\n\n---\n\n### 2. API reference – how to call the API\n\nThe **API reference** is the **technical contract** for every endpoint.[6] It explains *exactly* how to talk to the service.\n\nTypical structure:\n\n- **Endpoints grouped by functionality**  \n  For example (names/structure can change over time, but conceptually):  \n  - Chat / Assistants (multi‑turn conversations, tools)  \n  - Completions / text generation  \n  - Images (generate, edit, variations)  \n  - Audio (speech‑to‑text, text‑to‑speech)  \n  - Embeddings  \n  - Files / fine‑tuning / vector stores, etc.[6]\n\n- **Per‑endpoint details**  \n  For each endpoint, the reference includes:  \n  - HTTP method and path (e.g., `POST /v1/...`)  \n  - **Required and optional parameters**, with types and descriptions  \n  - Example **request and response** bodies in JSON  \n  - Error formats and status codes[3][6]\n\n- **Language‑specific examples**  \n  - Code snippets for curl, Python, JavaScript, and other SDKs (e.g., showing headers, auth, and JSON payload).[6]\n\nDevelopers mainly use this section when they:\n\n- Implement or debug calls in code  \n- Need exact parameter names, types, or defaults (e.g., `temperature`, `top_p`, `max_tokens`, `tools`)  \n- Want to see canonical examples of a specific endpoint’s usage[3]\n\n---\n\n### 3. Cookbook – concrete, end‑to‑end “recipes”\n\nThe **OpenAI Cookbook** is a collection of **worked examples** and **how‑to guides** for common tasks using the API.[4][5]\n\nKey characteristics:\n\n- **Task‑oriented “recipes”**  \n  Examples include:  \n  - building a Q&A chatbot over your documents  \n  - using embeddings for search or recommendation  \n  - creating function/tool calling flows  \n  - content moderation pipelines  \n  - structured JSON output, RAG workflows, etc.[4][5]\n\n- **Executable code**  \n  - Mostly Python and JavaScript notebooks/scripts.  \n  - Shows complete flows: data prep → API call(s) → post‑processing → basic app logic.[4]\n\n- **Concept explanations tied to code**  \n  - Explains *why* certain parameters are chosen, how to handle rate limiting, batching, streaming, etc., in the context of real applications.[4][5]\n\nThe Cookbook is what you reach for when the question is, “How do I **build X** with the API?” rather than “What does this parameter do?”\n\n---\n\n### How they fit together in practice\n\nWhen building with OpenAI’s API you typically:\n\n1. **Start with Models**  \n   - Pick the **model** that fits your task and constraints (capabilities, cost, speed).[6]\n\n2. **Use the API reference**  \n   - Implement the call(s) for the chosen endpoint.  \n   - Look up request format, parameters, and responses in detail.[3][6]\n\n3. **Consult the Cookbook**  \n   - Copy or adapt a **recipe** that matches your use case (e.g., RAG chatbot, summarization pipeline).[4][5]\n\nSo: **Models** answer “what can I use?”, the **API reference** answers “how do I call it exactly?”, and the **Cookbook** answers “how do I put this together into a working solution?”.",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779896014,
      "model": "sonar-pro",
      "citations": [
        "https://www.youtube.com/watch?v=9ZyHckE3iIo",
        "https://ai.google.dev/api",
        "https://www.youtube.com/watch?v=hLTOPHDCytM",
        "https://github.com/openai/openai-cookbook",
        "https://developers.openai.com/cookbook",
        "https://developers.openai.com/api/docs",
        "https://kwfoundation.org/wp-content/uploads/2025/10/OpenAI_API_Cookbook.pdf",
        "https://leanpub.com/openaiapicookbook"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "OpenAI API Masterclass: Platform, Models & API Explained (Part 1/5)",
          "url": "https://www.youtube.com/watch?v=9ZyHckE3iIo",
          "date": "2024-10-27",
          "last_updated": "2026-03-19",
          "snippet": "OpenAI API Masterclass: GPT-4, ChatGPT, Assistants API, DALL-E, Whisper | Complete Platform Tutorial for Beginners A Complete Beginner's ...",
          "source": "web"
        },
        {
          "title": "Gemini API reference | Google AI for Developers",
          "url": "https://ai.google.dev/api",
          "date": null,
          "last_updated": "2026-05-26",
          "snippet": "This API reference describes the standard, streaming, and real-time APIs you can use to interact with the Gemini models. You can use the REST APIs in any ...",
          "source": "web"
        },
        {
          "title": "The Definitive Guide to Reading OpenAI APIs & How to ... - YouTube",
          "url": "https://www.youtube.com/watch?v=hLTOPHDCytM",
          "date": "2023-05-02",
          "last_updated": "2026-02-23",
          "snippet": "In this video, you're going to learn how to read Open AI's API docs and connect this to apps such as Bubble. READ OUR FULL NO-CODE TOOL ...",
          "source": "web"
        },
        {
          "title": "Examples and guides for using the OpenAI API · GitHub",
          "url": "https://github.com/openai/openai-cookbook",
          "date": "2022-03-11",
          "last_updated": "2026-02-27",
          "snippet": "Example code and guides for accomplishing common tasks with the OpenAI API. To run these examples, you'll need an OpenAI account and associated API key.",
          "source": "web"
        },
        {
          "title": "Cookbook - OpenAI Developers",
          "url": "https://developers.openai.com/cookbook",
          "date": "2020-08-19",
          "last_updated": "2026-05-27",
          "snippet": "Recipes to help you build with OpenAI models ... OpenAI Developers · Home · API · Docs. Guides and concepts for the OpenAI API · API reference.",
          "source": "web"
        },
        {
          "title": "OpenAI API Platform Documentation",
          "url": "https://developers.openai.com/api/docs",
          "date": null,
          "last_updated": "2026-05-27",
          "snippet": "Explore guides, API docs, and examples for the OpenAI API.",
          "source": "web"
        },
        {
          "title": "[PDF] OpenAI API Cookbook | KW Foundation",
          "url": "https://kwfoundation.org/wp-content/uploads/2025/10/OpenAI_API_Cookbook.pdf",
          "date": null,
          "last_updated": null,
          "snippet": "As we learned in the Running a completion request in the OpenAI Playground recipe, ChatGPT and its. GPT models are built on a transformer architecture, which ...",
          "source": "web"
        },
        {
          "title": "OpenAI API Cookbook [Leanpub PDF/iPad/Kindle]",
          "url": "https://leanpub.com/openaiapicookbook",
          "date": "2024-12-23",
          "last_updated": "2025-02-02",
          "snippet": "You'll begin with the OpenAI API fundamentals, covering setup, authentication, and key parameters, and quickly progress to the different elements of the OpenAI ...",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 1014,
        "cost": {
          "input_tokens_cost": 6e-05,
          "output_tokens_cost": 0.01521,
          "total_cost": 0.02127,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 21,
        "total_tokens": 1035,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>

  <Accordion title="Response — What economic indicators do investors most commonly watch (CPI, jobs report, FOMC decis...">
    ```json theme={null}
    {
      "id": "9f2708a6-75ed-427a-86a1-8bc5b097a7cc",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "Investors tend to focus on a relatively small set of economic indicators that have the biggest, most direct impact on markets. The ones you mentioned—CPI, jobs report, and FOMC decisions—are at the top of that list, but they’re part of a broader core group.\n\nBelow are the most commonly watched indicators, what they measure, and why markets care.\n\n---\n\n## 1. Jobs Report (Nonfarm Payrolls / Labor Market Data)\n\n**What it is:**  \nThe U.S. Jobs Report (Nonfarm Payrolls) is released monthly by the Bureau of Labor Statistics. It includes:\n- Jobs added/lost (nonfarm payrolls)\n- Unemployment rate\n- Labor force participation\n- Average hourly earnings (wage growth)\n\n**Why investors watch it:**\n- **Growth signal:** Strong job gains usually mean businesses are hiring, production is rising, and consumers have income to spend—supporting corporate revenues and profits.\n- **Consumer spending:** Employment drives household income, which drives ~70% of U.S. GDP through consumption.\n- **Policy implications:** A very strong labor market (especially with fast wage growth) can increase inflation pressure and push the Federal Reserve toward tighter policy (higher interest rates). Weak labor data can have the opposite effect.\n\n**Market impact:**\n- **Stocks:** Strong jobs + controlled wages → bullish for many sectors. Weak jobs → can hurt cyclical stocks but sometimes helps rate‑sensitive stocks if it implies easier Fed policy.\n- **Bonds:** Strong jobs/wages → higher yields (lower bond prices) as markets anticipate rate hikes. Weak jobs → lower yields.\n- **Dollar:** Strong jobs → often a stronger U.S. dollar (on expectations of higher rates).\n\n---\n\n## 2. Inflation Data (Especially CPI, PCE, and PPI)\n\n### Consumer Price Index (CPI)\n\n**What it is:**  \nMonthly measure of the average price change of a basket of consumer goods and services (food, housing, transportation, medical care, etc.).\n\n**Why investors watch it:**\n- **Purchasing power:** Rising CPI means inflation is eroding the value of money.\n- **Interest rates:** High or rising inflation pressures central banks to raise rates; low inflation allows easier policy.\n- **Profit margins:** Higher input costs can squeeze corporate margins if firms can’t pass on price increases.\n\n**Market impact:**\n- **Bonds:** Very sensitive. Higher inflation → higher yields, lower bond prices.\n- **Equities:** High inflation can hurt valuations (higher discount rates) and pressure growth stocks. Some sectors (energy, materials, certain financials) may benefit.\n- **Asset allocation:** Sustained high inflation can make inflation‑linked securities (TIPS), real assets (real estate, commodities), and certain equities more attractive relative to nominal bonds.\n\n### Personal Consumption Expenditures (PCE) Price Index\n\n**What it is:**  \nA broader measure of consumer prices from the BEA, and the **Fed’s preferred inflation gauge**.\n\n**Why investors watch it:**\n- It’s what the Fed targets when it talks about its 2% inflation goal, so it’s key for **monetary policy expectations**.\n\n### Producer Price Index (PPI)\n\n**What it is:**  \nMeasures price changes received by domestic producers (wholesale level).\n\n**Why investors watch it:**\n- **Leading signal:** Rising producer prices often show up later in consumer prices (CPI), providing an early hint of inflation trends and margin pressures.\n\n---\n\n## 3. Federal Reserve / FOMC Decisions\n\n**What they are:**\n- **Federal funds rate decisions** (target range)\n- **FOMC statements and minutes**\n- **Press conferences and forward guidance** (what the Fed hints it will do next)\n\n**Why investors watch them:**\n- **Cost of capital:** Policy rates influence borrowing costs for consumers and companies, mortgage rates, corporate bonds, etc.\n- **Valuation anchor:** Interest rates are central to discounting future cash flows, which affects stock and bond valuations.\n- **Risk appetite:** Easier policy (low rates, quantitative easing) tends to boost risk assets; tighter policy often pressures them.\n\n**Market impact:**\n- **Stocks:** Lower rates → generally bullish, especially for growth/tech and highly leveraged firms. Higher rates → can hurt valuations and rate‑sensitive sectors.\n- **Bonds:** Direct effect on short‑term yields and expectations for the entire yield curve.\n- **Currencies:** Higher relative U.S. rates often support a stronger dollar, affecting global capital flows and commodity prices.\n\n---\n\n## 4. Gross Domestic Product (GDP)\n\n**What it is:**  \nTotal value of goods and services produced in a country. Reported quarterly (with estimates and revisions).\n\n**Why investors watch it:**\n- **Big‑picture growth:** It’s the broadest measure of economic activity—whether the economy is expanding or contracting.\n- **Corporate earnings backdrop:** Strong GDP growth supports higher revenues and profits; weak or negative growth suggests weaker earnings and possible recessions.\n- **Cycle positioning:** Helps investors gauge where we are in the business cycle (expansion, slowdown, recession, recovery).\n\n**Market impact:**\n- Stronger‑than‑expected GDP → can lift stocks but may also push bond yields up if it raises expectations of higher rates.\n- Weak GDP → can pressure equities but support bonds; if very weak, can trigger fear of recession.\n\n---\n\n## 5. Other Key Indicators Many Investors Track\n\n### a) Purchasing Managers’ Index (PMI / ISM Manufacturing & Services)\n\n**What it is:**  \nSurvey-based index of business conditions (new orders, production, employment, inventories, supplier deliveries).  \n- Above 50 = expansion  \n- Below 50 = contraction\n\n**Why investors watch it:**\n- **Leading indicator:** PMIs often turn before GDP and earnings, giving an early signal of accelerations or slowdowns.\n- **Sector insight:** Manufacturing and services PMIs show which parts of the economy are strengthening or weakening.\n\n**Market impact:**\n- Rising PMIs above 50 often support cyclical stocks and risk appetite; falling PMIs below 50 can trigger risk‑off shifts.\n\n### b) Consumer Confidence / Consumer Sentiment\n\n**What it is:**  \nSurveys of how optimistic/pessimistic consumers are about the economy and their own finances.\n\n**Why investors watch it:**\n- **Spending indicator:** Confident consumers are more likely to spend, supporting retail sales and corporate earnings.\n\n**Market impact:**\n- Rising confidence often aligns with rising equity markets and stronger consumer‑facing sectors; persistent declines can warn of weaker consumption.\n\n### c) Retail Sales\n\n**What it is:**  \nMonthly report of consumer spending at retail stores and online.\n\n**Why investors watch it:**\n- Direct read on consumer demand, which is central to GDP and corporate revenue.\n\n**Market impact:**\n- Strong retail sales → positive for consumer discretionary and broader equities; weak sales → negative signal for growth.\n\n### d) Housing Data (Housing Starts, Building Permits, Home Sales)\n\n**Why investors watch it:**\n- **Leading indicator:** Construction drives employment and demand for materials; housing is also sensitive to interest rates.\n- Weak housing can signal tighter credit or consumer stress; strong housing suggests confidence and easier financial conditions.\n\n### e) Durable Goods Orders / Industrial Production\n\n**Why investors watch them:**\n- Measure business investment and manufacturing activity, especially for big‑ticket items.\n- Rising orders and production → sign of corporate confidence and capex; falling numbers can warn of slowdown.\n\n---\n\n## How Investors Use These Indicators in Practice\n\n1. **Macro direction:**  \n   - Are we in expansion, slowdown, or recession risk?  \n   - Jobs + PMIs + retail sales + GDP → answer this.\n\n2. **Inflation and interest rate expectations:**  \n   - CPI/PCE + wage growth + PPI → inform where inflation is headed.  \n   - That, plus Fed communications → shape bond yields and discount rates.\n\n3. **Positioning portfolios:**\n   - **Strong growth, moderate inflation:** Favor cyclicals (industrials, consumer discretionary, financials), possibly reduce long-duration bonds.\n   - **High inflation, rising rates:** Emphasize value sectors, shorter-duration bonds, TIPS, and sometimes commodities.\n   - **Weak growth, easing policy:** Tilt to quality growth, defensives (utilities, staples, healthcare), and longer-duration bonds.\n\n---\n\nIf you’d like, tell me what you invest in (e.g., stock ETFs, individual stocks, bonds, options, crypto), and I can narrow this down to the 3–5 indicators that matter most for *your* strategy and how to practically track and act on them.",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779391864,
      "model": "sonar-pro",
      "citations": [
        "https://sheltonfunds.com/what-are-the-most-important-economic-indicators-to-watch/",
        "https://getbaraka.com/learn/economic-indicators-guide-to-informed-investing",
        "https://www.finra.org/investors/insights/key-economic-indicators-every-investor-should-know",
        "https://russellinvestments.com/ca/resources/financial-professionals/economic-indicators-dashboard",
        "https://www.youtube.com/watch?v=DEVRzIjAJCE",
        "https://www.financialsense.com/blog/21384/us-economic-boom-or-bust-indicators-every-investor-needs-watch"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "What Economic Indicators To Watch | Shelton Funds",
          "url": "https://sheltonfunds.com/what-are-the-most-important-economic-indicators-to-watch/",
          "date": "2025-08-01",
          "last_updated": "2025-11-03",
          "snippet": "What Are The Most Important Economic Indicators To Watch? · 1. The U.S. Jobs Report (Nonfarm Payrolls) · 2. Consumer Price Index (CPI) · 3. Gross ...",
          "source": "web"
        },
        {
          "title": "Economic Indicators: Guide to Informed Investing",
          "url": "https://getbaraka.com/learn/economic-indicators-guide-to-informed-investing",
          "date": "2026-01-22",
          "last_updated": "2026-01-28",
          "snippet": "Detailed Analysis of Top Economic Indicators · Gross Domestic Product (GDP) · Unemployment Rate · Consumer Price Index (CPI) · Producer Price Index (PPI).",
          "source": "web"
        },
        {
          "title": "Key Economic Indicators Every Investor Should Know | FINRA.org",
          "url": "https://www.finra.org/investors/insights/key-economic-indicators-every-investor-should-know",
          "date": "2024-12-10",
          "last_updated": "2026-05-20",
          "snippet": "Key Economic Indicators Every Investor Should Know · Real Gross Domestic Product (GDP) · Labor Market Data · Inflation Reports · Consumer Confidence ...",
          "source": "web"
        },
        {
          "title": "Economic Indicators Dashboard | Russell Investments",
          "url": "https://russellinvestments.com/ca/resources/financial-professionals/economic-indicators-dashboard",
          "date": null,
          "last_updated": "2026-03-24",
          "snippet": "To help you talk to your clients, we've identified a few key economic and market indicators to help assess the current economic health and trend. As of: 3/31/ ...",
          "source": "web"
        },
        {
          "title": "How Economic Indicators in India and the US Affect Your Investments",
          "url": "https://www.youtube.com/watch?v=DEVRzIjAJCE",
          "date": "2025-11-19",
          "last_updated": "2025-12-02",
          "snippet": "... data – and understanding both India and the US helps you move with them. To know more about investing in US stocks, ETFs and Mutual Funds ...",
          "source": "web"
        },
        {
          "title": "US Economic Boom or Bust? Indicators Every Investor Needs to Watch",
          "url": "https://www.financialsense.com/blog/21384/us-economic-boom-or-bust-indicators-every-investor-needs-watch",
          "date": "2025-08-28",
          "last_updated": null,
          "snippet": "Among the most widely followed are retail sales, industrial production, and the Services ISM Index. Retail sales directly measure consumer ...",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 1815,
        "cost": {
          "input_tokens_cost": 7e-05,
          "output_tokens_cost": 0.02722,
          "total_cost": 0.0333,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 24,
        "total_tokens": 1839,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>

  <Accordion title="Response — What are the major categories of machine learning, and what are the most common applica...">
    ```json theme={null}
    {
      "id": "f737c85e-f293-4758-8852-3d0a523c2f92",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "The major categories of machine learning are **supervised**, **unsupervised**, **reinforcement**, and (less central but increasingly important) **semi‑supervised** and **self‑supervised** learning.[1][3][8] Each is defined by how it uses data and feedback, and each maps to characteristic application areas.\n\n---\n\n## 1. Supervised learning\n\n**Idea:** Learn a mapping from inputs to known outputs using **labeled data** (each example has an input and the correct target).[1][2][3]\n\n**Typical tasks**\n\n- **Classification** (predict a category: spam vs non‑spam, disease vs no disease)[2][3]  \n- **Regression** (predict a continuous value: price, temperature, demand)[2][3]  \n- **Forecasting / time‑series prediction** (future sales, load, weather, etc.)[3]\n\n**Common applications**\n\n- **Image, speech, and text processing**:  \n  - Image classification (e.g., recognizing objects, medical imaging diagnosis)[1][2]  \n  - Speech recognition (converting audio to text)[2]  \n  - Sentiment analysis and topic classification in text (reviews, social media)[2]\n- **Predictive analytics & forecasting**:  \n  - Sales forecasting, demand prediction, churn prediction, stock or price prediction[2][3]  \n  - Weather and event forecasting (e.g., tornado prediction)[1][3]\n- **Risk assessment & fraud detection**:  \n  - Credit scoring, default risk prediction[2]  \n  - Transaction fraud detection and anomaly scoring with labeled fraud cases[1][2]\n- **Recommendation & personalization** (when treated as supervised prediction of click/engagement):  \n  - Product, movie, or content recommendations based on past user behavior[2]\n- **Healthcare and diagnostics**:  \n  - Disease diagnosis from symptoms, lab values, or images[1][2]  \n  - Outcome prediction (e.g., risk of readmission)\n- **Automation & control** (when targets are available):  \n  - Quality inspection from images in manufacturing[2]  \n  - Some autonomous driving components (lane detection, object detection, sign recognition)[1][2]\n\n---\n\n## 2. Unsupervised learning\n\n**Idea:** Discover **patterns or structure** in **unlabeled data** (no explicit targets).[2][3][8]\n\nMain families include **clustering**, **dimensionality reduction**, and **association rule learning**.[2][3]\n\n**Common applications**\n\n- **Clustering / segmentation**[2][3]  \n  - Customer segmentation (group customers by behavior for marketing)  \n  - Image or document clustering (organizing data into similar groups)  \n  - Biological data clustering (e.g., gene expression patterns)\n- **Anomaly / outlier detection**  \n  - Detect unusual network traffic, equipment sensor readings, or financial transactions[2]  \n  - Industrial fault detection\n- **Dimensionality reduction & visualization**  \n  - Reduce high‑dimensional data for visualization or as preprocessing (PCA, etc.)[2][3]  \n  - Feature compression before supervised models or for noise reduction\n- **Association rule mining**  \n  - Market basket analysis (which products are frequently bought together)[2]  \n  - Recommendation support and cross‑selling (e.g., “customers who bought X also bought Y”)\n- **Data exploration & preprocessing**  \n  - Discover latent structure to guide further analysis or model building[2]  \n\nUnsupervised learning is often used upstream of other ML methods, e.g., to cluster data, then train supervised models per cluster.[2][3]\n\n---\n\n## 3. Reinforcement learning (RL)\n\n**Idea:** An **agent** learns to make sequential decisions by interacting with an environment, receiving **rewards or penalties** and improving its policy to maximize cumulative reward over time.[3][4][8]\n\nUnlike supervised learning, there are no labeled “correct actions”; feedback is through rewards.[3][4]\n\n**Common applications**\n\n- **Game playing and strategy**  \n  - Agents that learn to play board games or video games at or beyond human level[4]  \n  - Multi‑agent strategies and simulations\n- **Robotics and control**  \n  - Robot navigation, manipulation, and path planning[4]  \n  - Drones, warehouse robots, and industrial automation where robots learn control policies\n- **Autonomous driving & decision making**  \n  - High‑level driving policies (lane changes, merging, planning maneuvers)[1][4]  \n  - Traffic signal control and route optimization\n- **Recommender systems (sequential)**  \n  - Adaptive recommendation policies that consider long‑term user engagement or retention (RL bandits and full RL)  \n- **Operations research & resource allocation**  \n  - Dynamic pricing, inventory control, and allocation problems where actions influence future states and rewards\n\nRL is used when decisions affect future states and we optimize for long‑term, not just immediate, outcomes.[4]\n\n---\n\n## 4. Semi‑supervised learning\n\n**Idea:** Combine a **small amount of labeled data** with a **large amount of unlabeled data** to improve performance, especially when labeling is expensive.[1][2][3][8]\n\nFor example, the model may first find clusters in unlabeled data and then use the few labeled examples to label clusters.[1][2]\n\n**Common applications**\n\n- **Image and video classification**  \n  - Large image or video collections where only a small subset is labeled[1][2]  \n- **Natural language tasks**  \n  - Text classification or information extraction where annotation is costly  \n- **Medical and scientific data**  \n  - Domains where labels require expert annotation (radiology, pathology, etc.)\n- **Web‑scale applications**  \n  - User behavior logs with a few labeled outcomes and many unlabeled events\n\nSemi‑supervised learning is particularly common in large‑scale industrial settings where unlabeled data is abundant but labels are sparse.[1][2][3]\n\n---\n\n## 5. Self‑supervised learning (often grouped with unsupervised)\n\n**Idea:** Create **supervision from the data itself** by defining a “pretext” task (e.g., predict missing parts of input, next token in text) and train on massive unlabeled datasets.[1][8][9] Labels are generated automatically from the data.\n\nIt is often considered a subcategory of unsupervised or a separate fifth category alongside the others.[1][8][9]\n\n**Common applications**\n\n- **Representation learning for images and video**  \n  - Learn general visual features by predicting missing patches or rotations, then fine‑tune on downstream tasks (classification, detection)\n- **Large language models (LLMs)**  \n  - Train models to predict the next word/token given previous text, enabling capabilities in generation, question answering, and summarization[1]\n- **Audio and speech**  \n  - Learn representations by predicting masked segments in audio signals\n- **Pretraining for downstream supervised tasks**  \n  - Use self‑supervised pretraining on large unlabeled corpora, then fine‑tune with smaller labeled datasets in any domain\n\n---\n\n### Quick mapping: category → typical applications\n\n| Category                    | Core idea                          | Typical applications |\n|----------------------------|------------------------------------|----------------------|\n| **Supervised**             | Learn from labeled input–output pairs | Classification, regression, forecasting, fraud detection, diagnosis, recommendations, image/speech recognition[1][2][3] |\n| **Unsupervised**           | Find structure in unlabeled data      | Clustering, segmentation, anomaly detection, dimensionality reduction, association rules, exploration[2][3] |\n| **Reinforcement**          | Learn by trial‑and‑error with rewards | Robotics, games, autonomous control, sequential recommendations, resource allocation[3][4] |\n| **Semi‑supervised**        | Small labeled + large unlabeled data  | Image/text classification with few labels, medical/scientific data, web‑scale tasks[1][2][3] |\n| **Self‑supervised**        | Labels generated from the data itself | Pretraining for LLMs, vision/audio representations, large‑scale foundation models[1][8][9] |\n\nIf you’d like, I can follow up with:  \n- concrete algorithm examples per category (e.g., Random Forest, k‑Means, Q‑learning), or  \n- guidance on which type to use for a specific problem you have in mind.",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779896021,
      "model": "sonar-pro",
      "citations": [
        "https://www.ibm.com/think/topics/machine-learning-types",
        "https://www.geeksforgeeks.org/machine-learning/types-of-machine-learning/",
        "https://www.sas.com/en_gb/insights/articles/analytics/machine-learning-algorithms.html",
        "https://help.pecan.ai/en/articles/6549972-three-types-of-machine-learning",
        "https://www.netcomlearning.com/blog/types-of-machine-learning",
        "https://www.youtube.com/watch?v=HI5muXcNngQ",
        "https://www.coursera.org/articles/types-of-machine-learning",
        "https://en.wikipedia.org/wiki/Machine_learning",
        "https://lumenalta.com/insights/5-types-of-machine-learning"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "Types of Machine Learning | IBM",
          "url": "https://www.ibm.com/think/topics/machine-learning-types",
          "date": "2023-12-20",
          "last_updated": "2026-03-31",
          "snippet": "Machine learning algorithms fall into five broad categories: supervised learning, unsupervised learning, semi-supervised learning, self-supervised and ...",
          "source": "web"
        },
        {
          "title": "Types of Machine Learning - GeeksforGeeks",
          "url": "https://www.geeksforgeeks.org/machine-learning/types-of-machine-learning/",
          "date": "2026-01-19",
          "last_updated": "2026-05-19",
          "snippet": "Types of Machine Learning · 1. Supervised Machine Learning · 2. Unsupervised Machine Learning · 3. Reinforcement Learning. Reinforcement ...",
          "source": "web"
        },
        {
          "title": "A guide to the types of machine learning algorithms | SAS UK",
          "url": "https://www.sas.com/en_gb/insights/articles/analytics/machine-learning-algorithms.html",
          "date": "2023-03-27",
          "last_updated": "2026-05-14",
          "snippet": "There are four types of machine learning algorithms: supervised, semi-supervised, unsupervised and reinforcement.",
          "source": "web"
        },
        {
          "title": "Three types of machine learning - Pecan Help Center",
          "url": "https://help.pecan.ai/en/articles/6549972-three-types-of-machine-learning",
          "date": null,
          "last_updated": "2025-09-03",
          "snippet": "Machine learning can be divided into three paradigms: supervised learning, unsupervised learning, and reinforcement learning.",
          "source": "web"
        },
        {
          "title": "Types of Machine Learning: Supervised, Unsupervised & More",
          "url": "https://www.netcomlearning.com/blog/types-of-machine-learning",
          "date": "2026-03-20",
          "last_updated": null,
          "snippet": "The four primary machine learning types are supervised learning, unsupervised learning, semi-supervised learning, and reinforcement learning. Q.",
          "source": "web"
        },
        {
          "title": "Types of Machine Learning Models - YouTube",
          "url": "https://www.youtube.com/watch?v=HI5muXcNngQ",
          "date": "2025-03-26",
          "last_updated": "2026-03-26",
          "snippet": "Types of Machine Learning Models | How Machine Learning Models REALLY Work | ML Models | Edureka · Comments. 10. Add a comment... 51:31. Go to ...",
          "source": "web"
        },
        {
          "title": "3 Types of Machine Learning You Should Know | Coursera",
          "url": "https://www.coursera.org/articles/types-of-machine-learning",
          "date": "2025-12-31",
          "last_updated": "2026-05-18",
          "snippet": "While machine learning models can learn through various methods, the most common types include supervised, unsupervised, and reinforcement ...",
          "source": "web"
        },
        {
          "title": "Machine learning - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/Machine_learning",
          "date": "2003-05-25",
          "last_updated": "2026-05-22",
          "snippet": "4.1 Supervised learning · 4.2 Unsupervised learning. 4.2.1 Dimensionality reduction · 4.3 Semi-supervised learning · 4.4 Reinforcement learning · 4.5 Other types.",
          "source": "web"
        },
        {
          "title": "5 types of machine learning - Lumenalta",
          "url": "https://lumenalta.com/insights/5-types-of-machine-learning",
          "date": "2024-12-10",
          "last_updated": "2026-05-12",
          "snippet": "The 5 types of machine learning are supervised, unsupervised, semi-supervised, self-supervised, and reinforcement learning.",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 1769,
        "cost": {
          "input_tokens_cost": 6e-05,
          "output_tokens_cost": 0.02653,
          "total_cost": 0.03259,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 20,
        "total_tokens": 1789,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

<Info>
  Date filters must use `%m/%d/%Y` format (e.g., `"3/1/2025"`). `search_recency_filter` cannot be combined with other date filters. Use `hour` for real-time data such as breaking news or live events.
</Info>

## Location Filters

Customize search results based on geographic location using `user_location` within `web_search_options`.

**Key parameters:**

* `country`: Two-letter ISO 3166 country code (required with coordinates)
* `region`: State, province, or administrative division
* `city`: City name
* `latitude`: Latitude coordinate (-90 to 90)
* `longitude`: Longitude coordinate (-180 to 180)

```python theme={null}
from perplexity import Perplexity

client = Perplexity()

# Full location specification (recommended)
completion = client.chat.completions.create(
    model="sonar-pro",
    messages=[{"role": "user", "content": "Explain what a Yelp business listing contains and how Yelp ranks local search results."}],
    web_search_options={
        "user_location": {
            "country": "US",
            "region": "California",
            "city": "San Francisco",
            "latitude": 37.7749,
            "longitude": -122.4194
        }
    }
)

# Country code only
completion = client.chat.completions.create(
    model="sonar-pro",
    messages=[{"role": "user", "content": "Summarize how the Financial Times and The Economist differ in their approach to covering global business news."}],
    web_search_options={
        "user_location": {
            "country": "US"
        }
    }
)
```

<AccordionGroup>
  <Accordion title="Response — Explain what a Yelp business listing contains and how Yelp ranks local search results.">
    ```json theme={null}
    {
      "id": "b0ef8be4-c355-485e-bd7f-684fbe021b03",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "A Yelp business listing is a free business page that includes core contact details, location, hours, categories, photos, descriptions, and customer reviews, and once claimed it can expose additional business-management features.[3][5][1] Yelp’s local search results are driven by the user’s search terms, the business category or keyword relevance, and the geographic area or city tied to the listing; Yelp also states that submitted business additions are reviewed by moderators before appearing in search results.[3][7]\n\nA Yelp business listing commonly contains:\n- **Business name, address, and phone number (NAP)**, plus a website link.[1]\n- **Hours of operation** and, where applicable, phone or store hours.[1]\n- **Categories** that describe what the business does.[1]\n- **Photos/images** showing the location, products, services, interior, or exterior.[1]\n- **Owner/manager information**, a **history** section, and **specialties** or service descriptions.[1]\n- **Reviews and ratings**, which are a major reason users visit Yelp.[1]\n- Access to additional features after claiming the page, which Yelp says can total **20+ features** for promotion and reputation management.[3]\n\nHow Yelp ranks or surfaces local results:\n- Yelp says businesses can be found in **organic search results** when users search by **categories, keywords, business name, service area, or city**.[3]\n- BrightLocal notes that when Yelp finds a match from a search, it may return either the listing or a list with the **most likely match at the top**.[2]\n- Yelp Support says new business additions must be **evaluated by moderators** before they appear in search results, and that process usually takes **two days or less**.[7]\n\nWhat the available sources do *not* fully specify is a detailed ranking formula such as how much weight Yelp gives to review count, review quality, proximity, or paid advertising. From the sources here, the safest explanation is that Yelp’s local visibility is primarily based on **query relevance, location relevance, and listing completeness/verification**, with moderation applied before newly added businesses appear.[3][2][7]\n\n",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779896017,
      "model": "sonar-pro",
      "citations": [
        "https://www.advicelocal.com/blog/yelp-business-listings/",
        "https://www.brightlocal.com/learn/how-to-add-or-claim-a-yelp-business-listing/",
        "https://business.yelp.com/products/business-page/",
        "https://www.youtube.com/watch?v=4DGpKPCyd6M",
        "https://business.yelp.com",
        "https://business.yelp.com/resources/videos/how-to-add-or-claim-your-yelp-business-page/?domain=local-business",
        "https://www.yelp-support.com/article/How-do-I-add-a-business-to-Yelp?l=en_US",
        "https://nowspeed.com/blog/yelp-guide/"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "Everything You Need to Know About Yelp Business Listings",
          "url": "https://www.advicelocal.com/blog/yelp-business-listings/",
          "date": "2019-04-23",
          "last_updated": "2026-04-30",
          "snippet": "Learn how to claim or create a business listing on Yelp. Additonally, dig into Yelp's other features such as the Yelp Q&A and activity dashboard.",
          "source": "web"
        },
        {
          "title": "How to Add or Claim a Yelp Business Listing - BrightLocal",
          "url": "https://www.brightlocal.com/learn/how-to-add-or-claim-a-yelp-business-listing/",
          "date": "2022-01-06",
          "last_updated": "2026-05-25",
          "snippet": "Read on to learn how you can easily add your business to Yelp, as well as to learn how to claim or verify an existing listing.",
          "source": "web"
        },
        {
          "title": "Why Claim Your Business Page on Yelp",
          "url": "https://business.yelp.com/products/business-page/",
          "date": "2026-05-12",
          "last_updated": "2026-05-27",
          "snippet": "Claiming your page gives you access to 20+ features that help you promote your services and build your reputation. Verify my free listing. Benefits of claiming ...",
          "source": "web"
        },
        {
          "title": "How to Access and Update your Yelp Listing - YouTube",
          "url": "https://www.youtube.com/watch?v=4DGpKPCyd6M",
          "date": "2024-07-17",
          "last_updated": "2025-08-09",
          "snippet": "... content and how to answer yelp reviews. I even show how to change the name of your business if it is incorrect. Referenced Video Links: Yelp ...",
          "source": "web"
        },
        {
          "title": "Yelp for Business: Free and paid advertising solutions",
          "url": "https://business.yelp.com",
          "date": "2026-05-26",
          "last_updated": "2026-05-26",
          "snippet": "It's free to be on Yelp. Simply search for your business below. Can't find it? Add your business name, and we'll help you claim your Yelp Page.",
          "source": "web"
        },
        {
          "title": "How to add or claim your Yelp Business Page I Watch Video",
          "url": "https://business.yelp.com/resources/videos/how-to-add-or-claim-your-yelp-business-page/?domain=local-business",
          "date": "2024-10-30",
          "last_updated": "2026-02-28",
          "snippet": "The first step in marketing your business on Yelp is adding or claiming your free Yelp Business Page. This video will walk you through the easy process.",
          "source": "web"
        },
        {
          "title": "How do I add a business to Yelp? | Support Center",
          "url": "https://www.yelp-support.com/article/How-do-I-add-a-business-to-Yelp?l=en_US",
          "date": "2004-01-01",
          "last_updated": "2026-02-25",
          "snippet": "Any business additions must first be evaluated by our moderators before they appear in search results. This process typically takes two days or less.",
          "source": "web"
        },
        {
          "title": "Should You Have A Listing For Your Business? A Yelp Guide.",
          "url": "https://nowspeed.com/blog/yelp-guide/",
          "date": "2024-09-12",
          "last_updated": "2026-05-24",
          "snippet": "Tip #1: Claim your business listing. Yelp users can add your business, and you can't block Yelp from listing your business, so it's best to claim it right away ...",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 443,
        "cost": {
          "input_tokens_cost": 5e-05,
          "output_tokens_cost": 0.00664,
          "total_cost": 0.0127,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 17,
        "total_tokens": 460,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>

  <Accordion title="Response — Summarize how the Financial Times and The Economist differ in their approach to coverin...">
    ```json theme={null}
    {
      "id": "9ad25773-905c-4f22-b3d1-e202753c126d",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "The **Financial Times** focuses on timely, data‑rich reporting and market-relevant analysis for practitioners, while **The Economist** offers weekly, highly opinionated, thematic essays that interpret global business within a broad political and social context.[1][3][5]\n\nKey differences in their approach to global business coverage:\n\n1. **Format and frequency**\n\n- **Financial Times (FT)**  \n  - **Daily newspaper** (plus live digital updates), designed to provide *real‑time* coverage of markets, deals, corporate moves, and policy developments.[1][3]  \n  - Emphasizes being a running log of what is happening now: market moves, earnings, M&A, regulatory changes, etc.[1][3]\n\n- **The Economist**  \n  - **Weekly magazine**, not a daily news source.[1][3]  \n  - Assumes readers already know the basic news and focuses on *explaining significance, causes, and consequences* with more distance from the daily news cycle.[1][3]\n\n2. **Core editorial style**\n\n- **FT**  \n  - Written in a relatively **straight news** style, closer to a traditional newspaper like the Wall Street Journal: concise articles, heavy use of data, clear separation of news and opinion.[1]  \n  - Reputation for being **“very concise”**, “rarely misstated facts,” and intellectually demanding, assuming readers are already literate in finance, economics, and markets.[1]  \n  - Opinion exists (e.g., Martin Wolf), but is structurally separated from the news pages.[2]\n\n- **The Economist**  \n  - Uses a **distinctive, unified editorial voice**, with unsigned articles that read more like essays than news reports.  \n  - Frequently described as **“strongly opinionated”** journalism, taking clear lines on economic and political questions rather than just describing events.[2]  \n  - Articles synthesize reporting from many places into narrative arguments: “here’s what this trend means and what should be done,” rather than “here’s what happened yesterday.”[2]\n\n3. **News vs. analysis emphasis**\n\n- **FT**  \n  - **News-led**: “extensive news, comment and data analysis for the global business community.”[3]  \n  - Primary value is *speed + depth*: timely coverage for professionals who need up‑to‑date information for decisions (investors, executives, policymakers).[1][3]  \n  - Analysis and commentary are present but usually tied tightly to specific events, markets, or companies (e.g., central bank decisions, earnings, bond markets).[1]\n\n- **The Economist**  \n  - **Analysis-led**: weekly issues scan many countries and sectors but focus on *interpretation*—what trends mean globally and ideologically.[1][3]  \n  - Often steps back to connect business news to broader themes: democracy, regulation, technology, demography, environment, etc.[1][3]  \n  - Less about “yesterday’s stock move,” more about “the long‑term direction of capitalism, trade, or regulation.”\n\n4. **Audience and assumed knowledge**\n\n- **FT**  \n  - Aimed squarely at the **global business and financial community** (investors, bankers, corporate executives, policymakers).[3]  \n  - Assumes substantial prior knowledge of **finance, accounting, economics, politics, and legal frameworks**, and does not spend much space re‑explaining basics.[1]  \n  - Coverage is very useful *transactionally* (e.g., for market participants).\n\n- **The Economist**  \n  - Aimed at a **broader elite readership**: professionals, policymakers, academics, and general readers with strong interest in global affairs.  \n  - Still assumes an educated reader, but covers a wider array of topics—science, society, culture—alongside business and economics.[3]  \n  - Provides context that can help non‑specialists understand complex business and economic issues, but in a conceptual, not “how to trade this” way.\n\n5. **Geographic and ideological orientation**\n\n- **FT**  \n  - Historically **London‑based** with a strong **European and global markets** focus.[1][5]  \n  - Editorial stance centered on **economic liberalism**—supportive of free trade and free markets—but day‑to‑day reporting strives for neutrality and tends to be more skeptical and nuanced on US coverage than many US outlets.[2][5]\n\n- **The Economist**  \n  - Also UK‑based but explicitly **internationalist**, covering “so many different countries in each issue.”[1]  \n  - Openly advocates a **market‑friendly, socially liberal, globalist** worldview, and its coverage frames business news within that ideological lens.[2]  \n\n6. **Use-case for a reader interested in global business**\n\n- Use **Financial Times** if you want:\n  - Up‑to‑the‑minute **global business and financial news**.  \n  - Detailed coverage of markets, deals, corporate results, and policy moves.  \n  - Concise, fact‑driven articles to inform investment or business decisions.[1][3]\n\n- Use **The Economist** if you want:\n  - Weekly, **big‑picture analysis** of global business trends.  \n  - Strongly argued pieces that connect business to politics, society, and long‑term structural forces.[2][3]  \n  - A coherent worldview and interpretive framework rather than continuous news flow.[2]\n\nIn short: the FT is a **daily global business newspaper** optimized for speed and precision in reporting, while The Economist is a **weekly analytical magazine** that uses business news as raw material for broader, explicitly opinionated essays about the global economy and world affairs.[1][2][3][5]",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779896032,
      "model": "sonar-pro",
      "citations": [
        "https://www.wallstreetoasis.com/forum/investment-banking/wsj-vs-economist-vs-ft-vs-businessweek",
        "https://news.ycombinator.com/item?id=33799353",
        "https://libguides.marist.edu/c.php?g=87335&p=563019",
        "https://voices.media/the-primacy-of-personality-led-newsletters-at-the-economist-and-financial-times/",
        "https://en.wikipedia.org/wiki/Financial_Times"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "WSJ vs. Economist vs. FT vs. Businessweek - Wall Street Oasis",
          "url": "https://www.wallstreetoasis.com/forum/investment-banking/wsj-vs-economist-vs-ft-vs-businessweek",
          "date": "2013-07-26",
          "last_updated": "2025-07-24",
          "snippet": "The FT is a paper that is written in a style similar to the WSJ with real time updates and coverage of economics, business, politics, and among ...",
          "source": "web"
        },
        {
          "title": "Ask HN: Alternatives to The Economist? - Hacker News",
          "url": "https://news.ycombinator.com/item?id=33799353",
          "date": "2022-11-30",
          "last_updated": "2026-03-06",
          "snippet": "It's the same market-based, socially progressive, pragmatic international strongly opinionated journalism it's always been.",
          "source": "web"
        },
        {
          "title": "Newspapers: Business and Economic News - LibGuides",
          "url": "https://libguides.marist.edu/c.php?g=87335&p=563019",
          "date": "2026-05-11",
          "last_updated": "2026-03-19",
          "snippet": "Provides extensive news, comment and data analysis for the global business community. Financial Times Online. Provides extensive news, comment ...",
          "source": "web"
        },
        {
          "title": "How The Economist and Financial Times manage personality-driven ...",
          "url": "https://voices.media/the-primacy-of-personality-led-newsletters-at-the-economist-and-financial-times/",
          "date": "2025-09-02",
          "last_updated": null,
          "snippet": "So even when a newspaper or magazine tries its very hardest to be objective, that news has to be delivered with a certain voice or personality.",
          "source": "web"
        },
        {
          "title": "Financial Times - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/Financial_Times",
          "date": "2002-10-25",
          "last_updated": "2026-05-22",
          "snippet": "The editorial stance of the Financial Times centres on economic liberalism, particularly advocacy of free trade and free markets. Since its founding, it has ...",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 1188,
        "cost": {
          "input_tokens_cost": 6e-05,
          "output_tokens_cost": 0.01782,
          "total_cost": 0.02388,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 21,
        "total_tokens": 1209,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

<Tip>
  For best accuracy, provide as many location fields as possible. City and region significantly improve location precision.
</Tip>

## Language Filter

Filter search results by language using ISO 639-1 language codes.

**Key parameters:**

* `search_language_filter`: Array of 2-letter language codes (max 10)

```python theme={null}
from perplexity import Perplexity

client = Perplexity()

# Single language
completion = client.chat.completions.create(
    model="sonar",
    messages=[{"role": "user", "content": "Explain how a transformer language model is trained: pretraining objective, supervised fine-tuning, and RLHF."}],
    search_language_filter=["en"]
)

# Multiple languages
completion = client.chat.completions.create(
    model="sonar-pro",
    messages=[{"role": "user", "content": "Explain how mortgage interest rates are set, including the role of the 10-year US Treasury yield and lender spreads."}],
    search_language_filter=["en", "fr", "de"]
)
```

<AccordionGroup>
  <Accordion title="Response — Explain how a transformer language model is trained: pretraining objective, supervised ...">
    ```json theme={null}
    {
      "id": "2df1cfe5-1231-443b-9f27-d1ef4530da8e",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "A transformer language model is typically trained in three main stages: **unsupervised pretraining** with a language-modeling objective, **supervised fine‑tuning** on curated labeled data, and **RLHF (Reinforcement Learning from Human Feedback)** to better align behavior with human preferences.\n\n---\n\n## 1. Pretraining Objective (Unsupervised / Self‑Supervised)\n\n**Goal:** Learn general language representations and world knowledge from massive unlabeled text.\n\n### Core idea\n\nYou start with a randomly initialized transformer (decoder-only like GPT, or encoder(-decoder) like BERT) and train it on raw text using a **self‑supervised objective**—no human labels beyond the text itself.\n\nTwo canonical objectives:\n\n1. **Autoregressive language modeling (GPT‑style)**  \n   The model learns to predict the next token given previous tokens.  \n   Formally, given a token sequence \\(u_1, \\dots, u_n\\), maximize:\n   \\[\n   \\sum_i \\log P(u_i \\mid u_{i-k}, \\dots, u_{i-1}; \\Theta)\n   \\]\n   where \\(k\\) is the context window and \\(\\Theta\\) are model parameters.[2]  \n   This is implemented with a **Transformer decoder**: masked self‑attention so each position attends only to earlier tokens, then a softmax over the vocabulary to predict the next token.[2][4]\n\n2. **Masked language modeling (BERT‑style)**  \n   Some input tokens are replaced with a special [MASK] token (or corrupted), and the model predicts the original tokens from both left and right context.[3]  \n   This allows learning **bidirectional** representations, instead of strictly left‑to‑right prediction.[3]\n\nAdditional pretraining objectives (especially for BERT-like models):\n\n- **Next Sentence Prediction (NSP):** Predict whether sentence B follows sentence A in the original text.[3]  \n- Variants (e.g., sentence order prediction) or combined objectives, but modern practice often de-emphasizes NSP because it sometimes hurts performance.[1][3]\n\n### Why pretraining?\n\n- Uses huge unlabeled corpora to learn rich **language and world knowledge**.[1][2]  \n- Produces a **task-agnostic** model that can be adapted to many downstream tasks.[1][2][3]  \n- Reduces labeled data requirements and improves generalization.[1][2]\n\nThe result is a **base language model checkpoint** that is not yet aligned but is broadly capable at modeling text.\n\n---\n\n## 2. Supervised Fine‑Tuning (Instruction / Task Tuning)\n\n**Goal:** Specialize the pretrained model to follow instructions and perform specific tasks using labeled data.\n\n### Basic supervised fine‑tuning\n\nYou now have a pretrained transformer. You adapt it on a **labeled dataset** where each example includes an input (prompt) and an output (target), and you train it with standard supervised learning.\n\n- Classical setting (e.g., GPT‑1 paper):  \n  Given labeled pairs \\((x, y)\\), you pass \\(x\\) through the pretrained model, take one (or more) hidden states (e.g., the final token), feed them into an added linear layer, and train to predict the label \\(y\\), maximizing:\n  \\[\n  \\sum_{(x,y)} \\log P(y \\mid x_1, \\dots, x_m)\n  \\][2]\n\n- For generation-style fine‑tuning (instruction-tuned LLMs):  \n  You treat the **prompt + target answer** as a single sequence and train with **teacher forcing**: the model’s objective is to maximize the likelihood of each target token given the prompt and previous target tokens (i.e., next-token prediction, but only on the answer region).  \n  This is still just **cross‑entropy loss** between the model’s predicted distribution and the reference output tokens.\n\nIn both cases:\n\n- You usually **start from the pretrained parameters** and **update all or most weights** on this supervised objective.[1][2][3]  \n- Sometimes you also keep a small language modeling term as an auxiliary objective during fine‑tuning to improve generalization.[2]\n\n### Instruction tuning vs task-specific fine‑tuning\n\n- Traditional: fine‑tune separate models for tasks like classification, QA, NLI, etc., often with task-specific heads.[2][3]  \n- Modern LLMs: fine‑tune on a **mixture of instruction‑following examples** across many tasks (e.g., “Summarize…”, “Translate…”, “Write code that…”) so the model learns the general pattern “read an instruction, produce an appropriate completion” using natural language as the interface.\n\nThe result is a **supervised fine‑tuned (SFT) model** that can follow instructions and perform tasks, but may still:\n- Over-imitate biases in the data,\n- Produce unsafe or unhelpful responses,\n- Optimize for likelihood of training text, not human preference.\n\n---\n\n## 3. RLHF (Reinforcement Learning from Human Feedback)\n\n**Goal:** Further align the model’s behavior with *human preferences* (helpfulness, harmlessness, honesty, style) rather than pure likelihood of text.\n\nRLHF is typically a **three‑step process** built on top of the SFT model:\n\n### Step 1: Supervised Fine‑Tuning (already done)\n\n- The SFT model is used as the starting policy for RLHF.  \n- It already responds somewhat sensibly to prompts.\n\n### Step 2: Train a Reward Model (RM) from Human Preferences\n\nYou collect **preference data**:\n\n1. Show human labelers a prompt and several candidate responses from the SFT model (e.g., 2–4 alternatives).\n2. Ask them to **rank or pick the better response** based on guidelines (safety, helpfulness, factuality, etc.).\n3. You get data of the form: for the *same* prompt, response A is preferred over response B.\n\nYou then train a **reward model**:\n\n- Input: prompt + response.  \n- Output: scalar reward \\(r_\\phi(\\text{prompt}, \\text{response})\\).  \n- Training objective: make the reward model assign a higher score to human‑preferred responses than to rejected ones, usually with a **pairwise logistic loss**.\n\nThis converts human judgments into a differentiable reward function approximated by a neural network.\n\n### Step 3: RL Optimization of the Policy Model\n\nNow you treat the language model as a **policy** in an RL setup:\n\n- State: the prompt and the partial response generated so far.\n- Action: the next token.\n- Episode: generating a full response to a prompt.\n- Reward: the reward model’s scalar score for the completed response (possibly plus other penalties, like length penalties or rule violations).\n\nYou perform RL (commonly **PPO – Proximal Policy Optimization**) to:\n\n- Maximize expected reward from the reward model,\n- While adding a **KL-divergence penalty** to keep the updated policy close to the original SFT model (to avoid severe degradation or mode collapse).\n\nConceptually:\n\n1. Sample prompts.\n2. Generate responses with the current policy model.\n3. Score each response using the reward model.\n4. Use PPO to update the policy parameters toward higher‑reward behavior, with a KL penalty to the SFT policy.\n\nThe effect:\n\n- The model shifts away from merely “what text is likely” towards “what text humans *prefer* given these instructions and safety guidelines.”\n- It typically becomes more:\n  - **Helpful** (better answers, more on-topic),\n  - **Harmless** (less toxic/unsafe content),\n  - **Honest** (more likely to express uncertainty, follow instructions about constraints).\n\n---\n\n## Putting It All Together\n\nIn modern LLM training, the pipeline is roughly:\n\n1. **Pretraining:**  \n   - Objective: next-token prediction (autoregressive LM) or masked LM on massive unlabeled text.  \n   - Outcome: general-purpose language model with broad knowledge but no task specialization or alignment.\n\n2. **Supervised Fine‑Tuning (SFT / Instruction Tuning):**  \n   - Objective: cross‑entropy on curated prompt–response pairs, often multi‑task instructions.  \n   - Outcome: instruction-following model that imitates provided examples.\n\n3. **RLHF:**  \n   - Objective: maximize reward from a human‑trained reward model under an RL algorithm (e.g., PPO) with a KL constraint to SFT.  \n   - Outcome: aligned assistant model that better matches human preferences for helpfulness, safety, and style.\n\nIf you want, I can also sketch the math for the RLHF update (with PPO and KL penalty) or walk through a concrete example prompt and show how each stage would handle it differently.",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779896038,
      "model": "sonar-pro",
      "citations": [
        "https://taoyds.github.io/assets/courses/COMP3361-lec11.pdf",
        "https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf",
        "https://aclanthology.org/N19-1423.pdf",
        "https://d2l.ai/chapter_attention-mechanisms-and-transformers/large-pretraining-transformers.html",
        "https://etc.cuit.columbia.edu/news/basics-language-modeling-transformers-gpt",
        "https://www.lesswrong.com/posts/8F4dXYriqbsom46x5/pretraining-language-models-with-human-preferences",
        "https://mbrenndoerfer.com/writing/gpt-1-generative-pretraining-language-understanding"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "[PDF] Lecture 11: Pre-training and large language models (LLMs)",
          "url": "https://taoyds.github.io/assets/courses/COMP3361-lec11.pdf",
          "date": null,
          "last_updated": "2025-03-06",
          "snippet": "(Devlin et al, 2019): BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding. • Two new pre-training objectives: • Masked language ...",
          "source": "web"
        },
        {
          "title": "[PDF] Improving Language Understanding by Generative Pre-Training",
          "url": "https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf",
          "date": null,
          "last_updated": "2026-05-25",
          "snippet": "First, we use a language modeling objective on the unlabeled data to learn the initial parameters of a neural network model. Subsequently, we adapt these ...",
          "source": "web"
        },
        {
          "title": "[PDF] BERT: Pre-training of Deep Bidirectional Transformers for Language ...",
          "url": "https://aclanthology.org/N19-1423.pdf",
          "date": null,
          "last_updated": "2026-05-16",
          "snippet": "The masked language model randomly masks some of the tokens from the input, and the objective is to predict the original vocabulary id of the masked. Page 2 ...",
          "source": "web"
        },
        {
          "title": "11.9. Large-Scale Pretraining with Transformers",
          "url": "https://d2l.ai/chapter_attention-mechanisms-and-transformers/large-pretraining-transformers.html",
          "date": null,
          "last_updated": "2026-03-05",
          "snippet": "Using language modeling as the training objective, the GPT (generative pre-training) model chooses a Transformer decoder as its backbone (Radford et al., 2018).",
          "source": "web"
        },
        {
          "title": "The Basics of Language Modeling with Transformers: GPT",
          "url": "https://etc.cuit.columbia.edu/news/basics-language-modeling-transformers-gpt",
          "date": "2021-11-14",
          "last_updated": "2025-07-19",
          "snippet": "It achieved great success in its time by pre-training the model in an unsupervised way on a large corpus, and then fine tuning the model for ...",
          "source": "web"
        },
        {
          "title": "Pretraining Language Models with Human Preferences - LessWrong",
          "url": "https://www.lesswrong.com/posts/8F4dXYriqbsom46x5/pretraining-language-models-with-human-preferences",
          "date": "2023-02-21",
          "last_updated": "2026-05-21",
          "snippet": "There are other objectives we can use that train a model to imitate only certain aspects of the training data while avoiding others. Consider a ...",
          "source": "web"
        },
        {
          "title": "GPT-1: The Origin of Generative Pre-Training for Language ...",
          "url": "https://mbrenndoerfer.com/writing/gpt-1-generative-pretraining-language-understanding",
          "date": "2025-07-20",
          "last_updated": "2025-12-23",
          "snippet": "Explore the GPT-1 architecture, pre-training objective, fine-tuning approach, and transfer learning results that established the foundation ...",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 1848,
        "cost": {
          "input_tokens_cost": 7e-05,
          "output_tokens_cost": 0.02772,
          "total_cost": 0.03379,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 24,
        "total_tokens": 1872,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>

  <Accordion title="Response — Explain how mortgage interest rates are set, including the role of the 10-year US Treas...">
    ```json theme={null}
    {
      "id": "dae6ef2c-852a-400d-b703-75f9c52a5041",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "Mortgage interest rates are set in two main layers: first, markets determine a **baseline level** using benchmarks like the **10‑year U.S. Treasury yield** and mortgage‑backed securities (MBS); then, individual lenders add **spreads and loan‑/borrower‑specific adjustments** to arrive at the actual rate you pay.[3][4][6]\n\nBelow is how the pieces fit together.\n\n---\n\n## 1. Market benchmark: 10‑year Treasury & MBS\n\nMost U.S. **30‑year fixed mortgage rates tend to move closely with the 10‑year U.S. Treasury yield**.[1][3][4][6]\n\n- 30‑year mortgages are long‑term loans, but they rarely last 30 full years because people move, sell, or refinance; statistically, their *average life* is closer to 7–10 years.[4]  \n- Because of that, lenders and investors use the **10‑year Treasury note** as a practical benchmark for pricing 30‑year mortgages.[4]\n\nAccording to Fannie Mae and other industry sources, **mortgage rates are determined by adding a spread to the 10‑year Treasury note**.[4][6] Bankrate notes that **mortgage rates typically move in lockstep with 10‑year Treasury yields**: when the yield rises, mortgage rates rise to maintain lender spreads, and vice versa.[3]\n\nTwo key market instruments matter:\n\n- **10‑year Treasury notes (T‑notes)**  \n  - These are low‑risk U.S. government bonds.  \n  - Their yields reflect **expectations for future short‑term rates, inflation, and growth**, shaped by Federal Reserve policy, economic data, and geopolitical risk.[1][3][4]  \n  - When investors seek safety (e.g., in uncertainty), they buy more Treasuries, pushing prices up and **yields down**, which typically pulls **mortgage rates down** as well.[3]\n\n- **Mortgage‑backed securities (MBS)**  \n  - Lenders often sell mortgages into MBS, which are bought by investors.[3][4]  \n  - When **MBS prices rise**, the yield investors demand on MBS falls, which supports **lower mortgage rates**; when MBS prices fall, mortgage rates tend to rise.[3]  \n  - Lenders “usually add a margin to the MBS rate to come up with the rate they charge for a mortgage loan.”[3]\n\nIn practice, lenders watch both **10‑year Treasury yields and MBS pricing** to set their base mortgage pricing each day.[3][4]\n\n---\n\n## 2. The “spread” over the 10‑year Treasury\n\nThe difference between the **30‑year fixed mortgage rate** and the **10‑year Treasury yield** is called the **spread**.[3][4][6]\n\n- Bankrate notes this spread is **usually about 2 percentage points** (e.g., 10‑year yield 4% → mortgage around 6%).[3]  \n- During stressed periods (like late in the pandemic), the spread widened to about **3 percentage points**, reflecting higher risk and market dislocation.[3]\n\nThe Federal Savings Bank and Fannie Mae break this spread into components:[4][6]\n\n### a) Secondary spread (MBS vs. 10‑year Treasury)\n\n- This is the difference between **MBS yields** and **10‑year Treasury yields**.[4]  \n- It exists because MBS are **riskier than Treasuries**:  \n  - **Prepayment risk**: borrowers can refinance or sell early, shortening or changing the cash flows.  \n  - **Credit risk**: borrowers can default, even on agency‑guaranteed loans there are guaranty structures and costs.[4]  \n- Investors demand a **higher yield** on MBS than on near‑risk‑free Treasuries, so MBS rates are above the 10‑year Treasury yield.[4]\n\n### b) Primary‑secondary spread (borrower rate vs. MBS)\n\n- This is the gap between the **rate offered to the borrower** and the **MBS yield**.[4]  \n- It includes:  \n  - **Origination costs** (staff, underwriting, overhead)  \n  - **Servicing fees** (collecting payments, managing escrow)  \n  - **Guaranty fees** (Fannie Mae, Freddie Mac, or FHA/VA/Ginnie Mae charges)  \n  - **Lender profit margin**[4]  \n\nCombined, these two pieces create the **overall mortgage‑Treasury spread**:\n\n\\[\n\\text{Borrower Rate} \\approx \\text{10‑yr Treasury Yield} + \\text{Secondary Spread} + \\text{Primary–Secondary Spread}\n\\]\n\nWhen market conditions change—credit stress, Fed buying/selling of MBS, investor appetite—the **spread can widen or narrow** even if the 10‑year yield is unchanged.[3][4]\n\n- For example, the Fed’s large‑scale **purchase of MBS during the pandemic** narrowed spreads and contributed to **record‑low mortgage rates**.[3]  \n- Later, as that support pulled back and volatility rose, spreads widened, so mortgage rates were higher relative to Treasuries.[3][4]\n\n---\n\n## 3. Role of the Federal Reserve and the economy\n\nThe **Fed does not directly set mortgage rates**.[3] Instead, it influences them through:\n\n- **Short‑term interest rate policy (federal funds rate)**, which shapes expectations for future rates and thus Treasury yields.[4]  \n- **Balance sheet policies (buying or selling Treasuries and MBS)**, which affect both Treasury yields and MBS prices/spreads.[3][4]  \n- Broader impacts on inflation and growth, which influence investor demand for bonds and risk assets.[2][3][4]\n\nMacro factors that move **Treasury yields and MBS spreads**—and therefore mortgage rates—include:[2][3][4]\n\n- Inflation and inflation expectations  \n- Overall economic growth and unemployment  \n- Risk sentiment and geopolitical events  \n- Government policy and regulation of the housing/finance system\n\n---\n\n## 4. How lenders set *your* specific rate\n\nOnce the **market baseline** is set (10‑year yield + market spread), individual lenders layer on **loan‑ and borrower‑specific adjustments**.\n\nExperian, the CFPB, and banks identify key factors:[1][2][5][7]\n\n- **Credit score and credit history**  \n  - Higher scores → lower perceived default risk → **lower rate**.[1][5][7]  \n  - Lower scores or recent derogatories → higher rate.\n\n- **Debt‑to‑income ratio (DTI) and income stability**  \n  - Lower DTI and stable income reduce risk, helping qualify for **better pricing**.[1][2][5][7]\n\n- **Loan‑to‑value (LTV) ratio / down payment**  \n  - Bigger down payment → lower LTV → less loss risk for lender → **lower rate**.[2][5][7]  \n  - High‑LTV or cash‑out refinances often carry rate add‑ons.\n\n- **Loan amount and type**  \n  - Jumbo vs. conforming, fixed vs. adjustable, conventional vs. FHA/VA/USDA all carry different capital, liquidity, and guarantee costs, which show up in your rate.[1][2][5][7]  \n  - Adjustable‑rate mortgages usually start lower because the rate can reset later to market levels.[1][5]\n\n- **Term length**  \n  - **Shorter terms (10–15 years)** generally have **lower rates** than 30‑year terms because the lender’s money is at risk for a shorter period.[1][5]\n\n- **Property and program details**  \n  - Investment property or 2–4 unit vs. primary residence  \n  - Manufactured housing, condos, or certain property types may have pricing add‑ons.\n\n- **Points and fees**  \n  - You can often pay **discount points** up front to reduce the interest rate; conversely, choosing lower closing costs may mean accepting a higher rate.[1][5]\n\nDifferent lenders also have different **overhead structures, risk appetites, and profit targets**, so **rates vary by lender even on the same day for the same borrower**.[2][5] This is why rate shopping is typically recommended.[2]\n\n---\n\n## 5. Putting it all together with a simple example\n\nConceptually, for a 30‑year fixed mortgage on a given day:\n\n1. **Market sets baseline**  \n   - 10‑year Treasury yield: 4.0%  \n   - MBS vs. Treasury secondary spread: +0.7%  \n   → MBS yield: 4.7%\n\n2. **Primary‑secondary and lender margin**  \n   - Servicing + guaranty fees + overhead + profit: +1.3%  \n   → Typical **par mortgage rate quote**: ~6.0% (a 2.0% spread over the 10‑year yield)[3][4][6]\n\n3. **Loan/borrower adjustments**  \n   - Strong borrower, 20% down, owner‑occupied, 740+ FICO: small or no add‑ons → ~6.0%  \n   - Riskier profile (lower credit score, high LTV, investment property): several add‑ons → 6.5–7.0%+\n\nThis illustrates how **the 10‑year Treasury yield anchors the level of mortgage rates**, while **spreads and loan‑specific pricing** explain why your actual rate may be higher or lower than that benchmark.",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779896043,
      "model": "sonar-pro",
      "citations": [
        "https://www.experian.com/blogs/ask-experian/how-mortgage-interest-works/",
        "https://www.leaderbank.com/blog/how-do-mortgage-interest-rates-work",
        "https://www.bankrate.com/mortgages/how-interest-rates-are-set/",
        "https://www.thefederalsavingsbank.com/Blog/how-are-mortgage-rates-determined/",
        "https://www.bankatfirst.com/personal/discover/flourish/how-banks-determine-mortgage-rates.html",
        "https://www.fanniemae.com/research-and-insights/publications/housing-insights/rate-30-year-mortgage",
        "https://www.consumerfinance.gov/about-us/blog/7-factors-determine-your-mortgage-interest-rate/",
        "https://www.freddiemac.com/pmms"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "How Does Mortgage Interest Work? - Experian",
          "url": "https://www.experian.com/blogs/ask-experian/how-mortgage-interest-works/",
          "date": "2026-04-23",
          "last_updated": "2026-05-27",
          "snippet": "To calculate the mortgage interest on a home loan, your lender typically takes your annual interest rate, divides it by 12 to get a monthly rate and then ...",
          "source": "web"
        },
        {
          "title": "How Do Mortgage Interest Rates Work? | Leader Bank",
          "url": "https://www.leaderbank.com/blog/how-do-mortgage-interest-rates-work",
          "date": "2025-08-13",
          "last_updated": "2026-05-27",
          "snippet": "Mortgage interest rates are determined by a range of factors including both broad economic conditions and the personal finances of individuals borrowers.",
          "source": "web"
        },
        {
          "title": "What Factors Determine And Move Mortgage Rates? | Bankrate",
          "url": "https://www.bankrate.com/mortgages/how-interest-rates-are-set/",
          "date": "2025-09-12",
          "last_updated": "2026-05-26",
          "snippet": "Other market factors impacting mortgage interest rates · Overall economy · Inflation · Federal Reserve · Mortgage spreads · Government policies.",
          "source": "web"
        },
        {
          "title": "How are mortgage rates determined? | The Federal Savings Bank",
          "url": "https://www.thefederalsavingsbank.com/Blog/how-are-mortgage-rates-determined/",
          "date": "2025-09-19",
          "last_updated": "2026-05-27",
          "snippet": "Mortgage rates are determined by a range of factors from larger economic inputs down to your personal financial profile.",
          "source": "web"
        },
        {
          "title": "How Do Banks Set Mortgage Rates",
          "url": "https://www.bankatfirst.com/personal/discover/flourish/how-banks-determine-mortgage-rates.html",
          "date": "2020-11-30",
          "last_updated": "2026-05-17",
          "snippet": "Understand the key factors that banks consider for your mortgage interest rate, including credit score, size & length of loan, and economic factors.",
          "source": "web"
        },
        {
          "title": "What Determines the Rate on a 30-Year Mortgage? | Fannie Mae",
          "url": "https://www.fanniemae.com/research-and-insights/publications/housing-insights/rate-30-year-mortgage",
          "date": "2024-12-11",
          "last_updated": "2026-05-26",
          "snippet": "Mortgage rates are determined by adding a spread to the benchmark 10-year Treasury note. The spread, or difference, between the rate offered on ...",
          "source": "web"
        },
        {
          "title": "Seven factors that determine your mortgage interest rate",
          "url": "https://www.consumerfinance.gov/about-us/blog/7-factors-determine-your-mortgage-interest-rate/",
          "date": "2017-09-29",
          "last_updated": "2026-05-27",
          "snippet": "1. Credit scores · 2. Home location · 3. Home price and loan amount · 4. Down payment · 5. Loan term · 6. Interest rate type · 7. Loan type.",
          "source": "web"
        },
        {
          "title": "Mortgage Rates - Freddie Mac",
          "url": "https://www.freddiemac.com/pmms",
          "date": "2022-11-17",
          "last_updated": "2026-05-27",
          "snippet": "The 30-year fixed-rate mortgage averaged 6.51% as of May 21, 2026, up from last week when it averaged 6.36%. A year ago at this time, the 30- ...",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 2040,
        "cost": {
          "input_tokens_cost": 8e-05,
          "output_tokens_cost": 0.0306,
          "total_cost": 0.03667,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 25,
        "total_tokens": 2065,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

<Info>
  Language codes must be valid ISO 639-1 codes (e.g., `"en"`, `"fr"`, `"de"`). You can filter by up to 10 languages per request.
</Info>

## Academic Filter

Prioritize scholarly sources and peer-reviewed content by setting `search_mode` to `"academic"`.

**Key parameters:**

* `search_mode`: Set to `"academic"` to target academic sources

```python theme={null}
from perplexity import Perplexity

client = Perplexity()

completion = client.chat.completions.create(
    model="sonar-pro",
    messages=[{"role": "user", "content": "What is lion's mane mushroom (Hericium erinaceus), and what mechanisms have been proposed in the published literature for its claimed cognitive effects?"}],
    search_mode="academic",
    web_search_options={"search_context_size": "low"}
)
```

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "1e485ec9-3f7b-4ba1-b00d-c6e31930403f",
    "choices": [
      {
        "delta": {
          "content": "",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "index": 0,
        "message": {
          "content": "Lion’s mane (Hericium erinaceus) is an edible/medicinal mushroom long used in East Asian traditional medicine and now marketed globally as a “nootropic.” It contains a variety of bioactive compounds and has shown interesting effects in cells and animal models, with early, small human trials suggesting possible cognitive and mood benefits. However, evidence in humans is still limited and mixed.\n\nBelow is a structured summary focused on mechanisms proposed in the scientific literature.\n\n---\n\n## 1. What is Lion’s Mane (Hericium erinaceus)?\n\n- **Species:** Hericium erinaceus, a tooth fungus with white, cascading spines (“lion’s mane” appearance).\n- **Traditional use:** In Traditional Chinese and Japanese medicine for digestive and general tonic purposes.\n- **Key bioactive classes** (from fruiting body and mycelium) [3][4][5]:\n  - **Terpenoids:**  \n    - *Hericenones* – mainly from the fruiting body  \n    - *Erinacines* – mainly from the mycelium  \n  - **Polysaccharides (β-glucans)**\n  - **Phenolic compounds & ergothioneine**\n  - Other sterols and small molecules (e.g., isoindolinones)\n\nThese compounds are being investigated particularly for **neuroprotective and neuroregenerative** properties.\n\n---\n\n## 2. Main Proposed Mechanisms for Cognitive / Neurological Effects\n\n### 2.1 Nerve Growth Factor (NGF) & Other Neurotrophic Factors\n\nThis is the central proposed mechanism.\n\n- **NGF stimulation:**  \n  - Hericenones and erinacines have repeatedly been shown in vitro and in animal models to **stimulate NGF synthesis and expression** [3][4][5][6].\n  - NGF is critical for **growth, maintenance, and survival of neurons**, particularly cholinergic neurons implicated in learning and memory.\n\n- **Neurite outgrowth & connectivity:**  \n  - UQ work and related studies found lion’s mane extracts and isolated compounds **promote neurite outgrowth (axon/dendrite growth)** and **increase the size of growth cones** in cultured neurons, enhancing the ability of neurons to extend processes and form new connections [1].\n  - This is consistent with **increased structural plasticity**, a basis for learning and memory.\n\n- **Blood–brain barrier penetration:**  \n  - Erinacines especially are reported to **cross the blood–brain barrier** and exert neurotrophic effects in the brain [3][4].\n  - This is important because many NGF-modulating agents can’t reach the CNS when taken orally.\n\n- **Other neurotrophic factors:**  \n  - Some studies suggest upregulation of **BDNF (brain-derived neurotrophic factor)**, another key molecule for **synaptic plasticity, learning, and memory consolidation** [2][4], though this is less well established than NGF.\n\n**Relevance to cognition:**  \nEnhancement of NGF/BDNF and neurite outgrowth could support **neurogenesis, synaptic remodeling, and resilience of existing circuits**, all relevant to memory and learning, especially in aging or neurodegenerative conditions.\n\n---\n\n### 2.2 Neuroprotection: Anti-Oxidant & Anti-Inflammatory Actions\n\nLion’s mane appears to protect neurons not only by promoting growth, but also by reducing damage.\n\n- **Antioxidant effects** [3][4][5]:\n  - Phenolics, ergothioneine, and polysaccharides show **free radical scavenging** and **reduction of oxidative stress** in cell and animal models.\n  - Oxidative stress is a major driver of neuronal damage in aging and neurodegenerative diseases.\n\n- **Anti-inflammatory effects** [3][4]:\n  - Extracts modulate inflammatory pathways such as **NF-κB** and **COX-2**, reducing pro-inflammatory cytokines.\n  - In animal models, this neuroinflammatory reduction is associated with **neuroprotection** and improved behavior.\n\n- **Protection in disease models:**  \n  In various rodent models (e.g., amyloid-β–induced Alzheimer’s-like pathology, aluminum chloride models) [3][4]:\n  - Lion’s mane increased NGF mRNA in the hippocampus.\n  - Reduced neuroinflammatory markers.\n  - Preserved or improved **spatial, short-term, and visual recognition memory** relative to untreated controls.\n\n**Relevance to cognition:**  \nBy reducing oxidative damage and inflammation in the brain, lion’s mane might **slow or mitigate processes that degrade cognitive function**, particularly in neurodegenerative conditions.\n\n---\n\n### 2.3 Cholinergic System Modulation\n\nThe cholinergic system is heavily implicated in attention and memory, and is one of the main targets in Alzheimer’s disease therapy.\n\n- In an aluminum chloride-induced Alzheimer’s model, lion’s mane **increased acetylcholine and choline acetyltransferase levels** in a dose-dependent manner [3].\n- This suggests potential support for **cholinergic neurotransmission**, which is typically impaired in Alzheimer’s and age-related cognitive decline.\n\n**Relevance to cognition:**  \nImproved cholinergic signaling is associated with better **attention, working memory, and learning**.\n\n---\n\n### 2.4 Neurogenesis and Synaptic Plasticity\n\n- Animal work suggests lion’s mane may **promote neurogenesis**, particularly in the hippocampus (a key learning and memory center), via NGF and possibly BDNF upregulation [3][4].\n- Enhanced **synaptic plasticity** (changes in synaptic strength and number) is inferred from:\n  - Increased neurite outgrowth.\n  - Improved behavioral outcomes in learning/memory tasks.\n\n**Relevance to cognition:**  \nNeurogenesis and synaptic plasticity are core mechanisms underlying **long-term memory formation and adaptation**.\n\n---\n\n### 2.5 Stress, Mood, and HPA Axis Modulation\n\nSome human and animal data point to **anxiolytic and stress-reducing** effects.\n\n- A placebo-controlled trial in healthy adults found that 28 days of lion’s mane supplementation:\n  - **Improved speed of performance on certain cognitive tasks.**\n  - Showed a **trend toward reduced subjective stress levels** compared with placebo [2][7].\n- Proposed mechanisms:\n  - NGF/BDNF-related changes in **neural circuits for mood and stress**.\n  - Anti-inflammatory and antioxidant effects dampening **neuroinflammation-related mood disturbances**.\n  - Possible modulation of the **HPA axis**, though direct evidence is limited.\n\n**Relevance to cognition:**  \nReduced stress and improved mood can secondarily improve **cognitive performance**, particularly in tasks requiring sustained attention or working memory.\n\n---\n\n### 2.6 Immunomodulation and Gut–Brain Axis (Emerging)\n\n- β-glucans and other polysaccharides have **immunomodulatory** actions and may influence the **gut microbiota** [3][4].\n- Since immune activation and gut–brain signaling affect brain function, some authors speculate that part of lion’s mane’s cognitive/mood effects may occur via:\n  - Reduced **systemic inflammation**.\n  - Changes in **microbial metabolites** that affect the brain.\n\nThese pathways are plausible but less directly demonstrated for cognition than NGF/BDNF-related mechanisms.\n\n---\n\n## 3. Evidence in Humans vs. Mechanistic Hype\n\nThe mechanistic data (cell culture and animal studies) are relatively strong for several points:\n\n- NGF stimulation and neurite outgrowth.\n- Neuroprotection in toxin or amyloid-based models.\n- Anti-oxidant and anti-inflammatory effects.\n- Improved learning/memory in rodent models.\n\nHowever, human data are still modest:\n\n- A few **small, short-duration clinical trials** in older adults and healthy volunteers show:\n  - Some improvements in **memory measures, performance speed, or mild cognitive impairment scores**.\n  - Some improvements in **mood, anxiety, or stress**.\n- Reviews (e.g., Alzheimer’s Drug Discovery Foundation reports) emphasize that:\n  - **Cognitive effects are mixed**, and\n  - **Larger, longer, better-controlled trials** are needed to confirm efficacy and determine dosing, duration, and which preparations (fruiting body vs. mycelium, specific erinacine/hericenone content) matter most [5][6].\n\n---\n\n## 4. Concise Mechanism Summary\n\nProposed mechanisms for lion’s mane’s cognitive and neurological effects, based on current literature, include:\n\n1. **Neurotrophic stimulation**  \n   - Hericenones and erinacines stimulate **NGF (and possibly BDNF)** synthesis, promoting neurite outgrowth, synaptic plasticity, and neuronal survival.\n\n2. **Neuroprotection**  \n   - Antioxidant and anti-inflammatory effects protect neurons from oxidative stress and neuroinflammation.\n\n3. **Cholinergic enhancement**  \n   - Increased acetylcholine and choline acetyltransferase in animal models suggests support of key neurotransmission for memory.\n\n4. **Neurogenesis and structural plasticity**  \n   - Promotion of neurogenesis and improved structural connectivity in cognitive brain regions (hippocampus, cortex).\n\n5. **Stress and mood modulation**  \n   - Likely via neurotrophic changes, reduced inflammation, and possibly HPA axis modulation, which can indirectly improve cognitive performance.\n\n6. **Immune and gut–brain interactions** (emerging, less direct)  \n   - Immunomodulatory effects and potential microbiome changes may influence brain function and mood.\n\n---\n\nIf you’d like, I can next:  \n- Summarize specific key human trials (design, dose, outcomes), or  \n- Compare fruiting-body vs. mycelium extracts and their different active compounds (hericenones vs. erinacines) in more detail.",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "finish_reason": "stop"
      }
    ],
    "created": 1779391793,
    "model": "sonar-pro",
    "citations": [
      "https://news.uq.edu.au/2023-02-10-mushrooms-magnify-memory-boosting-nerve-growth",
      "https://www.nutraingredients.com/Article/2023/12/01/Mushrooms-for-the-mind-Research-concludes-Lion-s-Mane-improves-cognitive-performance-and-reduces-stress/",
      "https://restorativemedicine.org/journal/neurological-activity-lions-mane-hericium-erinaceus/",
      "https://pmc.ncbi.nlm.nih.gov/articles/PMC12030463/",
      "https://www.alzdiscovery.org/uploads/cognitive_vitality_media/Lions-Mane-Cognitive-Vitality-For-Researchers.pdf",
      "https://www.alzdiscovery.org/cognitive-vitality/ratings/lions-mane",
      "https://pmc.ncbi.nlm.nih.gov/articles/PMC10675414/"
    ],
    "object": "chat.completion",
    "search_results": [
      {
        "title": "Mushrooms magnify memory by boosting nerve growth - UQ News",
        "url": "https://news.uq.edu.au/2023-02-10-mushrooms-magnify-memory-boosting-nerve-growth",
        "date": "2023-02-10",
        "last_updated": "2026-05-21",
        "snippet": "“Pre-clinical testing found the lion's mane mushroom had a significant impact on the growth of brain cells and improving memory. “Laboratory ...",
        "source": "web"
      },
      {
        "title": "Mushrooms for the mind: Research concludes Lion's Mane improves ...",
        "url": "https://www.nutraingredients.com/Article/2023/12/01/Mushrooms-for-the-mind-Research-concludes-Lion-s-Mane-improves-cognitive-performance-and-reduces-stress/",
        "date": "2024-01-08",
        "last_updated": "2026-05-14",
        "snippet": "Previous studies have observed memory and mood enhancements following intakes of Lion's Mane, whilst associations have been noted with cognitive ...",
        "source": "web"
      },
      {
        "title": "Neurological Activity of Lion's Mane (Hericium erinaceus)",
        "url": "https://restorativemedicine.org/journal/neurological-activity-lions-mane-hericium-erinaceus/",
        "date": "2017-12-19",
        "last_updated": "2025-06-15",
        "snippet": "Lion's Mane may be an important herbal remedy for Alzheimer's disease based on early research. This botanical medicine review explores the ...",
        "source": "web"
      },
      {
        "title": "Lion's Mane Mushroom (Hericium erinaceus): A Neuroprotective ...",
        "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC12030463/",
        "date": "2025-04-09",
        "last_updated": "2026-05-07",
        "snippet": "Among them, erinacines have been extensively studied for their ability to cross the blood–brain barrier and exert potent neuroprotective effects [30,72].",
        "source": "web"
      },
      {
        "title": "[PDF] Lion's Mane Mushroom - Alzheimer's Drug Discovery Foundation",
        "url": "https://www.alzdiscovery.org/uploads/cognitive_vitality_media/Lions-Mane-Cognitive-Vitality-For-Researchers.pdf",
        "date": null,
        "last_updated": "2026-05-15",
        "snippet": "Cognitive effects with lion's mane supplementation have been mixed based on a few small pilot clinical trials. Larger, longer duration trials are needed to ...",
        "source": "web"
      },
      {
        "title": "Lion's Mane & Your Brain | Cognitive Vitality",
        "url": "https://www.alzdiscovery.org/cognitive-vitality/ratings/lions-mane",
        "date": "2025-09-03",
        "last_updated": "2026-05-02",
        "snippet": "Cognitive effects with Lion's mane have been mixed based on small and short-duration clinical trials. Preclinical studies suggest that Lion's ...",
        "source": "web"
      },
      {
        "title": "The Acute and Chronic Effects of Lion's Mane Mushroom ... - PMC",
        "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC10675414/",
        "date": "2023-11-20",
        "last_updated": "2026-05-16",
        "snippet": "Conclusions: The findings tentatively suggest that Hericium erinaceus may improve speed of performance and reduce subjective stress in healthy, ...",
        "source": "web"
      }
    ],
    "status": null,
    "type": null,
    "usage": {
      "completion_tokens": 2063,
      "cost": {
        "input_tokens_cost": 0.0001,
        "output_tokens_cost": 0.03095,
        "total_cost": 0.03704,
        "citation_tokens_cost": null,
        "reasoning_tokens_cost": null,
        "request_cost": 0.006,
        "search_queries_cost": null
      },
      "prompt_tokens": 32,
      "total_tokens": 2095,
      "citation_tokens": null,
      "num_search_queries": null,
      "reasoning_tokens": null,
      "search_context_size": "low"
    }
  }
  ```
</Accordion>

<Warning>
  Date filters are **not supported** with `search_mode="academic"` and are silently ignored. This includes `search_after_date_filter`, `search_before_date_filter`, `search_recency_filter`, `last_updated_after_filter`, and `last_updated_before_filter`. To narrow academic results by date, include the desired time range directly in your query text (e.g., "findings on neural networks since 2023").
</Warning>

## SEC Filings Filter

Target U.S. Securities and Exchange Commission filings and official financial documents.

**Key parameters:**

* `search_mode`: Set to `"sec"` to target SEC filings

```python theme={null}
from perplexity import Perplexity

client = Perplexity()

completion = client.chat.completions.create(
    model="sonar-pro",
    messages=[{"role": "user", "content": "Prepare me for markets opening."}],
    search_mode="sec"
)

# Combine with date filters for recent filings
completion = client.chat.completions.create(
    model="sonar",
    messages=[{"role": "user", "content": "Explain what a 10-K filing is, who is required to file one, and the typical structure of the document."}],
    search_mode="sec",
    search_after_date_filter="1/1/2023"
)
```

<AccordionGroup>
  <Accordion title="Response — Prepare me for markets opening.">
    ```json theme={null}
    {
      "id": "ffc90d76-a3a0-43e8-bd5c-b061c1986c0f",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "Here’s a concise, practical pre‑market checklist you can follow before the next US session (NYSE/NASDAQ open at 9:30 a.m. ET).\n\n---\n\n## 1. Know the Session You’re Trading\n\n- Regular US cash session: 9:30–16:00 ET  \n- Pre‑market (depending on broker): often ~4:00–9:30 ET  \nDecide:  \n- Are you trading only regular hours, or also pre‑market/after‑hours?  \n- Are you a day trader, swing trader, or longer‑term? Your routine should match that.\n\n---\n\n## 2. Review the Bigger Picture (Top‑Down)\n\n**A. Index futures & global markets**  \nBefore the open, check:\n\n- S&P 500 / Nasdaq / Dow futures (ES, NQ, YM) – are they strongly up, down, or flat?\n- Key foreign markets that traded before the US:\n  - Europe (DAX, FTSE, Euro Stoxx)\n  - Asia (Nikkei, Hang Seng, etc.)\n\nThis tells you: “Risk‑on or risk‑off?” If risk is off and everything is red, you’ll weigh shorts/defensive names more heavily; if risk‑on, focus on long setups.\n\n**B. Economic calendar & events**\n\nCheck a reliable calendar (e.g., Forex Factory, Investing.com, your broker) for:\n\n- Major releases: CPI, PPI, NFP, GDP, FOMC, Fed speakers, etc.\n- Time of the event vs. your planned trades:\n  - Before open: may cause big gaps.\n  - Shortly after open: volatility spikes around the release.\n\nIf a huge report is 10–15 minutes after the open, consider reducing exposure or waiting until after the data.\n\n---\n\n## 3. Build/Update Your Watchlist the Day Before\n\nDo this after the close, then refine it pre‑market:\n\n1. **Scan for strong/weak names**:\n   - Strong uptrends, holding above key moving averages / prior resistance.\n   - Weak downtrends, rejecting resistance, breaking support.\n2. **Separate lists**:\n   - “Bullish list”: names you’re interested in buying if market confirms strength.\n   - “Bearish list”: names you’re interested in shorting if market is weak.\n3. **No hard decisions a day ahead**  \nHave *ideas*, not commitments. Your direction depends on how things actually look near the open.\n\n---\n\n## 4. Pre‑Market Routine (Morning of the Session)\n\n### A. News & Catalysts\n\nFocus on **fresh catalysts**, especially for day trades:\n\n- Earnings (beats/misses, guidance).\n- M&A, FDA approvals, major contracts, upgrades/downgrades.\n- Sector or macro news (oil, rates, geopolitics).\n\nFor each candidate, ask:\n- What is the catalyst?\n- Is it big enough to justify today’s move?\n- Is it in line with the broader market theme?\n\n### B. Use Scanners (If You Day Trade)\n\nFrom the scanner, filter for:\n\n- **Pre‑market gappers**: up or down with significant % change.\n- **High volume** vs. normal (relative volume).\n- **Float**: Low float + big volume + fresh news = potential explosive mover (and higher risk).\n\nNarrow to a small list (3–10 names) with:\n- Strong volume.\n- Clear news.\n- Clear price levels (see next step).\n\n---\n\n## 5. Mark Your Key Levels\n\nOn your charting platform, for each watchlist name:\n\n1. Start with **daily chart**:\n   - Recent highs/lows.\n   - Major support/resistance.\n   - Gaps.\n2. Then **intraday (e.g., 15m/5m)**:\n   - Yesterday’s high/low/close.\n   - Pre‑market high and low.\n   - Volume‑heavy zones (VWAP if you use it).\n\nIf you trade ORBs (Opening Range Breakouts) or key‑level breaks:\n- Pre‑market high = key resistance.\n- Pre‑market low = key support.\n- Plan potential entries around these.\n\n---\n\n## 6. Define Trade Plans in Advance\n\nFor each A‑setup on your list, write:\n\n- Direction: Long or short?\n- Trigger:  \n  - Example: “Long above pre‑market high with volume confirmation.”  \n  - Example: “Short on failed breakout above yesterday’s high.”\n- Stop loss:\n  - Based on technical level (below recent low, above resistance, etc.).\n- Profit targets:\n  - First target at logical resistance/support.\n  - Decide partial vs full exits.\n- Maximum risk per trade and per day:\n  - e.g., 0.5–1% of account per trade; 2–3% max daily loss.\n\nIf you cannot write the plan in one or two clear sentences, the trade is probably not clean enough.\n\n---\n\n## 7. Risk Management & “No‑Go” Rules\n\nDecide beforehand:\n\n- Max **number of trades**.\n- Max **daily loss** after which you stop trading.\n- No trading after:\n  - Hitting max loss.\n  - Breaking your rules emotionally.\n\nAvoid:\n- Illiquid symbols (thin volume, wide spreads).\n- Names at or near **market‑wide position limit** extremes or with unusual restrictions in derivatives, unless you fully understand the risk.\n\n---\n\n## 8. Time‑of‑Day Discipline\n\nHave a schedule:\n\n- **First 5–10 minutes after the open**:\n  - Volatility & spreads can be extreme.\n  - Consider either small size or no trading until price settles and levels are tested.\n- **Midday (“lunch hour”)**:\n  - Often choppy, low‑volume; many pros avoid initiating new trades then.\n- **Last 5–10 minutes**:\n  - Order imbalances, funds rebalancing; better for experienced traders or closing/adjusting swing positions, not impulsive new entries.\n\n---\n\n## 9. Mental & Practical Setup\n\n- Check platform: orders go through, quotes are real‑time, charts are correct.\n- Prepare order types you’ll use:\n  - Limit vs market, stop vs stop‑limit, bracket orders if available.\n- Clear your head:\n  - No revenge trading from yesterday.\n  - Accept that missing a trade is better than forcing a bad one.\n\nHave one sentence in mind:\n- “My only job is to follow my plan and protect my capital.”\n\n---\n\n## 10. Quick Template You Can Reuse Daily\n\nYou can literally fill this out each morning:\n\n1. Market bias (futures, global markets):  \n   - Bias: Bullish / Bearish / Neutral  \n2. Key macro events today & times:  \n3. Sectors in play (strong/weak):  \n4. Main watchlist (3–10 tickers) with catalysts:  \n   - Ticker – Long/Short – Catalyst – Key levels  \n5. A‑setups (max 3):  \n   - Entry, stop, targets, size  \n6. Risk limits:  \n   - Max loss per trade:  \n   - Max loss per day:  \n7. “No trade” conditions:  \n   - (e.g., choppy open, spreads too wide, news event in 5 min, etc.)\n\n---\n\nIf you tell me:\n- Your time zone,\n- Whether you’re day trading, swing trading, or investing,\n- And what tools/broker you use,\n\nI can turn this into a very specific, timed routine (e.g., what to do from 8:30–9:30 a.m. ET) tailored to you.",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779391587,
      "model": "sonar-pro",
      "citations": [
        "https://www.youtube.com/watch?v=RamId6Zyq3o",
        "https://www.timothysykes.com/blog/how-to-prepare-for-the-stock-market-open-tomorrow/",
        "https://www.youtube.com/watch?v=QlYbiDi4vOU",
        "https://www.youtube.com/watch?v=_LoiBT5LoSo",
        "https://www.sba.gov/business-guide/plan-your-business/market-research-competitive-analysis",
        "https://www.ig.com/uk/trading-strategies/us-stock-market-hours--when-do-the-nyse--nasdaq--dow-jones-and-s-200812",
        "https://vocal.media/journal/5-things-to-know-before-the-stock-market-opens"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "How to Prepare for Your Trading Day in 8 Simple Steps - YouTube",
          "url": "https://www.youtube.com/watch?v=RamId6Zyq3o",
          "date": "2019-12-11",
          "last_updated": "2025-07-17",
          "snippet": "... (Smart Money Approved). Pro Trading School•259K views · 15:46 · Go to channel Equitymaster · If the Market Falls, I Will Do This… Equitymaster• ...",
          "source": "web"
        },
        {
          "title": "How To Prepare For The Stock Market Open Tomorrow",
          "url": "https://www.timothysykes.com/blog/how-to-prepare-for-the-stock-market-open-tomorrow/",
          "date": "2023-01-10",
          "last_updated": "2026-05-21",
          "snippet": "Don't wait until 9:20am EST tomorrow to prepare your watchlist, do it TODAY/TONIGHT and be 100% ready for all the opportunities tomorrow morning!",
          "source": "web"
        },
        {
          "title": "Pre-Market Routine: How I Find The Best Stocks Every Morning",
          "url": "https://www.youtube.com/watch?v=QlYbiDi4vOU",
          "date": "2026-04-07",
          "last_updated": "2026-05-21",
          "snippet": "Most traders waste their pre-market time or skip preparation entirely, and it shows in their results ... market opens at 9:30 AM. This is ...",
          "source": "web"
        },
        {
          "title": "The AXIA Pre-Market Blueprint: How To Prepare Before Markets Open",
          "url": "https://www.youtube.com/watch?v=_LoiBT5LoSo",
          "date": "2026-01-14",
          "last_updated": "2026-05-16",
          "snippet": "... let mevolaxy beats wash over me as I work. 26:44 · Go to channel Axia Futures · 3 Trading Setups Used By Pro Traders. Axia Futures•13K views.",
          "source": "web"
        },
        {
          "title": "Market research and competitive analysis | U.S. Small Business ...",
          "url": "https://www.sba.gov/business-guide/plan-your-business/market-research-competitive-analysis",
          "date": "2026-03-24",
          "last_updated": "2026-05-05",
          "snippet": "Use market research to find customers. Market research blends consumer behavior and economic trends to confirm and improve your business idea.",
          "source": "web"
        },
        {
          "title": "US Stock Markets Opening Hours (UK Hours) - IG",
          "url": "https://www.ig.com/uk/trading-strategies/us-stock-market-hours--when-do-the-nyse--nasdaq--dow-jones-and-s-200812",
          "date": "2026-02-25",
          "last_updated": "2026-05-20",
          "snippet": "Learn the opening hours of the New York Stock Exchange (NYSE), NASDAQ and NASDAQ 100, as well as the Dow Jones and S&P 500, with IG UK.",
          "source": "web"
        },
        {
          "title": "5 Things to Know Before the Stock Market Opens - Vocal Media",
          "url": "https://vocal.media/journal/5-things-to-know-before-the-stock-market-opens",
          "date": "2025-04-04",
          "last_updated": "2025-07-28",
          "snippet": "Before the stock market opens, here are five essential facts to know: 1. Futures on Stock Indexes and the Performance of Global Markets One of the first ...",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 1598,
        "cost": {
          "input_tokens_cost": 2e-05,
          "output_tokens_cost": 0.02397,
          "total_cost": 0.02999,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 7,
        "total_tokens": 1605,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>

  <Accordion title="Response — Explain what a 10-K filing is, who is required to file one, and the typical structure o...">
    ```json theme={null}
    {
      "id": "0fe07f20-b9f9-4f5d-a122-c85f37ed5e47",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "A **Form 10‑K** is the detailed **annual report that U.S. public companies must file with the Securities and Exchange Commission (SEC)**, providing a comprehensive picture of their business, risks, and audited financial performance for the fiscal year.[2][3][7]\n\n### What a 10‑K filing is\n\n- Form 10‑K is an **SEC‑mandated annual disclosure** that gives a full summary of a company’s **business, risk factors, operations, and financial results**, including audited financial statements.[2][3][7]  \n- It is **more detailed and standardized** than the glossy “annual report to shareholders,” although some companies combine the two.[2][3][7][9]  \n- Typical content includes: company history and operations, organizational structure, markets, subsidiaries, executive compensation, major risks, and full financial statements (balance sheet, income statement, cash flow).[1][2][3][7]\n\n### Who is required to file a 10‑K\n\n- **Most U.S. public companies** are required to file a 10‑K annually with the SEC.[3][7][8]  \n- Under SEC rules, companies with **more than \\$10 million in assets** and a class of equity securities held by **more than 2,000 owners** must file annual and other periodic reports, whether or not the securities are exchange‑listed.[2]  \n- The form is used for annual reports filed under **Sections 13 or 15(d) of the Securities Exchange Act of 1934**.[4]  \n- **Non‑U.S. public companies** typically file on other forms (such as Form 20‑F or 40‑F) rather than 10‑K.[5][7]  \n- **Private companies** that do not have registered public securities generally do **not** file 10‑Ks.[8]\n\n### Filing deadlines\n\nThe deadline depends on filer status under SEC rules:[4][5][6]\n\n- **Large accelerated filers**: within **60 days** after fiscal year‑end.[4][5]  \n- **Accelerated filers**: within **75 days** after fiscal year‑end.[4][5]  \n- **All other registrants** (including smaller reporting companies): within **90 days**.[4][5][6]\n\n### Typical structure and required items in a 10‑K\n\nSEC rules require 10‑Ks to follow a **standard order of topics**, divided into parts and items.[4][6][7] A common structure (for domestic issuers on the modern form) is:\n\n**Part I** – Company and risk overview[6][7]  \n- **Item 1 – Business**: Description of the company’s business, principal products and services, business segments, significant customers, and the markets and geographies in which it operates.[6][7]  \n- **Item 1A – Risk Factors**: Material risks the company faces, such as market, operational, regulatory, liquidity, or cybersecurity risks.  \n- **Item 1B – Unresolved Staff Comments**: Certain outstanding SEC staff comments, if any.  \n- **Item 2 – Properties**: Principal physical properties (offices, plants, facilities) used in operations.[6]  \n- **Item 3 – Legal Proceedings**: Material pending or threatened legal proceedings involving the company.[6][7]  \n- **Item 4 – Mine Safety Disclosures** (for mining companies) or other specialized disclosures, if applicable.\n\n**Part II** – Market information and financial data  \n- **Item 5 – Market for Registrant’s Common Equity, Related Stockholder Matters and Issuer Purchases of Equity Securities**: Where the stock trades, number of holders, dividends, stock repurchases, etc.[6]  \n- **Item 6 – Selected Financial Data** (required historically; smaller companies may have scaled or modified requirements): Multi‑year summary of key financial metrics.[6]  \n- **Item 7 – Management’s Discussion and Analysis (MD&A)**: Management’s narrative explanation of financial condition, results of operations, liquidity, capital resources, and known trends or uncertainties.[6][7]  \n- **Item 7A – Quantitative and Qualitative Disclosures About Market Risk**: Exposures to interest rate, foreign exchange, commodity price and other market risks.[6]  \n- **Item 8 – Financial Statements and Supplementary Data**: **Audited financial statements** (balance sheet, income statement, cash flow statement, and notes), plus any required supplementary schedules.[1][6][7]  \n- **Item 9 – Changes in and Disagreements with Accountants on Accounting and Financial Disclosure**: Disclosures about auditor changes or disagreements.[6]\n\n**Part III** – Governance, management, and ownership  \n- **Item 10 – Directors, Executive Officers and Corporate Governance**: Biographical information and governance details.[6]  \n- **Item 11 – Executive Compensation**: Detailed compensation information for top executives and directors.[2][6]  \n- **Item 12 – Security Ownership of Certain Beneficial Owners and Management**: Major shareholders and management ownership.[6]  \n- **Item 13 – Certain Relationships and Related Transactions, and Director Independence**: Related‑party transactions and independence disclosures.[6]  \n- **Item 14 – Principal Accounting Fees and Services** (auditor fees and services; in older guidance this was grouped with controls/procedures).[6]\n\n**Part IV** – Exhibits and signatures  \n- **Item 15 – Exhibits and Financial Statement Schedules** (and, under older structure, “Controls and Procedures” and “Reports on Form 8‑K”)[4][6]  \n  - Includes lists of exhibits (e.g., material contracts, bylaws, credit agreements), certifications by officers, and any additional financial statement schedules.[4][6]\n\nIn practice, companies may add front‑matter sections (cover page, index, forward‑looking statements disclaimer) and detailed notes, but the **core items and sequence are dictated by the SEC instructions to Form 10‑K**.[4][7]",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779896034,
      "model": "sonar-pro",
      "citations": [
        "https://www.dfinsolutions.com/knowledge-hub/thought-leadership/knowledge-resources/what-10-k-filing",
        "https://en.wikipedia.org/wiki/Form_10-K",
        "https://www.investor.gov/introduction-investing/investing-basics/glossary/form-10-k",
        "https://www.sec.gov/files/form10-k.pdf",
        "https://www.toppanmerrill.com/blog/how-to-navigate-forms-10-k-10-q-20-f-40-f-8-k-and-6-k/",
        "https://guides.newman.baruch.cuny.edu/c.php?g=188202&p=1244183",
        "https://www.sec.gov/files/reada10k.pdf",
        "https://chat.library.berkeleycollege.edu/faq/53831",
        "https://en.wikipedia.org/wiki/Annual_report",
        "https://investors.coca-colacompany.com/filings-reports/annual-filings-10-k"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "What Is A 10-K Filing? - DFIN",
          "url": "https://www.dfinsolutions.com/knowledge-hub/thought-leadership/knowledge-resources/what-10-k-filing",
          "date": "2021-04-02",
          "last_updated": "2026-05-11",
          "snippet": "A Form 10-K discloses all the important business information that investors want to know about companies that are traded on the stock exchange.",
          "source": "web"
        },
        {
          "title": "Form 10-K - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/Form_10-K",
          "date": "2005-02-23",
          "last_updated": "2026-03-07",
          "snippet": "A Form 10-K is an annual report required by the U.S. Securities and Exchange Commission (SEC), that gives a comprehensive summary of a company's financial ...",
          "source": "web"
        },
        {
          "title": "Form 10-K - Investor.gov",
          "url": "https://www.investor.gov/introduction-investing/investing-basics/glossary/form-10-k",
          "date": null,
          "last_updated": "2026-05-23",
          "snippet": "The annual report on Form 10-K provides a comprehensive overview of the company's business and financial condition and includes audited financial statements.",
          "source": "web"
        },
        {
          "title": "[PDF] Form 10-K - SEC.gov",
          "url": "https://www.sec.gov/files/form10-k.pdf",
          "date": null,
          "last_updated": "2025-06-03",
          "snippet": "A. Rule as to Use of Form 10-K. (1) This Form shall be used for annual reports pursuant to Section 13 or 15(d) of the. Securities Exchange Act of 1934 (15 ...",
          "source": "web"
        },
        {
          "title": "How to navigate Forms 10-K, 10-Q, 20-F, 40-F, 8-K and 6-K",
          "url": "https://www.toppanmerrill.com/blog/how-to-navigate-forms-10-k-10-q-20-f-40-f-8-k-and-6-k/",
          "date": "2025-03-19",
          "last_updated": "2026-05-24",
          "snippet": "Form 10-K: The annual financial story. SEC Form 10-K is a report that public companies are required to file annually with the SEC within a ...",
          "source": "web"
        },
        {
          "title": "The 10-K - SEC Filings - Research Guides at Baruch College",
          "url": "https://guides.newman.baruch.cuny.edu/c.php?g=188202&p=1244183",
          "date": "2009-11-02",
          "last_updated": "2026-05-09",
          "snippet": "Filing Dates. Depending on their market cap, companies have 60 to 90 days after the end of their fiscal year to file their 10-K report. Find Bad News.",
          "source": "web"
        },
        {
          "title": "[PDF] Investor Bulletin: How to Read a 10-K - SEC.gov",
          "url": "https://www.sec.gov/files/reada10k.pdf",
          "date": null,
          "last_updated": "2025-05-22",
          "snippet": "The 10-K typically includes more detailed information than the annual report to shareholders. The annual report to shareholders, unlike the 10-K, sometimes ...",
          "source": "web"
        },
        {
          "title": "Q. How do I find a company's 10-K report? - LibAnswers",
          "url": "https://chat.library.berkeleycollege.edu/faq/53831",
          "date": "2023-02-06",
          "last_updated": "2026-03-19",
          "snippet": "A 10-K is an annual report required by the U.S. Securities and Exchange Commission (SEC) that gives a comprehensive summary of a public ...",
          "source": "web"
        },
        {
          "title": "Annual report",
          "url": "https://en.wikipedia.org/wiki/Annual_report",
          "date": "2004-12-13",
          "last_updated": "2026-05-05",
          "snippet": "An annual report is a comprehensive report on a company's activities throughout the preceding year. Annual reports are intended to give shareholders and other interested people information about the company's activities and financial performance....",
          "source": "web"
        },
        {
          "title": "Annual Filings (10-K) - Coca-Cola Investor Relations",
          "url": "https://investors.coca-colacompany.com/filings-reports/annual-filings-10-k",
          "date": "2026-02-20",
          "last_updated": "2026-05-21",
          "snippet": "Filings & Reports · All SEC Filings · Annual Publications · Annual Filings (10-K) · Quarterly Filings (10-Q). Filing Type. View All, 10-K, 10 ...",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 1258,
        "cost": {
          "input_tokens_cost": 8e-05,
          "output_tokens_cost": 0.01887,
          "total_cost": 0.02495,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 26,
        "total_tokens": 1284,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

## Context Size Control

Control how much search context is retrieved to balance cost and comprehensiveness.

**Key parameters:**

* `search_context_size`: Set to `"low"` (default), `"medium"`, or `"high"` within `web_search_options`

```python theme={null}
from perplexity import Perplexity

client = Perplexity()

# Low context (cost-efficient, default)
completion = client.chat.completions.create(
    model="sonar",
    messages=[{"role": "user", "content": "How many stars are estimated to be in the Milky Way galaxy?"}],
    web_search_options={"search_context_size": "low"}
)

# High context (comprehensive)
completion = client.chat.completions.create(
    model="sonar",
    messages=[{"role": "user", "content": "Explain the main causes of the 2008 financial crisis: subprime mortgages, securitization, and the Lehman Brothers collapse."}],
    web_search_options={"search_context_size": "high"}
)
```

<AccordionGroup>
  <Accordion title="Response — How many stars are estimated to be in the Milky Way galaxy?">
    ```json theme={null}
    {
      "id": "c60435ea-ca68-400f-b997-a588b269c449",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "Astronomers estimate that the **Milky Way contains on the order of a few hundred billion stars, roughly between 100–400 billion**, with many recent discussions centering around **~200–400 billion** as the most plausible range.[1][2][3]  \n\nBecause we cannot count every star directly, this is an informed estimate rather than an exact number:\n\n- **Commonly cited range:** Most references give **100–400 billion stars**.[2][3][7]  \n- **More up‑to‑date analyses:** Work combining star counts with mass estimates and Gaia data suggests the total is **unlikely as low as 100 billion and more likely in the ~200–400 billion range**.[1]  \n- **Why there is uncertainty:**  \n  - Very faint, low‑mass stars are hard to detect, especially far from the Sun.[2]  \n  - Estimates rely on measuring the **total stellar mass** of the galaxy and dividing by an assumed *average* stellar mass, which depends on models of the stellar mass distribution.[1][3]  \n\nSo the best concise answer is: **the Milky Way probably contains a few hundred billion stars, on the order of 10¹¹, typically quoted as about 100–400 billion, with ~200–400 billion considered most likely.**[1][2][3]",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779896024,
      "model": "sonar-pro",
      "citations": [
        "https://bigthink.com/starts-with-a-bang/how-many-stars-milky-way/",
        "https://en.wikipedia.org/wiki/Milky_Way",
        "https://asd.gsfc.nasa.gov/blueshift/index.php/2015/07/22/how-many-stars-in-the-milky-way/",
        "https://arxiv.org/html/2508.13665v1",
        "https://www.youtube.com/watch?v=gPZABF3Kssw",
        "https://lco.global/spacebook/galaxies/the-milky-way-galaxy/",
        "https://www.cloudynights.com/forums/topic/951234-number-of-stars-in-the-milky-way-estimate-question/"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "Why we still don't know how many stars are in the Milky Way",
          "url": "https://bigthink.com/starts-with-a-bang/how-many-stars-milky-way/",
          "date": "2025-04-02",
          "last_updated": "2025-09-23",
          "snippet": "Current estimates place the most likely number for “stars within the Milky Way” at between 200 billion and 400 billion: an enormous uncertainty.",
          "source": "web"
        },
        {
          "title": "Milky Way - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/Milky_Way",
          "date": "2001-09-15",
          "last_updated": "2026-05-22",
          "snippet": "It is estimated to contain 100–400 billion stars and at least that number of planets. The Solar System is located at a radius ...",
          "source": "web"
        },
        {
          "title": "How Many Stars in the Milky Way? | NASA Blueshift",
          "url": "https://asd.gsfc.nasa.gov/blueshift/index.php/2015/07/22/how-many-stars-in-the-milky-way/",
          "date": "2015-07-22",
          "last_updated": "2026-03-29",
          "snippet": "To make an estimate, we have to calculate the mass of our galaxy, and then the percentage of that mass that is made up of stars. Then we have to ...",
          "source": "web"
        },
        {
          "title": "The Milky Way is a less massive galaxy—new estimates of ... - arXiv",
          "url": "https://arxiv.org/html/2508.13665v1",
          "date": "2025-08-19",
          "last_updated": "2026-05-17",
          "snippet": "Adopting our revised total stellar mass estimate of 2.607 × 10 10 ​ M ⊙ 2.607\\ \\times 10^{10}\\ {\\rm M_{\\odot}} gives a new ratio of 1.6 × 10 − 4 ...",
          "source": "web"
        },
        {
          "title": "Ch. 28: The Milky Way (14 of 27) What is the Mass of the Galaxy?",
          "url": "https://www.youtube.com/watch?v=gPZABF3Kssw",
          "date": "2020-05-21",
          "last_updated": "2026-05-19",
          "snippet": "We will learn how to calculate the mass of our Milky Way Galaxy. ... 28: The Milky Way (15 of 27) Globular Star Clusters. Michel van Biezen ...",
          "source": "web"
        },
        {
          "title": "The Milky Way Galaxy - Las Cumbres Observatory",
          "url": "https://lco.global/spacebook/galaxies/the-milky-way-galaxy/",
          "date": null,
          "last_updated": "2026-05-15",
          "snippet": "The galaxy we live in, called the Milky Way Galaxy, is a barred spiral galaxy composed of at least 100 billion stars. It is approximately 100,000 light years ...",
          "source": "web"
        },
        {
          "title": "Number of Stars in the Milky Way Estimate question - Cloudy Nights",
          "url": "https://www.cloudynights.com/forums/topic/951234-number-of-stars-in-the-milky-way-estimate-question/",
          "date": "2025-01-14",
          "last_updated": null,
          "snippet": "So, 100-400 billion stars is as good an estimate as any, but the number is a guess based on density and size. Each time the size estimate ...",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 278,
        "cost": {
          "input_tokens_cost": 4e-05,
          "output_tokens_cost": 0.00417,
          "total_cost": 0.01021,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 14,
        "total_tokens": 292,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>

  <Accordion title="Response — Explain the main causes of the 2008 financial crisis: subprime mortgages, securitizatio...">
    ```json theme={null}
    {
      "id": "23d8e2d8-9b67-4ccc-a84a-3b3f25108749",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "The 2008 financial crisis grew out of a housing bubble financed by **subprime mortgages**, amplified by **securitization of those mortgages into complex securities**, and turned into a global panic when **Lehman Brothers was allowed to fail in September 2008**.[2][5]  \n\nBelow is how those three pieces fit together.\n\n---\n\n## 1. Subprime mortgages: risky loans at the core\n\n**What “subprime” means**\n\n- **Subprime mortgages** are home loans to borrowers with **poor credit histories, low incomes, or high debt**, meaning a higher risk they will not repay.[2][5]  \n- Through the early–mid‑2000s, **low interest rates and relaxed lending standards** encouraged banks to issue a high volume of these loans.[2][3]  \n\n**How subprime lending helped create a bubble**\n\n- Cheap credit plus loose standards led to a **surge in mortgage lending**, including to people who previously would not have qualified.[2][4]  \n- This helped push **house prices to “ever-greater heights”** in the 2000s, forming a housing bubble.[2][6]  \n- Lenders increasingly used **“exotic” or non‑traditional mortgages**—adjustable-rate, low‑documentation (“no income/no job”), interest-only, and high loan‑to‑value loans—which made repayment more fragile.[3][4][5]  \n\n**Why subprime loans blew up**\n\n- Many subprime mortgages had **teaser rates**: low initial payments that **reset to much higher interest rates** after a few years.[1][2]  \n- Borrowers and lenders often assumed **house prices would keep rising**, so borrowers could refinance before payments jumped or, failing that, lenders could foreclose and sell at a profit.[1][3]  \n- When house price growth slowed and then reversed around 2006–2007, that assumption broke.  \n  - Research finds a **“classic lending boom‑bust”**: lending standards deteriorated for at least six years, while loan quality fell, but poor performance was hidden by rapid house price appreciation until prices stalled.[3][6]  \n- As teaser rates reset and prices fell, **defaults and foreclosures surged**, especially among 2006–2007 “vintage” loans.[2][3][5]  \n- The resulting **collapse in housing prices** was the first broad national drop since the Great Depression and triggered massive losses for institutions exposed to those loans.[2][5][6]  \n\nSo, subprime mortgages created a large pool of **toxic assets**—loans very likely to default once house prices stopped rising.\n\n---\n\n## 2. Securitization: turning bad loans into global “safe” assets\n\n**What securitization is**\n\n- **Securitization** is the process by which banks **bundle loans (like mortgages) and sell them as tradable securities**, such as **mortgage‑backed securities (MBS)** and more complex **collateralized debt obligations (CDOs)**.[2][5][6]  \n- Instead of holding mortgages to maturity, **originators sold them into the bond market**, collecting fees and shifting the credit risk to investors.[1][2][3]  \n\n**How securitization fueled risky lending**\n\n- As investor demand for higher‑yield, “safe” assets grew after the early‑2000s recession, **private‑label MBS backed by subprime loans exploded**.[2][3][6]  \n- Because banks could quickly sell mortgages, they had **weaker incentives to enforce traditional lending standards** (thorough income verification, reasonable loan‑to‑value ratios, etc.).[2][3][4]  \n- A study of subprime loans shows **monotonic deterioration in loan quality**, rising combined loan‑to‑value ratios, and more low‑documentation loans throughout 2001–2007—evidence of **lending standards eroding as securitization volumes rose**.[3]  \n- Each step of the securitization chain—from originators to investment banks to structured‑product desks—earned **fees for “packaging and repackaging”** the same underlying mortgages.[1][5]  \n\n**Why the risks were mispriced**\n\n- **Credit‑rating agencies** (Moody’s, S&P, Fitch) frequently rated tranches of MBS and CDOs backed by subprime loans as **AAA**, comparable to **U.S. Treasuries**.[2][5]  \n- Fund managers and banks **relied on these ratings instead of doing their own analysis**, assuming mortgage‑backed securities were low‑risk.[2][7]  \n- Many of these securities were **opaque and complex**, with little regulatory oversight; investors did not fully understand how exposed they were to a downturn in U.S. housing.[2][4][5][7]  \n\n**How securitization transmitted the shock**\n\n- When subprime defaults rose, the value of **MBS and CDOs fell sharply**, inflicting losses on banks, investment funds, and institutions around the world.[2][5][6]  \n- Because many of these securities were used as **collateral in short‑term funding markets (like repo)**, doubts about their value quickly morphed into **funding crises** for heavily leveraged firms.[5][6][7]  \n- The FDIC describes the process as a **housing boom‑bust that exposed vulnerabilities in a highly leveraged, interconnected financial system**, centered on securitized mortgage credit.[6]  \n\nSecuritization transformed a U.S. housing problem into a **global financial crisis** by dispersing subprime risk widely—often under the label of “safe” assets.\n\n---\n\n## 3. Lehman Brothers’ collapse: from crisis to full‑blown panic\n\n**Lehman’s role in the system**\n\n- **Lehman Brothers** was a major Wall Street investment bank heavily involved in **underwriting, trading, and holding mortgage‑backed securities and related derivatives**.[2][5][6]  \n- Like other investment banks, Lehman relied heavily on **short‑term wholesale funding** and was **highly leveraged**, making it vulnerable if lenders lost confidence.[5][6]  \n\n**The lead‑up to failure**\n\n- As subprime defaults rose in 2007 and early 2008, large mortgage‑exposed institutions began to fail or be rescued:  \n  - **Bear Stearns** was taken over by JPMorgan Chase with Federal Reserve support in March 2008.[2]  \n  - **Fannie Mae and Freddie Mac**, which held or guaranteed trillions in mortgages, were placed into U.S. government conservatorship in early September 2008.[2]  \n- Despite writing down mortgage assets and seeking capital, Lehman could not convince markets it was solvent. Counterparties and short‑term lenders began to pull back.  \n\n**Bankruptcy and its impact**\n\n- On **September 15, 2008**, Lehman Brothers filed for **bankruptcy protection**, the largest bankruptcy in U.S. history.[2][5][6]  \n- Unlike Bear Stearns, Fannie, or Freddie, **Lehman was not rescued**, signaling to markets that major institutions could fail with little warning.  \n- According to contemporary accounts and later analyses, Lehman’s failure:  \n  - **Shocked global financial markets**, triggering a **worldwide panic**.[2][5]  \n  - Caused **money markets and interbank lending to seize up**, as institutions no longer trusted each other’s solvency or the value of their collateral.[5][6]  \n  - Forced fire‑sales of assets, further depressing prices of mortgage‑related and other securities, and **amplifying losses across the system**.[6][7]  \n\nThe Lehman collapse did not *cause* the underlying housing or securitization problems, but it **crystallized fears and turned a severe credit crisis into a full systemic meltdown**.\n\n---\n\n## How the three causes fit together\n\nYou can think of the crisis as a chain:\n\n1. **Subprime mortgages**  \n   - Aggressive, poorly underwritten loans, often with teaser rates and high leverage, created a **large stock of fragile debt** tied to ever‑rising home prices.[1][2][3][5]  \n\n2. **Securitization of those mortgages**  \n   - These risky loans were **bundled and sold globally** as supposedly safe MBS and CDOs, encouraged by ratings, fee incentives, and weak oversight.[2][3][5][6]  \n   - As defaults rose, the losses were **transmitted across the global financial system**, hitting highly leveraged banks and investors.[2][5][7]  \n\n3. **Lehman Brothers’ collapse**  \n   - Lehman’s failure **validated fears that major institutions holding mortgage‑related assets could suddenly fail**, freezing credit markets and turning a contained financial shock into a **full‑scale global crisis**.[2][5][6]  \n\nIf you like, I can add a short timeline (2001–2009) or a simple diagram-style explanation you could use in an essay or presentation.",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779896046,
      "model": "sonar-pro",
      "citations": [
        "https://www.heritage.org/report/the-subprime-mortgage-market-collapse-primer-the-causes-and-possible-solutions",
        "https://www.ebsco.com/research-starters/economics/subprime-mortgage-crisis",
        "https://www.stlouisfed.org/~/media/files/pdfs/banking/spa_2007_05.pdf",
        "https://predatorylending.duke.edu/business-analysis/evolution-of-mortgage-lending/subprime-lending/",
        "https://en.wikipedia.org/wiki/Subprime_mortgage_crisis",
        "https://www.fdic.gov/media/18636",
        "https://pmc.ncbi.nlm.nih.gov/articles/PMC10009346/",
        "https://www.youtube.com/watch?v=ofVzJIW7dms",
        "https://www.cato.org/policy-report/january/february-2009/lessons-subprime-crisis"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "The Subprime Mortgage Market Collapse: A Primer on the Causes ...",
          "url": "https://www.heritage.org/report/the-subprime-mortgage-market-collapse-primer-the-causes-and-possible-solutions",
          "date": "2008-04-22",
          "last_updated": "2026-03-28",
          "snippet": "Economic Adversity. In some cases, economic adversity has been an important contributing factor in mortgage defaults and foreclosures, notably in the ...",
          "source": "web"
        },
        {
          "title": "Subprime mortgage crisis | Economics | Research Starters - EBSCO",
          "url": "https://www.ebsco.com/research-starters/economics/subprime-mortgage-crisis",
          "date": "2022-01-01",
          "last_updated": "2026-05-24",
          "snippet": "Fueled by low interest rates and relaxed lending standards, banks began issuing a high volume of subprime mortgages to borrowers with poor credit histories, ...",
          "source": "web"
        },
        {
          "title": "[PDF] Understanding the Subprime Mortgage Crisis",
          "url": "https://www.stlouisfed.org/~/media/files/pdfs/banking/spa_2007_05.pdf",
          "date": null,
          "last_updated": "2026-04-20",
          "snippet": "We focus on first-lien loans and consider the 2001 through 2008 sample period. We first discuss the main characteristics of the loans in our database at ...",
          "source": "web"
        },
        {
          "title": "Subprime Lending - American Predatory Lending",
          "url": "https://predatorylending.duke.edu/business-analysis/evolution-of-mortgage-lending/subprime-lending/",
          "date": null,
          "last_updated": "2026-05-11",
          "snippet": "The emergence of these mortgage types was one of many contributing factors to the housing bubble that set the stage for the 2008 financial crisis. After ...",
          "source": "web"
        },
        {
          "title": "Subprime mortgage crisis - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/Subprime_mortgage_crisis",
          "date": "2007-03-15",
          "last_updated": "2026-05-18",
          "snippet": "A continuous buildup of toxic assets in the form of subprime mortgages acted as a catalyst for the Great Recession in the United States. The collapse of the ...",
          "source": "web"
        },
        {
          "title": "[PDF] Origins of the Crisis - FDIC",
          "url": "https://www.fdic.gov/media/18636",
          "date": null,
          "last_updated": "2026-05-06",
          "snippet": "The U.S. financial crisis of 2008 followed a boom and bust cycle in the housing market that originated several years earlier and exposed vulnerabilities in ...",
          "source": "web"
        },
        {
          "title": "Financial production and the subprime mortgage crisis - PMC - NIH",
          "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC10009346/",
          "date": "2023-03-13",
          "last_updated": "2026-04-12",
          "snippet": "The causes of the 2007-8 subprime crisis continue to be the subject of much debate, with explanations ranging from de-regulation and fraudulent behavior to ...",
          "source": "web"
        },
        {
          "title": "The Subprime Mortgage Crisis - Causes and Lessons Learned",
          "url": "https://www.youtube.com/watch?v=ofVzJIW7dms",
          "date": "2021-06-29",
          "last_updated": "2026-03-25",
          "snippet": "Visit us at https://lawshelf.com to earn college credit for only $20 a credit! We now offer multi-packs, which allow you to purchase 5 exams ...",
          "source": "web"
        },
        {
          "title": "Lessons from the Subprime Crisis | Cato Institute",
          "url": "https://www.cato.org/policy-report/january/february-2009/lessons-subprime-crisis",
          "date": "2012-08-13",
          "last_updated": "2026-04-03",
          "snippet": "Policies to encourage affordable housing fostered the growth of subprime lending and complex financial products to finance that lending.",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 1929,
        "cost": {
          "input_tokens_cost": 9e-05,
          "output_tokens_cost": 0.02894,
          "total_cost": 0.03503,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 30,
        "total_tokens": 1959,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

<Warning>
  Selecting `"high"` increases search costs due to more extensive web retrieval. Use `"low"` when cost efficiency is critical.
</Warning>

## Search Control

Control when web search is performed using the search classifier or by disabling search entirely.

**Key parameters:**

* `enable_search_classifier`: Let AI decide when to search (boolean)
* `disable_search`: Disable web search completely (boolean)

```python theme={null}
from perplexity import Perplexity

client = Perplexity()

# Search classifier (AI decides when to search)
completion = client.chat.completions.create(
    model="sonar-pro",
    messages=[{"role": "user", "content": "What is the difference between superconducting, trapped-ion, and photonic qubit architectures?"}],
    enable_search_classifier=True
)

# Disable search completely
completion = client.chat.completions.create(
    model="sonar-pro",
    messages=[{"role": "user", "content": "What is 2 + 2?"}],
    disable_search=True
)
```

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "5ca2fa94-7a99-436d-9ff1-8568f0166f4f",
    "choices": [
      {
        "delta": {
          "content": "",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "index": 0,
        "message": {
          "content": "Here’s the high-level difference among the three qubit architectures:\n\n## 1) Superconducting qubits\n- **What they are:** Tiny circuits made from superconducting materials, usually involving **Josephson junctions**.\n- **How they work:** Information is stored in microwave-frequency quantum states of the circuit.\n- **Control:** Driven with **microwave pulses**.\n- **Strengths:**\n  - Very fast gate operations\n  - Mature chip-fabrication style technology\n  - Good for scalable, on-chip integration\n- **Weaknesses:**\n  - Shorter coherence times than trapped ions\n  - Sensitive to noise and materials imperfections\n  - Connectivity is often limited to near-neighbor qubits\n\n## 2) Trapped-ion qubits\n- **What they are:** Individual **ions** held in place by electromagnetic fields.\n- **How they work:** Quantum information is stored in internal atomic states of the ions.\n- **Control:** Manipulated mainly with **lasers**.\n- **Strengths:**\n  - Very long coherence times\n  - High-fidelity gates\n  - Often **all-to-all connectivity** in small systems\n- **Weaknesses:**\n  - Gates are slower than superconducting qubits\n  - Hardware is more complex and harder to scale\n  - Large systems require sophisticated ion-shuttling or photonic linking schemes\n\n## 3) Photonic qubits\n- **What they are:** Qubits encoded in **photons**.\n- **How they work:** Quantum information is stored in properties of light, such as polarization, path, or time-bin.\n- **Control:** Uses **optical components** like beam splitters, phase shifters, and detectors.\n- **Strengths:**\n  - Excellent for communication and networking\n  - Photons are robust against some types of decoherence\n  - Can operate at or near room temperature in some setups\n- **Weaknesses:**\n  - Two-qubit gates are difficult because photons don’t naturally interact strongly\n  - Building large-scale universal photonic computers is challenging\n  - Often relies on probabilistic operations or measurement-based schemes\n\n## Simple comparison\n- **Superconducting:** fast, chip-based, but noisier\n- **Trapped-ion:** precise, long-lived, but slower\n- **Photonic:** great for transmitting quantum information, but harder to make qubits interact\n\n## Rule of thumb\n- If you want **speed and chip integration**: superconducting\n- If you want **high fidelity and long coherence**: trapped-ion\n- If you want **quantum communication or light-based computing**: photonic\n\nIf you want, I can also give you a **table comparing coherence time, gate speed, connectivity, and scalability** for these three.",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "finish_reason": "stop"
      }
    ],
    "created": 1779391592,
    "model": "sonar-pro",
    "citations": [
      "https://www.pnas.org/doi/10.1073/pnas.1618020114",
      "https://pennylane.ai/qml/demos/tutorial_trapped_ions",
      "https://iontrap.duke.edu/2017/03/13/trapped-ions-vs-superconductors/",
      "https://www.youtube.com/watch?v=floIDDd6ZXA",
      "https://www.spinquanta.com/news-detail/main-types-of-qubits",
      "https://pubs.aip.org/avs/aqs/article/3/3/033801/570603/Comparison-of-cloud-based-ion-trap-and"
    ],
    "object": "chat.completion",
    "search_results": [
      {
        "title": "Experimental comparison of two quantum computing architectures",
        "url": "https://www.pnas.org/doi/10.1073/pnas.1618020114",
        "date": "2017-03-28",
        "last_updated": "2026-05-19",
        "snippet": "Whereas the superconducting system offers faster gate clock speeds and a solid-state platform, the ion-trap system features superior qubits and reconfigurable ...",
        "source": "web"
      },
      {
        "title": "Trapped ion quantum computers | PennyLane Demos",
        "url": "https://pennylane.ai/qml/demos/tutorial_trapped_ions",
        "date": "2021-11-09",
        "last_updated": "2026-05-16",
        "snippet": "Trapped ions have relatively long coherence times, which means that the qubits are long-lived. Moreover, they can easily interact with their ...",
        "source": "web"
      },
      {
        "title": "Trapped Ions vs. Superconductors",
        "url": "https://iontrap.duke.edu/2017/03/13/trapped-ions-vs-superconductors/",
        "date": "2017-03-13",
        "last_updated": "2026-03-10",
        "snippet": "The performance is seen to mirror the connectivity of the systems, with the ion trap system out-performing the superconducting system on all ...",
        "source": "web"
      },
      {
        "title": "Superconducting Qubits vs Trapped Ions. Ilya Besedin and Moritz ...",
        "url": "https://www.youtube.com/watch?v=floIDDd6ZXA",
        "date": "2023-11-15",
        "last_updated": "2025-10-23",
        "snippet": "Dr. Ilya Besedin is a PostDoc in the Quantum Device Lab at ETH Zurich. He is working in quantum computing based on superconducting circuits.",
        "source": "web"
      },
      {
        "title": "9 Types of Qubits Driving Quantum Computing Forward [2025] - SpinQ",
        "url": "https://www.spinquanta.com/news-detail/main-types-of-qubits",
        "date": "2025-03-28",
        "last_updated": "2026-05-09",
        "snippet": "Trapped ion qubits are based on individual ions (charged atoms) that are trapped in electromagnetic fields. Quantum information is stored in the ...",
        "source": "web"
      },
      {
        "title": "Comparison of cloud-based ion trap and superconducting quantum ...",
        "url": "https://pubs.aip.org/avs/aqs/article/3/3/033801/570603/Comparison-of-cloud-based-ion-trap-and",
        "date": "2021-09-29",
        "last_updated": "2025-02-14",
        "snippet": "Superconducting systems generally have fewer connections because of the two-dimensional wiring between nearest-neighbor Josephson junctions. On ...",
        "source": "web"
      }
    ],
    "status": null,
    "type": null,
    "usage": {
      "completion_tokens": 579,
      "cost": {
        "input_tokens_cost": 6e-05,
        "output_tokens_cost": 0.00869,
        "total_cost": 0.01474,
        "citation_tokens_cost": null,
        "reasoning_tokens_cost": null,
        "request_cost": 0.006,
        "search_queries_cost": null
      },
      "prompt_tokens": 20,
      "total_tokens": 599,
      "citation_tokens": null,
      "num_search_queries": null,
      "reasoning_tokens": null,
      "search_context_size": "low"
    }
  }
  ```
</Accordion>

<Warning>
  Pricing remains the same regardless of whether search is triggered. Search control is for performance optimization, not cost reduction.
</Warning>

## Combining Filters

You can combine multiple filters for precise control over search results:

```python theme={null}
from perplexity import Perplexity

client = Perplexity()

# Combine domain, language, date, and context size filters
completion = client.chat.completions.create(
    model="sonar-pro",
    messages=[{"role": "user", "content": "Explain what quantum error correction is and why it is essential for fault-tolerant quantum computing."}],
    search_domain_filter=["nature.com", "science.org", "arxiv.org"],
    search_language_filter=["en", "de"],
    search_recency_filter="month",
    web_search_options={"search_context_size": "high"}
)
```

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "74bf0b53-1c08-4d5a-bcf9-8d87acc51944",
    "choices": [
      {
        "delta": {
          "content": "",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "index": 0,
        "message": {
          "content": "Quantum error correction (QEC) is a set of techniques that **encode one “logical” qubit into many “physical” qubits** so that errors from noise and decoherence can be *detected and corrected without measuring or destroying the quantum information*.[1][2][6] It is essential for **fault‑tolerant quantum computing** because, without it, the high error rates of physical qubits make long or large‑scale quantum algorithms effectively impossible.[2][3][7]\n\n### What quantum error correction is\n\n- **Basic idea**  \n  Quantum error correction protects quantum information from **decoherence, noise, and imperfect operations** by spreading the information of a single qubit across an entangled state of many qubits, forming a **quantum error‑correcting code (QECC)**.[1][6][7]  \n  The encoded qubit is called a **logical qubit**, and the underlying qubits are **physical qubits**.[2][6]\n\n- **How it works (conceptual steps)**[1][6][7]  \n  1. **Encoding**: Extra **ancilla** (helper) qubits are added and an encoding circuit maps a single‑qubit state into a special subspace of a larger Hilbert space (the code space).[1]  \n  2. **Storage / computation**: The encoded logical qubits undergo gates and idle time, during which **local errors** (bit flips, phase flips, or combinations) may occur on some physical qubits.[1][4]  \n  3. **Syndrome measurement and recovery**: Carefully designed measurements (often “stabilizer” measurements) extract an **error syndrome**—information about *which error occurred*—without revealing the encoded quantum state itself.[1][3][4] Based on the syndrome, a **recovery operation** is applied to correct the error and return the state to the code space.[1][4][7]\n\n- **Key properties that make QEC possible**  \n  - **Digitization of errors**: Although physical noise is continuous, QEC theory shows that it is enough to correct a finite set of basic errors (typically Pauli \\(X\\), \\(Z\\), and \\(Y\\)); any small error can be decomposed into these and is effectively corrected if those are corrected.[4][5]  \n  - **No‑cloning workaround**: Because we cannot copy an unknown quantum state, QEC uses **entanglement** and **indirect measurements** of stabilizers (not of the qubit itself) to detect errors without collapsing superpositions.[1][3][4]  \n  - **Stabilizer codes**: Many practical codes (e.g., Shor code, surface code) are **stabilizer codes**, defined by a set of commuting operators whose joint +1 eigenspace is the code space.[1][4] Measuring stabilizers gives error syndromes.\n\n### Why QEC is essential for fault‑tolerant quantum computing\n\n- **Physical qubits are very noisy**  \n  Real qubits suffer from **decoherence, control errors, crosstalk, and imperfect measurements**, with error rates far above what is acceptable for large algorithms.[2][3][7] Even a single uncorrected error can invalidate an entire computation, and long algorithms require **millions to trillions of gate operations**.[2][7] Without protection, errors accumulate faster than we can compute.\n\n- **From noisy physical qubits to reliable logical qubits**  \n  QEC allows us to construct **logical qubits whose effective error rate is much lower** than that of the underlying physical qubits, by adding redundancy and performing continuous error detection and correction.[2][3][6][7]  \n  By increasing the code size (more physical qubits per logical qubit), the logical error rate can, in principle, be **suppressed arbitrarily**, as long as physical error rates are below a certain **fault‑tolerance threshold**.[4][8]\n\n- **Fault tolerance vs. error correction**  \n  - **Quantum error correction**: A scheme for protecting encoded information from noise by detecting and correcting errors.[1][7]  \n  - **Fault tolerance**: Builds on QEC to ensure that **errors anywhere in the circuit—including during gates, measurements, and syndrome extraction—do not spread uncontrollably or overwhelm the code**.[1][4][7] Fault‑tolerant designs require that each logical gate, measurement, and QEC step is implemented so that a small number of physical faults leads to at most a bounded number of logical errors.[4][7]  \n  To build a **useful large‑scale quantum computer**, we need **fault tolerance, not just passive error protection**, and fault tolerance fundamentally relies on QEC.[3][4][7][8]\n\n- **Enabling long and large‑scale algorithms**  \n  Many promising quantum algorithms (e.g., quantum chemistry, materials simulation, breaking large‑key cryptosystems) demand **deep circuits with enormous operation counts**. Hardware improvements alone are unlikely to reduce raw physical error rates enough to run these algorithms reliably.[7][8]  \n  QEC is therefore seen as **the foundational technology** that will turn today’s “fragile demonstrations” into **reliable, industrial‑scale quantum machines**.[2][6][7]\n\n### Intuitive comparison to classical error correction\n\n- In **classical** systems, we add redundancy (e.g., repetition codes, parity bits) to detect and correct bit‑flip errors.  \n- In the **quantum** case, we must handle:\n  - More kinds of errors (bit flip, phase flip, combinations, and general noise)[1][4]  \n  - The **no‑cloning theorem**, which forbids copying unknown quantum states  \n  - The risk that **measurements collapse superpositions**, destroying the computation  \n  QEC overcomes these obstacles by using **entangled codewords and syndrome measurements** that reveal *only* error information, not the encoded logical state.[1][3][4]\n\nIf you’d like, I can next walk through a concrete example like the **Shor code** or the **surface code** to illustrate how a specific quantum error‑correcting code detects and corrects errors step by step.",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "finish_reason": "stop"
      }
    ],
    "created": 1779896036,
    "model": "sonar-pro",
    "citations": [
      "https://en.wikipedia.org/wiki/Quantum_error_correction",
      "https://www.quera.com/quantum-error-correction",
      "https://www.ibm.com/quantum/blog/quantum-error-suppression-mitigation-correction",
      "https://iontrap.duke.edu/files/2025/03/arxiv_sub_v2.pdf",
      "https://www.youtube.com/watch?v=OoQSdcKAIZc",
      "https://q-ctrl.com/topics/what-is-quantum-error-correction",
      "https://www.riverlane.com/quantum-error-correction",
      "https://arxiv.org/abs/1907.11157",
      "https://thequantuminsider.com/2026/03/16/understanding-quantum-error-correction/"
    ],
    "object": "chat.completion",
    "search_results": [
      {
        "title": "Quantum error correction - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Quantum_error_correction",
        "date": "2004-08-11",
        "last_updated": "2026-04-18",
        "snippet": "Quantum error correction (QEC) comprises a set of techniques used in quantum memory and quantum computing to protect quantum information from errors arising ...",
        "source": "web"
      },
      {
        "title": "Quantum Error Correction - QuEra",
        "url": "https://www.quera.com/quantum-error-correction",
        "date": "2026-05-19",
        "last_updated": "2026-05-26",
        "snippet": "Quantum Error Correction (QEC) is the essential foundation of moving quantum computing from fragile demonstrations to reliable, industrial-scale machines.",
        "source": "web"
      },
      {
        "title": "Differences in error suppression, mitigation, and correction - IBM",
        "url": "https://www.ibm.com/quantum/blog/quantum-error-suppression-mitigation-correction",
        "date": "2022-10-20",
        "last_updated": "2025-09-21",
        "snippet": "Error correction is how we hope to achieve our ultimate goal: fault-tolerant quantum computation, where we build up redundancies so that even if ...",
        "source": "web"
      },
      {
        "title": "[PDF] Quantum error correction : an introductory guide",
        "url": "https://iontrap.duke.edu/files/2025/03/arxiv_sub_v2.pdf",
        "date": null,
        "last_updated": "2026-05-25",
        "snippet": "Quantum error correction protocols will play a central role in the realisation of quantum computing; the choice of error correction code will influence the ...",
        "source": "web"
      },
      {
        "title": "Correcting Quantum Errors | Lesson 13 - YouTube",
        "url": "https://www.youtube.com/watch?v=OoQSdcKAIZc",
        "date": "2024-11-13",
        "last_updated": "2026-03-25",
        "snippet": "... quantum.ibm.com/course/foundations-of-quantum-error-correction/correcting-quantum-errors #qiskit #ibmquantum #learnquantum.",
        "source": "web"
      },
      {
        "title": "What is quantum error correction? | Q-CTRL",
        "url": "https://q-ctrl.com/topics/what-is-quantum-error-correction",
        "date": "2026-01-16",
        "last_updated": "2026-05-15",
        "snippet": "Quantum Error Correction - or QEC for short - is an algorithm known to identify and fix errors in quantum computers.",
        "source": "web"
      },
      {
        "title": "Quantum Error Correction: the grand challenge - Riverlane",
        "url": "https://www.riverlane.com/quantum-error-correction",
        "date": "2025-02-26",
        "last_updated": "2025-07-09",
        "snippet": "Quantum error correction is a set of techniques to protect the information stored in qubits from errors and decoherence caused by noise.",
        "source": "web"
      },
      {
        "title": "[1907.11157] Quantum Error Correction: An Introductory Guide - arXiv",
        "url": "https://arxiv.org/abs/1907.11157",
        "date": "2019-07-25",
        "last_updated": "2026-03-23",
        "snippet": "In this review, we provide an introductory guide to the theory and implementation of quantum error correction codes.",
        "source": "web"
      },
      {
        "title": "What Is Quantum Error Correction & How Does It Work",
        "url": "https://thequantuminsider.com/2026/03/16/understanding-quantum-error-correction/",
        "date": "2026-03-16",
        "last_updated": "2026-05-27",
        "snippet": "Quantum error correction is a set of techniques for protecting quantum information from errors caused by decoherence, noise, and imperfect ...",
        "source": "web"
      }
    ],
    "status": null,
    "type": null,
    "usage": {
      "completion_tokens": 1306,
      "cost": {
        "input_tokens_cost": 6e-05,
        "output_tokens_cost": 0.01959,
        "total_cost": 0.02565,
        "citation_tokens_cost": null,
        "reasoning_tokens_cost": null,
        "request_cost": 0.006,
        "search_queries_cost": null
      },
      "prompt_tokens": 21,
      "total_tokens": 1327,
      "citation_tokens": null,
      "num_search_queries": null,
      "reasoning_tokens": null,
      "search_context_size": "low"
    }
  }
  ```
</Accordion>

## Next Steps

<Card title="Sonar Quickstart" icon="rocket" href="/docs/sonar/quickstart">
  Get started with the Sonar API and learn the basics
</Card>


# Media & Attachments
Source: https://docs.perplexity.ai/docs/sonar/media

Send and receive images, videos, and files with the Sonar API

<SonarDeprecationNotice />

## Overview

The Sonar API supports comprehensive media handling: send images and files for analysis, and receive images and videos in responses. This guide covers all media functionality in one place.

## Sending Images

Send images to the API for analysis using either base64 encoding or HTTPS URLs. Images are embedded in the `messages` array alongside text content.

<Warning>
  * Base64 images: Maximum 50 MB per image. Supported formats: PNG, JPEG, WEBP, GIF
  * HTTPS URLs: Must be publicly accessible and point directly to the image file
</Warning>

### Base64 Encoded Images

Use base64 encoding when you have the image file locally:

```python Python SDK theme={null}
from perplexity import Perplexity
import base64

client = Perplexity()

# Read and encode image as base64
with open("path/to/your/image.png", "rb") as image_file:
    base64_image = base64.b64encode(image_file.read()).decode("utf-8")
    image_data_uri = f"data:image/png;base64,{base64_image}"

# Analyze the image
completion = client.chat.completions.create(
    model="sonar-pro",
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "Can you describe this image?"},
                {"type": "image_url", "image_url": {"url": image_data_uri}}
            ]
        }
    ]
)
print(completion.choices[0].message.content)
```

### HTTPS URL Images

Reference images hosted online:

```python Python SDK theme={null}
from perplexity import Perplexity

client = Perplexity()

image_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"

completion = client.chat.completions.create(
    model="sonar-pro",
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "Can you describe the image at this URL?"},
                {"type": "image_url", "image_url": {"url": image_url}}
            ]
        }
    ]
)
print(completion.choices[0].message.content)
```

### Key Parameters

* **Image format**: Use `data:image/{format};base64,{content}` for base64 (e.g., `data:image/png;base64,...`)
* **Token pricing**: Images are tokenized as `(width × height) / 750` tokens, priced at input token rates
* **Supported formats**: PNG (`image/png`), JPEG (`image/jpeg`), WEBP (`image/webp`), GIF (`image/gif`)

## Sending Files

Upload documents (PDF, DOC, DOCX, TXT, RTF) for analysis using URLs or base64 encoding. Files can be provided as publicly accessible URLs or base64 encoded bytes without any prefix.

<Warning>
  Maximum file size is 50MB per file. Files larger than this limit will not be processed.
</Warning>

### Using a Public URL

```python Python SDK theme={null}
from perplexity import Perplexity

client = Perplexity()

completion = client.chat.completions.create(
    model="sonar-pro",
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "Summarize this document"},
                {
                    "type": "file_url",
                    "file_url": {"url": "https://example.com/document.pdf"}
                }
            ]
        }
    ]
)
print(completion.choices[0].message.content)
```

### Using Base64 Encoding

```python Python SDK theme={null}
from perplexity import Perplexity
import base64

client = Perplexity()

# Read and encode file (no prefix needed)
with open("document.pdf", "rb") as file:
    encoded_file = base64.b64encode(file.read()).decode('utf-8')

completion = client.chat.completions.create(
    model="sonar-pro",
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "Summarize this document"},
                {
                    "type": "file_url",
                    "file_url": {"url": encoded_file}  # Just base64 string, no prefix
                }
            ]
        }
    ]
)
print(completion.choices[0].message.content)
```

### Key Parameters

* **Supported formats**: PDF, DOC, DOCX, TXT, RTF
* **Base64 encoding**: Provide only the base64 string without `data:` prefix
* **File size limit**: 50MB per file, maximum 30 files per request
* **URL requirements**: Must be publicly accessible and return the file directly

## Receiving Images

Control which images are returned in API responses using `return_images`, `image_domain_filter`, and `image_format_filter` parameters.

<Info>
  The `return_images` feature is currently only available in the Sonar API.
</Info>

### Basic Image Returns

Enable image returns by setting `return_images: true`:

```python Python SDK theme={null}
from perplexity import Perplexity

client = Perplexity()

completion = client.chat.completions.create(
    model="sonar",
    return_images=True,
    messages=[
        {"role": "user", "content": "Describe the James Webb Space Telescope's deep field observations and what they reveal about the early universe."}
    ]
)
print(completion.choices[0].message.content)
```

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "a44ef176-1cc4-48ac-bc55-20f36992ac00",
    "choices": [
      {
        "delta": {
          "content": "",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "index": 0,
        "message": {
          "content": "The James Webb Space Telescope’s **deep field** observations are ultra-long exposures of tiny patches of sky that reveal thousands of faint, distant galaxies, including objects seen from the Universe’s first billion years and beyond.[1][2][3] They show that the early Universe was already rich with galaxies of very different sizes, shapes, colors, and dust contents, giving astronomers a new way to study how galaxies assembled and evolved.[1][2][4]\n\nWebb’s deep fields matter because its **infrared** instruments can detect light that has been stretched by cosmic expansion out of visible wavelengths and into the infrared, where Webb is optimized to observe.[2][6] That lets astronomers see farther back in time than with Hubble and examine galaxies that were previously too faint, too red, or too obscured by dust to study well.[1][2][3]\n\nWhat the observations reveal about the early universe:\n\n- **Thousands of galaxies** appear in a very small patch of sky, showing that the distant universe was already highly populated with galaxies.[1][2][3]\n- Some galaxies are **extremely red**, which usually means either heavy dust obscuration or an older stellar population with mature stars formed early in cosmic history.[1][3]\n- Many of the farthest galaxies look **small, clumpy, and irregular** rather than like today’s well-ordered spirals and ellipticals, suggesting galaxies were still actively assembling.[4]\n- Webb’s sharp resolution reveals **star clusters, diffuse structure, and faint internal features** in galaxies billions of light-years away, improving measurements of their ages, masses, chemistry, and growth histories.[2][4]\n- Spectroscopic observations have already provided physical details for many targets, including light that traveled for **13.1 billion years**, helping constrain when stars and galaxies were forming.[2]\n- In some fields, Webb is seeing galaxies as they were **less than a billion years after the Big Bang**, extending the observational window into the cosmic dawn.[2][3]\n\nIn short, Webb’s deep fields are not just prettier images; they are a census of the early cosmos that is helping astronomers map when galaxies first appeared, how quickly they grew, how dust and star formation evolved, and how the first large cosmic structures took shape.[1][2][3][4]\n\n",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "finish_reason": "stop"
      }
    ],
    "created": 1779896029,
    "model": "sonar-pro",
    "citations": [
      "https://esawebb.org/images/potm2507a/",
      "https://www.esa.int/Science_Exploration/Space_Science/Webb/Webb_delivers_deepest_image_of_Universe_yet",
      "https://www.space.com/astronomy/james-webb-space-telescope/james-webb-space-telescope-revisits-a-classic-hubble-image-of-over-2-500-galaxies",
      "https://science.nasa.gov/asset/webb/webbs-first-deep-field-nircam-image/",
      "https://www.youtube.com/watch?v=WdTkH1v2NqI",
      "https://science.nasa.gov/mission/webb/",
      "https://www.dailymotion.com/video/x9af4aq"
    ],
    "object": "chat.completion",
    "search_results": [
      {
        "title": "A fresh look at a classic deep field | ESA/Webb",
        "url": "https://esawebb.org/images/potm2507a/",
        "date": "2025-08-01",
        "last_updated": "2026-05-14",
        "snippet": "These deep observations have revealed more than 2500 sources in this tiny patch of sky. Among them are hundreds of extremely red galaxies — some ...",
        "source": "web"
      },
      {
        "title": "Webb delivers deepest image of Universe yet - ESA",
        "url": "https://www.esa.int/Science_Exploration/Space_Science/Webb/Webb_delivers_deepest_image_of_Universe_yet",
        "date": null,
        "last_updated": "2026-03-12",
        "snippet": "This deep field, taken by Webb's Near-Infrared Camera (NIRCam), is a composite made from images at different wavelengths, totaling 12.5 hours – achieving depths ...",
        "source": "web"
      },
      {
        "title": "James Webb Space Telescope revisits a classic Hubble image of ...",
        "url": "https://www.space.com/astronomy/james-webb-space-telescope/james-webb-space-telescope-revisits-a-classic-hubble-image-of-over-2-500-galaxies",
        "date": "2025-08-04",
        "last_updated": "2025-08-04",
        "snippet": "The deep fields were Hubble's most intense stares into the universe, revealing the faintest galaxies at the highest redshifts that Hubble could ...",
        "source": "web"
      },
      {
        "title": "Webb's First Deep Field (NIRCam Image) - NASA Science",
        "url": "https://science.nasa.gov/asset/webb/webbs-first-deep-field-nircam-image/",
        "date": "2022-07-12",
        "last_updated": "2026-05-16",
        "snippet": "Webb's image has fully revealed their bright cores, which are filled with stars, along with orange star clusters along their edges. Not all galaxies in this ...",
        "source": "web"
      },
      {
        "title": "Deepest Ever Deep Field. Where Are The Limits of James Webb?",
        "url": "https://www.youtube.com/watch?v=WdTkH1v2NqI",
        "date": "2024-02-10",
        "last_updated": "2026-05-19",
        "snippet": "... observations and biases 19:53 Breadstick galaxies 31:07 Wen ... James Webb Space Telescope Finally Looked Into Alpha Centauri… What ...",
        "source": "web"
      },
      {
        "title": "James Webb Space Telescope - NASA Science",
        "url": "https://science.nasa.gov/mission/webb/",
        "date": "2023-05-25",
        "last_updated": "2026-05-27",
        "snippet": "Webb is the premier observatory of the next decade, serving thousands of astronomers worldwide. It studies every phase in the history of our Universe.",
        "source": "web"
      },
      {
        "title": "James Webb Space Telescope's First Deep Field Image Is Mind ...",
        "url": "https://www.dailymotion.com/video/x9af4aq",
        "date": "2024-12-07",
        "last_updated": "2025-04-15",
        "snippet": "A deep field image captured by the James Webb Space Telescope is of galaxy cluster SMACS 0723. Credit: NASA, ESA, CSA, and STScI",
        "source": "web"
      }
    ],
    "status": null,
    "type": null,
    "usage": {
      "completion_tokens": 469,
      "cost": {
        "input_tokens_cost": 6e-05,
        "output_tokens_cost": 0.00704,
        "total_cost": 0.0131,
        "citation_tokens_cost": null,
        "reasoning_tokens_cost": null,
        "request_cost": 0.006,
        "search_queries_cost": null
      },
      "prompt_tokens": 20,
      "total_tokens": 489,
      "citation_tokens": null,
      "num_search_queries": null,
      "reasoning_tokens": null,
      "search_context_size": "low"
    }
  }
  ```
</Accordion>

### Filtering Image Domains

Control which image sources are included or excluded:

```python Python SDK theme={null}
from perplexity import Perplexity

client = Perplexity()

# Exclude specific domains (prefix with -)
completion = client.chat.completions.create(
    model="sonar",
    return_images=True,
    image_domain_filter=["-gettyimages.com", "-shutterstock.com"],
    messages=[
        {"role": "user", "content": "What are the defining characteristics of award-winning nature photography?"}
    ]
)

# Include only specific domains
completion = client.chat.completions.create(
    model="sonar",
    return_images=True,
    image_domain_filter=["wikimedia.org", "nasa.gov"],
    messages=[
        {"role": "user", "content": "Describe iconic historical photographs from the 20th century and what each one documents."}
    ]
)
```

<AccordionGroup>
  <Accordion title="Response — What are the defining characteristics of award-winning nature photography?">
    ```json theme={null}
    {
      "id": "009ca52a-40f8-4099-b8b9-530f1713bcb3",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "Award‑winning nature photographs are defined by **strong emotional impact, a clear and original subject/story, excellent composition, and flawless technical execution**, all presented with **authentic, restrained post‑processing**.[1][2][4][5]\n\nKey characteristics judges and editors consistently look for:\n\n1. **Emotional and visual impact**  \n   - The image must **grab attention instantly** and stand out in a field of similar subjects.[1][2][5]  \n   - It typically evokes a strong feeling: awe, serenity, tension, mystery, or curiosity.[1][2]  \n   - Overall “impact” is often scored separately from other criteria in contests.[1][5]\n\n2. **Originality and storytelling**  \n   - Judges value **original perspectives, behavior, or conditions**—not just a technically perfect shot of a common scene.[2][4][5]  \n   - A winning image usually **tells a clear story or suggests one**: survival, vulnerability, power of weather, seasonal change, human–nature relationships, etc.[1][2][4]  \n   - Elements of **mystery** (fog, partial concealment, unusual viewpoints) help keep viewers engaged longer.[2]\n\n3. **Strong, intentional composition**  \n   - There is a **clear point of interest** that the eye goes to first; nothing important competes with it.[1][2][4]  \n   - Use of compositional tools such as:\n     - **Leading lines, framing, and foreground interest** to guide the eye.[1][2]  \n     - Smart use of **rule of thirds / off‑center placement** for dynamism.[1]  \n     - **Simplicity and minimal distractions**—clutter, stray branches, or bright patches are minimized or excluded.[1][2][4]  \n   - Award winners often have a **multi‑layered composition** (foreground, midground, background) or an intentionally minimalist design that feels deliberate.[1][2]\n\n4. **Exceptional use of light**  \n   - Light is rarely “neutral”: it adds **drama, depth, and mood**.[1][2][4]  \n   - Many award‑winning images exploit **golden hour, low‑angle, backlight, side‑light, or storm light** for texture and atmosphere.[1][2]  \n   - Good light also ensures **rich tonal contrast** without losing important detail in shadows or highlights.[1][2]\n\n5. **Technical excellence (craftsmanship)**  \n   - **Critical sharpness** where it matters (eyes in wildlife, key textures in landscapes) and appropriate depth of field.[1][4][5]  \n   - **Accurate, controlled exposure**: no distracting blown highlights, blocked shadows, or excessive noise; use of histogram, bracketing, and manual control is common.[1][4]  \n   - Clean files (no obvious dust spots, halos, or heavy artifacts) and competent handling of motion (freeze vs. blur) that supports the story.[1][4][5]  \n   - Major competitions explicitly score **technical excellence** alongside composition and impact.[5]\n\n6. **Clarity of subject and simplification**  \n   - The frame is **edited in‑camera**: everything included has a purpose.[1][2][4]  \n   - Backgrounds are often simplified using:\n     - **Careful camera position** to avoid bright or messy areas.[1][2]  \n     - **Shallow depth of field** in wildlife/close‑up to isolate the subject.[1]  \n   - Distractions may be controlled later via cropping, as long as the crop supports balance and “breathing room.”[1][2]\n\n7. **Thoughtful, restrained post‑processing**  \n   - Editing **enhances but does not overwhelm** the natural look of the scene.[1][4]  \n   - Judges tend to reject images with **obvious over‑saturation, heavy filters, or unrealistic colors/contrast** in nature categories.[1]  \n   - Many contests stress staying **true to reality** in nature and wildlife divisions, within reasonable artistic latitude.[1][3][6]\n\n8. **Personal vision and fine‑art quality**  \n   - Top‑tier award work shows a **consistent personal style or vision**, not just one lucky frame.[3]  \n   - Organizations like NANPA emphasize **mastery of both artistic and technical aspects** and the ability to create images that are not only beautiful but also **inspire appreciation for nature**.[3]  \n   - This often means a recognizable approach to mood, color palette, composition, or subject choice across a body of work.[3]\n\n9. **Subject choice and significance**  \n   - The subject is often **visually or biologically compelling**: rare behavior, pristine or fragile habitats, dramatic weather, or subtle, intimate scenes that reveal nature in a new way.[1][4][7]  \n   - Strong images frequently **communicate something unique, informative, or thought‑provoking** about the natural world, not just its surface beauty.[4][6]\n\n10. **Ethical and contextual suitability**  \n   - For major contests, nature/wildlife images must typically be of **wild, non‑captive animals in natural settings** and adhere to ethical guidelines.[6]  \n   - Authenticity of behavior and habitat, and respect for the subject and environment, are increasingly part of what makes an image award‑worthy in respected competitions.[3][6]\n\nIf you’d like, I can translate these characteristics into a practical checklist you can use when shooting or editing, or analyze a sample image (described or uploaded) against these criteria.",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779896043,
      "model": "sonar-pro",
      "citations": [
        "https://visualwilderness.com/q-and-a/how-to-capture-award-winning-nature-photographs",
        "https://www.meghanmaloneyphotography.co.nz/post/5-tips-for-an-award-winning-landscape-photo",
        "https://nanpa.org/contests-and-awards/career-awards/fine-art-in-nature-photography/",
        "https://coloradooutdoorsmag.com/2025/12/04/what-makes-a-great-nature-photograph/",
        "https://www.youtube.com/watch?v=DKnfgF-Ee0w",
        "https://en.wikipedia.org/wiki/Nature_photography",
        "https://www.worldnaturephotographyawards.com/winners-2026",
        "https://newyorkphotographyawards.com/nature-photography-awards.php",
        "https://globalphotographyawards.com/nature-photography-awards.php"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "How to Capture Award Winning Nature Photographs",
          "url": "https://visualwilderness.com/q-and-a/how-to-capture-award-winning-nature-photographs",
          "date": "2024-12-14",
          "last_updated": "2025-10-23",
          "snippet": "Whether you're shooting for a competition, a portfolio, or personal satisfaction, winning nature photographs share a few common characteristics.",
          "source": "web"
        },
        {
          "title": "5 tips for capturing an award-winning landscape photo",
          "url": "https://www.meghanmaloneyphotography.co.nz/post/5-tips-for-an-award-winning-landscape-photo",
          "date": "2026-04-16",
          "last_updated": "2025-05-09",
          "snippet": "Award-winning images will combine a strong or unusual composition with interesting lighting to great effect without any distractions allowing ...",
          "source": "web"
        },
        {
          "title": "Fine Art in Nature Photography award - NANPA",
          "url": "https://nanpa.org/contests-and-awards/career-awards/fine-art-in-nature-photography/",
          "date": "2026-04-22",
          "last_updated": "2026-04-30",
          "snippet": "Commitment to achieving a positive impact upon nature photography through the creation of fine art imagery; and · Dedication to educate/instruct other nature ...",
          "source": "web"
        },
        {
          "title": "What makes a great nature photograph? - Colorado Outdoors Online",
          "url": "https://coloradooutdoorsmag.com/2025/12/04/what-makes-a-great-nature-photograph/",
          "date": "2025-12-04",
          "last_updated": "2025-12-20",
          "snippet": "The simple answer would be that a great photograph is a combination of subject matter, lighting, composition, technical expertise and gear ...",
          "source": "web"
        },
        {
          "title": "How-To Win A Nature Photo Contest - YouTube",
          "url": "https://www.youtube.com/watch?v=DKnfgF-Ee0w",
          "date": "2010-03-30",
          "last_updated": "2026-05-18",
          "snippet": "Visit http://bit.ly/13zURQP to enter! You don't have to be a pro to take great pictures of nature and wildlife. Get tips from the experts at ...",
          "source": "web"
        },
        {
          "title": "Nature photography - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/Nature_photography",
          "date": "2006-09-06",
          "last_updated": "2026-05-10",
          "snippet": "Nature photography encompasses a wide range of photography taken outdoors and devoted to displaying natural elements such as landscapes, wildlife, plants, and ...",
          "source": "web"
        },
        {
          "title": "Winners 2026 - world nature photography awards",
          "url": "https://www.worldnaturephotographyawards.com/winners-2026",
          "date": null,
          "last_updated": "2026-05-22",
          "snippet": "Golden autumn colours explode in this intimate portrait of an incredible, lichen-laden elder birch in full seasonal display — bold, brilliant, and full of ...",
          "source": "web"
        },
        {
          "title": "Nature Photography Awards",
          "url": "https://newyorkphotographyawards.com/nature-photography-awards.php",
          "date": "2025-10-02",
          "last_updated": "2025-10-19",
          "snippet": "The Nature Photography award category at the 2026 New York Photography Awards celebrates the beauty and wonder of the natural world.",
          "source": "web"
        },
        {
          "title": "Nature Photography",
          "url": "https://globalphotographyawards.com/nature-photography-awards.php",
          "date": "2021-01-01",
          "last_updated": "2025-10-18",
          "snippet": "The International Nature Photography Awards is a celebration of the natural world in all its wild beauty and diversity.",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 1177,
        "cost": {
          "input_tokens_cost": 4e-05,
          "output_tokens_cost": 0.01766,
          "total_cost": 0.02369,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 12,
        "total_tokens": 1189,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>

  <Accordion title="Response — Describe iconic historical photographs from the 20th century and what each one documents.">
    ```json theme={null}
    {
      "id": "5eb4459b-e477-421d-960a-4bea51d37556",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "Here are several **iconic 20th-century historical photographs** and what each one documents:\n\n- **Earthrise** (1968, Bill Anders) — documents the first color photograph of Earth taken from space, and became a powerful symbol of the planet’s fragility and the environmental movement.[2]\n- **Raising the Flag on Iwo Jima** (1945, Joe Rosenthal) — documents U.S. Marines raising the American flag atop Mount Suribachi during the Battle of Iwo Jima in World War II.[1][2]\n- **V-J Day in Times Square** (“The Kiss,” 1945, Alfred Eisenstaedt) — documents a jubilant kiss between a sailor and a nurse in New York on the day Japan’s surrender marked the end of World War II.[1][4]\n- **Migrant Mother** (1936, Dorothea Lange) — documents Florence Owens Thompson and her children during the Great Depression, becoming an emblem of Depression-era hardship.[1][6][8]\n- **Napalm Girl** / **The Terror of War** (1972, Nick Ut) — documents the horror of the Vietnam War through the image of a severely burned child fleeing a napalm attack.[1][3]\n- **Tank Man** (1989, unidentified photographers, widely circulated from multiple sources) — documents a lone protester standing in front of tanks after the crackdown in Tiananmen Square, becoming a symbol of resistance.[6]\n- **Little Rock integration photograph** (“The Scream Image,” 1957, often associated with news photographer Will Counts) — documents Elizabeth Eckford being harassed by white students while integrating Central High School, and became a key Civil Rights Movement image.[2]\n- **Raising a Soviet flag over the Reichstag** (1945, Yevgeny Khaldei) — documents the Soviet capture of Berlin and the symbolic fall of Nazi Germany.[5]\n- **The Hindenburg disaster** (1937, news photographers including Sam Shere) — documents the airship bursting into flames as it attempted to land, marking a dramatic end to the zeppelin era.[5]\n- **The “Breaker Boys” photographs** (early 1900s, Lewis Hine) — document child labor in coal mines and helped build support for labor reform.[2]\n- **The first powered flight at Kitty Hawk** (1903, Wilbur and Orville Wright photo sequence) — documents the Wright brothers’ first successful airplane flight.[2]\n- **The execution of Nguyễn Văn Lém** / “Saigon Execution” (1968, Eddie Adams) — documents a South Vietnamese police chief shooting a prisoner during the Tet Offensive, becoming one of the defining images of the Vietnam War.[3]\n- **The Burning Monk** (1963, Malcolm Browne) — documents Buddhist monk Thích Quảng Đức’s self-immolation in protest against the South Vietnamese government.[6]\n\nIf you want, I can turn this into a **decade-by-decade timeline** or give you a **shorter top 10 list with one-line descriptions**.",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779896037,
      "model": "sonar-pro",
      "citations": [
        "https://www.artisera.com/blogs/expressions/10-most-iconic-photographs-of-the-20th-century-from-around-the-world",
        "https://historyfacts.com/arts-culture/article/iconic-photos-from-each-decade-of-the-20th-century/",
        "https://www.digitalphotomentor.com/20-most-famous-photographs/",
        "https://historycollection.com/20th-century-photos-that-changed-the-world/",
        "https://www.youtube.com/watch?v=YFNpff9W-BE",
        "https://rarehistoricalphotos.com/100-influential-historical-pictures-all-time/",
        "https://en.wikipedia.org/wiki/List_of_photographs_considered_the_most_important",
        "https://seanchase.wordpress.com/2018/09/25/unforgettable-photographs-of-the-20th-century-immortal-images-of-social-historical-significance/",
        "https://www.life.com/history/the-100-most-important-photos-ever/",
        "https://www.gettyimages.com/photos/20th-century"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "10 Most Iconic Photographs of the 20th Century From ... - Artisera",
          "url": "https://www.artisera.com/blogs/expressions/10-most-iconic-photographs-of-the-20th-century-from-around-the-world",
          "date": "2020-03-24",
          "last_updated": "2026-03-04",
          "snippet": "1. Gandhi and the Spinning Wheel by Margaret Bourke-White, 1946 · 2. Starving Child and Vulture by Kevin Carter, 1993 · 3. The Terror of War by ...",
          "source": "web"
        },
        {
          "title": "Iconic Photos From Each Decade of the 20th Century - History Facts",
          "url": "https://historyfacts.com/arts-culture/article/iconic-photos-from-each-decade-of-the-20th-century/",
          "date": "2024-08-29",
          "last_updated": "2026-04-08",
          "snippet": "Here are some of the most iconic photos from each decade of the last century, from Kitty Hawk, North Carolina, to the far-flung reaches of the universe.",
          "source": "web"
        },
        {
          "title": "20 of the Most Famous Photographs in History - Learn the Backstory",
          "url": "https://www.digitalphotomentor.com/20-most-famous-photographs/",
          "date": "2018-05-14",
          "last_updated": "2025-07-06",
          "snippet": "#1 Henri Cartier-Bresson's famous photo Man Jumping the Puddle | 1930 · #2 The famous photo The Steerage by Alfred Stieglitz | 1907 · #3 Stanley ...",
          "source": "web"
        },
        {
          "title": "20th Century Photos That Changed the World - History Collection",
          "url": "https://historycollection.com/20th-century-photos-that-changed-the-world/",
          "date": "2018-08-23",
          "last_updated": "2026-03-15",
          "snippet": "They cover themes of war and politics, love and hate, peace and violence as well as life and death. These photos achieved both national and international fame ...",
          "source": "web"
        },
        {
          "title": "20 ICONIC Photos of the 20TH Century - YouTube",
          "url": "https://www.youtube.com/watch?v=YFNpff9W-BE",
          "date": "2018-03-02",
          "last_updated": "2025-12-26",
          "snippet": "A lot has happened all over the world in the 20th century. Today, we present some of the most iconic photos that defined the last century.",
          "source": "web"
        },
        {
          "title": "The 100 Most Influential Historical Pictures of All Time",
          "url": "https://rarehistoricalphotos.com/100-influential-historical-pictures-all-time/",
          "date": "2021-03-08",
          "last_updated": "2026-03-05",
          "snippet": "TIME magazine decided to create a list of the 100 most influential pictures ever taken. They teamed up with curators, historians, photo editors, and famous ...",
          "source": "web"
        },
        {
          "title": "List of photographs considered the most important - Wikipedia",
          "url": "https://en.wikipedia.org/wiki/List_of_photographs_considered_the_most_important",
          "date": "2017-08-02",
          "last_updated": "2026-05-20",
          "snippet": "These images may be referred to as the most important, most iconic, or most influential—and are considered key images in the history of photography.",
          "source": "web"
        },
        {
          "title": "Unforgettable Photographs of the 20th Century: Immortal Images of ...",
          "url": "https://seanchase.wordpress.com/2018/09/25/unforgettable-photographs-of-the-20th-century-immortal-images-of-social-historical-significance/",
          "date": "2018-09-25",
          "last_updated": "2025-11-10",
          "snippet": "Collected here are some of the most iconic and socially significant photographs of the 20th Century and the stories behind them.",
          "source": "web"
        },
        {
          "title": "The 100 Most Important Photos Ever - LIFE",
          "url": "https://www.life.com/history/the-100-most-important-photos-ever/",
          "date": "2021-12-07",
          "last_updated": "2026-04-12",
          "snippet": "In our quest to select the most important 100 photographs ever, we looked for pictures that demonstrated something important and meaningful.",
          "source": "web"
        },
        {
          "title": "14591541 20th Century Stock Photos, High-Res Pictures, and Images",
          "url": "https://www.gettyimages.com/photos/20th-century",
          "date": "2005-08-31",
          "last_updated": "2025-04-10",
          "snippet": "Browse 14,591,541 authentic 20th century stock photos, high-res images, and pictures, or explore additional 20th century doctor or farm family 20th century ...",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 638,
        "cost": {
          "input_tokens_cost": 5e-05,
          "output_tokens_cost": 0.00957,
          "total_cost": 0.01562,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 17,
        "total_tokens": 655,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

### Filtering Image Formats

Restrict results to specific file formats:

```python Python SDK theme={null}
from perplexity import Perplexity

client = Perplexity()

# Only return GIF images
completion = client.chat.completions.create(
    model="sonar",
    return_images=True,
    image_format_filter=["gif"],
    messages=[
        {"role": "user", "content": "Explain how transformer self-attention works using a step-by-step conceptual walkthrough."}
    ]
)

# Allow multiple formats
completion = client.chat.completions.create(
    model="sonar",
    return_images=True,
    image_format_filter=["jpeg", "png", "webp"],
    messages=[
        {"role": "user", "content": "Show me images of the Eiffel Tower at night."}
    ]
)
```

<AccordionGroup>
  <Accordion title="Response — Explain how transformer self-attention works using a step-by-step conceptual walkthrough.">
    ```json theme={null}
    {
      "id": "c1b191ba-f6a9-4e4e-8c09-fcc3c1c85638",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "Transformer **self-attention** lets each token in a sequence look at the other tokens and decide which ones matter most for updating its own representation.[1][2] Conceptually, it turns a sentence into a set of context-aware vectors by computing weighted averages of the sequence based on similarity scores.[1][3]\n\nHere is the step-by-step walkthrough:\n\n1. **Start with token embeddings**  \n   Each word or token is first converted into a vector embedding that the model can process numerically.[2][5]\n\n2. **Create Query, Key, and Value vectors**  \n   For each token, the model applies learned linear transformations to produce three vectors: **Query (Q)**, **Key (K)**, and **Value (V)**.[1][2][5]\n\n3. **Compare each query with all keys**  \n   A token’s query is compared with every token’s key, usually by dot product, to produce attention scores that measure relevance.[1][3]\n\n4. **Scale the scores**  \n   The scores are divided by \\(\\sqrt{d_k}\\), where \\(d_k\\) is the key dimension, to keep values numerically stable during training.[1][2][5]\n\n5. **Convert scores into probabilities**  \n   A softmax function turns the scaled scores into attention weights that sum to 1, so the model can interpret them as relative importance values.[1][2][5]\n\n6. **Use the weights to mix the values**  \n   The attention weights are applied to the value vectors, and the weighted sum becomes the new representation for that token.[1][3][5]\n\n7. **Repeat for every token in parallel**  \n   Each token gets its own contextualized output, and transformer self-attention can do this for all positions at once rather than sequentially.[1][3]\n\nA compact intuition is: **Query = what I’m looking for**, **Key = what I contain**, and **Value = the information I will pass along if selected**.[2][5] The result is that each token representation becomes context-aware, which helps the model capture relationships like long-range dependencies and word meaning from surrounding context.[1][3]\n\nIn **multi-head attention**, the model runs several self-attention operations in parallel with different learned projections, then combines their outputs; this lets it capture different kinds of relationships at the same time.[1][3]",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779896040,
      "model": "sonar-pro",
      "citations": [
        "https://www.geeksforgeeks.org/nlp/self-attention-in-nlp/",
        "https://www.ibm.com/think/topics/self-attention",
        "https://uvadlc-notebooks.readthedocs.io/en/latest/tutorial_notebooks/tutorial6/Transformers_and_MHAttention.html",
        "https://www.youtube.com/watch?v=eMlx5fFNoYc&vl=en",
        "https://sebastianraschka.com/blog/2023/self-attention-from-scratch.html",
        "https://www.youtube.com/watch?v=KMHkbXzHn7s",
        "https://www.deeplearning.ai/courses/attention-in-transformers-concepts-and-code-in-pytorch"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "Self - Attention in NLP - GeeksforGeeks",
          "url": "https://www.geeksforgeeks.org/nlp/self-attention-in-nlp/",
          "date": "2026-04-01",
          "last_updated": "2026-05-26",
          "snippet": "It works by first understanding the input and then generating the corresponding output based on that understanding. Encoder: It takes the input ...",
          "source": "web"
        },
        {
          "title": "What is self-attention? | IBM",
          "url": "https://www.ibm.com/think/topics/self-attention",
          "date": "2025-02-18",
          "last_updated": "2026-03-31",
          "snippet": "The transformer architecture includes a self-attention layer where the attention process is integrated. The steps are explained as presented in the paper by ...",
          "source": "web"
        },
        {
          "title": "Tutorial 6: Transformers and Multi-Head Attention",
          "url": "https://uvadlc-notebooks.readthedocs.io/en/latest/tutorial_notebooks/tutorial6/Transformers_and_MHAttention.html",
          "date": null,
          "last_updated": "2026-04-28",
          "snippet": "In contrast to recurrent networks, the self-attention layer can parallelize all its operations making it much faster to execute for smaller sequence lengths.",
          "source": "web"
        },
        {
          "title": "Attention in transformers, step-by-step | Deep Learning Chapter 6",
          "url": "https://www.youtube.com/watch?v=eMlx5fFNoYc&vl=en",
          "date": "2024-04-07",
          "last_updated": "2026-05-26",
          "snippet": "I'm a university lecturer with a PhD in AI, and I cannot compete with the quality of this work. Videos like this put the entire higher ...",
          "source": "web"
        },
        {
          "title": "Understanding and Coding the Self-Attention Mechanism of Large ...",
          "url": "https://sebastianraschka.com/blog/2023/self-attention-from-scratch.html",
          "date": "2023-02-09",
          "last_updated": "2026-05-26",
          "snippet": "In self-attention, we work with the same input sequence. In cross-attention, we mix or combine two different input sequences. In the case of the ...",
          "source": "web"
        },
        {
          "title": "How Attention Mechanism Works in Transformer Architecture",
          "url": "https://www.youtube.com/watch?v=KMHkbXzHn7s",
          "date": "2025-03-08",
          "last_updated": "2026-05-27",
          "snippet": "... attention in transformers is self-attention, where each token in a sequence attends to all other tokens, capturing long-range dependencies ...",
          "source": "web"
        },
        {
          "title": "Attention in Transformers: Concepts and Code in PyTorch",
          "url": "https://www.deeplearning.ai/courses/attention-in-transformers-concepts-and-code-in-pytorch",
          "date": "2025-02-12",
          "last_updated": "2026-05-26",
          "snippet": "Learn the difference between self-attention, masked self-attention, and cross-attention, and how multi-head attention scales the algorithm. About this course.",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 486,
        "cost": {
          "input_tokens_cost": 5e-05,
          "output_tokens_cost": 0.00729,
          "total_cost": 0.01334,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 17,
        "total_tokens": 503,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>

  <Accordion title="Response — Show me images of the Eiffel Tower at night.">
    ```json theme={null}
    {
      "id": "1b0da5ef-c044-4c74-b88f-c5cc15c1459e",
      "choices": [
        {
          "delta": {
            "content": "",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "index": 0,
          "message": {
            "content": "Here are some image sources for the Eiffel Tower at night:\n\n1. iStock: Eiffel Tower Night Images and Stock Photos  \n   https://www.istockphoto.com/photos/eiffel-tower-night\n\n2. Getty Images: Eiffel Tower Night Stock Photos  \n   https://www.gettyimages.com/photos/eiffel-tower-night\n\n3. Adobe Stock: Eiffel Tower Night Search Results  \n   https://stock.adobe.com/search?k=eiffel+tower+night\n\n4. Tripadvisor: Eiffel Tower Tour by Night photo  \n   https://www.tripadvisor.com/LocationPhotoDirectLink-g187147-d11449765-i423267412-Eiffel_Tower_Tour_by_Night-Paris_Ile_de_France.html\n\n5. French Moments: The Eiffel Tower by Night  \n   https://frenchmoments.eu/the-eiffel-tower-by-night/\n\nIf you want, I can also help you find:\n- free-to-use images,\n- high-resolution wallpapers,\n- or a few especially beautiful night photos.",
            "role": "assistant",
            "reasoning_steps": null,
            "tool_call_id": null,
            "tool_calls": null
          },
          "finish_reason": "stop"
        }
      ],
      "created": 1779391773,
      "model": "sonar-pro",
      "citations": [
        "https://www.istockphoto.com/photos/eiffel-tower-night",
        "https://www.toureiffel.paris/en/news/history-and-culture/everything-you-need-know-about-eiffel-tower-night",
        "https://www.gettyimages.com/photos/eiffel-tower-night",
        "https://stock.adobe.com/search?k=eiffel+tower+night",
        "https://www.tripadvisor.com/LocationPhotoDirectLink-g187147-d11449765-i423267412-Eiffel_Tower_Tour_by_Night-Paris_Ile_de_France.html",
        "https://frenchmoments.eu/the-eiffel-tower-by-night/"
      ],
      "object": "chat.completion",
      "search_results": [
        {
          "title": "3661 Eiffel Tower Night Images and Stock Photos - iStock",
          "url": "https://www.istockphoto.com/photos/eiffel-tower-night",
          "date": "2024-04-02",
          "last_updated": "2026-03-07",
          "snippet": "Search from 3661 Eiffel Tower Night stock photos, pictures and royalty-free images from iStock. Get iStock exclusive photos, illustrations, and more.",
          "source": "web"
        },
        {
          "title": "Everything you need to know about the Eiffel Tower at night",
          "url": "https://www.toureiffel.paris/en/news/history-and-culture/everything-you-need-know-about-eiffel-tower-night",
          "date": "2020-04-09",
          "last_updated": "2026-05-05",
          "snippet": "Photographing the Eiffel Tower at night is not illegal at all. Any individual can take photos and share them on social networks. But the ...",
          "source": "web"
        },
        {
          "title": "4138 Eiffel Tower Night Stock Photos, High-Res Pictures, and Images",
          "url": "https://www.gettyimages.com/photos/eiffel-tower-night",
          "date": "2016-12-19",
          "last_updated": "2025-04-12",
          "snippet": "Browse 4,138 authentic eiffel tower night stock photos, high-res images, and pictures, or explore additional eiffel tower night lights or eiffel tower night ...",
          "source": "web"
        },
        {
          "title": "16678 results for eiffel tower night in all - Adobe Stock",
          "url": "https://stock.adobe.com/search?k=eiffel+tower+night",
          "date": null,
          "last_updated": null,
          "snippet": "Search from thousands of royalty-free Eiffel Tower Night stock images and video for your next project. Download royalty-free stock photos, vectors, ...",
          "source": "web"
        },
        {
          "title": "Picture of Eiffel Tower Tour by Night, Paris - Tripadvisor",
          "url": "https://www.tripadvisor.com/LocationPhotoDirectLink-g187147-d11449765-i423267412-Eiffel_Tower_Tour_by_Night-Paris_Ile_de_France.html",
          "date": "2026-02-24",
          "last_updated": "2026-02-24",
          "snippet": "Eiffel Tower Tour by Night, Paris Picture: Eiffel Tower at night - Check out Tripadvisor members' 50079 candid photos and videos of Eiffel Tower Tour by ...",
          "source": "web"
        },
        {
          "title": "The Eiffel Tower by Night: A Photographer's Dream - French Moments",
          "url": "https://frenchmoments.eu/the-eiffel-tower-by-night/",
          "date": "2024-04-17",
          "last_updated": "2026-05-19",
          "snippet": "Selfies, group photos, and creative shots juxtaposing the tower's lights with the city's landmarks are all part of the experience. As you stand ...",
          "source": "web"
        }
      ],
      "status": null,
      "type": null,
      "usage": {
        "completion_tokens": 223,
        "cost": {
          "input_tokens_cost": 4e-05,
          "output_tokens_cost": 0.00334,
          "total_cost": 0.00938,
          "citation_tokens_cost": null,
          "reasoning_tokens_cost": null,
          "request_cost": 0.006,
          "search_queries_cost": null
        },
        "prompt_tokens": 13,
        "total_tokens": 236,
        "citation_tokens": null,
        "num_search_queries": null,
        "reasoning_tokens": null,
        "search_context_size": "low"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

### Key Parameters

* **`return_images`**: Set to `true` to enable image returns
* **`image_domain_filter`**: Array of domains (max 10 entries). Prefix with `-` to exclude (e.g., `-gettyimages.com`)
* **`image_format_filter`**: Array of lowercase file extensions (max 10 entries). Use `gif`, `jpeg`, `png`, `webp` (no dot prefix)
* **Limitations**: Maximum 30 images per response, filters only apply when `return_images: true`

## Receiving Videos

Enable video returns in responses using the `media_response.overrides.return_videos` parameter.

<Info>
  The `return_videos` feature is currently only available in the Sonar API.
</Info>

<Warning>
  Video returns may increase response size and processing time. Use this feature selectively for queries where video content adds significant value.
</Warning>

### Basic Video Returns

```python Python SDK theme={null}
from perplexity import Perplexity

client = Perplexity()

completion = client.chat.completions.create(
    model="sonar-pro",
    media_response={
        "overrides": {
            "return_videos": True
        }
    },
    messages=[
        {"role": "user", "content": "Describe the history of the modern Winter Olympic Games from 1924 to today."}
    ]
)
print(completion.choices[0].message.content)
```

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "2c258952-4e5c-470e-90b6-10a8c206a58f",
    "choices": [
      {
        "delta": {
          "content": "",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "index": 0,
        "message": {
          "content": "The modern Winter Olympic Games began with **Chamonix 1924** and have evolved from a small European-focused festival of six sports into a global mega-event featuring more than 100 medal events, thousands of athletes, and over 90 nations, held on a separate four‑year cycle from the Summer Games since **1994**.[1][3]\n\nBelow is a concise chronological overview, focusing on major milestones in hosting, political context, program changes, and structural reforms.\n\n---\n\n### Origins and early years (1924–1936)\n\n- **Pre‑1924 background**  \n  Winter sports such as **figure skating** and **ice hockey** appeared sporadically at the Summer Olympics (e.g., 1920 Antwerp).[1][3] Growing popularity of skiing and skating in Europe and North America led the IOC to support a dedicated “**International Winter Sports Week**” in France in 1924.[1][3]\n\n- **1924 – Chamonix, France (retroactively I Winter Olympics)**  \n  Organized as “International Winter Sports Week” under IOC patronage, later designated the first Winter Olympic Games.[1][3]  \n  - About **258 athletes** (247 men, 11 women) from **16 nations**.[3]  \n  - **Six sports/16 events**: bobsleigh, curling, figure skating, ice hockey, speed skating, and Nordic skiing (cross‑country, ski jumping, Nordic combined).[1][3]  \n  - Established the basic model for a separate Winter Games tradition.[1][3]\n\n- **Creation of a separate Winter Olympic Games**  \n  In **1925**, the IOC formally created a distinct **Olympic Winter Games**, retroactively recognizing Chamonix 1924 as the first edition and awarding **St. Moritz, Switzerland** the 1928 Games.[1]\n\n- **1928 – St. Moritz, Switzerland**  \n  First Games officially organized as “Olympic Winter Games.”[1] St. Moritz’s alpine setting helped solidify the image of a mountain-based winter festival.\n\n- **1932 – Lake Placid, USA**  \n  First Winter Olympics held **outside Europe**, signaling early global expansion beyond the European core.[1]\n\n- **1936 – Garmisch‑Partenkirchen, Germany**  \n  - Hosted in Nazi Germany, mirroring the propaganda context of the 1936 Berlin Summer Games.  \n  - **Alpine skiing** was added to the Olympic winter program, marking the rise of modern downhill ski disciplines.[2]\n\n---\n\n### War interruption and postwar consolidation (1940–1960)\n\n- **Cancellations during World War II**  \n  Winter Games scheduled for **1940** and **1944** were **canceled** due to the war, interrupting the four‑year cycle.[1]\n\n- **1948 – St. Moritz, Switzerland**  \n  First postwar Winter Olympics, held in neutral Switzerland.[1] Germany and Japan, excluded from the 1948 Summer Games, also did not participate in these early postwar events.\n\n- **1952 – Oslo, Norway**  \n  The Games returned to Scandinavia, the birthplace of many Nordic skiing traditions.[1]\n\n- **1956 – Cortina d’Ampezzo, Italy**  \n  Marked increased television interest and laid groundwork for the media‑driven growth of later Games.[1]\n\n- **1960 – Squaw Valley (now Palisades Tahoe), USA**  \n  - Showcased extensive **television coverage**, accelerating commercialization and global visibility.  \n  - **Biathlon**—combining cross‑country skiing and rifle shooting, derived from the older “military patrol” event—was added as a medal sport.[2][3]\n\n---\n\n### Expansion of venues and sports (1960s–1980s)\n\n- **1964 – Innsbruck, Austria**  \n  - Hosted amid concerns over snow conditions, prompting large‑scale snow storage and transport efforts—an early example of climate-related operational challenges.  \n  - **Luge** was added to the Winter Olympic program.[2]\n\n- **1968, 1972, 1976**  \n  While specific host cities are not detailed in the provided sources, this era saw:  \n  - Growth in the number of participating nations and events.  \n  - Rising television revenues, making the Games financially significant for hosts and the IOC.[1]\n\n- **1980 – Lake Placid, USA (second time)**  \n  Known historically for iconic moments like the “Miracle on Ice” (noted widely in Olympic histories, though not in the cited pages), and increased Cold War symbolism around East–West rivalry in winter sports.\n\n- **1984 – Sarajevo, Yugoslavia**  \n  First Winter Games in a socialist, non‑aligned country; later remembered against the backdrop of the 1990s Balkan conflicts.\n\n- **1988 – Calgary, Canada**  \n  - Marked a major step in **commercialization** and large‑scale broadcast production for winter sports.[1]  \n  - **Freestyle skiing** and **short track speed skating** appeared as **demonstration sports**, foreshadowing program shifts toward more dynamic, TV‑friendly events.[2]\n\n---\n\n### Separation from the Summer Games and new disciplines (1990s)\n\n- **Until 1992**  \n  Winter and Summer Games were held in the **same year** every four years.[1][3]\n\n- **IOC reform (1986)**  \n  At the **91st IOC Session (1986)**, members decided to **separate** the Summer and Winter Games onto **staggered four‑year cycles in different even‑numbered years**.[1] The aims were to:  \n  - Spread logistical and financial demands.  \n  - Generate steady **broadcast and sponsorship revenue** by holding Olympics every two years (alternating Winter/Summer).[1][3]\n\n- **1992 – Albertville, France**  \n  Last Winter Olympics held in the same year as a Summer Games.[1]  \n  - **Short track speed skating** and **moguls** (freestyle skiing) became official medal events after their demonstration in 1988.[2]\n\n- **1994 – Lillehammer, Norway**  \n  - First Winter Games held **two years after** the previous edition, inaugurating the new staggered cycle.[1][3]  \n  - **Aerials** in freestyle skiing became a medal event, expanding the freestyle program.[2]  \n  - Lillehammer became a reference point for “human‑scale” Games with strong environmental and cultural branding.\n\n- **1998 – Nagano, Japan**  \n  - First Winter Olympics in Asia since Sapporo 1972 (noted in broader histories).  \n  - **Snowboarding** debuted as an Olympic sport (giant slalom and halfpipe), reflecting the rise of youth and action sports.[2]  \n  - **Curling**, present in 1924 then dropped, returned as a full medal sport.[2][3]\n\n---\n\n### Commercial mega-event and action sports era (2000s–2010s)\n\n- **2002 – Salt Lake City, USA**  \n  - Marked by post‑9/11 security concerns and extensive broadcast coverage.  \n  - **Skeleton** was reintroduced as a permanent Olympic winter sport after an earlier appearance in 1928 and 1948.[2]\n\n- **2006 – Torino, Italy**  \n  - Added **snowboard cross** (boardercross) and a **mass start** event in **biathlon**, illustrating how new formats are used to keep sports television‑friendly and exciting.[2]\n\n- **2010 – Vancouver, Canada**  \n  - Introduced **ski cross** in freestyle skiing.[2]  \n  - Featured large urban celebrations and further integrated digital media, social networking, and high‑definition broadcasts.\n\n- **2014 – Sochi, Russia**  \n  - Marked a significant expansion of “action sports” and new team formats:  \n    - **Ski slopestyle**, **snowboard slopestyle**, and **ski halfpipe** were added (men’s and women’s).[2]  \n    - A **team figure skating** event debuted.[2]  \n  - Record‑level spending on venues and infrastructure; geopolitical tensions and human‑rights debates framed international discussion of the Games (noted in many contemporary reports beyond the cited pages).\n\n- **2018 – PyeongChang, South Korea**  \n  - Added **mixed doubles curling**, **snowboard big air**, and **speed skating mass start** events.[2]  \n  - Continued the trend toward **mixed‑gender** and **spectator‑friendly** formats, aligning with the IOC’s push for gender balance and youth appeal.[2]\n\n---\n\n### Recent developments and future direction (2020s)\n\n- **2022 – Beijing, China**  \n  - Beijing became the first city to host both Summer (2008) and Winter Olympics.  \n  - The Games took place during the COVID‑19 era with extensive health protocols (context drawn from general Olympic coverage, though not explicit in the cited pages).  \n  - New events included **women’s monobob**, **mixed team aerials** (freestyle skiing), and a **mixed team relay in short track**, further expanding mixed‑gender and women’s events.[2]\n\n- **2026 – Milano Cortina, Italy (upcoming)**  \n  - Represents a multi‑city, region‑based model using existing and renovated venues across northern Italy.  \n  - Program changes include:  \n    - New **sport**: **ski mountaineering** added to the Winter Olympic program for the first time.[2]  \n    - New or expanded events such as **women’s doubles in luge**, **women’s individual large hill in ski jumping**, a **mixed team event in skeleton**, and **dual moguls** in freestyle skiing.[2]  \n  - These changes underscore ongoing efforts to balance tradition (Nordic skiing, skating) with new alpine and freestyle disciplines aimed at younger audiences.[2]\n\n---\n\n### Structural and programmatic evolution\n\nAcross 100 years, several broader trends have reshaped the Winter Olympics:\n\n- **Growth in scale**  \n  The Winter Olympics expanded from **16 events and 16 nations** in 1924 to **over 100 events and more than 90 nations** in the early 21st century.[3] Athlete participation increased from 258 in Chamonix to several thousand in recent Games.[1][3]\n\n- **Geographical diversification**  \n  Initially concentrated in the **Alps and Scandinavia**, hosts gradually spread to North America (Lake Placid, Squaw Valley, Calgary, Salt Lake City, Vancouver), Asia (Sapporo, Nagano, PyeongChang, Beijing), Eastern Europe (Sarajevo, Sochi), and a wider range of European regions.[1][5]\n\n- **Sport program innovation**  \n  - Early core: **Nordic skiing, speed skating, figure skating, ice hockey, bobsleigh, curling**.[1][3]  \n  - Mid‑century additions: **alpine skiing** (1936), **biathlon** (1960), **luge** (1964).[2]  \n  - Late 20th century: **freestyle skiing**, **short track**, **snowboarding**, **skeleton**.[2]  \n  - 21st century: expanding **X‑Games‑style events** (slopestyle, halfpipe, big air, cross), **mixed‑team formats**, and new sports such as **ski mountaineering** for 2026.[2]\n\n- **Gender balance and mixed events**  \n  Women participated in figure skating and some early disciplines but were under‑represented; over time, women’s events expanded across almost all sports, and **mixed‑gender events** (e.g., mixed doubles curling, mixed team aerials) have become a key IOC emphasis.[2][3]\n\n- **Scheduling and commercialization**  \n  The decision to **separate the Winter and Summer Games starting in 1994** transformed the Winter Olympics into a stand‑alone global event with its own media and marketing cycle, generating Olympic‑related revenue every two years rather than every four.[1][3]\n\n- **Politics, environment, and legacy**  \n  The Winter Games have intersected with global politics (Nazi Germany 1936, Cold War rivalries, post‑Soviet and contemporary geopolitics) and increasingly with **environmental issues**, as hosts confront climate change, snow reliability, and sustainability, leading to more reuse of existing venues and regional hosting models (e.g., Milano–Cortina).[1][5]\n\nIf you’d like, I can turn this into a compact timeline listing each Winter Games from 1924 onward with host city, notable firsts, and key sports changes.",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "finish_reason": "stop"
      }
    ],
    "created": 1779896062,
    "model": "sonar-pro",
    "citations": [
      "https://en.wikipedia.org/wiki/Winter_Olympic_Games",
      "https://utaholympiclegacy.org/2026/01/20/timeline-of-winter-sports-added-to-the-olympic-winter-games-1924-2026/",
      "https://info.mysticstamp.com/first-winter-olympic-games_tdih/",
      "https://oakgroveky.org/a-journey-through-time-the-evolution-of-the-olympic-games/",
      "https://www.tandfonline.com/doi/full/10.1080/09523367.2020.1866474",
      "https://www.demonsunglasses.com/blogs/snow-ski-and-snowboard-blog/history-of-the-winter-olympic-games-origins-and-evolution"
    ],
    "object": "chat.completion",
    "search_results": [
      {
        "title": "Winter Olympic Games - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Winter_Olympic_Games",
        "date": "2002-01-07",
        "last_updated": "2026-04-27",
        "snippet": "The first Winter Olympic Games, the 1924 Winter Olympics, were held in Chamonix, France. The modern Olympic Games were inspired by the ancient Olympic Games, ...",
        "source": "web"
      },
      {
        "title": "Timeline of Winter Sports Added to the Olympic Winter Games (1924 ...",
        "url": "https://utaholympiclegacy.org/2026/01/20/timeline-of-winter-sports-added-to-the-olympic-winter-games-1924-2026/",
        "date": "2026-01-20",
        "last_updated": "2026-04-08",
        "snippet": "The Olympic Winter Games have evolved dramatically since their debut in 1924, reflecting changes in athletic innovation, technology, ...",
        "source": "web"
      },
      {
        "title": "First Winter Olympic Games | Mystic Stamp Discovery Center",
        "url": "https://info.mysticstamp.com/first-winter-olympic-games_tdih/",
        "date": "2026-01-25",
        "last_updated": "2026-03-24",
        "snippet": "The games lasted from January 25 to February 5, 1924, featuring 258 athletes—247 men and 11 women—representing 16 nations. These nations included the United ...",
        "source": "web"
      },
      {
        "title": "A Journey Through Time: The Evolution of the Olympic Games",
        "url": "https://oakgroveky.org/a-journey-through-time-the-evolution-of-the-olympic-games/",
        "date": "2017-07-06",
        "last_updated": "2026-05-17",
        "snippet": "The inclusion of winter sports led to the Winter Olympics, first held in Chamonix, France, in 1924. Women's events were gradually added, starting with ...",
        "source": "web"
      },
      {
        "title": "Full article: The Winter Olympics: A Century of Games on Ice and Snow",
        "url": "https://www.tandfonline.com/doi/full/10.1080/09523367.2020.1866474",
        "date": "2021-03-23",
        "last_updated": "2026-02-03",
        "snippet": "From 1924 to 2010 the Olympic Winter Games were held 21 times, but only ten countries hosted the event. With two-thirds of those games taking ...",
        "source": "web"
      },
      {
        "title": "History of the Winter Olympic Games: origins and evolution",
        "url": "https://www.demonsunglasses.com/blogs/snow-ski-and-snowboard-blog/history-of-the-winter-olympic-games-origins-and-evolution",
        "date": "2025-11-25",
        "last_updated": "2026-01-23",
        "snippet": "The first Winter Olympic Games were held in 1924 in Chamonix, France, at the foot of Mont Blanc. The event was originally called the International Winter Sports ...",
        "source": "web"
      }
    ],
    "status": null,
    "type": null,
    "usage": {
      "completion_tokens": 2702,
      "cost": {
        "input_tokens_cost": 5e-05,
        "output_tokens_cost": 0.04053,
        "total_cost": 0.04658,
        "citation_tokens_cost": null,
        "reasoning_tokens_cost": null,
        "request_cost": 0.006,
        "search_queries_cost": null
      },
      "prompt_tokens": 17,
      "total_tokens": 2719,
      "citation_tokens": null,
      "num_search_queries": null,
      "reasoning_tokens": null,
      "search_context_size": "low"
    }
  }
  ```
</Accordion>

### Combining Videos with Images

You can request both videos and images in the same response:

```python Python SDK theme={null}
from perplexity import Perplexity

client = Perplexity()

completion = client.chat.completions.create(
    model="sonar-pro",
    return_images=True,
    media_response={
        "overrides": {
            "return_videos": True
        }
    },
    messages=[
        {"role": "user", "content": "Summarize the science goals of NASA's Mars Perseverance rover and the significance of the Jezero crater landing site."}
    ]
)
```

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "b278ecef-fc35-417d-b862-02183d0a3a03",
    "choices": [
      {
        "delta": {
          "content": "",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "index": 0,
        "message": {
          "content": "NASA’s Perseverance rover has four main science goals: **study past habitability**, **search for signs of ancient microbial life**, **collect and cache rock and soil samples for possible return to Earth**, and **test technologies to support future human missions**.[3][1] Jezero Crater was chosen as the landing site because strong evidence shows it once hosted a long‑lived lake and river delta, making it one of the most promising places on Mars to preserve biosignatures in sedimentary rocks.[3][1][2]\n\n**Science goals of Perseverance**\n\nPerseverance is the Mars 2020 rover in NASA’s Mars Exploration Program, and its mission-level science objectives are:[3][1][2][5]\n\n1. **Studying Mars’ habitability (past environments)**\n   - Reconstruct the **ancient environment** at Jezero Crater by studying its rocks, sediments, and geological context.[1][2]  \n   - Determine whether Jezero once had conditions that were **habitable**, such as long‑lasting liquid water, suitable chemistry, and energy sources.[1][3]  \n   - Examine the **climate history** recorded in rock layers, to understand how Mars’ environment evolved over billions of years.[1][2][5]  \n\n2. **Seeking signs of past microbial life (astrobiology)**\n   - Search for **biosignatures**—textural, chemical, or mineralogical evidence that could indicate past microbial life—in rocks that formed in water and are most likely to preserve such evidence.[1][2][3]  \n   - Focus on rocks with **high biosignature preservation potential**, such as fine‑grained sediments in the ancient lakebed and delta deposits.[1]  \n   - Use observations of habitability and preservation to **target the most promising locations** for detailed investigation.[1][2]  \n\n3. **Collecting and caching samples for Mars Sample Return**\n   - Drill **core samples of Martian rock and regolith** and seal them in tubes, caching a carefully documented set that captures the **geologic diversity** of Jezero Crater.[3][1][2]  \n   - Prepare these samples for possible **return to Earth** by a future mission, where laboratory instruments far more capable than those on a rover can analyze them for detailed geochemistry, mineralogy, and possible biosignatures.[3][1][2][4][6]  \n\n4. **Preparing for future human exploration**\n   - Demonstrate **in‑situ resource utilization (ISRU)**, notably producing oxygen from the Martian atmosphere (e.g., MOXIE technology) as a step toward making propellant and breathable oxygen on Mars.[1][6]  \n   - Characterize **atmospheric dust, weather, and environmental conditions** that will affect human systems and health.[1][6]  \n   - Improve **landing and surface operations technologies**, informing safer and more precise landings for future crewed missions.[1][6]  \n\nThese mission-level objectives implement the broader Mars Exploration Program themes: **life, climate, geology, and preparation for humans**.[5][8]\n\n**Why Jezero Crater is a significant landing site**\n\nJezero Crater is considered one of the most scientifically valuable locations on Mars for addressing these goals.[3][1][2][5][7]\n\n1. **Ancient lake and river delta**\n   - Remote sensing data show that **more than 3.5 billion years ago**, river channels breached Jezero’s rim, **flooded the crater**, and created a **long‑lived lake**.[3]  \n   - The crater hosts one of the **best‑preserved river delta deposits** on Mars—a fan‑shaped accumulation of sediments where a river flowed into the lake.[3][7]  \n   - The presence of both **inflow and outflow channels** indicates the lake was not ephemeral; water likely stood in the crater long enough to allow extensive sediment deposition.[7]  \n\n2. **High potential for biosignature preservation**\n   - On Earth, lake and delta environments with **fine‑grained sediments** are excellent at preserving **microbial fossils and chemical biosignatures**; Jezero offers a Mars analog of this setting.[2][3][7]  \n   - Sediments in a quiet lakebed and delta can trap and bury organic matter, potentially preserving signs of life for billions of years.[2][3]  \n   - Perseverance targets precisely these deposit types because they maximize the chance of finding **fossil biosignatures**, if life ever existed there.[1][2]  \n\n3. **Evidence of water‑related minerals**\n   - Orbital observations reveal that Jezero’s rocks contain **clay minerals and carbonates**, which typically form in the presence of liquid water and can help buffer pH, supporting habitable conditions.[3][1][5]  \n   - Such minerals can **encapsulate and preserve organic molecules** and microstructures, making them prime targets for astrobiology.[1][2]  \n\n4. **Geologic diversity and a long time record**\n   - Jezero combines **ancient crater floor rocks**, sedimentary lake and delta deposits, and materials from the surrounding highlands delivered by rivers.[1][3][5]  \n   - This diversity allows Perseverance to investigate **multiple geologic environments and time periods** within a single traversable region, helping reconstruct the **“on‑again, off‑again” wet history** of Mars.[3]  \n   - Exposed layers act as a **stratigraphic record**, capturing changing environmental and climate conditions as each layer formed.[2][5]  \n\n5. **Strategic value for Mars Sample Return**\n   - Because Jezero’s rocks are both **geologically diverse** and **potentially biosignature‑rich**, samples from this site are expected to be highly valuable for **Mars Sample Return**.[3][1][2]  \n   - The cached samples will likely include lakebed mudstones, deltaic sandstones, altered crater floor rocks, and possibly wind‑blown materials and atmosphere samples, together providing a comprehensive record of the site’s history.[3][1]  \n\nIn summary, Perseverance’s science goals are tightly coupled to the unique attributes of Jezero Crater: a once‑wet, mineral‑rich, geologically diverse site that offers one of the best natural laboratories on Mars to determine whether the planet was ever inhabited, how its environment evolved, and how future human explorers might live there.",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "finish_reason": "stop"
      }
    ],
    "created": 1779896061,
    "model": "sonar-pro",
    "citations": [
      "https://science.nasa.gov/mission/mars-2020-perseverance/science-objectives/",
      "https://www.dlr.de/en/research-and-transfer/projects-and-missions/mars2020/scientific-goals-of-the-mars-2020-mission",
      "https://science.nasa.gov/mission/mars-2020-perseverance/",
      "https://www.energy.gov/ne/articles/powering-perseverance-nasas-mars-2020-mission-fueled-doe-national-labs",
      "https://marspedia.org/Mars_Perseverance_Rover",
      "https://inl.gov/mars-2020/",
      "https://www.youtube.com/watch?v=5qqsMjy8Rx0",
      "https://science.nasa.gov/planetary-science/programs/mars-exploration/science-goals/"
    ],
    "object": "chat.completion",
    "search_results": [
      {
        "title": "Perseverance Science Objectives",
        "url": "https://science.nasa.gov/mission/mars-2020-perseverance/science-objectives/",
        "date": "2024-04-16",
        "last_updated": "2026-04-01",
        "snippet": "In addition to these science goals, Perseverance has a unique goal of collecting and caching samples of Mars material for possible future return. This image of ...",
        "source": "web"
      },
      {
        "title": "Scientific goals of the Mars 2020 mission",
        "url": "https://www.dlr.de/en/research-and-transfer/projects-and-missions/mars2020/scientific-goals-of-the-mars-2020-mission",
        "date": "2021-02-15",
        "last_updated": "2026-01-06",
        "snippet": "One of the two main goals of NASA's Mars 2020 mission is to search for traces of microbial life (biosignatures) on Earth's neighbouring planet.",
        "source": "web"
      },
      {
        "title": "Mars 2020: Perseverance Rover - NASA Science",
        "url": "https://science.nasa.gov/mission/mars-2020-perseverance/",
        "date": "2021-02-18",
        "last_updated": "2026-05-19",
        "snippet": "The rover's mission has four science objectives: Studying Mars' Habitability, Seeking Signs of Past Microbial Life, Collecting and Caching ...",
        "source": "web"
      },
      {
        "title": "Powering Perseverance: NASA's Mars 2020 Mission Fueled by DOE ...",
        "url": "https://www.energy.gov/ne/articles/powering-perseverance-nasas-mars-2020-mission-fueled-doe-national-labs",
        "date": "2026-05-22",
        "last_updated": "2026-05-17",
        "snippet": "The mission of the Mars 2020 Perseverance Rover is to find signs of ancient life and drill and collect soil samples that can be potentially ...",
        "source": "web"
      },
      {
        "title": "Mars Perseverance Rover - Marspedia",
        "url": "https://marspedia.org/Mars_Perseverance_Rover",
        "date": "2026-01-12",
        "last_updated": "2025-10-26",
        "snippet": "The first goal is to determine whether life ever arose on Mars, the second goal is to characterize the climate of Mars, third is to characterize ...",
        "source": "web"
      },
      {
        "title": "Mars 2020 | Powering NASA's Mars Perseverance Rover",
        "url": "https://inl.gov/mars-2020/",
        "date": "2025-07-08",
        "last_updated": "2025-11-23",
        "snippet": "Its mission is simple: To find signs of life and collect rock and soil samples for potential return to Earth in a future mission. The MMRTG will power ...",
        "source": "web"
      },
      {
        "title": "Mission Overview: NASA's Perseverance Mars Rover - YouTube",
        "url": "https://www.youtube.com/watch?v=5qqsMjy8Rx0",
        "date": "2020-07-27",
        "last_updated": "2026-02-17",
        "snippet": "NASA's Mars 2020 Perseverance Rover is heading to the Red Planet to search for signs of ancient life, collect samples for future return to ...",
        "source": "web"
      },
      {
        "title": "Mars Exploration: Science Goals",
        "url": "https://science.nasa.gov/planetary-science/programs/mars-exploration/science-goals/",
        "date": "2024-11-18",
        "last_updated": "2026-05-02",
        "snippet": "NASA's Mars Perseverance rover seeks signs of ancient life and collects samples of rock and regolith for possible Earth return. Mars Science ...",
        "source": "web"
      }
    ],
    "status": null,
    "type": null,
    "usage": {
      "completion_tokens": 1370,
      "cost": {
        "input_tokens_cost": 8e-05,
        "output_tokens_cost": 0.02055,
        "total_cost": 0.02663,
        "citation_tokens_cost": null,
        "reasoning_tokens_cost": null,
        "request_cost": 0.006,
        "search_queries_cost": null
      },
      "prompt_tokens": 28,
      "total_tokens": 1398,
      "citation_tokens": null,
      "num_search_queries": null,
      "reasoning_tokens": null,
      "search_context_size": "low"
    }
  }
  ```
</Accordion>

### Key Parameters

* **`media_response.overrides.return_videos`**: Set to `true` to enable video returns
* **Response format**: Videos appear in the `videos` array with `url`, `thumbnail_url`, and metadata
* **Performance**: Video-enabled requests may take longer to process and produce larger responses

## Best Practices

<Tip>
  **Image optimization**: Compress images before encoding to reduce payload size and token costs. Resize very large images before sending.

  **File preparation**: Ensure documents are text-based (not scanned images). For URLs, verify they return the file directly, not a preview page.

  **Filter strategy**: Start with broad filters and gradually refine based on result quality. Keep filter lists concise (≤10 entries) for best performance.
</Tip>

## Next Steps

<Card title="Sonar Quickstart" icon="rocket" href="/docs/sonar/quickstart">
  Get started with the Sonar API and learn the fundamentals
</Card>


# Models
Source: https://docs.perplexity.ai/docs/sonar/models

Compare Sonar, Sonar Pro, Sonar Reasoning Pro, and Sonar Deep Research models for the Sonar API.

<div>
  <div>
    <div>
      <SonarLogo />

      <h1><span>Models</span></h1>
    </div>
  </div>

  <SonarDeprecationNotice />

  <div>
    <div>
      <h3><span>Explore the Sonar range and compare models</span></h3>
    </div>
  </div>

  <Frame>
    <img alt="Sonar Range" />
  </Frame>

  <ModelOverviewCards />
</div>


# Sonar
Source: https://docs.perplexity.ai/docs/sonar/models/sonar

Learn about the Sonar search model, including its pricing, API usage, and best-fit use cases.

<div>
  <a href="/docs/sonar/models">
    <svg>
      <path />
    </svg>

    Models
  </a>
</div>

<div>
  <div>
    <div>
      <div>
        <div />

        <div>
          <div>
            <h1>Sonar</h1>
            <p>Fast answers with reliable search results</p>
          </div>
        </div>
      </div>

      <SonarDeprecationNotice />

      <div>
        <p>
          A lightweight, cost-effective search model optimized for quick, grounded answers with real-time web search.
        </p>
      </div>
    </div>
  </div>

  <div>
    <div>
      <h2>Pricing</h2>
      <a href="/docs/getting-started/pricing">See the full pricing and search context size guide.</a>
    </div>

    <div>
      <div>
        <div>
          <div>
            <h3>Input Tokens</h3>
          </div>

          <div>
            <span>\$1</span>
          </div>

          <div>
            <span>Per 1M Tokens</span>
          </div>
        </div>
      </div>

      <div>
        <div>
          <div>
            <h3>Output Tokens</h3>
          </div>

          <div>
            <span>\$1</span>
          </div>

          <div>
            <span>Per 1M Tokens</span>
          </div>
        </div>
      </div>

      <div>
        <div>
          <h3>Price Per 1K Requests</h3>

          <p />

          <div>
            <div>
              <span>\$12</span>
              <span>\$8</span>
              <span>\$5</span>
            </div>

            <div>
              <span>High</span>
              <span>Medium</span>
              <span>Low</span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <div>
    <h2>Features</h2>

    <div>
      <div>
        <div>
          <div>
            <img alt="Arrow" />
          </div>

          <div>
            <h3>Non-reasoning model</h3>
          </div>
        </div>

        <div>
          <div>
            <img alt="Search" />
          </div>

          <div>
            <h3>Ideal for quick searches and straightforward Q\&A tasks</h3>
          </div>
        </div>

        <div>
          <div>
            <img alt="Length" />
          </div>

          <div>
            <h3>128K context length</h3>
          </div>
        </div>
      </div>

      <div>
        <div>
          <div>
            <img alt="Speed" />
          </div>

          <div>
            <h3>Optimized for speed and cost</h3>
          </div>
        </div>

        <div>
          <div>
            <img alt="Citation" />
          </div>

          <div>
            <h3>Real-time web search-based answers with detailed search results</h3>
          </div>
        </div>

        <div>
          <div>
            <img alt="Lock" />
          </div>

          <div>
            <h3>No training on customer data</h3>
          </div>
        </div>
      </div>
    </div>
  </div>

  <div>
    <h2>Real World Use Cases</h2>

    <div>
      <div>
        <div>
          <img alt="Summarizing" />
        </div>

        <div>
          <h3>Summarizing books, TV shows, and movies</h3>
        </div>
      </div>

      <div>
        <div>
          <img alt="Definitions" />
        </div>

        <div>
          <h3>Looking up definitions or quick facts</h3>
        </div>
      </div>

      <div>
        <div>
          <img alt="Browsing" />
        </div>

        <div>
          <h3>Browsing news, sports, health, and finance content</h3>
        </div>
      </div>
    </div>
  </div>

  <div>
    <CodeGroup>
      ```bash cURL theme={null}
      curl --request POST \
      --url https://api.perplexity.ai/v1/sonar \
      --header "Authorization: Bearer <token>" \
      --header "Content-Type: application/json" \
      --data '{
        "model": "sonar",
        "messages": [
          {
            "role": "user",
            "content": "What is the latest news in AI research?"
          }
        ]
      }' | jq
      ```

      ```python python theme={null}
      import requests

      url = "https://api.perplexity.ai/v1/sonar"

      payload = {
          "model": "sonar",
          "messages": [
              {"role": "user", "content": "What is the latest news in AI research?"}
          ]
      }
      headers = {
          "Authorization": "Bearer <token>",
          "Content-Type": "application/json"
      }

      response = requests.post(url, json=payload, headers=headers)
      print(response.json())
      ```
    </CodeGroup>

    **Sample Response Metadata**

    <CodeGroup>
      ```json Success Response expandable wrap theme={null}
      {
      "id": "a954f304-9a7a-44f5-9605-152e9f5b1c74",
      "model": "sonar",
      "created": 1756485752,
      "usage": {
        "prompt_tokens": 9,
        "completion_tokens": 402,
        "total_tokens": 411,
        "search_context_size": "low",
        "cost": {
          "input_tokens_cost": 0.0,
          "output_tokens_cost": 0.0,
          "request_cost": 0.005,
          "total_cost": 0.005
        }
      },
      "citations": [
        "https://champaignmagazine.com/2025/07/01/ai-by-ai-first-half-of-2025-themes-and-breakthroughs/",
        "https://www.artificialintelligence-news.com",
        "https://www.crescendo.ai/news/latest-ai-news-and-updates",
        "https://www.sciencedaily.com/news/computers_math/artificial_intelligence/",
        "https://explodingtopics.com/blog/future-of-ai"
      ],
      "search_results": [
        {
          "title": "AI by AI: First Half of 2025 Themes and Breakthroughs",
          "url": "https://champaignmagazine.com/2025/07/01/ai-by-ai-first-half-of-2025-themes-and-breakthroughs/",
          "date": "2025-07-01",
          "last_updated": "2025-08-29",
          "snippet": "Research published on May 13, 2025, by philosopher Frank Martela suggests AI is approaching conditions for free will, sparking ethical debates."
        },
        {
          "title": "AI News | Latest AI News, Analysis & Events",
          "url": "https://www.artificialintelligence-news.com",
          "date": "2025-08-28",
          "last_updated": "2025-08-29",
          "snippet": "Marketing AI boom faces crisis of consumer trust · AI security wars: Can Google Cloud defend against tomorrow's threats? · Agentic AI: Promise, scepticism, and ..."
        },
        {
          "title": "Latest AI Breakthroughs and News: June, July, August 2025",
          "url": "https://www.crescendo.ai/news/latest-ai-news-and-updates",
          "date": "2025-08-29",
          "last_updated": "2025-08-29",
          "snippet": "Wondering what's happening in the AI world? Here are the latest AI breakthroughs and news that are shaping the world around us!"
        },
        {
          "title": "Artificial Intelligence News - ScienceDaily",
          "url": "https://www.sciencedaily.com/news/computers_math/artificial_intelligence/",
          "date": "2025-08-28",
          "last_updated": "2025-08-29",
          "snippet": "Latest Headlines · Harvard's Ultra-Thin Quantum Computing Chip · Google's Deepfake Hunter Is Here · Affordance: The Brain's Hidden Superpower · Half of Today's Jobs ..."
        },
        {
          "title": "Future of AI: 7 Key AI Trends For 2025 & 2026",
          "url": "https://explodingtopics.com/blog/future-of-ai",
          "date": "2025-08-15",
          "last_updated": "2025-08-29",
          "snippet": "A look into the future of AI and the rapidly evolving landscape including potential impacts in healthcare, finance, and sustainability."
        }
      ],
      "object": "chat.completion",
      "choices": [
        {
          "index": 0,
          "finish_reason": "stop",
          "message": {
            "role": "assistant",
            "content": "The latest AI research breakthroughs as of mid-2025 include significant advancements across AI models, robotics, quantum computing, and sustainable AI technologies. Key highlights are:\n\n- **GPT-4o**, released in May 2025, integrates real-time speech, vision, text, and memory with near-human expressiveness, enabling a shift from chatbot interfaces to fluid, embodied AI assistants with empathic interaction and full conversational memory[1].\n\n- Google DeepMind's **Gemini 2.5 Pro** and **Gemini Robotics** models demonstrate advanced parallel thinking for complex math and coding, while enhancing robot reasoning, dexterity, and autonomy in physical tasks without external positioning systems[1].\n\n- Researchers have demonstrated **photonic quantum circuits** that enhance machine learning performance, marking practical steps toward incorporating quantum computing in AI tasks[1][4].\n\n- Japanese scientists created a **self-powered artificial synapse** that processes visual data with very low energy, enabling sustainable AI deployment on edge devices such as IoT sensors and autonomous systems[1].\n\nAdditional notable developments:\n\n- Stanford developed a **virtual AI scientist** that can autonomously design and execute biological experiments, accelerating biomedical research in genomics and drug discovery[3].\n\n- China introduced a **low-cost open-source AI model** cheaper than previous leaders, aimed at enterprise use and reflecting strategic AI independence efforts amid global chip sanctions[3].\n\n- AI is also being applied in healthcare to improve precision medicine and cancer treatment, exemplified by platforms like Avenda Health’s system for mapping and treating prostate cancer, which outperforms MRI in detection and has influenced treatment decisions[5].\n\nEmerging themes include the ethical debate on AI approaching free will conditions, integration of AI in physical and cognitive domains, and progress toward agentive AI systems capable of naturalistic interaction and real-world tasks[1][2].\n\nThese developments signal a rapid and multi-dimensional evolution in AI research, spanning foundational AI capabilities, hardware innovations, and application-specific breakthroughs in medicine and robotics."
          },
          "delta": {
            "role": "assistant",
            "content": ""
          }
        }
      ]
      }
      ```
    </CodeGroup>

    <Accordion title="Cost Breakdown for Sample Request">
      <Info>
        **Token Usage**

        * Prompt Tokens: 9
        * Completion Tokens: 402
        * Search Context Size: Low
      </Info>

      <Steps>
        <Step title="Calculate Input Tokens Cost">
          9 tokens ÷ 1,000,000 × \$1 = \$0.000009
        </Step>

        <Step title="Calculate Output Tokens Cost">
          411 tokens ÷ 1,000,000 × \$1 = \$0.000411
        </Step>

        <Step title="Calculate Search Context Cost">
          1 request × \$5 ÷ 1,000 = \$0.005
        </Step>

        <Step title="Calculate Total Cost">
          \$0.000009 + \$0.000411 + \$0.005 = \$0.005420
        </Step>
      </Steps>

      <Check>
        **Total cost for this request: \$0.005420**
      </Check>
    </Accordion>
  </div>
</div>


# Sonar Deep Research
Source: https://docs.perplexity.ai/docs/sonar/models/sonar-deep-research

Learn about Sonar Deep Research for exhaustive research workflows, including pricing and API usage.

<div>
  <a href="/docs/sonar/models">
    <svg>
      <path />
    </svg>

    Models
  </a>
</div>

<div>
  <div>
    <div>
      <div>
        <div />

        <div>
          <div>
            <h1>Sonar Deep Research</h1>
            <p>Exhaustive research with expert-level insights</p>
          </div>
        </div>
      </div>

      <SonarDeprecationNotice />

      <div>
        <p>
          A powerful research model capable of conducting exhaustive searches across hundreds of sources, synthesizing expert-level insights, and generating detailed reports with comprehensive analysis.
        </p>
      </div>
    </div>
  </div>

  <div>
    <div>
      <h2>Pricing</h2>
      <a href="/docs/getting-started/pricing">See the full pricing and search context size guide.</a>
    </div>

    <div>
      <div>
        <div>
          <div>
            <h3>Input Tokens</h3>
          </div>

          <div>
            <span>\$2</span>
          </div>

          <div>
            <span>Per 1M Tokens</span>
          </div>
        </div>
      </div>

      <div>
        <div>
          <div>
            <h3>Output Tokens</h3>
          </div>

          <div>
            <span>\$8</span>
          </div>

          <div>
            <span>Per 1M Tokens</span>
          </div>
        </div>
      </div>

      <div>
        <div>
          <div>
            <h3>Citation Tokens</h3>
          </div>

          <div>
            <span>\$2</span>
          </div>

          <div>
            <span>Per 1M Tokens</span>
          </div>
        </div>
      </div>

      <div>
        <div>
          <div>
            <h3>Search Queries</h3>
          </div>

          <div>
            <span>\$5</span>
          </div>

          <div>
            <span>Per 1K Requests</span>
          </div>
        </div>
      </div>

      <div>
        <div>
          <div>
            <h3>Reasoning Tokens</h3>
          </div>

          <div>
            <span>\$3</span>
          </div>

          <div>
            <span>Per 1M Tokens</span>
          </div>
        </div>
      </div>
    </div>
  </div>

  <div>
    <h2>Features</h2>

    <div>
      <div>
        <div>
          <div>
            <img alt="Arrow" />
          </div>

          <div>
            <h3>Deep research / Reasoning model</h3>
          </div>
        </div>

        <div>
          <div>
            <img alt="Search" />
          </div>

          <div>
            <h3>Exhaustive research across hundreds of sources</h3>
          </div>
        </div>

        <div>
          <div>
            <img alt="Length" />
          </div>

          <div>
            <h3>128K context length</h3>
          </div>
        </div>
      </div>

      <div>
        <div>
          <div>
            <img alt="Speed" />
          </div>

          <div>
            <h3>Expert-level subject analysis</h3>
          </div>
        </div>

        <div>
          <div>
            <img alt="Citation" />
          </div>

          <div>
            <h3>Detailed report generation</h3>
          </div>
        </div>

        <div>
          <div>
            <img alt="Lock" />
          </div>

          <div>
            <h3>No training on customer data</h3>
          </div>
        </div>
      </div>
    </div>
  </div>

  <div>
    <h2>Real World Use Cases</h2>

    <div>
      <div>
        <div>
          <img alt="Academic Research" />
        </div>

        <div>
          <h3>Academic research and comprehensive reports</h3>
        </div>
      </div>

      <div>
        <div>
          <img alt="Market Analysis" />
        </div>

        <div>
          <h3>Market analysis and competitive intelligence</h3>
        </div>
      </div>

      <div>
        <div>
          <img alt="Due Diligence" />
        </div>

        <div>
          <h3>Due diligence and investigative research</h3>
        </div>
      </div>
    </div>
  </div>

  <div>
    <CodeGroup>
      ```bash cURL wrap theme={null}
      curl --request POST \
        --url https://api.perplexity.ai/v1/sonar \
        --header "Authorization: Bearer <token>" \
        --header "Content-Type: application/json" \
        --data '{
          "model": "sonar-deep-research",
          "messages": [
            {
              "role": "user",
              "content": "Conduct a comprehensive analysis of the quantum computing industry, including technological approaches, key players, market opportunities, regulatory challenges, and commercial viability projections through 2035."
            }
          ]
        }' | jq
      ```

      ```python python wrap theme={null}

      import requests

      url = "https://api.perplexity.ai/v1/sonar"

      payload = {
          "model": "sonar-deep-research",
          "messages": [
              {"role": "user", "content": "Conduct a comprehensive analysis of the quantum computing industry, including technological approaches, key players, market opportunities, regulatory challenges, and commercial viability projections through 2035."}
          ]
      }
      headers = {
          "Authorization": "Bearer <token>",
          "Content-Type": "application/json"
      }

      response = requests.post(url, json=payload, headers=headers)
      print(response.json())

      ```
    </CodeGroup>

    **Sample Response Metadata**

    ```json Success Response expandable wrap theme={null}
    {
    "id": "11d634c8-cf22-4154-9f09-d8f501ae29b5",
    "model": "sonar-deep-research",
    "created": 1756488074,
    "usage": {
      "prompt_tokens": 33,
      "completion_tokens": 11395,
      "total_tokens": 11428,
      "citation_tokens": 19028,
      "num_search_queries": 21,
      "reasoning_tokens": 193947,
      "cost": {
        "input_tokens_cost": 0.0,
        "output_tokens_cost": 0.091,
        "citation_tokens_cost": 0.038,
        "reasoning_tokens_cost": 0.582,
        "search_queries_cost": 0.105,
        "total_cost": 0.816
      }
    },
    "citations": [
      "https://www.moodys.com/web/en/us/insights/quantum/quantum-computings-six-most-important-trends-for-2025.html",
      "https://briandcolwell.com/2025-quantum-computing-industry-report-and-market-analysis-the-race-to-170b-by-2040/",
      "https://www.quandela.com/resources/blog/exploring-types-of-quantum-computers-which-technology-leads/",
      "https://www.marketsandmarkets.com/Market-Reports/quantum-computing-market-144888301.html",
      "https://thequantuminsider.com/2025/05/16/quantum-computing-roadmaps-a-look-at-the-maps-and-predictions-of-major-quantum-players/",
      "https://technologymagazine.com/top10/top-10-quantum-computing-companies",
      "https://www.spinquanta.com/news-detail/quantum-computing-companies",
      "https://thequantuminsider.com/2025/05/27/q1-2025-quantum-technology-investment-whats-driving-the-surge-in-quantum-investment/",
      "https://thequantuminsider.com/2024/09/13/the-quantum-insider-projects-1-trillion-in-economic-impact-from-quantum-computing-by-2035/",
      "https://scholarship.law.edu/cgi/viewcontent.cgi?article=1143&context=jlt",
      "https://www.pwc.com/us/en/services/consulting/cybersecurity-risk-regulatory/library/quantum-computing-cybersecurity-risk.html",
      "https://thequantuminsider.com/2024/12/04/senators-quantum-leaders-back-2-7-billion-national-quantum-initiative-reauthorization-act/",
      "https://itif.org/publications/2023/10/10/the-us-approach-to-quantum-policy/",
      "https://docs.paloaltonetworks.com/network-security/quantum-security/administration/quantum-security-concepts/the-quantum-computing-threat",
      "https://www.marketsandmarkets.com/Market-Reports/quantum-computing-in-healthcare-market-41524710.html",
      "https://milvus.io/ai-quick-reference/what-are-the-limitations-of-current-quantum-computing-hardware",
      "https://www.deloitte.com/us/en/insights/topics/emerging-technologies/quantum-computing-futures.html",
      "https://thequantuminsider.com/2025/03/26/national-quantum-computing-centres-paper-explores-quantum-computings-transformative-potential-in-healthcare-and-pharmaceuticals/",
      "https://quantumzeitgeist.com/quantum-business/",
      "https://www.renaissancecapital.com/IPO-Center/Sub-Industry/Quantum-Computing-IPOs",
      "https://thediplomat.com/2025/03/quantum-a-new-frontier-of-china-us-competition/",
      "https://www.aps.org/apsnews/2024/10/export-quantum-computer",
      "https://postquantum.com/quantum-computing/quantum-workforce-talent/",
      "https://thequantuminsider.com/2025/06/27/quantinuum-crosses-key-quantum-error-correction-threshold-marks-turn-from-nisq-to-utility-scale/",
      "https://postquantum.com/predicting-q-day/ibm-quantum-roadmap/",
      "https://semnexus.com/quantum-computing-in-2025-how-its-reshaping-technology-and-business/",
      "https://www.ibm.com/quantum/blog/large-scale-ftqc",
      "https://datafloq.com/read/5-real-world-applications-of-quantum-computing-in-2025/"
    ],
    "search_results": [
      {
        "title": "Quantum computing's six most important trends for 2025 - Moody's",
        "url": "https://www.moodys.com/web/en/us/insights/quantum/quantum-computings-six-most-important-trends-for-2025.html",
        "date": null,
        "last_updated": null,
        "snippet": "More experiments with logical qubits · More specialized hardware/software (as opposed to universal QC) · More networking NISQ devices together."
      },
      {
        "title": "2025 Quantum Computing Industry Report And Market Analysis",
        "url": "https://briandcolwell.com/2025-quantum-computing-industry-report-and-market-analysis-the-race-to-170b-by-2040/",
        "date": null,
        "last_updated": null,
        "snippet": "McKinsey projects the total quantum technology market could reach $198 billion by 2040, encompassing quantum computing ($28-72B by 2035), ..."
      },
      {
        "title": "Exploring Types of Quantum Computers: Which Technology Leads?",
        "url": "https://www.quandela.com/resources/blog/exploring-types-of-quantum-computers-which-technology-leads/",
        "date": null,
        "last_updated": null,
        "snippet": "This piece takes a closer look at the major types of quantum computers to help you learn how they work and compare their revolutionary potential."
      },
      {
        "title": "Quantum Computing Market Size, Share & Growth Report, 2025",
        "url": "https://www.marketsandmarkets.com/Market-Reports/quantum-computing-market-144888301.html",
        "date": null,
        "last_updated": null,
        "snippet": "The global Quantum Computing Market size in terms of revenue was estimated to be worth $1.3 billion in 2024 and is poised to reach $5.3 billion by 2029, ..."
      },
      {
        "title": "Quantum Computing Roadmaps & Predictions of Leading Players",
        "url": "https://thequantuminsider.com/2025/05/16/quantum-computing-roadmaps-a-look-at-the-maps-and-predictions-of-major-quantum-players/",
        "date": null,
        "last_updated": null,
        "snippet": "The roadmaps of major quantum computing companies reflect a dynamic field, with timelines from 2025 to 2030 for significant milestones."
      },
      {
        "title": "Top 10: Quantum Computing Companies",
        "url": "https://technologymagazine.com/top10/top-10-quantum-computing-companies",
        "date": null,
        "last_updated": null,
        "snippet": "IBM's quantum computing efforts are centred around its superconducting transmon qubit technology. Its latest processor, Condor, boasts 1,121 ..."
      },
      {
        "title": "23 Leading Quantum Computing Companies Worldwide ...",
        "url": "https://www.spinquanta.com/news-detail/quantum-computing-companies",
        "date": null,
        "last_updated": null,
        "snippet": "By 2025, IBM plans to unveil its first quantum-centric supercomputer, integrating modular processors, middleware, and quantum communication."
      },
      {
        "title": "Q1 2025 Quantum Investment: What's Driving the Surge?",
        "url": "https://thequantuminsider.com/2025/05/27/q1-2025-quantum-technology-investment-whats-driving-the-surge-in-quantum-investment/",
        "date": null,
        "last_updated": null,
        "snippet": "Investment in quantum computer companies rose from $550 million in Q1 2024 to more than $1.25 billion in Q1 2025, a 128% increase. Adjusted ..."
      },
      {
        "title": "The Quantum Insider Projects $1 Trillion in Economic ...",
        "url": "https://thequantuminsider.com/2024/09/13/the-quantum-insider-projects-1-trillion-in-economic-impact-from-quantum-computing-by-2035/",
        "date": null,
        "last_updated": null,
        "snippet": "The global quantum computing market could add a total of more than $1 trillion to the global economy between 2025 and 2035, according to a new analysis from ..."
      },
      {
        "title": "[PDF] Establishing the Legal Framework to Regulate Quantum Computing ...",
        "url": "https://scholarship.law.edu/cgi/viewcontent.cgi?article=1143&context=jlt",
        "date": null,
        "last_updated": null,
        "snippet": "Legislation is vital to establish a policy framework for quantum computing technology, but policy questions must be answered prior to the ..."
      },
      {
        "title": "Quantum computing cybersecurity risk: PwC",
        "url": "https://www.pwc.com/us/en/services/consulting/cybersecurity-risk-regulatory/library/quantum-computing-cybersecurity-risk.html",
        "date": null,
        "last_updated": null,
        "snippet": "The major risk posed by quantum computing capabilities is sensitive data being lost or compromised. This has wide-reaching impacts across industries."
      },
      {
        "title": "Senators, Quantum Leaders Back $2.7 Billion National Quantum ...",
        "url": "https://thequantuminsider.com/2024/12/04/senators-quantum-leaders-back-2-7-billion-national-quantum-initiative-reauthorization-act/",
        "date": null,
        "last_updated": null,
        "snippet": "U.S. Senators introduced the National Quantum Initiative Reauthorization Act, authorizing $2.7 billion over five years."
      },
      {
        "title": "The U.S. Approach to Quantum Policy | ITIF",
        "url": "https://itif.org/publications/2023/10/10/the-us-approach-to-quantum-policy/",
        "date": null,
        "last_updated": null,
        "snippet": "On the legislative side, the most significant piece of legislation related to quantum to date has been the National Quantum Initiative Act (NQIA) ..."
      },
      {
        "title": "The Quantum Computing Threat - Palo Alto Networks",
        "url": "https://docs.paloaltonetworks.com/network-security/quantum-security/administration/quantum-security-concepts/the-quantum-computing-threat",
        "date": null,
        "last_updated": null,
        "snippet": "The most immediate danger is Harvest Now, Decrypt Later attacks, where attackers steal data (at rest or in transit) that they can't decrypt now and store it ..."
      },
      {
        "title": "Quantum Computing in Healthcare Market Growth, Drivers, and ...",
        "url": "https://www.marketsandmarkets.com/Market-Reports/quantum-computing-in-healthcare-market-41524710.html",
        "date": null,
        "last_updated": null,
        "snippet": "Global quantum computing in healthcare market valued at $191.3M in 2024, reached $265.9M in 2025, and is projected to grow at a robust 37.9% CAGR, ..."
      },
      {
        "title": "What are the limitations of current quantum computing ...",
        "url": "https://milvus.io/ai-quick-reference/what-are-the-limitations-of-current-quantum-computing-hardware",
        "date": null,
        "last_updated": null,
        "snippet": "Current quantum computing hardware faces three primary limitations: qubit instability, scalability challenges, and the need for highly specialized environments."
      },
      {
        "title": "Quantum computing futures | Deloitte Insights",
        "url": "https://www.deloitte.com/us/en/insights/topics/emerging-technologies/quantum-computing-futures.html",
        "date": null,
        "last_updated": null,
        "snippet": "A few businesses that focused on quantum computing experiments before 2025 in fields like life sciences, banking, tech, and energy are expected ..."
      },
      {
        "title": "National Quantum Computing Centre's Paper Explores Quantum ...",
        "url": "https://thequantuminsider.com/2025/03/26/national-quantum-computing-centres-paper-explores-quantum-computings-transformative-potential-in-healthcare-and-pharmaceuticals/",
        "date": null,
        "last_updated": null,
        "snippet": "It identifies near-term opportunities and long-term challenges associated with the adoption of quantum computing in healthcare and ..."
      },
      {
        "title": "Quantum Business Case: Potential And Challenges",
        "url": "https://quantumzeitgeist.com/quantum-business/",
        "date": null,
        "last_updated": null,
        "snippet": "However, the lack of skilled professionals and the high cost of implementation are some of the major challenges faced by the market. According ..."
      },
      {
        "title": "Quantum Computing IPOs - Renaissance Capital",
        "url": "https://www.renaissancecapital.com/IPO-Center/Sub-Industry/Quantum-Computing-IPOs",
        "date": null,
        "last_updated": null,
        "snippet": "Recent quantum computing listings have offered early access to companies that aim to lead the next wave of computing. Though many are still in pre-revenue or ..."
      },
      {
        "title": "Quantum: A New Frontier of China-US Competition - The Diplomat",
        "url": "https://thediplomat.com/2025/03/quantum-a-new-frontier-of-china-us-competition/",
        "date": null,
        "last_updated": null,
        "snippet": "The U.S. and China find themselves headed for another high-stakes technology competition rooted in fears of being left behind and paranoia."
      },
      {
        "title": "US Puts Export Controls on Quantum Computers",
        "url": "https://www.aps.org/apsnews/2024/10/export-quantum-computer",
        "date": null,
        "last_updated": null,
        "snippet": "The controls cover key equipment, materials, and software used in quantum computers, as well as some complete computers."
      },
      {
        "title": "Building the Quantum Workforce: Talent Challenges and ...",
        "url": "https://postquantum.com/quantum-computing/quantum-workforce-talent/",
        "date": null,
        "last_updated": null,
        "snippet": "Quantum computing companies are investing in education and training to avoid a talent shortage and fuel the industry's growth."
      },
      {
        "title": "Quantinuum Crosses Key Quantum Error Correction Threshold ...",
        "url": "https://thequantuminsider.com/2025/06/27/quantinuum-crosses-key-quantum-error-correction-threshold-marks-turn-from-nisq-to-utility-scale/",
        "date": null,
        "last_updated": null,
        "snippet": "Quantinuum reports it has achieved the first universal, fully fault-tolerant quantum gate set with repeatable error correction."
      },
      {
        "title": "IBM's Roadmap to Large-Scale Fault-Tolerant Quantum Computing ...",
        "url": "https://postquantum.com/predicting-q-day/ibm-quantum-roadmap/",
        "date": null,
        "last_updated": null,
        "snippet": "In June 2025, IBM outlined a clear plan to build the world's first large-scale fault-tolerant quantum computer by 2029."
      },
      {
        "title": "Quantum Computing in 2025: How It's Reshaping ...",
        "url": "https://semnexus.com/quantum-computing-in-2025-how-its-reshaping-technology-and-business/",
        "date": null,
        "last_updated": null,
        "snippet": "Real-World Applications of Quantum Computing · 1. Healthcare & Drug Discovery. Pharmaceutical companies are investing heavily in quantum drug ..."
      },
      {
        "title": "IBM lays out clear path to fault-tolerant quantum computing",
        "url": "https://www.ibm.com/quantum/blog/large-scale-ftqc",
        "date": null,
        "last_updated": null,
        "snippet": "IBM lays out a clear, rigorous, comprehensive framework for realizing a large-scale, fault-tolerant quantum computer by 2029."
      },
      {
        "title": "5 Real-World Applications of Quantum Computing in 2025",
        "url": "https://datafloq.com/read/5-real-world-applications-of-quantum-computing-in-2025/",
        "date": null,
        "last_updated": null,
        "snippet": "5 Real-World Applications of Quantum Computing in 2025 · 1. Investment Portfolio Management · 2. Pharmaceutical Research · 3. Supply Chain ..."
      }
    ],
    "object": "chat.completion",
    "choices": [
      {
        "index": 0,
        "finish_reason": "stop",
        "message": {
          "role": "assistant",
          "content": "<think>\nThis is a comprehensive query about the quantum computing industry that requires me to analyze multiple dimensions:\n\n1. Technological approaches (different types of quantum computing)\n2. Key players (companies, organizations)\n3. Market opportunities (size, growth, applications)\n4. Regulatory challenges (policy, export controls, standards)\n5. Commercial viability projections through 2035\n\nI need to structure this as a long-form report (10,000+ words) covering all these aspects. Let me plan the structure:\n\n1. Title and summary\n2. Current State of Quantum Computing Technologies \n3. Market Size and Growth Projections\n4. Key Players and Competitive Landscape\n5. Commercial Applications and Use Cases\n6. Investment Trends and Funding Landscape\n7. Regulatory Framework and Policy Challenges\n8. Technical Challenges and Limitations\n9. Future Outlook and Commercial Viability to 2035\n10. Conclusion\n\nI'll need to cite the sources throughout and ensure I'm providing comprehensive coverage of each topic. The sources provide great information on market size, company roadmaps, investment trends, regulatory issues, and technical challenges.\n\nLet me start writing the comprehensive report.\n</think>\n\n# The Quantum Computing Revolution: A Comprehensive Industry Analysis Through 2035\n\nThe quantum computing industry stands at a pivotal inflection point in 2025, transitioning from experimental research to practical commercial applications across multiple sectors. This comprehensive analysis reveals that the global quantum computing market is experiencing unprecedented growth, with projections indicating expansion from approximately $1.3 billion in 2024 to between $90-170 billion by 2040, representing a phenomenal compound annual growth rate of 36-48%[2]. The industry's trajectory suggests that quantum computing has moved beyond theoretical possibilities to become a critical technology for solving complex computational problems that classical computers cannot address efficiently. Major technological breakthroughs, including Google's Willow chip achieving quantum error correction milestones and IBM's roadmap to fault-tolerant systems by 2029, signal that the technology is rapidly approaching commercial viability[2][27]. However, significant challenges remain, including qubit stability, scalability limitations, workforce shortages, and evolving regulatory frameworks that will shape the industry's development through 2035.\n\n## Current State of Quantum Computing Technologies\n\nThe quantum computing landscape in 2025 is characterized by multiple competing technological approaches, each offering distinct advantages and facing unique challenges in the race toward practical quantum advantage. The field has evolved beyond proof-of-concept demonstrations to encompass several mature hardware platforms that are beginning to demonstrate real-world utility across various applications.\n\nSuperconducting quantum computers represent the most advanced and commercially deployed quantum computing platform currently available. These systems utilize macroscopic circuits functioning as artificial atoms, operating at extremely low temperatures near absolute zero to maintain quantum coherence[3]. Companies like IBM have pioneered this approach with their superconducting transmon qubit technology, culminating in processors like the Condor system with 1,121 qubits[6]. The primary advantage of superconducting systems lies in their fast gate operation times and compatibility with existing semiconductor manufacturing processes, making them attractive candidates for scalable quantum computing architectures. However, these systems struggle with quantum coherence times that typically do not exceed 300 microseconds, limiting the complexity of quantum algorithms that can be executed before decoherence destroys the quantum information[3].\n\nGoogle's quantum computing efforts have focused heavily on superconducting technology, with their recent Willow chip representing a significant breakthrough in quantum error correction. This 105-qubit processor can perform computations in under five minutes that would require classical supercomputers an unfathomable 10 septillion years to complete[7]. More importantly, Google's Willow chip demonstrates exponential error reduction as more qubits are added to the system, addressing one of the fundamental challenges in scaling quantum computers. This achievement validates the potential for superconducting systems to achieve fault-tolerant quantum computing, a milestone critical for commercial applications requiring high reliability and accuracy.\n\nTrapped ion quantum computers offer a fundamentally different approach to quantum information processing, utilizing individual confined ions as qubits controlled through precise laser manipulation. These systems demonstrate significantly longer coherence times compared to superconducting approaches, with optical qubits maintaining quantum states for 0.2 seconds and hyperfine qubits achieving remarkable coherence times of up to 600 seconds[3]. The extended coherence times enable more complex quantum algorithms and higher-fidelity quantum operations. IonQ has emerged as a leading developer of trapped ion systems, raising $360 million in Q1 2025 to advance their commercial deployment efforts[8]. The company's approach focuses on achieving high measurement accuracy exceeding 99.9% readout fidelity within microseconds, while providing complete connectivity between all qubits in the system.\n\nPhotonic quantum computing has gained significant momentum as a room-temperature quantum computing platform that leverages light particles as qubits. This approach offers unique advantages for quantum networking applications due to photons' natural resistance to decoherence and ability to maintain quantum states over long distances[3]. Photonic systems can handle both discrete-variable and continuous-variable quantum computing approaches, providing versatility for different computational tasks. The room-temperature operation eliminates the need for expensive cryogenic cooling systems required by superconducting and trapped ion approaches, potentially reducing operational costs and complexity for commercial deployments.\n\nEmerging quantum technologies are expanding the field beyond these established platforms. Neutral atom quantum computers represent an exciting development that uses individual atoms as naturally identical qubits without manufacturing defects[3]. QuEra Computing's Aquila system leads this space with 256 atoms, making it the largest publicly available quantum computer by qubit count. The neutral atom approach offers room-temperature operation capability, all-to-all connectivity between qubits, and potential for scaling to thousands of atoms through precise optical tweezer control. QuEra's $230 million funding round in Q1 2025 reflects investor confidence in this alternative architecture[8].\n\nSilicon spin qubit technology leverages existing semiconductor fabrication infrastructure to create extremely compact qubits measuring approximately 50 nanometers by 50 nanometers, making them one million times smaller than other qubit types[3]. Intel's Tunnel Falls chip demonstrates the potential of this approach with a 95% yield rate across the wafer, suggesting manufacturability advantages that could enable large-scale production. The compatibility with semiconductor manufacturing processes positions silicon spin qubits as potentially the most cost-effective path to scaling quantum computers to thousands or millions of qubits.\n\nThe industry trend toward hybrid quantum-classical computing systems represents a pragmatic approach to near-term quantum applications. These systems combine quantum processing units with traditional CPUs, GPUs, and specialized processors to create quantum-enhanced workflows for practical applications[3]. This hybrid approach acknowledges that quantum computers will likely complement rather than replace classical computing for most applications, particularly in optimization, machine learning, and quantum chemistry where quantum processors can provide computational advantages for specific problem components while classical systems handle other aspects of the computation.\n\nMicrosoft's quantum computing strategy focuses on topological qubits, which theoretically offer superior error resistance compared to other qubit types. The company's Majorana 1 processor, announced in February 2025, is designed to scale to one million qubits through hardware-protected quantum states[5]. However, Microsoft's approach has faced skepticism from quantum experts who question whether the Majorana zero modes necessary for topological quantum computing have been definitively demonstrated[21]. Despite these challenges, Microsoft's partnerships with companies like Atom Computing and Quantinuum provide alternative pathways to quantum computing capabilities while the company continues developing its topological approach.\n\n## Market Size and Growth Projections\n\nThe quantum computing market is experiencing explosive growth that far exceeds typical technology sector expansion rates, with projections indicating a transformation from a nascent industry to a major economic force by 2035. Current market valuations place the global quantum computing market at $1.3 billion in 2024, with expectations of reaching $1.8 billion in 2025 and approximately $5.4 billion by 2029, representing a compound annual growth rate of 32.7% during the forecast period[4]. These growth projections reflect the industry's rapid maturation from research-focused initiatives to commercially viable applications across multiple sectors.\n\nThe long-term market projections present an even more dramatic growth trajectory, with McKinsey projecting that quantum computing could be worth $28-72 billion by 2035, quantum communication reaching $11-15 billion, and quantum sensing achieving $7-10 billion in market value[2]. The total quantum technology market could reach $198 billion by 2040, representing a comprehensive ecosystem that extends far beyond computing to encompass communication, sensing, and other quantum-enabled applications. The most optimistic projections suggest that quantum computing alone could reach $90-170 billion in market value by 2040, indicating the potential for this technology to become a major driver of global economic activity[2].\n\nThe phenomenal growth rates projected for quantum computing reflect several converging factors that are accelerating market development. Investment in quantum computer companies surged from $550 million in Q1 2024 to more than $1.25 billion in Q1 2025, representing a 128% increase year-over-year[8]. This dramatic increase in funding demonstrates growing investor confidence that quantum computing is approaching commercial viability rather than remaining confined to experimental research. The shift from research-focused investment to commercially oriented funding reflects industry maturation and expectations of near-term revenue generation from quantum technologies.\n\nQuantum Computing as a Service (QCaaS) represents the fastest-growing segment of the quantum computing market, with projections indicating it could account for over 40% of the quantum computing market by 2030[9]. This service-oriented approach enables organizations to access quantum computing capabilities without the substantial capital investments required for quantum hardware infrastructure. Major cloud providers including AWS, Google Cloud, and Azure are expanding their quantum services offerings, making quantum computing accessible to a broader range of organizations and use cases. The QCaaS model also accelerates adoption by reducing barriers to entry and enabling companies to experiment with quantum applications before committing to larger investments.\n\nThe geographic distribution of quantum market value creation reveals significant concentrations in countries with substantial public and private quantum investments. The United States, United Kingdom, Germany, France, China, and Japan are positioned to capture much of the value created by quantum computing through 2035[9]. These countries have made substantial public investments in quantum research and development while fostering private sector innovation through favorable regulatory environments and strategic partnerships between government, academia, and industry.\n\nHealthcare applications of quantum computing represent a particularly high-growth market segment, with the global quantum computing in healthcare market valued at $191.3 million in 2024 and projected to reach $1.324 billion by 2030, representing a compound annual growth rate of 37.9%[15]. The pharmaceutical and biotechnology sectors are expected to be primary adopters of quantum computing technologies, driven by the technology's potential to accelerate drug discovery, molecular modeling, and clinical trial optimization. Quantum computing's ability to simulate biological systems at the molecular level provides capabilities that classical computing cannot match, particularly for complex protein folding problems and drug interaction modeling.\n\nThe enterprise quantum computing market is witnessing rapid expansion as businesses across various industries recognize quantum computing's transformative potential. Companies are particularly focused on leveraging quantum computing for optimization, simulation, data analysis, and cryptography applications[4]. The increasing availability of quantum-as-a-service platforms has democratized access to quantum computing capabilities, enabling small and medium-sized enterprises to explore quantum applications without significant infrastructure investments. This democratization effect is accelerating market growth by expanding the potential customer base beyond large corporations and research institutions.\n\nInvestment patterns within the quantum computing ecosystem reveal strategic priorities and market expectations. Quantum computer companies received more than 70% of all quantum-related funding in Q1 2025, with major funding rounds going to IonQ ($360 million), QuEra Computing ($230 million), Quantum Machines ($170 million), and D-Wave Systems ($150 million)[8]. These substantial investment rounds reflect investor confidence in scalable quantum architectures and enterprise deployment capabilities rather than early-stage research initiatives.\n\nThe economic impact projections for quantum computing extend beyond direct market revenues to encompass broader value creation across industries. The Quantum Insider projects that quantum computing will unlock a cumulative $1 trillion of value creation for end users through 2035, while generating approximately $50 billion in direct vendor revenues during the same period[9]. This 20-to-1 ratio of value creation to vendor revenues reflects quantum computing's role as an enabling technology that can drive efficiency improvements, cost reductions, and new capabilities across multiple industries rather than simply generating direct hardware and software sales.\n\nEmployment projections for the quantum sector indicate substantial job creation potential, with estimates suggesting the quantum sector will generate approximately 250,000 new jobs by 2030, expanding to 840,000 jobs by 2035[9]. These employment opportunities span a range of industries and skill levels, from specialized quantum algorithm developers and hardware engineers to business analysts and project managers working on quantum-enabled applications. The broad employment impact reflects quantum computing's potential to create new industries and transform existing ones rather than simply replacing current technologies.\n\n## Key Players and Competitive Landscape\n\nThe quantum computing industry features a diverse ecosystem of established technology giants, specialized quantum companies, and emerging startups, each pursuing different technological approaches and market strategies. The competitive landscape reflects the industry's early stage, where multiple technological paradigms compete for market leadership and no single approach has achieved clear dominance.\n\nIBM maintains its position as the quantum computing industry leader through a comprehensive approach that encompasses both hardware development and software ecosystem creation. The company's quantum computing efforts center around superconducting transmon qubit technology, with their latest Condor processor featuring 1,121 qubits representing a significant milestone in quantum computing scale[6]. IBM's competitive advantage extends beyond raw qubit count to include their extensive software ecosystem, including the Qiskit quantum programming framework and quantum serverless computing platforms that make quantum computing more accessible to developers and researchers. The company's quantum roadmap extends to 2033 with ambitious plans for a 100,000-qubit system and the development of error-corrected logical qubits. IBM's June 2025 announcement of their plan to build the world's first large-scale fault-tolerant quantum computer by 2029, codenamed \"Quantum Starling,\" represents a bold commitment to achieving practical quantum advantage[25].\n\nGoogle's Quantum AI initiative represents one of the most technically advanced quantum computing programs, building on their 2019 demonstration of quantum supremacy with the Sycamore processor. The company's recent Willow chip achievement, demonstrating quantum error correction with 105 superconducting qubits, marks a crucial milestone in the path toward fault-tolerant quantum computing[7]. Google's approach combines cutting-edge hardware development with advanced quantum algorithms, particularly focusing on machine learning and artificial intelligence applications. The company's roadmap targets a practical, error-corrected quantum computer by 2029, with CEO Sundar Pichai emphasizing quantum computing's potential role in addressing global challenges including climate change and drug discovery. Google's quantum supremacy demonstration and subsequent error correction achievements have established the company as a technology leader, though questions remain about the practical applicability of their quantum advantage demonstrations.\n\nMicrosoft pursues a distinctive strategy focused on topological quantum computing, which theoretically offers superior error resistance compared to other quantum computing approaches. The company's Majorana 1 processor, introduced in February 2025, is designed to scale to one million qubits through hardware-protected quantum states[5]. Microsoft's quantum strategy also emphasizes software and cloud services integration, with their quantum development kit and Azure Quantum cloud platform providing comprehensive quantum computing tools. The company's partnerships with quantum hardware providers including Atom Computing and Quantinuum enable customers to access various quantum computing technologies through Microsoft's cloud infrastructure. However, Microsoft's topological approach has faced technical challenges and skepticism from quantum experts regarding the demonstration of Majorana zero modes necessary for topological quantum computing[21].\n\nIonQ has emerged as the leading pure-play quantum computing company, focusing exclusively on trapped ion quantum computing technology. The company's $360 million funding round in Q1 2025 represents the largest quantum computing investment during that period, reflecting strong investor confidence in their commercial prospects[8]. IonQ's trapped ion approach offers advantages in qubit quality and coherence times, with the company emphasizing their systems' ability to achieve high-fidelity quantum operations and all-to-all qubit connectivity. The company's strategy focuses on enterprise deployment through cloud platforms and direct customer engagements, targeting applications in finance, healthcare, and optimization. IonQ's public listing and substantial funding provide resources for scaling their technology and competing with larger technology companies in the quantum computing market.\n\nRigetti Computing represents another significant pure-play quantum computing company, focusing on superconducting quantum processors and hybrid quantum-classical computing systems. The company's roadmap plans a 36-qubit system by mid-2025 and over 100 qubits by year-end, with long-term goals of a 336-qubit Lyra system[5]. Rigetti's Ankaa-3 system achieved 84 qubits with 99%+ two-qubit gate fidelity by 2024, demonstrating competitive performance in the superconducting quantum computing space. The company's modular architecture approach aims to enable practical applications in machine learning and optimization, while their quantum cloud services platform provides access to quantum computing capabilities for enterprise customers.\n\nD-Wave Systems occupies a unique position in the quantum computing landscape through their focus on quantum annealing technology rather than gate-based quantum computing. The company's quantum annealing approach targets optimization problems where classical computers face computational limitations[8]. D-Wave's $150 million funding round in Q1 2025 reflects continued investor interest in their specialized approach to quantum computing, particularly for hybrid quantum-classical optimization applications. While quantum annealing has limitations compared to universal quantum computing approaches, D-Wave's technology offers near-term practical applications for specific problem types, providing a bridge between classical and quantum computing capabilities.\n\nQuEra Computing has gained significant attention for their neutral atom quantum computing approach, raising $230 million in Q1 2025 to advance their technology development[8]. The company's Aquila system represents the largest publicly available quantum computer with 256 atoms, demonstrating the scalability potential of neutral atom architectures. QuEra's technology offers advantages in qubit uniformity and scalability, with the potential to create quantum systems with thousands of atoms. The substantial investment in QuEra reflects growing investor confidence in alternative quantum computing approaches beyond the dominant superconducting and trapped ion platforms.\n\nQuantinuum has achieved significant technical milestones in quantum error correction, reporting the first universal, fully fault-tolerant quantum gate set with repeatable error correction[24]. The company's achievements in magic state distillation and fault-tolerant quantum operations represent crucial steps toward practical fault-tolerant quantum computing. Quantinuum's technical accomplishments have positioned the company as a leader in quantum error correction research, with their results validating key techniques required for scalable fault-tolerant quantum computers.\n\nAlice & Bob represents emerging European quantum computing capabilities, with the French company raising €100 million to advance their fault-tolerant cat qubit technology[8]. The company's approach to superconducting quantum computing focuses on error correction and fault tolerance, addressing fundamental challenges in scaling quantum computers to practical applications. European investment in quantum computing companies like Alice & Bob reflects the global nature of quantum computing competition and the importance of regional quantum technology capabilities.\n\nQuantum Machines has secured $170 million in funding to develop quantum orchestration hardware and software, addressing the critical need for control systems that can operate across various quantum computing architectures[8]. The company's focus on quantum control and orchestration represents an important ecosystem component that enables compatibility between different quantum hardware platforms and classical computing systems. Their substantial funding reflects the importance of control systems in realizing practical quantum computing applications.\n\nThe competitive landscape also includes major technology companies that have significant quantum computing initiatives but are not primarily quantum-focused. Intel leverages their semiconductor manufacturing expertise to develop silicon-based quantum processors, with their Tunnel Falls chip using spin qubits in silicon[6]. Amazon provides quantum computing access through their Amazon Web Services platform while developing their own quantum hardware through Amazon Center for Quantum Computing. These large technology companies bring substantial resources and complementary capabilities to quantum computing development, though their quantum efforts represent relatively small portions of their overall business activities.\n\n## Commercial Applications and Use Cases\n\nThe quantum computing industry is witnessing a significant shift from theoretical research to practical applications across multiple sectors, with early commercial deployments demonstrating real-world value creation. The breadth of applications spans industries from finance and healthcare to logistics and cybersecurity, indicating quantum computing's potential to transform numerous aspects of modern business and society.\n\nFinancial services represent one of the most promising near-term markets for quantum computing applications, with major institutions already investing heavily in quantum technologies for portfolio optimization, risk analysis, and fraud detection. JPMorgan Chase has partnered with quantum computing companies to explore portfolio optimization applications, achieving problem size reductions of up to 80% compared to classical approaches[28]. The financial sector's interest in quantum computing stems from the technology's ability to solve complex optimization problems that are computationally intractable for classical computers, particularly in areas like derivative pricing, risk modeling, and market analysis. Goldman Sachs has similarly partnered with quantum startups to explore quantum portfolio optimization, recognizing the potential for quantum algorithms to provide competitive advantages in financial modeling and decision-making[26]. Quantum computing's ability to analyze multivariate relationships and simulate complex market dynamics offers unprecedented capabilities for financial risk management and investment strategy development.\n\nHealthcare and pharmaceutical applications represent perhaps the most transformative potential for quantum computing, with the technology enabling molecular-level simulations that could revolutionize drug discovery and personalized medicine. The global quantum computing in healthcare market is projected to grow from $191.3 million in 2024 to $1.324 billion by 2030, reflecting the sector's recognition of quantum computing's potential impact[15]. Pharmaceutical companies are investing heavily in quantum drug discovery, utilizing quantum computers to simulate molecular interactions and test billions of drug compound combinations in silico before proceeding to costly physical trials. This approach has the potential to reduce drug development timelines from the current 10-year average to under three years, representing enormous cost savings and faster patient access to new treatments[26]. Quantum computing's ability to model quantum mechanical effects in biological systems provides capabilities that classical computers cannot match, particularly for understanding protein folding, enzyme catalysis, and drug-target interactions.\n\nPfizer and IBM have collaborated on quantum molecular modeling projects to advance treatments for diseases including cancer, demonstrating the practical application of quantum computing in pharmaceutical research[28]. The genomics and precision medicine segment is expected to experience the fastest growth among healthcare applications, with quantum technology's ability to process complex genetic data at unprecedented speeds enabling more accurate and personalized treatment development. Quantum computing can significantly enhance the analysis of genetic information including DNA sequences and protein structures, potentially leading to faster and more accurate development of personalized therapies for conditions like cancer and rare genetic disorders.\n\nSupply chain optimization represents another area where quantum computing is demonstrating practical value. DHL has successfully applied quantum algorithms to optimize international shipping routes, achieving delivery time reductions of up to 20% compared to classical optimization methods[28]. The logistics industry faces increasingly complex optimization challenges as global supply chains become more sophisticated and customers demand faster, more reliable delivery services. Quantum computing's ability to simultaneously evaluate vast numbers of variables and constraints makes it particularly well-suited for multi-modal transportation optimization, inventory management, and demand forecasting applications. The COVID-19 pandemic highlighted supply chain vulnerabilities and the need for more resilient and adaptive logistics networks, creating demand for advanced optimization technologies including quantum computing.\n\nCybersecurity applications present both opportunities and challenges for quantum computing adoption. While quantum computers pose a significant threat to current cryptographic systems, they also enable new forms of quantum-safe encryption and security protocols[11]. The development of post-quantum cryptography has become a critical priority for organizations seeking to protect sensitive data against future quantum computing threats. The National Institute of Standards and Technology (NIST) has begun standardizing quantum-safe encryption protocols, and businesses that implement these technologies early will maintain competitive advantages as quantum cybersecurity becomes essential[26]. The immediate threat of \"Harvest Now, Decrypt Later\" attacks, where adversaries collect encrypted data today with the intention of decrypting it using future quantum computers, is driving urgent adoption of quantum-safe security measures across industries.\n\nArtificial intelligence and machine learning applications represent a rapidly growing area of quantum computing utilization, with the convergence of AI and quantum computing creating opportunities for enhanced computational capabilities. Quantum AI can accelerate training times for deep learning models, solve complex optimization problems, and enhance natural language processing and computer vision applications[26]. Traditional AI models require enormous computational resources and training time, but quantum systems offer the potential to dramatically reduce these requirements while enabling more sophisticated AI capabilities. This convergence could lead to breakthroughs in autonomous vehicle technology, predictive analytics, and AI-driven healthcare applications.\n\nClimate modeling and sustainability applications leverage quantum computing's ability to simulate highly complex systems for environmental benefit. Quantum climate modeling can provide more accurate weather pattern predictions, optimize renewable energy grid management, and discover new sustainable materials[26]. Volkswagen has explored quantum algorithms for optimizing electric vehicle battery performance, demonstrating practical applications in sustainable transportation technology. The urgency of addressing climate change has created demand for more accurate environmental modeling and optimization tools, positioning quantum computing as a key technology for sustainability initiatives.\n\nManufacturing and materials science applications utilize quantum computing's molecular simulation capabilities to design new materials with enhanced properties. Quantum computers can simulate quantum mechanical effects in materials at the atomic level, enabling the discovery of new catalysts, semiconductors, and structural materials with properties optimized for specific applications[17]. This capability could transform industries ranging from aerospace and automotive to electronics and construction by enabling materials with superior performance, reliability, and sustainability characteristics.\n\nOptimization applications span multiple industries and use cases, from traffic flow management and energy distribution to financial trading and resource allocation. Quantum computing's ability to evaluate enormous solution spaces simultaneously makes it particularly valuable for complex optimization problems that classical computers cannot solve efficiently. These applications often provide immediate return on investment by reducing costs, improving efficiency, or enabling new capabilities that were previously impossible.\n\nThe transition from experimental to commercial quantum applications is accelerating as quantum computing hardware becomes more reliable and accessible through cloud platforms. Quantum-as-a-Service offerings from major cloud providers enable organizations to experiment with quantum applications without substantial capital investments, lowering barriers to adoption and accelerating the development of practical quantum use cases. This democratization of quantum computing access is enabling smaller organizations and startups to explore quantum applications, potentially accelerating innovation and expanding the range of commercial applications.\n\n## Investment Trends and Funding Landscape\n\nThe quantum computing investment landscape has undergone a dramatic transformation in 2025, reflecting a fundamental shift from long-term research funding to commercially focused investment expecting near-term returns. The surge in quantum computing investment represents one of the most significant developments in the technology sector, with total funding more than doubling compared to previous years and indicating strong investor confidence in the technology's commercial viability.\n\nInvestment in quantum computer companies reached unprecedented levels in Q1 2025, with more than $1.25 billion raised during the quarter compared to $550 million in the same period of 2024, representing a remarkable 128% increase year-over-year[8]. This dramatic growth in funding reflects a fundamental change in investor perception of quantum computing, shifting from viewing it as speculative long-term research to recognizing it as a technology approaching commercial readiness. The investment surge encompasses both private venture capital and public market activity, indicating broad-based confidence in quantum computing's near-term commercial prospects.\n\nThe distribution of investment across quantum technology segments reveals strategic priorities within the industry. Quantum computing companies captured more than 70% of all quantum-related funding in Q1 2025, significantly outpacing other quantum technology areas including quantum software, hardware components, communications, and sensing[8]. This concentration of investment in quantum computing reflects investor belief that quantum computers represent the most significant commercial opportunity within the broader quantum technology ecosystem. The focus on full-stack quantum computing companies suggests investors are prioritizing integrated solutions that can deliver complete quantum computing capabilities rather than specialized component technologies.\n\nIndividual company funding rounds in Q1 2025 demonstrate the scale of investment flowing into leading quantum computing companies. IonQ's $360 million funding round represents the largest quantum computing investment during the period, strengthening the company's position as the leading pure-play quantum computing company and providing resources for scaling their trapped ion quantum systems for enterprise applications[8]. QuEra Computing's $230 million funding round reflects growing investor confidence in neutral atom quantum computing architectures as a viable alternative to established superconducting and trapped ion approaches. The substantial investment in QuEra indicates that investors are diversifying their quantum computing bets across multiple technological approaches rather than concentrating on a single dominant technology.\n\nQuantum Machines' $170 million funding round highlights the importance of quantum control and orchestration systems that enable quantum computers to function effectively. The company's focus on hardware and software compatibility across various quantum architectures addresses a critical need for standardization and interoperability in the quantum computing ecosystem[8]. This investment reflects recognition that successful quantum computing deployments require sophisticated control systems and software stacks, not just quantum processors. D-Wave Systems' $150 million funding round demonstrates continued investor interest in quantum annealing technologies for optimization applications, even as the broader industry focuses on gate-based universal quantum computing approaches.\n\nThe geographic distribution of quantum computing investment reveals regional strengths and strategic priorities. North American companies continue to attract the largest share of quantum computing investment, reflecting the region's established quantum computing industry and favorable investment environment. European quantum computing companies, including France's Alice & Bob with their €100 million funding round, are gaining significant investor attention and developing regional quantum computing capabilities[8]. The global nature of quantum computing investment indicates that this technology is viewed as strategically important across multiple regions and economic systems.\n\nGovernment investment continues to play a crucial role in quantum computing development, complementing private sector funding with long-term research support and strategic initiatives. The U.S. National Quantum Initiative Reauthorization Act, authorizing $2.7 billion over five years for quantum technology development, demonstrates continued government commitment to maintaining American leadership in quantum technologies[12]. This legislation shifts focus from basic research toward applied quantum science and practical applications, reflecting the technology's maturation toward commercial viability. The inclusion of new federal agencies including the National Institutes of Health, State Department, and Small Business Administration in quantum initiatives indicates recognition of quantum computing's broad potential impact across government functions.\n\nThe funding pattern reveals a shift from early-stage research investments toward later-stage commercial development funding. Investors are increasingly focusing on companies that demonstrate clear paths to revenue generation and commercial deployment rather than purely research-oriented initiatives. This trend reflects growing confidence that quantum computing has moved beyond the experimental phase toward practical applications that can generate return on investment. The emphasis on enterprise-ready quantum computing solutions indicates investor belief that business applications will drive the first wave of quantum computing commercialization.\n\nVenture capital firms specializing in deep technology and hardware investments have become major players in quantum computing funding. These investors bring expertise in evaluating complex technical risks and supporting companies through the challenging transition from research to commercial deployment. The involvement of experienced deep technology investors provides quantum computing companies with strategic guidance and industry connections necessary for successful commercialization. Corporate venture capital arms of major technology companies are also increasing their quantum computing investments, recognizing the strategic importance of quantum technologies for future business applications.\n\nThe public market reception of quantum computing companies provides another indicator of investor sentiment and commercial expectations. Public quantum computing companies including IonQ, Rigetti Computing, and D-Wave Systems have provided investors with early access to quantum computing investment opportunities, though these companies remain in early revenue phases with profitability still years away[20]. The public market valuations of quantum computing companies reflect long-term growth expectations rather than current financial performance, indicating investor belief in the transformative potential of quantum technologies.\n\nInvestment metrics for evaluating quantum computing companies have evolved beyond traditional technology company financial measures to include quantum-specific technical indicators. Investors increasingly evaluate quantum companies based on qubit count and quality, quantum volume, gate fidelity, error rates, and technical roadmaps toward fault-tolerant quantum computing[20]. Patent portfolios, partnerships with government and enterprise customers, and cloud platform accessibility have become important factors in investment decisions. These specialized evaluation criteria reflect the unique technical challenges and opportunities in quantum computing compared to traditional software and hardware companies.\n\nThe investment landscape also reflects expectations for market consolidation as the quantum computing industry matures. Investors are positioning for potential acquisitions and partnerships between quantum computing companies and larger technology corporations. The substantial funding raised by leading quantum companies provides resources for competitive positioning and potential acquisition of smaller quantum technology firms. This dynamic suggests that the current diverse ecosystem of quantum computing companies may consolidate around a smaller number of dominant players as the technology reaches commercial maturity.\n\n## Regulatory Framework and Policy Challenges\n\nThe regulatory landscape surrounding quantum computing is rapidly evolving as governments worldwide recognize both the transformative potential and national security implications of quantum technologies. The development of comprehensive regulatory frameworks presents complex challenges that must balance innovation promotion with security concerns, international cooperation with competitive advantages, and technological advancement with ethical considerations.\n\nThe United States has established the most comprehensive quantum policy framework through the National Quantum Initiative Act, originally enacted in 2018 and recently reauthorized with $2.7 billion in funding through 2034[12]. This legislation creates a coordinated approach to quantum information science research and development across multiple federal agencies, including the National Institute of Standards and Technology (NIST), National Science Foundation (NSF), and Department of Energy. The reauthorization reflects a strategic shift from basic research toward practical applications, addressing the critical \"valley of death\" where promising technologies often fail to transition from laboratory research to commercial deployment. The legislation establishes new quantum research centers, workforce development programs, and public-private collaboration initiatives designed to maintain American leadership in quantum technologies while fostering commercial innovation.\n\nExport controls represent one of the most significant regulatory challenges facing the quantum computing industry, with the U.S. Commerce Department implementing comprehensive restrictions on quantum computing technologies in September 2024[22]. These controls cover key equipment, materials, software, and complete quantum computer systems, requiring licenses for exports to most countries while creating exceptions for allies with equivalent control measures. The export control framework reflects growing concerns about the national security implications of quantum computing, particularly the technology's potential to break current encryption methods and provide military advantages. The regulations specifically target countries identified as national security concerns, including China, Russia, and Iran, while attempting to preserve international scientific collaboration essential for quantum research advancement.\n\nThe implementation of export controls creates significant compliance burdens for quantum computing companies engaged in international business. Companies must navigate complex licensing requirements for technology transfers, international partnerships, and foreign investment arrangements[22]. The regulations extend to \"deemed exports\" where sharing controlled technology with foreign nationals within the United States is considered equivalent to exporting the technology to their home countries. However, recognizing the importance of foreign talent to the U.S. quantum workforce, the regulations create exceptions for academic research and educational activities while requiring disclosure of certain foreign national participation in quantum research projects.\n\nInternational coordination of quantum regulations presents both opportunities and challenges for industry development. The United States has encouraged allied countries to implement equivalent export controls, creating a coordinated approach to quantum technology security while maintaining scientific and commercial collaboration among trusted partners[22]. This approach aims to prevent authoritarian regimes from accessing advanced quantum technologies while preserving the international cooperation necessary for quantum research advancement. However, differing national approaches to quantum regulation create compliance complexities for multinational quantum companies and may fragment the global quantum technology ecosystem.\n\nCybersecurity regulations are evolving rapidly to address the quantum computing threat to current encryption systems. The National Institute of Standards and Technology has begun standardizing post-quantum cryptography algorithms designed to resist quantum computing attacks, with organizations increasingly required to implement quantum-safe encryption protocols[11]. The urgency of this transition stems from the threat of \"Harvest Now, Decrypt Later\" attacks where adversaries collect encrypted data today with the intention of decrypting it using future quantum computers. Regulatory frameworks are emerging to require organizations handling sensitive data to implement quantum-safe security measures, creating compliance requirements that will drive quantum cybersecurity market growth.\n\nThe regulatory approach to quantum computing differs significantly from traditional technology regulation due to the fundamental nature of quantum information processing. Quantum computers operate according to quantum mechanical principles that create both unprecedented computational capabilities and unique security vulnerabilities[10]. Traditional regulatory frameworks based on classical information processing assumptions may be inadequate for addressing quantum computing's implications. Policymakers must develop new regulatory approaches that account for quantum computing's ability to solve certain problems exponentially faster than classical computers while creating new categories of computational problems and security risks.\n\nIntellectual property policy presents complex challenges for quantum computing regulation, with questions arising about appropriate patent protection duration and scope for quantum technologies[10]. The rapidly evolving nature of quantum technology suggests that traditional patent protection periods may be too long, potentially stifling innovation by concentrating market power in early patent holders. Conversely, shorter patent protection periods might discourage investment in quantum research and development by reducing the exclusivity period for recovering research investments. The unique nature of quantum algorithms and hardware creates additional challenges for patent evaluation and enforcement, requiring specialized expertise that may not be available in traditional patent examination processes.\n\nAntitrust considerations are becoming increasingly important as the quantum computing industry begins to consolidate around a smaller number of dominant players. The substantial capital requirements for quantum computing research and development may create natural barriers to entry that could limit competition[10]. Large technology companies with existing quantum computing programs may have advantages in acquiring quantum startups and potentially limiting competition in quantum markets. Regulatory authorities must balance the need for industry consolidation to achieve technical milestones with maintaining competitive markets that foster innovation and prevent monopolistic behavior.\n\nData privacy and protection regulations must evolve to address quantum computing's unique capabilities and vulnerabilities. Quantum computers' ability to break current encryption methods creates new categories of data protection risks that existing privacy regulations may not adequately address[10]. Organizations collecting and processing personal data must consider the long-term security implications of quantum computing and implement appropriate protective measures. Regulatory frameworks like the European Union's General Data Protection Regulation may provide guidance for developing quantum-specific data protection requirements, but new regulatory approaches may be necessary to address quantum computing's unique characteristics.\n\nWorkforce development regulations and policies are crucial for addressing the quantum talent shortage that threatens industry growth. Government programs aimed at quantum education and training must navigate complex issues related to foreign national participation in quantum research while maintaining the international collaboration necessary for scientific advancement[23]. Immigration policies may need adjustment to attract and retain international quantum talent while addressing national security concerns. Educational regulations and standards must evolve to incorporate quantum information science into curricula at various levels, from K-12 education through advanced graduate training.\n\nThe regulatory framework must also address ethical considerations related to quantum computing applications. The technology's potential applications in surveillance, artificial intelligence enhancement, and military systems raise questions about appropriate use limitations and oversight mechanisms[10]. International agreements may be necessary to prevent quantum computing applications that could destabilize international security or violate human rights principles. The dual-use nature of quantum technologies creates challenges for regulators who must balance scientific advancement with security and ethical concerns.\n\n## Technical Challenges and Limitations\n\nDespite significant recent progress, quantum computing faces fundamental technical challenges that continue to limit commercial deployment and scalability. These limitations stem from the inherent fragility of quantum systems and the extreme precision required to manipulate quantum information reliably, creating substantial engineering obstacles that must be overcome before quantum computers can achieve their theoretical potential.\n\nQubit instability and decoherence represent the most fundamental technical challenge facing quantum computing systems. Qubits are extremely sensitive to environmental interference, losing their quantum state through interactions with their surroundings in a process called decoherence[16]. Most current quantum computing systems, including IBM's superconducting qubits, maintain coherence for only 100-200 microseconds, severely limiting the complexity of quantum algorithms that can be executed before quantum information is lost. Trapped ion systems achieve longer coherence times ranging from 0.2 seconds to 600 seconds depending on the qubit type, but even these extended periods constrain practical quantum computations. The fundamental challenge is that quantum computers require isolation from their environment to maintain quantum states, while simultaneously requiring external control to perform computations, creating an inherent tension that limits system performance.\n\nError rates in quantum operations present another critical limitation that must be addressed for practical quantum computing applications. Basic quantum operations like gate operations typically exhibit error rates of 0.1% to 1% per operation, which accumulate rapidly as quantum algorithms become more complex[16]. These error rates are orders of magnitude higher than classical computer error rates, making quantum computers unreliable for most practical applications without sophisticated error correction systems. The high error rates stem from the fundamental difficulty of controlling quantum systems with the precision required for reliable computation, including challenges in laser control for trapped ion systems, microwave pulse accuracy for superconducting systems, and environmental stability for all quantum computing platforms.\n\nQuantum error correction represents both a potential solution to error rate problems and a significant technical challenge in its own right. Current theoretical approaches to quantum error correction require thousands of physical qubits to create a single error-corrected logical qubit, a resource overhead that no current quantum computer can provide[16]. The threshold requirements for effective quantum error correction remain beyond the capabilities of existing quantum systems, creating a circular challenge where quantum computers need error correction to scale, but scaling is required to implement effective error correction. Recent breakthroughs by companies like Quantinuum demonstrate progress toward fault-tolerant quantum computing, but significant technical hurdles remain before practical error correction becomes available[24].\n\nScalability challenges extend beyond qubit count to encompass the increasing complexity of controlling large-scale quantum systems. Adding more qubits to quantum computers increases noise, crosstalk between qubits, and control complexity in ways that can degrade overall system performance[16]. IBM's 433-qubit Osprey processor, despite its impressive qubit count, still struggles with error rates that limit practical applications, demonstrating that simply increasing qubit numbers does not automatically improve quantum computing capabilities. The interconnection and control of large numbers of qubits requires sophisticated classical control systems that must operate with extreme precision while minimizing interference with quantum operations.\n\nQuantum algorithm development faces limitations related to the types of problems that quantum computers can solve more efficiently than classical computers. While quantum computing offers theoretical advantages for certain problem classes, including factoring large numbers and simulating quantum systems, many practical business applications do not map naturally onto quantum algorithms[19]. The development of quantum algorithms requires specialized expertise that combines quantum physics, computer science, and domain-specific knowledge, creating barriers for organizations seeking to apply quantum computing to their specific problems. The limited library of proven quantum algorithms constrains the range of applications where quantum computers can provide practical advantages over classical systems.\n\nManufacturing and fabrication challenges limit the ability to produce quantum computers reliably and cost-effectively. Quantum computer fabrication requires extreme precision and control, with manufacturing tolerances far exceeding those required for classical semiconductor devices[19]. Superconducting quantum computers require fabrication in clean room environments with atomic-level precision, while trapped ion systems need ultra-high vacuum chambers and precision laser systems. The specialized manufacturing requirements create high costs and limit the number of organizations capable of producing quantum computers, constraining supply and increasing prices for quantum computing systems.\n\nIntegration challenges arise when attempting to incorporate quantum computers into existing classical computing infrastructure. Quantum computers require sophisticated classical control systems, specialized software stacks, and hybrid quantum-classical algorithms to solve practical problems[3]. The integration of quantum processing units with classical computing systems requires new approaches to software development, system architecture, and workflow management. Most practical quantum applications will require hybrid systems that combine quantum and classical processing, creating additional complexity for system design and operation.\n\nStandardization limitations create interoperability challenges across different quantum computing platforms and vendors. The lack of common standards for quantum programming languages, hardware interfaces, and performance metrics makes it difficult to develop portable quantum applications or compare quantum systems objectively[19]. Different quantum computing companies have developed proprietary approaches to hardware architecture, software frameworks, and performance measurement, creating fragmentation that limits ecosystem development. The absence of industry standards also complicates procurement decisions for organizations considering quantum computing investments.\n\nEnvironmental requirements for quantum computing systems create operational challenges and cost burdens. Most quantum computers require cryogenic cooling systems that maintain temperatures near absolute zero, consuming substantial energy and requiring specialized facilities[16]. The extreme operating conditions necessary for quantum computers limit their deployment to specialized data centers and research facilities, reducing accessibility and increasing operational costs. While some quantum computing approaches like photonic and neutral atom systems can operate at room temperature, they face other technical limitations that may constrain their applications.\n\nThe talent shortage in quantum computing creates a bottleneck for addressing technical challenges and scaling quantum computing applications. The interdisciplinary nature of quantum computing requires expertise combining quantum physics, electrical engineering, computer science, and specific domain knowledge, creating a small pool of qualified professionals[23]. McKinsey reports only one qualified candidate available for every three quantum job openings, with more than half of quantum computing positions potentially going unfilled by 2025. The talent shortage limits the ability of organizations to develop quantum applications, maintain quantum systems, and address technical challenges limiting quantum computing deployment.\n\nCalibration and control challenges require continuous adjustment and optimization of quantum systems to maintain performance. Quantum computers require frequent recalibration as environmental conditions change and system components drift over time. The calibration process is complex and time-consuming, often requiring specialized expertise and limiting system availability for productive computation. Classical computers, in contrast, operate reliably without frequent recalibration, making them more suitable for production environments where consistent availability is required.\n\n## Future Outlook and Commercial Viability to 2035\n\nThe quantum computing industry stands at a critical juncture where technological breakthroughs, market demand, and investment convergence suggest a dramatic acceleration toward commercial viability through 2035. Multiple indicators point to the next decade as the period when quantum computing will transition from experimental technology to essential business infrastructure across multiple industries, though this transformation will occur gradually and face significant challenges.\n\nThe timeline for achieving fault-tolerant quantum computing, long considered the holy grail of the field, has accelerated significantly based on recent technical achievements and company roadmaps. IBM's commitment to delivering their Quantum Starling system by 2029, featuring 200 logical qubits capable of executing 100 million quantum gates, represents the most concrete timeline for large-scale fault-tolerant quantum computing[25]. Google's roadmap targets a useful, error-corrected quantum computer by 2029, building on their recent Willow chip achievements in quantum error correction. Quantinuum's breakthrough in achieving fault-tolerant quantum gates validates the technical approaches necessary for scaling to practical systems[24]. These converging timelines suggest that fault-tolerant quantum computing will become available in the late 2020s, providing the foundation for commercial applications requiring high reliability and accuracy.\n\nMarket projections indicate explosive growth in quantum computing adoption once technical barriers are overcome. The global quantum computing market is expected to grow from $1.3 billion in 2024 to potentially $72 billion by 2035, representing a compound annual growth rate that far exceeds typical technology sector expansion[2]. The total economic impact could reach $1 trillion in value creation by 2035, spanning industries from finance and healthcare to logistics and cybersecurity[9]. These projections reflect quantum computing's potential to solve previously intractable problems rather than simply improving upon classical computing approaches, creating entirely new categories of business value and competitive advantage.\n\nIndustry-specific adoption patterns will likely determine the commercial success of quantum computing through 2035. Financial services are positioned to become early adopters due to quantum computing's advantages in portfolio optimization, risk analysis, and fraud detection, with companies like JPMorgan Chase and Goldman Sachs already investing heavily in quantum applications[26]. The pharmaceutical industry represents another high-potential early adopter, with quantum molecular simulation capabilities offering transformative advantages in drug discovery and development that could reduce development timelines from decades to years. Healthcare applications beyond pharmaceuticals, including personalized medicine and medical imaging optimization, could drive quantum adoption across the broader healthcare ecosystem.\n\nThe development of quantum computing ecosystems will be crucial for commercial success, requiring coordination among hardware vendors, software developers, cloud service providers, and end-user organizations. Quantum-as-a-Service platforms are expected to drive the majority of early commercial adoption by reducing barriers to entry and enabling organizations to access quantum capabilities without substantial capital investments[9]. Major cloud providers including AWS, Google Cloud, and Microsoft Azure are expanding their quantum offerings, creating accessible pathways for businesses to experiment with and deploy quantum applications. The maturation of quantum software tools and programming frameworks will enable broader developer participation in quantum application development.\n\nGeopolitical competition will significantly influence quantum computing development and deployment through 2035. The U.S.-China technology competition has extended to quantum computing, with both countries making substantial public investments and implementing export controls to maintain competitive advantages[21]. The European Union, United Kingdom, Japan, and other nations are also developing national quantum strategies and investment programs, creating a multipolar quantum computing landscape. These geopolitical dynamics may accelerate quantum computing development through competitive pressure while potentially fragmenting international collaboration that has historically driven scientific advancement.\n\nWorkforce development will be critical for realizing quantum computing's commercial potential, with projections suggesting 840,000 quantum-related jobs by 2035[9]. The current talent shortage threatens to constrain industry growth, with only one qualified candidate available for every three quantum job openings according to McKinsey research[23]. Educational institutions, government programs, and industry initiatives will need to dramatically expand quantum education and training programs to meet workforce demands. The interdisciplinary nature of quantum computing requires new educational approaches that combine quantum physics, computer science, and domain-specific knowledge across multiple industries.\n\nThe regulatory environment will continue evolving to balance innovation promotion with security concerns, potentially creating both opportunities and constraints for commercial quantum computing deployment. Export controls and international agreements may limit technology transfer and collaboration, while cybersecurity regulations will drive demand for post-quantum cryptography solutions. The development of quantum-safe encryption standards and their mandatory adoption across industries will create substantial market opportunities for quantum cybersecurity companies while requiring significant investment from organizations seeking to protect sensitive data.\n\nTechnical progress toward practical quantum advantage will determine commercial success across different application areas. While quantum computers have demonstrated theoretical advantages for specific problems, practical quantum advantage requires quantum systems that solve real-world problems better than classical computers while accounting for the full cost of quantum hardware, software, and expertise[17]. The achievement of practical quantum advantage will likely occur gradually across different application areas, starting with specialized optimization and simulation problems before expanding to broader business applications. The timeline for practical quantum advantage varies significantly by application area, with some optimization problems potentially achieving quantum advantage by the late 2020s while more complex applications may require additional technical development.\n\nInvestment patterns suggest continued strong funding for quantum computing development, though market expectations may create pressure for companies to demonstrate commercial progress more rapidly than previously expected. The shift from research-focused to commercially oriented investment reflects growing confidence in near-term quantum applications but also creates performance pressure that could accelerate consolidation among quantum companies[8]. Companies that can demonstrate clear paths to revenue generation and customer adoption will likely attract continued investment, while those remaining in pure research mode may face funding challenges.\n\nThe hybrid quantum-classical computing model will likely dominate commercial deployments through 2035, with quantum processors serving as specialized accelerators for specific computational tasks rather than general-purpose computers[3]. This approach acknowledges that quantum computers excel at certain problem types while classical computers remain superior for most computational tasks. The development of seamless integration between quantum and classical systems will be crucial for commercial success, requiring new software architectures, programming models, and workflow management systems.\n\nMarket consolidation is likely as the quantum computing industry matures, with successful companies acquiring specialized technology firms or forming strategic partnerships to build comprehensive quantum computing capabilities. Large technology companies including IBM, Google, Microsoft, and Amazon have advantages in scaling quantum technologies through their existing cloud platforms and enterprise relationships. Pure-play quantum companies that can demonstrate unique technical capabilities or market positions may become acquisition targets or strategic partners for larger firms seeking to expand their quantum offerings.\n\nBy 2035, quantum computing is expected to have achieved commercial viability in multiple application areas while continuing to face limitations that prevent universal adoption. The technology will likely serve as a specialized tool for solving specific types of problems rather than replacing classical computers, similar to how graphics processing units serve specialized roles in modern computing systems. The economic impact will be substantial in targeted applications, justifying continued investment and development while creating new industries and transforming existing ones. Success will depend on continued technical progress, effective workforce development, supportive regulatory frameworks, and the evolution of business models that can capture value from quantum computing's unique capabilities.\n\n## Conclusion\n\nThe quantum computing industry in 2025 represents a remarkable convergence of scientific breakthrough and commercial opportunity that positions this technology as one of the most significant innovations of the 21st century. The comprehensive analysis reveals an industry that has decisively moved beyond theoretical research to demonstrate practical applications across finance, healthcare, logistics, and cybersecurity, while attracting unprecedented investment levels that signal strong confidence in near-term commercial viability.\n\nThe technological landscape shows multiple competing approaches achieving significant milestones, from Google's Willow chip demonstrating quantum error correction to IBM's roadmap for fault-tolerant systems by 2029. The diversity of technical approaches, including superconducting, trapped ion, photonic, and emerging neutral atom systems, indicates a maturing field where different technologies may serve distinct market segments rather than a single approach dominating all applications. The recent breakthroughs in quantum error correction by companies like Quantinuum validate the fundamental techniques necessary for scaling quantum computers to practical applications, suggesting that the long-sought goal of fault-tolerant quantum computing is within reach.\n\nMarket projections indicating growth from $1.3 billion in 2024 to potentially $72 billion by 2035 reflect quantum computing's potential to create entirely new categories of business value rather than simply improving existing computational approaches. The $1 trillion in projected economic impact by 2035 spans multiple industries and demonstrates quantum computing's role as an enabling technology that can transform entire sectors. The shift in investment patterns from research-focused funding to commercially oriented investment, with quantum computing companies raising over $1.25 billion in Q1 2025 alone, indicates that the technology has reached an inflection point where investors expect near-term returns rather than long-term research outcomes.\n\nThe regulatory environment presents both challenges and opportunities, with export controls reflecting quantum computing's strategic importance while potentially constraining international collaboration essential for continued innovation. The development of post-quantum cryptography standards and their eventual mandatory adoption will create substantial market opportunities while requiring significant investment from organizations seeking to protect sensitive data. The National Quantum Initiative Reauthorization Act's $2.7 billion authorization demonstrates continued government commitment to maintaining competitive advantages in quantum technologies.\n\nHowever, significant challenges remain that will influence the industry's trajectory through 2035. Technical limitations including qubit instability, scalability challenges, and the need for sophisticated error correction continue to constrain practical applications. The quantum talent shortage, with only one qualified candidate for every three job openings, threatens to become a critical bottleneck for industry growth unless addressed through expanded education and training programs. The interdisciplinary nature of quantum computing requires new approaches to workforce development that combine quantum physics, computer science, and domain-specific expertise.\n\nThe commercial viability assessment suggests that quantum computing will achieve practical applications in specialized areas by the late 2020s, with broader adoption occurring throughout the early 2030s. The hybrid quantum-classical computing model will likely dominate commercial deployments, with quantum processors serving as specialized accelerators for specific computational tasks rather than general-purpose computers. Industries with complex optimization and simulation requirements, particularly finance and pharmaceuticals, are positioned to capture early value from quantum computing capabilities.\n\nLooking toward 2035, quantum computing is expected to establish itself as an essential technology for organizations requiring advanced computational capabilities in optimization, simulation, and cryptography. The technology will likely create new industries while transforming existing ones, justifying continued substantial investment despite remaining technical challenges. Success will depend on sustained progress in hardware development, software tools, workforce preparation, and regulatory frameworks that balance innovation with security concerns.\n\nThe quantum computing revolution is not a distant possibility but a current reality that demands immediate attention from business leaders, policymakers, and investors. Organizations that begin preparing for quantum computing adoption today will be positioned to capture competitive advantages as the technology matures, while those that delay may find themselves at significant disadvantages in increasingly quantum-enabled competitive landscapes. The next decade will determine which organizations, countries, and technologies will lead the quantum computing transformation that promises to reshape multiple aspects of modern society and economic activity."
        },
        "delta": {
          "role": "assistant",
          "content": ""
        }
      }
    ]
    }
    ```

    <Accordion title="Cost Breakdown for Sample Request">
      <Info>
        **Token Usage**

        * Prompt Tokens: 33
        * Completion Tokens: 11,395
        * Citation Tokens: 19,028
        * Search Queries: 21
        * Reasoning Tokens: 193,947
      </Info>

      <Steps>
        <Step title="Calculate Input Tokens Cost">
          33 tokens ÷ 1,000,000 × \$2 = \$0.000066
        </Step>

        <Step title="Calculate Output Tokens Cost">
          11,395  tokens ÷ 1,000,000 × \$8 = \$0.09116
        </Step>

        <Step title="Calculate Citation Tokens Cost">
          19,028 tokens ÷ 1,000,000 × \$2 = \$0.038056
        </Step>

        <Step title="Calculate Search Queries Cost">
          21 queries × \$5 ÷ 1,000 = \$0.105
        </Step>

        <Step title="Calculate Reasoning Tokens Cost">
          193,947 tokens ÷ 1,000,000 × \$3 = \$0.581841
        </Step>

        <Step title="Calculate Total Cost">
          \$0.000066 + \$0.09116 + \$0.038056 + \$0.105 + \$0.581841 = \$0.816123
        </Step>
      </Steps>

      <Check>
        **Total cost for this request: \$0.816123**
      </Check>
    </Accordion>
  </div>

  <div>
    <h2>Advanced Features</h2>

    <Tabs>
      <Tab title="Reasoning Effort">
        Control the computational effort dedicated to each query with the `reasoning_effort` parameter. This allows you to balance between speed and thoroughness while managing costs by directly impacting the amount of reasoning tokens consumed.

        **Options:**

        * `"low"`: Faster, simpler answers with reduced token usage
        * `"medium"`: Balanced approach (default)
        * `"high"`: Deeper, more thorough responses with increased token usage

        <CodeGroup>
          ```bash cURL wrap theme={null}
          curl --request POST \
            --url https://api.perplexity.ai/v1/sonar \
            --header "Authorization: Bearer <token>" \
            --header "Content-Type: application/json" \
            --data '{
              "model": "sonar-deep-research",
              "messages": [{"role": "user", "content": "Provide an exhaustive analysis of current approaches to achieving net-zero carbon emissions in heavy industry, including technological solutions, policy frameworks, and economic feasibility across different sectors."}],
              "reasoning_effort": "low"
            }' | jq
          ```

          ```python Python theme={null}
          import requests

          url = "https://api.perplexity.ai/v1/sonar"

          payload = {
              "model": "sonar-deep-research",
              "messages": [
                  {"role": "user", "content": "Provide an exhaustive analysis of current approaches to achieving net-zero carbon emissions in heavy industry, including technological solutions, policy frameworks, and economic feasibility across different sectors."}
              ],
              "reasoning_effort": "low"
          }
          headers = {
              "Authorization": "Bearer <token>",
              "Content-Type": "application/json"
          }

          response = requests.post(url, json=payload, headers=headers)
          print(response.json())
          ```
        </CodeGroup>

        <CodeGroup>
          ```json Success Response expandable wrap theme={null}
          {
          "id": "75b0f5a0-010c-4231-bade-ca38ec9f8789",
          "model": "sonar-deep-research",
          "created": 1753127531,
          "usage": {
          "prompt_tokens": 31,
          "completion_tokens": 6994,
          "total_tokens": 7025,
          "citation_tokens": 18133,
          "num_search_queries": 14,
          "reasoning_tokens": 61889
          },

          "search_results": [
          {
          "title": "Net zero options for heavy industry – National Energy Analysis Centre",
          "url": "https://research.csiro.au/neac/net-zero-options-for-heavy-industry/",
          "date": null,
          "last_updated": null
          },
          {
          "title": "[PDF] Mission Possible - Energy Transitions Commission",
          "url": "https://www.energy-transitions.org/wp-content/uploads/2020/08/ETC_MissionPossible_FullReport.pdf",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Heavy Industry - Net Zero Climate",
          "url": "https://netzeroclimate.org/sectors/heavy_industry/",
          "date": null,
          "last_updated": null
          },
          {
          "title": "25 ways heavy industries can reach net zero - IEA report",
          "url": "https://www.weforum.org/stories/2022/10/industry-net-zero-breakthrough-agenda-iea/",
          "date": null,
          "last_updated": null
          },
          {
          "title": "[PDF] Achieving Net Zero Heavy Industry Sectors in G7 Members",
          "url": "https://iea.blob.core.windows.net/assets/c4d96342-f626-4aea-8dac-df1d1e567135/AchievingNetZeroHeavyIndustrySectorsinG7Members.pdf",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Heavy Industry - Net Zero Climate",
          "url": "https://netzeroclimate.org/sectors/heavy_industry/",
          "date": null,
          "last_updated": null
          },
          {
          "title": "The challenge of reaching zero emissions in heavy industry - IEA",
          "url": "https://www.iea.org/articles/the-challenge-of-reaching-zero-emissions-in-heavy-industry",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Executive summary – Achieving Net Zero Heavy Industry ...",
          "url": "https://www.iea.org/reports/achieving-net-zero-heavy-industry-sectors-in-g7-members/executive-summary",
          "date": null,
          "last_updated": null
          },
          {
          "title": "[PDF] Mission Possible - Energy Transitions Commission",
          "url": "https://www.energy-transitions.org/wp-content/uploads/2020/08/ETC_MissionPossible_FullReport.pdf",
          "date": null,
          "last_updated": null
          },
          {
          "title": "How 6 heavy-emitting industries are working to decarbonize",
          "url": "https://www.sustainablemanufacturingexpo.com/en/articles/heavy-industries-decarbonize.html",
          "date": null,
          "last_updated": null
          },
          {
          "title": "[PDF] Achieving Net Zero Heavy Industry Sectors in G7 Members",
          "url": "https://iea.blob.core.windows.net/assets/c4d96342-f626-4aea-8dac-df1d1e567135/AchievingNetZeroHeavyIndustrySectorsinG7Members.pdf",
          "date": null,
          "last_updated": null
          },
          {
          "title": "25 ways heavy industries can reach net zero - IEA report",
          "url": "https://www.weforum.org/stories/2022/10/industry-net-zero-breakthrough-agenda-iea/",
          "date": null,
          "last_updated": null
          },
          {
          "title": "[PDF] Reaching net-zero carbon emissions - Energy Transitions Commission",
          "url": "https://www.energy-transitions.org/wp-content/uploads/2020/08/ETC-sectoral-focus-Steel_final.pdf",
          "date": null,
          "last_updated": null
          },
          {
          "title": "The challenge of reaching zero emissions in heavy industry",
          "url": "https://www.iea.org/articles/the-challenge-of-reaching-zero-emissions-in-heavy-industry",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Iron and Steel Industry Will Buy $250B Carbon Credits for Net Zero",
          "url": "https://carboncredits.com/iron-and-steel-industry-buys-250b-carbon-credits-net-zero/",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Achieving Net Zero Heavy Industry Sectors in G7 Members",
          "url": "https://iea.blob.core.windows.net/assets/c4d96342-f626-4aea-8dac-df1d1e567135/AchievingNetZeroHeavyIndustrySectorsinG7Members.pdf",
          "date": null,
          "last_updated": null
          },
          {
          "title": "What is net-zero steel and why do we need it?",
          "url": "https://www.weforum.org/stories/2022/09/what-is-net-zero-steel-and-why-do-we-need-it/",
          "date": null,
          "last_updated": null
          },
          {
          "title": "[PDF] Cost-Efficient Decarbonization of Portland Cement Production",
          "url": "https://www.hbs.edu/ris/download.aspx?name=24-025.pdf",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Achieving Net Zero Heavy Industry Sectors in G7 Members",
          "url": "https://iea.blob.core.windows.net/assets/c4d96342-f626-4aea-8dac-df1d1e567135/AchievingNetZeroHeavyIndustrySectorsinG7Members.pdf",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Cement's Carbon Footprint Doesn't Have to Be Set in Stone",
          "url": "https://www.bcg.com/publications/2024/cement-industry-carbon-footprint",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Cement costs and energy economics?",
          "url": "https://thundersaidenergy.com/downloads/cement-costs-and-energy-economics/",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Five Insights on the Concrete and Cement Industry's Transition ... - RMI",
          "url": "https://rmi.org/five-insights-on-the-concrete-and-cement-industrys-transition-to-net-zero/",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Cost-Efficient Pathways to Decarbonize Portland Cement Production",
          "url": "https://climate.mit.edu/posts/cost-efficient-pathways-decarbonize-portland-cement-production",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Mapping the Path to Industrial Decarbonization - RMI",
          "url": "https://rmi.org/mapping-the-path-to-industrial-decarbonization/",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Pathways to Decarbonization: A North American Aluminum Roadmap",
          "url": "https://www.aluminum.org/Decarb",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Policy Packages for Decarbonizing Heavy Industry",
          "url": "https://www.unido.org/sites/default/files/unido-publications/2023-12/IID%20Policy%20Brief%209%20-%20Policy%20packages%20for%20decarbonizing%20heavy%20industry.pdf",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Designing Carbon Contracts for Difference - Clean Air Task Force",
          "url": "https://www.catf.us/resource/designing-carbon-contracts-for-difference/",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Learning from CBAM's transitional phase: Early impacts on ...",
          "url": "https://www.cer.eu/publications/archive/policy-brief/2024/learning-cbams-transitional-impacts-trade",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Net zero options for heavy industry - CSIRO Research",
          "url": "https://research.csiro.au/neac/net-zero-options-for-heavy-industry/",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Marginal Abatement Cost Curves for U.S. Net-Zero Energy ...",
          "url": "https://www.edf.org/sites/default/files/documents/MACC_2.0%20report_Evolved_EDF.pdf",
          "date": null,
          "last_updated": null
          },
          {
          "title": "The challenge of reaching zero emissions in heavy industry - IEA",
          "url": "https://www.iea.org/articles/the-challenge-of-reaching-zero-emissions-in-heavy-industry",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Sustainable emissions pathways in the chemicals industry - PwC",
          "url": "https://www.pwc.com/gx/en/issues/business-model-reinvention/how-we-fuel-and-power/net-zero-chemicals-industry-transformation.html",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Electrification in mining industry to reduce CO2",
          "url": "https://blog.se.com/industry/mining-metals-minerals/2023/09/14/how-will-electrification-reduce-minings-large-carbon-footprint/",
          "date": null,
          "last_updated": null
          },
          {
          "title": "The challenge of reaching zero emissions in heavy industry",
          "url": "https://www.iea.org/articles/the-challenge-of-reaching-zero-emissions-in-heavy-industry",
          "date": null,
          "last_updated": null
          },
          {
          "title": "[PDF] The chemical industry's road to net zero - Accenture",
          "url": "https://www.accenture.com/content/dam/accenture/final/a-com-migration/r3-3/pdf/pdf-174/accenture-chemicals-costs-opportunities-eu-green-deal.pdf",
          "date": null,
          "last_updated": null
          },
          {
          "title": "The potential of electric vehicles for decarbonising mining",
          "url": "https://mine.nridigital.com/mine_may25/electric-vehicles-mining",
          "date": null,
          "last_updated": null
          },
          {
          "title": "ETC_MissionPossible_FullReport.pdf",
          "url": "https://www.energy-transitions.org/wp-content/uploads/2020/08/ETC_MissionPossible_FullReport.pdf",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Electric Mine Consortium. The road to zero emissions.",
          "url": "https://www.electricmine.com",
          "date": null,
          "last_updated": null
          },
          {
          "title": "Achieving Net Zero Heavy Industry Sectors in G7 Members",
          "url": "https://iea.blob.core.windows.net/assets/c4d96342-f626-4aea-8dac-df1d1e567135/AchievingNetZeroHeavyIndustrySectorsinG7Members.pdf",
          "date": null,
          "last_updated": null
          }
          ],
          "object": "chat.completion",
          "choices": [
          {
          "index": 0,
          "finish_reason": "stop",
          "message": {
          "role": "assistant",
          "content": "<think>\nWe are given a query: \"Provide an exhaustive analysis of current approaches to achieving net-zero carbon emissions in heavy industry, including technological solutions, policy frameworks, and economic feasibility across different sectors.\"\n\nWe have multiple search results (indexed [1] to [39]) that provide valuable information on this topic.\n\nWe must write a comprehensive report of at least 10,000 words, structured with sections and subsections, using Markdown headers. The report must be self-contained, with no bullet points or lists, and each paragraph must be at least 4-5 sentences. We must cite the relevant search results by index number in brackets at the end of the sentence where the information is used.\n\nLet's break down the query into key components:\n1. Technological solutions for net-zero in heavy industry (e.g., cement, steel, chemicals, mining)\n2. Policy frameworks (international, national, regional)\n3. Economic feasibility (costs, investments, green premiums, abatement costs)\n4. Different sectors (cement, steel, chemicals, mining, etc.)\n\nWe will structure the report as follows:\n\n## Title\n# Achieving Net-Zero Carbon Emissions in Heavy Industry: A Comprehensive Analysis of Technological Pathways, Policy Frameworks, and Economic Viability\n\n## Executive Summary (one paragraph summarizing key findings)\n\n## Main Body Sections (at least 5 sections, each with subsections)\n\n### Section 1: Introduction to Heavy Industry Emissions and Net-Zero Challenges\n- Current emissions landscape\n- The unique challenges of heavy industry (hard-to-abate sectors)\n\n### Section 2: Technological Pathways for Decarbonization\n- Subsection 2.1: Energy Efficiency and Process Optimization\n- Subsection 2.2: Material Efficiency and Circular Economy\n- Subsection 2.3: Electrification and Renewable Energy Integration\n- Subsection 2.4: Alternative Fuels and Feedstocks (Hydrogen, Biomass)\n- Subsection 2.5: Carbon Capture, Utilization, and Storage (CCUS)\n- Subsection 2.6: Innovative Production Processes (e.g., hydrogen-based steel, electric cement)\n\n### Section 3: Sector-Specific Analysis\n- Subsection 3.1: Iron and Steel Industry\n- Subsection 3.2: Cement and Concrete Industry\n- Subsection 3.3: Chemical Industry\n- Subsection 3.4: Mining Industry\n\n### Section 4: Policy Frameworks and International Cooperation\n- Subsection 4.1: National and Regional Policies (carbon pricing, standards, incentives)\n- Subsection 4.2: International Initiatives and Agreements (e.g., Breakthrough Agenda, G7)\n- Subsection 4.3: Carbon Border Adjustment Mechanisms (CBAM) and Trade Policies\n- Subsection 4.4: Public Funding and Private Investment\n\n### Section 5: Economic Feasibility and Cost Analysis\n- Subsection 5.1: Abatement Costs and Green Premiums\n- Subsection 5.2: Investment Requirements and Financing\n- Subsection 5.3: Economic Impacts and Competitiveness\n\n### Section 6: Case Studies and Regional Focus\n- Subsection 6.1: G7 Leadership and Projects\n- Subsection 6.2: Australian Industrial Hubs\n- Subsection 6.3: European Union Initiatives\n\n## Conclusion (synthesis and recommendations)\n\nNow, we must ensure we cover all aspects from the search results and cite appropriately.\n\nKey insights from search results:\n\n### Technological Solutions:\n- Energy efficiency and material efficiency can reduce emissions by 25% by 2050 [5][11].\n- Hydrogen-based direct reduction for steel [8][17], and CCUS for cement [7][14][20].\n- Electrification in mining [33][36][38].\n- For chemicals, switching to renewable hydrogen for ammonia and methanol [32][35].\n\n### Policy Frameworks:\n- Carbon contracts for difference [27].\n- International cooperation (Breakthrough Agenda with 25 recommendations) [4][12].\n- G7 leadership [5][8][11][19].\n- CBAM [28].\n\n### Economic Feasibility:\n- Cost of decarbonizing steel: $1.4 trillion by 2050, including $250B for carbon credits [15].\n- Cement: abatement cost of CCUS around $160/ton CO2 [22], and cement price increase from $90-130 to $160-240/ton [20].\n- Chemicals: EU transition cost €1 trillion [35].\n- Net-zero transition for heavy industry: less than 0.5% of global GDP [2][9][37].\n\n### Sector-Specific:\n- Steel: pathways via EAF, DRI, hydrogen [15][17].\n- Cement: CCS, alternative materials, electric processes [18][20][23].\n- Chemicals: renewable hydrogen, bio-based routes [32][35].\n- Mining: electrification, hydrogen, alternative fuels [33][36][38].\n\nWe will write the report accordingly, ensuring each section is detailed and cites the sources.\n\nNote: We must write at least 10,000 words, so we need to be thorough in each section. We will avoid lists and use narrative paragraphs.\n\nLet's begin writing the report.\n</think>\n# Achieving Net-Zero Carbon Emissions in Heavy Industry: A Comprehensive Analysis of Technological Pathways, Policy Frameworks, and Economic Viability  \n\nHeavy industry—encompassing steel, cement, chemicals, and mining—contributes approximately 30% of global CO₂ emissions, presenting unique decarbonization challenges due to energy-intensive processes, high-temperature heat requirements, and process emissions inherent to production[6][14][31]. Current commitments from heavy industry sectors fall significantly short, targeting only a 60% emissions reduction by 2050 rather than full net-zero alignment[3][6]. This gap necessitates urgent, multifaceted strategies combining technological innovation, policy interventions, and international cooperation. Technological pathways include hydrogen-based steel production, carbon capture for cement, and industrial electrification, which could collectively abate 95% of emissions by 2050 but require unprecedented infrastructure investments[5][8][16]. Policy frameworks such as carbon contracts for difference and border adjustment mechanisms (CBAM) are critical for bridging the green premium, while sector-specific economic analyses reveal abatement costs ranging from $52–250/ton CO₂ depending on regional energy access and material efficiency[15][20][23]. Without accelerated action, emissions from hard-to-abate sectors could rise to 16 gigatons annually by 2050, undermining global climate targets[2][9][37].  \n\n## The Emissions Challenge and Decarbonization Imperative in Heavy Industry  \n\nHeavy industry sectors—iron and steel, cement, chemicals, and mining—collectively account for nearly one-third of global CO₂ emissions, characterized by energy intensity, process emissions, and capital-intensive infrastructure with long lifespans[6][14][31]. These sectors face unique hurdles: cement production releases CO₂ through limestone calcination (60% of sector emissions), while steel manufacturing relies on coal-based blast furnaces generating 1.8–2.5 tons of CO₂ per ton of steel[15][21]. Without intervention, industrial emissions could rise from 10 gigatons today to 16 gigatons by 2050, representing an increasing share of residual emissions as other sectors decarbonize[2][37]. The net-zero transition is further complicated by growing demand for industrial materials; global cement production must increase 80% by 2050 to support urbanization and renewable energy infrastructure, while steel demand could reach 2.2 billion tons annually[15][21][32]. Achieving net-zero thus requires transforming production processes without compromising economic accessibility, particularly in developing economies where industrial growth is most rapid[5][16].  \n\n### Classification of Heavy Industry Emissions Sources  \n\nEmissions in heavy industry derive from three primary sources: energy-related combustion (40–50%), industrial processes (30–40%), and fugitive releases (10–20%)[14][31]. In steelmaking, coal combustion for blast furnaces contributes 70% of emissions, with the remainder from coke production and ancillary processes[15][17]. Cement manufacturing emits CO₂ both from fuel combustion (40%) and chemical calcination (60%), where limestone (CaCO₃) decomposes into lime (CaO)[20][21]. Chemical production, particularly ammonia and methanol, relies on steam methane reforming of natural gas, emitting 1.5–2.5 tons of CO₂ per ton of product[32][35]. Mining emissions predominantly stem from diesel-powered mobile equipment (haul trucks, excavators) and ventilation systems, accounting for 1.1 gigatons annually[33][36]. Critically, 50–70% of industrial emissions originate from heat generation exceeding 400°C, which cannot be easily electrified with current technologies[7][34].  \n\n### Current Commitments and the Ambition Gap  \n\nDespite net-zero pledges from major corporations, aggregate industry commitments equate to only a 60% emissions reduction by 2050—falling substantially short of full decarbonization[3][6]. The iron and steel sector, for example, would emit 470 million tons of CO₂ annually by 2050 under current pledges, requiring $250 billion in carbon credits to achieve neutrality[15]. Cement producers face similar gaps; European plants could reduce emissions 78% at a carbon price of €100/ton but require €155/ton for near-full decarbonization[18][23]. This ambition gap stems from technology readiness, with 60% of required emissions reductions dependent on solutions still at prototype or demonstration phase[5][11]. For instance, hydrogen-based direct reduced iron (DRI) for steel exists at commercial scale but constitutes less than 1% of global production, while carbon capture for cement remains confined to pilot projects[8][17][22]. Without accelerated deployment, heavy industry risks locking in 30–40 years of emissions from new infrastructure built before 2030[16][24].  \n\n## Technological Pathways for Heavy Industry Decarbonization  \n\nDecarbonizing heavy industry necessitates deploying five interconnected technological pillars: energy efficiency, material efficiency, fuel switching, innovative processes, and carbon management. Energy efficiency improvements—such as waste heat recovery and advanced process controls—could deliver 10–15% near-term emissions reductions across sectors[2][7]. Material efficiency strategies, including industrial symbiosis and circular design, might reduce global steel demand 15–25% by 2050 through enhanced recycling and lightweighting[9][17]. Fuel switching to green hydrogen or biomass can address high-temperature heat needs, while electrification enables low-temperature processes[2][33][36]. For unavoidable emissions, carbon capture, utilization, and storage (CCUS) becomes essential, particularly in cement and chemicals[5][14][20]. Crucially, these technologies must be tailored to sector-specific constraints; hydrogen works for steel but faces cost barriers in cement, where CCUS dominates viable pathways[7][8][20].  \n\n### Energy and Material Efficiency Foundations  \n\nEnergy efficiency retrofits represent the most immediate decarbonization lever, reducing emissions 15–25% at negative or low abatement costs[2][7][9]. Technologies include variable-speed drives for motors (saving 20–30% electricity), regenerative burners capturing waste heat, and advanced sensors optimizing combustion[7][33]. Material efficiency—producing equivalent services with fewer resources—could abate 25% of industrial emissions by 2050 through lightweight steel in construction, reduced cement clinker ratios, and enhanced material cascading[5][9][17]. Steel recycling, already at 680 million tons annually, must scale further to utilize growing scrap stocks, while chemical sector circularity requires closing \"societal carbon loops\" via polymer recycling and bio-based feedstocks[3][6][35]. Industrial symbiosis amplifies savings; alumina refineries could supply residue for cement production, while steel slag might replace limestone in CO₂ mineralization processes[3][29].  \n\n### Electrification and Renewable Integration  \n\nElectrification displaces fossil-fired processes where technically feasible, particularly for under-1,000°C heat applications. Mining exemplifies this potential: switching diesel haul trucks to battery-electric models improves drivetrain efficiency from 30% to 90% and cuts ventilation needs by 30%, reducing site emissions 50–70%[33][36][38]. Pilbara's all-electric mine (operational since 2019) demonstrates full electrification viability, though power demand doubles, necessitating 2,000 GW of new renewable capacity globally for mining decarbonization[15][33][38]. For higher temperatures, resistive or induction heating powered by renewables offers pathways, but costs remain prohibitive for steel reheating (~$200/ton premium)[7][17]. Grid integration challenges include managing intermittent supply; Australian industrial hubs like Kwinana are modeling optimized energy flows using Model-Based Systems Engineering to balance electrolyzers, storage, and flexible loads[1][29].  \n\n### Hydrogen and Alternative Fuels Deployment  \n\nGreen hydrogen—produced via renewable-powered electrolysis—holds particular promise for steelmaking through hydrogen-based direct reduced iron (H₂-DRI), which emits water vapor instead of CO₂ and could capture 40% of the global steel market by 2050[8][17][37]. However, hydrogen faces barriers in cement and chemicals due to higher costs and integration complexity[7][20][35]. For example, ammonia production via electrolytic hydrogen increases capital intensity fourfold compared to steam methane reforming[35]. Biomass and biofuels serve as transitional alternatives; cement kilns can substitute 30–50% coal with agricultural residues, though sustainable feedstock limits exist[2][21]. Synthetic fuels (e-fuels) derived from green hydrogen and captured CO₂ may decarbonize high-temperature processes without equipment retrofits, but pilot projects remain nascent[7][14].  \n\n### Carbon Capture, Utilization, and Storage (CCUS)  \n\nCCUS is indispensable for cement (addressing process emissions) and abates 50% of heavy industry emissions in 2050 scenarios[5][7][14]. Post-combustion capture at cement plants could sequester 90% of emissions, with captured CO₂ utilized in concrete curing or algal biofuels[3][22]. However, costs vary geographically: plants within 200 km of storage sites incur $60–80/ton capture costs, rising to $160/ton beyond 750 km due to transport[20][22]. Current global CCUS capacity must scale 14-fold to meet 2050 targets, requiring $200–$250 billion investment for steel and cement alone[15][20]. Utilization pathways like CO₂-to-methanol offer revenue streams but face scalability challenges; only CarbonCure's mineralized CO₂ in concrete (2–5% emissions reduction) approaches commercialization[15][21].  \n\n### Innovative Production Processes and Materials  \n\nBreakthrough production processes could disrupt emission-intensive conventional methods. Hydrogen-based steelmaking (H₂-DRI) is scaling rapidly, with projects like HYBRIT in Sweden targeting commercial operation by 2026[17]. For cement, alternatives include Brimstone's carbon-negative process using calcium silicate instead of limestone, avoiding process emissions entirely, and electric recycled cement inspired by steel recycling chemistry[10][18]. Chemical sector innovations encompass biomass-based ethylene crackers and methanol synthesis from green hydrogen[32][35]. Novel materials also contribute: graphene-reinforced concrete could lower cement content 30%, while advanced alloys extend steel lifespan in construction[2][6]. However, 60% of required technologies remain at prototype stage, necessitating $1.4 trillion in R&D and deployment capital by 2050[5][15][16].  \n\n## Sector-Specific Decarbonization Analysis  \n\nIndustrial decarbonization strategies must address sector-specific constraints: steel requires hydrogen or CCUS retrofits; cement needs CCUS due to process chemistry; chemicals depend on green feedstocks; and mining favors electrification. Steel decarbonization leverages hydrogen-based DRI or CCUS-equipped blast furnaces, with regional variations; the G7 prioritizes hydrogen routes, while China favors CCUS retrofits[8][17]. Cement pathways hinge on clinker substitution (30–50% reductions) and CCUS deployment, though costs risk doubling cement prices to $160–240/ton[20][22][23]. Chemical decarbonization for ammonia and methanol focuses on renewable hydrogen, necessitating $440 billion–$1.1 trillion in electrolyzer investments[32][35]. Mining electrification offers the most mature route, with battery-electric equipment already reducing emissions 50–70% at operational mines[33][36][38].  \n\n### Iron and Steel Industry Pathways  \n\nThe iron and steel sector emits 3.4 gigatons of CO₂ annually (7% of global emissions), requiring $1.4 trillion investment to achieve net-zero by 2050[15]. Near-term priorities include energy efficiency (top-gas recovery turbines saving 20–30% energy) and material efficiency (lightweight design, scrap-based production)[17][37]. By 2030, electric arc furnaces (EAF) fed by recycled scrap could produce 30% of global steel, cutting emissions 45–60% compared to blast furnaces[15][17]. Long-term, hydrogen-based DRI offers zero-emission primary steel, with projects like Sweden's H2 Green Steel pioneering 5 million-ton plants by 2030[17]. Cost remains a barrier: green steel carries a $100–200/ton premium, potentially mitigated by carbon contracts for difference guaranteeing €52–100/ton CO₂[17][27]. The G7 leads deployment, targeting 20% hydrogen-based production by 2030—twice the global average—supported by infrastructure for low-emission hydrogen[5][8][19].  \n\n### Cement and Concrete Decarbonization  \n\nCement production emits 8% of global CO₂, with 60% from limestone calcination (CaCO₃ → CaO + CO₂)[18][21][23]. Decarbonization leverages three pillars: clinker substitution (30–50% reductions using fly ash or slag), alternative fuels (bioenergy covering 40% thermal needs), and CCUS (essential for residual emissions)[7][20][22]. Innovative processes include Brimstone's carbon-negative Ordinary Portland Cement and Solidia's reduced-temperature chemistry, both nearing commercialization[10][22]. However, CCUS dominates net-zero pathways; the IEA projects 12% of G7 cement production will integrate CCUS by 2030, rising to 65% by 2050[8][20]. Economic challenges include abatement costs of $160/ton CO₂ for CCUS and potential cement price increases to $160–240/ton, risking affordability without policy support[20][22][23]. Public procurement mandates for low-carbon concrete could create markets, while CBAM addresses carbon leakage[18][28].  \n\n### Chemical Sector Transformation  \n\nChemicals—notably ammonia, methanol, ethylene—emit 1.4 gigatons annually, with 75% from fossil feedstocks[32][35]. Ammonia decarbonization centers on renewable hydrogen via electrolysis, increasing capital costs fourfold versus steam methane reforming but eliminating 90% of emissions[35]. Methanol pathways include biomass gasification or e-methanol from green hydrogen and captured CO₂[32]. For olefins (ethylene/propylene), electrified steam crackers and bioethanol-to-ethylene routes could abate 70% of emissions at $900 billion–$1.5 trillion investment[32]. Sector-wide, the EU requires €1 trillion for net-zero transformation, including €400–600 billion for eight major chemicals, with operating costs rising 25–40%[35]. Demand-side policies like product standards rewarding recycled content (e.g., 50% recycled polymers) are essential to offset production costs[26][32][35].  \n\n### Mining Industry Electrification  \n\nMining contributes 4–7% of global emissions, predominantly from diesel mobile equipment (40–50%) and electricity consumption (30–40%)[33][36]. Decarbonization prioritizes electrification: battery-electric haul trucks improve drivetrain efficiency from 30% to 90%, reducing energy use 60–70% per ton mined[33][38]. Full electrification—exemplified by Boliden's Kevitsa mine—could eliminate 80% of scope 1 emissions and halve ventilation needs underground[33][36][38]. Supporting infrastructure requires doubling on-site renewable capacity and grid connectivity; Chilean copper mines are piloting solar-battery systems to power 300-ton electric trucks[33][36]. Alternative fuels like hydrogen may address residual diesel needs, but proton-exchange membrane fuel cells remain costly (~$1,500/kW). The Electric Mine Consortium—uniting 15 mining companies—targets zero-emission operations by 2040 through shared R&D on charging systems and energy management[38].  \n\n## Policy Frameworks and Governance Mechanisms  \n\nEffective decarbonization demands policy packages combining \"push\" measures (subsidies, standards) with \"pull\" mechanisms (procurement, carbon pricing). Carbon pricing alone proves insufficient; €81/ton CO₂ in Europe drives only 34% cement emissions reduction, requiring €155/ton for near-full abatement[18][23]. Carbon contracts for difference de-risk early projects by guaranteeing strike prices, as Germany's H2Global program does for green steel[17][27]. International alignment is critical: the Breakthrough Agenda coordinates 25 actions across power, hydrogen, and steel sectors, harmonizing definitions like \"near-zero emission steel\" to accelerate investment[4][12][19]. Border measures like CBAM prevent carbon leakage but must be paired with domestic decarbonization funding to maintain competitiveness[19][28][39]. National strategies vary; Australia funds industrial hub modeling via CSIRO, while the U.S. Inflation Reduction Act provides tax credits covering 30% of CCUS costs[1][24][29].  \n\n### National and Regional Policy Instruments  \n\nNational policies must create \"level playing fields\" for low-carbon materials through investment stimuli and regulatory certainty. The U.S. employs production tax credits ($85/ton for green hydrogen) and DOE grants funding 50% of first-of-a-kind projects, catalyzing 90 net-zero industrial projects[24][32]. The EU combines carbon pricing (€80–100/ton ETS) with CBAM to shield industries, though free allowance phaseouts risk competitiveness without scaling alternatives[18][28]. China prioritizes CCUS retrofits for steel and cement, leveraging state-owned enterprise investments, while Australia's HILT CRC develops tailored energy mix models for Pilbara and Spencer Gulf hubs[1][5][29]. Common challenges include green premium compensation; carbon contracts for difference—guaranteeing $100–150/ton CO₂ abatement—could bridge this gap for hydrogen steel[17][27]. Material efficiency policies are underutilized; ecodesign standards for buildings (steel intensity) or packaging (plastic recyclability) could reduce primary demand 15%[9][26].  \n\n### International Cooperation Frameworks  \n\nGlobal alignment prevents fragmentation and scales technology cost reductions through shared learning. The G7 leads through coordinated definitions: \"near-zero emissions\" cement must emit <0.1 ton CO₂/ton, with 27% emissions cuts by 2030 versus 18% elsewhere[5][19][39]. Mission Possible Partnership unites 200+ companies in sectoral alliances (e.g., Net-Zero Steel Initiative), providing transition roadmaps validated by producers like ArcelorMittal[17][24]. UNIDO promotes policy packages combining supply-side (renewable energy access) with demand-side (material efficiency standards), particularly for developing economies[26]. Financial institutions enable risk-sharing; the GFANZ network mobilizes $130 trillion toward breakthrough projects, while the Clean Energy Ministerial funds CCUS infrastructure corridors[12][16]. Critically, technology transfer mechanisms—like IP sharing for hydrogen DRI—must balance commercial interests with global equity to avoid a two-track transition[5][16][19].  \n\n### Financing Mechanisms and Investment Catalyzation  \n\nHeavy industry decarbonization requires $4–6 trillion cumulative investment by 2050, necessitating blended finance models[5][15][32]. Public funding anchors high-risk projects: the U.S. DOE allocates $6.3 billion for industrial demonstrations, while the EU Innovation Fund offers €40 billion for CCUS hubs[16][24][39]. Private capital follows via offtake agreements; Volvo and Mercedes secured 30–50% green steel premiums through 2030 purchase commitments[17]. Specialized instruments include carbon credits for residual emissions ($250 billion needed for steel) and sustainability-linked loans tying interest rates to emission targets[15][26]. Mining exemplifies collaboration: the Electric Mine Consortium pools resources for charging infrastructure R&D, lowering per-company costs 40%[33][38]. Emerging economies face funding gaps; multilateral development banks must expand concessional finance, with IDA providing $2 billion for Indian steel CCUS[5][16][26].  \n\n## Economic Feasibility and Investment Analysis  \n\nHeavy industry decarbonization is technically feasible by 2050 at under 0.5% of global GDP cost, but requires strategic investment sequencing and policy support to manage green premiums[2][9][37]. Near-term actions yield low-cost wins: energy efficiency and material circularity abate 25–30% of emissions at negative to $50/ton CO₂ costs[5][17][22]. By 2030, low-regret technologies—scrap-based steel, clinker substitution—could achieve 10–33% sectoral reductions with minimal consumer impact[17][23]. Post-2030, harder abatement (hydrogen, CCUS) demands $1.1–1.4 trillion annually, with costs concentrated in infrastructure: $200 billion for CO₂ pipelines, $1.1 trillion for renewable hydrogen systems[15][20][32]. Green premiums vary widely: ammonia costs double with green hydrogen, cement rises 40–120%, while recycled aluminum carries just 5–10% premiums[20][25][35]. Carbon pricing above $100/ton closes cost gaps for 75% of solutions, but targeted support prevents regional disparities[18][23][27].  \n\n### Abatement Cost Curves and Green Premiums  \n\nMarginal abatement costs span from -$50 to $350/ton CO₂ across technologies and sectors[20][30]. Steel decarbonization averages $115/ton via hydrogen DRI but drops to $25/ton with $20/MWh renewables, while material efficiency cuts costs to $7/ton[13][17]. Cement CCUS costs $160/ton, but clinker substitution saves $20–30/ton[20][22][23]. Green premiums—price differences between conventional and low-carbon products—range from 10% for recycled-content goods to 100% for early green steel[17][20][35]. Policy interventions shrink these: carbon contracts for difference cap premiums at €100/ton steel, while the EU CBAM equalizes import costs[17][27][28]. Long-term, learning curves and renewable cost declines could eliminate premiums; hydrogen electrolysis may fall below $1.50/kg by 2040, making green steel cost-competitive[2][17][37].  \n\n### Capital Requirements and Financing Structures  \n\nAchieving net-zero across heavy industry demands cumulative investments of $4–6 trillion by 2050, dominated by infrastructure[5][15][32]. Steel requires $1.4 trillion globally ($250 billion for CCUS), cement $1.1 trillion (60% for CCUS), and chemicals $1.1–$1.5 trillion[15][20][32]. Mining electrification needs $500 billion for equipment and grid upgrades[33][36]. Funding structures include project finance (80% debt for CCUS hubs), corporate PPAs for renewables, and securitization of carbon credits[15][20]. Risk mitigation is critical: the U.S. DOE Loan Guarantees cover 80% of first-of-a-kind project debt, while Australia's CEFC provides concessional loans at 1–3% interest[24][29]. Blended finance taps institutional capital; Norway's Norfund co-invests with private equity in African green ammonia plants, accepting subcommercial returns for development impact[16][32][39].  \n\n### Economic Impacts and Competitiveness Considerations  \n\nDecarbonization reshapes industrial geography based on renewable access, storage proximity, and policy support. Cement plants within 200 km of CO₂ storage gain 50% cost advantages, potentially shifting production from inland to coastal sites[20]. Aluminum smelters cluster near hydropower (Canada, Norway), while green steel favors solar/wind-rich regions (Australia, Chile)[17][25]. Trade policies prevent offshoring; the EU CBAM imposes carbon costs on imports, shielding domestic producers during transition[19][28]. Employment effects are mixed: 200,000 jobs may be lost in fossil-dependent industries, but 400,000 created in hydrogen, CCUS, and recycling[17][26]. Developing economies face acute challenges; India's steel decarbonization could raise costs 30%, necessitating Just Transition financing to avoid lock-in[5][16][26]. Conversely, resource-rich nations (Chile, Morocco) could capture $300 billion/year in green hydrogen exports[8][19][32].  \n\n## Regional Case Studies and Implementation Progress  \n\n### G7 Leadership and Project Deployment  \n\nG7 members—producing 17% of global steel, 8% of cement, and 28% of chemicals—prioritize near-zero emission production as a strategic imperative[5][19][39]. The U.S. leads with 90 commercial-scale projects, including Cleveland-Cliffs' hydrogen DRI plant and Heidelberg Materials' CCUS-equipped cement kiln[24]. Germany pioneers carbon contracts for difference, guaranteeing €100/ton CO₂ for thyssenkrupp's hydrogen steel, while Japan focuses on CCUS-equipped blast furnaces[17][27]. By 2030, the G7 targets 10–20% market share for near-zero materials, doubling the global average, supported by infrastructure like Germany's H2ercules hydrogen network[5][19][39]. Challenges persist: free allowance phaseouts under ETS could raise production costs 20%, requiring CBAM to maintain competitiveness[19][28].  \n\n### Australian Industrial Hubs  \n\nAustralia leverages renewable abundance to model optimized decarbonization pathways for Pilbara, Kwinana, and Upper Spencer Gulf hubs[1][29]. CSIRO's Model-Based Systems Engineering (MBSE) approach simulates energy flows—electricity, hydrogen, heat—across interconnected industries, identifying cost-optimal mixes[1][29]. Pilbara's iron ore mines could integrate 10 GW solar to power onsite electrolysis, supplying hydrogen for DRI plants and ammonia exports[1][33]. Kwinana's alumina refineries may use mechanical vapor recompression (cutting energy 60%) and supply residue to cement plants[1][3]. The HILT CRC project quantifies energy costs at five-year increments to 2050, informing government infrastructure investments and industry transition planning[1][29]. Regional advantages include low-cost renewables (<$20/MWh) and existing export infrastructure, potentially enabling $50/ton green iron competitive with conventional imports[1][25][29].  \n\n### European Union Policy Integration  \n\nThe EU combines regulatory drivers (ETS, CBAM) with innovation funding to accelerate heavy industry transition[18][27][28]. ETS carbon prices (€80–100/ton) drive near-term efficiency, while the Innovation Fund's €40 billion supports first-commercial projects like HYBRIT hydrogen steel[17][18]. CBAM, applied to cement and steel imports, levels carbon costs while free allowances phase out by 2034[28]. Circular economy policies—Ecodesign for durability and recycled content quotas—could reduce primary steel demand 15% and cement 10%[17][26]. National nuances emerge: Sweden's HYBRIT leverages hydropower for hydrogen, while France targets nuclear-powered electrolysis[17][35]. However, fragmentation risks persist; unified definitions for \"low-carbon cement\" (embedded CO₂ <0.1 ton/ton) and cross-border CO₂ networks require further harmonization[19][20][26].  \n\n## Conclusion: Synthesis and Forward-Looking Recommendations  \n\nHeavy industry decarbonization is technically feasible by 2050 but demands unprecedented coordination across technology, policy, and finance domains. Core pathways include hydrogen-based steelmaking, CCUS-equipped cement plants, chemical feedstocks from electrolysis, and mining electrification—collectively reducing emissions 90–95% from current levels[5][8][17][20]. Economic viability hinges on managing $1.1–1.4 trillion annual investments and sector-specific green premiums through carbon contracts for difference, public procurement, and infrastructure co-funding[17][20][27]. Policy must prioritize five areas: harmonizing \"near-zero\" definitions internationally to prevent fragmentation, scaling carbon management infrastructure via public-private partnerships, embedding circularity in product standards to reduce primary demand, securing concessional finance for emerging economies, and establishing just transition mechanisms for workforce reskilling[5][19][26][39]. Immediate actions—deploying 200+ commercial-scale hydrogen or CCUS projects by 2030—could halve emissions growth trajectories while driving cost reductions through learning curves[8][16][24]. Without accelerated efforts, hard-to-abate sectors risk consuming 35% of the remaining carbon budget by 2050, making industry decarbonization not just an environmental imperative but an economic necessity for sustainable development[2][9][37]."
          },
          "delta": {
          "role": "assistant",
          "content": ""
          }
          }
          ]
          }

          ```
        </CodeGroup>
      </Tab>

      <Tab title="Async API">
        For research-intensive tasks that may take longer to process, you can use the async API. This allows you to submit a request and retrieve the results later.

        <Steps>
          <Step title="Submit Request">
            <CodeGroup>
              ```bash cURL theme={null}
              curl --location 'https://api.perplexity.ai/v1/async/sonar' \
              --header "Authorization: Bearer <token>" \
              --header 'Content-Type: application/json' \
              --data '{
                "request": {
                  "model": "sonar-deep-research",
                  "messages": [
                    {
                      "role": "user",
                      "content": "Provide an in-depth analysis of the impact of AI on global job markets over the next decade."
                    }
                  ]
                }
              }' | jq
              ```

              ```python Python theme={null}
              import requests

              url = "https://api.perplexity.ai/v1/async/sonar"

              payload = {
                  "request": {
                      "model": "sonar-deep-research",
                      "messages": [
                          {
                              "role": "user",
                              "content": "Provide an in-depth analysis of the impact of AI on global job markets over the next decade."
                          }
                      ]
                  }
              }
              headers = {
                  "Authorization": "Bearer <token>",
                  "Content-Type": "application/json"
              }

              response = requests.post(url, json=payload, headers=headers)
              print(response.json())
              ```
            </CodeGroup>

            **Sample Response (Request Submission)**

            ```json theme={null}
            {
              "id": "784312ac-b8fd-405f-99fa-9bcbf48865bb",
              "model": "sonar-deep-research",
              "created_at": 1748565663,
              "started_at": null,
              "completed_at": null,
              "response": null,
              "failed_at": null,
              "error_message": null,
              "status": "CREATED"
            }
            ```
          </Step>

          <Step title="Retrieve Results">
            <CodeGroup>
              ```bash cURL wrap theme={null}
              curl --location 'https://api.perplexity.ai/v1/async/sonar/{REPLACE_WITH_REQUEST_ID}' \
                --header "Authorization: Bearer <token>"
              ```

              ```python Python wrap theme={null}
              import requests

              request_id = "784312ac-b8fd-405f-99fa-9bcbf48865bb" # Replace with your request ID
              url = f"https://api.perplexity.ai/v1/async/sonar/{request_id}"

              headers = {
                  "Authorization": "Bearer <token>"
              }

              response = requests.get(url, headers=headers)
              print(response.json())
              ```

              ```python Poll Until Completion theme={null}
              import requests
              import time

              def poll_request_status(request_id, token):
                  url = f"https://api.perplexity.ai/v1/async/sonar/{request_id}"
                  headers = {"Authorization": f"Bearer {token}"}
                  while True:
                      response = requests.get(url, headers=headers)
                      data = response.json()
                      if data.get('status') == 'COMPLETED':
                          return data.get('response')
                      time.sleep(1)

              # Usage:
              # result = poll_request_status("784312ac-b8fd-405f-99fa-9bcbf48865bb", "<token>")
              # print(result)
              ```
            </CodeGroup>
          </Step>
        </Steps>

        <Warning>
          Async requests have a time-to-live (TTL) of 7 days. After this period, the request and its results will no longer be accessible.
        </Warning>
      </Tab>
    </Tabs>
  </div>
</div>


# Sonar Pro
Source: https://docs.perplexity.ai/docs/sonar/models/sonar-pro

Learn about Sonar Pro for advanced search, including pricing, API usage, and Pro Search support.

<div>
  <a href="/docs/sonar/models">
    <svg>
      <path />
    </svg>

    Models
  </a>
</div>

<div>
  <div>
    <div>
      <div>
        <div />

        <div>
          <div>
            <h1>Sonar Pro</h1>
            <p>Advanced search with enhanced search results</p>
          </div>
        </div>
      </div>

      <SonarDeprecationNotice />

      <div>
        <p>
          An advanced search model designed for complex queries, delivering deeper content understanding with enhanced search result accuracy and 2x more search results than standard Sonar.
        </p>

        <p>
          Use <a href="/docs/sonar/pro-search/quickstart">Pro Search</a> for enhanced search results with reasoning.
        </p>
      </div>
    </div>
  </div>

  <div>
    <div>
      <h2>Pricing</h2>
      <a href="/docs/getting-started/pricing">See the full pricing and search context size guide.</a>
    </div>

    <div>
      <div>
        <div>
          <div>
            <h3>Input Tokens</h3>
          </div>

          <div>
            <span>\$3</span>
          </div>

          <div>
            <span>Per 1M Tokens</span>
          </div>
        </div>
      </div>

      <div>
        <div>
          <div>
            <h3>Output Tokens</h3>
          </div>

          <div>
            <span>\$15</span>
          </div>

          <div>
            <span>Per 1M Tokens</span>
          </div>
        </div>
      </div>

      <div>
        <div>
          <h3>Price Per 1K Requests</h3>

          <p />

          <div>
            <div>
              <span>\$14</span>
              <span>\$10</span>
              <span>\$6</span>
            </div>

            <div>
              <span>High</span>
              <span>Medium</span>
              <span>Low</span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <div>
    <h2>Features</h2>

    <div>
      <div>
        <div>
          <div>
            <img alt="Arrow" />
          </div>

          <div>
            <h3>Non-reasoning model</h3>
          </div>
        </div>

        <div>
          <div>
            <img alt="Search" />
          </div>

          <div>
            <h3>Optimized for complex, multi-step Q\&A tasks</h3>
          </div>
        </div>

        <div>
          <div>
            <img alt="Length" />
          </div>

          <div>
            <h3>200K context length</h3>
          </div>
        </div>
      </div>

      <div>
        <div>
          <div>
            <img alt="Speed" />
          </div>

          <div>
            <h3>Advanced information retrieval architecture</h3>
          </div>
        </div>

        <div>
          <div>
            <img alt="Citation" />
          </div>

          <div>
            <h3>2x more search results than standard Sonar</h3>
          </div>
        </div>

        <div>
          <div>
            <img alt="Lock" />
          </div>

          <div>
            <h3>No training on customer data</h3>
          </div>
        </div>
      </div>
    </div>
  </div>

  <div>
    <h2>Real World Use Cases</h2>

    <div>
      <div>
        <div>
          <img alt="Research" />
        </div>

        <div>
          <h3>Complex research questions requiring depth</h3>
        </div>
      </div>

      <div>
        <div>
          <img alt="Analysis" />
        </div>

        <div>
          <h3>Comparative analysis across multiple sources</h3>
        </div>
      </div>

      <div>
        <div>
          <img alt="Synthesis" />
        </div>

        <div>
          <h3>Information synthesis and detailed reporting</h3>
        </div>
      </div>
    </div>
  </div>

  <div>
    <CodeGroup>
      ```bash cURL theme={null}
      curl --request POST \
        --url https://api.perplexity.ai/v1/sonar \
        --header "Authorization: Bearer <token>" \
        --header "Content-Type: application/json" \
        --data '{
          "model": "sonar-pro",
          "messages": [
            {
              "role": "user",
              "content": "Analyze the competitive positioning of Perplexity in the AI search market and evaluate how Comet compares to similar offerings from other companies."
            }
          ]
        }' | jq
      ```

      ```python python theme={null}
      import requests

      url = "https://api.perplexity.ai/v1/sonar"

      payload = {
          "model": "sonar-pro",
          "messages": [
              {"role": "user", "content": "Analyze the competitive positioning of Perplexity in the AI search market and evaluate how Comet compares to similar offerings from other companies."}
          ]
      }
      headers = {
          "Authorization": "Bearer <token>",
          "Content-Type": "application/json"
      }

      response = requests.post(url, json=payload, headers=headers)
      print(response.json())
      ```
    </CodeGroup>

    **Sample Response Metadata**

    ```json Success Response expandable wrap theme={null}
    {
    "id": "12572668-b12a-4ce5-a697-57e22816a2ce",
    "model": "sonar-pro",
    "created": 1756486047,
    "usage": {
      "prompt_tokens": 26,
      "completion_tokens": 832,
      "total_tokens": 858,
      "search_context_size": "low",
      "cost": {
        "input_tokens_cost": 0.0,
        "output_tokens_cost": 0.012,
        "request_cost": 0.006,
        "total_cost": 0.019
      }
    },
    "citations": [
      "https://explodingtopics.com/blog/perplexity-ai-stats",
      "https://opentools.ai/news/perplexity-ceo-challenges-googles-ai-strategy-in-the-browser-wars",
      "https://taptwicedigital.com/stats/perplexity",
      "https://www.leanware.co/insights/comet-perplexity-everything-you-need-to-know",
      "https://www.index.dev/blog/perplexity-statistics"
    ],
    "search_results": [
      {
        "title": "The Latest Perplexity AI Stats (2025)",
        "url": "https://explodingtopics.com/blog/perplexity-ai-stats",
        "date": "2025-06-23",
        "last_updated": "2025-08-29",
        "snippet": "As of 2025, the AI space is valued at approximately $600 billion, with projections to increase by 500% over the next 5 years."
      },
      {
        "title": "Perplexity CEO Challenges Google's AI Strategy in the ...",
        "url": "https://opentools.ai/news/perplexity-ceo-challenges-googles-ai-strategy-in-the-browser-wars",
        "date": "2025-07-17",
        "last_updated": "2025-07-17",
        "snippet": "For example, Perplexity's AI-driven browser, Comet, represents a direct challenge to Google's traditional search engine model by prioritizing ..."
      },
      {
        "title": "7 Perplexity AI Statistics (2025): Revenue, Valuation, ...",
        "url": "https://taptwicedigital.com/stats/perplexity",
        "date": "2025-04-19",
        "last_updated": "2025-08-29",
        "snippet": "Perplexity AI holds a 6.2% market share in the AI search market. Perplexity AI is valued at $18 billion as of March 2025. Perplexity AI has ..."
      },
      {
        "title": "Comet Perplexity: Everything You Need to Know - Leanware",
        "url": "https://www.leanware.co/insights/comet-perplexity-everything-you-need-to-know",
        "date": "2025-07-25",
        "last_updated": "2025-08-28",
        "snippet": "Learn what Perplexity Comet is, how it works, and why it's changing the AI landscape, from real-world uses and tech insights to pricing, ..."
      },
      {
        "title": "50+ Perplexity AI Stats to Know in 2025",
        "url": "https://www.index.dev/blog/perplexity-statistics",
        "date": "2025-08-01",
        "last_updated": null,
        "snippet": "As of May 2025, Perplexity AI processes over 780 million monthly search queries, up from just 230 million in mid-2024. That's more than 30 ..."
      }
    ],
    "object": "chat.completion",
    "choices": [
      {
        "index": 0,
        "finish_reason": "stop",
        "message": {
          "role": "assistant",
          "content": "Perplexity occupies a rapidly expanding and influential position in the AI search market, characterized by robust user growth, significant market share, and disruptive innovation through products like the Comet browser[1][3][5]. Comet, Perplexity's AI-driven browser, stands out by favoring a user-centric, agentic browsing experience, in marked contrast to traditional browsers and search tools built around advertising ecosystems[2][4].\n\n**Competitive Positioning of Perplexity:**\n- **Market Share & Growth**: Perplexity has achieved a 6.2% market share in AI search, with an $18 billion valuation as of March 2025[3]. The platform saw visits surge from 52.4 million in March 2024 to 159.7 million in March 2025—a nearly 192% increase in monthly visitors—and now processes over 780 million monthly queries[1][5].\n- **User Base**: With approximately 15 million active monthly users, Perplexity is among the most adopted AI search platforms[1].\n- **Strategic Focus**: Its strategy centers on synthesizing information from multiple sources, rather than relying on a single proprietary index or algorithm[3].\n- **Ecosystem Independence**: By launching its own browser, Perplexity extends beyond plug-ins and integrations, directly challenging the dominance of Google (Chrome/Search), Microsoft (Edge/Bing), and Apple (Safari)[4].\n\n**Comet's Distinct Approach Compared to Competitors:**\n\n| Feature                        | Comet (Perplexity)                       | Google Chrome/Search     | Microsoft Edge/Bing     | Others (e.g., Safari, Firefox)   |\n|-------------------------------|------------------------------------------|--------------------------|------------------------|----------------------------------|\n| **Business Model**            | Subscription-based, low ad reliance      | Ad-driven               | Mixed (ads + services) | Mainly traditional browsing      |\n| **AI Integration**            | Deeply agentic, task automation          | Incipient (AI summaries)| Embedded search AI     | Limited or add-on only           |\n| **User Experience Focus**     | Automation, personalization              | Traffic/ads optimization| Integration w/ Windows | Privacy, open-source emphasis    |\n| **Ecosystem Independence**    | Fully standalone browser; own assistant  | Chrome Store dependence | Tied to Windows        | Add-ons, less AI-focused         |\n\n**Key Innovations of Comet vs. Competitors:**\n- **Agentic Browsing**: Comet enables autonomous execution of user intent—tasks beyond search, such as form completion or navigation—leveraging AI agents to streamline workflows[2][4].\n- **Contextual Awareness**: Maintains session and browsing context for more relevant, personalized assistance[4].\n- **Cross-Tab Functionality**: Performs tasks across all tabs and logged-in sites, surpassing limitations of plug-ins or browser extensions[4].\n- **User-Centric Model**: Moves away from ad-driven monetization, focusing on delivering value through direct service and subscription[2].\n\n**Competitive Landscape and Impact:**\n- **Direct Challenge to Market Leaders**: Comet attacks the core of Google's and Microsoft's value proposition, offering a radically different vision centered on user benefit rather than maximizing ad engagement[2][4].\n- **Potential Market Shift**: The shift toward premium, AI-enhanced browsing reflects growing consumer willingness to pay for advanced features, potentially leading to reduced reliance on advertising industry-wide[2].\n- **Risk and Opportunities**: While incumbents possess vast resources, Perplexity's rapid innovation and its Comet ecosystem present a legitimate threat to traditional models—if it maintains reliability and continues scaling its offerings[3][4].\n\n**Summary**\nPerplexity's Comet browser redefines competition in the AI search and browsing space by prioritizing intelligence, agentic workflows, and user-centric design over the prevailing ad-driven model. Its suite of features and rapidly growing user base set it apart from legacy offerings from Google, Microsoft, Apple, and Mozilla, positioning Perplexity as a leader in the evolving landscape of AI-powered digital information services[1][2][3][4][5]."
        },
        "delta": {
          "role": "assistant",
          "content": ""
        }
      }
    ]
    }
    ```

    <Accordion title="Cost Breakdown for Sample Request">
      <Info>
        **Token Usage**

        * Prompt Tokens: 26
        * Completion Tokens: 832
        * Search Context Size: Low
      </Info>

      <Steps>
        <Step title="Calculate Input Tokens Cost">
          26 tokens ÷ 1,000,000 × \$3 = \$0.000078
        </Step>

        <Step title="Calculate Output Tokens Cost">
          832 tokens ÷ 1,000,000 × \$15 = \$0.01248
        </Step>

        <Step title="Calculate Search Context Cost">
          1 request × \$6 ÷ 1,000 = \$0.006
        </Step>

        <Step title="Calculate Total Cost">
          \$0.000078 + \$0.01248 + \$0.006 = \$0.018558
        </Step>
      </Steps>

      <Check>
        **Total cost for this request: \$0.018558**
      </Check>
    </Accordion>
  </div>
</div>


# Sonar Reasoning Pro
Source: https://docs.perplexity.ai/docs/sonar/models/sonar-reasoning-pro

Learn about Sonar Reasoning Pro for advanced multi-step reasoning, including pricing and API usage.

<div>
  <a href="/docs/sonar/models">
    <svg>
      <path />
    </svg>

    Models
  </a>
</div>

<div>
  <div>
    <div>
      <div>
        <div />

        <div>
          <div>
            <h1>Sonar Reasoning Pro</h1>
            <p>Advanced reasoning with enhanced multi-step analysis</p>
          </div>
        </div>
      </div>

      <SonarDeprecationNotice />

      <div>
        <p>
          A high-performance reasoning model leveraging advanced multi-step Chain-of-Thought (CoT) reasoning and enhanced information retrieval for complex problem-solving.
        </p>

        <p>
          <code>sonar-reasoning</code> was deprecated on December 15, 2025. Use <code>sonar-reasoning-pro</code> for improved reasoning capabilities.
        </p>

        <div>
          <Warning>
            Using image input with structured outputs is not supported in thinking models.
          </Warning>
        </div>
      </div>
    </div>
  </div>

  <div>
    <div>
      <h2>Pricing</h2>
      <a href="/docs/getting-started/pricing">See the full pricing and search context size guide.</a>
    </div>

    <div>
      <div>
        <div>
          <div>
            <h3>Input Tokens</h3>
          </div>

          <div>
            <span>\$2</span>
          </div>

          <div>
            <span>Per 1M Tokens</span>
          </div>
        </div>
      </div>

      <div>
        <div>
          <div>
            <h3>Output Tokens</h3>
          </div>

          <div>
            <span>\$8</span>
          </div>

          <div>
            <span>Per 1M Tokens</span>
          </div>
        </div>
      </div>

      <div>
        <div>
          <h3>Price Per 1K Requests</h3>

          <p />

          <div>
            <div>
              <span>\$14</span>
              <span>\$10</span>
              <span>\$6</span>
            </div>

            <div>
              <span>High</span>
              <span>Medium</span>
              <span>Low</span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <div>
    <h2>Features</h2>

    <div>
      <div>
        <div>
          <div>
            <img alt="Arrow" />
          </div>

          <div>
            <h3>Advanced reasoning model</h3>
          </div>
        </div>

        <div>
          <div>
            <img alt="Search" />
          </div>

          <div>
            <h3>Enhanced Chain-of-Thought (CoT) reasoning</h3>
          </div>
        </div>

        <div>
          <div>
            <img alt="Length" />
          </div>

          <div>
            <h3>128K context length</h3>
          </div>
        </div>
      </div>

      <div>
        <div>
          <div>
            <img alt="Speed" />
          </div>

          <div>
            <h3>Best for complex multi-step reasoning tasks</h3>
          </div>
        </div>

        <div>
          <div>
            <img alt="Lock" />
          </div>

          <div>
            <h3>No training on customer data</h3>
          </div>
        </div>
      </div>
    </div>
  </div>

  <div>
    <h2>Real World Use Cases</h2>

    <div>
      <div>
        <div>
          <img alt="Complex Analysis" />
        </div>

        <div>
          <h3>Complex multi-step analysis and reasoning</h3>
        </div>
      </div>

      <div>
        <div>
          <img alt="Research" />
        </div>

        <div>
          <h3>Advanced research with deep reasoning</h3>
        </div>
      </div>

      <div>
        <div>
          <img alt="Decision Making" />
        </div>

        <div>
          <h3>Strategic decision making with comprehensive analysis</h3>
        </div>
      </div>
    </div>
  </div>

  <div>
    <CodeGroup>
      ```bash cURL theme={null}
      curl --request POST \
        --url https://api.perplexity.ai/v1/sonar \
        --header "Authorization: Bearer <token>" \
        --header "Content-Type: application/json" \
        --data '{
          "model": "sonar-reasoning-pro",
          "messages": [
            {
              "role": "user",
              "content": "Analyze the feasibility of fusion energy becoming a mainstream power source by 2040."
            }
          ]
        }' | jq
      ```

      ```python python theme={null}
      import requests

      url = "https://api.perplexity.ai/v1/sonar"

      payload = {
          "model": "sonar-reasoning-pro",
          "messages": [
              {"role": "user", "content": "Analyze the feasibility of fusion energy becoming a mainstream power source by 2040."}
          ]
      }
      headers = {
          "Authorization": "Bearer <token>",
          "Content-Type": "application/json"
      }

      response = requests.post(url, json=payload, headers=headers)
      print(response.json())
      ```
    </CodeGroup>

    <Note>
      * The `sonar-reasoning-pro` model is designed to output a `<think>` section containing reasoning tokens, immediately followed by a valid JSON object. As a result, the `response_format` parameter does not remove these reasoning tokens from the output. We recommend using a custom parser to extract the valid JSON portion, and an example implementation can be found [here](https://github.com/ppl-ai/api-discussion/blob/main/utils/extract_json_reasoning_models.py).
    </Note>

    **Sample Response Metadata**

    ```json Success Response expandable wrap theme={null}
    {
    "id": "f9a5c42b-a53f-4c63-8e68-80d927221e7a",
    "model": "sonar-reasoning-pro",
    "created": 1756486858,
    "usage": {
      "prompt_tokens": 17,
      "completion_tokens": 1152,
      "total_tokens": 1169,
      "search_context_size": "low",
      "cost": {
        "input_tokens_cost": 0.0,
        "output_tokens_cost": 0.009,
        "request_cost": 0.006,
        "total_cost": 0.015
      }
    },
    "citations": [
      "https://pubs.aip.org/physicstoday/article/77/12/22/3321123/UK-coalition-gears-up-to-demonstrate-commercial",
      "https://energy.mit.edu/news/mit-study-shows-that-fusion-energy-could-play-a-major-role-in-the-global-response-to-climate-change/",
      "https://www.world-nuclear-news.org/Articles/US-could-operate-a-fusion-plant-by-2040-Academy-sa",
      "https://www.youtube.com/watch?v=qUkn8FarAcw",
      "https://world-nuclear.org/information-library/current-and-future-generation/nuclear-fusion-power"
    ],
    "search_results": [
      {
        "title": "UK coalition gears up to demonstrate commercial viability of ...",
        "url": "https://pubs.aip.org/physicstoday/article/77/12/22/3321123/UK-coalition-gears-up-to-demonstrate-commercial",
        "date": "2024-12-01",
        "last_updated": "2025-05-24",
        "snippet": "The UK plans to build a prototype fusion plant by the early 2040s that can put electricity on the grid and demonstrates that fusion energy is commercially ...See more"
      },
      {
        "title": "MIT study shows that fusion energy could play a major role ...",
        "url": "https://energy.mit.edu/news/mit-study-shows-that-fusion-energy-could-play-a-major-role-in-the-global-response-to-climate-change/",
        "date": "2024-10-16",
        "last_updated": "2024-10-18",
        "snippet": "Experts in energy systems modeling and fusion technology explore the future role of fusion at various costs and carbon constraints."
      },
      {
        "title": "US could operate a fusion plant by 2040, Academy says",
        "url": "https://www.world-nuclear-news.org/Articles/US-could-operate-a-fusion-plant-by-2040-Academy-sa",
        "date": "2021-03-12",
        "last_updated": "2024-12-22",
        "snippet": "It identifies key goals and innovations needed to support the development of a US fusion pilot plant, many of which it says should be developed ...See more"
      },
      {
        "title": "MIT Cracked Nuclear Fusion.. And it Might Have Just ...",
        "url": "https://www.youtube.com/watch?v=qUkn8FarAcw",
        "date": "2025-05-31",
        "last_updated": "2025-08-23",
        "snippet": "This single breakthrough from MIT may have just triggered the beginning of the end for the global oil industry."
      },
      {
        "title": "Nuclear Fusion Power",
        "url": "https://world-nuclear.org/information-library/current-and-future-generation/nuclear-fusion-power",
        "date": "2025-06-05",
        "last_updated": "2025-08-29",
        "snippet": "STEP is scheduled for completion in 2040. In February 2022 researchers at JET achieved 59 megajoules of heat energy from fusion over a five- ...See more"
      }
    ],
    "object": "chat.completion",
    "choices": [
      {
        "index": 0,
        "finish_reason": "stop",
        "message": {
          "role": "assistant",
          "content": "<think>\nThe user is asking me to analyze the feasibility of fusion energy becoming a mainstream power source by 2040. Let me look at the search results to see what information is available about fusion energy timelines and viability.\n\nFrom the search results:\n\n1. UK STEP program plans to build a prototype fusion plant by early 2040s that can put electricity on the grid and demonstrate commercial viability. Goal is to produce about 100 MW of net electricity.\n\n2. MIT study shows fusion technologies may be a decade away from commercial deployment, with focus on determining what cost levels fusion plants must reach by 2050 to achieve strong market penetration.\n\n3. US could operate a fusion pilot plant by 2040 according to the National Academy. The report suggests the US is positioned to begin planning its first fusion pilot plant now to meet the challenge of operating between 2035 and 2040.\n\n4. YouTube video discussing MIT breakthrough and market projections of $80 billion by 2035 and $350 billion by 2050.\n\n5. World Nuclear Association mentions STEP scheduled for completion in 2040, and various tokamak projects including ITER operating in the 2020s and CFETR due for completion in 2030.\n\nSo I need to analyze the feasibility based on:\n- Technical challenges and progress\n- Timeline considerations  \n- Economic factors\n- Current projects and milestones\n\nThe query is asking for analysis, so I should provide a comprehensive assessment covering different aspects. This seems like it would benefit from multiple sections since it's a complex topic.\n\nLet me structure this as:\n- Current state and recent progress\n- Technical challenges \n- Timeline analysis\n- Economic considerations\n- Conclusion on feasibility\n\nI need to be careful about the restrictions - no hedging language, no \"according to search results\" phrases, cite sources appropriately, use past tense for events that happened before the current date (August 29, 2025).\n</think>\n\nThe prospect of fusion energy becoming a mainstream power source by 2040 represents one of the most ambitious technological challenges of our time, with significant progress being made but substantial hurdles remaining.\n\n## Current State and Recent Breakthroughs\n\nMultiple major projects are converging on the 2040 timeline with varying degrees of ambition. The UK's Spherical Tokamak for Energy Production (STEP) program aims to build a prototype fusion plant by the early 2040s that can deliver electricity to the grid and demonstrate commercial viability, targeting approximately 100 MW of net electricity output[1]. The United States has positioned itself to operate a fusion pilot plant between 2035 and 2040, with the National Academy concluding that requisite resources and planning can support this timeline[3].\n\nSeveral critical technological milestones have been achieved in recent years. The Joint European Torus (JET) achieved 59 megajoules of heat energy from fusion, while multiple tokamak facilities continue advancing the science[5]. The international ITER project, currently under construction in France, will become the largest tokamak when it operates in the 2020s, providing crucial data for commercial development[5].\n\n## Technical and Engineering Challenges\n\nThe technical demands for achieving mainstream fusion power by 2040 are **formidable**. Current fusion technologies face three primary engineering challenges: achieving sustained net energy output, maintaining adequate tritium supply for fuel, and demonstrating long-term operational maintenance capabilities[1]. Even successful projects like STEP acknowledge these goals as \"massively ambitious\" but \"just about doable\"[1].\n\nThe transition from experimental reactors to commercial power plants requires solving complex materials science problems, particularly regarding radiation-resistant components and magnetic confinement systems. The Chinese Fusion Engineering Test Reactor (CFETR), designed to be larger than ITER and scheduled for completion in 2030, represents a critical stepping stone toward commercial viability[5].\n\n## Economic Feasibility and Market Dynamics\n\nEconomic projections suggest the fusion market could reach $80 billion by 2035 and potentially exceed $350 billion by 2050[4]. However, research indicates that fusion technologies may still be a decade away from commercial deployment, with detailed costs of future commercial fusion power plants remaining uncertain[2].\n\nThe economic viability of fusion power will depend heavily on achieving competitive cost levels compared to other energy sources, including conventional fossil fuels, nuclear fission, renewable energy, and storage technologies[2]. Regulatory frameworks will play a crucial role as cost drivers, potentially creating significant barriers or enablers depending on policy approaches[2].\n\n## Timeline Reality Check\n\nWhile pilot plants and demonstration facilities may operate by 2040, achieving **mainstream** adoption requires distinguishing between proving technical feasibility and scaling to widespread commercial deployment. The evidence suggests 2040 will likely mark the beginning of commercial demonstration rather than mainstream adoption.\n\nResearch emphasizes that if cost and performance targets can be achieved, fusion energy can play a major role in meeting future electricity needs and achieving global net-zero carbon goals[2]. However, this transition will more likely occur in the latter half of the century rather than by 2040.\n\n## Assessment of 2040 Feasibility\n\nFusion energy becoming a mainstream power source by 2040 faces significant feasibility constraints. While multiple pilot plants and demonstration facilities will likely operate by this date, true mainstream adoption requires overcoming substantial technical, economic, and scaling challenges that extend beyond the 2040 timeline.\n\nThe convergence of major international projects, substantial investment flows, and recent technical breakthroughs creates a foundation for commercial fusion power. However, the transition from demonstration to mainstream deployment typically requires additional decades for technology maturation, cost reduction, and infrastructure development. The 2040s will more realistically represent the **beginning** of the commercial fusion era rather than its mainstream adoption."
        },
        "delta": {
          "role": "assistant",
          "content": ""
        }
      }
    ]
    }
    ```

    <Accordion title="Cost Breakdown for Sample Request">
      <Info>
        **Token Usage**

        * Prompt Tokens: 17
        * Completion Tokens: 1152
        * Search Context Size: Low
      </Info>

      <Steps>
        <Step title="Calculate Input Tokens Cost">
          17 tokens ÷ 1,000,000 × $2 = $0.000034
        </Step>

        <Step title="Calculate Output Tokens Cost">
          1152 tokens ÷ 1,000,000 × $8 = $0.009216
        </Step>

        <Step title="Calculate Search Context Cost">
          1 request × $6 ÷ 1,000 = $0.006
        </Step>

        <Step title="Calculate Total Cost">
          $0.000034 + $0.009216 + $0.006 = $0.015250
        </Step>
      </Steps>

      <Check>
        **Total cost for this request: \$0.015250**
      </Check>
    </Accordion>
  </div>
</div>


# OpenAI SDK Compatibility
Source: https://docs.perplexity.ai/docs/sonar/openai-compatibility

Use OpenAI SDKs with the Sonar API by changing the base URL and API key

<SonarDeprecationNotice />

## Overview

Perplexity's Sonar API is fully compatible with OpenAI's Chat Completions format. You can use your existing OpenAI client libraries with the Sonar API by simply changing the base URL and providing your Perplexity API key.

<Info>
  **Endpoint Note:** Perplexity's canonical Sonar API endpoint is `POST /v1/sonar`. For OpenAI SDK compatibility, `POST /chat/completions` is also accepted as an alias. The OpenAI SDK automatically routes `client.chat.completions.create()` to `/chat/completions`, which Perplexity handles seamlessly. No SDK changes are needed beyond setting the base URL.
</Info>

<Tip>
  **We recommend using the [Perplexity SDK](/docs/sdk/overview)** for the best experience with full type safety, enhanced features, and preset support. Use OpenAI SDKs if you're already integrated and need drop-in compatibility.
</Tip>

## Quick Start

Use the OpenAI SDK with Perplexity's Sonar API:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    from openai import OpenAI

    client = OpenAI(
        api_key=os.environ.get("PERPLEXITY_API_KEY"),
        base_url="https://api.perplexity.ai"
    )

    completion = client.chat.completions.create(
        model="sonar-pro",
        messages=[
            {"role": "user", "content": "Explain the underlying physics of magnetic confinement fusion and the role of the Lawson criterion."}
        ]
    )

    print(completion.choices[0].message.content)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    import OpenAI from 'openai';

    const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai"
    });

    const completion = await client.chat.completions.create({
      model: "sonar-pro",
      messages: [
        { role: "user", content: "Explain the underlying physics of magnetic confinement fusion and the role of the Lawson criterion." }
      ]
    });

    console.log(completion.choices[0].message.content);
    ```
  </Tab>
</Tabs>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "258a700e-40fd-4e8d-956b-351e6ebc7f37",
    "choices": [
      {
        "delta": {
          "content": "",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "index": 0,
        "message": {
          "content": "Magnetic confinement fusion uses strong magnetic fields to trap a very hot, ionized gas (plasma) so that light nuclei collide and fuse faster than the energy is lost, and the Lawson criterion quantifies the minimum combination of plasma density, temperature, and confinement time required for this to produce net energy. The core physics is charged-particle motion in magnetic fields (guiding centers following field lines plus gyration and drifts), collective plasma stability, and energy balance; the Lawson criterion is the formal expression of that energy balance.\n\n---\n\n### 1. Why fusion needs confinement\n\nFor deuterium–tritium (D–T) fusion to occur at an appreciable rate, the plasma must reach temperatures of order \\(10^8\\) K (∼10 keV), hotter than the Sun’s core, so that nuclei can overcome the Coulomb repulsion and get close enough for the strong nuclear force to fuse them.[1][4][6] At these temperatures:\n\n- All atoms are ionized → a **plasma** of electrons and ions.[1][4][6]  \n- No solid material can touch the plasma; it would vaporize instantly.[1][4]\n\nSo fusion requires:\n\n- **Heating** the fuel to fusion temperatures.  \n- **Confining** it long enough and dense enough that many fusion reactions occur before the energy escapes.[4][6]\n\nIn stars, gravity provides confinement; in labs, strong magnetic fields are used instead.[4][6]\n\n---\n\n### 2. Single-particle motion: how magnetic fields confine charges\n\nThe basic building block is the Lorentz force on a charged particle in a magnetic field: \\(\\mathbf{F} = q\\,\\mathbf{v} \\times \\mathbf{B}\\).\n\nFrom this follow key motions (as shown in standard plasma-physics treatments and educational material):[2][3][6]\n\n- A component of velocity **perpendicular** to \\(\\mathbf{B}\\) causes **circular gyro-motion** around the field line at the Larmor radius.  \n- A component **parallel** to \\(\\mathbf{B}\\) feels no magnetic force and moves freely along the field.[2]  \n\nCombined, ions and electrons **spiral** along magnetic field lines: they are tightly bound across the field but free to move along it.[2][3][6]\n\nThis leads to the confinement idea:\n\n- Shape the magnetic field so that **field lines are closed** (e.g., in a torus), forming a “magnetic bottle.”  \n- Particles spiral around these closed lines, remaining away from material walls.[1][3][6]\n\nThe stronger the magnetic field:\n\n- The **smaller** the Larmor radius.  \n- The **slower** cross-field drifts and diffusion.  \n- The **better** the confinement.[2][3]\n\n---\n\n### 3. From single particles to plasma: collective and MHD behavior\n\nAt fusion-relevant densities, the plasma’s own currents and charges significantly modify the externally applied magnetic field, and the medium must be treated collectively.[2][3][7] This is described by **magnetohydrodynamics (MHD)**:\n\n- The plasma behaves like a conducting fluid embedded in magnetic field lines.  \n- Magnetic field lines are often described as “frozen in” to the plasma: fluid elements move along field lines, and dragging the plasma across the field tends to drag the lines with it.[2]\n\nKey implications for magnetic confinement:\n\n- **Pressure balance:** Plasma pressure pushes outward, magnetic pressure and tension pull inward. Stable confinement demands that the magnetic field be strong enough and appropriately shaped to counter plasma pressure and currents.[3][7]  \n- **Instabilities:** Certain pressure/current configurations are unstable (e.g., kink, ballooning, interchange instabilities), leading to bulging, twisting, or breaking of confined regions and degraded confinement.[2][3][6][7]  \n- **Turbulence:** Small-scale fluctuations and turbulence cause enhanced transport of heat and particles across field lines, reducing the effective confinement time below what classical single-particle theory would predict.[2][3][7]\n\nDesigning a successful magnetic confinement system is largely about **finding magnetic geometries and operating regimes that avoid or tame these instabilities** and minimize turbulent transport.[3][6][7]\n\n---\n\n### 4. Magnetic geometry in practice: toroidal devices\n\nBecause particles stream freely along field lines, the field lines themselves must not intersect walls, which leads naturally to **toroidal (doughnut-shaped)** configurations:[1][5][6]\n\n- **Tokamak:**  \n  - Strong toroidal field from external coils.  \n  - Large plasma current generates a poloidal field, twisting field lines into helical paths, improving confinement and stability.[5][6][7]  \n- **Stellarator:**  \n  - Uses 3D-shaped external coils to create the required helical fields; does not rely on a large plasma current, which avoids some current-driven instabilities but demands complex coil engineering.[5][6][7]\n\nTwist in the field lines helps cancel or average out systematic drifts that would otherwise move particles to the wall.[2][6]\n\nOther configurations (mirror machines, reversed-field pinches, spherical tokamaks, etc.) explore different ways of shaping \\(\\mathbf{B}\\), but modern mainstream MCF focuses on tokamaks and stellarators.[5][6][7]\n\n---\n\n### 5. Energy balance and the Lawson criterion\n\nTo generate net power, the fusion plasma must satisfy an **energy balance condition**: fusion power produced must equal or exceed total power lost (radiation, conduction, convection, particle escape).[6][7]\n\nFor a D–T plasma, this condition is commonly expressed as the **Lawson criterion**, which relates:\n\n- **n** – plasma particle density  \n- **T** – temperature  \n- **τ\\_E** – energy confinement time (a measure of how long energy stays in the plasma before being lost)\n\nIn one common form, the Lawson criterion requires that the **triple product** \\(n T \\tau_E\\) exceed a critical value for ignition (self-sustaining fusion without external heating) or for net energy gain.[6][7]\n\nConceptually:\n\n- Fusion power density \\(\\propto n^2 \\langle \\sigma v \\rangle\\), where \\(\\langle \\sigma v \\rangle\\) increases with temperature up to an optimum.  \n- Loss power density \\(\\propto \\frac{3 n T}{\\tau_E}\\) (roughly, energy per particle divided by confinement time).  \n- Setting fusion power ≥ loss power gives a condition on \\(n T \\tau_E\\).[6][7]\n\nFor D–T at ∼10–20 keV, the required triple product is on the order of \\(10^{21}\\,\\text{keV·s·m}^{-3}\\) (order-of-magnitude; exact numbers depend on detailed assumptions), and modern large tokamaks operate near or approaching this regime in brief pulses.[6][7]\n\n**Role of the Lawson criterion in MCF:**\n\n- It defines the **minimum combination** of density, temperature, and confinement time needed for practical fusion.  \n- Because the temperature window is fairly constrained by fusion cross sections, MCF devices mostly trade off **density versus confinement time**:  \n  - Magnetic confinement operates at relatively **low density** and **long τ\\_E** (milliseconds to seconds or longer).  \n  - Inertial confinement operates at very **high density** and extremely **short τ\\_E** (nanoseconds).  \n- It provides a quantitative **performance metric**: experiments report their achieved \\(n T \\tau_E\\) and compare to the Lawson threshold for ignition or for specific gain factors.[6][7]\n\nIn short, the Lawson criterion translates “good enough confinement” into a precise inequality involving measurable plasma parameters.\n\n---\n\n### 6. Why magnetic confinement is hard\n\nLinking the physics pieces:\n\n- **Single-particle physics** explains why strong magnetic fields can, in principle, confine hot plasmas away from walls.  \n- **Collective and MHD physics** explain why real plasmas develop currents, instabilities, and turbulence that degrade that ideal confinement.  \n- The **Lawson criterion** states the quantitative target: despite all losses, achieve a triple product high enough that fusion heating balances or exceeds losses.\n\nMajor technical and physics challenges in MCF include:[3][4][6][7]\n\n- Achieving and sustaining **multi-tesla magnetic fields** with high precision.  \n- Controlling **MHD instabilities** and turbulent transport to attain long τ\\_E.  \n- Handling **extreme heat and particle loads** where confined plasma meets material surfaces (divertors, first wall).[3]  \n- Integrating materials, superconducting magnets, heating systems, and control systems to operate reliably for long durations.[3][6][7]\n\nAll of these are pursued with the Lawson criterion in mind: improving confinement time and allowable density at a given temperature to reach or surpass the ignition and net-gain conditions.\n\nIf you’d like, I can next walk through the Lawson criterion derivation step-by-step from the energy balance equations, or compare typical Lawson targets for magnetic vs inertial confinement.",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "finish_reason": "stop"
      }
    ],
    "created": 1779896019,
    "model": "sonar-pro",
    "citations": [
      "https://www.york.ac.uk/physics-engineering-technology/ypi/research/mcf/",
      "https://www.youtube.com/watch?v=gwOrbr8KWDs",
      "https://www.peaknano.com/blog/magnetic-confinement-fusion-explained-history-challenges-and-enabling-technologies-peak-blog",
      "https://www.energy.gov/science/doe-explainsplasma-confinement",
      "http://www.iaea.org/bulletin/magnetic-fusion-confinement-with-tokamaks-and-stellarators",
      "https://en.wikipedia.org/wiki/Magnetic_confinement_fusion",
      "http://ui.adsabs.harvard.edu/abs/2016NatPh..12..398O/abstract"
    ],
    "object": "chat.completion",
    "search_results": [
      {
        "title": "Magnetic Confinement Fusion - University of York",
        "url": "https://www.york.ac.uk/physics-engineering-technology/ypi/research/mcf/",
        "date": null,
        "last_updated": "2026-04-21",
        "snippet": "In magnetic confinement fusion (MCF), the fuel (deuterium and tritium) is heated to a temperature which is ten times hotter than the centre of the Sun.",
        "source": "web"
      },
      {
        "title": "How nuclear fusion works (3) - magnetic confinement, tokamaks ...",
        "url": "https://www.youtube.com/watch?v=gwOrbr8KWDs",
        "date": "2022-07-11",
        "last_updated": "2026-03-31",
        "snippet": ".youtube.com/watch?v=IhHsOwLdCu4 [2] J. P. Freidberg, “Plasma Physics and Fusion Energy” (CUP 2010). [3] T. F. Neiser et al., “Gyrokinetic ...",
        "source": "web"
      },
      {
        "title": "Magnetic Confinement Fusion Explained: History, Challenges, and ...",
        "url": "https://www.peaknano.com/blog/magnetic-confinement-fusion-explained-history-challenges-and-enabling-technologies-peak-blog",
        "date": "2025-12-18",
        "last_updated": "2026-05-27",
        "snippet": "The principle behind MCF is grounded in charged particle motion. Plasmas naturally follow magnetic field lines. Under the right magnetic ...",
        "source": "web"
      },
      {
        "title": "DOE Explains...Plasma Confinement - Department of Energy",
        "url": "https://www.energy.gov/science/doe-explainsplasma-confinement",
        "date": "2026-05-22",
        "last_updated": "2026-05-17",
        "snippet": "Plasma confinement refers to the containment of a plasma by various forces at the extreme conditions necessary for fusion.",
        "source": "web"
      },
      {
        "title": "Magnetic Fusion Confinement with Tokamaks and Stellarators",
        "url": "http://www.iaea.org/bulletin/magnetic-fusion-confinement-with-tokamaks-and-stellarators",
        "date": null,
        "last_updated": null,
        "snippet": "Strong magnets in the reactors keep the ions confined. Electrons are also bound by the reactors' forces and play a role in the surroundings. The magnetic forces ...",
        "source": "web"
      },
      {
        "title": "Magnetic confinement fusion - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Magnetic_confinement_fusion",
        "date": "2005-04-04",
        "last_updated": "2026-03-03",
        "snippet": "Magnetic confinement fusion (MCF) is an approach to generate thermonuclear fusion power that uses magnetic fields to confine fusion fuel in the form of a ...",
        "source": "web"
      },
      {
        "title": "Magnetic-confinement fusion - NASA ADS",
        "url": "http://ui.adsabs.harvard.edu/abs/2016NatPh..12..398O/abstract",
        "date": "1999-01-01",
        "last_updated": "2025-03-17",
        "snippet": "Here we review the basic physics underlying magnetic fusion: past achievements, present efforts and the prospects for future production of electrical energy.",
        "source": "web"
      }
    ],
    "status": null,
    "type": null,
    "usage": {
      "completion_tokens": 1917,
      "cost": {
        "input_tokens_cost": 5e-05,
        "output_tokens_cost": 0.02875,
        "total_cost": 0.03481,
        "citation_tokens_cost": null,
        "reasoning_tokens_cost": null,
        "request_cost": 0.006,
        "search_queries_cost": null
      },
      "prompt_tokens": 18,
      "total_tokens": 1935,
      "citation_tokens": null,
      "num_search_queries": null,
      "reasoning_tokens": null,
      "search_context_size": "low"
    }
  }
  ```
</Accordion>

## Configuration

### Setting Up the OpenAI SDK

Configure OpenAI SDKs to work with Perplexity by setting the `base_url` to `https://api.perplexity.ai`:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    from openai import OpenAI

    client = OpenAI(
        api_key=os.environ.get("PERPLEXITY_API_KEY"),
        base_url="https://api.perplexity.ai"
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    import OpenAI from 'openai';

    const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai"
    });
    ```
  </Tab>
</Tabs>

<Info>
  **Important**: Use `base_url="https://api.perplexity.ai"` for the Sonar API.
</Info>

## Basic Usage

Perplexity's Sonar API is fully compatible with OpenAI's Chat Completions interface.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    from openai import OpenAI

    client = OpenAI(
        api_key=os.environ.get("PERPLEXITY_API_KEY"),
        base_url="https://api.perplexity.ai"
    )

    completion = client.chat.completions.create(
        model="sonar-pro",
        messages=[
            {"role": "user", "content": "Explain the underlying physics of magnetic confinement fusion and the role of the Lawson criterion."}
        ]
    )

    print(completion.choices[0].message.content)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    import OpenAI from 'openai';

    const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai"
    });

    const completion = await client.chat.completions.create({
      model: "sonar-pro",
      messages: [
        { role: "user", content: "Explain the underlying physics of magnetic confinement fusion and the role of the Lawson criterion." }
      ]
    });

    console.log(completion.choices[0].message.content);
    ```
  </Tab>
</Tabs>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "258a700e-40fd-4e8d-956b-351e6ebc7f37",
    "choices": [
      {
        "delta": {
          "content": "",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "index": 0,
        "message": {
          "content": "Magnetic confinement fusion uses strong magnetic fields to trap a very hot, ionized gas (plasma) so that light nuclei collide and fuse faster than the energy is lost, and the Lawson criterion quantifies the minimum combination of plasma density, temperature, and confinement time required for this to produce net energy. The core physics is charged-particle motion in magnetic fields (guiding centers following field lines plus gyration and drifts), collective plasma stability, and energy balance; the Lawson criterion is the formal expression of that energy balance.\n\n---\n\n### 1. Why fusion needs confinement\n\nFor deuterium–tritium (D–T) fusion to occur at an appreciable rate, the plasma must reach temperatures of order \\(10^8\\) K (∼10 keV), hotter than the Sun’s core, so that nuclei can overcome the Coulomb repulsion and get close enough for the strong nuclear force to fuse them.[1][4][6] At these temperatures:\n\n- All atoms are ionized → a **plasma** of electrons and ions.[1][4][6]  \n- No solid material can touch the plasma; it would vaporize instantly.[1][4]\n\nSo fusion requires:\n\n- **Heating** the fuel to fusion temperatures.  \n- **Confining** it long enough and dense enough that many fusion reactions occur before the energy escapes.[4][6]\n\nIn stars, gravity provides confinement; in labs, strong magnetic fields are used instead.[4][6]\n\n---\n\n### 2. Single-particle motion: how magnetic fields confine charges\n\nThe basic building block is the Lorentz force on a charged particle in a magnetic field: \\(\\mathbf{F} = q\\,\\mathbf{v} \\times \\mathbf{B}\\).\n\nFrom this follow key motions (as shown in standard plasma-physics treatments and educational material):[2][3][6]\n\n- A component of velocity **perpendicular** to \\(\\mathbf{B}\\) causes **circular gyro-motion** around the field line at the Larmor radius.  \n- A component **parallel** to \\(\\mathbf{B}\\) feels no magnetic force and moves freely along the field.[2]  \n\nCombined, ions and electrons **spiral** along magnetic field lines: they are tightly bound across the field but free to move along it.[2][3][6]\n\nThis leads to the confinement idea:\n\n- Shape the magnetic field so that **field lines are closed** (e.g., in a torus), forming a “magnetic bottle.”  \n- Particles spiral around these closed lines, remaining away from material walls.[1][3][6]\n\nThe stronger the magnetic field:\n\n- The **smaller** the Larmor radius.  \n- The **slower** cross-field drifts and diffusion.  \n- The **better** the confinement.[2][3]\n\n---\n\n### 3. From single particles to plasma: collective and MHD behavior\n\nAt fusion-relevant densities, the plasma’s own currents and charges significantly modify the externally applied magnetic field, and the medium must be treated collectively.[2][3][7] This is described by **magnetohydrodynamics (MHD)**:\n\n- The plasma behaves like a conducting fluid embedded in magnetic field lines.  \n- Magnetic field lines are often described as “frozen in” to the plasma: fluid elements move along field lines, and dragging the plasma across the field tends to drag the lines with it.[2]\n\nKey implications for magnetic confinement:\n\n- **Pressure balance:** Plasma pressure pushes outward, magnetic pressure and tension pull inward. Stable confinement demands that the magnetic field be strong enough and appropriately shaped to counter plasma pressure and currents.[3][7]  \n- **Instabilities:** Certain pressure/current configurations are unstable (e.g., kink, ballooning, interchange instabilities), leading to bulging, twisting, or breaking of confined regions and degraded confinement.[2][3][6][7]  \n- **Turbulence:** Small-scale fluctuations and turbulence cause enhanced transport of heat and particles across field lines, reducing the effective confinement time below what classical single-particle theory would predict.[2][3][7]\n\nDesigning a successful magnetic confinement system is largely about **finding magnetic geometries and operating regimes that avoid or tame these instabilities** and minimize turbulent transport.[3][6][7]\n\n---\n\n### 4. Magnetic geometry in practice: toroidal devices\n\nBecause particles stream freely along field lines, the field lines themselves must not intersect walls, which leads naturally to **toroidal (doughnut-shaped)** configurations:[1][5][6]\n\n- **Tokamak:**  \n  - Strong toroidal field from external coils.  \n  - Large plasma current generates a poloidal field, twisting field lines into helical paths, improving confinement and stability.[5][6][7]  \n- **Stellarator:**  \n  - Uses 3D-shaped external coils to create the required helical fields; does not rely on a large plasma current, which avoids some current-driven instabilities but demands complex coil engineering.[5][6][7]\n\nTwist in the field lines helps cancel or average out systematic drifts that would otherwise move particles to the wall.[2][6]\n\nOther configurations (mirror machines, reversed-field pinches, spherical tokamaks, etc.) explore different ways of shaping \\(\\mathbf{B}\\), but modern mainstream MCF focuses on tokamaks and stellarators.[5][6][7]\n\n---\n\n### 5. Energy balance and the Lawson criterion\n\nTo generate net power, the fusion plasma must satisfy an **energy balance condition**: fusion power produced must equal or exceed total power lost (radiation, conduction, convection, particle escape).[6][7]\n\nFor a D–T plasma, this condition is commonly expressed as the **Lawson criterion**, which relates:\n\n- **n** – plasma particle density  \n- **T** – temperature  \n- **τ\\_E** – energy confinement time (a measure of how long energy stays in the plasma before being lost)\n\nIn one common form, the Lawson criterion requires that the **triple product** \\(n T \\tau_E\\) exceed a critical value for ignition (self-sustaining fusion without external heating) or for net energy gain.[6][7]\n\nConceptually:\n\n- Fusion power density \\(\\propto n^2 \\langle \\sigma v \\rangle\\), where \\(\\langle \\sigma v \\rangle\\) increases with temperature up to an optimum.  \n- Loss power density \\(\\propto \\frac{3 n T}{\\tau_E}\\) (roughly, energy per particle divided by confinement time).  \n- Setting fusion power ≥ loss power gives a condition on \\(n T \\tau_E\\).[6][7]\n\nFor D–T at ∼10–20 keV, the required triple product is on the order of \\(10^{21}\\,\\text{keV·s·m}^{-3}\\) (order-of-magnitude; exact numbers depend on detailed assumptions), and modern large tokamaks operate near or approaching this regime in brief pulses.[6][7]\n\n**Role of the Lawson criterion in MCF:**\n\n- It defines the **minimum combination** of density, temperature, and confinement time needed for practical fusion.  \n- Because the temperature window is fairly constrained by fusion cross sections, MCF devices mostly trade off **density versus confinement time**:  \n  - Magnetic confinement operates at relatively **low density** and **long τ\\_E** (milliseconds to seconds or longer).  \n  - Inertial confinement operates at very **high density** and extremely **short τ\\_E** (nanoseconds).  \n- It provides a quantitative **performance metric**: experiments report their achieved \\(n T \\tau_E\\) and compare to the Lawson threshold for ignition or for specific gain factors.[6][7]\n\nIn short, the Lawson criterion translates “good enough confinement” into a precise inequality involving measurable plasma parameters.\n\n---\n\n### 6. Why magnetic confinement is hard\n\nLinking the physics pieces:\n\n- **Single-particle physics** explains why strong magnetic fields can, in principle, confine hot plasmas away from walls.  \n- **Collective and MHD physics** explain why real plasmas develop currents, instabilities, and turbulence that degrade that ideal confinement.  \n- The **Lawson criterion** states the quantitative target: despite all losses, achieve a triple product high enough that fusion heating balances or exceeds losses.\n\nMajor technical and physics challenges in MCF include:[3][4][6][7]\n\n- Achieving and sustaining **multi-tesla magnetic fields** with high precision.  \n- Controlling **MHD instabilities** and turbulent transport to attain long τ\\_E.  \n- Handling **extreme heat and particle loads** where confined plasma meets material surfaces (divertors, first wall).[3]  \n- Integrating materials, superconducting magnets, heating systems, and control systems to operate reliably for long durations.[3][6][7]\n\nAll of these are pursued with the Lawson criterion in mind: improving confinement time and allowable density at a given temperature to reach or surpass the ignition and net-gain conditions.\n\nIf you’d like, I can next walk through the Lawson criterion derivation step-by-step from the energy balance equations, or compare typical Lawson targets for magnetic vs inertial confinement.",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "finish_reason": "stop"
      }
    ],
    "created": 1779896019,
    "model": "sonar-pro",
    "citations": [
      "https://www.york.ac.uk/physics-engineering-technology/ypi/research/mcf/",
      "https://www.youtube.com/watch?v=gwOrbr8KWDs",
      "https://www.peaknano.com/blog/magnetic-confinement-fusion-explained-history-challenges-and-enabling-technologies-peak-blog",
      "https://www.energy.gov/science/doe-explainsplasma-confinement",
      "http://www.iaea.org/bulletin/magnetic-fusion-confinement-with-tokamaks-and-stellarators",
      "https://en.wikipedia.org/wiki/Magnetic_confinement_fusion",
      "http://ui.adsabs.harvard.edu/abs/2016NatPh..12..398O/abstract"
    ],
    "object": "chat.completion",
    "search_results": [
      {
        "title": "Magnetic Confinement Fusion - University of York",
        "url": "https://www.york.ac.uk/physics-engineering-technology/ypi/research/mcf/",
        "date": null,
        "last_updated": "2026-04-21",
        "snippet": "In magnetic confinement fusion (MCF), the fuel (deuterium and tritium) is heated to a temperature which is ten times hotter than the centre of the Sun.",
        "source": "web"
      },
      {
        "title": "How nuclear fusion works (3) - magnetic confinement, tokamaks ...",
        "url": "https://www.youtube.com/watch?v=gwOrbr8KWDs",
        "date": "2022-07-11",
        "last_updated": "2026-03-31",
        "snippet": ".youtube.com/watch?v=IhHsOwLdCu4 [2] J. P. Freidberg, “Plasma Physics and Fusion Energy” (CUP 2010). [3] T. F. Neiser et al., “Gyrokinetic ...",
        "source": "web"
      },
      {
        "title": "Magnetic Confinement Fusion Explained: History, Challenges, and ...",
        "url": "https://www.peaknano.com/blog/magnetic-confinement-fusion-explained-history-challenges-and-enabling-technologies-peak-blog",
        "date": "2025-12-18",
        "last_updated": "2026-05-27",
        "snippet": "The principle behind MCF is grounded in charged particle motion. Plasmas naturally follow magnetic field lines. Under the right magnetic ...",
        "source": "web"
      },
      {
        "title": "DOE Explains...Plasma Confinement - Department of Energy",
        "url": "https://www.energy.gov/science/doe-explainsplasma-confinement",
        "date": "2026-05-22",
        "last_updated": "2026-05-17",
        "snippet": "Plasma confinement refers to the containment of a plasma by various forces at the extreme conditions necessary for fusion.",
        "source": "web"
      },
      {
        "title": "Magnetic Fusion Confinement with Tokamaks and Stellarators",
        "url": "http://www.iaea.org/bulletin/magnetic-fusion-confinement-with-tokamaks-and-stellarators",
        "date": null,
        "last_updated": null,
        "snippet": "Strong magnets in the reactors keep the ions confined. Electrons are also bound by the reactors' forces and play a role in the surroundings. The magnetic forces ...",
        "source": "web"
      },
      {
        "title": "Magnetic confinement fusion - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Magnetic_confinement_fusion",
        "date": "2005-04-04",
        "last_updated": "2026-03-03",
        "snippet": "Magnetic confinement fusion (MCF) is an approach to generate thermonuclear fusion power that uses magnetic fields to confine fusion fuel in the form of a ...",
        "source": "web"
      },
      {
        "title": "Magnetic-confinement fusion - NASA ADS",
        "url": "http://ui.adsabs.harvard.edu/abs/2016NatPh..12..398O/abstract",
        "date": "1999-01-01",
        "last_updated": "2025-03-17",
        "snippet": "Here we review the basic physics underlying magnetic fusion: past achievements, present efforts and the prospects for future production of electrical energy.",
        "source": "web"
      }
    ],
    "status": null,
    "type": null,
    "usage": {
      "completion_tokens": 1917,
      "cost": {
        "input_tokens_cost": 5e-05,
        "output_tokens_cost": 0.02875,
        "total_cost": 0.03481,
        "citation_tokens_cost": null,
        "reasoning_tokens_cost": null,
        "request_cost": 0.006,
        "search_queries_cost": null
      },
      "prompt_tokens": 18,
      "total_tokens": 1935,
      "citation_tokens": null,
      "num_search_queries": null,
      "reasoning_tokens": null,
      "search_context_size": "low"
    }
  }
  ```
</Accordion>

## Streaming

Streaming works exactly like OpenAI's API:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    from openai import OpenAI

    client = OpenAI(
        api_key=os.environ.get("PERPLEXITY_API_KEY"),
        base_url="https://api.perplexity.ai"
    )

    stream = client.chat.completions.create(
        model="sonar-pro",
        messages=[
            {"role": "user", "content": "Explain the underlying physics of magnetic confinement fusion and the role of the Lawson criterion."}
        ],
        stream=True
    )

    for chunk in stream:
        if chunk.choices[0].delta.content:
            print(chunk.choices[0].delta.content, end="", flush=True)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    import OpenAI from 'openai';

    const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai"
    });

    const stream = await client.chat.completions.create({
      model: "sonar-pro",
      messages: [
        { role: "user", content: "Explain the underlying physics of magnetic confinement fusion and the role of the Lawson criterion." }
      ],
      stream: true
    });

    for await (const chunk of stream) {
      if (chunk.choices[0]?.delta?.content) {
        process.stdout.write(chunk.choices[0].delta.content);
      }
    }
    ```
  </Tab>
</Tabs>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "258a700e-40fd-4e8d-956b-351e6ebc7f37",
    "choices": [
      {
        "delta": {
          "content": "",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "index": 0,
        "message": {
          "content": "Magnetic confinement fusion uses strong magnetic fields to trap a very hot, ionized gas (plasma) so that light nuclei collide and fuse faster than the energy is lost, and the Lawson criterion quantifies the minimum combination of plasma density, temperature, and confinement time required for this to produce net energy. The core physics is charged-particle motion in magnetic fields (guiding centers following field lines plus gyration and drifts), collective plasma stability, and energy balance; the Lawson criterion is the formal expression of that energy balance.\n\n---\n\n### 1. Why fusion needs confinement\n\nFor deuterium–tritium (D–T) fusion to occur at an appreciable rate, the plasma must reach temperatures of order \\(10^8\\) K (∼10 keV), hotter than the Sun’s core, so that nuclei can overcome the Coulomb repulsion and get close enough for the strong nuclear force to fuse them.[1][4][6] At these temperatures:\n\n- All atoms are ionized → a **plasma** of electrons and ions.[1][4][6]  \n- No solid material can touch the plasma; it would vaporize instantly.[1][4]\n\nSo fusion requires:\n\n- **Heating** the fuel to fusion temperatures.  \n- **Confining** it long enough and dense enough that many fusion reactions occur before the energy escapes.[4][6]\n\nIn stars, gravity provides confinement; in labs, strong magnetic fields are used instead.[4][6]\n\n---\n\n### 2. Single-particle motion: how magnetic fields confine charges\n\nThe basic building block is the Lorentz force on a charged particle in a magnetic field: \\(\\mathbf{F} = q\\,\\mathbf{v} \\times \\mathbf{B}\\).\n\nFrom this follow key motions (as shown in standard plasma-physics treatments and educational material):[2][3][6]\n\n- A component of velocity **perpendicular** to \\(\\mathbf{B}\\) causes **circular gyro-motion** around the field line at the Larmor radius.  \n- A component **parallel** to \\(\\mathbf{B}\\) feels no magnetic force and moves freely along the field.[2]  \n\nCombined, ions and electrons **spiral** along magnetic field lines: they are tightly bound across the field but free to move along it.[2][3][6]\n\nThis leads to the confinement idea:\n\n- Shape the magnetic field so that **field lines are closed** (e.g., in a torus), forming a “magnetic bottle.”  \n- Particles spiral around these closed lines, remaining away from material walls.[1][3][6]\n\nThe stronger the magnetic field:\n\n- The **smaller** the Larmor radius.  \n- The **slower** cross-field drifts and diffusion.  \n- The **better** the confinement.[2][3]\n\n---\n\n### 3. From single particles to plasma: collective and MHD behavior\n\nAt fusion-relevant densities, the plasma’s own currents and charges significantly modify the externally applied magnetic field, and the medium must be treated collectively.[2][3][7] This is described by **magnetohydrodynamics (MHD)**:\n\n- The plasma behaves like a conducting fluid embedded in magnetic field lines.  \n- Magnetic field lines are often described as “frozen in” to the plasma: fluid elements move along field lines, and dragging the plasma across the field tends to drag the lines with it.[2]\n\nKey implications for magnetic confinement:\n\n- **Pressure balance:** Plasma pressure pushes outward, magnetic pressure and tension pull inward. Stable confinement demands that the magnetic field be strong enough and appropriately shaped to counter plasma pressure and currents.[3][7]  \n- **Instabilities:** Certain pressure/current configurations are unstable (e.g., kink, ballooning, interchange instabilities), leading to bulging, twisting, or breaking of confined regions and degraded confinement.[2][3][6][7]  \n- **Turbulence:** Small-scale fluctuations and turbulence cause enhanced transport of heat and particles across field lines, reducing the effective confinement time below what classical single-particle theory would predict.[2][3][7]\n\nDesigning a successful magnetic confinement system is largely about **finding magnetic geometries and operating regimes that avoid or tame these instabilities** and minimize turbulent transport.[3][6][7]\n\n---\n\n### 4. Magnetic geometry in practice: toroidal devices\n\nBecause particles stream freely along field lines, the field lines themselves must not intersect walls, which leads naturally to **toroidal (doughnut-shaped)** configurations:[1][5][6]\n\n- **Tokamak:**  \n  - Strong toroidal field from external coils.  \n  - Large plasma current generates a poloidal field, twisting field lines into helical paths, improving confinement and stability.[5][6][7]  \n- **Stellarator:**  \n  - Uses 3D-shaped external coils to create the required helical fields; does not rely on a large plasma current, which avoids some current-driven instabilities but demands complex coil engineering.[5][6][7]\n\nTwist in the field lines helps cancel or average out systematic drifts that would otherwise move particles to the wall.[2][6]\n\nOther configurations (mirror machines, reversed-field pinches, spherical tokamaks, etc.) explore different ways of shaping \\(\\mathbf{B}\\), but modern mainstream MCF focuses on tokamaks and stellarators.[5][6][7]\n\n---\n\n### 5. Energy balance and the Lawson criterion\n\nTo generate net power, the fusion plasma must satisfy an **energy balance condition**: fusion power produced must equal or exceed total power lost (radiation, conduction, convection, particle escape).[6][7]\n\nFor a D–T plasma, this condition is commonly expressed as the **Lawson criterion**, which relates:\n\n- **n** – plasma particle density  \n- **T** – temperature  \n- **τ\\_E** – energy confinement time (a measure of how long energy stays in the plasma before being lost)\n\nIn one common form, the Lawson criterion requires that the **triple product** \\(n T \\tau_E\\) exceed a critical value for ignition (self-sustaining fusion without external heating) or for net energy gain.[6][7]\n\nConceptually:\n\n- Fusion power density \\(\\propto n^2 \\langle \\sigma v \\rangle\\), where \\(\\langle \\sigma v \\rangle\\) increases with temperature up to an optimum.  \n- Loss power density \\(\\propto \\frac{3 n T}{\\tau_E}\\) (roughly, energy per particle divided by confinement time).  \n- Setting fusion power ≥ loss power gives a condition on \\(n T \\tau_E\\).[6][7]\n\nFor D–T at ∼10–20 keV, the required triple product is on the order of \\(10^{21}\\,\\text{keV·s·m}^{-3}\\) (order-of-magnitude; exact numbers depend on detailed assumptions), and modern large tokamaks operate near or approaching this regime in brief pulses.[6][7]\n\n**Role of the Lawson criterion in MCF:**\n\n- It defines the **minimum combination** of density, temperature, and confinement time needed for practical fusion.  \n- Because the temperature window is fairly constrained by fusion cross sections, MCF devices mostly trade off **density versus confinement time**:  \n  - Magnetic confinement operates at relatively **low density** and **long τ\\_E** (milliseconds to seconds or longer).  \n  - Inertial confinement operates at very **high density** and extremely **short τ\\_E** (nanoseconds).  \n- It provides a quantitative **performance metric**: experiments report their achieved \\(n T \\tau_E\\) and compare to the Lawson threshold for ignition or for specific gain factors.[6][7]\n\nIn short, the Lawson criterion translates “good enough confinement” into a precise inequality involving measurable plasma parameters.\n\n---\n\n### 6. Why magnetic confinement is hard\n\nLinking the physics pieces:\n\n- **Single-particle physics** explains why strong magnetic fields can, in principle, confine hot plasmas away from walls.  \n- **Collective and MHD physics** explain why real plasmas develop currents, instabilities, and turbulence that degrade that ideal confinement.  \n- The **Lawson criterion** states the quantitative target: despite all losses, achieve a triple product high enough that fusion heating balances or exceeds losses.\n\nMajor technical and physics challenges in MCF include:[3][4][6][7]\n\n- Achieving and sustaining **multi-tesla magnetic fields** with high precision.  \n- Controlling **MHD instabilities** and turbulent transport to attain long τ\\_E.  \n- Handling **extreme heat and particle loads** where confined plasma meets material surfaces (divertors, first wall).[3]  \n- Integrating materials, superconducting magnets, heating systems, and control systems to operate reliably for long durations.[3][6][7]\n\nAll of these are pursued with the Lawson criterion in mind: improving confinement time and allowable density at a given temperature to reach or surpass the ignition and net-gain conditions.\n\nIf you’d like, I can next walk through the Lawson criterion derivation step-by-step from the energy balance equations, or compare typical Lawson targets for magnetic vs inertial confinement.",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "finish_reason": "stop"
      }
    ],
    "created": 1779896019,
    "model": "sonar-pro",
    "citations": [
      "https://www.york.ac.uk/physics-engineering-technology/ypi/research/mcf/",
      "https://www.youtube.com/watch?v=gwOrbr8KWDs",
      "https://www.peaknano.com/blog/magnetic-confinement-fusion-explained-history-challenges-and-enabling-technologies-peak-blog",
      "https://www.energy.gov/science/doe-explainsplasma-confinement",
      "http://www.iaea.org/bulletin/magnetic-fusion-confinement-with-tokamaks-and-stellarators",
      "https://en.wikipedia.org/wiki/Magnetic_confinement_fusion",
      "http://ui.adsabs.harvard.edu/abs/2016NatPh..12..398O/abstract"
    ],
    "object": "chat.completion",
    "search_results": [
      {
        "title": "Magnetic Confinement Fusion - University of York",
        "url": "https://www.york.ac.uk/physics-engineering-technology/ypi/research/mcf/",
        "date": null,
        "last_updated": "2026-04-21",
        "snippet": "In magnetic confinement fusion (MCF), the fuel (deuterium and tritium) is heated to a temperature which is ten times hotter than the centre of the Sun.",
        "source": "web"
      },
      {
        "title": "How nuclear fusion works (3) - magnetic confinement, tokamaks ...",
        "url": "https://www.youtube.com/watch?v=gwOrbr8KWDs",
        "date": "2022-07-11",
        "last_updated": "2026-03-31",
        "snippet": ".youtube.com/watch?v=IhHsOwLdCu4 [2] J. P. Freidberg, “Plasma Physics and Fusion Energy” (CUP 2010). [3] T. F. Neiser et al., “Gyrokinetic ...",
        "source": "web"
      },
      {
        "title": "Magnetic Confinement Fusion Explained: History, Challenges, and ...",
        "url": "https://www.peaknano.com/blog/magnetic-confinement-fusion-explained-history-challenges-and-enabling-technologies-peak-blog",
        "date": "2025-12-18",
        "last_updated": "2026-05-27",
        "snippet": "The principle behind MCF is grounded in charged particle motion. Plasmas naturally follow magnetic field lines. Under the right magnetic ...",
        "source": "web"
      },
      {
        "title": "DOE Explains...Plasma Confinement - Department of Energy",
        "url": "https://www.energy.gov/science/doe-explainsplasma-confinement",
        "date": "2026-05-22",
        "last_updated": "2026-05-17",
        "snippet": "Plasma confinement refers to the containment of a plasma by various forces at the extreme conditions necessary for fusion.",
        "source": "web"
      },
      {
        "title": "Magnetic Fusion Confinement with Tokamaks and Stellarators",
        "url": "http://www.iaea.org/bulletin/magnetic-fusion-confinement-with-tokamaks-and-stellarators",
        "date": null,
        "last_updated": null,
        "snippet": "Strong magnets in the reactors keep the ions confined. Electrons are also bound by the reactors' forces and play a role in the surroundings. The magnetic forces ...",
        "source": "web"
      },
      {
        "title": "Magnetic confinement fusion - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Magnetic_confinement_fusion",
        "date": "2005-04-04",
        "last_updated": "2026-03-03",
        "snippet": "Magnetic confinement fusion (MCF) is an approach to generate thermonuclear fusion power that uses magnetic fields to confine fusion fuel in the form of a ...",
        "source": "web"
      },
      {
        "title": "Magnetic-confinement fusion - NASA ADS",
        "url": "http://ui.adsabs.harvard.edu/abs/2016NatPh..12..398O/abstract",
        "date": "1999-01-01",
        "last_updated": "2025-03-17",
        "snippet": "Here we review the basic physics underlying magnetic fusion: past achievements, present efforts and the prospects for future production of electrical energy.",
        "source": "web"
      }
    ],
    "status": null,
    "type": null,
    "usage": {
      "completion_tokens": 1917,
      "cost": {
        "input_tokens_cost": 5e-05,
        "output_tokens_cost": 0.02875,
        "total_cost": 0.03481,
        "citation_tokens_cost": null,
        "reasoning_tokens_cost": null,
        "request_cost": 0.006,
        "search_queries_cost": null
      },
      "prompt_tokens": 18,
      "total_tokens": 1935,
      "citation_tokens": null,
      "num_search_queries": null,
      "reasoning_tokens": null,
      "search_context_size": "low"
    }
  }
  ```
</Accordion>

## Perplexity-Specific Parameters

Add Perplexity-specific search parameters using `extra_body` (Python) or direct parameters (TypeScript):

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    from openai import OpenAI

    client = OpenAI(
        api_key=os.environ.get("PERPLEXITY_API_KEY"),
        base_url="https://api.perplexity.ai"
    )

    completion = client.chat.completions.create(
        model="sonar-pro",
        messages=[
            {"role": "user", "content": "What does the National Snow and Ice Data Center (NSIDC) report about long-term trends in Arctic sea ice extent?"}
        ],
        extra_body={
            "search_domain_filter": ["nature.com", "science.org"],
            "search_recency_filter": "month"
        }
    )

    print(completion.choices[0].message.content)
    print(f"Sources: {len(completion.search_results)} articles found")
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    import OpenAI from 'openai';

    const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai"
    });

    const completion = await client.chat.completions.create({
      model: "sonar-pro",
      messages: [
        { role: "user", content: "What does the National Snow and Ice Data Center (NSIDC) report about long-term trends in Arctic sea ice extent?" }
      ],
      search_domain_filter: ["nature.com", "science.org"],
      search_recency_filter: "month"
    } as any);

    console.log(completion.choices[0].message.content);
    console.log(`Sources: ${(completion as any).search_results.length} articles found`);
    ```
  </Tab>
</Tabs>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "31d5d419-b5f0-413e-8f86-4d55bad6866e",
    "choices": [
      {
        "delta": {
          "content": "",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "index": 0,
        "message": {
          "content": "NSIDC reports that **Arctic sea ice extent has declined over the long term** since the satellite record began in 1979, and that the decline is **statistically significant** across all months.[5] NSIDC also says the Arctic trend is part of a broader pattern of **less ice overall, including lower seasonal minima and less multi-year ice**.[1][5]\n\nA few specific points NSIDC emphasizes:\n\n- **All months have shown a declining trend** in Arctic sea ice extent from November 1978 through March 2025.[5]\n- The **annual minimum** and **annual maximum** extents are now both lower than earlier decades, with recent minimums about **50% of 1980s values**.[3]\n- NSIDC uses the long satellite record to show the **big picture**, noting that short-term ups and downs do not outweigh the longer downward trend.[5]\n- Scientists at NSIDC and NASA have said recent low-ice years continue the **long-term trend observed over several decades**.[1]\n\nIn short, NSIDC’s message is that Arctic sea ice extent is **shrinking over time**, especially in the context of the full satellite record, even though year-to-year variability remains large.[1][5][6]",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "finish_reason": "stop"
      }
    ],
    "created": 1779896048,
    "model": "sonar-pro",
    "citations": [
      "https://science.nasa.gov/earth/arctic-winter-sea-ice-2026/",
      "https://www.climate.gov/news-features/event-tracker/2024-antarctic-sea-ice-winter-maximum-second-lowest-record",
      "https://arctic.noaa.gov/report-card/report-card-2024/sea-ice-2024/",
      "https://svs.gsfc.nasa.gov/5521/",
      "https://nsidc.org/learn/ask-scientist/what-value-sea-ice-time-series-data",
      "https://nsidc.org/sea-ice-today",
      "https://nsidc.org/sea-ice-today/sea-ice-tools/charctic-interactive-sea-ice-graph",
      "https://climatedataguide.ucar.edu/climate-data/nsidc-sea-ice-index",
      "https://zacklabe.com/arctic-sea-ice-figures/"
    ],
    "object": "chat.completion",
    "search_results": [
      {
        "title": "Arctic Winter Sea Ice Ties Record Low, NASA, NSIDC Scientists Find",
        "url": "https://science.nasa.gov/earth/arctic-winter-sea-ice-2026/",
        "date": "2026-03-26",
        "last_updated": "2026-05-15",
        "snippet": "Scientists with NASA and NSIDC found that this winter's peak Arctic ice coverage continues the long-term trend observed over the past several ...",
        "source": "web"
      },
      {
        "title": "2024 Antarctic sea ice winter maximum second lowest on record",
        "url": "https://www.climate.gov/news-features/event-tracker/2024-antarctic-sea-ice-winter-maximum-second-lowest-record",
        "date": "2024-10-08",
        "last_updated": "2026-03-04",
        "snippet": "I think the long-term trend will be a decreasing ice extent in all seasons, but there is such variability on the time scale of a few years ...",
        "source": "web"
      },
      {
        "title": "Sea Ice - NOAA Arctic",
        "url": "https://arctic.noaa.gov/report-card/report-card-2024/sea-ice-2024/",
        "date": "2024-11-11",
        "last_updated": "2026-05-26",
        "snippet": "Sea ice extent in September 2024 was the 6th lowest in the satellite record (1979 to present); the last 18 September extents (2007-24) are the ...",
        "source": "web"
      },
      {
        "title": "Sea Ice Extent 1978-2025 - NASA Scientific Visualization Studio",
        "url": "https://svs.gsfc.nasa.gov/5521/",
        "date": "2025-03-27",
        "last_updated": "2026-05-27",
        "snippet": "The Sea Ice Index provides a quick look at Arctic- and Antarctic-wide changes in sea ice. It is a source for consistent, up-to-date sea ice ...",
        "source": "web"
      },
      {
        "title": "What is the value of sea ice time series data?",
        "url": "https://nsidc.org/learn/ask-scientist/what-value-sea-ice-time-series-data",
        "date": "2025-05-15",
        "last_updated": "2026-03-03",
        "snippet": "From November 1978 to March 2025, Arctic sea ice extent showed a declining trend in all months. Meanwhile, Antarctic sea ice has been linked ...",
        "source": "web"
      },
      {
        "title": "Sea Ice Today | National Snow and Ice Data Center",
        "url": "https://nsidc.org/sea-ice-today",
        "date": null,
        "last_updated": "2026-05-26",
        "snippet": "In the Arctic, the annual minimum sea ice extent occurs in September and the annual sea ice maximum extent occurs in March. In the Antarctic, the minimum extent ...",
        "source": "web"
      },
      {
        "title": "Charctic Interactive Sea Ice Graph",
        "url": "https://nsidc.org/sea-ice-today/sea-ice-tools/charctic-interactive-sea-ice-graph",
        "date": null,
        "last_updated": "2026-05-27",
        "snippet": "For both the Arctic and Antarctic, the graph compares sea ice extent (area of ocean with at least 15 percent sea ice concentration) between all years selected.",
        "source": "web"
      },
      {
        "title": "NSIDC Sea Ice Index - Climate Data Guide",
        "url": "https://climatedataguide.ucar.edu/climate-data/nsidc-sea-ice-index",
        "date": "2025-12-11",
        "last_updated": "2026-05-26",
        "snippet": "The Sea Ice Index provides consistent long-term statistics on sea ice extent and area change. However, it is not reliable for operational uses ...",
        "source": "web"
      },
      {
        "title": "Polar Climate Change Figures - Zachary Labe",
        "url": "https://zacklabe.com/arctic-sea-ice-figures/",
        "date": "2026-01-04",
        "last_updated": "2026-05-26",
        "snippet": "Animation of changes in average September sea ice extent from 1979 through 2025 – with substantial natural variability and a long-term decline.",
        "source": "web"
      }
    ],
    "status": null,
    "type": null,
    "usage": {
      "completion_tokens": 263,
      "cost": {
        "input_tokens_cost": 8e-05,
        "output_tokens_cost": 0.00394,
        "total_cost": 0.01002,
        "citation_tokens_cost": null,
        "reasoning_tokens_cost": null,
        "request_cost": 0.006,
        "search_queries_cost": null
      },
      "prompt_tokens": 26,
      "total_tokens": 289,
      "citation_tokens": null,
      "num_search_queries": null,
      "reasoning_tokens": null,
      "search_context_size": "low"
    }
  }
  ```
</Accordion>

## API Compatibility

### Standard OpenAI Parameters

These parameters work exactly the same as OpenAI's API:

* `model` - Model name (use Perplexity model names like `sonar-pro`)
* `messages` - Chat messages array
* `max_tokens` - Maximum tokens in response
* `stream` - Enable streaming responses
* `temperature` - Response randomness (0-2)
* `top_p` - Nucleus sampling parameter
* `response_format` - Response format specification

### Perplexity-Specific Parameters

Sonar API supports additional search and response parameters:

* `search_domain_filter` - Limit or exclude specific domains
* `search_recency_filter` - Filter by content recency ("day", "week", "month", "year")
* `return_images` - Include image URLs in response
* `return_related_questions` - Include related questions
* `search_mode` - "web" (default) or "academic" mode selector
* `enable_search_classifier` - Let AI decide when to search
* `disable_search` - Turn off web search completely

<Info>
  See [Sonar API Reference](/api-reference/sonar-post) for complete parameter details.
</Info>

## Endpoint Mapping

| Method                                    | Perplexity Endpoint    | OpenAI Equivalent              | Notes                                               |
| ----------------------------------------- | ---------------------- | ------------------------------ | --------------------------------------------------- |
| `client.chat.completions.create()`        | `POST /v1/sonar`       | `POST /chat/completions`       | Both paths accepted by Perplexity for compatibility |
| `client.async_.chat.completions.create()` | `POST /v1/async/sonar` | `POST /async/chat/completions` | Both paths accepted by Perplexity for compatibility |

<Info>
  When using the OpenAI SDK, `client.chat.completions.create()` sends requests to `/chat/completions`. Perplexity accepts this path as an alias for `/v1/sonar`, so no SDK configuration changes are needed beyond `base_url`.
</Info>

## Response Structure

Perplexity responses match OpenAI's format exactly, with additional fields:

### Standard OpenAI Fields

* `choices[0].message.content` - The AI-generated response
* `model` - The model name used
* `usage` - Token consumption details
* `id`, `created`, `object` - Standard response metadata

### Perplexity-Specific Fields

* `search_results` - Array of web sources with `title`, `url`, and `date`
* `citations` - Array of citation URLs referenced in the response

**Example Response:**

```json theme={null}
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "model": "sonar-pro",
  "created": 1234567890,
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "The latest developments in AI include..."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 12,
    "completion_tokens": 315,
    "total_tokens": 327
  },
  "search_results": [
    {
      "title": "Latest AI Developments",
      "url": "https://example.com/ai-news",
      "date": "2025-02-01"
    }
  ],
  "citations": [
    "https://example.com/ai-news"
  ]
}
```

## Best Practices

<Steps>
  <Step title="Use the correct base URL">
    Always use `https://api.perplexity.ai` for the Sonar API.

    ```python theme={null}
    client = OpenAI(
        api_key=os.environ.get("PERPLEXITY_API_KEY"),
        base_url="https://api.perplexity.ai"  # Correct
    )
    ```
  </Step>

  <Step title="Handle errors gracefully">
    Use the OpenAI SDK's error handling:

    ```python theme={null}
    import os
    from openai import OpenAI, APIError, RateLimitError

    client = OpenAI(
        api_key=os.environ.get("PERPLEXITY_API_KEY"),
        base_url="https://api.perplexity.ai"
    )

    try:
        completion = client.chat.completions.create(
            model="sonar-pro",
            messages=[{"role": "user", "content": "Hello"}]
        )
    except RateLimitError:
        print("Rate limit exceeded, please retry later")
    except APIError as e:
        print(f"API error: {e.message}")
    ```
  </Step>

  <Step title="Use streaming for better UX">
    Stream responses for real-time user experience:

    ```python theme={null}
    stream = client.chat.completions.create(
        model="sonar-pro",
        messages=[{"role": "user", "content": "Long query..."}],
        stream=True
    )

    for chunk in stream:
        if chunk.choices[0].delta.content:
            print(chunk.choices[0].delta.content, end="", flush=True)
    ```
  </Step>

  <Step title="Access search results">
    Use the `search_results` field to get accurate source URLs:

    ```python theme={null}
    completion = client.chat.completions.create(
        model="sonar-pro",
        messages=[{"role": "user", "content": "What was NVIDIA's data-center segment revenue growth in fiscal 2024, and how did the stock react to the Q4 print?"}]
    )

    # Access search results
    for result in completion.search_results:
        print(f"{result['title']}: {result['url']}")
    ```

    <Accordion title="Response">
      ```json theme={null}
      {
        "id": "1ca706ec-87b5-4e45-b4a1-0a0b4e015085",
        "choices": [
          {
            "delta": {
              "content": "",
              "role": "assistant",
              "reasoning_steps": null,
              "tool_call_id": null,
              "tool_calls": null
            },
            "index": 0,
            "message": {
              "content": "NVIDIA’s data-center segment revenue growth in fiscal 2024 and the stock reaction to the Q4 print can be summarized as follows:\n\n**1. Data-center revenue growth in fiscal 2024**\n\nFrom NVIDIA’s own fiscal 2024 results release ([source 4](https://investor.nvidia.com/news/press-release-details/2024/NVIDIA-Announces-Financial-Results-for-Fourth-Quarter-and-Fiscal-2024/)):\n\n- Fiscal 2024 **data-center revenue**: **$47.5 billion**\n- Year-over-year growth: **up 217%** versus the prior fiscal year  \n\nSo, NVIDIA’s data-center segment revenue grew **217% year over year** in fiscal 2024.\n\n**2. Stock reaction to the Q4 FY2024 print**\n\nS&P Global’s post-earnings analysis for the subsequent Q1 FY2025 report includes a backward look at the Q4 FY2024 earnings release on Feb. 21, 2024 ([source 3](https://www.spglobal.com/market-intelligence/en/news-insights/research/2024/05/data-center-revenue-growth-continues-nvidias-fiscal-q1-2025-earnings)):\n\n- It notes that **NVDA stock was up close to 58% since the Q4 release on February 21, 2024** (measured by the time of their May 2024 analysis).\n\nIn other words, following the **Q4 FY2024 earnings print** (which reported the huge data-center growth), NVIDIA’s stock **rallied on the order of ~58% over the subsequent weeks/months**, according to S&P Global Market Intelligence.",
              "role": "assistant",
              "reasoning_steps": null,
              "tool_call_id": null,
              "tool_calls": null
            },
            "finish_reason": "stop"
          }
        ],
        "created": 1779391605,
        "model": "sonar-pro",
        "citations": [
          "https://www.govconwire.com/articles/nvidia-revenue-climbs-126-to-60-9b-in-fiscal-2024-jensen-huang-quoted",
          "https://www.statista.com/chart/25578/nvidias-quarterly-revenue-by-segments/",
          "https://www.spglobal.com/market-intelligence/en/news-insights/research/2024/05/data-center-revenue-growth-continues-nvidias-fiscal-q1-2025-earnings",
          "https://investor.nvidia.com/news/press-release-details/2024/NVIDIA-Announces-Financial-Results-for-Fourth-Quarter-and-Fiscal-2024/",
          "https://ycharts.com/indicators/nvidia_corp_nvda_data_center_revenue_quarterly",
          "http://bullfincher.io/companies/nvidia-corporation/revenue-by-segment"
        ],
        "object": "chat.completion",
        "search_results": [
          {
            "title": "NVIDIA Revenue Climbs 126% to $60.9B in Fiscal 2024",
            "url": "https://www.govconwire.com/articles/nvidia-revenue-climbs-126-to-60-9b-in-fiscal-2024-jensen-huang-quoted",
            "date": "2024-02-22",
            "last_updated": "2026-04-22",
            "snippet": "NVIDIA's Data Center segment contributed $47.5 billion revenue in the full year, a 217 percent growth from the previous year. “Our Data ...",
            "source": "web"
          },
          {
            "title": "Data Centers Almost Sole Driver of Nvidia's Revenue Boom - Statista",
            "url": "https://www.statista.com/chart/25578/nvidias-quarterly-revenue-by-segments/",
            "date": "2024-05-24",
            "last_updated": "2026-05-18",
            "snippet": "Between February and April 2024, $22.6 billion or 87 percent of Nvidia's overall revenue was attributable to data center solutions.",
            "source": "web"
          },
          {
            "title": "Data Center Revenue Growth Continues: Nvidia's Fiscal Q1 2025 ...",
            "url": "https://www.spglobal.com/market-intelligence/en/news-insights/research/2024/05/data-center-revenue-growth-continues-nvidias-fiscal-q1-2025-earnings",
            "date": "2024-05-29",
            "last_updated": "2026-05-17",
            "snippet": "The top-end estimate expects $189.9 billion, up from $182.6 billion, while the low-end estimate is now at $119.5 billion, up from $95.8 billion, ...",
            "source": "web"
          },
          {
            "title": "NVIDIA Announces Financial Results for Fourth Quarter and Fiscal ...",
            "url": "https://investor.nvidia.com/news/press-release-details/2024/NVIDIA-Announces-Financial-Results-for-Fourth-Quarter-and-Fiscal-2024/",
            "date": "2024-02-21",
            "last_updated": "2026-05-13",
            "snippet": "For fiscal 2024, revenue was up 126% to $60.9 billion. GAAP earnings per diluted share was $11.93, up 586% from a year ago. Non-GAAP earnings ...",
            "source": "web"
          },
          {
            "title": "NVIDIA Corp (NVDA) - Data Center Revenue (Quarterly) - YCharts",
            "url": "https://ycharts.com/indicators/nvidia_corp_nvda_data_center_revenue_quarterly",
            "date": "2026-03-23",
            "last_updated": "2026-05-18",
            "snippet": "NVIDIA Corp (NVDA) - Data Center Revenue is at a current level of 62.31B, up from 51.22B last quarter and up from 30.77B one year ago. This is a change of ...",
            "source": "web"
          },
          {
            "title": "NVIDIA Corporation Revenue Breakdown By Segment - Bullfincher",
            "url": "http://bullfincher.io/companies/nvidia-corporation/revenue-by-segment",
            "date": null,
            "last_updated": "2026-03-30",
            "snippet": "In fiscal year 2026, Data Center revenue reached $193.74 Billion, representing 89.72% of NVIDIA Corporation's total revenue and making it the largest segment ...",
            "source": "web"
          }
        ],
        "status": null,
        "type": null,
        "usage": {
          "completion_tokens": 354,
          "cost": {
            "input_tokens_cost": 8e-05,
            "output_tokens_cost": 0.00531,
            "total_cost": 0.01139,
            "citation_tokens_cost": null,
            "reasoning_tokens_cost": null,
            "request_cost": 0.006,
            "search_queries_cost": null
          },
          "prompt_tokens": 28,
          "total_tokens": 382,
          "citation_tokens": null,
          "num_search_queries": null,
          "reasoning_tokens": null,
          "search_context_size": "low"
        }
      }
      ```
    </Accordion>
  </Step>
</Steps>

## Recommended: Perplexity SDK

We recommend using Perplexity's native SDKs for the best developer experience:

* **Type safety** - Full TypeScript/Python type definitions for all parameters
* **Enhanced features** - Direct access to all Perplexity-specific features
* **Better error messages** - Perplexity-specific error handling
* **Simpler setup** - No need to configure base URLs

See the [Perplexity SDK Guide](/docs/sdk/overview) for details.

## Next Steps

<CardGroup>
  <Card title="Sonar Quickstart" icon="rocket" href="/docs/sonar/quickstart">
    Get started with Sonar API using OpenAI SDKs.
  </Card>

  <Card title="Sonar API Features" icon="book" href="/docs/sonar/features">
    Learn best practices for prompting and using the Sonar API.
  </Card>

  <Card title="API Reference" icon="code-circle" href="/api-reference/sonar-post">
    View complete API documentation for the Sonar endpoint.
  </Card>

  <Card title="Search Filters" icon="search" href="/docs/sonar/filters#search-control">
    Learn how to control search behavior with filters and parameters.
  </Card>
</CardGroup>


# Pro Search Classifier
Source: https://docs.perplexity.ai/docs/sonar/pro-search/classifier

Optimize cost and performance with automatic query classification between Pro Search and Fast Search modes

<SonarDeprecationNotice />

## Overview

The Pro Search Classifier is an intelligent system that automatically determines whether a query requires the advanced multi-step tool usage of Pro Search or can be effectively answered with standard Fast Search. This optimization helps you balance performance needs with cost efficiency.

<Info>
  Instead of manually choosing between `"pro"` and `"fast"` search types, you can use `"auto"` to let the classifier make the optimal decision for each query.
</Info>

## How It Works

When you set `search_type: "auto"`, the classifier analyzes your query across multiple dimensions:

<Steps>
  <Step title="Query Complexity Analysis">
    The classifier evaluates:

    * Number of sub-questions or aspects
    * Requirement for comparative analysis
    * Need for multi-step reasoning
    * Complexity of information synthesis required

    ```json theme={null}
    {
      "web_search_options": {
        "search_type": "auto"  // Let the classifier decide
      }
    }
    ```
  </Step>

  <Step title="Classification Decision">
    Based on the analysis, the classifier routes the query to either:

    * **Pro Search** for complex, multi-faceted queries requiring multi-step tool usage
    * **Fast Search** for straightforward information retrieval

    The decision is transparent in the response metadata.
  </Step>

  <Step title="Execution">
    The selected search mode processes your query:

    * **Pro Search**: Uses built-in tools (web\_search, fetch\_url\_content) automatically
    * **Fast Search**: Performs optimized single-pass search and synthesis

    You receive the same high-quality response format regardless of which mode is used.
  </Step>
</Steps>

## Classification Patterns

### Queries Classified as Pro Search

Complex queries that benefit from multi-step tool usage are automatically routed to Pro Search:

<AccordionGroup>
  <Accordion title="Multi-Part Questions">
    **Example Query:**
    "What are the differences between React, Vue, and Angular in terms of performance, learning curve, and ecosystem? Which one should I choose for a large enterprise application?"

    **Why Pro Search:**

    * Requires information about three different frameworks
    * Needs comparative analysis across multiple dimensions
    * Involves gathering expert opinions and recommendations
    * Benefits from synthesis of diverse sources

    **Tool Usage:**

    * Multiple web searches for each framework
    * URL fetching for benchmark data and official documentation
  </Accordion>

  <Accordion title="Research Synthesis">
    **Example Query:**
    "Summarize the latest peer-reviewed research on the effectiveness of intermittent fasting for weight loss and metabolic health. Include sample sizes and study limitations."

    **Why Pro Search:**

    * Requires finding multiple research papers
    * Needs access to full paper content, not just abstracts
    * Involves extracting specific data (sample sizes, limitations)
    * Requires synthesis across multiple studies

    **Tool Usage:**

    * Web search for recent peer-reviewed papers
    * `fetch_url_content` to read full papers
    * Information extraction and synthesis
  </Accordion>

  <Accordion title="Time-Sensitive Complex Analysis">
    **Example Query:**
    "Analyze the stock market impact of the Federal Reserve's most recent interest rate decision, including effects on different sectors and expert predictions for the next quarter."

    **Why Pro Search:**

    * Requires very recent information
    * Needs multi-source verification
    * Involves sector-by-sector analysis
    * Benefits from expert opinion gathering

    **Tool Usage:**

    * Multiple targeted web searches
    * URL fetching for financial analysis reports
    * Synthesis of diverse expert opinions
  </Accordion>
</AccordionGroup>

### Queries Classified as Fast Search

Straightforward queries that don't require multi-step reasoning are efficiently handled by Fast Search:

<AccordionGroup>
  <Accordion title="Simple Factual Questions">
    **Example Query:**
    "What is the capital of France?"

    **Why Fast Search:**

    * Single, well-established fact
    * No calculation or analysis needed
    * Information readily available in search snippets

    **Processing:**

    * Single web search
    * Direct answer from search results
    * No need for multi-step reasoning
  </Accordion>

  <Accordion title="Straightforward Information Retrieval">
    **Example Query:**
    "What are the main features of the iPhone 15 Pro?"

    **Why Fast Search:**

    * Single product inquiry
    * Information available in product descriptions
    * No comparative analysis required
    * No calculations needed

    **Processing:**

    * Search for product specifications
    * Extract and list features
    * Synthesize from search results
  </Accordion>

  <Accordion title="Single-Topic Queries">
    **Example Query:**
    "Explain what machine learning is."

    **Why Fast Search:**

    * Single concept definition
    * No multi-part analysis required
    * Standard information readily available

    **Processing:**

    * Search for machine learning explanations
    * Synthesize clear definition
    * Provide context from reliable sources
  </Accordion>

  <Accordion title="Basic Definitional Requests">
    **Example Query:**
    "What does API stand for and what is it used for?"

    **Why Fast Search:**

    * Simple definition request
    * No complex analysis needed
    * Information readily available

    **Processing:**

    * Quick search for API definition
    * Explain acronym and basic usage
    * Provide clear, concise answer
  </Accordion>
</AccordionGroup>

## Cost Implications

Understanding the cost difference helps you optimize your API usage:

<div>
  <div>
    <h4>Classified as Pro Search</h4>

    <ul>
      <li>Complex multi-part questions</li>
      <li>Requests requiring calculation or analysis</li>
      <li>Comparative research across sources</li>
      <li>Time-sensitive information needs</li>
    </ul>

    <div>
      <span>Uses Pro Search billing rates</span>
    </div>
  </div>

  <div>
    <h4>Classified as Fast Search</h4>

    <ul>
      <li>Simple factual questions</li>
      <li>Straightforward information retrieval</li>
      <li>Single-topic queries</li>
      <li>Basic definitional requests</li>
    </ul>

    <div>
      <span>Uses standard Sonar Pro billing rates</span>
    </div>
  </div>
</div>

### Pricing Comparison

**Pro Search Rates:**

* Input: \$3 per 1M tokens
* Output: \$15 per 1M tokens
* Request fees: \$14-\$22 per 1,000 requests (based on context size)

**Fast Search Rates:**

* Input: \$3 per 1M tokens
* Output: \$15 per 1M tokens
* Request fees: \$6-\$14 per 1,000 requests (based on context size - same as standard Sonar Pro)

<Tip>
  The automatic classifier helps you save money by using Pro Search only when its advanced capabilities are truly needed, while still ensuring complex queries get full multi-step tool usage.
</Tip>

## Usage Examples

### Using Automatic Classification

<CodeGroup>
  ```python Python SDK theme={null}
  from perplexity import Perplexity

  client = Perplexity()
  # Let the classifier decide
  response = client.chat.completions.create(
      model="sonar-pro",
      messages=[
          {
              "role": "user",
              "content": "Compare the energy efficiency (kWh/100mi and MPGe) of the Tesla Model 3, Chevrolet Bolt, and Nissan Leaf using EPA data."
          }
      ],
      stream=True,
      web_search_options={
          "search_type": "auto"  # Automatic classification
      }
  )

  for chunk in response:
      if chunk.choices[0].delta.content:
          print(chunk.choices[0].delta.content, end="")
  ```

  ```typescript Typescript SDK theme={null}
  import { Perplexity } from '@perplexity-ai/sdk';

  const client = new Perplexity();

  // Let the classifier decide
  const response = await client.chat.completions.create({
    model: 'sonar-pro',
    messages: [
      {
        role: 'user',
        content: 'Compare the energy efficiency (kWh/100mi and MPGe) of the Tesla Model 3, Chevrolet Bolt, and Nissan Leaf using EPA data.'
      }
    ],
    stream: true,
    web_search_options: {
      search_type: 'auto'  // Automatic classification
    }
  });

  for await (const chunk of response) {
    if (chunk.choices[0]?.delta?.content) {
      process.stdout.write(chunk.choices[0].delta.content);
    }
  }
  ```

  ```bash cURL theme={null}
  curl --request POST \
    --url https://api.perplexity.ai/v1/sonar \
    --header "Authorization: Bearer $PERPLEXITY_API_KEY" \
    --header "Content-Type: application/json" \
    --data '{
      "model": "sonar-pro",
      "messages": [
        {
          "role": "user",
          "content": "Compare the energy efficiency (kWh/100mi and MPGe) of the Tesla Model 3, Chevrolet Bolt, and Nissan Leaf using EPA data."
        }
      ],
      "stream": true,
      "web_search_options": {
        "search_type": "auto"
      }
    }' --no-buffer
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "cab71ad3-867d-4139-997e-c36ce805351b",
    "results": [
      {
        "snippet": "The following table compares official EPA ratings for fuel economy (in miles per gallon gasoline equivalent, mpg-e or MPGe, for plug-in electric vehicles) for series production all-electric passenger vehicles rated by the EPA for model years 2015, 2016, 2017, and 2023 versus the model year\n2016 vehicles that were rated the most efficient by the EPA with plug-in hybrid drivetrains (Chevrolet Volt – second generation), gasoline-electric hybrid drivetrains (Toyota Prius Eco - fourth generation), and the average new vehicle for that model year, which has a fuel economy of 25 mpg~‑US~ (9.4 L/100 km; 30 mpg~‑imp~).\nEPA rating data are taken from manufacturer testing of their own vehicles using a series of tests specified by federal law.\n...\nReal-world EV efficiency can also be expressed in miles per kilowatt-hour (mi/kWh), which converts EPA MPGe values into direct electrical energy consumption, allowing cross-comparison between electric and gasoline vehicles.\n...\n|Vehicle|Model year|EPA rated fuel economy|EPA rated fuel economy|EPA rated fuel economy|Notes| | |\n...\n|Toyota Prius HEV|2023|57 mpg|57 mpg|56 mpg|(9)| | |\n|Hyundai Ioniq 6 Long Range RWD w/ 18-inch wheels|2023|140 mpg‑e 24.1 kWh/100 mi; 15.0 kWh/100 km|153 mpg‑e 22.0 kWh/100 mi; 13.7 kWh/100 km|127 mpg‑e 26.5 kWh/100 mi; 16.5 kWh/100 km|(1)| | |\n...\n|Tesla Model Y AWD|2023|123 mpg‑e 27.4 kWh/100 mi; 17.0 kWh/100 km|129 mpg‑e 26.1 kWh/100 mi; 16.2 kWh/100 km|116 mpg‑e 29.1 kWh/100 mi; 18.1 kWh/100 km|(1)| | |\n|Tesla Model 3 Standard Range|2020|141 mpg‑e 23.9 kWh/100 mi; 14.9 kWh/100 km|148 mpg‑e 22.8 kWh/100 mi; 14.2 kWh/100 km|132 mpg‑e 25.5 kWh/100 mi; 15.9 kWh/100 km|(1)| | |\n...\n|Tesla Model 3 Long Range AWD|2020|121 mpg‑e 27.9 kWh/100 mi; 17.3 kWh/100 km|124 mpg‑e 27.2 kWh/100 mi; 16.9 kWh/100 km|116 mpg‑e 29.1 kWh/100 mi; 18.1 kWh/100 km|(1)| | |\n|Chevrolet Bolt EV|2017|119 mpg‑e 28.3 kWh/100 mi; 17.6 kWh/100 km|121 mpg‑e 27.9 kWh/100 mi; 17.3 kWh/100 km|110 mpg‑e 30.6 kWh/100 mi; 19.0 kWh/100 km| | | |\n...\n|Nissan Leaf (24 kW-h)|2013/14/15/16|114 mpg‑e 29.6 kWh/100 mi; 18.4 kWh/100 km|126 mpg‑e 26.8 kWh/100 mi; 16.6 kWh/100 km|101 mpg‑e 33.4 kWh/100 mi; 20.7 kWh/100 km|(1) (6)| | |\n...\n|Nissan Leaf (30 kW-h)|2016|112 mpg‑e 30.1 kWh/100 mi; 18.7 kWh/100 km|124 mpg‑e 27.2 kWh/100 mi; 16.9 kWh/100 km|101 mpg‑e 33.4 kWh/100 mi; 20.7 kWh/100 km|(1)| | |",
        "title": "Electric car EPA fuel economy - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Electric_car_EPA_fuel_economy",
        "date": "2015-04-30",
        "last_updated": "2026-05-05"
      },
      {
        "snippet": "Instead of focusing on battery size or total range, we look at **energy consumption (kWh per 100 miles)** and **MPGe**, the EPA’s miles-per-gallon equivalent metric.\n...\n**Methodology**: Recurrent's Most Efficient EVs of 2026 were determined based on combined efficiency in kWh/100miles as reported to the EPA.\n...\n## 3.\nTesla Model 3\n**Efficiency:** 25 kWh/100 miles\n**MPGe:** 134.8\n**Body style:** Compact sedan\n...\n## 5.\nTesla Model Y\n**Efficiency:** 26 kWh/100 miles\n**MPGe:** 129.6\n**Body style:** Compact crossover SUV\n...\n## 6.\nNissan LEAF\n**Efficiency:** 28 kWh/100 miles\n**MPGe:** 120.4\n**Body style:** Compact crossover (redesigned)",
        "title": "2026 Most Efficient EV by Size According to Testing - Recurrent",
        "url": "https://www.recurrentauto.com/research/most-efficient-ev",
        "date": "2026-03-02",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "|EPA MPG MPGe:Miles per Gallon Equivalent 1 gallon of gasoline=33.7 kWh About All-Electric Cars|Electricity Combined MPG:111 MPGe City MPG:123 Highway MPG:99 30 kWh/100 miles|",
        "title": "Find and Compare Cars",
        "url": "https://www.fueleconomy.gov/feg/noframes/48400.shtml",
        "date": "2023-01-01",
        "last_updated": "2024-10-03"
      },
      {
        "snippet": "MPGe is a unit of measure used by the Environmental Protection Agency (EPA) to represent EV fuel economy in a common unit with gas-powered vehicles, where 33.7 kilowatt-hours of electricity are equal to the energy contained in one gallon of gasoline.\nAmong those 17 models, there were a total of 37 unique configurations that achieved 100 MPGe or higher.\nThe Tesla Model 3 in rear-wheel drive configuration achieved the highest rating for MY 2022 with 132 MPGe.\n||\n|--|\n|||\n|Tesla Model 3|132|\n|Lucid Air|131|\n|Tesla Model Y|129|\n|Chevrolet Bolt EV|120|\n|Hyundai Kona Electric|120|\n|Tesla Model S|120|\n|Kia EV6|117|\n|Chevrolet Bolt EUV|115|\n|Hyundai Ioniq 5|114|\n|Kia Niro Electric|112|\n|Nissan Leaf|111|\n|MINI Cooper SE|110|\n|BMW i4 Gran Coupe|109|\n|Polestar 2|107|\n|Volkswagen ID.4|107|\n|Ford Mustang Mach-E|103|\n|Tesla Model X|102|\n...\n**Source: **U.S. Department of Energy and U.S. Environmental Protection Agency’s Fuel Economy Website, Compare Electric Vehicles Side-by-Side.\nData accessed August 24, 2022.",
        "title": "FOTW #1257, September 26, 2022: Seventeen EV Models Achieved ...",
        "url": "https://www.energy.gov/eere/vehicles/articles/fotw-1257-september-26-2022-seventeen-ev-models-achieved-epa-combined-rating",
        "date": "2022-09-26",
        "last_updated": "2025-10-09"
      },
      {
        "snippet": "Nevertheless, the efficiency and range varies a lot from EV to EV.\nTo help you choose which electric car is more suitable for you, I made the table below with EPA efficiency and range figures – for different driving scenarios (city, highway and mixed/combined).\nElectric car range and efficiency (EPA)\n|Electric car\n|City\nrange\n|Combined\nrange\n|Highway\nrange\n|City\nefficiency\n|Combined\nefficiency\n|Highway\nefficiency\n|2019 Tesla Model 3 Long Range (RWD)\n|340 miles\n547 km\n|325 miles\n523 km\n|307 miles\n494 km\n|24,8 kWh/100 miles\n15,4 kWh/100 km\n|25,9 kWh/100 miles\n16,1 kWh/100 km\n|27,4 kWh/100 miles\n17 kWh/100 km\n|2019 Tesla Model 3 Long Range (AWD)\n|320 miles\n515 km\n|310 miles\n499 km\n|297 miles\n478 km\n|28,1 kWh/100 miles\n17,5 kWh/100 km\n|29,1 kWh/100 miles\n18,1 kWh/100 km\n|30,1 kWh/100 miles\n18,7 kWh/100 km\n|2019 Tesla Model 3 Standard Range Plus\n|253 miles\n407 km\n|240 miles\n386 km\n|224 miles\n361 km\n|24,1 kWh/100 miles\n15 kWh/100 km\n|25,3 kWh/100 miles\n15,7 kWh/100 km\n|27,2 kWh/100 miles\n16,9 kWh/100 km\n|2019 Tesla Model S Long Range\n|382 miles\n614 km\n|370 miles\n595 km\n|356 miles\n573 km\n|29,3 kWh/100 miles\n18,2 kWh/100 km\n|30,4 kWh/100 miles\n18,9 kWh/100 km\n|31,5 kWh/100 miles\n19,6 kWh/100 km\n|2019 Tesla Model X Long Range\n...\n22,5 kWh/100 km\n...\n|2017-2019 Chevrolet Bolt EV\n|255 miles\n411 km\n|238 miles\n383 km\n|217 miles\n350 km\n|26,3 kWh/100 miles\n16,4 kWh/100 km\n|28,3 kWh/100 miles\n17,6 kWh/100 km\n|30,6 kWh/100 miles\n19 kWh/100 km\n|2020 Chevrolet Bolt EV\n|279 miles\n449 km\n|259 miles\n417 km\n|237 miles\n381 km\n|26,5 kWh/100 miles\n16,5 kWh/100 km\n|28,6 kWh/100 miles\n17,7 kWh/100 km\n|31,2 kWh/100 miles\n19,4 kWh/100 km",
        "title": "Electric car range and efficiency (EPA) - 🔋PushEVs",
        "url": "https://pushevs.com/electric-car-range-efficiency-epa/",
        "date": null,
        "last_updated": "2024-02-21"
      },
      {
        "snippet": "An efficient EV is simply a car that uses fewer kilowatt-hours of electricity to go the same distance.\n...\n53–140 MPGe\nEPA spread\nModel‑year 2024 EVs range from about 53 to 140 miles‑per‑gallon‑equivalent, nearly a 3x difference in efficiency.\n1.5–4.2 mi/kWh\nEnergy use\nOn the same test cycle, some EVs travel less than 1.5 miles per kWh while the best creep above 4 miles per kWh.\n...\nMPGe, or **miles per gallon equivalent**, is the EPA’s attempt to put EVs in gas‑car language.\nOne “gallon” of gasoline is treated as 33.7 kWh of energy.\nIf an EV uses 25 kWh to travel 100 miles, the math works out to roughly 135 MPGe.\n...\nElectricity is billed in **kilowatt‑hours** (kWh).\nSo the most honest unit is simply: how many kWh do you burn to go 100 miles?\n- **kWh/100 mi**: lower is better (like L/100 km)\n- **mi/kWh**: higher is better (like MPG)\nExample: a car that uses 25 kWh/100 mi delivers 4.0 mi/kWh.\nAt $0.15/kWh, those 100 miles cost about $3.75.\n...\nTake the EPA’s kWh/100‑mile number, divide by 100, and multiply by your home rate.\n...\nThat’s why EPA ratings show 2024 EVs spanning roughly 53–140 MPGe while gasoline cars live between 9–57 MPG for the same model year.\n...\nRecent EPA data and independent testing put a handful of EVs at the sharp end of the efficiency spear, especially in sedan form.\n### Sample of highly efficient EVs on sale (2024–2025)\nRepresentative trims; always confirm the exact configuration’s window sticker, as wheels, motors, and options change the numbers.\n|Model & year|Type|Energy use (kWh/100 mi)*|Approx. mi/kWh|EPA combined MPGe*|Notable trait|\n|--|--|--|--|--|--|\n|Lucid Air Pure (2025 RWD)|Sedan|≈23–24|≈4.2–4.3|High 130s–140s|Luxury sedan that somehow drinks like a subcompact.|\n|Hyundai Ioniq 6 SE (2024–2025 RWD)|Sedan|≈24–25|≈4.0–4.2|Around 140|Super‑slippery aero and efficient 800‑V platform.|\n|Tesla Model 3 Long Range RWD (2025)|Sedan|≈25|≈4.0|Low‑to‑mid 130s|The efficiency benchmark among mass‑market sedans.|\n|Tesla Model Y Long Range RWD (2025)|SUV|≈27–28|≈3.6–3.7|Mid‑120s|Roomier crossover form factor, small aero penalty.|\n|Lexus RZ 300e (2024–2025)|SUV|≈27|≈3.7|Mid‑120s|Luxury compact SUV that surprised everyone with its frugality.|\n|Kia EV6 / Hyundai Kona Electric / Kia Niro EV (2024–2025 RWD)|Crossovers|≈28–29|≈3.4–3.6|High teens/low 120s|The efficient heartland of the EV market.|\n|GMC Hummer EV Pickup/SUV|Truck/SUV|≈70+|≈1.4–1.5|Under 50|Off‑the‑charts consumption; think of it as a rolling coal plant with a conscience.|\n...\n### Sedans & hatchbacks\n- **Typical energy use:** ~24–30 kWh/100 mi\n- **Examples:** Hyundai Ioniq 6, Tesla Model 3, Lucid Air, Chevy Bolt (used)\n...\n#### 1.\nStart with kWh/100 mi, not just range\nRange is a product of pack size; kWh/100 mi is the diet.\n...\n#### 2.\nNormalize for body style and mission\nCompare sedans to sedans, crossovers to crossovers, trucks to trucks.\n...\nWhen you compare electric cars, focus less on the billboard range number and more on **kWh per 100 miles, body style, and real battery health**.\n- Use kWh/100 miles (or mi/kWh) as your primary yardstick; MPGe is just the translation into gas‑car language.",
        "title": "Electric Car Efficiency Comparison: 2025 Buyer's Guide - Recharged",
        "url": "https://recharged.com/articles/electric-car-efficiency-comparison-guide",
        "date": "2025-11-17",
        "last_updated": "2026-05-26"
      },
      {
        "snippet": "With an EPA-rated efficiency of 111 MPGe, it’s middle-of-the-road in efficiency, far below the Tesla but way above the 2021 Ford Mustang Mach-E GT’s 84 MPGe.\n...\nRecent figures from the U.S. Environmental Protection Agency (EPA) show that the 2021 Tesla Model 3 Standard Range Plus RWD stands at the top of the efficiency range, boasting a combined 142 MPGe—the electrical equivalent of a gallon of fuel.\n...\nEV testing and analysis firm Recurrent crunched the numbers on a set of 99 cars—half Tesla Model 3s and half Nissan Leafs—and their 500,000 data points of efficiency metrics were logged between November 2021 and March 2022.\nUsing an EPA figure-based mile per kWh (mi/kWh) measurement as opposed to MPGe, the Tesla range was calculated from 3.33 to 4.17 mi/kWh, and the Nissan Leaf was 2.94 to 3.45 mi/kWh.\nTherefore, even bargain standard Model 3s will achieve greater road efficiency than the best Leaf.\nHowever, the EPA ratings weren’t what was measured when real-world driving conditions were considered.\nOver the four-month timeframe, Recurrent revealed the median observed efficiency for each vehicle as the Tesla Model 3 having 3.39 mi/kWh and the Nissan Leaf having 3.71 mi/kWh.",
        "title": "Is the Nissan Leaf More Efficient Than the Tesla Model 3? Here's What 1 Study Found",
        "url": "https://www.motorbiscuit.com/nissan-leaf-more-efficient-tesla-model-3-what-study-found/",
        "date": "2022-08-11",
        "last_updated": "2025-06-25"
      },
      {
        "snippet": "Compare USA EV efficiency by kWh/100 mi and MPGe, with EPA and charging metrics across all models and trims.\nUpdated monthly (2026).",
        "title": "Most Efficient EVs in the USA (kWh/100 mi) - BEV Database",
        "url": "https://bev-database.com/cars-list-usa/most-efficient-electric-cars",
        "date": "2026-02-28",
        "last_updated": "2026-02-28"
      },
      {
        "snippet": ",\nModel Year 2022 EVs Achieving EPA Combined Rating of 100 MPGe or more,\nMake and Model,Highest MPGe For Base Model\nTesla Model 3,132\nLucid Air,131\nTesla Model Y,129\nChevrolet Bolt EV,120\nHyundai Kona Electric,120\nTesla Model S,120\nKia EV6,117\nChevrolet Bolt EUV,115\nHyundai Ioniq 5,114\nKia Niro Electric,112\nNissan Leaf,111\nMINI Cooper SE,110\nBMW i4 Gran Coupe,109\nPolestar 2,107\nVolkswagen ID.4,107\nFord Mustang Mach-E,103\nTesla Model X,102\n,\n...\nEVs include only all-electric vehicles.,\n...\nOnly the base model names are shown and only the highest MPGe values are shown for each model name.\nSome models listed have configurations that fall below 100 MPGe.,\n...\n,\n\"Source: U.S. Department of Energy and U.S. Environmental Protection Agency’s Fuel Economy Website, Compare Electric Vehicles Side-by-Side.\nData accessed August 24, 2022.\",\n,\n,\nhttps://www.fueleconomy.gov/feg/evSelect.jsp,",
        "title": "FOTW_1257_web.xlsx",
        "url": "https://www.energy.gov/sites/default/files/2022-09/FOTW_1257_web.xlsx",
        "date": null,
        "last_updated": "2025-03-28"
      },
      {
        "snippet": ",\nModel Year 2022 EVs Achieving EPA Combined Rating of 100 MPGe or more,\nMake and Model,Highest MPGe For Base Model\nTesla Model 3,132\nLucid Air,131\nTesla Model Y,129\nChevrolet Bolt EV,120\nHyundai Kona Electric,120\nTesla Model S,120\nKia EV6,117\nChevrolet Bolt EUV,115\nHyundai Ioniq 5,114\nKia Niro Electric,112\nNissan Leaf,111\nMINI Cooper SE,110\nBMW i4 Gran Coupe,109\nPolestar 2,107\nVolkswagen ID.4,107\nFord Mustang Mach-E,103\nTesla Model X,102\n,\n...\nEVs include only all-electric vehicles.,\n...\nOnly the base model names are shown and only the highest MPGe values are shown for each model name.\nSome models listed have configurations that fall below 100 MPGe.,\n...\n,\n\"Source: U.S. Department of Energy and U.S. Environmental Protection Agency’s Fuel Economy Website, Compare Electric Vehicles Side-by-Side.\nData accessed August 24, 2022.\",\n,\n,\nhttps://www.fueleconomy.gov/feg/evSelect.jsp,",
        "title": "[XLS] FOTW #1257 - Energy.gov",
        "url": "https://www.energy.gov/documents/fotw1257webxlsx",
        "date": null,
        "last_updated": "2026-03-05"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

### Manual Override

You can still manually specify the search type when you know what you need:

<Tabs>
  <Tab title="Force Pro Search">
    Use when you know you need multi-step tool usage:

    ```python theme={null}
    response = client.chat.completions.create(
        model="sonar-pro",
        messages=[{"role": "user", "content": "Your complex query"}],
        stream=True,
        web_search_options={
            "search_type": "pro"  # Force Pro Search
        }
    )
    ```

    **Use cases for manual Pro:**

    * You know the query needs multi-step reasoning
    * Previous auto-classification was Fast but you need deeper analysis
    * Critical queries where you want maximum capability
  </Tab>

  <Tab title="Force Fast Search">
    Use when you want to optimize for speed and cost:

    ```python theme={null}
    response = client.chat.completions.create(
        model="sonar-pro",
        messages=[{"role": "user", "content": "Your simple query"}],
        stream=True,
        web_search_options={
            "search_type": "fast"  # Force Fast Search (or omit - fast is default)
        }
    )
    ```

    **Use cases for manual Fast:**

    * Simple queries where Pro Search would be overkill
    * Cost-sensitive applications
    * When response speed is critical
  </Tab>
</Tabs>

## Best Practices

<Steps>
  <Step title="Default to automatic classification">
    For most applications, use `search_type: "auto"` and let the classifier optimize:

    ```python theme={null}
    web_search_options={"search_type": "auto"}
    ```

    This ensures the right tool for each query while optimizing costs.
  </Step>

  <Step title="Monitor classification patterns">
    Track which queries get classified as Pro vs Fast to understand your usage patterns:

    * Review queries that consistently use Pro Search
    * Identify opportunities to rephrase queries for Fast Search when appropriate
    * Understand which user questions require advanced capabilities

    This helps optimize your application's query design.
  </Step>

  <Step title="Use manual override strategically">
    Override the classifier only when:

    * You have specific performance requirements
    * Testing and comparing Pro vs Fast results
    * Building features with known complexity levels

    **Example:**

    ```python theme={null}
    # Known complex analysis - force Pro
    if query_requires_calculations(user_query):
        search_type = "pro"
    else:
        search_type = "auto"
    ```
  </Step>

  <Step title="Design queries effectively">
    Structure queries to help the classifier make optimal decisions:

    **Less optimal:**
    "Tell me about electric cars"

    **Better:**
    "What is the average range of electric vehicles?" (Fast Search appropriate)

    **Or:**
    "Compare the total cost of ownership over 5 years for Tesla Model 3, Chevrolet Bolt, and Nissan Leaf, including depreciation, electricity costs, and maintenance" (Pro Search appropriate)

    Clear, specific queries enable better classification.
  </Step>
</Steps>

## Classification Transparency

You can verify the classification decision in the response metadata:

```json theme={null}
{
  "id": "12345",
  "model": "sonar-pro",
  "search_metadata": {
    "search_type_used": "pro",  // or "fast"
    "classification_reason": "Multi-part comparative analysis with calculations"
  },
  "usage": {
    "prompt_tokens": 25,
    "completion_tokens": 150,
    "total_tokens": 175
  }
}
```

<Info>
  This transparency helps you understand why queries were classified a certain way and optimize future queries.
</Info>

## When to Use Each Mode

<CardGroup>
  <Card title="Auto (Recommended)" icon="wand">
    **Best for:** Most applications

    Let the classifier optimize for you. Balances cost and capability automatically based on query complexity.
  </Card>

  <Card title="Manual Pro" icon="brain">
    **Best for:** Known complex tasks

    Use when you're certain multi-step tool usage is needed: calculations, multi-source synthesis, deep analysis.
  </Card>

  <Card title="Manual Fast" icon="bolt">
    **Best for:** Simple retrieval

    Use for straightforward facts, definitions, or when optimizing for speed and cost with simple queries.
  </Card>
</CardGroup>

## Common Questions

<AccordionGroup>
  <Accordion title="How accurate is the classifier?">
    The classifier is highly accurate, trained on thousands of query patterns. It errs on the side of using Pro Search when there's any ambiguity, ensuring you don't lose capability.

    However, if you notice consistent mis-classifications:

    * Rephrase queries to be more specific
    * Use manual override for those query types
    * Consider your use case's specific needs
  </Accordion>

  <Accordion title="Can I see which mode was used?">
    Yes, the response includes metadata showing:

    * Which search type was used
    * Why the classification was made (when using auto)
    * Cost breakdown by search type

    This helps you understand and optimize your usage patterns.
  </Accordion>

  <Accordion title="Does automatic classification add latency?">
    No. Classification happens in milliseconds before query processing begins and does not meaningfully impact response time. The classifier is optimized for real-time decision making.
  </Accordion>

  <Accordion title="What if I disagree with the classification?">
    You can always use manual override:

    ```python theme={null}
    web_search_options={"search_type": "pro"}  # Force your preference
    ```

    If you consistently disagree with classifications, consider:

    * Making queries more specific
    * Using manual override for those query types
    * Reviewing whether your use case needs consistent Pro or Fast mode
  </Accordion>
</AccordionGroup>

## Related Resources

<CardGroup>
  <Card title="Quickstart" icon="rocket" href="/docs/sonar/pro-search/quickstart">
    Get started with Pro Search basics
  </Card>

  <Card title="Built-in Tool Capabilities" icon="tool" href="/docs/sonar/pro-search/tools">
    Learn about Pro Search's built-in tools and capabilities
  </Card>

  <Card title="Pricing Guide" icon="currency-dollar" href="/docs/getting-started/pricing">
    Understand pricing for Pro and Fast Search
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/sonar-post">
    Complete API documentation
  </Card>
</CardGroup>


# Quickstart
Source: https://docs.perplexity.ai/docs/sonar/pro-search/quickstart

Get started with Pro Search for Sonar Pro - enhanced search with automated tools, multi-step reasoning, and real-time thought streaming

<SonarDeprecationNotice />

## Overview

Pro Search enhances [Sonar Pro](/docs/sonar/models/sonar-pro) with automated tool usage, enabling multi-step reasoning through intelligent tool orchestration including web search and URL content fetching.

<Warning>
  Pro Search only works when streaming is enabled. Non-streaming requests will fall back to standard Sonar Pro behavior.
</Warning>

<div>
  <div>
    <h3>Standard Sonar Pro</h3>

    <ul>
      <li>Single web search execution</li>
      <li>Fast response synthesis</li>
      <li>Fixed search strategy</li>
      <li>Static result processing</li>
    </ul>
  </div>

  <div>
    <h3>Pro Search for Sonar Pro</h3>

    <ul>
      <li>Multi-step reasoning with automated tools</li>
      <li>Dynamic tool execution</li>
      <li>Real-time thought streaming</li>
      <li>Adaptive research strategies</li>
    </ul>
  </div>
</div>

## Basic Usage

Enabling Pro Search requires setting `stream` to `true` and specifying `"search_type": "pro"` in your API request. The default search type is `"fast"` for regular Sonar Pro.

Here is an example of how to enable Pro Search with streaming:

<CodeGroup>
  ```python Python SDK theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  messages = [
      {
          "role": "user", 
          "content": "Summarize developments in post-quantum cryptography and how lattice-based and hash-based schemes are being standardized by NIST."
      }
  ]

  response = client.chat.completions.create(
      model="sonar-pro",
      messages=messages,
      stream=True,
      web_search_options={
          "search_type": "pro"
      }
  )

  for chunk in response:
      if chunk.choices[0].delta.content:
          print(chunk.choices[0].delta.content, end="")
  ```

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

  const client = new Perplexity();

  const response = await client.chat.completions.create({
    model: 'sonar-pro',
    messages: [
      {
        role: 'user',
        content: 'Summarize developments in post-quantum cryptography and how lattice-based and hash-based schemes are being standardized by NIST.'
      }
    ],
    stream: true,
    web_search_options: {
      search_type: 'pro'
    }
  });

  for await (const chunk of response) {
    if (chunk.choices[0]?.delta?.content) {
      process.stdout.write((chunk.choices[0]?.delta?.content ?? '') as string);
    }
  }
  ```

  ```bash cURL theme={null}
  curl --request POST \
    --url https://api.perplexity.ai/v1/sonar \
    --header "Authorization: Bearer $PERPLEXITY_API_KEY" \
    --header "Content-Type: application/json" \
    --data '{
      "model": "sonar-pro",
      "messages": [
        {
          "role": "user",
          "content": "Summarize developments in post-quantum cryptography and how lattice-based and hash-based schemes are being standardized by NIST."
        }
      ],
      "stream": true,
      "web_search_options": {
        "search_type": "pro"
      }
    }' --no-buffer
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "8326e168-7408-4978-853c-468a2500f757",
    "results": [
      {
        "snippet": "NIST’s Post-Quantum Cryptography (PQC) project leads the national and global effort to secure electronic information against the future threat of quantum computers—machines that may be years or decades away but could eventually break many of today’s widely used cryptographic systems.\nThrough a multi-year international competition involving industry, academia, and governments, NIST released the principal three PQC standards in 2024 and is developing additional standards to serve as backups or alternatives.\nOrganizations should begin applying these standards now to migrate their systems to quantum-resistant cryptography.\n...\n#### PQC Standards SIn August 2024, NIST released its principal PQC standards (as Federal Information Processing Standards, or FIPS), specifying key establishment and digital signature schemes based on candidates evaluated and selected through this multi-year process.\n##### FIPS 203# Module-Lattice-Based\nKey-Encapsulation Mechanism Standard\n(ML-KEM)\n##### FIPS 204# Module-Lattice-Based\nDigital Signature Standard\n(ML-DSA)\n##### FIPS 205# Stateless Hash-Based\nDigital Signature Standard\n(SLH-DSA)\n#### Migration to PQCioWith the release of the first three final PQC standards, organizations should begin migrating their systems to quantum-resistant cryptography.\n...\nUnder the transition timeline in NIST IR 8547, NIST will deprecate and ultimately remove quantum-vulnerable algorithms from its standards by 2035, with high-risk systems transitioning much earlier.\n...\n#### Ongoing PQC Standardization ProcessonNIST expects that the two digital signature standards (ML-DSA and SLH-DSA) and key-encapsulation mechanism standard (ML-KEM) will provide the foundation for most deployments of post-quantum cryptography.\n***They can and should be put into use now.** *\nNIST continues to evaluate the security and performance of innovative algorithms in order to identify additional candidates for standardization.\nIn addition to the three algorithms specified in the initial FIPS standards, the Falcon digital signature algorithm and HQC key encapsulation mechanism were selected for ongoing standardization; that process is underway.\nThis process continues with a longer-term effort that solicited additional algorithms for digital signature schemes that could serve as a backup to ML-DSA or that could address unique use cases.",
        "title": "Post-Quantum Cryptography | CSRC",
        "url": "https://csrc.nist.gov/projects/post-quantum-cryptography",
        "date": "2017-01-03",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "**Post-Quantum Cryptography Standardization** is a program and competition by NIST to update their standards to include post-quantum cryptography.\nIt was announced at PQCrypto 2016.\nTwenty-three signature schemes and fifty-nine encryption/KEM schemes were submitted by the initial submission deadline at the end of 2017 of which sixty-nine total were deemed complete and proper and participated in the first round.\nSeven of these, of which three are signature schemes, advanced to the third round, which was announced in July 2020.\nOn August 13, 2024, NIST released final versions of the first three Post Quantum Crypto Standards: FIPS 203, FIPS 204, and FIPS 205.\n...\nAcademic research on the potential impact of quantum computing dates back to at least 2001.\nA NIST published report from April 2016 cites experts that acknowledge the possibility of quantum technology to render the commonly used RSA algorithm insecure by 2030.\nAs a result, a need to standardize quantum-secure cryptographic primitives was pursued.\nSince most symmetric primitives are relatively easy to modify in a way that makes them quantum resistant, efforts have focused on public-key cryptography, namely digital signatures and key encapsulation mechanisms.\nIn December 2016 NIST initiated a standardization process by announcing a call for proposals.\n...\n|Hash-based| |- Gravity-SPHINCS - SPHINCS+| |\n...\nOn July 22, 2020, NIST announced seven finalists (\"first track\"), as well as eight alternate algorithms (\"second track\").\nThe first track contains the algorithms which appear to have the most promise, and will be considered for standardization at the end of the third round.\n...\nOn August 13, 2024, NIST released final versions of its first three Post Quantum Crypto Standards.\nAccording to the release announcement:\n> While there have been no substantive changes made to the standards since the draft versions, NIST has changed the algorithms’ names to specify the versions that appear in the three finalized standards, which are:\n>\n- Federal Information Processing Standard (FIPS) 203, intended as the primary standard for general encryption.\nAmong its advantages are comparatively small encryption keys that two parties can exchange easily, as well as its speed of operation.\nThe standard is based on the CRYSTALS-Kyber algorithm, which has been renamed ML-KEM, short for Module-Lattice-Based Key-Encapsulation Mechanism.\n> - FIPS 204, intended as the primary standard for protecting digital signatures.\nThe standard uses the CRYSTALS-Dilithium algorithm, which has been renamed ML-DSA, short for Module-Lattice-Based Digital Signature Algorithm.\n> - FIPS 205, also designed for digital signatures.\nThe standard employs the SPHINCS+ algorithm, which has been renamed SLH-DSA, short for Stateless Hash-Based Digital Signature Algorithm.\nThe standard is based on a different math approach than ML-DSA, and it is intended as a backup method in case ML-DSA proves vulnerable.\n> - Similarly, when the draft FIPS 206 standard built around FALCON is released, the algorithm will be dubbed FN-DSA, short for FFT (fast-Fourier transform) over NTRU-Lattice-Based Digital Signature Algorithm.\nOn March 11, 2025 NIST released Hamming Quasi-Cyclic (HQC) as the fifth algorithm for post-quantum asymmetric encryption as used for key encapsulation / exchange.\nThe new algorithm is as a backup for ML-KEM, the main algorithm for general encryption.\nHQC is a code-based scheme using different math than ML-KEM, thus mitigating possible weaknesses should any be found in the lattice-based ML-KEM.\nThe draft standard incorporating the HQC algorithm is expected in early 2026 with the final in 2027.",
        "title": "NIST Post-Quantum Cryptography Standardization - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/NIST_Post-Quantum_Cryptography_Standardization",
        "date": "2017-12-29",
        "last_updated": "2026-03-31"
      },
      {
        "snippet": "- NIST has released a final set of encryption tools designed to withstand the attack of a quantum computer.\n- These post-quantum encryption standards secure a wide range of electronic information, from confidential email messages to e-commerce transactions that propel the modern economy.\n- NIST is encouraging computer system administrators to begin transitioning to the new standards as soon as possible.\nGAITHERSBURG, Md.\n— The U.S. Department of Commerce’s National Institute of Standards and Technology (NIST) has finalized its principal set of encryption algorithms designed to withstand cyberattacks from a quantum computer.\n...\nThe algorithms announced today are specified in the first completed standards from NIST’s post-quantum cryptography (PQC) standardization project, and are ready for immediate use.\n...\nThe standards — containing the encryption algorithms’ computer code, instructions for how to implement them, and their intended uses — are the result of an eight-year effort managed by NIST, which has a long history of developing encryption.\nThe agency has rallied the world’s cryptography experts to conceive, submit and then evaluate cryptographic algorithms that could resist the assault of quantum computers.\n...\nThe algorithms NIST has standardized are based on different math problems that would stymie both conventional and quantum computers.\n“These finalized standards include instructions for incorporating them into products and encryption systems,” said NIST mathematician Dustin Moody, who heads the PQC standardization project.\n...\nMoody said that these standards are the primary tools for general encryption and protecting digital signatures.\nNIST also continues to evaluate two other sets of algorithms that could one day serve as backup standards.\nOne of these sets consists of three algorithms designed for general encryption but based on a different type of math problem than the general-purpose algorithm in the finalized standards.\nNIST plans to announce its selection of one or two of these algorithms by the end of 2024.\nThe second set includes a larger group of algorithms designed for digital signatures.\nIn order to accommodate any ideas that cryptographers may have had since the initial 2016 call for submissions, NIST asked the public for additional algorithms in 2022 and has begun a process of evaluating them.\nIn the near future, NIST expects to announce about 15 algorithms from this group that will proceed to the next round of testing, evaluation and analysis.\nWhile analysis of these two additional sets of algorithms will continue, Moody said that any subsequent PQC standards will function as backups to the three that NIST announced today.\n...\nThe new standards are designed for two essential tasks for which encryption is typically used: general encryption, used to protect information exchanged across a public network; and digital signatures, used for identity authentication.\nNIST announced its selection of four algorithms — CRYSTALS-Kyber, CRYSTALS-Dilithium, Sphincs+ and FALCON — slated for standardization in 2022 and released draft versions of three of these standards in 2023.\nThe fourth draft standard based on FALCON is planned for late 2024.\nWhile there have been no substantive changes made to the standards since the draft versions, NIST has changed the algorithms’ names to specify the versions that appear in the three finalized standards, which are:\n- **Federal Information Processing Standard (FIPS) 203**, intended as the primary standard for general encryption.\nAmong its advantages are comparatively small encryption keys that two parties can exchange easily, as well as its speed of operation.\nThe standard is based on the CRYSTALS-Kyber algorithm, which has been renamed ML-KEM, short for Module-Lattice-Based Key-Encapsulation Mechanism.\n- **FIPS 204**, intended as the primary standard for protecting digital signatures.\nThe standard uses the CRYSTALS-Dilithium algorithm, which has been renamed ML-DSA, short for Module-Lattice-Based Digital Signature Algorithm.\n- **FIPS 205**, also designed for digital signatures.\nThe standard employs the Sphincs+ algorithm, which has been renamed SLH-DSA, short for Stateless Hash-Based Digital Signature Algorithm.\nThe standard is based on a different math approach than ML-DSA, and it is intended as a backup method in case ML-DSA proves vulnerable.\nSimilarly, when the draft FIPS 206 standard built around FALCON is released, the algorithm will be dubbed FN-DSA, short for FFT (fast-Fourier transform) over NTRU-Lattice-Based Digital Signature Algorithm.",
        "title": "NIST Releases First 3 Finalized Post-Quantum Encryption Standards",
        "url": "https://www.nist.gov/news-events/news/2024/08/nist-releases-first-3-finalized-post-quantum-encryption-standards",
        "date": "2024-08-13",
        "last_updated": "2026-05-14"
      },
      {
        "snippet": "**FIPS 203, FIPS 204,** and** FIPS 205**, which specify algorithms derived from **CRYSTALS-Dilithium, CRYSTALS-KYBER**, and **SPHINCS^+^,** were published August 13, 2024.\n**FALCON** was also selected and will be published in **FIPS 206 (in development)**.\nSee NIST IR 8413, Status Report of the Third Round of the NIST Post-Quantum Cryptography Standardization Process.\n**HQC** was selected for standardization on March 11, 2025.\nSee NIST IR 8545, Status Report on the Fourth Round of the NIST Post-Quantum Cryptography Standardization Process.",
        "title": "PQC Standardization Process - Post-Quantum Cryptography | CSRC",
        "url": "https://csrc.nist.gov/projects/post-quantum-cryptography/post-quantum-cryptography-standardization",
        "date": "2017-01-03",
        "last_updated": "2026-05-22"
      },
      {
        "snippet": "- Three NIST standards that were developed through a rigorous, international process are ready to be implemented now.\nAs researchers around the world race to build quantum computers that could break the current encryption providing security and privacy for our digital lives, NIST is helping to secure our future by developing algorithms to protect our data and systems.\nNIST has already released three post-quantum cryptography standards that can be implemented now to secure a wide range of electronic information, from confidential email messages to e-commerce transactions that propel the modern economy.\nNIST continues to evaluate additional algorithms that could one day serve as backup standards.\nThese Federal Information Processing Standards (FIPS), which are mandatory for federal systems and adopted by organizations around the world, provide detailed descriptions of post-quantum encryption and digital signature algorithms so they can be implemented consistently to facilitate secure and interoperable communication.\nThey were developed through an eight-year effort managed by NIST, which has a long history of developing cryptography standards.\n...\nThe new algorithm will serve as a backup for the general encryption needed to protect data from quantum computers developed in the future.\n...\nThree new algorithms are expected to be ready for use in 2024.\nOthers will follow.",
        "title": "Post-quantum cryptography | NIST",
        "url": "https://www.nist.gov/pqc",
        "date": "2025-12-03",
        "last_updated": "2026-05-20"
      },
      {
        "snippet": "",
        "title": "Post-Quantum Cryptography and Quantum-Safe Security - arXiv",
        "url": "https://arxiv.org/html/2510.10436v1",
        "date": "2025-10-11",
        "last_updated": "2026-03-24"
      },
      {
        "snippet": "**Post-Quantum Cryptography Standardization** is a program and competition by NIST to update their standards to include post-quantum cryptography.\nIt was announced at PQCrypto 2016.\n23 signature schemes and 59 encryption/KEM schemes were submitted by the initial submission deadline at the end of 2017 of which 69 total were deemed complete and proper and participated in the first round.\nSeven of these, of which 3 are signature schemes, have advanced to the third round, which was announced on July 22, 2020.\nOn August 13, 2024, NIST released final versions of the first three Post Quantum Crypto Standards: FIPS 203, FIPS 204, and FIPS 205.\n...\nAcademic research on the potential impact of quantum computing dates back to at least 2001.\nA NIST published report from April 2016 cites experts that acknowledge the possibility of quantum technology to render the commonly used RSA algorithm insecure by 2030.\nAs a result, a need to standardize quantum-secure cryptographic primitives was pursued.\nSince most symmetric primitives are relatively easy to modify in a way that makes them quantum resistant, efforts have focused on public-key cryptography, namely digital signatures and key encapsulation mechanisms.\nIn December 2016 NIST initiated a standardization process by announcing a call for proposals.\nThe competition is now in its third round out of expected four, where in each round some algorithms are discarded and others are studied more closely.\nNIST hopes to publish the standardization documents by 2024, but may speed up the process if major breakthroughs in quantum computing are made.\nIt is currently undecided whether the future standards will be published as FIPS or as NIST Special Publication (SP).\n...\nOn July 22, 2020, NIST announced seven finalists (\"first track\"), as well as eight alternate algorithms (\"second track\").\nThe first track contains the algorithms which appear to have the most promise, and will be considered for standardization at the end of the third round.\nAlgorithms in the second track could still become part of the standard, after the third round ends.\nNIST expects some of the alternate candidates to be considered in a fourth round.\nNIST also suggests it may re-open the signature category for new schemes proposals in the future.\n...\nOn July 5, 2022, NIST announced the first group of winners from its six-year competition.\n...\nOn August 13, 2024, NIST released final versions of its first three Post Quantum Crypto Standards.\nAccording to the release announcement:\nWhile there have been no substantive changes made to the standards since the draft versions, NIST has changed the algorithms’ names to specify the versions that appear in the three finalized standards, which are:\n- Federal Information Processing Standard (FIPS) 203, intended as the primary standard for general encryption.\nAmong its advantages are comparatively small encryption keys that two parties can exchange easily, as well as its speed of operation.\nThe standard is based on the CRYSTALS-Kyber algorithm, which has been renamed ML-KEM, short for Module-Lattice-Based Key-Encapsulation Mechanism.\n- FIPS 204, intended as the primary standard for protecting digital signatures.\nThe standard uses the CRYSTALS-Dilithium algorithm, which has been renamed ML-DSA, short for Module-Lattice-Based Digital Signature Algorithm.\n- FIPS 205, also designed for digital signatures.\nThe standard employs the Sphincs+ algorithm, which has been renamed SLH-DSA, short for Stateless Hash-Based Digital Signature Algorithm.\nThe standard is based on a different math approach than ML-DSA, and it is intended as a backup method in case ML-DSA proves vulnerable.\n- Similarly, when the draft FIPS 206 standard built around FALCON is released, the algorithm will be dubbed FN-DSA, short for FFT (fast-Fourier transform) over NTRU-Lattice-Based Digital Signature Algorithm.\nOn March 11, 2025 NIST released HQC as the fifth algorithm for post-quantum asymmetric encryption as used for key encapsulation / exchange.\nThe new algorithm is as a backup for ML-KEM, the main algorithm for general encryption.\nHQC is based on different math than ML-KEM, thus mitigating weakness if found.\nThe draft standard incorporating the HQC algorithm is expected in early 2026 with the final in 2027.",
        "title": "NIST Post-Quantum Cryptography Standardization - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Post-Quantum_Cryptography_Standardization",
        "date": "2025-03-19",
        "last_updated": "2025-03-26"
      },
      {
        "snippet": "NIST is leading a global effort to create electronic defenses against such attacks through its Post-Quantum Cryptography (PQC) project, which released * *the first three finalized PQC standards* * in 2024.\n...\nTo counter this looming threat, we need encryption methods that can stave off cyberattacks by both the conventional computers we know today and the quantum computers of tomorrow.\nThese new methods are called post-quantum encryption algorithms.\n...\nTo stave off attacks by a quantum computer — if and when a cryptographically relevant one is built — the worldwide community must retire current encryption algorithms.\nPost-quantum encryption algorithms must be based on math problems that would be difficult for both conventional and quantum computers to solve.\nThe algorithms are designed for two main tasks for which encryption is typically used: general encryption, used to protect information such as passwords exchanged across a public network, and digital signatures, used for identity authentication.\nOf the four algorithms NIST has selected as the initial ones to be standardized, three are based on a family of math problems called structured lattices, while the fourth uses mathematical relationships known as hash functions.\nInstead of requiring a computer to factor large numbers, lattice and hash problems use other types of math that experts believe will be hard to solve for quantum computers and conventional computers alike.\nAdditional algorithms still under consideration are designed for general encryption and do not use structured lattices or hash functions in their approaches.\nTo put these algorithms into practice, NIST has led efforts to develop technical standards for post-quantum encryption.\nThese standards aim to provide solutions for different situations, employ varied approaches for encryption, and offer more than one algorithm for each kind of application in the event one proves vulnerable.\n...\nNIST kicked off the Post-Quantum Cryptography project in 2016 and late that year formally asked the world’s cryptography experts to submit algorithms that would prove intractable to both classical and quantum computers.\n...\nWe now have post-quantum encryption algorithms that are ready for use.\nNIST released the first three finalized PQC standards that incorporate them in 2024.",
        "title": "What Is Post-Quantum Cryptography? | NIST",
        "url": "https://www.nist.gov/cybersecurity-and-privacy/what-post-quantum-cryptography",
        "date": "2024-08-13",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "",
        "title": "Post-Quantum Cryptography (PQC) Standardization - 2025 Update",
        "url": "https://postquantum.com/post-quantum/cryptography-pqc-nist/",
        "date": "2025-09-24",
        "last_updated": "2026-05-25"
      },
      {
        "snippet": "",
        "title": "Post-quantum cryptography - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Post-quantum_cryptography",
        "date": "2010-03-18",
        "last_updated": "2026-05-06"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

## Enabling Automatic Classification

Sonar Pro can be configured to automatically classify queries into Pro Search or Fast Search based on complexity. This is the recommended approach for most applications.

Set `search_type: "auto"` to let the system intelligently route queries based on complexity.

<CodeGroup>
  ```python Python SDK theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  response = client.chat.completions.create(
      model="sonar-pro",
      messages=[
          {
              "role": "user",
              "content": "Compare the energy efficiency (kWh/100mi and MPGe) of the Tesla Model 3, Chevrolet Bolt, and Nissan Leaf using EPA data."
          }
      ],
      stream=True,
      web_search_options={
          "search_type": "auto"  # Automatic classification
      }
  )

  for chunk in response:
      if chunk.choices[0].delta.content:
          print(chunk.choices[0].delta.content, end="")
  ```

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

  const client = new Perplexity();

  const response = await client.chat.completions.create({
    model: 'sonar-pro',
    messages: [
      {
        role: 'user',
        content: 'Compare the energy efficiency (kWh/100mi and MPGe) of the Tesla Model 3, Chevrolet Bolt, and Nissan Leaf using EPA data.'
      }
    ],
    stream: true,
    web_search_options: {
      search_type: 'auto'  // Automatic classification
    }
  });

  for await (const chunk of response) {
    if (chunk.choices[0]?.delta?.content) {
      process.stdout.write((chunk.choices[0]?.delta?.content ?? '') as string);
    }
  }
  ```

  ```bash cURL theme={null}
  curl --request POST \
    --url https://api.perplexity.ai/v1/sonar \
    --header "Authorization: Bearer $PERPLEXITY_API_KEY" \
    --header "Content-Type: application/json" \
    --data '{
      "model": "sonar-pro",
      "messages": [
        {
          "role": "user",
          "content": "Compare the energy efficiency (kWh/100mi and MPGe) of the Tesla Model 3, Chevrolet Bolt, and Nissan Leaf using EPA data."
        }
      ],
      "stream": true,
      "web_search_options": {
        "search_type": "auto"
      }
    }' --no-buffer
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "cab71ad3-867d-4139-997e-c36ce805351b",
    "results": [
      {
        "snippet": "The following table compares official EPA ratings for fuel economy (in miles per gallon gasoline equivalent, mpg-e or MPGe, for plug-in electric vehicles) for series production all-electric passenger vehicles rated by the EPA for model years 2015, 2016, 2017, and 2023 versus the model year\n2016 vehicles that were rated the most efficient by the EPA with plug-in hybrid drivetrains (Chevrolet Volt – second generation), gasoline-electric hybrid drivetrains (Toyota Prius Eco - fourth generation), and the average new vehicle for that model year, which has a fuel economy of 25 mpg~‑US~ (9.4 L/100 km; 30 mpg~‑imp~).\nEPA rating data are taken from manufacturer testing of their own vehicles using a series of tests specified by federal law.\n...\nReal-world EV efficiency can also be expressed in miles per kilowatt-hour (mi/kWh), which converts EPA MPGe values into direct electrical energy consumption, allowing cross-comparison between electric and gasoline vehicles.\n...\n|Vehicle|Model year|EPA rated fuel economy|EPA rated fuel economy|EPA rated fuel economy|Notes| | |\n...\n|Toyota Prius HEV|2023|57 mpg|57 mpg|56 mpg|(9)| | |\n|Hyundai Ioniq 6 Long Range RWD w/ 18-inch wheels|2023|140 mpg‑e 24.1 kWh/100 mi; 15.0 kWh/100 km|153 mpg‑e 22.0 kWh/100 mi; 13.7 kWh/100 km|127 mpg‑e 26.5 kWh/100 mi; 16.5 kWh/100 km|(1)| | |\n...\n|Tesla Model Y AWD|2023|123 mpg‑e 27.4 kWh/100 mi; 17.0 kWh/100 km|129 mpg‑e 26.1 kWh/100 mi; 16.2 kWh/100 km|116 mpg‑e 29.1 kWh/100 mi; 18.1 kWh/100 km|(1)| | |\n|Tesla Model 3 Standard Range|2020|141 mpg‑e 23.9 kWh/100 mi; 14.9 kWh/100 km|148 mpg‑e 22.8 kWh/100 mi; 14.2 kWh/100 km|132 mpg‑e 25.5 kWh/100 mi; 15.9 kWh/100 km|(1)| | |\n...\n|Tesla Model 3 Long Range AWD|2020|121 mpg‑e 27.9 kWh/100 mi; 17.3 kWh/100 km|124 mpg‑e 27.2 kWh/100 mi; 16.9 kWh/100 km|116 mpg‑e 29.1 kWh/100 mi; 18.1 kWh/100 km|(1)| | |\n|Chevrolet Bolt EV|2017|119 mpg‑e 28.3 kWh/100 mi; 17.6 kWh/100 km|121 mpg‑e 27.9 kWh/100 mi; 17.3 kWh/100 km|110 mpg‑e 30.6 kWh/100 mi; 19.0 kWh/100 km| | | |\n...\n|Nissan Leaf (24 kW-h)|2013/14/15/16|114 mpg‑e 29.6 kWh/100 mi; 18.4 kWh/100 km|126 mpg‑e 26.8 kWh/100 mi; 16.6 kWh/100 km|101 mpg‑e 33.4 kWh/100 mi; 20.7 kWh/100 km|(1) (6)| | |\n...\n|Nissan Leaf (30 kW-h)|2016|112 mpg‑e 30.1 kWh/100 mi; 18.7 kWh/100 km|124 mpg‑e 27.2 kWh/100 mi; 16.9 kWh/100 km|101 mpg‑e 33.4 kWh/100 mi; 20.7 kWh/100 km|(1)| | |",
        "title": "Electric car EPA fuel economy - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Electric_car_EPA_fuel_economy",
        "date": "2015-04-30",
        "last_updated": "2026-05-05"
      },
      {
        "snippet": "Instead of focusing on battery size or total range, we look at **energy consumption (kWh per 100 miles)** and **MPGe**, the EPA’s miles-per-gallon equivalent metric.\n...\n**Methodology**: Recurrent's Most Efficient EVs of 2026 were determined based on combined efficiency in kWh/100miles as reported to the EPA.\n...\n## 3.\nTesla Model 3\n**Efficiency:** 25 kWh/100 miles\n**MPGe:** 134.8\n**Body style:** Compact sedan\n...\n## 5.\nTesla Model Y\n**Efficiency:** 26 kWh/100 miles\n**MPGe:** 129.6\n**Body style:** Compact crossover SUV\n...\n## 6.\nNissan LEAF\n**Efficiency:** 28 kWh/100 miles\n**MPGe:** 120.4\n**Body style:** Compact crossover (redesigned)",
        "title": "2026 Most Efficient EV by Size According to Testing - Recurrent",
        "url": "https://www.recurrentauto.com/research/most-efficient-ev",
        "date": "2026-03-02",
        "last_updated": "2026-05-27"
      },
      {
        "snippet": "|EPA MPG MPGe:Miles per Gallon Equivalent 1 gallon of gasoline=33.7 kWh About All-Electric Cars|Electricity Combined MPG:111 MPGe City MPG:123 Highway MPG:99 30 kWh/100 miles|",
        "title": "Find and Compare Cars",
        "url": "https://www.fueleconomy.gov/feg/noframes/48400.shtml",
        "date": "2023-01-01",
        "last_updated": "2024-10-03"
      },
      {
        "snippet": "MPGe is a unit of measure used by the Environmental Protection Agency (EPA) to represent EV fuel economy in a common unit with gas-powered vehicles, where 33.7 kilowatt-hours of electricity are equal to the energy contained in one gallon of gasoline.\nAmong those 17 models, there were a total of 37 unique configurations that achieved 100 MPGe or higher.\nThe Tesla Model 3 in rear-wheel drive configuration achieved the highest rating for MY 2022 with 132 MPGe.\n||\n|--|\n|||\n|Tesla Model 3|132|\n|Lucid Air|131|\n|Tesla Model Y|129|\n|Chevrolet Bolt EV|120|\n|Hyundai Kona Electric|120|\n|Tesla Model S|120|\n|Kia EV6|117|\n|Chevrolet Bolt EUV|115|\n|Hyundai Ioniq 5|114|\n|Kia Niro Electric|112|\n|Nissan Leaf|111|\n|MINI Cooper SE|110|\n|BMW i4 Gran Coupe|109|\n|Polestar 2|107|\n|Volkswagen ID.4|107|\n|Ford Mustang Mach-E|103|\n|Tesla Model X|102|\n...\n**Source: **U.S. Department of Energy and U.S. Environmental Protection Agency’s Fuel Economy Website, Compare Electric Vehicles Side-by-Side.\nData accessed August 24, 2022.",
        "title": "FOTW #1257, September 26, 2022: Seventeen EV Models Achieved ...",
        "url": "https://www.energy.gov/eere/vehicles/articles/fotw-1257-september-26-2022-seventeen-ev-models-achieved-epa-combined-rating",
        "date": "2022-09-26",
        "last_updated": "2025-10-09"
      },
      {
        "snippet": "Nevertheless, the efficiency and range varies a lot from EV to EV.\nTo help you choose which electric car is more suitable for you, I made the table below with EPA efficiency and range figures – for different driving scenarios (city, highway and mixed/combined).\nElectric car range and efficiency (EPA)\n|Electric car\n|City\nrange\n|Combined\nrange\n|Highway\nrange\n|City\nefficiency\n|Combined\nefficiency\n|Highway\nefficiency\n|2019 Tesla Model 3 Long Range (RWD)\n|340 miles\n547 km\n|325 miles\n523 km\n|307 miles\n494 km\n|24,8 kWh/100 miles\n15,4 kWh/100 km\n|25,9 kWh/100 miles\n16,1 kWh/100 km\n|27,4 kWh/100 miles\n17 kWh/100 km\n|2019 Tesla Model 3 Long Range (AWD)\n|320 miles\n515 km\n|310 miles\n499 km\n|297 miles\n478 km\n|28,1 kWh/100 miles\n17,5 kWh/100 km\n|29,1 kWh/100 miles\n18,1 kWh/100 km\n|30,1 kWh/100 miles\n18,7 kWh/100 km\n|2019 Tesla Model 3 Standard Range Plus\n|253 miles\n407 km\n|240 miles\n386 km\n|224 miles\n361 km\n|24,1 kWh/100 miles\n15 kWh/100 km\n|25,3 kWh/100 miles\n15,7 kWh/100 km\n|27,2 kWh/100 miles\n16,9 kWh/100 km\n|2019 Tesla Model S Long Range\n|382 miles\n614 km\n|370 miles\n595 km\n|356 miles\n573 km\n|29,3 kWh/100 miles\n18,2 kWh/100 km\n|30,4 kWh/100 miles\n18,9 kWh/100 km\n|31,5 kWh/100 miles\n19,6 kWh/100 km\n|2019 Tesla Model X Long Range\n...\n22,5 kWh/100 km\n...\n|2017-2019 Chevrolet Bolt EV\n|255 miles\n411 km\n|238 miles\n383 km\n|217 miles\n350 km\n|26,3 kWh/100 miles\n16,4 kWh/100 km\n|28,3 kWh/100 miles\n17,6 kWh/100 km\n|30,6 kWh/100 miles\n19 kWh/100 km\n|2020 Chevrolet Bolt EV\n|279 miles\n449 km\n|259 miles\n417 km\n|237 miles\n381 km\n|26,5 kWh/100 miles\n16,5 kWh/100 km\n|28,6 kWh/100 miles\n17,7 kWh/100 km\n|31,2 kWh/100 miles\n19,4 kWh/100 km",
        "title": "Electric car range and efficiency (EPA) - 🔋PushEVs",
        "url": "https://pushevs.com/electric-car-range-efficiency-epa/",
        "date": null,
        "last_updated": "2024-02-21"
      },
      {
        "snippet": "An efficient EV is simply a car that uses fewer kilowatt-hours of electricity to go the same distance.\n...\n53–140 MPGe\nEPA spread\nModel‑year 2024 EVs range from about 53 to 140 miles‑per‑gallon‑equivalent, nearly a 3x difference in efficiency.\n1.5–4.2 mi/kWh\nEnergy use\nOn the same test cycle, some EVs travel less than 1.5 miles per kWh while the best creep above 4 miles per kWh.\n...\nMPGe, or **miles per gallon equivalent**, is the EPA’s attempt to put EVs in gas‑car language.\nOne “gallon” of gasoline is treated as 33.7 kWh of energy.\nIf an EV uses 25 kWh to travel 100 miles, the math works out to roughly 135 MPGe.\n...\nElectricity is billed in **kilowatt‑hours** (kWh).\nSo the most honest unit is simply: how many kWh do you burn to go 100 miles?\n- **kWh/100 mi**: lower is better (like L/100 km)\n- **mi/kWh**: higher is better (like MPG)\nExample: a car that uses 25 kWh/100 mi delivers 4.0 mi/kWh.\nAt $0.15/kWh, those 100 miles cost about $3.75.\n...\nTake the EPA’s kWh/100‑mile number, divide by 100, and multiply by your home rate.\n...\nThat’s why EPA ratings show 2024 EVs spanning roughly 53–140 MPGe while gasoline cars live between 9–57 MPG for the same model year.\n...\nRecent EPA data and independent testing put a handful of EVs at the sharp end of the efficiency spear, especially in sedan form.\n### Sample of highly efficient EVs on sale (2024–2025)\nRepresentative trims; always confirm the exact configuration’s window sticker, as wheels, motors, and options change the numbers.\n|Model & year|Type|Energy use (kWh/100 mi)*|Approx. mi/kWh|EPA combined MPGe*|Notable trait|\n|--|--|--|--|--|--|\n|Lucid Air Pure (2025 RWD)|Sedan|≈23–24|≈4.2–4.3|High 130s–140s|Luxury sedan that somehow drinks like a subcompact.|\n|Hyundai Ioniq 6 SE (2024–2025 RWD)|Sedan|≈24–25|≈4.0–4.2|Around 140|Super‑slippery aero and efficient 800‑V platform.|\n|Tesla Model 3 Long Range RWD (2025)|Sedan|≈25|≈4.0|Low‑to‑mid 130s|The efficiency benchmark among mass‑market sedans.|\n|Tesla Model Y Long Range RWD (2025)|SUV|≈27–28|≈3.6–3.7|Mid‑120s|Roomier crossover form factor, small aero penalty.|\n|Lexus RZ 300e (2024–2025)|SUV|≈27|≈3.7|Mid‑120s|Luxury compact SUV that surprised everyone with its frugality.|\n|Kia EV6 / Hyundai Kona Electric / Kia Niro EV (2024–2025 RWD)|Crossovers|≈28–29|≈3.4–3.6|High teens/low 120s|The efficient heartland of the EV market.|\n|GMC Hummer EV Pickup/SUV|Truck/SUV|≈70+|≈1.4–1.5|Under 50|Off‑the‑charts consumption; think of it as a rolling coal plant with a conscience.|\n...\n### Sedans & hatchbacks\n- **Typical energy use:** ~24–30 kWh/100 mi\n- **Examples:** Hyundai Ioniq 6, Tesla Model 3, Lucid Air, Chevy Bolt (used)\n...\n#### 1.\nStart with kWh/100 mi, not just range\nRange is a product of pack size; kWh/100 mi is the diet.\n...\n#### 2.\nNormalize for body style and mission\nCompare sedans to sedans, crossovers to crossovers, trucks to trucks.\n...\nWhen you compare electric cars, focus less on the billboard range number and more on **kWh per 100 miles, body style, and real battery health**.\n- Use kWh/100 miles (or mi/kWh) as your primary yardstick; MPGe is just the translation into gas‑car language.",
        "title": "Electric Car Efficiency Comparison: 2025 Buyer's Guide - Recharged",
        "url": "https://recharged.com/articles/electric-car-efficiency-comparison-guide",
        "date": "2025-11-17",
        "last_updated": "2026-05-26"
      },
      {
        "snippet": "With an EPA-rated efficiency of 111 MPGe, it’s middle-of-the-road in efficiency, far below the Tesla but way above the 2021 Ford Mustang Mach-E GT’s 84 MPGe.\n...\nRecent figures from the U.S. Environmental Protection Agency (EPA) show that the 2021 Tesla Model 3 Standard Range Plus RWD stands at the top of the efficiency range, boasting a combined 142 MPGe—the electrical equivalent of a gallon of fuel.\n...\nEV testing and analysis firm Recurrent crunched the numbers on a set of 99 cars—half Tesla Model 3s and half Nissan Leafs—and their 500,000 data points of efficiency metrics were logged between November 2021 and March 2022.\nUsing an EPA figure-based mile per kWh (mi/kWh) measurement as opposed to MPGe, the Tesla range was calculated from 3.33 to 4.17 mi/kWh, and the Nissan Leaf was 2.94 to 3.45 mi/kWh.\nTherefore, even bargain standard Model 3s will achieve greater road efficiency than the best Leaf.\nHowever, the EPA ratings weren’t what was measured when real-world driving conditions were considered.\nOver the four-month timeframe, Recurrent revealed the median observed efficiency for each vehicle as the Tesla Model 3 having 3.39 mi/kWh and the Nissan Leaf having 3.71 mi/kWh.",
        "title": "Is the Nissan Leaf More Efficient Than the Tesla Model 3? Here's What 1 Study Found",
        "url": "https://www.motorbiscuit.com/nissan-leaf-more-efficient-tesla-model-3-what-study-found/",
        "date": "2022-08-11",
        "last_updated": "2025-06-25"
      },
      {
        "snippet": "Compare USA EV efficiency by kWh/100 mi and MPGe, with EPA and charging metrics across all models and trims.\nUpdated monthly (2026).",
        "title": "Most Efficient EVs in the USA (kWh/100 mi) - BEV Database",
        "url": "https://bev-database.com/cars-list-usa/most-efficient-electric-cars",
        "date": "2026-02-28",
        "last_updated": "2026-02-28"
      },
      {
        "snippet": ",\nModel Year 2022 EVs Achieving EPA Combined Rating of 100 MPGe or more,\nMake and Model,Highest MPGe For Base Model\nTesla Model 3,132\nLucid Air,131\nTesla Model Y,129\nChevrolet Bolt EV,120\nHyundai Kona Electric,120\nTesla Model S,120\nKia EV6,117\nChevrolet Bolt EUV,115\nHyundai Ioniq 5,114\nKia Niro Electric,112\nNissan Leaf,111\nMINI Cooper SE,110\nBMW i4 Gran Coupe,109\nPolestar 2,107\nVolkswagen ID.4,107\nFord Mustang Mach-E,103\nTesla Model X,102\n,\n...\nEVs include only all-electric vehicles.,\n...\nOnly the base model names are shown and only the highest MPGe values are shown for each model name.\nSome models listed have configurations that fall below 100 MPGe.,\n...\n,\n\"Source: U.S. Department of Energy and U.S. Environmental Protection Agency’s Fuel Economy Website, Compare Electric Vehicles Side-by-Side.\nData accessed August 24, 2022.\",\n,\n,\nhttps://www.fueleconomy.gov/feg/evSelect.jsp,",
        "title": "FOTW_1257_web.xlsx",
        "url": "https://www.energy.gov/sites/default/files/2022-09/FOTW_1257_web.xlsx",
        "date": null,
        "last_updated": "2025-03-28"
      },
      {
        "snippet": ",\nModel Year 2022 EVs Achieving EPA Combined Rating of 100 MPGe or more,\nMake and Model,Highest MPGe For Base Model\nTesla Model 3,132\nLucid Air,131\nTesla Model Y,129\nChevrolet Bolt EV,120\nHyundai Kona Electric,120\nTesla Model S,120\nKia EV6,117\nChevrolet Bolt EUV,115\nHyundai Ioniq 5,114\nKia Niro Electric,112\nNissan Leaf,111\nMINI Cooper SE,110\nBMW i4 Gran Coupe,109\nPolestar 2,107\nVolkswagen ID.4,107\nFord Mustang Mach-E,103\nTesla Model X,102\n,\n...\nEVs include only all-electric vehicles.,\n...\nOnly the base model names are shown and only the highest MPGe values are shown for each model name.\nSome models listed have configurations that fall below 100 MPGe.,\n...\n,\n\"Source: U.S. Department of Energy and U.S. Environmental Protection Agency’s Fuel Economy Website, Compare Electric Vehicles Side-by-Side.\nData accessed August 24, 2022.\",\n,\n,\nhttps://www.fueleconomy.gov/feg/evSelect.jsp,",
        "title": "[XLS] FOTW #1257 - Energy.gov",
        "url": "https://www.energy.gov/documents/fotw1257webxlsx",
        "date": null,
        "last_updated": "2026-03-05"
      }
    ],
    "server_time": null
  }
  ```
</Accordion>

#### How Classification Works

The classifier analyzes your query and automatically routes it to:

* **Pro Search** for complex queries requiring:
  * Multi-step reasoning or analysis
  * Comparative analysis across multiple sources
  * Deep research workflows

* **Fast Search** for straightforward queries like:
  * Simple fact lookups
  * Direct information retrieval
  * Basic question answering

#### Billing with Auto Classification

**You are billed based on which search type your query triggers:**

* If classified as **Pro Search**: \$14–\$22 per 1,000 requests (based on context size)
* If classified as **Fast Search**: \$6–\$14 per 1,000 requests (based on context size - same as standard Sonar Pro)

To see the full pricing details, see the <a href="/docs/sonar/pro-search/quickstart#pricing">Pricing</a> section.

<Tip>
  Automatic classification is recommended for most applications as it balances cost optimization with query performance. You get Pro Search capabilities when needed without overpaying for simple queries.
</Tip>

### Manually Specifying the Search Type

If needed, you can manually specify the search type. This is useful for specific use cases where you know the query requires Pro Search capabilities.

* **`"search_type": "pro"`**: Manually specify Pro Search for complex queries when you know multi-step tool usage is needed
* **`"search_type": "fast"`**: Manually specify Fast Search for simple queries to optimize speed and cost (this is also the default when `search_type` is omitted)

## Built-in Tool Capabilities

Pro Search provides access to two powerful built-in tools that the model can use automatically:

<CardGroup>
  <Card title="web_search" icon="search" href="/docs/sonar/pro-search/tools#web_search">
    Conduct targeted web searches with custom queries, filters, and search strategies based on the evolving research context.
  </Card>

  <Card title="fetch_url_content" icon="globe" href="/docs/sonar/pro-search/tools#fetch_url_content">
    Retrieve and analyze content from specific URLs to gather detailed information beyond search result snippets.
  </Card>
</CardGroup>

<Info>
  The model automatically decides which tools to use and when, creating dynamic research workflows tailored to each specific query. These are built-in tools called by the system. Custom tools cannot be registered. Learn more in the [Built-in Tool Capabilities](/docs/sonar/pro-search/tools) guide.
</Info>

## Additional Capabilities

Pro Search also provides access to advanced Sonar Pro features that enhance your development experience:

* **[Stream Mode Guide](/docs/sonar/pro-search/stream-mode)**: Control streaming response formats with concise or full mode for optimized bandwidth usage and enhanced reasoning visibility.

## Pricing

Pro Search pricing consists of token usage plus request fees that vary by search type and context size.

<div>
  <div>
    <h3>Token Usage (Same for All Search Types)</h3>

    <div>
      <div>
        <span>Input Tokens</span>
        <span>\$3 per 1M</span>
      </div>

      <div>
        <span>Output Tokens</span>
        <span>\$15 per 1M</span>
      </div>
    </div>
  </div>

  <div>
    <h3>Request Fees (per 1,000 requests)</h3>

    <div>
      <h4>Pro Search (Complex Queries)</h4>

      <div>
        <div>
          <span>High Context</span>
          <span>\$22</span>
        </div>

        <div>
          <span>Medium Context</span>
          <span>\$18</span>
        </div>

        <div>
          <span>Low Context</span>
          <span>\$14</span>
        </div>
      </div>
    </div>

    <div>
      <h4>Fast Search (Simple Queries)</h4>

      <div>
        <div>
          <span>High Context</span>
          <span>\$14</span>
        </div>

        <div>
          <span>Medium Context</span>
          <span>\$10</span>
        </div>

        <div>
          <span>Low Context</span>
          <span>\$6</span>
        </div>
      </div>
    </div>
  </div>
</div>

<Info>
  When using `search_type: "auto"`, you're billed at the Pro Search rate if your query is classified as complex, or the Fast Search rate if classified as simple. See the full pricing details <a href="/docs/getting-started/pricing">here</a>.
</Info>

## Next Steps

<CardGroup>
  <Card title="Pro Search Tools" icon="brain" href="/docs/sonar/pro-search/tools">
    Learn about the tools available to the model for Pro Search.
  </Card>

  <Card title="Pro Search Classifier" icon="brain" href="/docs/sonar/pro-search/classifier">
    Learn about the classifier that automatically determines whether a query requires Pro Search or Fast Search.
  </Card>

  <Card title="Pro Search Stream Mode" icon="bolt" href="/docs/sonar/pro-search/stream-mode">
    Learn about the streaming mode for Pro Search.
  </Card>

  <Card title="Agent API Quickstart" icon="rocket" href="/docs/agent-api/quickstart">
    Get started with the Agent API.
  </Card>
</CardGroup>


# Stream Mode: Concise vs Full
Source: https://docs.perplexity.ai/docs/sonar/pro-search/stream-mode

Learn how to use stream_mode to control streaming response formats and optimize your integration

<SonarDeprecationNotice />

## Overview

The `stream_mode` parameter gives you control over how streaming responses are formatted. Choose between two modes:

* **`full`** (default) - Traditional streaming format with complete message objects in each chunk
* **`concise`** - Optimized streaming format with reduced redundancy and enhanced reasoning visibility

<Info>
  The `concise` mode is designed to minimize bandwidth usage and provide better visibility into the model's reasoning process.
</Info>

## Quick Comparison

| Feature                 | Full Mode                                | Concise Mode                        |
| ----------------------- | ---------------------------------------- | ----------------------------------- |
| **Message aggregation** | Server-side (includes `choices.message`) | Client-side (delta only)            |
| **Chunk types**         | Single type (`chat.completion.chunk`)    | Multiple types for different stages |
| **Search results**      | Multiple times during stream             | Only in `done` chunks               |
| **Bandwidth**           | Higher (includes redundant data)         | Lower (optimized for efficiency)    |

## Using Concise Mode

Set `stream_mode: "concise"` when creating streaming completions:

<Tabs>
  <Tab title="Python SDK">
    ```python theme={null}
    from perplexity import Perplexity

    client = Perplexity()

    stream = client.chat.completions.create(
        model="sonar-pro",
        messages=[{"role": "user", "content": "Current weather and 7-day forecast for Seattle, Washington"}],
        stream=True,
        stream_mode="concise"
    )

    for chunk in stream:
        print(f"Chunk type: {chunk.object}")
        if chunk.choices and chunk.choices[0].delta.content:
            print(chunk.choices[0].delta.content, end="")
    ```
  </Tab>

  <Tab title="Typescript SDK">
    ```typescript theme={null}
    import Perplexity from '@perplexity-ai/perplexity_ai';

    const client = new Perplexity();

    const stream = await client.chat.completions.create({
      model: "sonar-pro",
      messages: [{ role: "user", content: "Current weather and 7-day forecast for Seattle, Washington" }],
      stream: true,
      stream_mode: "concise"
    });

    for await (const chunk of stream) {
      console.log(`Chunk type: ${chunk.object}`);
      if (chunk.choices[0]?.delta?.content) {
        process.stdout.write((chunk.choices[0]?.delta?.content ?? '') as string);
      }
    }
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://api.perplexity.ai/v1/sonar" \
      -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "sonar-pro",
        "messages": [{"role": "user", "content": "What is the weather in Seattle?"}],
        "stream": true,
        "stream_mode": "concise"
      }'
    ```
  </Tab>
</Tabs>

<AccordionGroup>
  <Accordion title="Response — Current weather and 7-day forecast for Seattle, Washington">
    ```json theme={null}
    {
      "id": "300fab98-92a3-4a69-9e84-fe05c918f831",
      "results": [
        {
          "snippet": "**Current conditions at**\n## Boeing Field - King County International Airport (KBFI)\n**Lat: ** 47.54548°N**Lon: ** 122.3147°W**Elev: ** 20.0ft.\nMostly Cloudy\n61°F\n16°C\n|**Humidity**|63%|\n|--|--|\n|**Wind Speed**|N 0 MPH|\n|**Barometer**|29.95 in (1014.22 mb)|\n|**Dewpoint**|48°F (9°C)|\n|**Visibility**|10.00 mi|\n|**Last update**|26 May 03:00 PM PDT|\n...\n**Extended Forecast for**\n## Seattle WA\n- Tonight\nLow: 50 °F\nMostly Clear\n- Wednesday\nHigh: 71 °F\nSunny\n- Wednesday Night\nLow: 54 °F\nMostly Clear\n- Thursday\nHigh: 77 °F\nSunny\n- Thursday Night\nLow: 53 °F\nChance Rain\n- Friday\nHigh: 60 °F\nChance Rain\n- Friday Night\nLow: 49 °F\nMostly Cloudy\n- Saturday\nHigh: 62 °F\nPartly Sunny\n- Saturday Night\nLow: 48 °F\nPartly Cloudy\n## Detailed Forecast\n**Tonight**\nMostly clear, with a low around 50.\nNorth wind 5 to 8 mph becoming calm in the evening.\n**Wednesday**\nSunny, with a high near 71.\nLight and variable wind becoming north 5 to 10 mph in the morning.\n**Wednesday Night**\nMostly clear, with a low around 54.\nNorth wind 5 to 8 mph becoming calm in the evening.\n**Thursday**\nSunny, with a high near 77.\nCalm wind becoming north northwest around 5 mph in the afternoon.\n**Thursday Night**\nA 30 percent chance of rain, mainly after 11pm.\nMostly cloudy, with a low around 53.\nNorth northwest wind 5 to 9 mph becoming south after midnight.\n**Friday**\nA 50 percent chance of rain.\nMostly cloudy, with a high near 60.\n**Friday Night**\nMostly cloudy, with a low around 49.\n**Saturday**\nPartly sunny, with a high near 62.\n**Saturday Night**\nPartly cloudy, with a low around 48.\n**Sunday**\nMostly sunny, with a high near 64.\n**Sunday Night**\nMostly clear, with a low around 49.\n**Monday**\nSunny, with a high near 70.\n**Monday Night**\nPartly cloudy, with a low around 53.\n**Tuesday**\nMostly sunny, with a high near 78.\n...\nSeattle WA\n47.62°N 122.36°W (Elev. 105 ft)\nLast Update:\n11:26 am PDT May 26, 2026\nForecast Valid:\n3pm PDT May 26, 2026-6pm PDT Jun 2, 2026",
          "title": "7-Day Forecast 47.62N 122.36W",
          "url": "https://forecast.weather.gov/MapClick.php?lat=47.6218&lon=-122.3503",
          "date": "2026-05-26",
          "last_updated": "2026-05-26"
        },
        {
          "snippet": "Seattle, WA Weather Forecast | AccuWeather\n## Today's Weather\nTue, May 26\nMainly cloudy; brief morning showers followed by a shower in spots this afternoon\n**Hi: 62°**\nTonight: Partly cloudy\n**Lo: 51°**\n## Current Weather\n2:32 PM\n57°F\nRealFeel®\n60°\nCloudy More Details\nRealFeel Shade™ 56°\nWind NW 2 mph\nWind Gusts 5 mph\nAir Quality Fair\n## Looking Ahead\nWarming up, then noticeably cooler weather again Friday\n## Hourly Weather\n3 PM 59°\n40%\n4 PM 61°\n37%\n5 PM 62°\n32%\n6 PM 62°\n32%\n7 PM 61°\n21%\n8 PM 60°\n0%\n9 PM 59°\n0%\n10 PM 57°\n0%\n11 PM 56°\n0%\n12 AM 54°\n0%\n1 AM 53°\n0%\n2 AM 53°\n0%\n## 10-Day Weather Forecast\nToday\n5/26\n62° 51°\nA few showers this morning\nNight: Partly cloudy\n80%\nWed\n5/27\n73° 55°\nPartly sunny and pleasant\nPartly cloudy\n0%\nThu\n5/28\n77° 53°\nMostly sunny and pleasant\nPartly cloudy\n12%\nFri\n5/29\n59° 47°\nCooler\nLow clouds\n25%\nSat\n5/30\n62° 47°\nMostly cloudy\nMostly cloudy\n25%\nSun\n5/31\n70° 50°\nPleasant with clouds and sun\nMainly clear\n19%\nMon\n6/1\n76° 57°\nMostly sunny and pleasant\nMainly clear\n13%\nTue\n6/2\n93° 58°\nHot with high clouds\nCloudy\n2%\nWed\n6/3\n76° 55°\nMostly cloudy\nMostly cloudy\n6%\nThu\n6/4\n73° 53°\nSunshine and a few clouds\nMainly clear\n1%\n...\nAir Quality Fair\nThe air quality is generally acceptable for most individuals.\nHowever, sensitive groups may experience minor to moderate symptoms from long-term exposure.",
          "title": "Seattle, WA Weather Forecast",
          "url": "https://www.accuweather.com/en/us/seattle/98104/weather-forecast/351409",
          "date": null,
          "last_updated": "2026-05-26"
        },
        {
          "snippet": "Additional Conditions\nPressure\n29.93 °in\nVisibility\n10 °miles\nClouds\nPartly Cloudy\nDew Point\n47 °F\nHumidity\n60 °%\nRainfall\n0 °in\nSnow Depth\n0 °in\nTop Video Stories\n...\n5:20 AM\n8:55 PM",
          "title": "Seattle, WA 10-Day Weather Forecast",
          "url": "https://www.wunderground.com/forecast/us/wa/seattle",
          "date": "2026-05-26",
          "last_updated": "2026-05-27"
        },
        {
          "snippet": "**Current conditions at**\n## Boeing Field - King County International Airport (KBFI)\n**Lat: ** 47.54548°N**Lon: ** 122.3147°W**Elev: ** 20.0ft.\nMostly Cloudy\n52°F\n11°C\n|**Humidity**|66%|\n|--|--|\n|**Wind Speed**|WSW 6 MPH|\n|**Barometer**|30.15 in (1021.0 mb)|\n|**Dewpoint**|41°F (5°C)|\n|**Visibility**|10.00 mi|\n|**Last update**|16 May 06:20 PM PDT|\n...\n**Extended Forecast for**\n## Downtown Seattle WA\n- Tonight\nLow: 43 °F\nChance Rain\nthen Partly\nCloudy\n- Sunday\nHigh: 62 °F\nMostly Sunny\n- Sunday Night\nLow: 48 °F\nIncreasing\nClouds\n- Monday\nHigh: 66 °F\nDecreasing\nClouds\n- Monday Night\nLow: 50 °F\nPartly Cloudy\n- Tuesday\nHigh: 65 °F\nPartly Sunny\n- Tuesday Night\nLow: 50 °F\nMostly Cloudy\n- Wednesday\nHigh: 68 °F\nMostly Sunny\n- Wednesday Night\nLow: 51 °F\nPartly Cloudy\n## Detailed Forecast\n**Tonight**\nA 50 percent chance of rain, mainly before 8pm.\nMostly cloudy, with a low around 43.\nWest wind around 5 mph becoming calm in the evening.\n**Sunday**\nMostly sunny, with a high near 62.\nLight and variable wind.\n**Sunday Night**\nIncreasing clouds, with a low around 48.\nCalm wind.\n**Monday**\nCloudy, then gradually becoming mostly sunny, with a high near 66.\nLight and variable wind.\n**Monday Night**\nPartly cloudy, with a low around 50.\nNorth wind around 6 mph becoming calm in the evening.\n**Tuesday**\nPartly sunny, with a high near 65.\n**Tuesday Night**\nMostly cloudy, with a low around 50.\n**Wednesday**\nMostly sunny, with a high near 68.\n**Wednesday Night**\nPartly cloudy, with a low around 51.\n**Thursday**\nMostly sunny, with a high near 69.\n**Thursday Night**\nPartly cloudy, with a low around 52.\n**Friday**\nMostly sunny, with a high near 69.\n**Friday Night**\nMostly clear, with a low around 52.\n**Saturday**\nMostly sunny, with a high near 73.\n...\nDowntown Seattle WA\n47.61°N 122.32°W (Elev. 240 ft)\nLast Update:\n11:27 am PDT May 16, 2026\nForecast Valid:\n6pm PDT May 16, 2026-6pm PDT May 23, 2026\nForecast Discussion",
          "title": "7-Day Forecast 47.61N 122.32W - National Weather Service",
          "url": "https://forecast.weather.gov/MapClick.php?lat=47.6032&lon=-122.3303",
          "date": "2026-05-17",
          "last_updated": "2026-05-17"
        },
        {
          "snippet": "**Current conditions at**\n## SEATTLE WEATHER FORECAST OFFICE (SEAW1)\n**Lat: ** 47.68528°N**Lon: ** 122.25111°W**Elev: ** 29.0ft.\nNA\n45°F\n7°C\n|**Humidity**|75%|\n|--|--|\n|**Wind Speed**|SSW 5 MPH|\n|**Barometer**|30.45 in (1031.16 mb)|\n|**Dewpoint**|37°F (3°C)|\n|**Visibility**|NA|\n|**Wind Chill**|42°F (6°C)|\n|**Last update**|26 Mar 09:30 AM PDT|\n...\n**Extended Forecast for**\n## 2 Miles SSE Seattle-University WA\n- Today\nHigh: 53 °F\nSunny\n- Tonight\nLow: 35 °F\nIncreasing\nClouds\n- Friday\nHigh: 56 °F\nMostly Sunny\n- Friday Night\nLow: 38 °F\nMostly Cloudy\n- Saturday\nHigh: 54 °F\nPartly Sunny\n- Saturday Night\nLow: 39 °F\nMostly Cloudy\n- Sunday\nHigh: 54 °F\nSlight Chance\nRain\n- Sunday Night\nLow: 39 °F\nChance Rain\n- Monday\nHigh: 51 °F\nChance Rain\n## Detailed Forecast\n**Today**\nSunny, with a high near 53.\nSouth wind around 6 mph.\n**Tonight**\nIncreasing clouds, with a low around 35.\nCalm wind.\n**Friday**\nMostly sunny, with a high near 56.\nCalm wind becoming north 5 to 7 mph in the afternoon.\n**Friday Night**\nMostly cloudy, with a low around 38.\nNorth wind 5 to 8 mph becoming calm in the evening.\n**Saturday**\nPartly sunny, with a high near 54.\nCalm wind becoming north northwest around 5 mph in the afternoon.\n**Saturday Night**\nMostly cloudy, with a low around 39.\n**Sunday**\nA 20 percent chance of rain after 11am.\nMostly cloudy, with a high near 54.\n**Sunday Night**\nA chance of rain.\nMostly cloudy, with a low around 39.\n**Monday**\nA chance of rain.\nMostly cloudy, with a high near 51.\n**Monday Night**\nA chance of rain, mainly before 11pm.\nPartly cloudy, with a low around 36.\n**Tuesday**\nA slight chance of rain.\nMostly sunny, with a high near 53.\n**Tuesday Night**\nA chance of rain.\nMostly cloudy, with a low around 40.\n**Wednesday**\nA chance of rain.\nMostly cloudy, with a high near 53.\n...\n2 Miles SSE Seattle-University WA\n47.63°N 122.3°W (Elev. 190 ft)\nLast Update:\n11:27 pm PDT Mar 25, 2026\nForecast Valid:\n10am PDT Mar 26, 2026-6pm PDT Apr 1, 2026\nForecast Discussion",
          "title": "7-Day Forecast 47.63N 122.3W - National Weather Service",
          "url": "https://forecast.weather.gov/MapClick.php?lat=47.6329523&lon=-122.28918880000003&site=all&smap=1&searchresult=Seattle%2C+WA+98112%2C+USA",
          "date": "2026-03-26",
          "last_updated": "2026-03-26"
        },
        {
          "snippet": "Elevated to Critical fire weather conditions due to gusty winds and low humidity are expected through Tuesday across Oregon and Nevada.\nShowers and thunderstorms will develop over the Northwest.\n...\n**Current conditions at**\n## SEATTLE WEATHER FORECAST OFFICE (SEAW1)\n**Lat: ** 47.68528°N**Lon: ** 122.25111°W**Elev: ** 29.0ft.\nNA\n53°F\n12°C\n|**Humidity**|86%|\n|--|--|\n|**Wind Speed**|ESE 5 MPH|\n|**Barometer**|29.71 in (1006.1 mb)|\n|**Dewpoint**|49°F (9°C)|\n|**Visibility**|NA|\n|**Last update**|25 May 10:30 PM PDT|\n...\n**Extended Forecast for**\n## Seattle-University WA\n- Tonight\nLow: 48 °F\nSlight Chance\nRain\n- Tuesday\nHigh: 65 °F\nChance Rain\nthen Partly\nSunny\n- Tuesday Night\nLow: 49 °F\nPartly Cloudy\n- Wednesday\nHigh: 74 °F\nSunny\n- Wednesday Night\nLow: 53 °F\nMostly Clear\n- Thursday\nHigh: 78 °F\nSunny\n- Thursday Night\nLow: 53 °F\nPartly Cloudy\n- Friday\nHigh: 64 °F\nChance Rain\n- Friday Night\nLow: 48 °F\nChance Rain\nthen Mostly\nCloudy\n## Detailed Forecast\n**Tonight**\nA 10 percent chance of rain after 5am.\nPartly cloudy, with a low around 48.\nSouth wind around 6 mph becoming calm after midnight.\n**Tuesday**\nA 30 percent chance of rain, mainly before 9am.\nPartly sunny, with a high near 65.\nCalm wind becoming north northwest 5 to 7 mph in the afternoon.\n**Tuesday Night**\nPartly cloudy, with a low around 49.\nNorth wind around 6 mph becoming calm in the evening.\n**Wednesday**\nSunny, with a high near 74.\nCalm wind becoming north 5 to 8 mph in the afternoon.\n**Wednesday Night**\nMostly clear, with a low around 53.\nNorth wind 5 to 7 mph becoming calm in the evening.\n**Thursday**\nSunny, with a high near 78.\n**Thursday Night**\nPartly cloudy, with a low around 53.\n**Friday**\nA chance of rain.\nMostly cloudy, with a high near 64.\n**Friday Night**\nA chance of rain before 11pm.\nMostly cloudy, with a low around 48.\n**Saturday**\nPartly sunny, with a high near 65.\n**Saturday Night**\nPartly cloudy, with a low around 47.\n**Sunday**\nMostly sunny, with a high near 66.\n**Sunday Night**\nPartly cloudy, with a low around 48.\n**Monday**\nMostly sunny, with a high near 72.\n...\nSeattle-University WA\n47.65°N 122.3°W (Elev. 33 ft)\nLast Update:\n1:00 pm PDT May 25, 2026\nForecast Valid:\n11pm PDT May 25, 2026-6pm PDT Jun 1, 2026\nForecast Discussion",
          "title": "7-Day Forecast 47.65N 122.3W - National Weather Service",
          "url": "https://forecast.weather.gov/MapClick.php?CityName=Seattle&state=WA&site=SEW&lat=47.6606&lon=-122.292",
          "date": "2026-05-26",
          "last_updated": "2026-05-26"
        }
      ],
      "server_time": null
    }
    ```
  </Accordion>

  <Accordion title="Response — What is the weather in Seattle?">
    ```json theme={null}
    {
      "id": "3b076c08-870a-45e5-881d-ddaf39781638",
      "results": [
        {
          "snippet": "Seattle, WA Weather Forecast | AccuWeather\n## Today's Weather\nWed, May 20\nClouds breaking for some sun\n**Hi: 68°**\nTonight: Mainly clear\n**Lo: 51°**\n## Current Weather\n1:47 PM\n64°F\nRealFeel®\n77°\nMostly cloudy More Details\nRealFeel Shade™ 65°\nWind NNW 3 mph\nWind Gusts 6 mph\nAir Quality Fair\n## Looking Ahead\n...\n68° 51°\nClouds breaking for some sun\nNight: Mainly clear",
          "title": "Seattle, WA Weather Forecast - AccuWeather",
          "url": "https://www.accuweather.com/en/us/seattle/98104/weather-forecast/351409",
          "date": null,
          "last_updated": "2026-05-20"
        },
        {
          "snippet": "**Current conditions at**\n## Boeing Field - King County International Airport (KBFI)\n**Lat: ** 47.54548°N**Lon: ** 122.3147°W**Elev: ** 20.0ft.\nClear\n64°F\n18°C\n|**Humidity**|52%|\n|--|--|\n|**Wind Speed**|WNW 10 MPH|\n|**Barometer**|30.19 in (1022.35 mb)|\n|**Dewpoint**|46°F (8°C)|\n|**Visibility**|10.00 mi|\n|**Last update**|20 May 02:30 PM PDT|\n...\n## Seattle WA\n- This Afternoon\nHigh: 67 °F\nMostly Sunny\n- Tonight\nLow: 51 °F\nDecreasing\nClouds\n- Thursday\n...\n**This Afternoon**\nMostly sunny, with a high near 67.\nNorth northwest wind around 8 mph.\n**Tonight**\nMostly cloudy, then gradually becoming clear, with a low around 51.\nNorth wind 5 to 7 mph becoming calm after midnight.\n...\n2pm PDT May 20, 2026-6pm PDT May 26, 2026",
          "title": "7-Day Forecast 47.62N 122.36W - National Weather Service",
          "url": "https://forecast.weather.gov/MapClick.php?lat=47.6218&lon=-122.3503",
          "date": "2026-05-20",
          "last_updated": "2026-05-20"
        },
        {
          "snippet": "*access_time* ** 10:20 PM PDT on May 20, 2026** (GMT -7) | Updated 2 seconds ago\n--° | 50°\nlike 61°\nClear\nN\nGusts\nTomorrow's temperature is forecast to be WARMER than today.",
          "title": "Seattle, WA Weather Conditions | Weather Underground",
          "url": "https://www.wunderground.com/weather/us/wa/seattle",
          "date": "2026-05-20",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "Clear\n56°\n73°\n49°\nPrecipitation:0%\nWind:3 mphNNE\nHumidity:69%\nUV Index:Low\nSeattle, WA\nChange Location\nWednesday\n73\n49\n0%\nClear\nWind:3 mphNNE\nHumidity:69%\nUV Index:Low\nThursday\n73\n51\n...\nPartly Cloudy\nWind:9 mphN\nHumidity:56%\nUV Index:High\nFriday\n74\n...\nSunny\nWind:7 mphNNW\nHumidity:60%\nUV Index:High\nSaturday\n...\nAM Clouds/PM Sun\n...\nSunday\n...\nCloudy\n...\nMonday\n56\n48\n40%\nShowers\nWind:12 mphSSW\nHumidity:74%\nUV Index:Moderate\nTuesday\n61\n49\n30%\nAM Showers\nWind:8 mphW\nHumidity:71%\nUV Index:High",
          "title": "Weather - KOMO News",
          "url": "https://komonews.com/weather",
          "date": "2026-05-21",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "Wednesday, May 20\n# Current Weather\n2:37 PM\n65°F\nSunny\nRealFeel® 75°\nPleasant\nRealFeel Shade™ 64°\nPleasant\nRealFeel®\n75°\nRealFeel Shade™\n64°\nMax UV Index\n5.8 (High)\nWind\nNNW 4 mph\nWind Gusts\n7 mph\nHumidity\n65%\nIndoor Humidity\n59% (Ideal Humidity)\nDew Point\n53° F\nPressure\n↓ 30.21 in\nCloud Cover\n1%\nVisibility\n6 mi\nCloud Ceiling\n40000 ft\n## Day\n5/20\n68°Hi\nRealFeel®\n75°\nPleasant\nRealFeel Shade™\n65°\nPleasant\nClouds breaking for some sun\nMax UV Index8.0 (Very High)\nAccuLumen Brightness Index™6 (Medium)\nWindN 7 mph\nWind Gusts13 mph\nProbability of Precipitation0%\nProbability of Thunderstorms0%\nPrecipitation0.00 in\nCloud Cover59%\n...\n5/20\n51°Lo\nRealFeel®\n50°\nChilly\nMainly clear\nWindNNE 6 mph\nWind Gusts12 mph\nProbability of Precipitation0%\nProbability of Thunderstorms0%\nPrecipitation0.00 in\nCloud Cover22%\n...\n## Current Weather Conditions in Seattle\nSeattle, Washington is currently Sunny with a temperature of 65°.\nThe current RealFeel® Temperature is 75° (Pleasant) based on observed conditions including 65% humidity, 1% cloud cover, a UV index of 6, and winds of 4 mph.\nIn shade, the RealFeel Shade™ is 64°.",
          "title": "Current Weather - Seattle, WA - AccuWeather",
          "url": "https://www.accuweather.com/en/us/seattle/98104/current-weather/351409",
          "date": null,
          "last_updated": "2026-05-20"
        },
        {
          "snippet": "Additional Conditions\nPressure\n30.14 °in\nVisibility\n10 °miles\nClouds\nPartly Cloudy\nDew Point\n45 °F\nHumidity\n44 °%\nRainfall\n0 °in\nSnow Depth\n0 °in\nTop Video Stories",
          "title": "Seattle, WA 10-Day Weather Forecast",
          "url": "https://www.wunderground.com/forecast/us/wa/seattle",
          "date": "2026-05-20",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "Seattle, WA\n57°\nFeels like **57°**\nH: ° L: 49° as of 1:48 AM PDT\n2AM\n...\nLive\nSeattle\n, WA\n57°\nLive\nSeattle\n, WA\n57°\nLive\nSeattle\n, WA\n57°\nLive\n...\nSeattle weather: sunny and 70's return to end the work week",
          "title": "FOX 13 Weather for Seattle & Western Washington",
          "url": "https://www.fox13seattle.com/weather",
          "date": "2026-05-20",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "18\n°C\nClear\nFeels 18\nH: 18°   L: 10°\n## Hourly\n...\nPartly cloudy.\n...\n## Weather FAQ for Seattle, WA\nWhat is the current temperature in Seattle?\n18°\nWhat is the “feels like” temperature in Seattle?\n18°\nWhat is the high and low temperature today in Seattle?\n18°\n10°\nWhat is the probability of rain or snow today in Seattle?\n20% P.O.P.\nHow much will it rain or snow today in Seattle?\nNone expected\nWhat is the current wind speed and direction in Seattle?\n9 km/h NW\nWhat is the current humidity level in Seattle?\n52%\nAre there any active weather alerts in Seattle?\nNo\nWhat is the UV index right now in Seattle?\nLow\nWhat time is sunrise and sunset today in Seattle?\nSunrise 5:25am\nSunset 8:45pm",
          "title": "Seattle, WA Current Weather",
          "url": "https://www.theweathernetwork.com/en/city/us/washington/seattle/current?_guid_iss_=1",
          "date": "2026-05-20",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "# Seattle, WA Weather\nAs of\n- **Current Temperature**\n52\nFeels like:52°\n- **Today's high temperature**\n72°\n- **Today's low temperature**\n52°\nCurrent Weather ConditionSunny\n## Live Weather Radar\n...\n## Current Weather Details\n- **Windchill**\n52°\n- **Daily Rain**\n0\"\n- **Dew point**\n46°\n- **Monthly Rain**\n0.35\"\n- **Humidity**\n81%\n- **Avg.\nWind**\nW 2 mph\n- **Pressure**\n30.19\" →\n- **Wind Gust**\nW 3 mph\n- **Sunrise**\n5:25 AM\n- **Moon**\nWaxing Crescent\n- **Sunset**\n8:47 PM\n- **UV Index**\n7 (High)\n## Weather Forecast\n- ### Today\nHi\nSunny.\nHighs in the upper 60s to mid 70s.\nLight wind becoming northwest around 10 mph in the afternoon.\n- ### Tonight\nLo\nMostly clear.\nLows in the lower 50s.\nNorth wind to 10 mph in the evening becoming light.",
          "title": "Seattle, WA Weather Today & Tomorrow - Local Forecast & Live ...",
          "url": "https://www.weatherbug.com/weather-forecast/now/seattle-wa-98104",
          "date": "2026-05-21",
          "last_updated": "2026-05-21"
        },
        {
          "snippet": "Seattle, WA Hourly Weather | AccuWeather\n## 11 PM\n56°\nRealFeel®\n53°\nCool\n0%\nMostly clear\nWindNNE 7 mph\nAir QualityPoor\nWind Gusts9 mph\nHumidity68%\nIndoor Humidity44% (Ideal Humidity)\nDew Point45° F\nAccuLumen Brightness Index™0 (Dark)\nCloud Cover13%\nVisibility10 mi\nCloud Ceiling34000 ft\n...\nAccuWeather's hourly forecast for Seattle provides hour-by-hour temperatures, RealFeel® Temperature, and precipitation probability through the next 10 days.\nThe current hour shows 56° with a RealFeel® of 53°, mostly clear with a 0% chance of precipitation.",
          "title": "Seattle, WA Hourly Weather - AccuWeather",
          "url": "https://www.accuweather.com/en/us/seattle/98104/hourly-weather-forecast/351409",
          "date": null,
          "last_updated": "2026-05-21"
        }
      ],
      "server_time": null
    }
    ```
  </Accordion>
</AccordionGroup>

## Understanding Chunk Types

In concise mode, you'll receive four different types of chunks during the stream:

### 1. `chat.reasoning`

Streamed during the reasoning stage, containing real-time reasoning steps and search operations.

<Tabs>
  <Tab title="Structure">
    ```json theme={null}
    {
      "id": "cfa38f9d-fdbc-4ac6-a5d2-a3010b6a33a6",
      "model": "sonar-pro",
      "created": 1759441590,
      "object": "chat.reasoning",
      "choices": [{
        "index": 0,
        "finish_reason": null,
        "message": {
          "role": "assistant",
          "content": ""
        },
        "delta": {
          "role": "assistant",
          "content": "",
          "reasoning_steps": [{
            "thought": "Searching the web for Seattle's current weather...",
            "type": "web_search",
            "web_search": {
              "search_results": [...],
              "search_keywords": ["Seattle current weather"]
            }
          }]
        }
      }],
      "type": "message"
    }
    ```
  </Tab>

  <Tab title="Python Handler">
    ```python theme={null}
    def handle_reasoning_chunk(chunk):
        """Process reasoning stage updates"""
        if chunk.object == "chat.reasoning":
            delta = chunk.choices[0].delta

            if hasattr(delta, 'reasoning_steps'):
                for step in delta.reasoning_steps:
                    print(f"\n[Reasoning] {step.thought}")

                    if step.type == "web_search":
                        keywords = step.web_search.search_keywords
                        print(f"[Search] Keywords: {', '.join(keywords)}")
    ```
  </Tab>

  <Tab title="Typescript Handler">
    ```typescript theme={null}
    function handleReasoningChunk(chunk: any) {
      if (chunk.object === "chat.reasoning") {
        const delta = chunk.choices[0].delta;

        if (delta.reasoning_steps) {
          for (const step of delta.reasoning_steps) {
            console.log(`\n[Reasoning] ${step.thought}`);

            if (step.type === "web_search") {
              const keywords = step.web_search.search_keywords;
              console.log(`[Search] Keywords: ${keywords.join(', ')}`);
            }
          }
        }
      }
    }
    ```
  </Tab>
</Tabs>

### 2. `chat.reasoning.done`

Marks the end of the reasoning stage and includes all search results (web, images, videos) and reasoning steps.

<Tabs>
  <Tab title="Structure">
    ```json theme={null}
    {
      "id": "3dd9d463-0fef-47e3-af70-92f9fcc4db1f",
      "model": "sonar-pro",
      "created": 1759459505,
      "object": "chat.reasoning.done",
      "usage": {
        "prompt_tokens": 6,
        "completion_tokens": 0,
        "total_tokens": 6,
        "search_context_size": "low"
      },
      "search_results": [...],
      "images": [...],
      "choices": [{
        "index": 0,
        "finish_reason": null,
        "message": {
          "role": "assistant",
          "content": "",
          "reasoning_steps": [...]
        },
        "delta": {
          "role": "assistant",
          "content": ""
        }
      }]
    }
    ```
  </Tab>

  <Tab title="Python Handler">
    ```python theme={null}
    def handle_reasoning_done(chunk):
        """Process end of reasoning stage"""
        if chunk.object == "chat.reasoning.done":
            print("\n[Reasoning Complete]")

            # Access all search results
            if hasattr(chunk, 'search_results'):
                print(f"Found {len(chunk.search_results)} sources")
                for result in chunk.search_results[:3]:
                    print(f"  • {result['title']}")

            # Access image results
            if hasattr(chunk, 'images'):
                print(f"Found {len(chunk.images)} images")

            # Partial usage stats available
            if hasattr(chunk, 'usage'):
                print(f"Tokens used so far: {chunk.usage.total_tokens}")
    ```
  </Tab>

  <Tab title="Typescript Handler">
    ```typescript theme={null}
    function handleReasoningDone(chunk: any) {
      if (chunk.object === "chat.reasoning.done") {
        console.log("\n[Reasoning Complete]");

        // Access all search results
        if (chunk.search_results) {
          console.log(`Found ${chunk.search_results.length} sources`);
          chunk.search_results.slice(0, 3).forEach((result: any) => {
            console.log(`  • ${result.title}`);
          });
        }

        // Access image results
        if (chunk.images) {
          console.log(`Found ${chunk.images.length} images`);
        }

        // Partial usage stats available
        if (chunk.usage) {
          console.log(`Tokens used so far: ${chunk.usage.total_tokens}`);
        }
      }
    }
    ```
  </Tab>
</Tabs>

### 3. `chat.completion.chunk`

Streamed during the response generation stage, containing the actual content being generated.

<Tabs>
  <Tab title="Structure">
    ```json theme={null}
    {
      "id": "cfa38f9d-fdbc-4ac6-a5d2-a3010b6a33a6",
      "model": "sonar-pro",
      "created": 1759441592,
      "object": "chat.completion.chunk",
      "choices": [{
        "index": 0,
        "finish_reason": null,
        "message": {
          "role": "assistant",
          "content": ""
        },
        "delta": {
          "role": "assistant",
          "content": " tonight"
        }
      }]
    }
    ```
  </Tab>

  <Tab title="Python Handler">
    ```python theme={null}
    def handle_completion_chunk(chunk):
        """Process content generation updates"""
        if chunk.object == "chat.completion.chunk":
            delta = chunk.choices[0].delta

            if hasattr(delta, 'content') and delta.content:
                # Stream content to user
                print(delta.content, end='', flush=True)
                return delta.content

        return ""
    ```
  </Tab>

  <Tab title="Typescript Handler">
    ```typescript theme={null}
    function handleCompletionChunk(chunk: any): string {
      if (chunk.object === "chat.completion.chunk") {
        const delta = chunk.choices[0]?.delta;

        if (delta?.content) {
          // Stream content to user
          process.stdout.write(delta.content);
          return delta.content;
        }
      }

      return "";
    }
    ```
  </Tab>
</Tabs>

### 4. `chat.completion.done`

Final chunk indicating the stream is complete, including final search results, usage statistics, and cost information.

<Tabs>
  <Tab title="Structure">
    ```json theme={null}
    {
      "id": "cfa38f9d-fdbc-4ac6-a5d2-a3010b6a33a6",
      "model": "sonar-pro",
      "created": 1759441595,
      "object": "chat.completion.done",
      "usage": {
        "prompt_tokens": 6,
        "completion_tokens": 238,
        "total_tokens": 244,
        "search_context_size": "low",
        "cost": {
          "input_tokens_cost": 0.0,
          "output_tokens_cost": 0.004,
          "request_cost": 0.006,
          "total_cost": 0.01
        }
      },
      "search_results": [...],
      "images": [...],
      "choices": [{
        "index": 0,
        "finish_reason": "stop",
        "message": {
          "role": "assistant",
          "content": "## Seattle Weather Forecast\n\nSeattle is experiencing...",
          "reasoning_steps": [...]
        },
        "delta": {
          "role": "assistant",
          "content": ""
        }
      }]
    }
    ```
  </Tab>

  <Tab title="Python Handler">
    ```python theme={null}
    def handle_completion_done(chunk):
        """Process stream completion"""
        if chunk.object == "chat.completion.done":
            print("\n\n[Stream Complete]")

            # Final aggregated message
            full_message = chunk.choices[0].message.content

            # Final search results
            if hasattr(chunk, 'search_results'):
                print(f"\nFinal sources: {len(chunk.search_results)}")

            # Complete usage and cost information
            if hasattr(chunk, 'usage'):
                usage = chunk.usage
                print(f"\nTokens: {usage.total_tokens}")

                if hasattr(usage, 'cost'):
                    print(f"Cost: ${usage.cost.total_cost:.4f}")

            return {
                'content': full_message,
                'search_results': getattr(chunk, 'search_results', []),
                'images': getattr(chunk, 'images', []),
                'usage': getattr(chunk, 'usage', None)
            }
    ```
  </Tab>

  <Tab title="Typescript Handler">
    ```typescript theme={null}
    function handleCompletionDone(chunk: any) {
      if (chunk.object === "chat.completion.done") {
        console.log("\n\n[Stream Complete]");

        // Final aggregated message
        const fullMessage = chunk.choices[0].message.content;

        // Final search results
        if (chunk.search_results) {
          console.log(`\nFinal sources: ${chunk.search_results.length}`);
        }

        // Complete usage and cost information
        if (chunk.usage) {
          console.log(`\nTokens: ${chunk.usage.total_tokens}`);

          if (chunk.usage.cost) {
            console.log(`Cost: $${chunk.usage.cost.total_cost.toFixed(4)}`);
          }
        }

        return {
          content: fullMessage,
          search_results: chunk.search_results || [],
          images: chunk.images || [],
          usage: chunk.usage || null
        };
      }
    }
    ```
  </Tab>
</Tabs>

## Complete Implementation Examples

### Full Concise Mode Handler

<Tabs>
  <Tab title="Python SDK">
    ```python theme={null}
    from perplexity import Perplexity

    class ConciseStreamHandler:
        def __init__(self):
            self.content = ""
            self.reasoning_steps = []
            self.search_results = []
            self.images = []
            self.usage = None

        def stream_query(self, query: str, model: str = "sonar-pro"):
            """Handle a complete concise streaming request"""
            client = Perplexity()

            stream = client.chat.completions.create(
                model=model,
                messages=[{"role": "user", "content": query}],
                stream=True,
                stream_mode="concise"
            )

            for chunk in stream:
                self.process_chunk(chunk)

            return self.get_result()

        def process_chunk(self, chunk):
            """Route chunk to appropriate handler"""
            chunk_type = chunk.object

            if chunk_type == "chat.reasoning":
                self.handle_reasoning(chunk)
            elif chunk_type == "chat.reasoning.done":
                self.handle_reasoning_done(chunk)
            elif chunk_type == "chat.completion.chunk":
                self.handle_content(chunk)
            elif chunk_type == "chat.completion.done":
                self.handle_done(chunk)

        def handle_reasoning(self, chunk):
            """Process reasoning updates"""
            delta = chunk.choices[0].delta

            if hasattr(delta, 'reasoning_steps'):
                for step in delta.reasoning_steps:
                    self.reasoning_steps.append(step)
                    print(f"💭 {step.thought}")

        def handle_reasoning_done(self, chunk):
            """Process end of reasoning"""
            if hasattr(chunk, 'search_results'):
                self.search_results = chunk.search_results
                print(f"\n🔍 Found {len(self.search_results)} sources")

            if hasattr(chunk, 'images'):
                self.images = chunk.images
                print(f"🖼️  Found {len(self.images)} images")

            print("\n📝 Generating response...\n")

        def handle_content(self, chunk):
            """Process content chunks"""
            delta = chunk.choices[0].delta

            if hasattr(delta, 'content') and delta.content:
                self.content += delta.content
                print(delta.content, end='', flush=True)

        def handle_done(self, chunk):
            """Process completion"""
            if hasattr(chunk, 'usage'):
                self.usage = chunk.usage
                print(f"\n\n✅ Complete | Tokens: {self.usage.total_tokens}")

                if hasattr(self.usage, 'cost'):
                    print(f"💰 Cost: ${self.usage.cost.total_cost:.4f}")

        def get_result(self):
            """Return complete result"""
            return {
                'content': self.content,
                'reasoning_steps': self.reasoning_steps,
                'search_results': self.search_results,
                'images': self.images,
                'usage': self.usage
            }

    # Usage
    handler = ConciseStreamHandler()
    result = handler.stream_query("What's the latest news in AI?")

    print(f"\n\nFinal content length: {len(result['content'])} characters")
    print(f"Sources used: {len(result['search_results'])}")
    ```
  </Tab>

  <Tab title="Typescript SDK">
    ```typescript theme={null}
    import Perplexity from '@perplexity-ai/perplexity_ai';

    interface StreamResult {
      content: string;
      reasoning_steps: any[];
      search_results: any[];
      images: any[];
      usage: any;
    }

    class ConciseStreamHandler {
      private content: string = "";
      private reasoning_steps: any[] = [];
      private search_results: any[] = [];
      private images: any[] = [];
      private usage: any = null;

      async streamQuery(query: string, model: string = "sonar-pro"): Promise<StreamResult> {
        const client = new Perplexity();

        const stream = await client.chat.completions.create({
          model,
          messages: [{ role: "user", content: query }],
          stream: true,
          stream_mode: "concise"
        });

        for await (const chunk of stream) {
          this.processChunk(chunk);
        }

        return this.getResult();
      }

      private processChunk(chunk: any) {
        const chunkType = chunk.object;

        switch (chunkType) {
          case "chat.reasoning":
            this.handleReasoning(chunk);
            break;
          case "chat.reasoning.done":
            this.handleReasoningDone(chunk);
            break;
          case "chat.completion.chunk":
            this.handleContent(chunk);
            break;
          case "chat.completion.done":
            this.handleDone(chunk);
            break;
        }
      }

      private handleReasoning(chunk: any) {
        const delta = chunk.choices[0].delta;

        if (delta.reasoning_steps) {
          for (const step of delta.reasoning_steps) {
            this.reasoning_steps.push(step);
            console.log(`💭 ${step.thought}`);
          }
        }
      }

      private handleReasoningDone(chunk: any) {
        if (chunk.search_results) {
          this.search_results = chunk.search_results;
          console.log(`\n🔍 Found ${this.search_results.length} sources`);
        }

        if (chunk.images) {
          this.images = chunk.images;
          console.log(`🖼️  Found ${this.images.length} images`);
        }

        console.log("\n📝 Generating response...\n");
      }

      private handleContent(chunk: any) {
        const delta = chunk.choices[0]?.delta;

        if (delta?.content) {
          this.content += delta.content;
          process.stdout.write(delta.content);
        }
      }

      private handleDone(chunk: any) {
        if (chunk.usage) {
          this.usage = chunk.usage;
          console.log(`\n\n✅ Complete | Tokens: ${this.usage.total_tokens}`);

          if (this.usage.cost) {
            console.log(`💰 Cost: $${this.usage.cost.total_cost.toFixed(4)}`);
          }
        }
      }

      private getResult(): StreamResult {
        return {
          content: this.content,
          reasoning_steps: this.reasoning_steps,
          search_results: this.search_results,
          images: this.images,
          usage: this.usage
        };
      }
    }

    // Usage
    const handler = new ConciseStreamHandler();
    const result = await handler.streamQuery("What's the latest news in AI?");

    console.log(`\n\nFinal content length: ${result.content.length} characters`);
    console.log(`Sources used: ${result.search_results.length}`);
    ```
  </Tab>

  <Tab title="Raw HTTP">
    ```python theme={null}
    import os
    import requests
    import json

    def stream_concise_mode(query: str):
        """Handle concise streaming with raw HTTP"""
        url = "https://api.perplexity.ai/v1/sonar"
        headers = {
            "Authorization": f"Bearer {os.environ.get('PERPLEXITY_API_KEY')}",
            "Content-Type": "application/json"
        }
        payload = {
            "model": "sonar-pro",
            "messages": [{"role": "user", "content": query}],
            "stream": True,
            "stream_mode": "concise"
        }

        response = requests.post(url, headers=headers, json=payload, stream=True)

        content = ""
        search_results = []
        usage = None

        for line in response.iter_lines():
            if line:
                line = line.decode('utf-8')
                if line.startswith('data: '):
                    data_str = line[6:]
                    if data_str == '[DONE]':
                        break

                    try:
                        chunk = json.loads(data_str)
                        chunk_type = chunk.get('object')

                        if chunk_type == 'chat.reasoning':
                            # Handle reasoning
                            delta = chunk['choices'][0]['delta']
                            if 'reasoning_steps' in delta:
                                for step in delta['reasoning_steps']:
                                    print(f"💭 {step['thought']}")

                        elif chunk_type == 'chat.reasoning.done':
                            # Handle reasoning completion
                            if 'search_results' in chunk:
                                search_results = chunk['search_results']
                                print(f"\n🔍 Found {len(search_results)} sources\n")

                        elif chunk_type == 'chat.completion.chunk':
                            # Handle content
                            delta = chunk['choices'][0]['delta']
                            if 'content' in delta and delta['content']:
                                content += delta['content']
                                print(delta['content'], end='', flush=True)

                        elif chunk_type == 'chat.completion.done':
                            # Handle completion
                            if 'usage' in chunk:
                                usage = chunk['usage']
                                print(f"\n\n✅ Tokens: {usage['total_tokens']}")

                    except json.JSONDecodeError:
                        continue

        return {
            'content': content,
            'search_results': search_results,
            'usage': usage
        }

    # Usage
    result = stream_concise_mode("What's the latest news in AI?")
    ```
  </Tab>
</Tabs>

## Best Practices

<Steps>
  <Step title="Aggregate content on the client side">
    In concise mode, `choices.message` is not incrementally updated. You must aggregate chunks yourself.

    ```python theme={null}
    # Track content yourself
    content = ""
    for chunk in stream:
        if chunk.object == "chat.completion.chunk":
            if chunk.choices[0].delta.content:
                content += chunk.choices[0].delta.content
    ```
  </Step>

  <Step title="Use reasoning steps for transparency">
    Display reasoning steps to users for better transparency and trust.

    ```python theme={null}
    def display_reasoning(step):
        """Show reasoning to users"""
        print(f"🔍 Searching for: {step.web_search.search_keywords}")
        print(f"💭 {step.thought}")
    ```
  </Step>

  <Step title="Handle search results from done chunks only">
    Search results and usage information only appear in `chat.reasoning.done` and `chat.completion.done` chunks.

    ```python theme={null}
    # Don't check for search_results in other chunk types
    if chunk.object in ["chat.reasoning.done", "chat.completion.done"]:
        if hasattr(chunk, 'search_results'):
            process_search_results(chunk.search_results)
    ```
  </Step>

  <Step title="Implement proper type checking">
    Use the `object` field to route chunks to appropriate handlers.

    ```python theme={null}
    chunk_handlers = {
        "chat.reasoning": handle_reasoning,
        "chat.reasoning.done": handle_reasoning_done,
        "chat.completion.chunk": handle_content,
        "chat.completion.done": handle_done
    }

    handler = chunk_handlers.get(chunk.object)
    if handler:
        handler(chunk)
    ```
  </Step>

  <Step title="Track cost from the final chunk">
    Cost information is only available in the `chat.completion.done` chunk.

    ```python theme={null}
    if chunk.object == "chat.completion.done":
        if hasattr(chunk.usage, 'cost'):
            total_cost = chunk.usage.cost.total_cost
            print(f"Request cost: ${total_cost:.4f}")
    ```
  </Step>
</Steps>

## Migration from Full Mode

If you're migrating from full mode to concise mode, here are the key changes:

<Tabs>
  <Tab title="Before (Full Mode)">
    ```python theme={null}
    from perplexity import Perplexity

    client = Perplexity()

    stream = client.chat.completions.create(
        model="sonar-pro",
        messages=[{"role": "user", "content": "What's the weather?"}],
        stream=True
        # stream_mode defaults to "full"
    )

    for chunk in stream:
        # All chunks are chat.completion.chunk
        if chunk.choices[0].delta.content:
            print(chunk.choices[0].delta.content, end="")

        # Search results may appear in multiple chunks
        if hasattr(chunk, 'search_results'):
            print(f"Sources: {len(chunk.search_results)}")
    ```
  </Tab>

  <Tab title="After (Concise Mode)">
    ```python theme={null}
    from perplexity import Perplexity

    client = Perplexity()

    stream = client.chat.completions.create(
        model="sonar-pro",
        messages=[{"role": "user", "content": "What's the weather?"}],
        stream=True,
        stream_mode="concise"  # Enable concise mode
    )

    for chunk in stream:
        # Multiple chunk types - route appropriately
        if chunk.object == "chat.reasoning":
            # New: Handle reasoning steps
            if chunk.choices[0].delta.reasoning_steps:
                print("Reasoning in progress...")

        elif chunk.object == "chat.reasoning.done":
            # New: Reasoning complete, search results available
            if hasattr(chunk, 'search_results'):
                print(f"Sources: {len(chunk.search_results)}")

        elif chunk.object == "chat.completion.chunk":
            # Content chunks (similar to full mode)
            if chunk.choices[0].delta.content:
                print(chunk.choices[0].delta.content, end="")

        elif chunk.object == "chat.completion.done":
            # Final chunk with complete metadata
            print(f"\nTotal tokens: {chunk.usage.total_tokens}")
    ```
  </Tab>
</Tabs>

## When to Use Each Mode

<CardGroup>
  <Card title="Use Full Mode" icon="clipboard-list">
    * Simple integrations where you want the SDK to handle aggregation
    * Backward compatibility with existing implementations
    * When you don't need reasoning visibility
  </Card>

  <Card title="Use Concise Mode" icon="bolt">
    * Production applications optimizing for bandwidth
    * Applications that need reasoning transparency
    * Real-time chat interfaces with reasoning display
    * Cost-sensitive applications
  </Card>
</CardGroup>

## Resources

* [Streaming Responses Guide](/docs/agent-api/output-control#streaming-responses) - General streaming documentation
* [Sonar API Guide](/docs/sonar/quickstart) - Complete Sonar API guide
* [API Reference - Sonar API](/api-reference/sonar-post) - API documentation


# Built-in Tool Capabilities
Source: https://docs.perplexity.ai/docs/sonar/pro-search/tools

Learn about Pro Search's built-in tools: web search and URL content fetching

<SonarDeprecationNotice />

## Overview

Pro Search provides two built-in tools that the model uses automatically to answer your queries. The model decides which tools to use and when, so no configuration is needed. These tools are called automatically by the system; custom tools cannot be registered.

<Info>
  All tool executions appear in the `reasoning_steps` array of streaming responses, giving you visibility into how the model researched your query.
</Info>

## web\_search

Conducts web searches to find current information, statistics, and expert opinions.

**Example in action:**

```json theme={null}
{
  "thought": "I need current data on EV market trends",
  "type": "web_search",
  "web_search": {
    "search_keywords": [
      "EV Statistics 2023-2024",
      "electric vehicle sales data",
      "global EV market trends"
    ],
    "search_results": [
      {
        "title": "Trends in electric cars",
        "url": "https://www.iea.org/reports/global-ev-outlook-2024/trends-in-electric-cars",
        "date": "2024-03-15",
        "last_updated": null,
        "snippet": "Electric car sales neared 14 million in 2023, 95% of which were in China, Europe and the United States...",
        "source": "web"
      }
    ]
  }
}
```

## fetch\_url\_content

Retrieves full content from specific URLs to access detailed information beyond search result snippets.

**Example in action:**

```json theme={null}
{
  "thought": "This research paper contains detailed methodology I need to review",
  "type": "fetch_url_content",
  "fetch_url_content": {
    "contents": [
      {
        "title": "Attention Is All You Need",
        "url": "https://arxiv.org/pdf/1706.03762",
        "date": null,
        "last_updated": null,
        "snippet": "The dominant sequence transduction models are based on complex recurrent or convolutional neural networks that include an encoder and a decoder...",
        "source": "web"
      }
    ]
  }
}
```

## Multi-Tool Workflows

The model automatically combines multiple tools when needed. For example, when asked to research solar panel options, it might:

1. Use `web_search` to find current incentives and costs
2. Use `fetch_url_content` to read detailed policy documents
3. Use `web_search` again to verify electricity rates and compare providers

## Related Resources

<CardGroup>
  <Card title="Quickstart" icon="rocket" href="/docs/sonar/pro-search/quickstart">
    Get started with Pro Search basics
  </Card>

  <Card title="Stream Mode Guide" icon="bolt" href="/docs/sonar/pro-search/stream-mode">
    Learn about streaming and real-time reasoning visibility
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/sonar-post">
    Complete API documentation
  </Card>
</CardGroup>


# Prompt Guide
Source: https://docs.perplexity.ai/docs/sonar/prompt-guide

Sonar-specific prompting guidance and how it differs from the Agent API.

<SonarDeprecationNotice />

The shared prompting best practices live in the [Agent API Prompt Guide](/docs/agent-api/prompt-guide) and apply to Sonar without modification — be specific, cap result counts, don't ask for URLs in prose, avoid few-shot content, and prefer parameters over prose for filters.

This page covers the one structural difference that changes how Sonar is prompted: the system prompt does not influence search.

## Shape Search Through the User Message

Sonar runs a web search before generating its answer, and only the user message is used to drive that search. The system prompt is not visible to search; it reaches the model only at answer time, when results are already in hand. Use the system prompt for tone, style, and grounding rules, but treat the user message as both the question for the model and the seed for the search.

The practical consequence: phrasing in the user message directly affects which sources show up. A specific, descriptive question produces better results than a vague one, and a polished system prompt cannot rescue a vague user message. If retrieval quality matters, invest there first.

**Good Example**: "What guidance has the FDA issued on AI in medical devices in the past year, and which device categories does it cover?"

**Poor Example**: "Tell me about FDA AI rules."

<Warning>
  Do not put search instructions in the system prompt. Phrases like "search only on Wikipedia" or "look for the latest results" have no effect. For hard constraints like domain, recency, or region, use the dedicated [search filter parameters](/docs/sonar/filters) on the request body rather than trying to express the constraint in prose.
</Warning>

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  completion = client.chat.completions.create(
      model="sonar",
      messages=[
          {"role": "user", "content": "Summarize the FDA's regulatory framework for Software as a Medical Device (SaMD), including the Pre-Cert program."}
      ],
      search_domain_filter=["fda.gov"],
      search_recency_filter="month"
  )

  print(completion.choices[0].message.content)
  ```

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

  const client = new Perplexity();

  const completion = await client.chat.completions.create({
    model: "sonar",
    messages: [
      { role: "user", content: "Summarize the FDA's regulatory framework for Software as a Medical Device (SaMD), including the Pre-Cert program." }
    ],
    search_domain_filter: ["fda.gov"],
    search_recency_filter: "month"
  });

  console.log(completion.choices[0].message.content);
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/sonar \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "sonar",
      "messages": [
        {"role": "user", "content": "Summarize the FDA\u0027s regulatory framework for Software as a Medical Device (SaMD), including the Pre-Cert program."}
      ],
      "search_domain_filter": ["fda.gov"],
      "search_recency_filter": "month"
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "da79e65e-93df-4ef4-8a0c-78027f264bd3",
    "choices": [
      {
        "delta": {
          "content": "",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "index": 0,
        "message": {
          "content": "The FDA regulates **Software as a Medical Device (SaMD)** under the existing medical device statutory framework (FD&C Act), using risk‑based classification and traditional premarket pathways (510(k), De Novo, PMA), guided by IMDRF SaMD principles; the **Digital Health Center of Excellence** coordinates SaMD policy.[1][3][4] The **Software Precertification (Pre‑Cert) Pilot Program** was an experimental, time‑limited initiative to explore an organization‑based, streamlined approach for digital health software, but it has not been adopted as a standing alternative pathway and is no longer accepting participants.[7]  \n\nBelow is a concise, framework‑oriented summary.\n\n---\n\n### 1. Definition and scope of SaMD\n\n- FDA adopts the IMDRF definition of **SaMD** as: **software intended for one or more medical purposes that performs those purposes without being part of a hardware medical device**.[1][2]  \n- Key clarifications:[2]  \n  - Runs on **general‑purpose platforms** (PC, smartphone, cloud).[2]  \n  - Not SaMD if the software is necessary to **drive or control a hardware medical device** (that is treated as “software in a medical device,” SiMD).[2]  \n  - Mobile apps meeting this definition are regulated as SaMD.[1][2]  \n\nSaMD is therefore regulated as a **medical device “device software function”**; FDA provides examples of regulated device software functions, especially mobile apps that diagnose, treat, or transform a mobile platform into a medical device.[5]\n\n---\n\n### 2. Risk classification and basic regulatory posture\n\n- SaMD is classified into **Class I, II, or III** under the same risk‑based device classification system applied to other medical devices.[2]  \n- IMDRF also provides a **SaMD risk categorization framework (I–IV)** based on:  \n  - **State of the healthcare condition** (e.g., critical, serious, non‑serious) and  \n  - The **significance of the information** the SaMD provides (treat/diagnose, drive clinical management, inform clinical management).[3]  \n- FDA, which chaired the IMDRF SaMD work, references these IMDRF categories to inform its own risk thinking, although IMDRF documents themselves are not binding U.S. regulations.[1][3]  \n\nRegulatory requirements (e.g., premarket submission type, clinical evidence depth, controls) increase with device class and risk category.[2][3][4]\n\n---\n\n### 3. Core regulatory requirements for SaMD\n\nAlthough the specifics depend on device class and intended use, SaMD manufacturers generally must:\n\n**a. Meet device‑level and software‑specific regulations**\n\n- Comply with **21 CFR Part 820** (Quality System Regulation) and related quality system expectations.[2][3]  \n- For electronic records/signatures, comply with **21 CFR Part 11** where applicable.[2]  \n- Implement a software lifecycle consistent with **IEC 62304**; FDA and IMDRF recognize this as a key standard for medical device software.[2][3]  \n\n**b. Use risk‑based software documentation (“level of concern”)**\n\nFDA software guidance uses three **levels of concern** based on potential harm if the software fails:[2]  \n\n- **Minor** – unlikely to cause injury.  \n- **Moderate** – could lead to minor injury, including via incorrect/delayed information or provider actions.[2]  \n- **Major** – could directly result in serious injury or death, including via incorrect/delayed information.[2]  \n\nThe required **software documentation** in a submission scales with this level of concern.[2]\n\n**c. Conduct clinical evaluation**\n\n- FDA participates in IMDRF and has issued **“Software as a Medical Device: Clinical Evaluation”** guidance, describing how regulators evaluate **safety, effectiveness, and performance** of SaMD.[3]  \n- This guidance is currently positioned as a **harmonized framework** and does **not change existing submission requirements**, but informs how clinical evidence should be generated and justified for SaMD.[3]  \n\n**d. Premarket review pathways**\n\nSaMD that meets the device definition and is not exempt will go through an appropriate pathway:[4]  \n\n- **510(k) premarket notification** – for most moderate‑risk SaMD with a predicate device.  \n- **De Novo classification** – for novel, low‑ to moderate‑risk SaMD without a predicate.  \n- **Premarket approval (PMA)** – for high‑risk Class III SaMD.  \n\nFDA may also require review of **significant software modifications** (e.g., new indications, major algorithm changes), including for AI/ML SaMD.[4]\n\n**e. Post‑market surveillance and change control**\n\n- Manufacturers must monitor and act on: customer feedback, complaints, vigilance events, trend reports, clinical data, and usage/usability data.[2]  \n- For SaMD, post‑market oversight is complemented by software‑specific monitoring:  \n  - Field and internal **software issues**,  \n  - **SOUP** (Software of Unknown Provenance) issues (new versions, obsolescence),  \n  - **Cybersecurity** vulnerabilities.[2]  \n- Change control processes and validation of **updates and upgrades** are critical because SaMD is frequently updated.[2][4][7]  \n\n---\n\n### 4. IMDRF‑aligned SaMD framework elements\n\nFDA’s SaMD thinking is anchored in IMDRF documents, which are **nonbinding but influential**.[1][3] Key elements include:\n\n- **Risk categorization (I–IV)** based on clinical context and use of the information.[3]  \n- A SaMD‑specific **Quality Management System (QMS)** concept that interprets generic device QMS requirements for software (e.g., configuration management, problem resolution, verification/validation).[3]  \n- The **clinical evaluation framework** for SaMD, covering valid clinical association, analytical validation, and clinical validation.[3]  \n\nFDA uses these to shape expectations and guidance but still applies **U.S. device law and regulation** as the legal basis.[3]\n\n---\n\n### 5. AI/ML‑enabled SaMD\n\nAI/ML‑based SaMD is subject to the same overarching framework, with additional guidance:\n\n- FDA acknowledges that traditional, “locked” software assumptions do not fully fit **adaptive AI/ML SaMD**, where models may evolve post‑market.[4][7]  \n- Key FDA actions and documents for AI/ML device software functions include:[4]  \n  - 2019 **AI/ML SaMD Discussion Paper** on a proposed regulatory framework for AI/ML SaMD modifications.[4][7]  \n  - 2021 **AI/ML SaMD Action Plan**.[4][7]  \n  - Guidance and principles on **Good Machine Learning Practice**, **Predetermined Change Control Plans (PCCPs)**, and **transparency** for ML‑enabled devices.[4]  \n  - Draft guidance (2025) on **AI‑enabled device software functions: lifecycle management and marketing submission recommendations**, intended to be used in addition to existing device guidances.[4]  \n\nFor AI/ML SaMD, FDA emphasizes:\n\n- Clearly defined **intended use and algorithm behavior**,  \n- Robust **training and test data** practices,  \n- Use of **PCCPs** to pre‑specify allowable algorithm changes and verification/validation methods,  \n- Ongoing **post‑market performance monitoring**.[4][7][8]  \n\n---\n\n### 6. Software Pre‑Certification (Pre‑Cert) Program\n\n**Purpose and concept**\n\n- The **Digital Health Software Precertification (Pre‑Cert) Pilot Program** was launched to explore a **more agile, organization‑based approach** to software oversight.[7]  \n- Conceptually, it aimed to evaluate:[7]  \n  - The **developer’s organization** (culture of quality and organizational excellence),  \n  - Combine this with **streamlined premarket review** and **robust real‑world performance monitoring**,  \n  - Potentially enable lower‑burden review for firms that demonstrated strong processes and track record.  \n\n**Key features (pilot concept)**[7][8]:\n\n- **Excellence appraisal** of the company (rather than just the product).  \n- A **streamlined review** for certain SaMD products from “pre‑certified” organizations.  \n- **Real‑world performance analytics** to continuously assure safety and effectiveness.  \n\n**Status and outcome**\n\n- The Pre‑Cert program was explicitly a **pilot**, implemented under existing statutory authorities and limited in scope.[7]  \n- FDA has since indicated that insights from the pilot will inform future digital health policies and potential legislative needs, but the **program itself is not a standing, general‑use regulatory pathway**, and enrollment of new participants has ended.[7]  \n- For now, SaMD developers must rely on **existing device pathways** (510(k), De Novo, PMA) and guidances, not on Pre‑Cert, for actual market access.[4][7]  \n\n---\n\n### 7. Practical takeaway for SaMD developers\n\nIn practice, to bring SaMD to the U.S. market, a manufacturer should:\n\n- Determine whether the software is **SaMD vs. SiMD vs. non‑device** using FDA and IMDRF definitions and examples.[1][2][5][6]  \n- Identify the device’s **intended use**, risk, and likely **Class I/II/III** classification.[2][3]  \n- Set up a **QMS compliant with 21 CFR 820**, aligned with **IEC 62304** and IMDRF SaMD QMS principles.[2][3]  \n- Develop a **clinical evaluation plan** consistent with the SaMD Clinical Evaluation guidance and risk level.[3]  \n- Choose the appropriate **premarket pathway** (exemption, 510(k), De Novo, PMA) and prepare software documentation appropriate to the **level of concern**.[2][4]  \n- Implement robust **post‑market surveillance, cybersecurity, and change control**, especially for frequently updated or AI/ML‑enabled SaMD.[2][4][7]  \n\nIf you want, I can next map this framework to a concrete example (e.g., a diagnostic imaging SaMD or a patient‑facing dosing calculator) and outline what its submission package and evidence would typically look like.",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "finish_reason": "stop"
      }
    ],
    "created": 1779896066,
    "model": "sonar-pro",
    "citations": [
      "https://www.fda.gov/medical-devices/digital-health-center-excellence/software-medical-device-samd",
      "https://www.cognidox.com/blog/how-is-software-as-a-medical-device-regulated-by-fda",
      "https://www.fda.gov/medical-devices/software-medical-device-samd/global-approach-software-medical-device",
      "https://www.fda.gov/medical-devices/software-medical-device-samd/artificial-intelligence-software-medical-device",
      "https://www.fda.gov/medical-devices/device-software-functions-including-mobile-medical-applications/examples-device-software-functions-fda-regulates",
      "https://pmc.ncbi.nlm.nih.gov/articles/PMC12264609/",
      "https://www.greenlight.guru/blog/samd-software-as-a-medical-device",
      "https://namsa.com/resources/blog/fdas-regulation-of-ai-ml-samd/",
      "https://www.rimsys.io/blogs/software-as-a-medical-device-samd"
    ],
    "object": "chat.completion",
    "search_results": [
      {
        "title": "Software as a Medical Device (SaMD) - FDA",
        "url": "https://www.fda.gov/medical-devices/digital-health-center-excellence/software-medical-device-samd",
        "date": "2018-12-04",
        "last_updated": "2026-05-16",
        "snippet": "SaMD is defined as \"software intended to be used for one or more medical purposes that perform these purposes without being part of a ...",
        "source": "web"
      },
      {
        "title": "How is SaMD regulated by the FDA? - Cognidox",
        "url": "https://www.cognidox.com/blog/how-is-software-as-a-medical-device-regulated-by-fda",
        "date": "2023-01-27",
        "last_updated": "2026-05-13",
        "snippet": "The FDA classifies SaMD using the same risk classes they use for medical devices: Class I, Class II, and Class III.",
        "source": "web"
      },
      {
        "title": "Global Approach to Software as a Medical Device - FDA",
        "url": "https://www.fda.gov/medical-devices/software-medical-device-samd/global-approach-software-medical-device",
        "date": "2022-09-27",
        "last_updated": "2026-05-05",
        "snippet": "The IMDRF Software as a Medical Device framework provides harmonized quality management principles for the FDA, along with other regulators, to ...",
        "source": "web"
      },
      {
        "title": "Artificial Intelligence in Software as a Medical Device - FDA",
        "url": "https://www.fda.gov/medical-devices/software-medical-device-samd/artificial-intelligence-software-medical-device",
        "date": "2025-03-25",
        "last_updated": "2026-05-23",
        "snippet": "The FDA reviews medical devices through an appropriate premarket pathway, such as premarket clearance (510(k)), De Novo classification, or ...",
        "source": "web"
      },
      {
        "title": "Examples of Device Software Functions the FDA Regulates",
        "url": "https://www.fda.gov/medical-devices/device-software-functions-including-mobile-medical-applications/examples-device-software-functions-fda-regulates",
        "date": "2026-05-20",
        "last_updated": "2026-05-22",
        "snippet": "This list provides examples of software functions that are considered medical devices and on which the FDA will focus its regulatory oversight.",
        "source": "web"
      },
      {
        "title": "United States Food and Drug Administration Regulation of Clinical ...",
        "url": "https://pmc.ncbi.nlm.nih.gov/articles/PMC12264609/",
        "date": "2025-05-27",
        "last_updated": "2026-03-31",
        "snippet": "The FDA has published guidelines to help manufacturers determine if their software technology is a medical device that requires SaMD classification and FDA ...",
        "source": "web"
      },
      {
        "title": "Software as a Medical Device (SaMD): The Ultimate Guide to ...",
        "url": "https://www.greenlight.guru/blog/samd-software-as-a-medical-device",
        "date": "2025-05-05",
        "last_updated": "2026-05-26",
        "snippet": "In 2019, FDA released a Proposed Regulatory Framework for Modifications to Artificial Intelligence/Machine Learning (AI/ML)-Based Software ...",
        "source": "web"
      },
      {
        "title": "FDA's Regulation of AI/ML SaMD - NAMSA",
        "url": "https://namsa.com/resources/blog/fdas-regulation-of-ai-ml-samd/",
        "date": "2024-09-25",
        "last_updated": "2026-02-14",
        "snippet": "Of course, any software that meets the Act's definition of a medical device will indeed come under FDA's purview. But there are specific ...",
        "source": "web"
      },
      {
        "title": "Software as a medical device (SAMD) - classification overview",
        "url": "https://www.rimsys.io/blogs/software-as-a-medical-device-samd",
        "date": "2026-04-03",
        "last_updated": "2026-05-27",
        "snippet": "Software as a Medical Device (SaMD) has emerged as a separate medical device category that is regulated in the U.S., the European Union, other countries.",
        "source": "web"
      }
    ],
    "status": null,
    "type": null,
    "usage": {
      "completion_tokens": 2176,
      "cost": {
        "input_tokens_cost": 8e-05,
        "output_tokens_cost": 0.03264,
        "total_cost": 0.03872,
        "citation_tokens_cost": null,
        "reasoning_tokens_cost": null,
        "request_cost": 0.006,
        "search_queries_cost": null
      },
      "prompt_tokens": 26,
      "total_tokens": 2202,
      "citation_tokens": null,
      "num_search_queries": null,
      "reasoning_tokens": null,
      "search_context_size": "low"
    }
  }
  ```
</Accordion>

This contrasts with the Agent API, where `instructions` are re-read on every turn of the agent loop and shape both tool calls and the final answer. In Sonar, `instructions` has no equivalent. System messages only influence generation, never retrieval.

## Reduce Hallucinations

LLMs are tuned to be helpful, which can occasionally lead them to provide an answer when search results are thin or off-target rather than flagging the gap. The system prompt doesn't shape the search step itself, but it does shape how the model uses the search results when writing the final response, which makes it the right place for grounding rules. Two short additions cover most of these edge cases.

**Give the model permission to say it didn't find anything.** With an explicit out in the system prompt, the model is more likely to acknowledge insufficient results instead of leaning on training data to fill the gap.

```text System Prompt theme={null}
Only answer using the search results provided. If the results do not contain the answer, say so explicitly rather than guessing.
```

**Require disclosure of near-misses.** Search sometimes returns related but non-matching results (a different year, a parent company instead of a subsidiary, a similar product). Asking the model to surface the mismatch up front keeps these cases from being presented as direct answers.

```text System Prompt theme={null}
If the search results are related but do not match the question (a different year, a parent company, or a similar product), state the mismatch explicitly before answering.
```

## What Carries Over from the Agent API Guide

The same core prompting rules apply with no changes:

* **Be specific and descriptive** in the user message. Vague queries produce scattered results.
* **Cap result counts.** If a list is needed, say how long.
* **Don't few-shot content.** Pasting a written-out example answer can cause the search step to latch onto the example topic. Few-shotting *structure* is fine; for guaranteed shape use `response_format`.
* **Don't ask for URLs in the response text.** Sonar always returns sources in the top-level `citations` and `search_results` fields. Read them from there.
* **Use parameters, not prose, for filters.** The search backend reads parameters; it does not read the system prompt.

## Next Steps

<CardGroup>
  <Card title="Agent API Prompt Guide" icon="book" href="/docs/agent-api/prompt-guide">
    The full prompting guide. Most rules apply to Sonar as well.
  </Card>

  <Card title="Search Filters" icon="magnifying-glass" href="/docs/sonar/filters">
    Domain, recency, and date filters for narrowing Sonar search results.
  </Card>

  <Card title="Pro Search" icon="layer-group" href="/docs/sonar/pro-search/quickstart">
    Multi-step search and reasoning when single-shot is not enough.
  </Card>

  <Card title="Agent API Quickstart" icon="rocket" href="/docs/agent-api/quickstart">
    Recommended for new applications. Multi-turn loop and custom tools.
  </Card>
</CardGroup>


# Sonar API
Source: https://docs.perplexity.ai/docs/sonar/quickstart

Get started with Perplexity's Sonar API for web-grounded AI responses. Make your first API call in minutes.

<SonarDeprecationNotice />

## Overview

The Sonar API provides web-grounded chat completions using Perplexity's Sonar models through an OpenAI-compatible interface. You can use it with OpenAI-compatible client libraries or our native SDKs for type safety and enhanced features.

<Tip>
  Keep using your existing OpenAI SDKs to get started fast; switch to our [native SDKs](/docs/sdk/overview) later as needed.
</Tip>

<Card title="Pricing" icon="receipt" href="/docs/getting-started/pricing">
  Pay-as-you-go pricing for all APIs. No subscription required.
</Card>

## Installation

Install the SDK for your preferred language:

<CodeGroup>
  ```bash Python theme={null}
  pip install perplexityai
  ```

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

  ```bash OpenAI Python (Compatible) theme={null}
  pip install openai
  ```

  ```bash OpenAI Typescript (Compatible) theme={null}
  npm install openai
  ```
</CodeGroup>

## Authentication

Set your API key as an environment variable. The SDK will automatically read it:

<Tabs>
  <Tab title="macOS/Linux">
    ```bash theme={null}
    export PERPLEXITY_API_KEY="your_api_key_here"
    ```
  </Tab>

  <Tab title="Windows">
    ```powershell theme={null}
    setx PERPLEXITY_API_KEY "your_api_key_here"
    ```
  </Tab>
</Tabs>

<Info>
  All SDK examples below automatically use the `PERPLEXITY_API_KEY` environment variable. You can also pass the key explicitly if needed.
</Info>

## Generating an API Key

<Card title="Get your Perplexity API Key" icon="key" href="https://console.perplexity.ai/group/keys">
  Generate a new key on the **API Keys** page in the API Console.
</Card>

<Note>
  **OpenAI SDK Compatible:** Perplexity's API supports the OpenAI Chat Completions format. You can use OpenAI client libraries by pointing to our endpoint.
</Note>

## Basic Usage

### Non-Streaming Request

<CodeGroup>
  ```python Python SDK theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  completion = client.chat.completions.create(
      model="sonar-pro",
      messages=[
          {"role": "user", "content": "What is quantum computing, what is a qubit, and what distinguishes NISQ-era machines from fault-tolerant systems?"}
      ]
  )

  print(completion.choices[0].message.content)
  ```

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

  const client = new Perplexity();

  const completion = await client.chat.completions.create({
      model: "sonar-pro",
      messages: [
          { role: "user", content: "What is quantum computing, what is a qubit, and what distinguishes NISQ-era machines from fault-tolerant systems?" }
      ],
  });

  console.log(completion.choices[0].message.content);
  ```

  ```python OpenAI Python SDK theme={null}
  import os
  from openai import OpenAI

  client = OpenAI(
      api_key=os.environ.get("PERPLEXITY_API_KEY"),
      base_url="https://api.perplexity.ai"
  )

  resp = client.chat.completions.create(
      model="sonar-pro",
      messages=[
          {"role": "user", "content": "What is quantum computing, what is a qubit, and what distinguishes NISQ-era machines from fault-tolerant systems?"}
      ]
  )
  print(resp.choices[0].message.content)
  ```

  ```typescript OpenAI Typescript SDK theme={null}
  import OpenAI from 'openai';

  const client = new OpenAI({
      apiKey: process.env.PERPLEXITY_API_KEY,
      baseURL: "https://api.perplexity.ai"
  });

  const resp = await client.chat.completions.create({
      model: "sonar-pro",
      messages: [
          { role: "user", content: "What is quantum computing, what is a qubit, and what distinguishes NISQ-era machines from fault-tolerant systems?" }
      ],
  });
  console.log(resp.choices[0].message.content);
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/sonar \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "sonar-pro",
      "messages": [
        {
          "role": "user",
          "content": "What is quantum computing, what is a qubit, and what distinguishes NISQ-era machines from fault-tolerant systems?"
        }
      ]
    }' | jq
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "74c299b6-fac7-45af-a69f-e0d08be695e5",
    "choices": [
      {
        "delta": {
          "content": "",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "index": 0,
        "message": {
          "content": "Quantum computing is a model of computation that uses **quantum-mechanical effects such as superposition and entanglement** to process information in ways that can outperform classical computers on certain problems.[1][2][7] A **qubit** is the basic unit of quantum information: unlike a classical bit that is strictly 0 or 1, a qubit can be in a **superposition** of 0 and 1 and can be **entangled** with other qubits.[1][2][7] **NISQ-era machines** are today’s small, noisy quantum processors with limited qubit counts and high error rates, while **fault-tolerant systems** are future quantum computers designed to operate reliably at scale using quantum error correction to suppress noise and run long, complex algorithms.[1][2][7]  \n\n---\n\n### 1. What is quantum computing?\n\n- Quantum computing is a **computing paradigm that uses quantum mechanics**—the physics of very small systems—to perform computation.[1][2][5][7]  \n- A quantum computer manipulates **qubits** using quantum gates and algorithms, exploiting:\n  - **Superposition**: a qubit can exist in a combination of \\(|0\\rangle\\) and \\(|1\\rangle\\) simultaneously until measured.[1][2][4][7]  \n  - **Entanglement**: correlations between qubits such that the state of one is linked to the state of another, even when separated.[1][4][7]  \n  - **Quantum interference**: amplitudes for different computational paths can add or cancel, allowing algorithms to amplify correct answers and suppress wrong ones.[2][4][7]  \n\nThese properties allow quantum computers to potentially solve certain specialized problems (e.g., some optimization, simulation, factoring, and chemistry problems) **much faster or more efficiently** than any classical computer can.[1][2][6][9]  \n\n---\n\n### 2. What is a qubit?\n\n- A **qubit (quantum bit)** is the quantum analogue of the classical bit and is the **fundamental unit of information** in a quantum computer.[1][2][7][8]  \n- A classical bit is always **either** 0 **or** 1 at any given time.[1][2]  \n- A qubit can be in a state  \n  \\[\n  |\\psi\\rangle = \\alpha|0\\rangle + \\beta|1\\rangle,\n  \\]\n  where \\(\\alpha\\) and \\(\\beta\\) are complex numbers with \\(|\\alpha|^2 + |\\beta|^2 = 1\\). This is **superposition** of 0 and 1.[1][2][4][7]  \n- When you **measure** a qubit, you get 0 with probability \\(|\\alpha|^2\\) and 1 with probability \\(|\\beta|^2\\); the state “collapses” to the outcome.[4][7]  \n- Multiple qubits can be prepared in **entangled states**, where you cannot describe each qubit independently—measuring one instantaneously constrains the possible outcomes for the others.[1][4][7]  \n\n**Physical realizations of qubits** include:[1][4][6][7]  \n- **Superconducting circuits** (used by IBM, Google, etc.)  \n- **Trapped ions** (charged atoms held by electromagnetic fields)  \n- **Photons** (polarization or path as qubits)  \n- **Spin of electrons or nuclei**, quantum dots, and other “artificial atoms”  \n\nWhat matters is that the physical system has two well-defined quantum states that can be controlled and measured as \\(|0\\rangle\\) and \\(|1\\rangle\\), plus the ability to create superposition and entanglement between them.[1][4]  \n\n---\n\n### 3. NISQ-era machines vs. fault-tolerant systems\n\nResearchers often divide practical quantum hardware into two broad regimes:\n\n| Aspect | **NISQ-era machines** | **Fault-tolerant quantum computers** |\n|-------|------------------------|--------------------------------------|\n| Acronym / meaning | **NISQ** = *Noisy Intermediate-Scale Quantum* | Large-scale, **error-corrected** quantum systems |\n| Qubit count | Tens to a few hundred **physical** qubits | Thousands to millions of **physical** qubits to realize thousands–millions of **logical** qubits |\n| Noise & errors | High error rates; **noisy qubits and gates**; limited coherence times | Logical qubits have very **low effective error rates** via quantum error correction |\n| Error correction | Generally **no full error correction**; at best small error-mitigation techniques | **Full quantum error correction**, using many physical qubits to protect each logical qubit |\n| Algorithm depth | Can run only **shallow circuits** (limited gate depth) before noise destroys the computation | Can run **deep, long-running algorithms** (e.g., full-scale Shor, large simulations) |\n| Practical status | Represents **current quantum processors** from major vendors; useful mainly for research, demonstrations, and early applications | **Still a goal**; no fully fault-tolerant, large-scale machine exists yet[1][2][6][7] |\n| Use cases | Exploratory work: small-scale optimization, chemistry toy models, benchmarking, development of algorithms and compilers | Targeted for **scalable, reliable quantum advantage** in cryptography, complex simulation, large optimization, etc.[1][2][6][7] |\n\n**Key distinguishing ideas:**\n\n1. **Noise vs. fault tolerance**  \n   - NISQ devices are *inherently noisy*; each gate, measurement, and qubit has a significant chance of error, and computations quickly become unreliable as circuits grow.[1][2][7][8]  \n   - Fault-tolerant systems use **quantum error-correcting codes** to detect and correct errors without measuring and destroying the underlying quantum information (using operations like syndrome extraction). This lets them run long algorithms while keeping the overall error probability acceptably low.[1][2][7]  \n\n2. **Physical vs. logical qubits**  \n   - A **physical qubit** is one directly implemented in hardware (e.g., a single superconducting circuit or trapped ion). Current machines are described by their physical qubit counts (e.g., 50–100 qubits).[1][2]  \n   - A **logical qubit** is a robust, error-corrected qubit encoded across many physical qubits. Fault-tolerant machines will be described in terms of logical qubits, but will require many more physical qubits underneath.  \n\n3. **Scale and algorithm capability**  \n   - NISQ devices can demonstrate interesting quantum behavior and may achieve **limited, problem-specific advantages**, but they are not reliable enough for general-purpose quantum algorithms at useful scales.[1][2][6]  \n   - Fault-tolerant systems are the theoretical model assumed in most major quantum algorithms (e.g., large-scale Shor and Grover), enabling **provable, large quantum speedups** on certain tasks.  \n\nIf you’d like, I can follow up with a more math-focused explanation of qubits (Dirac notation, Bloch sphere) or a more application-focused view (what NISQ devices might realistically be used for in the near term).",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "finish_reason": "stop"
      }
    ],
    "created": 1779896060,
    "model": "sonar-pro",
    "citations": [
      "https://scienceexchange.caltech.edu/topics/quantum-science-explained/quantum-computing-computers",
      "https://aws.amazon.com/what-is/quantum-computing/",
      "https://www.youtube.com/watch?v=B3U1NDUiwSA",
      "https://www.youtube.com/watch?v=Kv8N9alyYNc",
      "https://www.nist.gov/quantum-information-science/quantum-computing-explained",
      "https://www.ibm.com/think/topics/quantum-computing",
      "https://en.wikipedia.org/wiki/Quantum_computing",
      "https://www.bluequbit.io/blog/quantum-computing-basics",
      "https://www.mckinsey.com/featured-insights/mckinsey-explainers/what-is-quantum-computing"
    ],
    "object": "chat.completion",
    "search_results": [
      {
        "title": "What Is Quantum Computing? - Caltech Science Exchange",
        "url": "https://scienceexchange.caltech.edu/topics/quantum-science-explained/quantum-computing-computers",
        "date": null,
        "last_updated": "2026-05-26",
        "snippet": "Quantum computers will help us learn about, model, and manipulate other quantum systems. That ability will improve our understanding of physics.",
        "source": "web"
      },
      {
        "title": "What is Quantum Computing? - AWS",
        "url": "https://aws.amazon.com/what-is/quantum-computing/",
        "date": "2026-05-13",
        "last_updated": "2026-05-18",
        "snippet": "Quantum computing is a multidisciplinary field comprising aspects of computer science, physics, and mathematics that utilizes quantum mechanics to solve ...",
        "source": "web"
      },
      {
        "title": "Quantum Computers Explained: How Quantum Computing Works",
        "url": "https://www.youtube.com/watch?v=B3U1NDUiwSA",
        "date": "2024-09-23",
        "last_updated": "2026-05-16",
        "snippet": "Quantum Computing is the ability to predict the outcome of all possible paths simultaneously and choosing the best path to achieve the ...",
        "source": "web"
      },
      {
        "title": "Quantum Computers: Explained VISUALLY - YouTube",
        "url": "https://www.youtube.com/watch?v=Kv8N9alyYNc",
        "date": "2025-04-22",
        "last_updated": "2026-05-24",
        "snippet": "In this video we take a visual look at the math of quantum computing. Also, check out this video on different types of quantum computers ...",
        "source": "web"
      },
      {
        "title": "Quantum Computing Explained | NIST",
        "url": "https://www.nist.gov/quantum-information-science/quantum-computing-explained",
        "date": "2025-03-18",
        "last_updated": "2026-05-23",
        "snippet": "These computers work by harnessing quantum physics — the strange, often counterintuitive laws that govern the universe at its smallest scales ...",
        "source": "web"
      },
      {
        "title": "What Is Quantum Computing? - IBM",
        "url": "https://www.ibm.com/think/topics/quantum-computing",
        "date": "2025-06-10",
        "last_updated": "2026-03-31",
        "snippet": "Quantum computing is an emergent field of computer science and engineering that harnesses the unique qualities of quantum mechanics to solve problems",
        "source": "web"
      },
      {
        "title": "Quantum computing - Wikipedia",
        "url": "https://en.wikipedia.org/wiki/Quantum_computing",
        "date": "2001-10-21",
        "last_updated": "2026-05-27",
        "snippet": "A quantum computer is a real or theoretical computer that exploits quantum phenomena like superposition and entanglement in an essential way.",
        "source": "web"
      },
      {
        "title": "Quantum Computing Basics: A Beginner's Guide - BlueQubit",
        "url": "https://www.bluequbit.io/blog/quantum-computing-basics",
        "date": "2026-04-27",
        "last_updated": "2026-05-11",
        "snippet": "Quantum computing is a type of computing that uses the principles of quantum mechanics to process information. Unlike classical computers, which ...",
        "source": "web"
      },
      {
        "title": "What is quantum computing? - McKinsey",
        "url": "https://www.mckinsey.com/featured-insights/mckinsey-explainers/what-is-quantum-computing",
        "date": "2025-03-31",
        "last_updated": "2026-05-27",
        "snippet": "Quantum computing is a new approach to calculation that uses principles of fundamental physics to solve extremely complex problems very quickly.",
        "source": "web"
      }
    ],
    "status": null,
    "type": null,
    "usage": {
      "completion_tokens": 1541,
      "cost": {
        "input_tokens_cost": 8e-05,
        "output_tokens_cost": 0.02312,
        "total_cost": 0.0292,
        "citation_tokens_cost": null,
        "reasoning_tokens_cost": null,
        "request_cost": 0.006,
        "search_queries_cost": null
      },
      "prompt_tokens": 28,
      "total_tokens": 1569,
      "citation_tokens": null,
      "num_search_queries": null,
      "reasoning_tokens": null,
      "search_context_size": "low"
    }
  }
  ```
</Accordion>

### Streaming Response

<CodeGroup>
  ```python Python SDK theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  stream = client.chat.completions.create(
      model="sonar-pro",
      messages=[
          {"role": "user", "content": "What are the most widely used open-source large language models that serve as alternatives to OpenAI's GPT models?"}
      ],
      stream=True
  )

  for chunk in stream:
      if chunk.choices[0].delta.content:
          print(chunk.choices[0].delta.content, end="")
  ```

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

  const client = new Perplexity();

  const stream = await client.chat.completions.create({
      model: "sonar-pro",
      messages: [
          { role: "user", content: "What are the most widely used open-source large language models that serve as alternatives to OpenAI's GPT models?" }
      ],
      stream: true,
  });

  for await (const chunk of stream) {
      if (chunk.choices[0].delta.content) {
          process.stdout.write((chunk.choices[0]?.delta?.content ?? '') as string);
      }
  }
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/sonar \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "sonar-pro",
      "messages": [
        {
          "role": "user",
          "content": "What are the most popular open-source alternatives to OpenAI'\''s GPT models?"
        }
      ],
      "stream": true
    }'
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "id": "38678936-bd01-4447-ad3a-196dce1cea08",
    "choices": [
      {
        "delta": {
          "content": "",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "index": 0,
        "message": {
          "content": "Here are the most widely used and actively maintained open‑source (or open‑weight) alternatives to OpenAI’s GPT models, based on the sources you provided plus current ecosystem reality. I’ll group them by how general‑purpose and “GPT‑like” they are.\n\n---\n\n## 1. Llama 3 (and Llama 2) – Meta\n\n**Why it’s popular**\n\n- Currently the *de facto* standard open‑weight GPT alternative for general use.\n- Strong performance on coding, chat, and general reasoning.\n- Huge ecosystem: quantized builds, fine‑tunes, tools, and UIs (Ollama, LM Studio, etc.).\n\n**Key points**\n\n- **Developer**: Meta (FAIR).\n- **Models**: Llama 3 8B, 70B (and Llama 2 7B/13B/70B).\n- **Use cases**: Chatbots, coding assistants, content generation, RAG apps.\n- **License**: Custom “open‑weight” license (free but with some restrictions for large‑scale commercial use).\n\n---\n\n## 2. Qwen – Alibaba\n\n**Why it’s popular**\n\n- Competitive performance with Llama in many benchmarks.\n- Strong multilingual support (especially English + Chinese).\n- Many model variants and sizes.\n\n**Key points**\n\n- **Developer**: Alibaba Cloud.\n- **Models**: Qwen 2 and Qwen 1.5 in sizes from small (1.8B) to large (72B), plus code and vision variants.\n- **Use cases**: Chat, code, multilingual assistants.\n- **License**: Generally permissive for most commercial uses, with some conditions.\n\n---\n\n## 3. DeepSeek\n\n**Why it’s popular**\n\n- Frequently cited as one of the best **reasoning and coding** open models.\n- Very attractive **cost‑performance** ratio and strong support in hosted and local stacks.\n\n**Key points**\n\n- **Focus**: Technical reasoning, math, and programming.\n- **Use cases**: Code assistants, analysis tools, agents.\n- **License**: Open‑weight; needs license review for large‑scale commercial deployments.\n\n---\n\n## 4. Mistral & Mixtral – Mistral AI\n\n**Why it’s popular**\n\n- High‑quality models with efficient Mixture‑of‑Experts (MoE) architectures.\n- Strong performance on many standard benchmarks.\n- Widely integrated by infra providers and tools.\n\n**Key points**\n\n- **Developer**: Mistral AI.\n- **Models**: Mistral 7B, Mixtral 8x7B, 8x22B, etc.\n- **Use cases**: General chat, code, RAG, production APIs.\n- **License**: Apache 2.0 or similar for many models (good for commercial).\n\n---\n\n## 5. GPT‑OSS – OpenAI’s open‑weight family\n\n**Why it’s popular**\n\n- Directly from OpenAI, designed as an “open alternative” with reasoning capabilities similar to their frontier models (per your source).\n- Specifically aimed at organizations that want **self‑hosting** and more control.\n\n**Key points**\n\n- **Developer**: OpenAI.\n- **Use cases**: General GPT‑like assistant on private infrastructure.\n- **License**: Open‑weight; details matter for redistribution and commercial use.\n\n---\n\n## 6. GPT4All – Ecosystem for local LLMs\n\n**Why it’s popular**\n\n- Not a single model but a **tooling ecosystem**: lets you download and run many Llama/Mistral/etc. models locally with a simple UI.\n- Very user‑friendly for non‑experts.\n\n**Key points**\n\n- **Developer**: Nomic AI.\n- **Use cases**: Local ChatGPT‑like experience, experimentation with many open models.\n- **License**: Varies by model; the framework itself is open‑source.\n\n---\n\n## 7. Vicuna\n\n**Why it’s popular**\n\n- Early high‑quality chat fine‑tune of LLaMA; widely cited (“90% of ChatGPT quality”).\n- Still used in research and some legacy systems.\n\n**Key points**\n\n- **Base**: LLaMA / Llama 2.\n- **Use cases**: Conversational agents, research.\n- **License**: Follows base model license; often non‑commercial or restricted.\n\n---\n\n## 8. OpenAssistant\n\n**Why it’s popular**\n\n- Community‑driven attempt to replicate ChatGPT with **fully open data and models**.\n- Emphasis on transparency and RLHF pipeline.\n\n**Key points**\n\n- **Developer**: LAION and community.\n- **Use cases**: Chatbots, research on alignment and RLHF.\n- **License**: Open‑source; good for research and customization.\n\n---\n\n## 9. Falcon\n\n**Why it’s popular**\n\n- One of the first strong, fully open‑weight 40B–180B‑parameter models.\n- Widely available on Hugging Face; still used in many pipelines.\n\n**Key points**\n\n- **Developer**: TII (Technology Innovation Institute).\n- **Use cases**: General‑purpose LLM, multilingual tasks.\n- **License**: Falcon License (permissive but with some constraints).\n\n---\n\n## 10. MPT (MosaicML) – e.g., MPT‑7B\n\n**Why it’s popular**\n\n- Focus on **commercial usability** and efficient deployment.\n- Often used as a base for custom fine‑tunes.\n\n**Key points**\n\n- **Developer**: MosaicML (acquired by Databricks).\n- **Models**: MPT‑7B and derivatives (instruct, story, etc.).\n- **Use cases**: Apps needing permissive licensing and predictable behavior.\n- **License**: Mostly Apache 2.0 / commercially friendly.\n\n---\n\n## 11. Older but still relevant GPT‑like families\n\nThese are less competitive with the newest Llama/Qwen/Mistral generations but still important, especially for research, education, or low‑resource setups:\n\n- **GPT‑J / GPT‑Neo / GPT‑NeoX** (EleutherAI)  \n  Early GPT‑3‑style open models; common in open‑source tools and papers.\n\n- **OPT** (Meta)  \n  175B‑parameter GPT‑3‑scale model; useful for research and benchmarks.\n\n- **BLOOM** (BigScience)  \n  Large multilingual open model; widely used in academia.\n\n- **RWKV / ChatRWKV / Raven RWKV**  \n  RNN‑like architecture as a transformer alternative; efficient and popular among enthusiasts.\n\n---\n\n## 12. Multimodal “GPT‑4‑Vision‑like” open alternatives\n\nFor GPT‑4‑Vision‑style capabilities, these are frequently cited:\n\n- **LLaVA** – LLaMA + vision encoder; question answering about images.\n- **Fuyu** – Multimodal model designed for structured visual inputs.\n- **CogVLM** – Another strong vision‑language model family.\n\nAll are open‑weight and can be hosted privately.\n\n---\n\n## How to pick one\n\nVery roughly:\n\n- **General‑purpose / closest to GPT‑4‑style chat**:  \n  Llama 3, Qwen 2, Mistral/Mixtral, GPT‑OSS.\n- **Best for coding & reasoning**:  \n  DeepSeek, Qwen‑Coder, Llama 3 Instruct/Code variants.\n- **Fully local “ChatGPT on your laptop”**:  \n  Llama 3 via **Ollama**, **GPT4All**, or **LM Studio**.\n- **Research / transparency focus**:  \n  OpenAssistant, Vicuna, BLOOM, GPT‑J/NeoX, Falcon, RWKV.\n\nIf you tell me your main use case (e.g., “small startup, needs on‑prem, heavy coding,” or “university research, must be very open license”), I can narrow this down to a short, concrete recommendation list.",
          "role": "assistant",
          "reasoning_steps": null,
          "tool_call_id": null,
          "tool_calls": null
        },
        "finish_reason": "stop"
      }
    ],
    "created": 1779391627,
    "model": "sonar-pro",
    "citations": [
      "https://neoteric.eu/blog/open-source-vs-openai-8-best-open-source-alternatives-to-gpt",
      "https://www.datacamp.com/blog/12-gpt4-open-source-alternatives",
      "https://bdtechtalks.substack.com/p/what-are-the-open-source-alternatives",
      "https://www.simular.ai/alternatives/top-best-open-source-model-alternatives-to-gpt-5-for-teams",
      "https://www.lindy.ai/blog/chatgpt-alternative",
      "https://github.com/GPT-Alternatives/gpt_alternatives",
      "https://northflank.com/blog/open-source-chatgpt-alternatives-enterprise",
      "https://connect.oeglobal.org/t/tagged-for-oeg-connect-13-best-open-source-chatgpt-alternatives/6303"
    ],
    "object": "chat.completion",
    "search_results": [
      {
        "title": "8 Best Open-Source Alternatives to GPT - Neoteric",
        "url": "https://neoteric.eu/blog/open-source-vs-openai-8-best-open-source-alternatives-to-gpt",
        "date": "2023-06-08",
        "last_updated": "2026-05-21",
        "snippet": "Best alternatives to GPT (open source only) · LLaMA · GPT-J & GPT-NeoX · Dolly · Alpaca · Vicuna · OpenAssistant · ChatGPT alternatives.",
        "source": "web"
      },
      {
        "title": "12 GPT-4 Open-Source Alternatives - DataCamp",
        "url": "https://www.datacamp.com/blog/12-gpt4-open-source-alternatives",
        "date": "2024-08-01",
        "last_updated": "2026-05-18",
        "snippet": "12 GPT-4 Open-Source Alternatives · 1. ColossalChat · 2. Alpaca-LoRA · 3. Vicuna · 4. GPT4ALL · 5. Raven RWKV · 6. OpenChatKit · 7. OPT · 8. Flan-T5-XXL.",
        "source": "web"
      },
      {
        "title": "What are the open-source alternatives to GPT-4 Vision? - TechTalks",
        "url": "https://bdtechtalks.substack.com/p/what-are-the-open-source-alternatives",
        "date": "2024-01-04",
        "last_updated": "2026-02-06",
        "snippet": "There are open-source models that provide similar capabilities. Some of these models include LLaVA, Fuyu, and CogVLM. All these models are available for ...",
        "source": "web"
      },
      {
        "title": "Top Best Open source model alternatives to GPT-5 for teams",
        "url": "https://www.simular.ai/alternatives/top-best-open-source-model-alternatives-to-gpt-5-for-teams",
        "date": "2026-02-28",
        "last_updated": "2026-05-16",
        "snippet": "Comparison Summary · 1. Simular Pro: The \"Hands\" for Your Open-Source Brain · 2. GPT-OSS: OpenAI's Powerful Open Alternative · 3. Llama 3: The Industry Standard.",
        "source": "web"
      },
      {
        "title": "I Tested 20+ ChatGPT Alternatives. These Are The Best in 2026 | Lindy",
        "url": "https://www.lindy.ai/blog/chatgpt-alternative",
        "date": "2026-05-06",
        "last_updated": "2026-05-21",
        "snippet": "DeepSeek: Best ChatGPT alternative for technical reasoning & coding. Why I picked DeepSeek: DeepSeek feels built for thinking things through.",
        "source": "web"
      },
      {
        "title": "GPT-Alternatives/gpt_alternatives - GitHub",
        "url": "https://github.com/GPT-Alternatives/gpt_alternatives",
        "date": "2023-08-02",
        "last_updated": "2025-10-28",
        "snippet": "In this survey paper, we provide an examination of alternative open-sourced models of large GPTs, focusing on user-friendly and relatively small models.",
        "source": "web"
      },
      {
        "title": "Top open-source alternatives to ChatGPT for companies - Northflank",
        "url": "https://northflank.com/blog/open-source-chatgpt-alternatives-enterprise",
        "date": "2025-09-01",
        "last_updated": "2026-05-21",
        "snippet": "1. OpenAI GPT-OSS: OpenAI's first open-weight model release · 2. DeepSeek: Cost-effective reasoning models · 3. Qwen: Alibaba's solution · 4. Meta ...",
        "source": "web"
      },
      {
        "title": "Tagged for OEG Connect: 13 Best Open Source ChatGPT Alternatives",
        "url": "https://connect.oeglobal.org/t/tagged-for-oeg-connect-13-best-open-source-chatgpt-alternatives/6303",
        "date": "2024-01-13",
        "last_updated": "2025-10-10",
        "snippet": "Ollama / Jan.ai can be used as ChatGPT alternatives running on the local computer. I mostly use the text / code generation features but expect ...",
        "source": "web"
      }
    ],
    "status": null,
    "type": null,
    "usage": {
      "completion_tokens": 1664,
      "cost": {
        "input_tokens_cost": 5e-05,
        "output_tokens_cost": 0.02496,
        "total_cost": 0.03101,
        "citation_tokens_cost": null,
        "reasoning_tokens_cost": null,
        "request_cost": 0.006,
        "search_queries_cost": null
      },
      "prompt_tokens": 17,
      "total_tokens": 1681,
      "citation_tokens": null,
      "num_search_queries": null,
      "reasoning_tokens": null,
      "search_context_size": "low"
    }
  }
  ```
</Accordion>

<Info title="Complete Streaming Guide" href="/docs/agent-api/output-control#streaming-responses">
  For a full guide on streaming, including parsing, error handling, citation management, and best practices, see our [Agent API streaming guide](/docs/agent-api/output-control#streaming-responses).
</Info>

## Response Structure

Sonar API responses follow an OpenAI-compatible format:

```json theme={null}
{
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "model": "sonar-pro",
    "created": 1234567890,
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "Recent developments in quantum computing include advances in error correction, new qubit architectures, and progress toward fault-tolerant systems..."
            },
            "finish_reason": "stop"
        }
    ],
    "usage": {
        "prompt_tokens": 14,
        "completion_tokens": 287,
        "total_tokens": 301
    }
}
```

## Next Steps

<CardGroup>
  <Card title="Agent API" icon="code-circle" href="/docs/agent-api/quickstart">
    Need structured outputs or third-party models? Check out the Agent API.
  </Card>

  <Card title="Search API" icon="search" href="/docs/search/quickstart">
    Get raw search results with the Search API.
  </Card>

  <Card title="Sonar API Features" icon="book" href="/docs/sonar/features">
    Complete guide to the Sonar API with advanced features and examples.
  </Card>

  <Card title="Models" icon="brain" href="/docs/sonar/models">
    Explore available Sonar models and their capabilities.
  </Card>

  <Card title="API Reference" icon="code-circle" href="/api-reference/sonar-post">
    View complete endpoint documentation and parameters.
  </Card>

  <Card title="Search Filters" icon="search" href="/docs/sonar/filters#search-control">
    Learn how to control search behavior with filters and parameters.
  </Card>
</CardGroup>

<Info>
  Need help? Check out our [community](https://community.perplexity.ai) for support and discussions with other developers.
</Info>