> ## Documentation Index
> Fetch the complete documentation index at: https://docs.perplexity.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent API vs 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.

export const MIGRATION_BENCHMARKS = {
  browseComp: [{
    api: 'sonar',
    label: 'Sonar',
    score: 7.00,
    cost: 7.0,
    labelDx: 8,
    labelDy: 7
  }, {
    api: 'sonar',
    label: 'Pro',
    score: 7.33,
    cost: 15.6,
    labelDx: 6,
    labelDy: 5
  }, {
    api: 'sonar',
    label: 'Reasoning Pro',
    score: 16.33,
    cost: 16.3,
    labelDx: 11,
    labelDy: -12
  }, {
    api: 'sonar',
    label: 'Deep Research',
    score: 29.10,
    cost: 611.0,
    labelDx: -49,
    labelDy: 22
  }, {
    api: 'agent',
    label: 'fast',
    score: 14.00,
    cost: 11.7,
    labelDx: 4,
    labelDy: 10
  }, {
    api: 'agent',
    label: 'low',
    score: 40.00,
    cost: 67.9,
    labelDx: -25,
    labelDy: -19
  }, {
    api: 'agent',
    label: 'medium',
    score: 62.88,
    cost: 206.1,
    labelDx: -26,
    labelDy: -19
  }, {
    api: 'agent',
    label: 'high',
    score: 79.67,
    cost: 777.6,
    labelDx: 21,
    labelDy: -21
  }],
  deepSearchQA: [{
    api: 'sonar',
    label: 'Sonar',
    score: 27.26,
    cost: 5.9,
    labelDx: -6,
    labelDy: 19
  }, {
    api: 'sonar',
    label: 'Pro',
    score: 30.11,
    cost: 20.9,
    labelDx: 2,
    labelDy: 14
  }, {
    api: 'sonar',
    label: 'Reasoning Pro',
    score: 38.41,
    cost: 26.0,
    labelDy: 15
  }, {
    api: 'sonar',
    label: 'Deep Research',
    score: 48.94,
    cost: 565.6,
    labelDx: 36,
    labelDy: 23
  }, {
    api: 'agent',
    label: 'fast',
    score: 37.49,
    cost: 11.9,
    labelDx: -14,
    labelDy: -20
  }, {
    api: 'agent',
    label: 'low',
    score: 75.61,
    cost: 57.0,
    labelDx: -25,
    labelDy: -19
  }, {
    api: 'agent',
    label: 'medium',
    score: 82.58,
    cost: 168.7,
    labelDx: -30,
    labelDy: -19
  }, {
    api: 'agent',
    label: 'high',
    score: 85.86,
    cost: 527.8,
    labelDx: 22,
    labelDy: -20
  }],
  wideSearch: [{
    api: 'sonar',
    label: 'Sonar',
    score: 8.01,
    cost: 6.4,
    labelDx: 5,
    labelDy: 11
  }, {
    api: 'sonar',
    label: 'Pro',
    score: 17.92,
    cost: 28.5,
    labelDx: -3,
    labelDy: 21
  }, {
    api: 'sonar',
    label: 'Reasoning Pro',
    score: 18.90,
    cost: 32.0,
    labelDy: 16
  }, {
    api: 'sonar',
    label: 'Deep Research',
    score: 19.42,
    cost: 581.5,
    labelDx: -46,
    labelDy: 19
  }, {
    api: 'agent',
    label: 'fast',
    score: 19.41,
    cost: 17.9,
    labelDx: 5,
    labelDy: -15
  }, {
    api: 'agent',
    label: 'low',
    score: 47.28,
    cost: 54.2,
    labelDx: -21,
    labelDy: -19
  }, {
    api: 'agent',
    label: 'medium',
    score: 53.05,
    cost: 179.5,
    labelDx: -26,
    labelDy: -19
  }, {
    api: 'agent',
    label: 'high',
    score: 63.86,
    cost: 939.0,
    labelDx: 22,
    labelDy: -19
  }]
};

export const MigrationBenchmarkChart = ({benchmarks = {}} = {}) => {
  const benchmarkTabs = [{
    key: 'browseComp',
    label: 'BrowseComp',
    metric: 'Accuracy'
  }, {
    key: 'deepSearchQA',
    label: 'DSQA',
    metric: 'F1'
  }, {
    key: 'wideSearch',
    label: 'WideSearch',
    metric: 'F1'
  }];
  const seriesByApi = {
    agent: {
      label: 'Agent API',
      color: 'var(--cb-agent-api-fg)'
    },
    sonar: {
      label: 'Sonar',
      color: 'var(--cb-sonar-api-fg)'
    }
  };
  const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
  const formatCostPerRequest = cost => `$${(cost / 1000).toFixed(cost >= 100 ? 4 : 5)}`;
  const formatScore = score => `${score.toFixed(2)}%`;
  const [activeTabKey, setActiveTabKey] = useState('browseComp');
  const [hoveredPointKey, setHoveredPointKey] = useState(null);
  const [copyStatus, setCopyStatus] = useState('');
  const tabRefs = useRef([]);
  const activeTab = benchmarkTabs.find(tab => tab.key === activeTabKey) || benchmarkTabs[0];
  const points = Array.isArray(benchmarks[activeTab.key]) ? benchmarks[activeTab.key] : [];
  const validPoints = points.filter(point => point && seriesByApi[point.api] && Number.isFinite(point.cost) && point.cost > 0 && Number.isFinite(point.score));
  if (validPoints.length === 0) {
    return null;
  }
  const width = 680;
  const height = 400;
  const plot = {
    left: 52,
    right: 22,
    top: 22,
    bottom: 50
  };
  const plotWidth = width - plot.left - plot.right;
  const plotHeight = height - plot.top - plot.bottom;
  const baselineY = plot.top + plotHeight;
  const maxCost = Math.max(...validPoints.map(point => point.cost));
  const niceStep = (range, count) => {
    const raw = range / count;
    const magnitude = Math.pow(10, Math.floor(Math.log10(raw)));
    const normalized = raw / magnitude;
    const step = normalized >= 5 ? 5 : normalized >= 2 ? 2 : 1;
    return step * magnitude;
  };
  const xStep = niceStep(maxCost, 5);
  const xMax = Math.ceil(maxCost / xStep) * xStep;
  const x = cost => plot.left + cost / xMax * plotWidth;
  const y = score => plot.top + plotHeight - score / 100 * plotHeight;
  const pointX = point => x(point.cost) + (point.dx ?? 0);
  const pointY = point => y(point.score) + (point.dy ?? 0);
  const yTicks = [0, 20, 40, 60, 80, 100];
  const xTicks = [];
  for (let tick = 0; tick <= xMax + xStep * 0.001; tick += xStep) {
    xTicks.push(Number(tick.toFixed(6)));
  }
  const pointKey = point => `${point.api}-${point.label}`;
  const activePoint = validPoints.find(point => pointKey(point) === hoveredPointKey);
  const tabPanelId = `migration-benchmark-${activeTab.key}`;
  const activeTabId = `migration-benchmark-tab-${activeTab.key}`;
  const selectTab = (index, moveFocus = false) => {
    const tab = benchmarkTabs[index];
    if (!tab) return;
    setActiveTabKey(tab.key);
    setHoveredPointKey(null);
    setCopyStatus('');
    if (moveFocus) {
      requestAnimationFrame(() => {
        const tab = tabRefs.current[index];
        if (tab) tab.focus();
      });
    }
  };
  const handleTabKeyDown = (event, index) => {
    const lastIndex = benchmarkTabs.length - 1;
    const nextIndexByKey = {
      ArrowLeft: index === 0 ? lastIndex : index - 1,
      ArrowRight: index === lastIndex ? 0 : index + 1,
      Home: 0,
      End: lastIndex
    };
    const nextIndex = nextIndexByKey[event.key];
    if (nextIndex === undefined) return;
    event.preventDefault();
    selectTab(nextIndex, true);
  };
  const guardZoom = panel => {
    if (!panel || panel.__mbcZoomGuard) return;
    panel.__mbcZoomGuard = true;
    const wrap = panel.closest('[data-rmiz]') || panel;
    const neutralize = () => {
      const svg = panel.querySelector('svg');
      if (svg) svg.style.cursor = 'default';
      const zoomBtn = wrap.querySelector('[data-rmiz-btn-zoom]');
      if (zoomBtn) zoomBtn.style.display = 'none';
    };
    neutralize();
    if (typeof requestAnimationFrame === 'function') requestAnimationFrame(neutralize);
    wrap.addEventListener('click', event => {
      const target = event.target;
      if (panel.contains(target) || target.closest && target.closest('[data-rmiz-btn-zoom]')) {
        event.stopPropagation();
      }
    }, true);
  };
  const flashCopied = status => {
    setCopyStatus(status);
    if (typeof window !== 'undefined') {
      window.setTimeout(() => setCopyStatus(''), 2000);
    }
  };
  const copyTable = async () => {
    const header = `| Configuration | API | Score | Cost per request |`;
    const divider = '| --- | --- | ---: | ---: |';
    const rows = validPoints.map(point => `| ${point.label} | ${seriesByApi[point.api].label} | ${formatScore(point.score)} | ${formatCostPerRequest(point.cost)} |`);
    const text = [header, divider, ...rows].join('\n');
    if (typeof navigator !== 'undefined' && navigator.clipboard && navigator.clipboard.writeText) {
      try {
        await navigator.clipboard.writeText(text);
        flashCopied('Copied');
        return;
      } catch {}
    }
    if (typeof document === 'undefined') {
      flashCopied('Copy failed');
      return;
    }
    try {
      const textarea = document.createElement('textarea');
      textarea.value = text;
      textarea.style.position = 'fixed';
      textarea.style.opacity = '0';
      document.body.appendChild(textarea);
      textarea.select();
      const copied = document.execCommand('copy');
      document.body.removeChild(textarea);
      flashCopied(copied ? 'Copied' : 'Copy failed');
    } catch {
      flashCopied('Copy failed');
    }
  };
  const tooltipX = activePoint ? clamp(pointX(activePoint) + 14, 8, width - 196) : 0;
  const tooltipY = activePoint ? clamp(pointY(activePoint) - 74, 8, height - 78) : 0;
  const labelGeom = point => {
    const cx = pointX(point);
    const cy = pointY(point);
    const fs = 11;
    const padX = 5;
    const padY = 3;
    const textW = point.label.length * fs * 0.58;
    const pillW = textW + padX * 2;
    const pillH = fs + padY * 2;
    const anchor = cx > width - 120 ? 'end' : 'start';
    const labelX = clamp(cx + (anchor === 'end' ? -10 : 10) + (point.labelDx ?? 0), plot.left + 4, width - plot.right - 4);
    const labelY = clamp(cy + (point.labelDy ?? -14), plot.top + 12, baselineY - 4);
    const pillX = anchor === 'end' ? labelX - textW - padX : labelX - padX;
    return {
      fs,
      pillW,
      pillH,
      anchor,
      labelX,
      labelY,
      pillX
    };
  };
  const labelVisible = (() => {
    const set = new Set();
    const gap = 2;
    const placed = [];
    const ordered = [...validPoints].sort((a, b) => (a.api === 'agent' ? 0 : 1) - (b.api === 'agent' ? 0 : 1) || b.score - a.score);
    for (const point of ordered) {
      const g = labelGeom(point);
      const box = {
        left: g.pillX - gap,
        top: g.labelY - g.pillH / 2 - gap,
        right: g.pillX + g.pillW + gap,
        bottom: g.labelY + g.pillH / 2 + gap
      };
      const overlaps = placed.some(p => !(box.right <= p.left || box.left >= p.right || box.bottom <= p.top || box.top >= p.bottom));
      if (!overlaps) {
        placed.push(box);
        set.add(pointKey(point));
      }
    }
    return set;
  })();
  const renderLabel = point => {
    const key = pointKey(point);
    const token = point.api === 'agent' ? 'agent-api' : 'sonar-api';
    const g = labelGeom(point);
    return <g key={`label-${key}`} pointerEvents="none">
        <rect x={g.pillX} y={g.labelY - g.pillH / 2} width={g.pillW} height={g.pillH} rx="3" fill="var(--cb-popover-bg)" />
        <rect x={g.pillX} y={g.labelY - g.pillH / 2} width={g.pillW} height={g.pillH} rx="3" fill={`var(--cb-${token}-bg)`} />
        <text x={g.labelX} y={g.labelY} textAnchor={g.anchor} dominantBaseline="central" fill={`var(--cb-${token}-fg)`} fontSize={g.fs} fontWeight="600">{point.label}</text>
      </g>;
  };
  return <figure className="mbc-card not-prose mx-auto overflow-hidden" style={{
    maxWidth: 720,
    marginTop: 24,
    marginBottom: 24,
    border: '1px solid var(--color-border)',
    borderRadius: 14,
    backgroundColor: 'var(--color-card)'
  }} aria-label="Sonar and Agent API benchmark comparison">
      <style>{`
        .mbc-card :focus:not(:focus-visible) { outline: none !important; }
        .mbc-card button:focus-visible { outline: 2px solid var(--cb-agent-api-fg); outline-offset: 2px; }
        /* Mintlify wraps the snippet in react-medium-image-zoom, which treats the chart SVG as a
           zoomable image (zoom-in cursor + click-to-zoom overlay). Disable that for this chart only. */
        span[data-rmiz]:has(.mbc-card) [data-rmiz-btn-zoom] { display: none !important; }
        span[data-rmiz]:has(.mbc-card) svg { cursor: default !important; }
      `}</style>

      <div className="flex items-center justify-between border-b px-2" style={{
    borderColor: 'var(--color-border)'
  }}>
        <div role="tablist" aria-label="Benchmark" className="flex flex-wrap items-center">
          {benchmarkTabs.map((tab, index) => {
    const isActive = tab.key === activeTab.key;
    return <button key={tab.key} ref={element => {
      tabRefs.current[index] = element;
    }} id={`migration-benchmark-tab-${tab.key}`} type="button" role="tab" aria-selected={isActive} aria-controls={`migration-benchmark-${tab.key}`} tabIndex={isActive ? 0 : -1} className={`relative min-h-[40px] rounded-t-[8px] rounded-b-none px-3.5 py-2 text-sm transition-colors ${isActive ? 'font-medium' : ''}`} style={{
      color: isActive ? 'var(--color-foreground)' : 'var(--color-muted-foreground)',
      cursor: 'pointer'
    }} onClick={() => selectTab(index)} onKeyDown={event => handleTabKeyDown(event, index)}>
                {tab.label}
                {isActive && <span className="absolute inset-x-0 -bottom-px h-0.5" style={{
      backgroundColor: 'var(--cb-agent-api-fg)'
    }} aria-hidden="true" />}
              </button>;
  })}
        </div>

        <div className="flex items-center" style={{
    gap: 8
  }}>
          <span className="sr-only" aria-live="polite">{copyStatus}</span>
          <button type="button" className="rounded-[8px] border text-xs transition-colors hover:bg-[var(--cb-hover)]" style={{
    padding: '5px 10px',
    color: 'var(--color-foreground)',
    borderColor: 'var(--color-border)',
    cursor: 'pointer'
  }} aria-label={`Copy ${activeTab.label} benchmark data as a table`} onClick={copyTable}>
            {copyStatus === 'Copied' ? 'Copied ✓' : 'Copy table'}
          </button>
        </div>
      </div>

      <div className="flex items-center justify-end" style={{
    gap: 16,
    padding: '12px 18px 0'
  }} aria-label="Chart legend">
        {Object.entries(seriesByApi).map(([key, series]) => {
    const isAgent = key === 'agent';
    return <span key={key} className="inline-flex items-center text-xs font-medium text-foreground" style={{
      gap: 7
    }}>
              <span aria-hidden="true" style={{
      position: 'relative',
      display: 'inline-block',
      width: 22,
      height: 12
    }}>
                <span style={{
      position: 'absolute',
      top: '50%',
      left: 0,
      width: '100%',
      height: 0,
      borderTop: `${isAgent ? '2px solid' : '2px dashed'} ${series.color}`,
      opacity: isAgent ? 1 : 0.8,
      transform: 'translateY(-50%)'
    }} />
                <span style={{
      position: 'absolute',
      top: '50%',
      left: '50%',
      width: 8,
      height: 8,
      backgroundColor: series.color,
      border: '1.5px solid var(--cb-popover-bg)',
      borderRadius: isAgent ? '50%' : '1px',
      transform: isAgent ? 'translate(-50%, -50%)' : 'translate(-50%, -50%) rotate(45deg)'
    }} />
              </span>
              {series.label}
            </span>;
  })}
      </div>

      <div id={tabPanelId} ref={guardZoom} role="tabpanel" aria-labelledby={activeTabId} className="overflow-x-auto" style={{
    padding: '4px 14px 14px'
  }}>
        <svg viewBox={`0 0 ${width} ${height}`} width="680" style={{
    display: 'block',
    width: '100%',
    minWidth: 540,
    height: 'auto'
  }} role="img" aria-label={`${activeTab.label}: score by cost per request for Agent API presets and Sonar models. Hover or focus a point for details.`}>
          {}
          {yTicks.map(tick => <g key={`y-${tick}`}>
              {tick !== 0 && <line x1={plot.left} x2={width - plot.right} y1={y(tick)} y2={y(tick)} stroke="var(--color-muted-foreground)" strokeWidth="1" strokeDasharray="1 4" opacity="0.3" />}
              <text x={plot.left - 10} y={y(tick) + 4} textAnchor="end" fill="var(--color-muted-foreground)" fontSize="11">{`${tick}%`}</text>
            </g>)}
          {xTicks.map(tick => <g key={`x-${tick}`}>
              {tick !== 0 && <line x1={x(tick)} x2={x(tick)} y1={plot.top} y2={baselineY} stroke="var(--color-muted-foreground)" strokeWidth="1" strokeDasharray="1 4" opacity="0.3" />}
              <text x={x(tick)} y={baselineY + 20} textAnchor="middle" fill="var(--color-muted-foreground)" fontSize="11">
                {`$${(tick / 1000).toFixed(2)}`}
              </text>
            </g>)}
          {}
          <line x1={plot.left} x2={plot.left} y1={plot.top} y2={baselineY} stroke="var(--color-border)" strokeWidth="1" opacity="0.6" />
          <line x1={plot.left} x2={width - plot.right} y1={baselineY} y2={baselineY} stroke="var(--color-border)" strokeWidth="1" opacity="0.6" />

          {Object.keys(seriesByApi).map(api => {
    const seriesPoints = validPoints.filter(point => point.api === api).sort((a, b) => a.cost - b.cost);
    const path = seriesPoints.map((point, index) => `${index === 0 ? 'M' : 'L'} ${pointX(point)} ${pointY(point)}`).join(' ');
    const isAgent = api === 'agent';
    return <path key={api} d={path} fill="none" stroke={seriesByApi[api].color} strokeWidth={isAgent ? 2.5 : 1.5} strokeLinecap="round" strokeLinejoin="round" strokeDasharray={isAgent ? undefined : '5 5'} opacity={isAgent ? 1 : 0.7} />;
  })}

          {}
          {validPoints.map(point => {
    const series = seriesByApi[point.api];
    const key = pointKey(point);
    const isAgent = point.api === 'agent';
    const cx = pointX(point);
    const cy = pointY(point);
    const accessibleLabel = `${series.label} ${point.label}: score ${formatScore(point.score)}, ${formatCostPerRequest(point.cost)} per request`;
    const ring = 'var(--cb-popover-bg)';
    return <g key={key} aria-label={accessibleLabel} onMouseEnter={() => setHoveredPointKey(key)} onMouseLeave={() => setHoveredPointKey(null)} style={{
      cursor: 'default'
    }}>
                {isAgent ? <circle cx={cx} cy={cy} r="6" fill={series.color} stroke={ring} strokeWidth="1.75" /> : <polygon points={`${cx},${cy - 6.6} ${cx + 6.6},${cy} ${cx},${cy + 6.6} ${cx - 6.6},${cy}`} fill={series.color} stroke={ring} strokeWidth="1.75" strokeLinejoin="round" />}
              </g>;
  })}

          {}
          {activePoint && (() => {
    const series = seriesByApi[activePoint.api];
    const isAgent = activePoint.api === 'agent';
    const cx = pointX(activePoint);
    const cy = pointY(activePoint);
    const ring = 'var(--cb-popover-bg)';
    return <g pointerEvents="none">
                <circle cx={cx} cy={cy} r="11" fill={series.color} opacity="0.16" />
                {isAgent ? <circle cx={cx} cy={cy} r="7" fill={series.color} stroke={ring} strokeWidth="2" /> : <polygon points={`${cx},${cy - 7.7} ${cx + 7.7},${cy} ${cx},${cy + 7.7} ${cx - 7.7},${cy}`} fill={series.color} stroke={ring} strokeWidth="2" strokeLinejoin="round" />}
              </g>;
  })()}

          {}
          {validPoints.filter(point => labelVisible.has(pointKey(point)) && pointKey(point) !== hoveredPointKey).map(point => renderLabel(point))}
          {activePoint && renderLabel(activePoint)}

          <text x={plot.left + plotWidth / 2} y={height - 8} textAnchor="middle" fill="var(--color-muted-foreground)" fontSize="11">
            Cost per request
          </text>
          <text x="13" y={plot.top + plotHeight / 2} textAnchor="middle" fill="var(--color-muted-foreground)" fontSize="11" transform={`rotate(-90 13 ${plot.top + plotHeight / 2})`}>
            {activeTab.metric}
          </text>

          {activePoint && <g pointerEvents="none" role="tooltip">
              <rect x={tooltipX} y={tooltipY} width="188" height="74" rx="8" fill="var(--cb-popover-bg)" stroke="var(--cb-popover-border)" strokeWidth="1" />
              <text x={tooltipX + 15} y={tooltipY + 25} fill="var(--color-foreground)" fontSize="12" fontWeight="600">
                {seriesByApi[activePoint.api].label} · {activePoint.label}
              </text>
              <text x={tooltipX + 15} y={tooltipY + 47} fill="var(--color-muted-foreground)" fontSize="11">
                Score <tspan x={tooltipX + 173} textAnchor="end" fontWeight="600">{formatScore(activePoint.score)}</tspan>
              </text>
              <text x={tooltipX + 15} y={tooltipY + 65} fill="var(--color-muted-foreground)" fontSize="11">
                Cost/request <tspan x={tooltipX + 173} textAnchor="end" fontWeight="600">{formatCostPerRequest(activePoint.cost)}</tspan>
              </text>
            </g>}
        </svg>
      </div>

      <table className="sr-only">
        <caption>{`${activeTab.label} benchmark data`}</caption>
        <thead>
          <tr><th>Configuration</th><th>API</th><th>Score</th><th>Cost per request</th></tr>
        </thead>
        <tbody>
          {validPoints.map(point => <tr key={`table-${pointKey(point)}`}>
              <th>{point.label}</th><td>{seriesByApi[point.api].label}</td><td>{formatScore(point.score)}</td><td>{formatCostPerRequest(point.cost)}</td>
            </tr>)}
        </tbody>
      </table>
    </figure>;
};

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

## What we measured

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

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

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

<MigrationBenchmarkChart benchmarks={MIGRATION_BENCHMARKS} />

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

## Which preset should you use?

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

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

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

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

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