---
title: "Brand API skill"
description: "A skill file that teaches an AI agent to manage Tarkle brand pages with the API, and when to use MCP instead."
---

> Documentation Index
> Fetch the complete documentation index at: https://tarkle.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Brand API skill

This page is the text of the `tarkle-brand-api` agent skill.

The skill file itself is `SKILL.md` with this front matter:

```yaml
name: tarkle-brand-api
description: Create, update, publish, archive and restore Tarkle brand pages through the Tarkle API, including brand files, brand domains and brand webhooks. Use when a task manages a workspace's brand pages from code or from an agent, or when you must choose between the Tarkle MCP server and the API.
```

Use this skill to manage Tarkle brand pages (logo, color, font and guideline pages that a workspace shares with clients) from code or an agent. Check facts in the live OpenAPI file before relying on this text: `GET https://tarkle.com/api/v1/openapi.json` describes the paths and the error codes.

## API or MCP?

| You hold | You can do |
| --- | --- |
| A Tarkle API key, made in [Settings > API](https://tarkle.com/dashboard/settings/api) | Everything in this skill. |
| The same key in an MCP client, sent as `Authorization: Bearer <your-tarkle-key>` to `https://mcp.tarkle.com/mcp` | The MCP brand tools: read a brand, check and connect a brand's domain, create a draft brand and update a brand. |
| Browser sign-in (OAuth), with no key | The same MCP brand tools. |

A key marked **Legacy** does not open the MCP server: create a new key for it. Never put a key in a prompt, a file in the repository or a log.

## Your API key

Only the organization's owners and admins can open [Settings > API](https://tarkle.com/dashboard/settings/api). It has two tabs, **API keys** and **Webhooks**.

To make a key, click **Create**, enter a **Name**, choose **Access**, then click **Create** again. **Access** is **All workspaces** or **Only selected workspaces**. With the second choice, pick the workspaces the key may reach. The new key is shown once, in the **API key created** dialog: click it to copy, then click **Done**.

A key does everything the API and the MCP server can do in the workspaces it reaches, reading and writing. It acts as the person who made it. No key can make purchases. A brand call also needs that person to be an owner or admin of the workspace.

The key's menu (**Key actions**) has **Copy token**, **Rename** and **Delete**. Owners and admins can copy a key again from there. **Delete** stops the key at once. A key marked **Legacy** was made before API keys had full access and cannot be copied: create a new key instead.

A key made before API keys had full access keeps working for the calls its access covers. A call it lacks answers `403 forbidden`, and the answer names what is missing. A key that has no access at all answers `403 token_without_scopes`: create a new key.

## Every call

- Base URL `https://tarkle.com/api/v1`. Header `Authorization: Bearer <your-tarkle-key>`.
- Header `X-Workspace-Key: <8 character key>` on every call inside a workspace. `GET /workspaces` lists the keys the key can use. A workspace id is refused with `400 workspace_key_required`.
- A key limited to selected workspaces gets `403 no_access` in any other workspace.
- The key acts as the person who created it. For brand calls that person must be an **owner or admin** of the workspace, otherwise `403 forbidden`.
- A brand in `{brand}` is its id (uuid) or its slug. A brand of another workspace is `404 not_found`.
- Add `Idempotency-Key: <uuid>` to a `POST`, `PATCH`, `PUT` or `DELETE` you may repeat. The same key with the same request returns the first answer. A reused key with a different request is `422 idempotency_key_reused`.
- Errors are `application/problem+json`. Branch on `code`, not on the message. On `429`, wait `Retry-After` seconds.
- Brand calls allow 120 requests a minute per key.

## Recipes

**Create a brand and fill it in**

1. `POST /brands {"name": "Acme Bank", "slug": "acme-bank", "summary": "Business banking for small firms", "industry": "Finance"}`. `name`, `summary` and `industry` are required. Limits: summary 200 characters, story 2,000 characters. Do not send `access`, `is_draft` or `confirm_public`: a new brand is a private draft.
2. `PATCH /brands/{brand}` with the fields that change, such as text, links, colors, `download_approval`, `tracking` and SEO fields.
3. Upload the brand's files (below).
4. To publish, `PATCH {"is_draft": false}`. Read the brand with `GET /brands/{brand}` and check it is complete first.
5. To open it to everyone, `PATCH {"access": "public", "confirm_public": true}`. Without `confirm_public` the call answers `400 confirmation_required`. Ask the user before you do it.

**Upload a file (three steps)**

1. `POST /brands/{brand}/files {"slot": "icon", "size": <bytes>, "filename": "icon.png"}`. Slots: `icon`, `main_logo`, `banner`, `social_image`, `favicon`, `logo` (an extra logo), `asset` (a collection file), `team_photo` and `guideline_image`. The answer holds the `file_id`, an `upload` address to `PUT` the file to and a `complete_url`.
2. `PUT` the bytes to `upload.url`.
3. `POST /brands/{brand}/files/{file_id}/complete`. Logo, asset and team photo uploads take more fields. See [Upload brand files](/docs/api/brands/files).

- Types and sizes: icons, main and extra logos take PNG, JPEG, WebP or SVG up to 10 MB, and guideline images take the same. Banners, social images and team photos take PNG, JPEG or WebP up to 10 MB. A favicon takes PNG, JPEG, WebP, SVG or ICO up to 2 MB. Collection files take any type up to 100 MB.
- A file whose contents are not what its name says answers `422 invalid_file`, and the stored file is removed.

**Connect a domain**

`PUT /brands/{brand}/domain {"domain": "brand.example.com"}` takes a plain hostname, with no `https://`, path, port or spaces. The answer lists the `dns_records` to add at the domain's DNS host. Show them to the user before you go on.

- `409 domain_taken` means another brand, or another part of Tarkle, already uses the domain.
- `DELETE /brands/{brand}/domain` disconnects the domain. Ask the user before you remove a domain.

**Archive and restore**

`DELETE /brands/{brand}` with `{"confirm_delete": true}` archives the brand. Without `confirm_delete` the call answers `400 confirmation_required`. Ask the user before you archive. A brand is restored with `POST /archived-brands/{brand}/restore`.

**Listen for changes**

`POST /webhooks {"url": "https://...", "events": ["brand.updated"]}` adds an endpoint. Each request is signed with the endpoint's signing secret.

Verify each request with its `Tarkle-Signature` header, `t=<unix seconds>,v1=<hex>`. The `v1` value is an HMAC-SHA256 of `<t>.<raw body>` made with the secret. Reject a `t` more than 5 minutes old, and accept the request when one `v1` value matches.

Events: `brand.updated` (brand edits), `brand.downloaded` (downloads), `brand.request.created` (new access requests), `brand.request.approved` and `brand.request.rejected`. `brand.viewed` (page views) is sent only when an endpoint names it: "all events" does not include it.

## Rules for agents

- Read before you write: `GET /brands/{brand}` and show the user what will change. Send only the fields that change.
- Confirm with the user before: making a brand public, archiving a brand, removing a domain, deleting a webhook.
- Treat test data as real: use a clearly named test brand and archive it when you are done.
- Do not call the API from browser code. A key in a page is a leaked key.
- Not in the API: setting a password on an existing brand. Only `POST /brands` takes a password.

## Where to read more

- [Brand API guides](/docs/api/brands)
- [Errors](/docs/api/errors)
- [Authentication](/docs/get-started/authentication)
- [MCP server](/docs/mcp)
- [What is a brand page?](https://tarkle.com/help/branding/what-is-a-brand-page)

Source: https://tarkle.com/docs/ai-agents/brand-skill/index.mdx
