---
title: "Get one video's bottom-of-funnel verdict"
method: GET
path: "/videos/{video_id}/bof"
tags: ["Video Intelligence"]
---

# Get one video's bottom-of-funnel verdict

`GET /videos/{video_id}/bof`

## Request

- Base URL: `https://api.reacherapp.com/public/v1`
- URL: `https://api.reacherapp.com/public/v1/videos/{video_id}/bof`
- Auth: API key in header `x-api-key` and API key in header `x-shop-id`

Whether a video is bottom-of-funnel content — direct-response creative that pushes the viewer to buy now (discount, urgency, explicit call to action) rather than building awareness.

`bof_status` is the raw verdict (`bof`, `not_bof`, `needs_review`, `pending`) and `bof_confidence` scores it 0-100; `is_bof` is the displayable answer, true only for a `bof` verdict at confidence >= 90 — the same threshold behind the BOF badge and filter in the Reacher portal, so the API and the portal can never disagree about a video. `matched_keywords`, `matched_patterns` and `matched_signals` explain the verdict.

A video this shop owns that the classifier has no verdict for returns 200 with `classified: false` and `is_bof: false`; `classification_status` then says why (`pending`, `no_transcript`, or `not_analyzed`) — `classified: false` is a coverage state, not an error.

Only videos belonging to the calling key's shop are readable; any other `video_id` returns 404. Single-shop only — set `x-shop-id` to one shop ID.

## Path parameters

- `video_id` string, required: Video id from any Reacher video surface.

## Response `200`

Successful Response

- VideoBofResponse: Envelope for one video's BOF verdict. ``data`` carries ``classification_status`` alongside the verdict, so an owned-but-unclassified video says *why* it has none rather than only ``classified: false``.
  - `data` VideoBof, required: Bottom-of-funnel verdict for one video.
    - `video_id` string, required
    - `classified` boolean, required: False when the shop owns this video but the classifier has no verdict for it — every other field is then null / false. See `classification_status` for *why*.
    - `classification_status` 'classified' | 'pending' | 'no_transcript' | 'not_analyzed': Why the video is (un)classified. BOF classification is a separate pipeline from UVI analysis, so an analysed video is not automatically classified. One of: `classified` (a verdict exists); `pending` (analysed with a transcript, classifier hasn't reached it — transient); `no_transcript` (analysed but no usable transcript to classify, e.g. a thumbnail-only analysis); `not_analyzed` (UVI hasn't analysed the video yet).
    - `bof_status` string, nullable: `bof`, `not_bof`, `needs_review` or `pending`.
    - `bof_confidence` integer, nullable: Confidence in the verdict, 0-100.
    - `is_bof` boolean, required: The displayable verdict: `bof_status` is `bof` **and** `bof_confidence` >= 90. Identical to the BOF badge in the Reacher portal.
    - `matched_signals` string[], nullable: Where the signals were found (e.g. `transcript`, `on_screen_text`).
    - `matched_keywords` string[], nullable: Bottom-of-funnel keywords found in the video.
    - `matched_patterns` string[], nullable: Bottom-of-funnel phrase patterns the video matched.
    - `classified_at` string, date-time, nullable

## Other responses

- `422`: Validation Error

## Changes

> 76 revisions in range; 1 not diffed.

- **2026-09-05** `643422c93bd8`: 1 info
  - added the optional property `data/classification_status` to the response with the `200` status

[Operation history](https://skmtc.dev/reacherapp/apis/reacher-data-api/changes/videos/:video_id/bof/get.md)

---

[API](https://skmtc.dev/reacherapp/apis/reacher-data-api.md) - [All operations](https://skmtc.dev/reacherapp/apis/reacher-data-api/llms.txt) - [OpenAPI document](https://skmtc.dev/reacherapp/apis/reacher-data-api/revisions/63ce74b30b5a?raw)
