DAM Wiki

Brandfolder API

Smartsheet Inc. (Brandfolder by Smartsheet) · USA (Brandfolder founded in Denver, CO; parent Smartsheet in Bellevue, WA) · Founded 2012 · subsidiary of SmartsheetVerified 2026-09-30 · 110 sources
  • SaaS
  • Mid-market
  • REST API
  • OpenAPI spec
  • Webhooks
  • SAML SSO
Complete · 7 of 7 pages
110sources
1API specs
09-30verified 2026
Official website ↗Brandfolder alternatives →

Scope: the public Brandfolder REST API ("V4", plus the separate v1 webhooks service) and the adjacent Insights Data Connector (BigQuery). Since the Smartsheet acquisition the documentation lives on the Smartsheet developer portal under /api/brandfolder, but the API itself still runs on brandfolder.com S3 S19. The Smartsheet API (api.smartsheet.com/2.0) and the Smartsheet MCP server are different products and do not expose Brandfolder assets S20.

At a glance

API styles
REST/JSON with JSON:API-style envelopes (data, included, meta) S1 S5. Methods GET, PUT, POST, DELETE only (405 otherwise) S6. No GraphQL.
Base URL(s)
https://brandfolder.com/api/v4 for everything except webhooks; https://brandfolder.com/api/v1 for /webhooks* S1 S3. Binary uploads go to signed Google Cloud Storage URLs returned by /upload_requests S1. Single global host — no tenant subdomains and no regional API hosts are documented S3. CDN delivery: cdn.bfldr.com / cdn.brandfolder.io S51 S52
Current version(s) & deprecations
Spec info.version: v4; no header- or date-based versioning S1. Deprecated and removed from the spec: org-wide asset/attachment listing and DELETE/tags/{id} (announced "soon deprecated" in the legacy docs S17; "API Endpoint Updates" deprecation dated 2025-02-03 on the product timeline S83)
Auth methods
Per-user API key sent as Authorization: Bearer {BF_API_KEY} (security scheme APIToken, HTTP bearer) S1 S4. No OAuth for the Brandfolder API: /.well-known/openid-configuration and /.well-known/oauth-authorization-server return 404 S19
Token lifetime / refresh
No expiry, rotation or refresh mechanism is documented for API keys S4 (Not public)
Scopes / permission model
No scopes: a key sees exactly what its user can see (Owner / Admin / Collaborator / Guest, plus one custom role) S3 S28. Service accounts are not documented
Official spec
OpenAPI 3.0.3, 45 paths / 73 operations S1; rendered reference with "Try it" console S2; every portal page has a Markdown twin (.md) and the portal publishes llms.txt S16. Archived copy on DAM Wiki: API spec downloads. No Postman collection
Rate limits
Not public (no number, window or quota). 429 "Too Many Requests" when the API key reaches the threshold S6 S11. No Retry-After / X-RateLimit-* headers observed S18
Pagination
page (1-based) + per (default 100, max 3000); meta carries current_page, next_page, prev_page, total_pages, total_count S1 S5 S11
Webhooks / events
Yes — API-managed subscriptions, per Brandfolder, 3 event types (asset.create, asset.update, asset.delete), skinny payload, up to 15 retries, no documented signature S1 S13
Official SDKs
Python (brandfolder 2.0.0, 2024-12-20), PHP (repo states "no longer under active development"), Panel UI SDK for embedding the Brandfolder panel (npm @brandfolder-panel/sdk 0.9.33) S8 S21 S22 S23
Sandbox / trial access
No public sandbox or free trial documented; the pricing page offers demo/quote only S80. Using the API is subject to an API License Agreement S3

Authentication

Getting a key S3 S4

  1. Each user finds a personal API key on the profile page, Integrations tab (https://brandfolder.com/profile#integrations), and copies it with the icon next to the key.
  2. Send it on every call: Authorization: Bearer {BF_API_KEY}. The spec also declares Accept: application/json and Content-Type: application/json as required header parameters on most operations, including GETs S1.
  3. The same key authenticates the v1 webhooks service (Content-Type: application/json + Bearer); the key is checked against the subscribed Brandfolder S1.

Permission model — responses only include resources the key's user can access S3. Roles: Owner (organization level only), Admin, one optional custom role (Collaborator abilities plus selected admin capabilities), Collaborator, Guest; permissions flow downward from Organization → Brandfolder → Collection; Portals and Brandguides are separate permissible objects S28. The API enum for permission_level lists only guest, collaborator, admin, owner S1; how the custom role is represented is Unknown.

Behaviour of a missing or bad key — list endpoints answer 200 with an empty list rather than 401/403 (/organizations, /brandfolders), while /upload_requests answers 403 and the v1 webhooks service answers 403 S18. Integrators therefore need an explicit key check (non-empty /organizations, or GET/users/whoami) S9 Unverified (/users/whoami is documented only in a recipe, is absent from the spec, and returned 404 without a key S18).

Other identity products — Smartsheet's own API/MCP use Smartsheet tokens and OAuth; they are not a way to authenticate to Brandfolder S20. Content Automation (Outfit) has its own separate SAML app S69.

Core resources

Paths relative to https://brandfolder.com/api/v4 unless stated. Inventory from the spec S1; items marked † are used in official recipes/SDK but absent from the spec.

ResourceEndpointsNotes
OrganizationsGET/organizations, GET/organizations/{id}fields=asset_count (+ cname on fetch, added to docs 2025-11-24 S7); include=brandfolders,brandguides,collections,portals
Brandfolders (libraries)GET/brandfolders, GET/PUT/brandfolders/{id}, POST/organizations/{id}/brandfoldersAttributes name, privacy, slug, tagline; list fields=asset_count,attachment_count,storage; fetch fields=asset_count,attachment_count,section_count, include=organization,collections,search_filters,sections; 422 on invalid/non-unique slug
SectionsGET/POST/brandfolders/{id}/sections, GET/sections/{id}default_asset_type ∈ GenericFile, Color, Font, ExternalMedium, Person, Press, Text; no update/delete endpoint; GET/collections/{id}/sections † S12
Collections (incl. Workspaces)GET/collections, GET/POST/brandfolders/{id}/collections, GET/PUT/DELETE/collections/{id}Attributes name, slug, tagline, public, stealth, is_workspace
Assets (list / search)GET/brandfolders/{id}/assets, GET/collections/{id}/assets, GET/sections/{id}/assets, GET/labels/{id}/assetspage, per, search, fields=created_at,updated_at,cdn_url,availability, include=attachments,brandfolder,collections,custom_fields,section,tags (section list has no include in the spec)
Assets (single)GET/PUT/DELETE/assets/{id}Fetch additionally allows fields=availability_start,availability_end; PUT sets name, description, availability_start/end, approved, and adds attachments (never replaces)
Asset creationPOST/brandfolders/{id}/assets, POST/collections/{id}/assetsBulk: data.attributes is an array of assets, each with attachments[{url, filename}]; section_key required S1 S14
Attachments (files)GET/PUT/DELETE/attachments/{id}; GET/assets/{id}/attachments † S13fields=metadata,thumbnail_url,view_thumbnail_retina,extension,version_count,tag_names,label_names; include=asset,section,brandfolder,collections,tags,labels; created only via asset create/update
TagsGET/brandfolders/{id}/tags, GET/collections/{id}/tags, GET/POST/assets/{id}/tags, PUT/tags/{id}, DELETE/async/tags/assets/{asset_key}One tag record per asset; async bulk delete body {"tags":[…],"locale":"en"} S1 S17
Metadata schema (custom field keys)GET/POST/brandfolders/{id}/custom_field_keys, PUT/DELETE/custom_field_keys/{id}Per Brandfolder; fields=value, include=custom_field_values; deleting a key deletes its values
Metadata valuesGET/assets/{id}/custom_field_values, POST/custom_field_keys/{key_id}/custom_field_values (one key → many assets), PUT/DELETE/custom_field_values/{id}All values are strings
Labels (hierarchical taxonomy)GET/POST/brandfolders/{id}/labels, GET/PUT/DELETE/labels/{id}, PUT/labels/{id}/move, GET/labels/{id}/assetsFeature not enabled on every account S1; no endpoint to assign an asset to a label
Users / permissions`GET /organizationsbrandfolders
InvitationsGET/`POST /organizationsbrandfolders
Current userGET/users/whoami † S9 Unverified not in spec
UploadsGET/upload_requests → PUT/resumable to GCSSee Uploads & binaries
Renditions / derivativescdn_url field (asset lists), attachment url, thumbnail_url, view_thumbnail_retinaOn-the-fly transforms via Smart CDN URL parameters S51; no rendition endpoint in the API
Rightsavailability_start / availability_end / computed availability, approvedNo dedicated rights/licence object S1 S37
Workflows / approvalsapproved boolean onlyApproval configuration, approvers, Workspace tasks, comments and annotations have no endpoints S1
Webhooks (v1)GET/POST/webhooks, GET/DELETE/webhooks/{id}, POST/webhooks/sendSee Events & webhooks
Analytics (bulk)Insights Data Connector (BigQuery) — not RESTSee Data model S15

Not exposed in the documented API (checked against the spec S1): share links, portals and Brandguides content (only their invitations), user groups and SSO/SAML teams, comments/annotations, version history (only version_count), download/view analytics, asset history log, search-filter CRUD, asset automations, metadata conversions, duplicate-detection settings, moving an asset to another section, adding an existing asset to a collection or label, and bulk update/delete of assets.

Data model

  • Hierarchy: Organization → Brandfolder → Section → Asset → Attachment(s). Assets can also belong to many Collections in the same Brandfolder; an asset lives in exactly one Section S3 S1. Portals and Brandguides hang off the Organization S28.
  • Asset = a container; the files are Attachments (files, but also colours, fonts, external media links) S1. An asset can hold up to 75 attachments S49. The JSON:API type of an asset follows the asset type (generic_files in all examples) S5; the Insights connector lists types Color, ExternalMedium, Font, GenericFile, Person, Press, Text S15.
  • Asset attributes: default name, description, thumbnail_url (signed, expiring), approved; optional via fields=: created_at, updated_at, cdn_url, availability, and on single fetch availability_start / availability_end S1.
  • Attachment attributes: mimetype, extension, filename, size (bytes), width, height, url, position, thumbnail_url; optional metadata, version_count, tag_names, label_names S1. No checksum/hash field is documented S1.
  • Identifiers: opaque string keys (e.g. oqgiju-21olts-ce9egi); the docs use "key" and "id" interchangeably (asset_key) S1 S13. Organizations, Brandfolders and Collections also have URL slugs S1.
  • Custom fields: schema is per Brandfolder (custom_field_keys: name, allowed_values[], restricted, required, prioritized (≤ 5), position) S1. Each value is a separate key/value record attached to exactly one asset; keys and values are always strings S1. Multi-value, dependent fields (one level, ≤ 12 children per parent value) and translations exist in the UI but are not modelled in the API schema S38 S39 S1.
  • Tags: per-asset keyword records with name, read-only auto_generated and nullable source (e.g. google_vision) — distinguishes AI tags from user tags S1.
  • Labels: hierarchical (path[] of label ids, depth starting at 1, position); spec wording ("starting with this label's ID") and example ordering are ambiguous Unverified S1.
  • Availability: availability_start = publish date (Draft banner before), availability_end = expiry (Expired banner after) S1 S37. The Insights connector documents availability values published, unpublished, expired, pending approval S15; whether the REST field uses the same strings is Unknown.
  • Dates: ISO 8601 with milliseconds and Z (e.g. 2018-09-11T20:31:34.858Z) S5; webhook event_time is YYYY-MM-DD HH:MM:SS.ffffff S1.
  • Insights Data Connector (paid analytics path): a customer-specific GCP project with BigQuery dataset brandfolder (bfdc-<org-slug>.brandfolder.<table>), refreshed nightly; tables assets (incl. created_by, availability), attachments, brandfolders, cdn_aggregates, collections, custom_field_values, events, sessions, tags, users (incl. SSO/SAML-team and last-active columns), user_permissions, sharelink, share_link_items S15. It is the only documented machine-readable source for events, share links and user activity.

Search & querying

AspectBehaviour
Wheresearch= on the four asset-list endpoints and on GET/brandfolders S1 S10
SyntaxSame as the UI search bar (Lucene-like), must be URL-encoded S5 S10. Default operator between bare terms is OR; AND/&&, NOT, * (trailing wildcard), ~ (fuzzy), "phrase", grouping tags:(a "b c"), ranges [a TO b], >/< S48
Field filtersname:, asset_key:, asset_type:, filename:, extension:, description:, section:, collection:, labels:, tags: / tags.strict:, custom_fields.<Key>:"<Value>", metadata.<key>:, created_at:, updated_at:, published_at:, expires_at:, approved:, expired:, comments:, view_only:, size:, width:/height:, creator:, people.strict: S48 S11
Empty / non-emptyNOT custom_fields.Key:(*) (key missing), NOT label: *, NOT expires_at:* S48
Relative datescreated_at:>now-10m, updated_at:>now-1d, expires_at:[now TO now+14d] S48
Facets / aggregationsNone in the API; counts only via meta.total_count of a filtered query S5
Sortingsort_by ∈ name, score, position, updated_at, created_at with order ∈ ASC, DESC (both required together) S5
Page sizeper default 100, max 3000 S1 S5; fields/include "can slow down" responses S5. Behaviour above 3000 is Unknown (anonymous probe with per=5000 returned an empty 200, which proves nothing) S18
Deep pagination / deltaNo cursor and no since parameter S1; deltas rely on updated_at search/sort or webhooks. Maximum reachable page is Not public
Organization-wide crawlOfficially: list Brandfolders (?include=organization), then sections per Brandfolder, then GET/sections/{id}/assets?include=attachments S1
Errors404 often means a misspelled custom-field key/value in the query; an empty 200 can mean bad syntax/encoding S11
Reserved characters> < ( ) { } [ ] " * : reserved; ! ? + - / ~ ^ = have special meaning S48

Uploads & binaries

From a public URL (bulk) S1 S14: POST/brandfolders/{id}/assets (or /collections/{id}/assets) with data.attributes[] = assets, each with attachments[{url, filename}], and a top-level section_key. The source URL must stay reachable "for at least a couple of hours"; attachment metadata (mimetype, size) is filled asynchronously after processing S1.

From a private/local file (binary upload) S1

  1. GET/upload_requests → upload_url, resumable_upload_url, storage service type and object_url (the spec schema names it service, the prose service_type Unverified).
  2. PUT the bytes to upload_url, or use the GCS resumable protocol: POSTresumable_upload_url with x-goog-resumable: start, then PUT chunks. Resumable is recommended for poor connections, local files > 200 MB or server-side files > 500 MB.
  3. Create the asset with attachments[].url = object_url.
  • URLs are single-use for one asset; upload_url/resumable_upload_url expire after 24 h; objects at object_url are purged after 7 days.

New versions: PUT/attachments/{id} with a new url, or PUT/assets/{id} with extra attachments (added, not replacing) S1. The version list itself is UI-only; the API exposes version_count S1 S47.

Downloads & renditions

  • Attachment url and thumbnail_url are signed, expiring URLs S1.
  • cdn_url (Smart CDN) is available when the CDN is included in the plan S13. Smart CDN URLs accept parameters such as width, height, pad=true, position=n (nth attachment), extension swap (e.g. .png → .jpg), auto=webp (v2) or .auto (v1) S51. CDN links are disabled for pending, expired, draft or view-only assets S51; the spec documents a 404 on asset lists and a 403 on GET/assets/{id} "for CDN URLs of assets that are pending approval or unpublished" S1. Links may stay cached up to 24 h after expiry/deletion S51.
  • Custom CDN links by filename (/<CDN-KEY>/fn/<filename>) are activated by support S51. Customers can front the origin cdn.bfldr.com with their own CDN, but lose automatic invalidation (Brandfolder suggests webhooks for that) S52.
  • Video: HLS stream link in the asset's Embed tab; iframe player with loop, muted, autoplay parameters S51 S57.

Events & webhooks

S1 S13 unless noted.

  • Host: https://brandfolder.com/api/v1 (a separate service: Server: gunicorn S18).
  • Subscribe: POST/webhooks {"data":{"attributes":{"event_type","resource_type":"brandfolder","resource_key":<brandfolder_id>,"callback_url"}}}; list active (GET/webhooks), fetch, delete. One subscription per event type per Brandfolder (409 if it already exists).
  • Events: asset.create, asset.update (name, description, section, approval status, expiration status, comments & annotations, tags, custom fields — add/update/delete), asset.delete. A new asset fires create and then update (when processing completes). Edits made at Collection level also fire. No events for users, permissions, labels, collections or schema.
  • Payload ("skinny"): {"data":{"attributes":{"key","event_time","event_type","brandfolder_key","organization_key"},"webhook_id"}} — the receiver must re-fetch the asset.
  • Delivery: acknowledge immediately with 2xx; otherwise up to 15 retries with exponential backoff; persistently failing subscriptions become inactive; ordering not guaranteed (sort by event_time); subscriptions are deactivated within 30 minutes if the key's user loses access; callback_url must be public HTTPS.
  • Test: POST/webhooks/send → 202 and a fake notification to callback_url.
  • Signature / HMAC: Not public (none documented).
  • UI side: webhooks appear in the integrations directory as a developer option S81.

Limits & quirks

TopicDetail
Silent empty listsMissing/invalid key → 200 + empty list on list endpoints, not 401 S1 S18
403 / 404 semantics403 = missing/inappropriate key or deleted resource; for CDN URLs of pending/unpublished assets the spec lists 403 on GET/assets/{id} but 404 on asset lists S6 S1 Unverified
Rate limitThreshold Not public; counted per API key; no rate headers S11 S18
Required headersAccept and Content-Type: application/json declared required even on GET S1
Bodiesattributes is an object for single updates but an array for bulk creates (assets, tags, custom field keys); custom-field-value creation uses data as an array of {attributes, relationships} S1 S17
fields semanticsAdds non-default attributes (not a sparse fieldset) S5
Endpoints outside the specGET/users/whoami, GET/assets/{id}/attachments, GET/collections/{id}/sections are used in official recipes/SDK but not in the spec S9 S12 S13 Unverified
Per-Brandfolder schemaCustom fields, labels and webhooks are all scoped to one Brandfolder; an organization has no shared schema S1
Tag/value rowsRenaming or deleting a tag or custom-field value affects only that asset's record S1
No checksumNo MD5/SHA field on attachments; native duplicate detection is UI-only, pixel-exact S1 S45
Section changesNo API to update/delete sections or to move an asset between sections S1
Deprecated org-wide listingGET/organizations/{id}/assets and /attachments removed; Python SDK 2.0.0 warns org-level listing will break S17 S21
Stale doc linksSDK READMEs still point to developer(s).brandfolder.com, which now 301-redirects to the Smartsheet portal S21 S19
Label path orderingSpec description vs example ambiguous S1 Unverified

SDKs, tools & code samples

Library / toolLanguageMaintainerStatus
brandfolder (brandfolder-sdk-python)PythonBrandfolder / Smartsheet2.0.0 on PyPI (2024-12-20); thin client wrapper; repo last pushed 2024-12-20 S21 S98
brandfolder/brandfolder-sdk-phpPHPBrandfolder / SmartsheetREADME: no longer under active development; last push 2024-01-10 (still listed on the portal) S8 S22
@brandfolder-panel/sdk (Panel UI SDK)JavaScriptBrandfolder (brandfolder-developers)0.9.33 (2024-12-17); iframes the Brandfolder panel for browse/upload in third-party apps S8 S23
sketch-plugin-brandfolderJavaScriptBrandfolderSketch plugin; last push 2026-04-14 S24
orientier/brandfolder-sdk-phpPHPCommunity forkLast push 2025-07-28 S25
contentstack/marketplace-brandfolder-appTypeScriptContentstackContentstack Marketplace app; last push 2026-09-10 S25
damiankw/brandfolder.uploadPythonCommunityBulk uploader to Organization > Brandfolder > Section; last push 2026-01-13 S25
moiso97barrantes-ship-it/Brandfolder-MCPTypeScriptCommunityOnly public Brandfolder MCP repo found; no licence; single push 2026-04-23 S25
Postman collection——None published S16
Official Ruby / .NET / Java SDKs——None found S98

Changelog of the API

DateChange
2025-11-24Docs fix: cname listed as a valid fields value on GET/organizations/{id} S7
2025-07-10Docs fix: operation titles renamed ("Create custom field values for an asset", "Create tags for an asset") S7
2025-02-03"API Endpoint Updates": endpoints unsuited to searching assets across Brandfolders deprecated (org-wide asset/attachment listing) S83 S17
2024-12-20Python SDK 2.0.0 deprecates org-level asset/attachment listing S21
2024-12-16Custom CDN links (by filename) S83
≤ 2024-04DELETE/tags/{id} announced as "soon deprecated" in favour of DELETE/async/tags/assets/{asset_key} (exact date Unknown) S17
2022-12-01SDK for Panel UI integration released S83
2020-02-24Webhooks documentation improved (create/edit/delete asset events) S83

Stored API specs

1 file · 207 KB · verbatim copies of public vendor filesSpecs README & provenance
FileFormatSizeDownload
brandfolder_openapi_v4.yamlOpenAPI207 KBDownload
Search the wiki