# 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. # 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. # Create Async Chat Completion Source: https://docs.perplexity.ai/api-reference/async-sonar-post post /v1/async/sonar Submit an asynchronous chat completion request. # 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. 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. # 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. 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. # 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. # 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. **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. ## Response Shape The Search API returns a ranked `results[]` array. Each result includes `title`, `url`, `snippet`, and optional `date` and `last_updated` fields: ```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" } ``` ## 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. # 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. **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. API keys should be treated as sensitive credentials. Store them securely and never expose them in client-side code or public repositories. ## Getting Started: Create Your API Group First **Important Prerequisites**: Before you can generate any API keys, you must first create an API group through the Perplexity web interface. Navigate to the API Groups page and create your first group: **[Create API Group →](https://console.perplexity.ai)** API groups help organize your keys and manage access across different projects or environments. Choose a descriptive name for your API group (e.g., "Production", "Development", or your project name) to help with organization. Once you have an API group, navigate to the API Keys page to generate your first key: **[Generate API Keys →](https://console.perplexity.ai)** 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. After creating your first API key through the web interface, you can use the programmatic endpoints below to generate and manage additional keys. ## 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 Once an API key is revoked, it cannot be recovered. Make sure to update your applications with new keys before revoking old ones. ## 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 ```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}`); ``` ### Response ```json theme={null} { "auth_token": "pplx-1234567890abcdef", "created_at_epoch_seconds": 1735689600, "token_name": "Production API Key" } ``` 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. ## Revoking API Keys Revoke API keys that are no longer needed or may have been compromised. ### Request ```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"); } ``` ### 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 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"] ``` 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 ``` 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 ``` 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") ``` ### Automated Rotation Example Here's a complete example of an automated key rotation script: ```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 { 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 { 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): Promise { 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 { 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)}...`); ``` ## Best Practices 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"` 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. 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" Track which keys are being used in your applications and revoke unused keys promptly. Maintain an inventory of active keys and their purposes. ## Security Considerations **Never expose API keys in:** * Client-side JavaScript code * Mobile applications * Public repositories * Log files or error messages * URLs or query parameters ### 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 | For additional support with API key management, visit the [API Platform console](https://console.perplexity.ai) or contact our support team. # 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. 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. ## Getting Access Access is managed by your organization's admins from the Perplexity web app: 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. In the row that appears below the toggle, select **Generate key**. 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`. **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. ### 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. You can check your current usage tier by visiting the [API Platform console](https://console.perplexity.ai). *** ## 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 | Tiers are based on **cumulative purchases** across your account lifetime, not current balance. *** ## 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 requests per second | 50 requests | **Search Rate Limiter Behavior:** * **Burst**: Can handle 50 requests instantly * **Sustained**: Exactly 50 QPS average over time Search rate limits are independent of your usage tier and apply consistently across all accounts using the same leaky bucket algorithm. *** ## Sonar API Rate Limits The Sonar API uses tier-based rate limits that scale with your usage tier: | 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 | | 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 | | 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 | | 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 | | 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 | | 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 | *** ## 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 | Contextualized embeddings are rate limited by **total chunks**, not by request count. *** ## 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 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. 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 ``` 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. *** ## 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 **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 *** ## Upgrading Your Tier Visit the [API Platform console](https://console.perplexity.ai) to see your current tier and total spending. Add credits to your account through the billing section. Your tier will automatically upgrade once you reach the spending threshold. Your new rate limits take effect immediately after the tier upgrade. Check your settings page to confirm. 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. Higher tiers significantly improve your API experience with increased rate limits, especially important for production applications. 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. # 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. API Platform login page with Continue with Google, Continue with Apple, Single sign-on (SSO), and Continue with email options ## 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. | 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). *** ## Continue With Google Use Google to sign in with any Google or Google Workspace account. On the login page, click **Continue with Google** and choose the Google account you want to use. Google asks you to confirm the sign-in and share your name, email, and profile picture with Perplexity. Approve to continue. 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. 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. *** ## Continue With Apple Use Sign in with Apple, including the Hide My Email relay address. On the login page, click **Continue with Apple** and authenticate with Face ID, Touch ID, or your Apple ID password. Apple lets you share your real email or use **Hide My Email** to generate a private relay address. Perplexity uses whichever address Apple returns. 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. 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. *** ## 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. 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). ### Signing In With SSO On the login page, click **Single sign-on (SSO)**. The form switches to a work-email prompt. Single sign-on view with Work email field, Continue with SSO button, and Back to all options link 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. 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. 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. ### 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). 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. 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. Add and verify at least one domain (for example, `yourcompany.com`) that your team uses for email. Verification is done through a DNS record. 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). 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. 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. Need help with SSO setup or want us to walk through it with you? Reach out to your Perplexity account team. *** ## Continue With Email Email sign-in is passwordless. There is no password to set or remember. Enter your email in the **Email** field and click **Continue with email**. 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. Once verified, you are signed in. If this is your first visit, the setup wizard walks you through creating an API group. 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. *** ## 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. 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). *** ## Next Steps Create your organization's workspace, add billing, and invite teammates. Generate and manage keys once your API group is set up. Send a request to the Perplexity API in Python, TypeScript, or cURL. See per-model and per-tool pricing before you start. # 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`. ```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}' ``` ## 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. ```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 ``` 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`. 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. ```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" ``` ## 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`. ```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" ``` ## Next Steps # 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. ```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 ``` 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. 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. ## 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. Start from a `preset`, then move to an explicit `model` (or `models` chain) when you need to pin the exact engine. ## Next steps Split the system prompt from the question, and ground the run. See the tuned presets you can start from. # 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). ```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 ``` 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 | Let the model choose. You enable a tool, and the model decides whether and when to call it based on `input` and `instructions`. ## 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. ```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 ``` 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. ```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 ``` 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`: ```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 = { '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 ``` `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. ## 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 Give the agent a sandbox to compute exact answers and return files. Enforce structured JSON your code can parse. # 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 Attach images to a request. Control streaming, background runs, error handling, and structured output. # 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`. ```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 ``` 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). ## 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", }, }] ``` 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. ## 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 Enable built-in tools and your own custom tools, then read their results. Full prompting patterns and best practices. # 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. ```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 ``` ## 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 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. ## 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: ```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 ``` ```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 } ``` ## 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`: ```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 ``` 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). ## Next steps Enforce structured JSON your code can parse. Full sandbox settings, response shape, file retrieval, and pricing. # 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: ```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 ``` Reinforce the schema in your prompt ("Return the data as a JSON object matching the schema") to improve adherence. 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. ## Next steps Carry state across multiple turns. Streaming, background runs, error handling, and full structured-output examples. # 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 a `role` (`user` or `assistant`). Append the new question at the end. ```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=[ {"role": "user", "content": "My favorite programming language is Rust."}, {"role": "assistant", "content": first.output_text}, {"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: [ { role: 'user', content: 'My favorite programming language is Rust.' }, { role: 'assistant', content: first.output_text ?? '' }, { 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: [ { role: "user", content: "My favorite programming language is Rust." }, { role: "assistant", content: $text }, { role: "user", content: "What'\''s a good beginner project to practice it?" } ] }')" | jq ``` 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. 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). 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`. ```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 ``` ### 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. ```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 ``` 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`: ```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 ``` ### 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 Attach images to a request. Control streaming, background runs, error handling, and structured output. # 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. * 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. ## Examples 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). ```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 ``` Use this method when you have a publicly accessible image URL. The model will fetch the image from the provided URL. ```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 ``` ## 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": "" } ] } ``` 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 Get started with the Agent API Learn about the `web_search` tool. # 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. 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). ## 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. | For state-of-the-art deep research, use the `xhigh` preset — the highest quality in the lineup, leading across the benchmarks we run. See what each preset configures and how to override individual settings. Follow the field-by-field procedure to move a Sonar integration to the Agent API. # 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.
**Sonar** ```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 ```
**Agent API** ```python Python theme={null} from perplexity import Perplexity client = Perplexity() response = client.responses.create( model="perplexity/sonar", input=[ {"role": "system", "content": "You are a concise research assistant."}, {"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: [ { role: 'system', content: 'You are a concise research assistant.' }, { 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": [ {"role": "system", "content": "You are a concise research assistant."}, {"role": "user", "content": "What are the latest developments in AI agents?"} ] }' | jq ```
## 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.
**Sonar** ```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 ```
**Agent API** ```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=[ {"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: [ { 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": [ {"role": "user", "content": "What are the latest developments in AI agents?"} ] }' | jq ```
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). ## 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`.
**Sonar** ```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' ```
**Agent API** ```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 ```
**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. ### 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.
**Sonar** ```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 }' ```
**Agent API** ```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 }' ```
## 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.
**Sonar** ```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 ```
**Agent API** ```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 ```
**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. ### Inline citations Sonar returned inline `[n]` citations by default. To get the same on the Agent API, tell the model to cite the numbered web search results in its `instructions`: ```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 ``` 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`. **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. ## 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.
**Sonar** ```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 ```
**Agent API** ```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 ```
**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. ## 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. 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. ### Standard OpenAI parameters These standard OpenAI parameters carry over unchanged: `temperature`, `top_p`, and `stream`. 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)
(`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`. See the [Web Search](/docs/agent-api/tools/web-search) reference for the full set of `web_search` options. ### 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. We recommend: * Migrating existing Sonar Chat Completions usage to the Agent API. * Using the Agent API for all new projects. ## 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 | | | | Built-in web search | | | | People Search | | | | Finance Search | | | | Code sandbox | | | | MCP servers | | | | Model fallback | | | | Structured outputs | | | | Streaming | | | | Async mode | | | 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.
**Sonar** ```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 ```
**Agent API** ```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 ```
```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} // ... ] // ... } ``` ```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" // ... } ``` ## 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. | For state-of-the-art deep research, use the `xhigh` preset — the highest quality in the lineup, leading across the benchmarks we run. 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 Follow the complete field-by-field migration procedure and parameter reference. See what each preset configures and how to override individual settings. # 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. **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 ## Basic Example ```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 '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 }' ``` 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. ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` ## Cross-Provider Fallback For maximum reliability, use models from different providers: ```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 }' ``` ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` ## Pricing Billing is based on the model that serves the request, not all models in the fallback chain. The `model` field in the response indicates which model was used, and the `usage` field shows the token counts for that model. **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. Place preferred models first in the array. Consider pricing differences when ordering the fallback chain. ## Next Steps Explore available models and their pricing. Explore available presets and their configurations. Get started with your first Agent API call. View complete endpoint documentation. # 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. Looking for pre-configured model setups? See [**Presets**](/docs/agent-api/presets) — optimized for specific use cases. 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. Sonar — Perplexity's grounded search model. | 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) | Claude Opus (highest reasoning), Sonnet (balanced), and Haiku (fastest, cheapest). | Model | Input (\$/1M) | Output (\$/1M) | Cache (\$/1M) | Docs | | ----------------------------- | ------------- | -------------- | ------------- | --------------------------------------------------------------------------------------------- | | `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-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) | GPT-5 family — flagship, mini, and nano variants. | Model | Input (\$/1M) | Output (\$/1M) | Cache (\$/1M) | Docs | | ---------------------- | ------------------------------- | -------------------------------- | ------------- | -------------------------------------------------------------------- | | `openai/gpt-5.6-sol` | 5.00 (≤272k)
10.00 (>272k) | 30.00 (≤272k)
45.00 (>272k) | 90% off input | [GPT-5.6](https://openai.com/index/gpt-5-6/) | | `openai/gpt-5.6-terra` | 2.50 (≤272k)
5.00 (>272k) | 15.00 (≤272k)
22.50 (>272k) | 90% off input | [GPT-5.6](https://openai.com/index/gpt-5-6/) | | `openai/gpt-5.6-luna` | 1.00 (≤272k)
2.00 (>272k) | 6.00 (≤272k)
9.00 (>272k) | 90% off input | [GPT-5.6](https://openai.com/index/gpt-5-6/) | | `openai/gpt-5.5` | 5.00 (≤272k)
10.00 (>272k) | 30.00 (≤272k)
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)
5.00 (>272k) | 15.00 (≤272k)
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) |
Gemini 3 family — Pro for long-context, Flash and Flash Lite for speed. | Model | Input (\$/1M) | Output (\$/1M) | Cache (\$/1M) | Docs | | ------------------------------- | ------------------------------ | -------------------------------- | ------------- | ------------------------------------------------------------------------------------------- | | `google/gemini-3.1-pro-preview` | 2.00 (≤200k)
4.00 (>200k) | 12.00 (≤200k)
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-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) |
Grok 4.5, 4.3, and 4.20 variants — flagship, reasoning, non-reasoning, and multi-agent. | Model | Input (\$/1M) | Output (\$/1M) | Cache (\$/1M) | Docs | | ----------------------------- | ------------------------------ | ------------------------------- | ------------------------------ | -------------------------------------------------------------- | | `xai/grok-4.5` | 2.00 (≤200k)
4.00 (>200k) | 6.00 (≤200k)
12.00 (>200k) | 0.30 (≤200k)
0.60 (>200k) | [Grok 4.5](https://docs.x.ai/developers/models) | | `xai/grok-4.3` | 1.25 (≤200k)
2.50 (>200k) | 2.50 (≤200k)
5.00 (>200k) | 0.20 | [Grok 4.3](https://docs.x.ai/developers/models) | | `xai/grok-4.20-reasoning` | 1.25 (≤200k)
2.50 (>200k) | 2.50 (≤200k)
5.00 (>200k) | 0.20 | [Grok 4.20 Reasoning](https://docs.x.ai/developers/models) | | `xai/grok-4.20-non-reasoning` | 1.25 (≤200k)
2.50 (>200k) | 2.50 (≤200k)
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)
2.50 (>200k) | 2.50 (≤200k)
5.00 (>200k) | 0.20 | [Grok 4.20 Multi-Agent](https://docs.x.ai/developers/models) |
GLM 5.2 — Z.AI's flagship reasoning model. | Model | Input (\$/1M) | Output (\$/1M) | Cache (\$/1M) | Docs | | -------------------- | ------------- | -------------- | ------------- | ------------------------ | | `perplexity/glm-5.2` | 1.40 | 4.40 | 0.26 | [GLM](https://docs.z.ai) | Kimi K2.7 Code — Moonshot AI's coding and agentic model. | Model | Input (\$/1M) | Output (\$/1M) | Cache (\$/1M) | Docs | | --------------------------- | ------------- | -------------- | ------------- | -------------------------------------------- | | `perplexity/kimi-k2.7-code` | 0.95 | 4.00 | 0.19 | [Kimi K2](https://platform.moonshot.ai/docs) | Nemotron 3 Super — NVIDIA's open-weight reasoning model. | Model | Input (\$/1M) | Output (\$/1M) | Cache (\$/1M) | Docs | | ----------------------------------- | ------------- | -------------- | ------------- | ------------------------------------------------------------------------------ | | `nvidia/nemotron-3-super-120b-a12b` | 0.25 | 2.50 | — | [Nemotron 3 Super 120B](https://research.nvidia.com/labs/nemotron/Nemotron-3/) |
Not all third-party models support all features (e.g., reasoning, tools). Check model documentation for specific capabilities. ## Estimate your cost ## Using a Model ```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 ``` ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` **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 } } ``` ## 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. Learn how to use model fallback chains to ensure high availability and reliability by automatically trying multiple models when one fails. **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). ## Next Steps Equip your model with web search for source-grounded context. Write prompts that get the most out of the Agent API. Shape responses with structured outputs and JSON schemas. Query market data, filings, and ticker-level information. # 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. **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. **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. ## Quick Start Use the OpenAI SDK with Perplexity's Agent API: ```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) ``` ```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); ``` ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` ## Configuration ### Setting Up the OpenAI SDK Configure OpenAI SDKs to work with Perplexity by setting the `base_url` to `https://api.perplexity.ai/v1`: ```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" ) ``` ```typescript theme={null} import OpenAI from 'openai'; const client = new OpenAI({ apiKey: process.env.PERPLEXITY_API_KEY, baseURL: "https://api.perplexity.ai/v1" }); ``` **Important**: Use `base_url="https://api.perplexity.ai/v1"` (with `/v1`) for the Agent API. ## 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 ```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}") ``` ```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}`); ``` ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` ### Using Presets Presets are pre-configured setups optimized for specific use cases. Use `extra_body` to pass presets via the OpenAI SDK: ```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) ``` ```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); ``` ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` See [Agent API Presets](/docs/agent-api/presets) for available presets and their configurations. ### Using Third-Party Models You can also specify third-party models directly instead of using presets: ```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) ``` ```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); ``` ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` ### Streaming Responses Streaming works with the Agent API: ```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) ``` ```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); } } ``` ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` ### 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: ```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) ``` ```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); ``` ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` ## 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 See [Agent API Reference](/api-reference/agent-post) for complete parameter details. ## 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. | 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`. ### Model Discovery The `GET /v1/models` endpoint returns all models available for the Agent API in OpenAI-compatible format. No authentication is required. ```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})") ``` ```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})`); } ``` ```bash theme={null} curl https://api.perplexity.ai/v1/models ``` 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. ## 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 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 ) ``` 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}") ``` 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) ``` ## 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: ```bash theme={null} pip install perplexityai ``` ```bash theme={null} npm install @perplexity-ai/perplexity_ai ``` ```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 ``` ```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 ``` **No base URL needed** - The Perplexity SDK automatically uses the correct endpoint. The API calls are very similar: ```python theme={null} # Agent API - same interface response = client.responses.create( model="openai/gpt-5.6-sol", input="Hello!" ) ``` ```typescript theme={null} // Agent API - same interface const response = await client.responses.create({ model: "openai/gpt-5-mini", input: "Hello!" }); ``` The Perplexity SDK supports presets with cleaner syntax compared to OpenAI SDK: ```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?" ) ``` ```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?" }); ``` ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` ## Next Steps Get started with Agent API using OpenAI SDKs. Explore direct model selection and third-party models. Continue a conversation with `previous_response_id` or replay turns yourself. View complete endpoint documentation. Configure streaming responses and structured outputs with JSON schema. Specify multiple models for automatic failover and higher availability. Apply filters to web search results. # 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. Streaming is supported across all models available through the Agent API. To enable streaming, set `stream=True` (Python) or `stream: true` (TypeScript) when creating responses: ```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 }' ``` ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` ### Error Handling Handle errors gracefully during streaming: ```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}`); } } ``` ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` 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. ## 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. For the full background-run lifecycle — submitting, polling on terminal status, streaming with reconnect, and cancelling — see [Background mode](/docs/agent-api/background-mode). ```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" ``` 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`. **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." 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. ### Example ```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 ``` ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` **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. ## Next Steps Back to the build flow: enforce structured JSON your code can parse. Explore direct model selection and third-party models. # 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. Agent API presets now use tier-based names: fast-search → fast, pro-search → low, deep-research → medium, advanced-deep-research → high, and ultra → xhigh. 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. 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. **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. ### 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, quick summaries. | 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. | A query needs current information with light research and tool use. | | **medium** | Multi-hop browsing and wide aggregation across many sources. | A question requires chaining evidence across many sources over several rounds of search and reasoning. | | **high** | Expert-level reasoning and exhaustive source coverage. | 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). | The full current configuration for each preset — model, tools, parameters, and system prompt — is in the [Current preset values](#current-preset-values) section below. ## 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. ```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." }' ``` 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. 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). ```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"], }, }], ) ``` ```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"], }, }], }); ``` ```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 ``` 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. ## 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. 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. The cURL tab can show a more complete configuration than the SDK tabs: some parameters aren't exposed by the SDK yet. Quick factual lookups with minimal latency. * **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 ```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 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. ## 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 Make at most one tool call before concluding. ## Citation Instructions Your response must include citations. Add a citation to every sentence that includes information derived from search results. - 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 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]." If you did not perform a search, do not include citations. ## Response Guidelines - 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 - 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. - 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 ## Query Type Adaptations Adapt your response structure based on query type while following all general guidelines. Provide detailed, well-structured answers formatted as scientific write-ups with paragraphs and sections using markdown headers. 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. Provide only the weather forecast in a brief format. If search results lack relevant weather data, state this clearly. 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. Use markdown code blocks with appropriate language identifiers. Present code first, then explain it. Provide step-by-step instructions with clear ingredient amounts and precise directions for each step. Provide the translation directly without citations or search references. Follow user instructions precisely. Search results and citations are not required. Focus on delivering exactly what the user needs. 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. 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. ## Prohibited Content 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 ## 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 """, 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 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. ## 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 Make at most one tool call before concluding. ## Citation Instructions Your response must include citations. Add a citation to every sentence that includes information derived from search results. - 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 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]." If you did not perform a search, do not include citations. ## Response Guidelines - 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 - 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. - 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 ## Query Type Adaptations Adapt your response structure based on query type while following all general guidelines. Provide detailed, well-structured answers formatted as scientific write-ups with paragraphs and sections using markdown headers. 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. Provide only the weather forecast in a brief format. If search results lack relevant weather data, state this clearly. 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. Use markdown code blocks with appropriate language identifiers. Present code first, then explain it. Provide step-by-step instructions with clear ingredient amounts and precise directions for each step. Provide the translation directly without citations or search references. Follow user instructions precisely. Search results and citations are not required. Focus on delivering exactly what the user needs. 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. 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. ## Prohibited Content 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 ## 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 `, 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\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\n\n## Tools Workflow\n\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\nMake at most one tool call before concluding.\n\n\n## Citation Instructions\n\nYour response must include citations. Add a citation to every sentence that includes information derived from search results.\n\n\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\n\n\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\n\nIf you did not perform a search, do not include citations.\n\n\n## Response Guidelines\n\n\n\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\n\n\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\n\n\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\n\n\n\n## Query Type Adaptations\n\nAdapt your response structure based on query type while following all general guidelines.\n\n\nProvide detailed, well-structured answers formatted as scientific write-ups with paragraphs and sections using markdown headers.\n\n\n\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\n\n\nProvide only the weather forecast in a brief format. If search results lack relevant weather data, state this clearly.\n\n\n\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\n\n\nUse markdown code blocks with appropriate language identifiers. Present code first, then explain it.\n\n\n\nProvide step-by-step instructions with clear ingredient amounts and precise directions for each step.\n\n\n\nProvide the translation directly without citations or search references.\n\n\n\nFollow user instructions precisely. Search results and citations are not required. Focus on delivering exactly what the user needs.\n\n\n\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\n\n\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\n\n\n\n## Prohibited Content\n\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\n\n## Copyright\n\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", "tools": [ { "type": "web_search", "max_results": 10 } ] } JSON ``` Balanced research with tool access. * **Model:** `google/gemini-3-flash-preview` * **Max steps:** 5 * **Reasoning effort:** `high` * **Max output tokens:** 16384 * **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 ```python Python theme={null} from perplexity import Perplexity client = Perplexity() response = client.responses.create( model="google/gemini-3-flash-preview", 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=16384, reasoning={"effort": "high"}, 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. 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: "google/gemini-3-flash-preview", 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: 16384, reasoning: { effort: "high" }, 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. 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": "google/gemini-3-flash-preview", "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": 16384, "reasoning": { "effort": "high" }, "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\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 ``` In-depth, multi-step research and analysis. * **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 high effort. These are preset-level settings and are not request-settable fields. * **System prompt:** included inline below ```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. 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. 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\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 ``` Maximum-depth, institutional-grade research. * **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 high effort. These are preset-level settings and are not request-settable fields. * **System prompt:** included inline below ```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. 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. 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\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 ``` 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 ```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 ``` 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 ```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 ``` ## Next Steps Get started with the Agent API. Explore direct model selection and third-party models. View complete endpoint documentation. # 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. 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. **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 ```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 ``` ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` ## Best Practices 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" 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" 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." ## 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 (LinkedIn posts, 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." ) ``` ```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.06264, "cache_creation_cost": null, "cache_read_cost": 0.00045, "tool_calls_cost": 0.00275 }, "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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` ```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" } } ] ) ``` ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` See [Filters](/docs/agent-api/tools/web-search#filters) for the full list of available parameters. 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. ## Next Steps Shape responses with `response_format` and learn the full response payload structure. Constrain search with domain, recency, and region parameters. Configure the `web_search` tool for source-grounded context. Choose a preset that matches your latency, depth, and tool requirements. # 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. Test Agent API requests and parameters interactively in the API console. Pay-as-you-go pricing for all APIs. No subscription required. ## Why Use the Agent API? Get accurate, up-to-date answers grounded in real-time web search, with inline citations in a single call, and conversation context across turns. Access OpenAI, Anthropic, Google, xAI, and more through one unified API, no need to manage multiple API keys. See exact token counts and costs per request, no markup, just direct provider pricing. Change models, reasoning, tokens, and tools with consistent syntax. We recommend using our [official SDKs](/docs/sdk/overview) for a more convenient and type-safe way to interact with the Agent API. **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. ## Installation Install the SDK for your preferred language: ```bash Python theme={null} pip install perplexityai ``` ```bash Typescript theme={null} npm install @perplexity-ai/perplexity_ai ``` ## Authentication Set your API key as an environment variable. The SDK will automatically read it: ```bash theme={null} export PERPLEXITY_API_KEY="your_api_key_here" ``` ```powershell theme={null} setx PERPLEXITY_API_KEY "your_api_key_here" ``` All SDK examples below automatically use the `PERPLEXITY_API_KEY` environment variable. You can also pass the key explicitly if needed. ## Basic Usage **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. ### Using a Third-Party Model Use third-party models from OpenAI, Anthropic, Google, xAI, and other providers for specific capabilities: ```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 ``` ```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 } ``` ### Using a Preset Presets provide optimized defaults for specific use cases. Start with a preset for quick setup: ```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 ``` ```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\nYou are an AI assistant developed by Perplexity AI...\n\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.00275, "total_cost": 0.03996 }, "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 } ``` 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. ### 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: ```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" \ -d '{ "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." }' | jq ``` ```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 } ``` ### 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. ```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's GPU compute model: streaming multiprocessors, CUDA cores, Tensor Cores, and HBM memory bandwidth.", "tools": [{"type": "finance_search"}] }' | jq ``` ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` ## Next Steps Use web search for source-grounded, current context. Browse available models and pricing across all supported providers. Explore pre-configured setups for common use cases like low and medium. Configure streaming responses and structured outputs with JSON schema. Specify multiple models for automatic failover and higher availability. Best practices for effective prompting with web search models. Control search results with domain, date, and location filters. View complete endpoint documentation and parameters. Need help? Check out our [community](https://community.perplexity.ai) for support and discussions with other developers. # 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" }`. 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. | 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" }` | Office skills create documents from scratch. They do not edit files you upload. ### 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. ```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" ``` 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 Full walkthrough of the daily AI stock news PDF, including file download and the complete design book. # Custom Functions Source: https://docs.perplexity.ai/docs/agent-api/tools/custom-functions Define custom function tools the Agent API can call, then feed results back to continue the run - the type: function tool, the function_call item, and function_call_output keyed by call_id. A custom tool (`type: function`) lets the agent call code you control - your database, an internal API, or any business logic. You declare the function with a `name`, a `description`, and a JSON Schema for its `parameters`. The model decides when to call it and fills in the arguments; you run the function and return the result so the run can continue. Unlike built-in tools, the Agent API never executes your code. When the model calls a custom function, the run pauses and hands the call back to you. ## Define a custom tool Declare the tool in the `tools` array. Set `strict: true` to enforce the parameter schema. ```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 ``` ## Read the function call The run pauses and returns the call in the response `output` array as 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\"}" } ``` ## Return the result 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`: ```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 = { '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 ``` `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 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. ## Next steps The end-to-end how-to for wiring built-in, MCP, and custom tools into a run. Every built-in tool, plus MCP servers and custom functions. # 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. ```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 ``` ```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\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\n\n## Instructions\n\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 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 Make at most three tool calls before concluding.\n\n\n## Citation Instructions\n\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 are included below.\n\n\n- `web`: Internet sources\n- `page`: Full web page content\n- `conversation_history`: past queries and answers from your interaction with the user\n\n\n\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\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\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\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\n\n### Lists and Paragraphs\n\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\n\n### Summaries and Conclusions\n\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\n\n## Prohibited Meta-Commentary\n\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\n\n\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\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 } ``` ## 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 | Combine `web_search` and `fetch_url` for multi-step research: search to find relevant pages, then fetch the most important URLs for fuller context. ## 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.25 per 1,000 invocations**. Model token usage is billed separately according to Agent API token pricing. Pricing follows the same pattern as other tool calls: pay for tool invocations plus model tokens. See [Pricing](/docs/getting-started/pricing). ## Next Steps Search the web before fetching source content. Retrieve structured financial and market data. Search for professionals and employees. View complete endpoint documentation. # 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. | 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. ## Quickstart Add `finance_search` to the `tools` array. ```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"} ] }' ``` ```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 } ``` ## 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. ```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'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 }' ``` ```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 } ``` ### 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. ```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" \ -d '{ "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 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 } } } } ``` ### 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. ```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 }' ``` ```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'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 } ``` ## 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. Pricing follows the same pattern as other tool calls: pay for invocations plus model tokens. See [Pricing](/docs/getting-started/pricing). ## 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 Search the web for source-grounded context. Fetch full content from known URLs. Search for professionals and employees. Get started with the Agent API. # 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. 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. ```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', }, ], }); 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 ``` ```json theme={null} { "id": "resp_df17e3cb-5cdd-4197-a5c7-36746b4729cd", "model": "openai/gpt-5.6-sol", "object": "response", "status": "completed", "output": [ { "type": "mcp_list_tools", "id": "mcpl_8a21fbe7-9dfa-4b66-8326-24145ad33518", "server_label": "deepwiki", "tools": [ { "name": "read_wiki_structure", "description": "Get a list of documentation topics for a GitHub repository.", "input_schema": { "type": "object", "properties": { "repoName": { "type": "string" } }, "required": ["repoName"] } }, { "name": "read_wiki_contents", "description": "View documentation about a GitHub repository.", "input_schema": { "type": "object", "properties": { "repoName": { "type": "string" } }, "required": ["repoName"] } }, { "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": { "type": "string" }, "question": { "type": "string" } }, "required": ["repoName", "question"] } } ], "error": null }, { "type": "mcp_call", "id": "call_4zPrdxq5mvF107NpSktdKxgR", "server_label": "deepwiki", "name": "ask_question", "arguments": "{\"repoName\":\"perplexityai/perplexity-py\",\"question\":\"What does the perplexityai/perplexity-py repository do?\"}", "output": "The `perplexityai/perplexity-py` repository provides the official Python SDK for the Perplexity AI API. It offers type-safe access to chat completions, search, responses, embeddings, and browser sessions, with both synchronous and asynchronous clients...", "error": null }, { "type": "message", "role": "assistant", "status": "completed", "content": [ { "type": "output_text", "text": "The `perplexityai/perplexity-py` repository is the official Python SDK for the Perplexity AI API. It lets Python developers call Perplexity's services from their own applications using a typed, convenient client library instead of making raw HTTP requests...", "annotations": [] } ] } ], "usage": { "input_tokens": 2029, "output_tokens": 1335, "total_tokens": 3364 } } ``` ## 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: ```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 ``` 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`. ## 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. | ## 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. ### `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 \| null | `null` 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. | Example response `output` array: ```json theme={null} { "output": [ { "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"] } } ], "error": null }, { "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. 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. 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`. | | `defer_loading` | Ignored. Tools are discovered when the request starts. | | 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 Connect a remote MCP server with `type: mcp` and let the model call its tools automatically. Declare a `type: function` tool with a JSON Schema and run the call on your side. # 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." | **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. ### 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" | The tool works best for people-related queries — it is not suited for general web search. ## 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 | 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`. **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. ### pro Balanced configuration with all three tools enabled and moderate reasoning effort. ```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?" }' ``` ```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 } ``` ### deep Higher reasoning effort and step count with a generous output budget for fuller multi-source answers. ```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." }' ``` ```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 } ``` ### advanced-deep A frontier-model configuration for high-quality, multi-step research when latency budget is generous. ```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's professional background." }' ``` ```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 } ``` ### ultra-deep Maximum-depth configuration with the largest token budgets, the highest step count, and `xltokens` per-tool settings. Best for exhaustive investigations. `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. ```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." }' ``` ```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 } ``` ## 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 Search the web for source-grounded context. Fetch full content from known URLs. Retrieve structured financial and market data. Get started with the Agent API. # 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. ```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 ``` ## 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. ```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" ``` ## 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: ```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 ``` ```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. ```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 ``` ## 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. ```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'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." }' | jq ``` ```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 } ``` ## 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 | 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. ```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" } ] ``` ### 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. ```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 ``` ```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 } ``` ### 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. ```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 } ] ``` `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). ## 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 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. 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. `city` and `region` significantly improve location accuracy. Include them alongside `country` whenever possible. `latitude` and `longitude` must be provided together with `country`. They cannot be supplied on their own. ### 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 }` | 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. ```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'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" } } ] }' | jq ``` ```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 } ``` ## 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"`). | **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. ## Pricing `web_search` is billed at **\$2.50 per 1,000 invocations**. Model token usage is billed separately according to Agent API token pricing. Pricing follows the same pattern as other tool calls: pay for tool invocations plus model tokens. See [Pricing](/docs/getting-started/pricing). ## 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 Fetch full content from known URLs. Search for professionals, employees, and people. Use optimized presets for common Agent API workloads. View complete endpoint documentation. # 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. ```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 ``` ## How it works A wide-research run has three parts, each backed by its own feature page: 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). 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). 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). 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. ## Next Steps Submit, poll, stream, and reconnect long-running runs. List and download the files a run produces. See every preset and what it configures. Read the research behind wide-and-deep evaluation. # 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. ```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." }' ``` For runs that take a while, submit with `background=true` and poll before listing files. See [Background mode](/docs/agent-api/background-mode). ## List a response's files `GET /v1/agent/{id}/files` Use the response `id` from the run above to list the files it produced. ```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" ``` ```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`. 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. ```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 ``` ## Full example Create a run that writes a file, then list and download everything it produced. ```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)`); } ``` ## Next Steps # 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. 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. ## Prerequisites Install the Perplexity SDK: ```bash Python theme={null} pip install perplexityai ``` ```bash TypeScript theme={null} npm install @perplexity-ai/perplexity_ai ``` If you don't have an API key yet: Navigate to the **API Keys** tab in the API Portal and generate a new key. Then export your API key as an environment variable: ```bash theme={null} export PERPLEXITY_API_KEY="your-api-key" ``` ## Basic Academic Search Use `search_domain_filter` to restrict the Agent API's `web_search` tool to academic sources only. ```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." }' ``` 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. ## Extracting Paper Metadata Use structured outputs to extract detailed paper metadata from academic search results. ```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(); } ``` ## Building Citation Chains Trace how papers cite each other to understand the evolution of an idea across the literature. ```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)) ``` 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. ## Research Summary with Attribution Generate a research summary that properly attributes each claim to its source paper. ```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 { 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); ``` ## Multi-Field Academic Search Use field-specific domain filters to search across different academic disciplines. ```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 = { 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)); } ``` ## 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 Full reference for domain, recency, and location filters on the Agent API. Extract typed JSON for paper metadata and research findings. Control which domains the search includes or excludes. # 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: Navigate to the **API Keys** tab in the API Portal and generate a new key. 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. ```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" ``` ## 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 Full reference for the skills field, the built-in catalog, and inline skills. List and download files an Agent API response produced in the sandbox. Submit, poll, stream, and cancel long-running agent runs. # 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. 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. ## Prerequisites Install the Perplexity SDK: ```bash Python theme={null} pip install perplexityai ``` ```bash TypeScript theme={null} npm install @perplexity-ai/perplexity_ai ``` If you don't have an API key yet: Navigate to the **API Keys** tab in the API Portal and generate a new key. Then export your API key as an environment variable: ```bash theme={null} export PERPLEXITY_API_KEY="your-api-key" ``` ## Basic Deep Research Use the `medium` preset for comprehensive research queries. ```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." }' ``` The `medium` preset automatically selects the best model and configures tools for multi-step research. You don't need to specify a model or tools when using presets. ## Processing Deep Research Results Extract and format the key parts of a deep research response. ```python Python theme={null} from perplexity import Perplexity client = Perplexity() def deep_research(query: str) -> dict: """Run a deep research query and extract structured results.""" print(f"Researching: {query[:80]}...") response = client.responses.create( preset="medium", input=query, ) content = response.output_text usage = response.usage return { "content": content, "model": response.model, "tokens": { "input": usage.input_tokens if usage else 0, "output": usage.output_tokens if usage else 0, }, "word_count": len(content.split()), } if __name__ == "__main__": output = deep_research( "What is the current state of solid-state battery technology? " "Cover the leading companies, technical challenges remaining, " "and expected timeline for mass production in EVs." ) print(f"\nModel: {output['model']}") print(f"Words: {output['word_count']}") print(f"Tokens: {output['tokens']['input']} in, {output['tokens']['output']} out") print(f"\n{'='*60}\n") print(output["content"][:2000]) ``` ```typescript TypeScript theme={null} import Perplexity from '@perplexity-ai/perplexity_ai'; const client = new Perplexity(); async function deepResearch(query: string) { console.log(`Researching: ${query.slice(0, 80)}...`); const response = await client.responses.create({ preset: "medium", input: query, }); const content = response.output_text; const usage = response.usage; return { content, model: response.model, tokens: { input: usage?.input_tokens ?? 0, output: usage?.output_tokens ?? 0, }, wordCount: content.split(/\s+/).length, }; } const output = await deepResearch( "What is the current state of solid-state battery technology? Cover the leading companies, technical challenges remaining, and expected timeline for mass production in EVs." ); console.log(`\nModel: ${output.model}`); console.log(`Words: ${output.wordCount}`); console.log(`Tokens: ${output.tokens.input} in, ${output.tokens.output} out`); console.log(`\n${"=".repeat(60)}\n`); console.log(output.content.slice(0, 2000)); ``` ## Deep Research with Domain Filtering Combine deep research with domain filters for focused, authoritative research. ```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); ``` ## Batch Research with Concurrency Run multiple deep research queries concurrently using asyncio and the Perplexity SDK. ```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 { 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)`); } ``` 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. ## 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 Full reference for available presets including medium. Get started with the Agent API for multi-provider access and tools. Control which domains the search includes or excludes. Understand rate limits for research and batch workflows. # 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. 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). ## 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. RAG Pipeline Diagram 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: ```bash Python theme={null} pip install perplexityai ``` ```bash TypeScript theme={null} npm install @perplexity-ai/perplexity_ai ``` If you don't have an API key yet: Navigate to the **API Keys** tab in the API Portal and generate a new key. Then export your API key as an environment variable: ```bash theme={null} export PERPLEXITY_API_KEY="your-api-key" ``` ## 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. ```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)}...`); }); ``` 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. ## 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. ```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`); ``` ## 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. ```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)}...`); } } ``` **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. ## 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: ```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}`); ``` ## 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.). ```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 = { "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`); ``` ## 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. ```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 { // 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); ``` 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. ## 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. ```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`); ``` 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 | 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. ## 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. ```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 { 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`); ``` 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. **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. ## Complete Example A self-contained pipeline that indexes two documents with contextualized embeddings and answers questions against the indexed content. ```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 = { "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): Promise { 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 { 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)}`); } ``` ## Next Steps API reference for standard embedding parameters and response format. API reference for contextualized embedding parameters and response format. Encoding formats, similarity metrics, normalization, and error handling. Learn more about the Responses API used for answer generation. # 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. 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). ## Prerequisites Install the Perplexity SDK: ```bash Python theme={null} pip install perplexityai ``` ```bash TypeScript theme={null} npm install @perplexity-ai/perplexity_ai ``` If you don't have an API key yet: Navigate to the **API Keys** tab in the API Portal and generate a new key. Then export your API key as an environment variable: ```bash theme={null} export PERPLEXITY_API_KEY="your-api-key" ``` 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. ## 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. ```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 { // 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); ``` Always use `json.loads()` (Python) or `JSON.parse()` (TypeScript) on the `arguments` field. It is a JSON string, not a parsed object. ## 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. ```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 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); ``` 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. ## 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. ```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); ``` 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. ## 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. ```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 { if (!orderId.startsWith("ORD-")) { throw new Error(`Invalid order ID format: ${orderId}`); } return { order_id: orderId, status: "delivered" }; } function cancelOrder(orderId: string): Record { // Simulate a failure throw new Error("Order service is temporarily unavailable"); } function executeFunction(name: string, args: Record): Record { const functionMap: Record Record> = { 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 { 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; } ``` 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. ```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 = { 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 = { 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 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); ``` 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. ## Next Steps Review request parameters and tool schema fields. Choose a model for your function-calling workload. Get up and running with the Agent API in minutes. Combine function calling with structured outputs and response shaping. # 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. ## 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. 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 {"
": "..."}; 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: - — 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 professional-network sources." ), "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: " Each section's H2 heading must be exactly `## ·
` \ (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 \ 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. 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`: 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 # 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 ## 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 # 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 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. 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. ## Prerequisites Install the Perplexity SDK: ```bash Python theme={null} pip install perplexityai ``` ```bash TypeScript theme={null} npm install @perplexity-ai/perplexity_ai ``` If you don't have an API key yet: Navigate to the **API Keys** tab in the API Portal and generate a new key. Then export your API key as an environment variable: ```bash theme={null} export PERPLEXITY_API_KEY="your-api-key" ``` ## 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. ```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 = {}; 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 ``` 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. ```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)}...`); ``` ## 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. ```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)}...`); ``` 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. ## Comparing Responses Across Providers Send the same prompt to multiple models and compare quality, latency, and cost. ```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)}`); } } ``` ## Task-Based Model Routing Different tasks suit different models. Build a router that picks the best model for each task type. ```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 = { 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 = {}) { 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)); ``` ## 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. ```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) ``` ## Dynamic Model Discovery Build applications that automatically adapt to newly available models by querying the `/v1/models` endpoint at startup. ```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> { 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 = {}; 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, 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)); ``` 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. ## Next Steps Full list of available models, capabilities, and pricing. Deep dive into fallback chain configuration and behavior. CLI tool for benchmarking models side-by-side. Use presets like `low` for optimized defaults. # 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: Navigate to the **API Keys** tab in the API Portal and generate a new key. 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. ```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 = {}; 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)`); } ``` ## 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 How the container works, calling other tools from code, pricing, and limits. Submit, poll, stream, and cancel long-running agent runs. List and download files an Agent API response produced in the sandbox. # 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 ## 🎯 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. 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). ## Prerequisites Install the Perplexity SDK: ```bash Python theme={null} pip install perplexityai ``` ```bash TypeScript theme={null} npm install @perplexity-ai/perplexity_ai ``` If you don't have an API key yet: Navigate to the **API Keys** tab in the API Portal and generate a new key. Then export your API key as an environment variable: ```bash theme={null} export PERPLEXITY_API_KEY="your-api-key" ``` ## 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.* **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. ## Basic Domain Filtering Domain filters are configured per-tool under the `tools` array. ```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); ``` ## Pattern: Denylist Filtering Use the `-` prefix to exclude specific domains from search results. ```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); ``` ## 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. ```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); ``` 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`). ## Pattern: News-Only Search Restrict results to major news outlets for current events and breaking news. ```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); ``` Combine `search_domain_filter` with `search_recency_filter` for time-sensitive queries. Options are `day`, `week`, `month`, and `year`. ## Pattern: Government and Official Sources Restrict to government domains for policy, regulation, and official statistics. ```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); ``` ## Pattern: Academic and Research Filtering Target educational and research institutions. ```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); ``` ## Pattern: Competitor Exclusion Use denylists to exclude competitor websites from search results when building customer-facing content. ```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); ``` ## Configurable Filter Builder A reusable helper that builds domain filter configurations from named presets. ```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 = { 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 { if (!(preset in FILTER_PRESETS)) { throw new Error(`Unknown preset: ${preset}. Options: ${Object.keys(FILTER_PRESETS).join(", ")}`); } const filters: Record = { 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")); ``` ## 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 Full reference for domain, date range, and location filters on the Agent API. Domain filtering on the raw Search API for result-level control. Specialized academic search with domain filtering. # 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. 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. ## Prerequisites Install the SDKs: ```bash Python theme={null} pip install perplexityai openai ``` ```bash TypeScript theme={null} npm install @perplexity-ai/perplexity_ai openai ``` If you don't have an API key yet: Navigate to the **API Keys** tab in the API Portal and generate a new key. Then export your API key as an environment variable: ```bash theme={null} export PERPLEXITY_API_KEY="your-api-key" ``` ## 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. **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. ## Basic Streaming with Citations ```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 }' ``` ## 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. ```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(); 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); ``` ## 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. ```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> { 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}`); // }); ``` **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. ## 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. ```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(); 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?"); ``` ## 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. ```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(); } ``` 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. ## 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. ```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) ``` ## 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 Explore all presets and their citation formats. Get started with the Agent API for multi-provider access and tools. Streaming patterns and event types for the Agent API. # 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. 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). ## Prerequisites Install the Perplexity SDK: ```bash Python theme={null} pip install perplexityai ``` ```bash TypeScript theme={null} npm install @perplexity-ai/perplexity_ai ``` If you don't have an API key yet: Navigate to the **API Keys** tab in the API Portal and generate a new key. Then export your API key as an environment variable: ```bash theme={null} export PERPLEXITY_API_KEY="your-api-key" ``` ## 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. ```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}`); ``` ## Extracting Lists: Product Comparisons Extract a structured comparison of multiple items from a single query. ```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(); } ``` ## Research Findings Extraction Parse search-grounded research into a structured format suitable for reports or databases. ```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(); } ``` ## Building a Data Pipeline Chain structured output extraction into a pipeline that queries, extracts, and stores structured data. ```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) ``` ## Schema Design Constraints 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. ### 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. ```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']}") ``` 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. ## Next Steps Full reference for response\_format, streaming, and output shaping. Combine structured outputs with multi-turn function calling. Get started with the Agent API in minutes. Choose the right model for structured extraction tasks. # 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 Deep web research using the `medium` preset with structured report output. Compare responses from 5 providers side-by-side — quality, latency, and cost. Interactive TypeScript CLI with streaming, model selection, and web search. Vision + web search for context-enriched image analysis. Upload documents and ask questions about them with optional web search enrichment. Two chained agent requests: the sandbox searches and counts each brand's share of voice, then renders a downloadable bar-chart PDF. 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. 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. ### Search API Multi-topic news monitoring with domain filtering and recency control. Search SEC.gov and EDGAR for financial filings with structured data extraction. ### Embeddings API Self-contained RAG system with contextualized embeddings and Agent API answer generation. ## 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" ``` Get your API key at [perplexity.ai/account/api](https://perplexity.ai/account/api). ## 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 ```bash Python theme={null} pip install perplexityai pydantic ``` ```bash TypeScript theme={null} npm install @perplexity-ai/perplexity_ai ``` ## 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. 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. ## Full Code ```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 { const client = new Perplexity(); const params: Record = { 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 [--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(); ``` ## 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 ============================================================ ``` 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. 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. ## 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. 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. 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. ## 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. 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. ## 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-_