Swipe

Swipe endpoints expose the authenticated user's collections inside the Brandsearch app — Saved Ads, Saved Advertisers, Tracked Brands — and the boards that group them. Use them to pull a user's saved items into your own workflows.

There are three folder types:

  • Ads folders (/v1/swipe/ads-folders) — collections of saved Meta / TikTok / Instagram ads
  • Brands folders (/v1/swipe/brands-folders) — collections of saved advertisers (by brand ID)
  • Spectre folders (/v1/swipe/spectre-folders) — collections of tracked brands

For each folder type there are 3 endpoints — list folders, get folder (returns saved item IDs), and resolve to records (returns full ad / brand objects). Folder listing and item-listing endpoints are unmetered. Resolution endpoints charge 1 credit per returned row.

A _swipe field is attached to every resolved record so you can correlate the public ad/brand back to the saved-item entry that referenced it.

Access model — owner, edit, view

Folders and boards honour the dashboard's sharing model. Access is resolved as a permission level (owner > edit > view), granted either by sharing the folder directly with the user or by linking it into a board shared with them.

  • Reads (GET /v1/swipe/*-folders/{id}, /ads, /brands, and GET /v1/swipe/boards/{id}) need view or higher — a callable who's been shared a folder gets 200 instead of 404.
  • Writes (POST /v1/swipe/*-folders/{id}/items to save, PATCH /v1/swipe/*-folders/{id} to rename, DELETE /v1/swipe/*-folders/{id}/items/{item_id} to remove an item) need edit or higher. A caller with only view who attempts a write gets 403 swipe_folder_forbidden ("you can see it but not edit it"). The saved item is attributed to the folder owner's account — including the per-user save quota it counts against — mirroring the dashboard's save flow, so an edit collaborator adds to the owner's tally rather than their own.
  • Deleting a folder (DELETE /v1/swipe/*-folders/{id}) is owner-only. A user the folder is merely shared with — even at edit — gets 403 swipe_folder_forbidden.
  • No grant at all: still 404 swipe_folder_not_found (we never disclose folders the caller has no access to).

Permission lookups are cached briefly, so a share added or revoked in the dashboard takes effect within ~60s.


Manage folders

Three verbs complete the folder lifecycle and work identically for every folder type — just swap the slug (ads-folders, brands-folders, or spectre-folders). Each counts as 1 request, charges 0 credits, and carries the same hard per-key rate limit as create/save: 1 req/s and 5 req/min, on its own independent bucket. A folder the caller has no access to is hidden as 404 swipe_folder_not_found.

Rename a folder

Rename a folder you own or have edit access to. Body is { name } (1-100 characters). Returns the updated folder summary. Renaming to a name another of the owner's folders of that type already uses returns 409 swipe_folder_name_taken; a view-only collaborator gets 403 swipe_folder_forbidden.

Path parameters

  • Name
    folder_id
    Type
    string
    Description

    The folder's id.

Body parameters

  • Name
    name
    Type
    string
    Description

    New display name, 1-100 characters.

Request

PATCH
/v1/swipe/ads-folders/:folder_id
curl -X PATCH https://api.brandsearch.co/v1/swipe/ads-folders/ckxa1b2c3d4e5 \
  -H "X-API-Key: bsk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "Winning skincare ads"}'

200 OK

{
  "id": "ckxa1b2c3d4e5f6g7h8i9j0k",
  "name": "Winning skincare ads",
  "short_id": 7,
  "item_count": 12,
  "created_at": "2026-05-18T10:00:00Z",
  "updated_at": "2026-06-23T09:30:00Z"
}

Delete a folder

Delete a folder. Owner only — a user the folder is merely shared with (even at edit) gets 403 swipe_folder_forbidden. The folder and its item links are removed; the saved ads / advertisers / brands themselves are kept (they may live in other folders).

Path parameters

  • Name
    folder_id
    Type
    string
    Description

    The folder's id.

Request

DELETE
/v1/swipe/ads-folders/:folder_id
curl -X DELETE https://api.brandsearch.co/v1/swipe/ads-folders/ckxa1b2c3d4e5 \
  -H "X-API-Key: bsk_your_api_key"

200 OK

{
  "id": "ckxa1b2c3d4e5f6g7h8i9j0k",
  "deleted": true
}

Remove an item from a folder

Remove a single saved item from a folder — owner or edit access. Only the folder link is dropped; the saved entity itself is kept. item_id is the saved_ad_id / saved_advertiser_id / tracked_brand_id reported by the folder's GET response. Idempotent: removing an item that isn't in the folder still returns 200 with already_removed: true.

Path parameters

  • Name
    folder_id
    Type
    string
    Description

    The folder's id.

  • Name
    item_id
    Type
    string
    Description

    The saved item's id (saved_ad_id / saved_advertiser_id / tracked_brand_id).

Request

DELETE
/v1/swipe/ads-folders/:folder_id/items/:item_id
curl -X DELETE \
  https://api.brandsearch.co/v1/swipe/ads-folders/ckxa1b2c3d4e5/items/cksaved789 \
  -H "X-API-Key: bsk_your_api_key"

200 OK

{
  "folder_id": "ckxa1b2c3d4e5f6g7h8i9j0k",
  "item_id": "cksaved789",
  "removed": true,
  "already_removed": false
}

Ads folders

Create an ads folder

Create a new ads folder for the authenticated user. Counts as 1 request against your daily/monthly quota; does not charge credits. Folders created via the API appear immediately in the dashboard.

Body parameters

  • Name
    name
    Type
    string
    Description

    Display name for the folder. 1-100 characters. Names must be unique per user — re-using a name returns 409 swipe_folder_name_taken.

Each user has a folder cap (default 100 per type, raise on request). Over the cap returns 429 swipe_folder_quota_exceeded with details.current and details.limit.

Rate limit

A hard per-key rate limit applies on top of the global one: 1 request/second and 5 requests/minute — per endpoint type. The brands and spectre create endpoints have their own independent buckets, so hitting all three in parallel allows up to 3 req/s and 15 req/min total. Over either window returns the standard 429 rate_limited envelope with Retry-After and the X-RateLimit-* headers pointing at the tighter bucket.

Request

POST
/v1/swipe/ads-folders
curl https://api.brandsearch.co/v1/swipe/ads-folders \
  -H "X-API-Key: bsk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "Q4 Black Friday"}'

201 Created

{
  "id": "ckxa1b2c3d4e5f6g7h8i9j0k",
  "name": "Q4 Black Friday",
  "short_id": 42,
  "item_count": 0,
  "created_at": "2026-05-18T10:00:00Z",
  "updated_at": "2026-05-18T10:00:00Z"
}

Save an ad to a folder

Save an ad to one of your folders. Mirrors the dashboard's "save ad" flow.

There are two ways to describe the ad, and you must use one of them:

  • By id{ ad_id, type }. Pass the ad's id exactly as any other endpoint gave it to you (the id from a search / discover / folder result, the bare ad id, or Meta's composite {brand_id}_{ad_id}), and we build the canonical URL for you. This is the form to use for an ad you found through the API — it is byte-identical to what the dashboard stores, so the same ad saved from the app and from the API stays one row.
  • By URL{ url, type }, optionally with ad_id. Use this to save an ad that isn't in our catalogue.

A body carrying neither url nor ad_id returns 400 validation_error. An ad_id that matches no ad we know returns 400 invalid_parameter (details.parameter is ad_id) rather than saving an item that would never resolve back to anything.

Dedup is per (url, user): re-saving the same URL reuses the existing saved-ad record and just attaches it to the folder you specify. Idempotent on re-save: if the ad is already in the target folder, the response is still 201 with already_in_folder: true — no error.

Counts as 1 request against your daily/monthly quota; does not charge credits.

Path parameters

  • Name
    folder_id
    Type
    string
    Description

    Folder ID (1-64 chars). The folder must be owned by the authenticated user — folders owned by someone else return 404 swipe_folder_not_found.

Body parameters

  • Name
    ad_id
    Type
    string
    Description

    The ad's identifier — any form we publish for it. On its own it is enough to save the ad: the URL is built from our record. Required when url is absent.

  • Name
    url
    Type
    string
    Description

    The ad's source URL. Used as the dedup key alongside the user. Required when ad_id is absent.

  • Name
    type
    Type
    string
    Description

    Platform the ad came from. Must be meta, tiktok, or instagram. The alias facebook is accepted and normalised to meta server-side.

Quota

Each user has a saved-ads cap (default 5; raise on request). Creating a new saved-ad row that pushes you past the cap returns 429 swipe_item_quota_exceeded with details.item_type, details.current, and details.limit. Adding an already-saved ad to an additional folder does NOT consume save-quota — only the first save of a given URL does.

Rate limit

Same hard per-key limit as the folder-create endpoints: 1 request/second and 5 requests/minute on this endpoint. Brands and spectre save endpoints have their own buckets.

Request

POST
/v1/swipe/ads-folders/:folder_id/items
curl https://api.brandsearch.co/v1/swipe/ads-folders/ckxa1b2c3d4e5/items \
  -H "X-API-Key: bsk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "ad_id": "1472557257729515",
    "type": "meta"
  }'

201 Created

{
  "saved_ad_id": "cky1z2a3b4c5d6e",
  "url": "https://facebook.com/ads/library/?id=123",
  "type": "meta",
  "ad_id": "123",
  "added_at": "2026-05-23T10:00:00Z",
  "folder_id": "ckxa1b2c3d4e5",
  "already_in_folder": false
}

List ads folders

Paginated list of the authenticated user's Saved Ads folders. Unmetered.

Standard page / page_size pagination apply.

Request

GET
/v1/swipe/ads-folders
curl -G https://api.brandsearch.co/v1/swipe/ads-folders \
  -H "X-API-Key: bsk_your_api_key"

Response

{
  "data": [
    { "id": "fold_abc123", "name": "Q4 Black Friday", "item_count": 42 },
    { "id": "fold_def456", "name": "Skincare creatives", "item_count": 18 }
  ],
  "pagination": {"page": 1, "page_size": 20, "total": 2, "total_pages": 1}
}

Get an ads folder

Folder metadata + saved-ad items (ID and platform only — call /ads to resolve them to records). Unmetered.

Path parameters

  • Name
    folder_id
    Type
    string
    Description

    Folder ID (1-64 chars).

Returns 404 swipe_folder_not_found if the folder is not owned by the authenticated user.

Request

GET
/v1/swipe/ads-folders/:folder_id
curl https://api.brandsearch.co/v1/swipe/ads-folders/fold_abc123 \
  -H "X-API-Key: bsk_your_api_key"

Response

{
  "id": "fold_abc123",
  "name": "Q4 Black Friday",
  "item_count": 2,
  "items": [
    {"saved_ad_id": "sa_001", "ad_id": "123456789", "platform": "meta", "added_at": "2026-04-15T10:00:00Z"},
    {"saved_ad_id": "sa_002", "ad_id": "7321456789", "platform": "tiktok", "added_at": "2026-04-16T14:00:00Z"}
  ]
}

Resolve folder ads to records

Resolve every saved ad in the folder to its public record. Per-platform resolution is automatic — Meta items hit Meta data, TikTok items hit TikTok data, etc. Ads saved moments ago (the ones still showing is_valid: false and scraped_at: null in the folder listing) resolve too. Items we genuinely can't find — a deleted ad, or one that was never in our catalogue — are skipped silently.

Each returned record gets a _swipe block with the saved-ad id, platform, and added_at timestamp.

Charges 1 credit per returned row.

Optional attributes

  • Name
    fields
    Type
    string
    Description

    Comma-separated field allowlist applied across all platforms.

Request

GET
/v1/swipe/ads-folders/:folder_id/ads
curl -G https://api.brandsearch.co/v1/swipe/ads-folders/fold_abc123/ads \
  -H "X-API-Key: bsk_your_api_key" \
  -d page_size=20

Response

{
  "data": [
    {"id": "abc123", "brand_id": "nike.com", "status": "Active", "creative": {"title": "Just Do It.", "description": "Shop the latest collection.", "cta": {"text": "Shop now", "type": "SHOP_NOW"}}, "_swipe": "..."}
  ],
  "pagination": {"page": 1, "page_size": 20, "total": 42, "total_pages": 3}
}

Each row's _swipe block contains saved_ad_id, platform, and added_at.


Brands folders (Saved Advertisers)

Create a brands folder

Create a new brands folder for the authenticated user. Same shape as POST /v1/swipe/ads-folders — body is { name }, 1 request charged, 0 credits. Names are unique per user; duplicates return 409 swipe_folder_name_taken. Folder cap (default 100) over-limit returns 429 swipe_folder_quota_exceeded. Same hard rate limit: 1 req/s and 5 req/min on this endpoint.

Request

POST
/v1/swipe/brands-folders
curl https://api.brandsearch.co/v1/swipe/brands-folders \
  -H "X-API-Key: bsk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "Skincare competitors"}'

201 Created

{
  "id": "ckxa1b2c3d4e5f6g7h8i9j0k",
  "name": "Skincare competitors",
  "short_id": 7,
  "item_count": 0,
  "created_at": "2026-05-18T10:00:00Z",
  "updated_at": "2026-05-18T10:00:00Z"
}

Save an advertiser to a folder

Save an advertiser to one of your brands folders — the same "Saved Advertisers" list the dashboard shows. Identify it by brand id (the cleaned domain, e.g. gymshark.com); a Meta page id is also accepted and resolved to its brand before the row is written.

Dedup is per (brand_id, user): re-saving the same advertiser reuses the existing record. Idempotent on re-save: already in the target folder returns 201 with already_in_folder: true.

Counts as 1 request against your daily/monthly quota; does not charge credits.

Path parameters

  • Name
    folder_id
    Type
    string
    Description

    Folder ID (1-64 chars). Must be owned by the authenticated user — otherwise 404 swipe_folder_not_found.

Body parameters

  • Name
    brand_id
    Type
    string
    Description

    The brand identifier — the cleaned domain, e.g. gymshark.com. A Meta page id (the numeric string from /v1/brands/{id}/advertisers or the Meta Ads Library) is accepted too and resolved to its brand. 1-255 characters.

  • Name
    advertiser_id
    Type
    string
    Description

    Alias for brand_id, kept for existing integrations. Pass exactly one of the two.

A value matching no brand we know returns 400 invalid_parameter (details.parameter is advertiser_id), rather than saving an item that would show up as a blank card in the app.

No per-user save-quota is enforced on advertisers (intentional behavioural parity with the dashboard). The folder cap on POST /v1/swipe/brands-folders still bounds how many brands folders a user can create.

Rate limit

1 request/second and 5 requests/minute on this endpoint, separate bucket from the ads and spectre save endpoints.

Request

POST
/v1/swipe/brands-folders/:folder_id/items
curl https://api.brandsearch.co/v1/swipe/brands-folders/ckxa1b2c3d4e5/items \
  -H "X-API-Key: bsk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"brand_id": "gymshark.com"}'

201 Created

{
  "saved_advertiser_id": "cky1z2a3b4c5d6e",
  "advertiser_id": "gymshark.com",
  "added_at": "2026-05-23T10:00:00Z",
  "folder_id": "ckxa1b2c3d4e5",
  "already_in_folder": false
}

List brands folders

Paginated list of the authenticated user's Saved Advertisers folders. Saved advertisers are stored as Meta page IDs and resolved to brand records on demand. Unmetered.

Request

GET
/v1/swipe/brands-folders
curl https://api.brandsearch.co/v1/swipe/brands-folders \
  -H "X-API-Key: bsk_your_api_key"

Get a brands folder

Folder metadata + saved-advertiser items (each item carries an advertiser_id — the brand ID, or a Meta page ID on rows saved before that changed). Unmetered.

Returns 404 swipe_folder_not_found if the folder is not owned by the authenticated user.

Item shape

{
  "saved_advertiser_id": "sav_001",
  "advertiser_id": "15087023444",
  "added_at": "2026-04-15T10:00:00Z"
}

Resolve folder advertisers to brands

Resolve every saved advertiser to its brand record.

Every saved item yields exactly one row, so the page slice and pagination.total always agree. Items we can't match to a brand still come back, as flagged placeholders — see unresolved items below. Note that two saved items pointing at the same brand return two rows, one per folder item.

Each returned brand gets a _swipe block with the saved-advertiser id, the original advertiser id, added_at, and resolved.

Charges 1 credit per resolved row — placeholders are free.

Optional attributes

  • Name
    fields
    Type
    string
    Description

    Comma-separated brand fields to include.

  • Name
    exclude_fields
    Type
    string
    Description

    Comma-separated brand fields to exclude.

Request

GET
/v1/swipe/brands-folders/:folder_id/brands
curl -G https://api.brandsearch.co/v1/swipe/brands-folders/fold_xyz/brands \
  -H "X-API-Key: bsk_your_api_key" \
  -d fields=name,monthly_visits,niche

Response

{
  "data": [
    {"name": "Nike", "monthly_visits": 150000000, "niche": "Fashion", "_swipe": "..."}
  ],
  "unresolved_count": 1,
  "pagination": {"page": 1, "page_size": 20, "total": 12, "total_pages": 1}
}

Each brand's _swipe block contains saved_advertiser_id, advertiser_id, added_at, and resolved.


Spectre folders (Tracked Brands)

Create a spectre folder

Create a new spectre folder for the authenticated user. Same shape as the other create endpoints — body is { name }, 1 request charged, 0 credits. Names are unique per user; duplicates return 409 swipe_folder_name_taken. Folder cap (default 100) over-limit returns 429 swipe_folder_quota_exceeded.

Request

POST
/v1/swipe/spectre-folders
curl https://api.brandsearch.co/v1/swipe/spectre-folders \
  -H "X-API-Key: bsk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "Brands to watch"}'

201 Created

{
  "id": "ckxa1b2c3d4e5f6g7h8i9j0k",
  "name": "Brands to watch",
  "short_id": 3,
  "item_count": 0,
  "created_at": "2026-05-18T10:00:00Z",
  "updated_at": "2026-05-18T10:00:00Z"
}

Save a tracked brand to a folder

Save a tracked brand to one of your spectre folders. Three mutually-exclusive modes:

  • Brand mode — body: { brand_id } on its own, or { url } pointing at the brand's own site (gymshark.com, https://www.gymshark.com/collections/mens — any URL form works). We resolve it against the catalogue and store it exactly as the dashboard would, so a brand tracked through the API is indistinguishable from one added in the app. This is the mode to use when all you have is a domain or a brand id. An input matching no brand we know returns 400 invalid_parameter (details.parameter is url or brand_id).
  • Meta Ads Library mode — body: { url, page_id }. url must point at facebook.com/ads/library/…. Dedup per (url, user).
  • Track Creatives mode — body: { brand_id, scrapman_id }. Dedup per (brand_id, user).

page_id pins the body to Meta mode, so { url: <storefront>, page_id: … } is still a 400. Providing nothing usable, or two modes at once, returns 400 validation_error. Idempotent on re-save: already in the target folder returns 201 with already_in_folder: true.

Saved brands are seeded with their name, logos, page name, follower counts and ad counts straight away, so they are presentable in the app immediately rather than after the next refresh.

Counts as 1 request against your daily/monthly quota; does not charge credits.

Path parameters

  • Name
    folder_id
    Type
    string
    Description

    Folder ID (1-64 chars). Must be owned by the authenticated user — otherwise 404 swipe_folder_not_found.

Body parameters

  • Name
    brand_id
    Type
    string
    Description

    Brand identifier (cleaned domain, e.g. nike.com). On its own it is a complete Brand-mode body; paired with scrapman_id it selects Creatives-mode.

  • Name
    url
    Type
    string
    Description

    In Brand-mode, the brand's own website in any URL form. In Meta-mode, a facebook.com/ads/library/… URL — which requires page_id alongside it.

  • Name
    page_id
    Type
    string
    Description

    Meta page identifier associated with a Meta Ads Library url. Required in Meta-mode, and its presence is what selects that mode.

  • Name
    scrapman_id
    Type
    string
    Description

    Source-side tracking identifier paired with brand_id in Creatives-mode. We do not publish this value anywhere, so use Brand-mode instead.

Quota

Each user has a tracked-brands cap on the user profile (trackedBrandsQuota, default 0 — most users will need it raised). Creating a new tracked-brand record past the cap returns 429 swipe_item_quota_exceeded. Linking an already-tracked brand to another folder does NOT consume this quota.

Rate limit

1 request/second and 5 requests/minute on this endpoint, separate bucket from ads and brands save endpoints.

Request

POST
/v1/swipe/spectre-folders/:folder_id/items
curl https://api.brandsearch.co/v1/swipe/spectre-folders/ckxa1b2c3d4e5/items \
  -H "X-API-Key: bsk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://www.gymshark.com"}'

201 Created

{
  "tracked_brand_id": "cky1z2a3b4c5d6e",
  "url": "https://facebook.com/ads/library/?id=42",
  "page_id": "100064123456789",
  "brand_id": null,
  "scrapman_id": null,
  "added_at": "2026-05-23T10:00:00Z",
  "folder_id": "ckxa1b2c3d4e5",
  "already_in_folder": false
}

List spectre folders

Paginated list of the authenticated user's Tracked Brands folders. Unmetered.

Request

GET
/v1/swipe/spectre-folders
curl https://api.brandsearch.co/v1/swipe/spectre-folders \
  -H "X-API-Key: bsk_your_api_key"

Get a spectre folder

Folder metadata + tracked-brand items. Each item carries a tracked_brand_id plus the brand reference used when it was tracked — typically a brand_id (the domain) or, as a fallback, a url. Unmetered.

Returns 404 swipe_folder_not_found if the folder is not owned by the authenticated user.

Item shape

{
  "tracked_brand_id": "tb_001",
  "brand_id": "nike.com",
  "url": null,
  "added_at": "2026-04-15T10:00:00Z"
}

Resolve folder ads

Resolve every tracked brand in the folder to its Meta ads — a one-call way to pull "show me the latest creatives from everyone I'm tracking". Per-tracked-brand fan-out is capped by max_ads_per_brand so one prolific brand doesn't drown out the others.

Each returned ad gets a _swipe block with tracked_brand_id, brand_id, and added_at so you can correlate ads back to the tracked brand entry that pulled them in.

Default fields include duration and has_transcript. When has_transcript=true, the ad also carries a transcript_url — fetch that URL to get a JSON transcript of the ad.

Charges 1 credit per returned row, matching /v1/brands/{id}/ads.

Optional attributes

  • Name
    max_ads_per_brand
    Type
    integer
    Description

    Max ads to pull per tracked brand (1-50, default 20).

  • Name
    status
    Type
    string
    Description

    active or inactive. Default: include both.

  • Name
    is_video
    Type
    boolean
    Description

    Filter by video ads.

  • Name
    is_image
    Type
    boolean
    Description

    Filter by image ads.

  • Name
    sort_by
    Type
    string
    Description

    Same Meta sort fields as /v1/brands/{id}/ads.

  • Name
    sort_order
    Type
    string
    Description

    asc or desc (default desc).

  • Name
    fields
    Type
    string
    Description

    Comma-separated Meta ad fields to include.

Request

GET
/v1/swipe/spectre-folders/:folder_id/ads
curl -G https://api.brandsearch.co/v1/swipe/spectre-folders/fold_xyz/ads \
  -H "X-API-Key: bsk_your_api_key" \
  -d max_ads_per_brand=10 \
  -d status=active \
  -d sort_by=eu_total_spend

Response

{
  "data": [
    {"id": "abc123", "brand_id": "nike.com", "duration": 30, "has_transcript": true, "transcript_url": "https://...", "_swipe": "..."}
  ],
  "pagination": {"page": 1, "page_size": 20, "total": 280, "total_pages": 14}
}

Each row's _swipe block contains tracked_brand_id, brand_id, and added_at.


Resolve folder to brands

Resolve every tracked brand to its brand record. Resolution tries the strongest identifier first — brand_id, then the Meta page id, then url — so brands tracked from the Meta Ads Library resolve just like ones tracked by domain.

As with brands folders, every saved item yields exactly one row; items that match nothing come back as flagged placeholders (see below). Each returned brand gets a _swipe block with the tracked-brand id, added_at, and resolved.

Charges 1 credit per resolved row — placeholders are free.

Same fields / exclude_fields options as brands folders above.

Request

GET
/v1/swipe/spectre-folders/:folder_id/brands
curl -G https://api.brandsearch.co/v1/swipe/spectre-folders/fold_xyz/brands \
  -H "X-API-Key: bsk_your_api_key"

Unresolved items

GET /v1/swipe/brands-folders/{folder_id}/brands and GET /v1/swipe/spectre-folders/{folder_id}/brands return one row per saved item, always — a folder holding 11 items answers with 11 rows, so the page slice and pagination.total never disagree.

Some of those items match no brand we know: a page with no store behind it, a domain that was never indexed, or a row saved without a usable identifier. They come back as placeholders rather than quietly disappearing.

  • Name
    unresolved_count
    Type
    integer
    Description

    On the response envelope: how many rows on this page are placeholders.

  • Name
    _swipe.resolved
    Type
    boolean
    Description

    On every row: true for a real brand record, false for a placeholder. Filter on this to get only brands.

  • Name
    _swipe.unresolved_reason
    Type
    string
    Description

    On placeholders only: not_indexed (we have no brand matching the identifier) or no_identifier (the saved row carries nothing to look up).

A placeholder also carries whichever identifiers the folder holds — brand_id, page_id, scrapman_id, url for spectre folders; advertiser_id for brands folders — and its id is the value that was looked up rather than a brand id.

Placeholders are free: credits are charged per resolved row only.

Response with a placeholder

{
  "data": [
    {
      "id": "gymshark.com",
      "name": "Gymshark",
      "_swipe": { "tracked_brand_id": "cky1z2a3b4c5d6e", "resolved": true, "added_at": "2026-05-23T10:00:00Z" }
    },
    {
      "id": "100064123456789",
      "_swipe": {
        "tracked_brand_id": "cky9y8x7w6v5u4t",
        "resolved": false,
        "unresolved_reason": "not_indexed",
        "page_id": "100064123456789",
        "url": "https://facebook.com/ads/library/?id=42",
        "added_at": "2026-05-24T08:30:00Z"
      }
    }
  ],
  "unresolved_count": 1,
  "pagination": { "page": 1, "page_size": 20, "total": 2, "total_pages": 1 }
}

Boards

Get a board

A board groups multiple folders into a workspace (e.g., a research board that bundles a Saved Ads folder, a Saved Advertisers folder, and a Tracked Brands folder). This endpoint returns the board metadata + each linked directory.

Each section identifies its directory type via directory.type, which is one of: saved_ads, saved_advertisers, tracked_brands, landing_pages.

Unmetered. Returns 404 swipe_board_not_found if the board is not owned by the authenticated user.

Request

GET
/v1/swipe/boards/:board_id
curl https://api.brandsearch.co/v1/swipe/boards/board_001 \
  -H "X-API-Key: bsk_your_api_key"

Response

{
  "id": "board_001",
  "name": "Q4 Beauty Research",
  "sections": [
    {"directory": "..."},
    {"directory": "..."}
  ]
}

Each directory object contains type (one of saved_ads, saved_advertisers, tracked_brands, landing_pages), id, name, and item_count.


Errors

CodeHTTPDescription
swipe_not_provisioned403The API key's account has not been linked to a Brandsearch user.
swipe_folder_not_found404The folder does not exist, or the authenticated user has no access to it.
swipe_folder_forbidden403The user can see the folder but is not allowed to perform this action — writing with only view access, or deleting a folder they do not own.
swipe_folder_name_taken409Another folder of the same type already uses that name. Returned when creating or renaming.
swipe_folder_quota_exceeded429The per-type folder cap has been reached.
swipe_item_quota_exceeded429The per-type saved-item cap has been reached.
swipe_board_not_found404The board does not exist, or is not owned by the authenticated user.

Was this page helpful?