Search media
CURL *hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");curl_easy_setopt(hnd, CURLOPT_URL, "https://api.focal.inc/v1/media/search");
struct curl_slist *headers = NULL;headers = curl_slist_append(headers, "Authorization: Bearer <token>");headers = curl_slist_append(headers, "Content-Type: application/json");curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "{ \"space_id\": \"6916bc3d-e1ab-425b-ac25-eefada01a9a2\", \"query\": \"trail runner at sunrise\", \"type\": \"video\", \"folder_id\": \"80539d38-3a8e-48f8-929b-8c0e9a22ab43\", \"include_subfolders\": true, \"status\": \"Approved\", \"uploaded_by\": \"cfebb6ef-f092-4591-a6e3-e6667ab5a252\", \"attributes\": [ { \"attribute_id\": \"846196ad-9fa2-40a8-8938-655a962220e1\", \"values\": [ \"Spring Launch\" ], \"match\": \"any\" } ], \"created_after\": \"2027-03-01\", \"created_before\": \"2027-03-31\", \"sort\": \"relevance\", \"order\": \"asc\", \"limit\": 25, \"cursor\": \"eyJvIjoyNX0\", \"last_activity_after\": \"2027-03-01\", \"last_activity_before\": \"2027-03-31\", \"metric_filters\": [ { \"metric\": \"spend\", \"operator\": \"greater_than\", \"value\": 1000 } ], \"fields\": [ \"id\" ], \"metrics\": [ \"spend\", \"impressions\" ] }");
CURLcode ret = curl_easy_perform(hnd);using System.Net.Http.Headers;var client = new HttpClient();var request = new HttpRequestMessage{ Method = HttpMethod.Post, RequestUri = new Uri("https://api.focal.inc/v1/media/search"), Headers = { { "Authorization", "Bearer <token>" }, }, Content = new StringContent("{ \"space_id\": \"6916bc3d-e1ab-425b-ac25-eefada01a9a2\", \"query\": \"trail runner at sunrise\", \"type\": \"video\", \"folder_id\": \"80539d38-3a8e-48f8-929b-8c0e9a22ab43\", \"include_subfolders\": true, \"status\": \"Approved\", \"uploaded_by\": \"cfebb6ef-f092-4591-a6e3-e6667ab5a252\", \"attributes\": [ { \"attribute_id\": \"846196ad-9fa2-40a8-8938-655a962220e1\", \"values\": [ \"Spring Launch\" ], \"match\": \"any\" } ], \"created_after\": \"2027-03-01\", \"created_before\": \"2027-03-31\", \"sort\": \"relevance\", \"order\": \"asc\", \"limit\": 25, \"cursor\": \"eyJvIjoyNX0\", \"last_activity_after\": \"2027-03-01\", \"last_activity_before\": \"2027-03-31\", \"metric_filters\": [ { \"metric\": \"spend\", \"operator\": \"greater_than\", \"value\": 1000 } ], \"fields\": [ \"id\" ], \"metrics\": [ \"spend\", \"impressions\" ] }") { Headers = { ContentType = new MediaTypeHeaderValue("application/json") } }};using (var response = await client.SendAsync(request)){ response.EnsureSuccessStatusCode(); var body = await response.Content.ReadAsStringAsync(); Console.WriteLine(body);}package main
import ( "fmt" "strings" "net/http" "io")
func main() {
url := "https://api.focal.inc/v1/media/search"
payload := strings.NewReader("{ \"space_id\": \"6916bc3d-e1ab-425b-ac25-eefada01a9a2\", \"query\": \"trail runner at sunrise\", \"type\": \"video\", \"folder_id\": \"80539d38-3a8e-48f8-929b-8c0e9a22ab43\", \"include_subfolders\": true, \"status\": \"Approved\", \"uploaded_by\": \"cfebb6ef-f092-4591-a6e3-e6667ab5a252\", \"attributes\": [ { \"attribute_id\": \"846196ad-9fa2-40a8-8938-655a962220e1\", \"values\": [ \"Spring Launch\" ], \"match\": \"any\" } ], \"created_after\": \"2027-03-01\", \"created_before\": \"2027-03-31\", \"sort\": \"relevance\", \"order\": \"asc\", \"limit\": 25, \"cursor\": \"eyJvIjoyNX0\", \"last_activity_after\": \"2027-03-01\", \"last_activity_before\": \"2027-03-31\", \"metric_filters\": [ { \"metric\": \"spend\", \"operator\": \"greater_than\", \"value\": 1000 } ], \"fields\": [ \"id\" ], \"metrics\": [ \"spend\", \"impressions\" ] }")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>") req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close() body, _ := io.ReadAll(res.Body)
fmt.Println(res) fmt.Println(string(body))
}HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.focal.inc/v1/media/search")) .header("Authorization", "Bearer <token>") .header("Content-Type", "application/json") .method("POST", HttpRequest.BodyPublishers.ofString("{ \"space_id\": \"6916bc3d-e1ab-425b-ac25-eefada01a9a2\", \"query\": \"trail runner at sunrise\", \"type\": \"video\", \"folder_id\": \"80539d38-3a8e-48f8-929b-8c0e9a22ab43\", \"include_subfolders\": true, \"status\": \"Approved\", \"uploaded_by\": \"cfebb6ef-f092-4591-a6e3-e6667ab5a252\", \"attributes\": [ { \"attribute_id\": \"846196ad-9fa2-40a8-8938-655a962220e1\", \"values\": [ \"Spring Launch\" ], \"match\": \"any\" } ], \"created_after\": \"2027-03-01\", \"created_before\": \"2027-03-31\", \"sort\": \"relevance\", \"order\": \"asc\", \"limit\": 25, \"cursor\": \"eyJvIjoyNX0\", \"last_activity_after\": \"2027-03-01\", \"last_activity_before\": \"2027-03-31\", \"metric_filters\": [ { \"metric\": \"spend\", \"operator\": \"greater_than\", \"value\": 1000 } ], \"fields\": [ \"id\" ], \"metrics\": [ \"spend\", \"impressions\" ] }")) .build();HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());System.out.println(response.body());OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json");RequestBody body = RequestBody.create(mediaType, "{ \"space_id\": \"6916bc3d-e1ab-425b-ac25-eefada01a9a2\", \"query\": \"trail runner at sunrise\", \"type\": \"video\", \"folder_id\": \"80539d38-3a8e-48f8-929b-8c0e9a22ab43\", \"include_subfolders\": true, \"status\": \"Approved\", \"uploaded_by\": \"cfebb6ef-f092-4591-a6e3-e6667ab5a252\", \"attributes\": [ { \"attribute_id\": \"846196ad-9fa2-40a8-8938-655a962220e1\", \"values\": [ \"Spring Launch\" ], \"match\": \"any\" } ], \"created_after\": \"2027-03-01\", \"created_before\": \"2027-03-31\", \"sort\": \"relevance\", \"order\": \"asc\", \"limit\": 25, \"cursor\": \"eyJvIjoyNX0\", \"last_activity_after\": \"2027-03-01\", \"last_activity_before\": \"2027-03-31\", \"metric_filters\": [ { \"metric\": \"spend\", \"operator\": \"greater_than\", \"value\": 1000 } ], \"fields\": [ \"id\" ], \"metrics\": [ \"spend\", \"impressions\" ] }");Request request = new Request.Builder() .url("https://api.focal.inc/v1/media/search") .post(body) .addHeader("Authorization", "Bearer <token>") .addHeader("Content-Type", "application/json") .build();
Response response = client.newCall(request).execute();import axios from 'axios';
const options = { method: 'POST', url: 'https://api.focal.inc/v1/media/search', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, data: { space_id: '6916bc3d-e1ab-425b-ac25-eefada01a9a2', query: 'trail runner at sunrise', type: 'video', folder_id: '80539d38-3a8e-48f8-929b-8c0e9a22ab43', include_subfolders: true, status: 'Approved', uploaded_by: 'cfebb6ef-f092-4591-a6e3-e6667ab5a252', attributes: [ { attribute_id: '846196ad-9fa2-40a8-8938-655a962220e1', values: ['Spring Launch'], match: 'any' } ], created_after: '2027-03-01', created_before: '2027-03-31', sort: 'relevance', order: 'asc', limit: 25, cursor: 'eyJvIjoyNX0', last_activity_after: '2027-03-01', last_activity_before: '2027-03-31', metric_filters: [{metric: 'spend', operator: 'greater_than', value: 1000}], fields: ['id'], metrics: ['spend', 'impressions'] }};
try { const { data } = await axios.request(options); console.log(data);} catch (error) { console.error(error);}const url = 'https://api.focal.inc/v1/media/search';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"space_id":"6916bc3d-e1ab-425b-ac25-eefada01a9a2","query":"trail runner at sunrise","type":"video","folder_id":"80539d38-3a8e-48f8-929b-8c0e9a22ab43","include_subfolders":true,"status":"Approved","uploaded_by":"cfebb6ef-f092-4591-a6e3-e6667ab5a252","attributes":[{"attribute_id":"846196ad-9fa2-40a8-8938-655a962220e1","values":["Spring Launch"],"match":"any"}],"created_after":"2027-03-01","created_before":"2027-03-31","sort":"relevance","order":"asc","limit":25,"cursor":"eyJvIjoyNX0","last_activity_after":"2027-03-01","last_activity_before":"2027-03-31","metric_filters":[{"metric":"spend","operator":"greater_than","value":1000}],"fields":["id"],"metrics":["spend","impressions"]}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}val client = OkHttpClient()
val mediaType = MediaType.parse("application/json")val body = RequestBody.create(mediaType, "{ \"space_id\": \"6916bc3d-e1ab-425b-ac25-eefada01a9a2\", \"query\": \"trail runner at sunrise\", \"type\": \"video\", \"folder_id\": \"80539d38-3a8e-48f8-929b-8c0e9a22ab43\", \"include_subfolders\": true, \"status\": \"Approved\", \"uploaded_by\": \"cfebb6ef-f092-4591-a6e3-e6667ab5a252\", \"attributes\": [ { \"attribute_id\": \"846196ad-9fa2-40a8-8938-655a962220e1\", \"values\": [ \"Spring Launch\" ], \"match\": \"any\" } ], \"created_after\": \"2027-03-01\", \"created_before\": \"2027-03-31\", \"sort\": \"relevance\", \"order\": \"asc\", \"limit\": 25, \"cursor\": \"eyJvIjoyNX0\", \"last_activity_after\": \"2027-03-01\", \"last_activity_before\": \"2027-03-31\", \"metric_filters\": [ { \"metric\": \"spend\", \"operator\": \"greater_than\", \"value\": 1000 } ], \"fields\": [ \"id\" ], \"metrics\": [ \"spend\", \"impressions\" ] }")val request = Request.Builder() .url("https://api.focal.inc/v1/media/search") .post(body) .addHeader("Authorization", "Bearer <token>") .addHeader("Content-Type", "application/json") .build()
val response = client.newCall(request).execute()use serde_json::json;use reqwest;
#[tokio::main]pub async fn main() { let url = "https://api.focal.inc/v1/media/search";
let payload = json!({ "space_id": "6916bc3d-e1ab-425b-ac25-eefada01a9a2", "query": "trail runner at sunrise", "type": "video", "folder_id": "80539d38-3a8e-48f8-929b-8c0e9a22ab43", "include_subfolders": true, "status": "Approved", "uploaded_by": "cfebb6ef-f092-4591-a6e3-e6667ab5a252", "attributes": ( json!({ "attribute_id": "846196ad-9fa2-40a8-8938-655a962220e1", "values": ("Spring Launch"), "match": "any" }) ), "created_after": "2027-03-01", "created_before": "2027-03-31", "sort": "relevance", "order": "asc", "limit": 25, "cursor": "eyJvIjoyNX0", "last_activity_after": "2027-03-01", "last_activity_before": "2027-03-31", "metric_filters": ( json!({ "metric": "spend", "operator": "greater_than", "value": 1000 }) ), "fields": ("id"), "metrics": ("spend", "impressions") });
let mut headers = reqwest::header::HeaderMap::new(); headers.insert("Authorization", "Bearer <token>".parse().unwrap()); headers.insert("Content-Type", "application/json".parse().unwrap());
let client = reqwest::Client::new(); let response = client.post(url) .headers(headers) .json(&payload) .send() .await;
let results = response.unwrap() .json::<serde_json::Value>() .await .unwrap();
dbg!(results);}curl --request POST \ --url https://api.focal.inc/v1/media/search \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "space_id": "6916bc3d-e1ab-425b-ac25-eefada01a9a2", "query": "trail runner at sunrise", "type": "video", "folder_id": "80539d38-3a8e-48f8-929b-8c0e9a22ab43", "include_subfolders": true, "status": "Approved", "uploaded_by": "cfebb6ef-f092-4591-a6e3-e6667ab5a252", "attributes": [ { "attribute_id": "846196ad-9fa2-40a8-8938-655a962220e1", "values": [ "Spring Launch" ], "match": "any" } ], "created_after": "2027-03-01", "created_before": "2027-03-31", "sort": "relevance", "order": "asc", "limit": 25, "cursor": "eyJvIjoyNX0", "last_activity_after": "2027-03-01", "last_activity_before": "2027-03-31", "metric_filters": [ { "metric": "spend", "operator": "greater_than", "value": 1000 } ], "fields": [ "id" ], "metrics": [ "spend", "impressions" ] }'wget --quiet \ --method POST \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --body-data '{ "space_id": "6916bc3d-e1ab-425b-ac25-eefada01a9a2", "query": "trail runner at sunrise", "type": "video", "folder_id": "80539d38-3a8e-48f8-929b-8c0e9a22ab43", "include_subfolders": true, "status": "Approved", "uploaded_by": "cfebb6ef-f092-4591-a6e3-e6667ab5a252", "attributes": [ { "attribute_id": "846196ad-9fa2-40a8-8938-655a962220e1", "values": [ "Spring Launch" ], "match": "any" } ], "created_after": "2027-03-01", "created_before": "2027-03-31", "sort": "relevance", "order": "asc", "limit": 25, "cursor": "eyJvIjoyNX0", "last_activity_after": "2027-03-01", "last_activity_before": "2027-03-31", "metric_filters": [ { "metric": "spend", "operator": "greater_than", "value": 1000 } ], "fields": [ "id" ], "metrics": [ "spend", "impressions" ] }' \ --output-document \ - https://api.focal.inc/v1/media/searchSearch a space’s media with the same engine that powers search inside Focal — so results and their ordering match what your team sees in the app.
query is ranked free text: it matches names, descriptions, folder names, tags and attribute values, and in spaces with Focal AI enabled it also matches text detected in the asset (OCR), speech transcripts, and the visual content itself — so “woman drinking coffee” can find a video nobody labelled that way. Filters (type, folder_id, status, uploaded_by, attributes, the created_* range) narrow the result set and combine with AND; a search with only filters and no query is ordered newest first.
Prefer GET /v1/media when you’re enumerating or syncing a space (stable keyset paging, cheaper), and this endpoint when you’re looking for something. Archived and still-uploading assets are excluded from both, and the response items are the same Media shape.
POST is used for the request-body filters; the call reads state and creates nothing — no Idempotency-Key applies.
Paging is an opaque next_cursor like the list endpoints, but over a ranked result set: it isn’t stable against assets entering or leaving the match set between pages, and relevance ordering gets approximate deep into the tail. Read the first pages, or sort by a column when you need to walk everything.
Pass fields to trim the response to the properties you actually need — e.g. "fields": ["name", "html_url"] returns just those (plus id, always). Unknown names are rejected rather than ignored.
Required scope: media:read. Rate-limit cost: 10.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”object
Required. The single space to query, as a UUID. The API reads one space at a time — comma-separated lists and wildcards are not accepted, and there is no implicit default.
Example
6916bc3d-e1ab-425b-ac25-eefada01a9a2Free-text query, ranked by relevance (≤200 chars). Matches names, descriptions, folder names, tags and attribute values; in spaces with Focal AI enabled it also matches text detected in the asset (OCR), speech transcripts, and the visual content itself. A media id here matches that asset exactly.
Example
trail runner at sunriseRestrict to one file type.
Restrict to a folder in the searched space. Subfolders are included unless include_subfolders is false. Unknown folders are rejected rather than ignored.
Example
80539d38-3a8e-48f8-929b-8c0e9a22ab43Whether to descend into subfolders. Default true. With folder_id, false restricts to that folder’s immediate contents; without it, false restricts to the space root.
Example
trueRestrict to media with this status — an id or name from the space’s catalog (the Space resource’s media_statuses), the same id-or-name contract as a status write.
Example
ApprovedRestrict to media uploaded by this user (a GET /v1/users id).
Example
cfebb6ef-f092-4591-a6e3-e6667ab5a252Filter on media attribute (custom field) values. Media must satisfy every entry; within an entry, values is any-of. number and date attributes aren’t searchable yet and are rejected.
object
The media attribute (custom field) to filter on — an id from GET /v1/media-attributes.
Example
846196ad-9fa2-40a8-8938-655a962220e1Values to match, interpreted per the attribute’s type: option ids or names for a tags field, user ids for a user field, "true" / "false" for a checkbox field (exactly one), and the stored text for text / link. Several values match any of them. An option value matching none of the attribute’s options — and a user value that isn’t a user id — is rejected rather than ignored, so a filter never silently widens the result set.
Example
[ "Spring Launch"]any (default) keeps media matching at least one value; none excludes media matching any of them.
Result ordering. relevance (default) ranks by match quality — meaningful only with a query; a filter-only search falls back to newest first. Any other key sorts by that column and ignores relevance entirely.
Sort direction. Defaults to asc for name and desc for the other columns. Ignored when sort is relevance (best matches always come first).
Max results per page (1–100). Default 25.
Example
25Pagination cursor returned as next_cursor from the previous page.
Example
eyJvIjoyNX0Narrow to media whose ad-platform metrics satisfy every one of these (ANDed, like the other filters). Compares against lifetime totals — { metric: "spend", operator: "greater_than", value: 1000 } means “has spent over 1000 in total”, not “spent over 1000 in some window”. Media with no data for the metric never match.
object
Which metric to compare — one of the keys that appear in a media’s metrics.insights.
How to compare — greater_than, less_than, or equals.
The bound to compare the metric’s lifetime total against.
Example
1000Return only these properties of each media asset, instead of the full object. id is always included. Omit for the complete object.
Performance metrics to include in each media’s metrics.insights. Default: the core set (spend, impressions, clicks, reach, installs, watch_min_3_seconds). all returns every metric with data — ad platforms report hundreds of conversion events, so expect a large response — or name keys like meta.omni_purchase. Only metrics with stored data come back, so an unknown key is silently absent rather than an error. Needs metrics to survive the fields selection.
Example
[ "spend", "impressions"]Responses
Section titled “Responses”OK
object
object
File extension.
IANA media type (the spec’s current name for what was historically called MIME type) derived from format. Provided as a convenience so clients don’t need to maintain their own extension → media-type table when uploading to ad platforms.
Don’t confuse this with the top-level type field — type is Focal’s coarse asset bucket (image/video/playable/file), while media_type is the precise IANA identifier ad platforms expect (e.g. image/jpeg, video/mp4).
Parent folder summary, or null if the media is at the space root.
object
File size in bytes.
Pixel width for visual media. null when dimensions don’t apply (e.g. type=file) or couldn’t be extracted.
Pixel height for visual media. null when dimensions don’t apply (e.g. type=file) or couldn’t be extracted.
width / height for visual media. null when dimensions don’t apply (e.g. type=file) or couldn’t be extracted.
Duration in seconds for video files. null for other types.
Total page count for multi-page formats (e.g. PDF). null for other types.
AI-generated summary of the media content, produced by Focal’s analysis pipeline. null until analysis has run (or for media types that aren’t analyzed). Read-only — for the customer-managed free-text field use description.
The media’s workflow status name (e.g. Approved), one of the space’s configured media statuses — see the Space resource’s media_statuses for the catalog. null when no status is set. Same read/write semantics as a tags attribute: reads return the name; writes accept the status id or name.
Generated identifier produced by a Creative ID naming convention — the combined <concept_id>-<variant_id> string the customer configured. null when the media isn’t governed by a Creative ID configuration.
Concept portion of the Creative ID — the stable text/date/counter prefix shared across variants. null when the media has no Creative ID.
Variant number within a concept. Incremented per variant of the same concept. null when the media has no Creative ID.
Custom-field values attached to this media — one entry per populated field. A multi-value field carries an array value; a single-value field a scalar. Empty array when no custom fields are populated.
object
The kind of custom field this value belongs to. Combined with multiple, tells you the JSON type of value (for a multi-value field it’s the type of each array element):
number→ JSONnumbercheckbox→ JSONtrue/falsedate→ ISO 8601stringtags→ option idstring(option names indisplay_value)user→ user idstring(display names indisplay_value)- everything else → JSON
string(e.g. URLs forlink)
Whether this field holds multiple values. When true, value is an array (one element per stored value); when false, value is a single scalar.
External identifiers for the ad platforms this media has been successfully exported to (YouTube, Meta, TikTok). One entry per export — re-exports and separate destinations each add an entry, so a media can appear more than once for the same channel. Empty array when the media hasn’t been exported, or only to channels without creative identifiers (e.g. Google Drive). In-progress and failed exports are excluded.
object
YouTube video id — the watch id.
Canonical YouTube watch URL.
Id of the YouTube channel the video was uploaded to (e.g. UC…).
UTC ISO timestamp of when this export was created.
object
Meta ad video id.
Meta ad account the asset was uploaded to, in the act_<id> form the Marketing API expects. null for Business Library exports, which target a business asset library rather than an ad account.
UTC ISO timestamp of when this export was created.
object
Meta ad image id.
Meta image hash — the value you reference in an ad creative’s image_hash field.
Meta ad account the asset was uploaded to, in the act_<id> form the Marketing API expects. null for Business Library exports, which target a business asset library rather than an ad account.
UTC ISO timestamp of when this export was created.
object
TikTok video id.
TikTok material id, referenced when assembling TikTok ad creatives. null until TikTok finishes processing the asset.
TikTok asset preview URL, once available. null until TikTok finishes processing the asset.
UTC ISO timestamp of when this export was created.
object
TikTok image id.
TikTok material id, referenced when assembling TikTok ad creatives. null until TikTok finishes processing the asset.
TikTok asset preview URL, once available. null until TikTok finishes processing the asset.
UTC ISO timestamp of when this export was created.
Ad-platform performance for this media, rolled up by Focal’s metrics sync across every ad it has run in — where it ran (ad_accounts / campaigns / ad_sets), when it was last live (last_activity), and its lifetime totals (insights). null for media that has never run as an ad, or when the organization has no ad accounts connected. Use the metrics request parameter to choose which metrics come back.
object
The most recent date the ad platforms reported any data for this media — i.e. when it was last live. null when no dated data has been synced.
Ad accounts this media has been running in.
object
Focal’s id for this ad account / campaign / ad set.
Its name as reported by the ad platform. null when the sync hasn’t recorded one.
Campaigns this media has been running in.
object
Focal’s id for this ad account / campaign / ad set.
Its name as reported by the ad platform. null when the sync hasn’t recorded one.
Ad sets this media has been running in.
object
Focal’s id for this ad account / campaign / ad set.
Its name as reported by the ad platform. null when the sync hasn’t recorded one.
Lifetime performance totals, one entry per metric. Which metrics appear is controlled by the metrics request parameter — by default the core set, and only those a media actually has data for. Core metrics come first, then the rest alphabetically.
object
The metric key — a core name (spend, impressions, clicks, reach, installs, watch_min_3_seconds) or a platform-specific one (e.g. meta.omni_purchase). Pass these to the metrics parameter to select them.
The metric’s total across every ad this media has run in, over all time — not a windowed figure. Currency amounts are in the ad account’s own currency.
Browser URL that opens this media in the Focal web app (its space’s library). Hand this to users as a clickable link to the exact asset.
Pass back as cursor to fetch the next page. null on the last page.
true when another page is available. Equivalent to next_cursor !== null.
Total number of media matching the search across all pages. Relevance-ranked results are approximate at the tail — treat this as the size of the match set, not a promise about how many pages you can walk.
Example
{ "data": [ { "id": "786beeda-55ac-4025-bf6e-43b2918e84a9", "name": "spring-hero-4x5.mp4", "type": "video", "format": "mp4", "media_type": "video/mp4", "organization_id": "b46d9033-24b2-4441-87ad-2151088fde01", "space_id": "6916bc3d-e1ab-425b-ac25-eefada01a9a2", "folder": { "id": "80539d38-3a8e-48f8-929b-8c0e9a22ab43", "name": "Spring 2027" }, "size": 48213504, "width": 1080, "height": 1350, "aspect_ratio": 0.8, "duration": 18.5, "page_count": null, "description": "Hero cut for Meta and TikTok placements, 4:5.", "summary": "A trail runner crests a ridge at sunrise in Alder & Pine gear, then the logo and Spring 2027 title card appear.", "status": "Approved", "creative_id": "SPR27-0042-3", "concept_id": "SPR27-0042", "variant_id": 3, "attributes": [ { "attribute_id": "0f35c2a2-a71a-4423-b1f2-3b5d795c6332", "attribute_name": "Usage rights", "attribute_type": "text", "multiple": false, "value": "Paid social only, 12 months", "display_value": "Paid social only, 12 months" } ], "exports": [ { "kind": "youtube", "type": "video", "video_id": "u8Lk2VnTq4c", "url": "https://www.youtube.com/watch?v=u8Lk2VnTq4c", "youtube_channel": "UCa1Dp9Qw3nXr7LbT5vHkZ2g", "exported_at": "2027-03-05T09:30:00Z" } ], "metrics": { "last_activity": "2027-03-14T00:00:00Z", "ad_accounts": [ { "id": "act_2048117733", "name": "Alder & Pine – Paid Social" } ], "campaigns": [ { "id": "120211482993410331", "name": "Spring 2027 – Prospecting" } ], "ad_sets": [ { "id": "120211482993520447", "name": "Trail runners 25–44" } ], "insights": [ { "metric": "spend", "value": 1842.5 }, { "metric": "impressions", "value": 412930 }, { "metric": "clicks", "value": 9318 } ] }, "created_at": "2027-03-04T10:15:00Z", "updated_at": "2027-03-06T14:42:00Z", "html_url": "https://app.focal.inc/spaces/6916bc3d-e1ab-425b-ac25-eefada01a9a2/library?file=786beeda-55ac-4025-bf6e-43b2918e84a9&folder=80539d38-3a8e-48f8-929b-8c0e9a22ab43" } ], "next_cursor": "eyJ0IjoiMjAyNy0wMy0wNFQxMDoxNTowMC4wMDBaIiwiaSI6Ijc4NmJlZWRhLTU1YWMtNDAyNS1iZjZlLTQzYjI5MThlODRhOSJ9", "has_more": true, "total": 128}The request was malformed (invalid cursor, unknown type, validation failure, etc.). error.code is bad_request.
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
object
object
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.
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
object
object
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.
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
object
object
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.
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
object
object
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.
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
object
object
Example
{ "error": { "code": "rate_limited", "message": "Rate limit of 1000 units per 60s exceeded (this request cost 5)" }}Headers
Section titled “Headers”Example
12Seconds to wait before retrying.