postreef

API reference

Every v1 endpoint, generated from the OpenAPI 3.1 spec. Read on the left, run live against your account on the right. Base URL https://postreef.com.

View as Markdown
POST/v1/extractions

Submit an extraction

Starts an extraction for a public video URL. Credits are debited up-front (a flat base fee plus download rates for the requested artifacts, plus per-second AI rates when a schema is set; use `POST /v1/probe` for the exact quote first) and refunded in full if the extraction fails. When the duration can't be determined up-front, a worst-case duration of 300s is debited and the difference is refunded on completion. If an identical extraction (same URL, schema and inputs) completed recently, the result is reused: the response has `cached: true` semantics on subsequent reads and `creditsDebited: 0`. Pass `force: true` to skip the cache and re-run. Rate limit: 6 requests per minute. At most 2 extractions run per account at once. Submissions past that limit are accepted with status `queued` (credits debited up-front) and dispatched automatically when a slot frees.

Parameters

Parameters
FieldTypeDescription
Idempotency-Key (header)stringAny unique string (e.g. a UUID). Retrying a submit with the same key and the same request body returns the original extraction with status 200 instead of creating a new one. Reusing a key with a *different* body returns 409 conflict.

Request body

Request body fields
FieldTypeDescription
urlrequiredstringPublic video URL (YouTube, Shorts, TikTok, Instagram Reels, …).
inputs"transcript" | "comments" | "audio" | "video"[]Which modalities feed the AI extraction. Defaults to ["transcript","comments"]. Determines the price.
schemaIdstringId of a predefined schema (e.g. `Recipe`) or one of your saved schemas. Mutually exclusive with `schema`.
schemaobjectInline JSON Schema (max 100KB) describing the structured object you want back. Omit both `schema` and `schemaId` for a download-only run (no AI, no per-second AI charge).
promptstringExtraction guidance sent to the model alongside the schema. It steers how the video is read into the schema (source priority, what to omit, common pitfalls). For a predefined `schemaId` this overrides that schema's built-in prompt; for an inline `schema` it's the prompt that pairs with it. Max 20KB. Part of the cache key, so an edited prompt re-runs instead of reusing a cached result. Ignored on download-only runs.
autobooleanAuto mode: start with the cheapest inputs (text), judge the result, and only climb to audio/video if quality is below threshold. `inputs` becomes the ceiling the climb may reach. Requires `maxSpendCredits`. Charged the ceiling at submit, refunded down to the rung actually used. Auto runs reuse a recent result on the same URL, schema and model when its inputs fit inside your `inputs` ceiling (free, `creditsDebited: 0`); pass `force: true` to re-run instead.
forcebooleanSkip the result cache and run the full pipeline even when a recent identical extraction exists. The run is billed as fresh. Default false.
maxSpendCreditsnumberSpend ceiling for an auto run, in credits. Required when `auto` is true. Must be at least the cost of the cheapest rung.
policy"strict" | "fallback" | "best-effort"What to do when a requested input isn't available for this video (e.g. no comments): `strict` fails the run, `fallback` (default) proceeds with reduced inputs, `best-effort` silently drops the missing input.
parts"transcript" | "comments" | "audio" | "video"[]Download-only runs (no schema): which artifacts to fetch. Omit for everything. Metadata, thumbnail and description are always included. Invalid alongside `schema`/`schemaId`.
webhookUrlstringPer-run webhook override: an https URL (public hosts only) that receives `extraction.completed` / `extraction.failed` for this run in addition to your registered endpoints. Signed with your first registered endpoint's secret when one exists; unsigned otherwise.
{
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "inputs": [
    "transcript",
    "comments"
  ],
  "schemaId": "Recipe",
  "webhookUrl": "https://example.com/hooks/postreef"
}

Response fields

Response fields
FieldTypeDescription
idrequiredstringExtraction id, used for polling, results and files.
statusrequired"queued" | "pending" | "running" | "complete" | "failed"
urlrequiredstring
creditsDebitedrequiredintegerCredits debited up-front. 0 when the result was served from a recent identical extraction.
createdAtrequiredstring

Responses

200 Idempotent replay: the Idempotency-Key matched a previous submit with the same body, so the original extraction is returned.

201 Extraction created and started.

{
  "id": "run_8f3a2b1c",
  "status": "pending",
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "creditsDebited": 127,
  "createdAt": "2026-06-11T10:15:00.000Z"
}

400 Invalid request: missing/invalid url (`invalid_url`), unsupported platform (`unsupported_url`), invalid options or webhookUrl (`invalid_request`).

401 Missing or invalid API key.

402 Insufficient credits (`insufficient_credits`). `details.balance` and `details.cost` carry your current balance and the quoted cost in credits.

404 Referenced schemaId not found.

409 Idempotency-Key was already used with a different request body (`conflict`).

429 `rate_limited` (per-minute window exceeded, includes Retry-After).

GET/v1/extractions

List extractions

Lists your extractions, newest first, with cursor pagination. Pass `next_cursor` from a previous page as `cursor` to fetch the next page.

Parameters

Parameters
FieldTypeDescription
limit (query)integerPage size, 1–100.
cursor (query)stringOpaque cursor from the previous page's `next_cursor`. Do not construct it yourself.

Response fields

Response fields
FieldTypeDescription
datarequiredExtraction[]
has_morerequiredboolean
next_cursorrequiredstring | nullPass as `cursor` to fetch the next page. Null on the last page.

Responses

200 One page of extractions.

{
  "data": [
    {
      "id": "run_8f3a2b1c",
      "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
      "status": "complete",
      "createdAt": "2026-06-11T10:15:00.000Z",
      "completedAt": "2026-06-11T10:16:42.000Z",
      "creditsDebited": 127,
      "cached": false,
      "outcome": "ok"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

400 Invalid limit or cursor.

401 Missing or invalid API key.

429 Rate limit exceeded.

POST/v1/extract

Submit an extraction (alias)

Exact alias of `POST /v1/extractions`, with the same request, responses, rate limit and Idempotency-Key support.

Request body

Request body fields
FieldTypeDescription
urlrequiredstringPublic video URL (YouTube, Shorts, TikTok, Instagram Reels, …).
inputs"transcript" | "comments" | "audio" | "video"[]Which modalities feed the AI extraction. Defaults to ["transcript","comments"]. Determines the price.
schemaIdstringId of a predefined schema (e.g. `Recipe`) or one of your saved schemas. Mutually exclusive with `schema`.
schemaobjectInline JSON Schema (max 100KB) describing the structured object you want back. Omit both `schema` and `schemaId` for a download-only run (no AI, no per-second AI charge).
promptstringExtraction guidance sent to the model alongside the schema. It steers how the video is read into the schema (source priority, what to omit, common pitfalls). For a predefined `schemaId` this overrides that schema's built-in prompt; for an inline `schema` it's the prompt that pairs with it. Max 20KB. Part of the cache key, so an edited prompt re-runs instead of reusing a cached result. Ignored on download-only runs.
autobooleanAuto mode: start with the cheapest inputs (text), judge the result, and only climb to audio/video if quality is below threshold. `inputs` becomes the ceiling the climb may reach. Requires `maxSpendCredits`. Charged the ceiling at submit, refunded down to the rung actually used. Auto runs reuse a recent result on the same URL, schema and model when its inputs fit inside your `inputs` ceiling (free, `creditsDebited: 0`); pass `force: true` to re-run instead.
forcebooleanSkip the result cache and run the full pipeline even when a recent identical extraction exists. The run is billed as fresh. Default false.
maxSpendCreditsnumberSpend ceiling for an auto run, in credits. Required when `auto` is true. Must be at least the cost of the cheapest rung.
policy"strict" | "fallback" | "best-effort"What to do when a requested input isn't available for this video (e.g. no comments): `strict` fails the run, `fallback` (default) proceeds with reduced inputs, `best-effort` silently drops the missing input.
parts"transcript" | "comments" | "audio" | "video"[]Download-only runs (no schema): which artifacts to fetch. Omit for everything. Metadata, thumbnail and description are always included. Invalid alongside `schema`/`schemaId`.
webhookUrlstringPer-run webhook override: an https URL (public hosts only) that receives `extraction.completed` / `extraction.failed` for this run in addition to your registered endpoints. Signed with your first registered endpoint's secret when one exists; unsigned otherwise.
{
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "inputs": [
    "transcript",
    "comments"
  ],
  "schemaId": "Recipe",
  "webhookUrl": "https://example.com/hooks/postreef"
}

Response fields

Response fields
FieldTypeDescription
idrequiredstringExtraction id, used for polling, results and files.
statusrequired"queued" | "pending" | "running" | "complete" | "failed"
urlrequiredstring
creditsDebitedrequiredintegerCredits debited up-front. 0 when the result was served from a recent identical extraction.
createdAtrequiredstring

Responses

201 Extraction created and started.

GET/v1/extractions/{id}

Get an extraction

Returns the current state of one extraction, including a coarse `phase` (`queued`, `processing`, `done`, `failed`). Poll this (or `/result`) until the status is terminal, or skip polling entirely with a webhook.

Parameters

Parameters
FieldTypeDescription
id (path)requiredstringExtraction id returned at submit time.

Response fields

Response fields
FieldTypeDescription
idrequiredstring
urlrequiredstring
statusrequired"queued" | "pending" | "running" | "complete" | "failed"
createdAtrequiredstring
completedAtrequiredstring | null
creditsDebitedrequiredinteger
cachedrequiredbooleanTrue when the result was reused from a recent identical extraction (no credits were debited).
outcome"ok" | "no_match" | "uncertain" | "null"Content-match verdict for an AI run. `ok` means the content matched the schema and `extraction` holds the data. `no_match` means the content is about something else, with a null `extraction`. `uncertain` means the inputs were too sparse to decide, also with a null `extraction`. Null on download-only runs and runs from before this field existed.
verdictReasonstringOne-sentence explanation of the content-match verdict, present only when `outcome` is `no_match` or `uncertain`.
errorstringPresent only when status is `failed`.
phaserequired"queued" | "processing" | "done" | "failed"Coarse progress phase derived from status.

Responses

200 The extraction.

{
  "id": "run_8f3a2b1c",
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "status": "complete",
  "createdAt": "2026-06-11T10:15:00.000Z",
  "completedAt": "2026-06-11T10:16:42.000Z",
  "creditsDebited": 127,
  "cached": false,
  "outcome": "ok",
  "phase": "done"
}

401 Missing or invalid API key.

404 No extraction with this id belongs to you.

429 Rate limit exceeded.

GET/v1/extractions/{id}/result

Get an extraction's result

Returns the final result. While the extraction is still queued or processing, responds **202** with `{ "status": "queued" | "processing" }` and keep polling. Once complete, responds 200 with the summary (metadata + available file names) and, when an AI schema was supplied, the structured `extraction` object conforming to it. A failed extraction responds 200 with `status: "failed"` and a human-readable `error`.

Parameters

Parameters
FieldTypeDescription
id (path)requiredstring

Responses

200 Terminal result (complete or failed).

{
  "id": "run_8f3a2b1c",
  "status": "complete",
  "summary": {
    "title": "Weeknight pasta in 15 minutes",
    "uploader": "@kitchen",
    "durationSeconds": 212,
    "files": [
      "video.mp4",
      "transcript.txt",
      "comments.json"
    ]
  },
  "extraction": {
    "name": "Weeknight pasta",
    "servings": 2
  }
}

202 Still running. The body is `{ "status": "queued" | "processing" }`.

{
  "status": "processing"
}

401 Missing or invalid API key.

404 No extraction with this id belongs to you.

429 Rate limit exceeded.

GET/v1/extractions/{id}/files/{name}

Download an extraction artifact

Streams one artifact produced by a completed extraction: `video.mp4`, `audio.m4a`, `transcript.txt`, `comments.json`, `thumbnail.jpg`, `description.txt` or subtitle files. The available names are listed in the result's `summary.files`.

Parameters

Parameters
FieldTypeDescription
id (path)requiredstring
name (path)requiredstringFile name exactly as listed in `summary.files`.

Responses

200 The file bytes; `Content-Type` matches the artifact (video/mp4, text/plain, application/json, …).

400 Invalid file name.

401 Missing or invalid API key.

404 Extraction or file not found.

429 Rate limit exceeded.

POST/v1/probe

Probe a URL and quote the price

Inspects a video URL without starting an extraction: returns the title, duration, whether subtitles/comments exist, and the exact credit price for the inputs you intend to request. This is the canonical quote: submitting the same URL with the same inputs debits exactly this amount (or the worst-case ceiling when duration is unknown). Rate limit: 10 requests per minute. Probing is free.

Request body

Request body fields
FieldTypeDescription
urlrequiredstring
inputs"transcript" | "comments" | "audio" | "video"[]Inputs you intend to submit with (AI extraction quote). The quote depends on them. Defaults to ["transcript","comments"]. Mutually exclusive with `parts`.
parts"transcript" | "comments" | "audio" | "video"[]Quote a download-only run instead: base fee + download rates, no AI component. Mutually exclusive with `inputs`.
{
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "inputs": [
    "transcript",
    "comments"
  ]
}

Response fields

Response fields
FieldTypeDescription
urlrequiredstring
durationSecrequirednumber | nullNull when the platform hides the duration. Submitting then debits the 300s worst case, refunded down to actual on completion.
titlerequiredstring | null
hasSubtitlesrequiredboolean
hasCommentsrequiredboolean
pricerequiredobject

Responses

200 Probe result with price quote.

{
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "durationSec": 212,
  "title": "Weeknight pasta in 15 minutes",
  "hasSubtitles": true,
  "hasComments": true,
  "price": {
    "credits": 636,
    "usd": 0.0636,
    "breakdown": {
      "text": 0.0636,
      "audio": 0,
      "video": 0
    }
  }
}

400 Invalid url, unsupported platform, or bad inputs.

401 Missing or invalid API key.

429 Rate limit exceeded.

502 The video could not be probed right now.

GET/v1/openapi.json

This document

Returns this OpenAPI 3.1 document. Public, no authentication required. Import it into Postman, Insomnia, or your codegen of choice.

Responses

200 The OpenAPI 3.1 document.

Request builder
Requests run server-side with a short-lived ephemeral API key against your account, so submissions spend real credits. Paste one of your own keys below to use it instead.

Pasted keys are forwarded once and never stored.

Sign in to send live requests. You can still build the request and copy the code below.
URL is required
Request
The exact HTTP request that will be sent.
POST /v1/extractions HTTP/1.1
x-api-key: vidx_••••••••••••••••
Content-Type: application/json

{
  "url": "<video url>",
  "inputs": [
    "transcript",
    "comments"
  ]
}
Response
Send a request to see the response here.

No response yet.

Code snippet

curl -X POST https://postreef.com/v1/extractions \
  -H "x-api-key: vidx_••••••••••••••••" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "<video url>",
  "inputs": [
    "transcript",
    "comments"
  ]
}'