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 URL: a video, a photo post/carousel, or an ordinary article/webpage (webpage runs are priced flat and read the page text and images; photo posts/carousels are priced flat and per-slide — their reported "duration" is a background track, never billed). 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; the debit is never exceeded. Videos longer than 60 minutes are rejected before any debit. If an identical extraction (same URL, schema and inputs) completed within the last 30 days, 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 URL: a video (YouTube, Shorts, TikTok, Instagram Reels, …), a photo post or carousel, or an ordinary article/webpage.
inputs"transcript" | "comments" | "audio" | "video"[]Which modalities feed the AI extraction. Requires `schema` or `schemaId` — without one there is no AI call, and a download-only run selects its artifacts with `parts`. Defaults to ["transcript","comments"]. Determines the price.
schemaIdstringId of a predefined schema (e.g. `postreef.predefined.recipe.v1`), one of your saved schemas, or `auto` to skip picking a schema entirely — the AI extracts whatever structured information is actually there, and the output is compiled into a new schema saved to your library. 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 an identical extraction from the last 30 days 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": "postreef.predefined.recipe.v1",
  "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 URL: a video (YouTube, Shorts, TikTok, Instagram Reels, …), a photo post or carousel, or an ordinary article/webpage.
inputs"transcript" | "comments" | "audio" | "video"[]Which modalities feed the AI extraction. Requires `schema` or `schemaId` — without one there is no AI call, and a download-only run selects its artifacts with `parts`. Defaults to ["transcript","comments"]. Determines the price.
schemaIdstringId of a predefined schema (e.g. `postreef.predefined.recipe.v1`), one of your saved schemas, or `auto` to skip picking a schema entirely — the AI extracts whatever structured information is actually there, and the output is compiled into a new schema saved to your library. 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 an identical extraction from the last 30 days 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": "postreef.predefined.recipe.v1",
  "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), `artifacts` (the same files as ready-to-fetch URLs), 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"
    ]
  },
  "artifacts": {
    "video": "https://postreef.com/v1/extractions/run_8f3a2b1c/files/video.mp4",
    "transcript": "https://postreef.com/v1/extractions/run_8f3a2b1c/files/transcript.txt",
    "comments": "https://postreef.com/v1/extractions/run_8f3a2b1c/files/comments.json",
    "images": [],
    "files": {
      "video.mp4": "https://postreef.com/v1/extractions/run_8f3a2b1c/files/video.mp4",
      "transcript.txt": "https://postreef.com/v1/extractions/run_8f3a2b1c/files/transcript.txt",
      "comments.json": "https://postreef.com/v1/extractions/run_8f3a2b1c/files/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` (the page text, for webpage runs), `comments.json`, `thumbnail.jpg`, `description.txt`, subtitle files, or the numbered `image.NN.jpg` slides of a photo post or carousel. The available names are listed in the result's `summary.files`, and the result's `artifacts` object gives you the full URL directly. Accepts either an API key or, if you're signed in to the web app, your browser session — so an `artifacts` URL also opens directly in a tab.

Parameters

Parameters
FieldTypeDescription
id (path)requiredstring
name (path)requiredstringFile name exactly as listed in `summary.files` or `artifacts.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 URL without starting an extraction: returns the title, duration, whether subtitles/comments exist, and the exact credit price for the run you intend to submit (a URL that resolves to an article/webpage is quoted at the flat webpage price, with `durationSec: null`). This is the canonical quote: send the same body you will submit (a schema when you want an AI extraction, `parts` when you want a download) and `POST /v1/extractions` 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
schemaobjectQuote an AI extraction. Only its presence matters — the AI rates are per-second and schema-independent, so the quote never validates it. Send the schema you intend to submit, or any object.
schemaIdstringAlternative to `schema` for signalling an AI extraction quote. Not resolved by the probe.
inputs"transcript" | "comments" | "audio" | "video"[]Inputs you intend to submit with. Requires `schema` or `schemaId` — without one there is no AI call to bill. Defaults to ["transcript","comments"]. Mutually exclusive with `parts`.
parts"transcript" | "comments" | "audio" | "video"[]Artifacts a download-only run should fetch: base fee + download rates, no AI component. Defaults to all four. Mutually exclusive with `inputs` and with a schema.
{
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "schemaId": "postreef.predefined.recipe.v1",
  "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": {
    "mode": "ai",
    "credits": 186,
    "usd": 0.0186,
    "baseUsd": 0.005,
    "downloadUsd": 0.003,
    "downloadBreakdown": {
      "transcript": 0.001,
      "comments": 0.002
    },
    "breakdown": {
      "text": 0.0106,
      "audio": 0,
      "video": 0
    }
  }
}

400 Invalid url, unsupported platform, or bad inputs.

401 Missing or invalid API key.

422 The content itself is unavailable: private, removed, or login-gated (`content_unavailable`). Permanent — don't retry.

429 Rate limit exceeded.

502 The content 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: pr_••••••••••••••••
Content-Type: application/json

{
  "url": "<video url>"
}
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: pr_••••••••••••••••" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "<video url>"
}'