Zendesk Brands API

The Zendesk brands API is small, well behaved and quietly essential. If you create tickets programmatically across brands, you'll need it on day one.

What the endpoint gives you

Brands are a first class resource, so they list, read, create, update and delete like anything else in the Zendesk API.

The reason most people arrive here is duller than brand management: they need the id. Tickets, users and help centre articles all carry a brand_id, and creating a ticket without one drops it on the default brand. See multibrand for why that matters to the customer receiving the reply.

Paths and field names below reflect the shape the API has had for a long time, but always confirm against the current Zendesk developer docs before shipping.

Listing brands with the Zendesk brands API

The simplest useful call on the whole endpoint.

curl -s -u you@example.com/token:APITOKEN \
  https://acme.zendesk.com/api/v2/brands.json \
  | jq -r ".brands[] | [.id, .subdomain, .active, .default, .name] | @tsv"

You get id, name, subdomain, whether the brand is active, whether it's the default, plus the host mapping and the logo if one is set. Results are paginated, and unless you run a lot of brands the first page is the only page.

Cache this at startup and key your code off a stable brand name or subdomain rather than pasting numeric ids into source. Sandbox brand ids differ from production. That's exactly the class of bug that only shows up after a release.

Creating and updating

A create needs a name and a subdomain. The subdomain has to be globally unique across all of Zendesk, not just your account, so expect collisions on anything generic.

curl -s -u you@example.com/token:APITOKEN -X POST \
  -H "Content-Type: application/json" \
  -d @brand.json \
  https://acme.zendesk.com/api/v2/brands.json

With brand.json:

{
  "brand": {
    "name": "Acme Wholesale",
    "subdomain": "acme-wholesale",
    "active": true,
    "has_help_center": true
  }
}

Updating is a PUT to /api/v2/brands/{id}.json with only the attributes you want changed. Two notes. Renaming a brand is safe and cosmetic. Changing a subdomain isn't, because anything pointing at the old one, including bookmarks and links in old emails, stops working.

Uploading a logo isn't a plain JSON field, since it involves an upload token rather than a URL string. Check the current docs for the exact flow, and honestly, setting logos in the admin interface once is easier than automating a thing you do twice a year.

Brand on other resources

The brand id shows up wherever an identity is customer-facing. Creating a ticket on a specific brand is one field.

{
  "ticket": {
    "subject": "Pallet delivery delayed",
    "brand_id": 360001234567,
    "comment": { "body": "Order 4471 has not arrived." }
  }
}

The same idea applies when you filter. Pulling tickets for a single brand is a search query on brand, or a filter applied after an export, depending on which route you use to read tickets. See the ticket API for the create and update mechanics.

Help centre resources carry a brand too, which matters if you push articles programmatically. Article endpoints live under the Guide side of the API and are addressed per brand host, so a script that publishes to two help centres talks to two base URLs, not one endpoint with a parameter.

Gotchas worth knowing before you build

Nothing here is obscure, and all of it's easier to read now than to discover during a launch window.

Deactivate rather than delete. Deleting a brand affects the tickets and content associated with it. Setting active to false takes it out of circulation without the drama.
The default brand cannot simply be removed. Move the default elsewhere first, and expect the API to refuse otherwise.
Host mapping is DNS. Pointing a custom domain at a brand needs records on your side, so it's never instant, whatever the API returns.
Brand limits depend on plan. The number of brands an account may hold varies by tier. Check yours before writing a provisioning script.
Rate limits apply as usual. Brand calls are cheap, so cache the list rather than fetching it on every ticket create.

One last piece of advice that has nothing to do with the API and everything to do with using it. Brands change roughly never. Whatever you build, build it to read brands once and hold them, and put a loud alert on the case where a brand you expect by name is missing from the response. That single check catches the misconfigured sandbox, the half-finished migration and the brand somebody deactivated on a Friday, all before a customer sees an email signed by the wrong company.

FAQ

Frequently asked questions

Where does brand_id appear on other resources?

On tickets, users and triggers. The Zendesk brand_id field is how a created ticket lands on the right brand, and forgetting it is why API-created tickets show up under the default brand.

How do I list all brands with the Zendesk API?

GET the brands endpoint on your subdomain. It returns id, name, subdomain, active and default flags for each brand, paginated.

How do I create a ticket on a specific brand?

Include brand_id in the ticket payload. Leave it out and the ticket lands on the default brand, so the reply carries the wrong identity.

Can I create brands through the API?

Yes, with a name and a globally unique subdomain. Plan limits on the number of brands still apply, so check yours first.

Should I delete a brand through the API?

Prefer deactivating it. Deletion affects associated tickets and content, and the default brand can't be removed until you move the default elsewhere.

Are brand IDs the same in sandbox and production?

No. Resolve brands by name or subdomain at startup instead of hardcoding numeric ids, or your sandbox-tested code will target the wrong brand live.

Automation creates tickets, and duplicates

Scripted ticket creation is a reliable source of near-identical tickets. Ticket Merger catches them before an agent does.

Start free trial

14-day free trial. No credit card required.