The DeepResearch API performs comprehensive research by searching multiple sources, analyzing content, and generating detailed reports. Unlike synchronous APIs, tasks run in the background, enabling thorough multi-step research that can take several minutes.
DeepResearch is ideal for complex research tasks. For quick answers to simple questions, use the Answer API instead.
Basic Usage
import { Valyu } from "valyu-js";
const valyu = new Valyu();
// Create a research task
const task = await valyu.deepresearch.create({
input: "What are the key differences between RAG and fine-tuning for LLMs?",
model: "lite"
});
if (task.success) {
console.log(`Task created: ${task.deepresearch_id}`);
// Wait for completion with progress updates
const result = await valyu.deepresearch.wait(task.deepresearch_id, {
onProgress: (s) => console.log(`Status: ${s.status}`)
});
if (result.status === "completed") {
console.log(result.output);
console.log(`Cost: $${result.usage?.total_cost.toFixed(4)}`);
}
}
Research Modes
DeepResearch offers two modes optimized for different use cases:
| Mode | Best For | Typical Completion Time |
|---|
lite | Quick research, fact-checking, straightforward questions | 5-10 minutes |
heavy | Complex analysis, multi-faceted topics, detailed reports | 15-30 minutes |
// Use heavy mode for complex research
const task = await valyu.deepresearch.create({
input: "Analyze the competitive landscape of cloud computing in 2024",
model: "heavy"
});
Parameters
| Parameter | Type | Description |
|---|
input | string | Research query or task description |
Options (Optional)
| Parameter | Type | Description | Default |
|---|
model | "lite" | "heavy" | Research mode | "lite" |
outputFormats | array | Output formats (see below) | ["markdown"] |
strategy | string | Natural language strategy instructions | undefined |
search | object | Search configuration (filters, date range) | undefined |
urls | string[] | URLs to analyze (max 10) | undefined |
files | FileAttachment[] | File attachments (max 10) | undefined |
mcpServers | MCPServerConfig[] | MCP server configurations (max 5) | undefined |
codeExecution | boolean | Enable code execution | true |
previousReports | string[] | Previous task IDs for context (max 3) | undefined |
webhookUrl | string | HTTPS URL for completion notification | undefined |
metadata | object | Custom metadata for tracking | undefined |
Markdown (Default)
const task = await valyu.deepresearch.create({
input: "Explain quantum computing advancements in 2024",
outputFormats: ["markdown"]
});
Markdown + PDF
Request both markdown and a downloadable PDF report:
const task = await valyu.deepresearch.create({
input: "Write a report on renewable energy trends",
outputFormats: ["markdown", "pdf"]
});
const result = await valyu.deepresearch.wait(task.deepresearch_id!);
if (result.pdf_url) {
console.log(`PDF available at: ${result.pdf_url}`);
}
Structured JSON
Get research results in a custom schema using JSON Schema specification:
const task = await valyu.deepresearch.create({
input: "Research competitor pricing in the SaaS market",
outputFormats: [{
type: "object",
properties: {
competitors: {
type: "array",
items: {
type: "object",
properties: {
name: { type: "string" },
pricing_model: { type: "string" },
price_range: { type: "string" },
key_features: {
type: "array",
items: { type: "string" }
}
},
required: ["name", "pricing_model"]
}
},
market_summary: { type: "string" },
recommendations: {
type: "array",
items: { type: "string" }
}
},
required: ["competitors", "market_summary"]
}]
});
const result = await valyu.deepresearch.wait(task.deepresearch_id!);
if (result.output_type === "json") {
const data = result.output as any;
data.competitors.forEach((competitor: any) => {
console.log(`${competitor.name}: ${competitor.pricing_model}`);
});
}
You cannot mix JSON Schema with markdown/pdf formats. Use one or the other.
The schema must be a valid JSON Schema. Use type, properties, required, items, and other standard JSON Schema keywords.
Search Configuration
Filter which sources the research uses:
const task = await valyu.deepresearch.create({
input: "Latest AI research in healthcare diagnostics",
model: "heavy",
search: {
searchType: "all", // "all", "web", or "proprietary"
includedSources: ["pubmed", "arxiv", "nature.com"]
}
});
Search Types
| Type | Description |
|---|
all | Search web and proprietary sources (default) |
web | Web sources only |
proprietary | Academic and premium sources only |
File Attachments
Analyze documents as part of research:
import * as fs from "fs";
// Read and encode a PDF
const pdfBuffer = fs.readFileSync("report.pdf");
const pdfData = pdfBuffer.toString("base64");
const task = await valyu.deepresearch.create({
input: "Summarize the key findings and compare with market trends",
model: "heavy",
files: [{
data: `data:application/pdf;base64,${pdfData}`,
filename: "report.pdf",
mediaType: "application/pdf",
context: "Q4 2024 financial report" // Optional context
}]
});
Supported file types: PDFs, images (PNG, JPEG, WebP), and documents.
Include specific URLs to analyze alongside web research:
const task = await valyu.deepresearch.create({
input: "Compare the approaches described in these articles",
urls: [
"https://example.com/article-1",
"https://example.com/article-2"
]
});
Waiting for Completion
Basic Wait
const result = await valyu.deepresearch.wait(task.deepresearch_id!);
if (result.status === "completed") {
console.log(result.output);
}
With Progress Callback
Track research progress in real-time:
const result = await valyu.deepresearch.wait(task.deepresearch_id!, {
pollInterval: 5000, // Check every 5 seconds
maxWaitTime: 900000, // Timeout after 15 minutes (lite mode)
onProgress: (status) => {
if (status.progress) {
const pct = (status.progress.current_step / status.progress.total_steps) * 100;
console.log(`Progress: ${pct.toFixed(0)}% - Step ${status.progress.current_step}/${status.progress.total_steps}`);
}
console.log(`Status: ${status.status}`);
}
});
Polling Options
| Option | Type | Description | Default |
|---|
pollInterval | number | Milliseconds between status checks | 5000 |
maxWaitTime | number | Maximum wait time in milliseconds | 3600000 |
onProgress | function | Callback for progress updates | undefined |
interface DeepResearchStatusResponse {
success: boolean;
deepresearch_id?: string;
status?: "queued" | "running" | "completed" | "failed" | "cancelled";
query?: string;
mode?: "lite" | "heavy";
output_type?: "markdown" | "json";
output?: string | Record<string, any>; // Research output
sources?: DeepResearchSource[]; // Sources used
usage?: DeepResearchUsage; // Cost breakdown
completed_at?: number; // Unix timestamp
pdf_url?: string; // PDF download URL
images?: ImageMetadata[]; // Generated images
error?: string; // Error message if failed
}
Source Object
interface DeepResearchSource {
title: string;
url: string;
snippet?: string;
source?: string; // web, pubmed, arxiv, etc.
word_count?: number;
doi?: string; // For academic papers
}
Usage Object
interface DeepResearchUsage {
search_cost: number; // Search operations
contents_cost: number; // Content retrieval
ai_cost: number; // AI processing
compute_cost: number; // Compute resources
total_cost: number; // Total billed
}
Task Management
Check Status
const status = await valyu.deepresearch.status(taskId);
console.log(`Status: ${status.status}`);
if (status.progress) {
console.log(`Step ${status.progress.current_step}/${status.progress.total_steps}`);
}
Add Follow-up Instructions
Add instructions to a running task:
const response = await valyu.deepresearch.update(
taskId,
"Focus more on peer-reviewed sources from 2024"
);
if (response.success) {
console.log("Instruction added");
}
Cancel a Task
const response = await valyu.deepresearch.cancel(taskId);
if (response.success) {
console.log("Task cancelled");
}
Delete a Task
const response = await valyu.deepresearch.delete(taskId);
if (response.success) {
console.log("Task deleted");
}
List All Tasks
const tasks = await valyu.deepresearch.list({
apiKeyId: "your-api-key-id",
limit: 50
});
tasks.data?.forEach(task => {
console.log(`${task.query?.substring(0, 50)}... - ${task.status}`);
});
Webhooks
Get notified when research completes instead of polling. Webhooks are ideal for production systems and serverless architectures.
Setup
const task = await valyu.deepresearch.create({
input: "Research market trends in AI",
webhookUrl: "https://your-app.com/webhooks/deepresearch" // Must be HTTPS
});
// IMPORTANT: Save the secret immediately - it's only returned once
const webhookSecret = task.webhook_secret;
console.log(`Store securely: ${webhookSecret}`);
The webhook_secret is only returned once. Store it securely—you cannot retrieve it later.
Verifying Signatures
Always verify webhook signatures to ensure authenticity:
import crypto from "crypto";
function verifyWebhook(
payloadBody: string,
signatureHeader: string,
timestampHeader: string,
secret: string
): boolean {
// Reconstruct signed payload: timestamp.payload
const signedPayload = `${timestampHeader}.${payloadBody}`;
// Generate expected signature
const expectedSignature = "sha256=" + crypto
.createHmac("sha256", secret)
.update(signedPayload)
.digest("hex");
// Constant-time comparison prevents timing attacks
return crypto.timingSafeEqual(
Buffer.from(expectedSignature),
Buffer.from(signatureHeader)
);
}
Handling Webhooks
import express from "express";
const app = express();
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET!;
app.post(
"/webhooks/deepresearch",
express.raw({ type: "application/json" }),
(req, res) => {
const signature = req.headers["x-webhook-signature"] as string;
const timestamp = req.headers["x-webhook-timestamp"] as string;
const payload = req.body.toString();
if (!verifyWebhook(payload, signature, timestamp, WEBHOOK_SECRET)) {
return res.status(401).json({ error: "Invalid signature" });
}
const data = JSON.parse(payload);
if (data.status === "completed") {
// Process completed research
saveResearchResult(data.deepresearch_id, data.output);
} else if (data.status === "failed") {
// Handle failure
logError(data.deepresearch_id, data.error);
}
return res.status(200).json({ received: true });
}
);
| Header | Description |
|---|
X-Webhook-Signature | HMAC-SHA256 signature: sha256=<hex> |
X-Webhook-Timestamp | Unix timestamp (ms) when sent |
Content-Type | application/json |
Retry Behavior
- 5 retry attempts with exponential backoff (1s → 2s → 4s → 8s → 16s)
- 15 second timeout per request
- 4xx errors: No retry (client error)
- 5xx errors: Will retry (server error)
Return a 2xx status quickly and process the payload asynchronously to avoid timeouts.
Use Case Examples
Academic Research Assistant
const task = await valyu.deepresearch.create({
input: "Analyze recent advances in transformer architectures for NLP",
model: "heavy",
search: {
searchType: "proprietary",
includedSources: ["arxiv", "pubmed", "nature.com"]
},
strategy: "Focus on peer-reviewed sources. Include methodology comparisons and performance benchmarks."
});
const result = await valyu.deepresearch.wait(task.deepresearch_id!);
// Access academic sources
result.sources?.forEach(source => {
if (source.doi) {
console.log(`📄 ${source.title}`);
console.log(` DOI: ${source.doi}`);
}
});
Competitive Intelligence
interface CompetitiveAnalysis {
market_overview: string;
key_players: Array<{
company: string;
market_share: string;
strengths: string[];
weaknesses: string[];
}>;
trends: string[];
opportunities: string[];
}
const task = await valyu.deepresearch.create({
input: "Analyze the competitive landscape of the cloud computing market",
model: "heavy",
outputFormats: [{
type: "object",
properties: {
market_overview: { type: "string" },
key_players: {
type: "array",
items: {
type: "object",
properties: {
company: { type: "string" },
market_share: { type: "string" },
strengths: { type: "array", items: { type: "string" } },
weaknesses: { type: "array", items: { type: "string" } }
}
}
},
trends: { type: "array", items: { type: "string" } },
opportunities: { type: "array", items: { type: "string" } }
},
required: ["market_overview", "key_players", "trends"]
}]
});
const result = await valyu.deepresearch.wait(task.deepresearch_id!);
if (result.output_type === "json") {
const analysis = result.output as CompetitiveAnalysis;
console.log(`Market Overview: ${analysis.market_overview}\n`);
analysis.key_players.forEach(player => {
console.log(`📊 ${player.company} (${player.market_share})`);
console.log(` Strengths: ${player.strengths.slice(0, 3).join(", ")}`);
});
}
Document Analysis
import * as fs from "fs";
// Load multiple documents
const files = ["q1_report.pdf", "q2_report.pdf"].map(filename => {
const buffer = fs.readFileSync(filename);
const data = buffer.toString("base64");
return {
data: `data:application/pdf;base64,${data}`,
filename,
mediaType: "application/pdf"
};
});
const task = await valyu.deepresearch.create({
input: "Compare performance across these quarterly reports. Identify trends and anomalies.",
model: "heavy",
files,
outputFormats: ["markdown", "pdf"]
});
const result = await valyu.deepresearch.wait(task.deepresearch_id!);
console.log(`Analysis complete. PDF: ${result.pdf_url}`);
Error Handling
const task = await valyu.deepresearch.create({
input: "Research query"
});
if (!task.success) {
console.error(`Failed to create task: ${task.error}`);
return;
}
try {
const result = await valyu.deepresearch.wait(task.deepresearch_id!, {
maxWaitTime: 900000 // 15 minutes for lite, use 2700000 for heavy
});
if (result.status === "completed") {
console.log(result.output);
} else if (result.status === "failed") {
console.error(`Research failed: ${result.error}`);
}
} catch (error: any) {
if (error.message.includes("Maximum wait time")) {
console.log("Task timed out - cancelling");
await valyu.deepresearch.cancel(task.deepresearch_id!);
} else {
console.error(`Task error: ${error.message}`);
}
}
Best Practices
Choose the Right Mode
// Lite: Quick research, simple questions
await valyu.deepresearch.create({
input: "What is the current market cap of Apple?",
model: "lite"
});
// Heavy: Complex analysis, detailed reports
await valyu.deepresearch.create({
input: "Analyze Apple's competitive position vs Microsoft in cloud services",
model: "heavy"
});
Optimize Polling
// Lite mode: poll every 5 seconds, 15 min timeout
await valyu.deepresearch.wait(taskId, { pollInterval: 5000, maxWaitTime: 900000 });
// Heavy mode: poll every 15 seconds, 45 min timeout
await valyu.deepresearch.wait(taskId, { pollInterval: 15000, maxWaitTime: 2700000 });
// Production: use webhooks instead
await valyu.deepresearch.create({
input: "...",
webhookUrl: "https://your-app.com/webhooks"
});
Provide Clear Context
// ❌ Vague
await valyu.deepresearch.create({ input: "Tell me about AI" });
// ✅ Specific with context
await valyu.deepresearch.create({
input: "What are the practical applications of large language models in healthcare, focusing on diagnostic assistance and clinical documentation?",
strategy: "Focus on peer-reviewed studies and real-world deployments. Include both benefits and limitations.",
search: { searchType: "proprietary" }
});
Type-Safe Structured Output
// Define your expected output structure
interface ResearchOutput {
summary: string;
key_findings: string[];
recommendations: string[];
}
const result = await valyu.deepresearch.wait(taskId);
if (result.output_type === "json" && result.output) {
const data = result.output as ResearchOutput;
// TypeScript now knows the structure
console.log(data.summary);
data.key_findings.forEach(finding => console.log(`- ${finding}`));
}
Handle Long-Running Tasks
async function researchWithStatus(query: string) {
const task = await valyu.deepresearch.create({
input: query,
model: "heavy"
});
if (!task.success) {
return null;
}
console.log(`Started research: ${task.deepresearch_id}`);
try {
const result = await valyu.deepresearch.wait(task.deepresearch_id!, {
pollInterval: 10000,
maxWaitTime: 2700000, // 45 minutes for heavy mode
onProgress: (s) => console.log(` ${s.status}...`)
});
return result;
} catch (error: any) {
if (error.message.includes("Maximum wait time")) {
// Check if still running
const status = await valyu.deepresearch.status(task.deepresearch_id!);
if (status.status === "running") {
console.log("Still running - check back later");
return status;
}
}
throw error;
}
}
const result = await researchWithStatus("Comprehensive market analysis of EV industry");