Skip to content
Developers
Open app

Get OCR text

GET
/v1/media/{id}/ocr
const url = 'https://api.focal.inc/v1/media/786beeda-55ac-4025-bf6e-43b2918e84a9/ocr?format=blocks';
const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try {
const response = await fetch(url, options);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}

Returns the text detected in the media as one assembled document — all blocks in reading/playback order, no pagination. Image media yields blocks with a reading-order index; video media yields blocks with an on-screen time range. Check status to distinguish not-yet-analyzed (pending) from analyzed-with-no-text (completed with no blocks). Pass format=text for a single newline-joined string suited to LLM prompts.

Kept as a separate request — like /download — so list and get traffic never carries the OCR payload.

Required scope: media:read. Rate-limit cost: 5.

id
required
string format: uuid

Example

786beeda-55ac-4025-bf6e-43b2918e84a9
format
string
Allowed values: blocks text

Response form: blocks (default) returns the structured block array; text returns all detected text as one newline-joined string instead.

OK

Media typeapplication/json
object
data
required
object
media_id
required
string format: uuid
status
required

Whether the analysis feature has run for this media:

  • completed — analysis ran; an empty result means nothing was found (e.g. no speech, no visible text)
  • pending — the media hasn’t been analyzed (yet)
  • not_applicable — this media type is never analyzed, so no data will ever appear
string
Allowed values: pending completed not_applicable
blocks

The detected text blocks in reading/playback order. Present unless format=text was requested. Empty when status isn’t completed, or when analysis found no text.

Array
Any of:
object
type
required
string
Allowed values: image
index
required

Reading order of the block within the image, from 0.

integer
content
required

The detected text.

string
text

All detected text as one newline-joined string — a token-lean form for feeding to an LLM. Present only when format=text was requested.

string

Example

{
"data": {
"media_id": "786beeda-55ac-4025-bf6e-43b2918e84a9",
"status": "pending",
"blocks": [
{
"type": "image",
"index": 0,
"content": "ALDER & PINE"
}
],
"text": "ALDER & PINE\nSpring 2027\nShop the collection"
}
}

The request was malformed (invalid cursor, unknown type, validation failure, etc.). error.code is bad_request.

Media typeapplication/json

Canonical error envelope. code is stable across releases and intended for programmatic handling; message is human-readable. details only appears for validation failures and lists the offending fields.

object
error
required
object
code
required
string
Allowed values: unauthenticated forbidden not_found bad_request conflict rate_limited internal_error
message
required
string
details
Array<object>
object
field
string
issue
required
string

Example

{
"error": {
"code": "bad_request",
"message": "Invalid request body",
"details": [
{
"field": "space_id",
"issue": "Invalid UUID"
}
]
}
}

Missing, invalid, or disabled token. error.code is unauthenticated.

Media typeapplication/json

Canonical error envelope. code is stable across releases and intended for programmatic handling; message is human-readable. details only appears for validation failures and lists the offending fields.

object
error
required
object
code
required
string
Allowed values: unauthenticated forbidden not_found bad_request conflict rate_limited internal_error
message
required
string
details
Array<object>
object
field
string
issue
required
string

Example

{
"error": {
"code": "unauthenticated",
"message": "Bearer token is missing or invalid"
}
}

The token doesn’t have the scope this endpoint requires. error.code is forbidden.

Media typeapplication/json

Canonical error envelope. code is stable across releases and intended for programmatic handling; message is human-readable. details only appears for validation failures and lists the offending fields.

object
error
required
object
code
required
string
Allowed values: unauthenticated forbidden not_found bad_request conflict rate_limited internal_error
message
required
string
details
Array<object>
object
field
string
issue
required
string

Example

{
"error": {
"code": "forbidden",
"message": "Token doesn't have the required scope"
}
}

Resource doesn’t exist or is outside the token’s space allow-list. The two cases share a response shape so a restricted token can’t probe for the existence of out-of-scope spaces. error.code is not_found.

Media typeapplication/json

Canonical error envelope. code is stable across releases and intended for programmatic handling; message is human-readable. details only appears for validation failures and lists the offending fields.

object
error
required
object
code
required
string
Allowed values: unauthenticated forbidden not_found bad_request conflict rate_limited internal_error
message
required
string
details
Array<object>
object
field
string
issue
required
string

Example

{
"error": {
"code": "not_found",
"message": "Not found"
}
}

Rate limit exceeded. error.code is rate_limited. Wait the number of seconds in the Retry-After header before retrying. Quotas are per-token; see the “Rate limiting” section at the top of this document.

Media typeapplication/json

Canonical error envelope. code is stable across releases and intended for programmatic handling; message is human-readable. details only appears for validation failures and lists the offending fields.

object
error
required
object
code
required
string
Allowed values: unauthenticated forbidden not_found bad_request conflict rate_limited internal_error
message
required
string
details
Array<object>
object
field
string
issue
required
string

Example

{
"error": {
"code": "rate_limited",
"message": "Rate limit of 1000 units per 60s exceeded (this request cost 5)"
}
}
Retry-After
integer
Example
12

Seconds to wait before retrying.