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

# API overview

> Find companies and authors, reuse tags and saved filter sets, then list or fetch pitches.

The Yellowbrick API is for developers with Premium. It is an entity search plus a filtered pitch catalog: look up a company or author, read the tag vocabulary, reuse filter sets you already saved, then list or fetch pitches.

Create a key on [Profile](https://www.joinyellowbrick.com/profile). Send `Authorization: Bearer yb_...`. See [Authentication](/api/authentication).

Use of the API is subject to the [Yellowbrick Terms of Service](https://www.joinyellowbrick.com/terms-of-service). You may use Yellowbrick data for trading, research, and investment decisions. You may not use the API or the data to create, operate, or offer a product or service that conflicts with or competes with any Yellowbrick Investing Inc. service, including Yellowbrick and CEO Watcher.

## How the pieces fit

Use the resources in this order.

1. **Search** finds companies and authors. You get a `companyId` or an author `username`.
2. **Tags** is the filter vocabulary. You get `slug` values and `tagTypeKey` values.
3. **Filter sets** are combinations of tags the key owner already saved. You get an `id` to pass into the pitch list.
4. **Pitches** lists write-ups that match those identifiers, then returns one pitch by id.

Search finds entities so you can list their pitches. It does not look through pitch titles or bodies.

## Search

`GET /api/v1/search?q=`

`q` is a fuzzy match across:

* Author **username** and **display name**
* Company **ticker**, **legal name**, and alternate names

The response is two lists: `authors` and `companies`. Take `authors[].username` for `authorUsername` on the pitch list, and `companies[].companyId` for `companyId`.

## Tags

`GET /api/v1/tags`

Each tag has a `slug` (what you send) and sits in a type (`tagTypeKey`).

**Catalog types** (from the Yellowbrick taxonomy): `market_cap`, `sector_industry`, `country_region`, `pitch_category`, `strategy`, `content_format`, `source`. Some of these nest children under a parent, such as sector → industry.

**Quality and pitch attributes** (closed lists, also typed on the pitch list):

| Type key | What it filters | Typed parameter |
| - | - | - |
| `badge` | Elite or Rising authors | `authorBadge=elite` or `rising` |
| `author_return` | Author realized return floor | `authorReturn=1y_abs_gte_25` |
| `win_rate` | Author 1-year win rate floor | `winRateGte=60` |
| `pitch_return` | This write-up's return floor | `pitchReturn=1y_abs_gte_x2` |
| `sentiment` | Bullish, bearish, or neutral | `sentiment=bullish` |
| `position_decision` | Extracted position action | `positionDecision=initiate_long` |
| `premium` | Paywalled vs free write-up | `isPremiumPitch=true` |

Use `slug` in `extraTags` if you already have a filter-set payload. Prefer the typed parameters on `GET /api/v1/pitches` when you are building the query yourself. Use `tagTypeKey` in `extraTagsNoneOf` to invert that type.

Author return tokens are `{period}_{abs|excess}_gte_{0|10|25|50}`. Period is `6m`, `1y`, or `2y`. Pitch return tokens are `{period}_{abs|excess}_gte_pct{0|25|50|100}` or `{period}_{abs|excess}_gte_x{2|3|4|10}`. Win rate is `50`, `60`, or `75` (percent, at least 8 pitches).

## Filter sets

`GET /api/v1/filter-sets`

A filter set is a named, saved combination of tags on the key owner's account. This API lists them. It does not create or edit them.

Each item has:

* `id` — pass this as `filterSetIds` on the pitch list
* `displayName` — the name you saved
* `criteria` — the tags inside the set (`tags.any` or `tagsByType`, plus `noneOf` for inverted types)

## Pitches

`GET /api/v1/pitches` returns a page of pitches. `GET /api/v1/pitches/{id}` returns one pitch.

Unlocked pitch detail includes an `archive` object: whether a snapshot is ready (`available`), which write-up formats exist (`pdf`, `mhtml`, `md`), whether a linked attachment was captured (`has_attachment`), and whether a reader has already requested an archive.

| Parameter | What it does |
| - | - |
| `companyId` | Pitches on that company |
| `authorUsername` | Pitches by that author |
| `extraTags` | Tag slugs from GET /api/v1/tags |
| `extraTagsNoneOf` | Invert those tag types in `extraTags` |
| `authorBadge` | `elite` or `rising` |
| `authorReturn` | Author return floor, e.g. `1y_abs_gte_25` |
| `winRateGte` | Author win rate floor: `50`, `60`, or `75` |
| `pitchReturn` | Pitch return floor, e.g. `1y_abs_gte_x2` |
| `sentiment` | `bullish`, `bearish`, or `neutral` |
| `positionDecision` | Position action, e.g. `initiate_long` |
| `isPremiumPitch` | `true` (paywalled) or `false` (free) |
| `filterSetIds` | Reuse saved sets |
| `followingOnly` | Authors the key owner follows |
| `addedOnFrom` / `addedOnTo` | Inclusive `YYYY-MM-DD` bounds on the date Yellowbrick added the pitch |
| `sort` | `post_date`, `pitch_returns`, or `investor_returns` |
| `cursor` / `limit` | Pagination. `limit` is 1–50, default 20 |

## How filters combine

Every constraint on the pitch list is **AND**'d together. A pitch must satisfy the company (if set), the author (if set), author badge / following (if set), the date range (if set), the extra tags (if set), **and** the filter sets (if set).

Inside **extraTags**:

* Slugs are grouped by type.
* Within one type, a pitch matches if it has **any** of those slugs (OR).
* Across types, a pitch must satisfy **every** type you sent (AND).
* `extraTagsNoneOf` lists type keys to flip: the pitch must **not** match that type's slugs.

Inside **filterSetIds**:

* Each set uses the same per-type OR / AND rules, plus that set's `noneOf`.
* Several set ids are **OR**'d: the pitch matches if it matches any of the sets.
* Those sets as a group are still **AND**'d with `extraTags` and the other parameters.

Example: `companyId=123&extraTags=long&extraTags=value&filterSetIds=fil_a&filterSetIds=fil_b` means this company, and long or value (same type: pitch category), and (set A or set B).

## Archived documents

`GET /api/v1/pitches/{id}/document` returns a time-limited signed URL for a snapshot artifact: either a write-up or a linked attachment.

By default the response is JSON. Write-up:

```json theme={null}
{
  "url": "https://…",
  "format": "pdf",
  "artifact": null,
  "snapshot": "20260410T120000Z",
  "filename": "20260410-TSLA_is-now-the-time-to-build_4e93e2.pdf",
  "expires_in_seconds": 900
}
```

Attachment (`artifact=attachment` when `archive.has_attachment` is true):

```json theme={null}
{
  "url": "https://…",
  "format": null,
  "artifact": "attachment",
  "snapshot": "20260410T120000Z",
  "filename": "20260410-TSLA_is-now-the-time-to-build_4e93e2_attachment.pdf",
  "expires_in_seconds": 900
}
```

The signed URL includes an S3 `response-content-disposition` override so browsers download with that filename.

| Parameter | What it does |
| - | - |
| `format` | Write-up: `pdf`, `mhtml`, or `md`. Defaults to the best available (pdf → mhtml → md). Do not combine with `artifact`. |
| `artifact` | Sidecar: `attachment` for `document.attachment.pdf`. Do not combine with `format`. |
| `snapshot` | Snapshot id. Defaults to the latest. |
| `redirect` | `1` / `true` / `yes` returns a `302` to `url` instead of JSON. |

This endpoint is Premium-only (`403` `premium-required` if the key owner's membership has lapsed). Locked author pitches still return `403`. Missing or unfinished archives return `404`. Passing both `format` and `artifact` returns `400`.

## What you can see

The key identifies the Premium account. Yellowbrick still applies that account's access on every request.

* If Premium lapses, every `/api/v1` call returns `403` (`premium-required`). The key can still exist.
* Author badge, author return, win rate, and pitch return are Premium filters. They are in the tag catalog and on the pitch list because this API is Premium-only.
* A Yellowbrick Premium membership does not unlock an author's paywalled pitch. You still need access to that author.

On the list, a locked pitch stays in the page with `is_locked: true`. Title, summary, ticker, and company name are cleared. Only sector slugs remain.

On detail, a locked pitch still returns `200` with `is_locked: true` and the write-up fields withheld. `archive` is null when locked.

## Errors

Responses use problem details: `type`, `title`, `status`, `detail`.

| Status | When |
| - | - |
| `400` | Invalid query or cursor |
| `401` | Missing or invalid API key |
| `403` | Premium required, or no access to a paywalled pitch document |
| `404` | Pitch or archive not found |
| `503` | Archive CDN misconfigured or signing failed |

Bookmarks are not in this API.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.