Per-User Brand Assets

Scope colors, images, fonts, videos and audio to a single embed user

Published


Give each of your embed users their own colors, images, fonts, videos and audio, seeded from your backend. This builds on Per-User Data, which needs to be enabled on the embed first.

Overview#

Every brand asset belongs to a workspace. When you also pass an embed user, the asset belongs to that user's private library instead, and only that user sees it in the editor.

This is what you want when one embed serves many brands, tenants or customers and each needs its own brand space. Push a brand's palette, logos and typeface from your backend, and the next time that brand opens the embed the assets are already there.

Pass both parameters together on any brand assets endpoint:

ParameterTypeDescription
embedIdStringYour embed instance ID, from the embed settings in your dashboard
embedUserIdStringThe same userId your app passes to the embed URL

They work as query parameters on every endpoint and verb. Write endpoints also accept them in the JSON body as embedUserId (or embed_user_id), matching the Studio Templates API.

Seeding a Brand#

const API = "https://api.orshot.com/v1/brand-assets";
const auth = {
  "Content-Type": "application/json",
  Authorization: "Bearer <ORSHOT_API_KEY>",
};
const scope = "embedId=YOUR_EMBED_ID&embedUserId=brand_123";

// A color, straight into that brand's palette
await fetch(`${API}/colors/add?${scope}`, {
  method: "POST",
  headers: auth,
  body: JSON.stringify({ type: "hex", value: "#FF5733", tags: ["primary"] }),
});

// A logo, into that brand's image library
await fetch(`${API}/images/add?${scope}`, {
  method: "POST",
  headers: auth,
  body: JSON.stringify({
    file: "https://cdn.example.com/brand-123/logo.png",
    fileName: "logo.png",
  }),
});

// A typeface, into that brand's font list
await fetch(`${API}/fonts/add?${scope}`, {
  method: "POST",
  headers: auth,
  body: JSON.stringify({
    file: "https://cdn.example.com/brand-123/Grotesk.woff2",
    name: "Brand Grotesk",
  }),
});

Reading back what one brand has:

await fetch(`${API}/colors/get?${scope}`, {
  headers: { Authorization: "Bearer <ORSHOT_API_KEY>" },
});

Supported Endpoints#

embedId and embedUserId are accepted on every brand assets endpoint:

AssetEndpoints
Images/images/get, /images/add, /images/confirm, /images/update/:id, /images/delete/:id
Colors/colors/get, /colors/add, /colors/update/:id, /colors/delete/:id
Fonts/fonts/get, /fonts/add, /fonts/update/:id, /fonts/delete/:id
Videos/videos/get, /videos/add, /videos/update/:id, /videos/delete/:id
Audio/audio/get, /audio/add, /audio/update/:id, /audio/delete/:id
Search/search

/images/upload-url takes no scope of its own. Pass the parameters to /images/confirm instead, which is where the asset is created.

What Each User Sees#

With Per-User Data enabled and a userId in the embed URL, the editor scopes most asset types to that user rather than merging them with the workspace library:

AssetWorkspace levelThat user's own
TemplatesVisible*Visible
FontsVisibleVisible
ImagesHiddenVisible
VideosHiddenVisible
AudioHiddenVisible
ColorsHiddenVisible

*Workspace templates are hidden when Can see studio templates is turned off for the embed.

So for images, videos, audio and colors, seeding per user is the only way to put an asset in front of an end user on a per-user embed. Fonts are the exception: a workspace-level font reaches every user.

Rendering is unaffected by scope. A template that references a per-user font or image renders the same through the API regardless of which library the asset lives in.

Notes#

  • Writes create the embed user if it does not exist yet, so you can seed a brand before it has ever opened the embed. This requires Per-User Data & Templates to be enabled on the embed, and it counts against your plan's embed user limit.
  • Reads, tag updates and deletes never create a user. They resolve the ID and match rows, so an unknown embedUserId simply returns nothing.
  • Deletes and tag updates are scoped too, so one user's ID can never touch another user's asset.
  • Responses carry embed_user_id as a hashed internal ID (eui_ plus 16 characters), so asset rows never expose your original userId. The original ID is kept on the embed user record itself, visible to you in your dashboard's user list. Passing either form back works.
  • If your workspace has more than one embed, always send embedId. Without it a brand new user cannot be placed.
  • Deleting an embed user from the dashboard either deletes their assets or releases them back to the workspace, depending on the option you choose.

Rate Limits#

  • 30 requests per minute per endpoint

Ready to automate?

Start rendering images, PDFs and videos from your templates in under 2 minutes. Free plan, no credit card.

Get your API key
  • Image, PDF and video generation via API
  • Visual editor with AI and smart layouts
  • Zapier, Make, MCP and 50+ integrations
  • White-label embed for your own app
  • 30 free credits — no credit card required