Skip to main content
A brand kit is how the notetaker presents itself in your customer’s calls. It also holds the look of a summary email, which only the preview shows for now. You build one in five steps:
  1. Upload your images with POST /files.
  2. Create the kit with POST /brand_kits. It answers a preview_url.
  3. Show preview_url to a human.
  4. Change the kit with PATCH /brand_kits/{id} until they approve it. Nothing is live yet.
  5. Apply it: set branding.brand_kit_id in a workspace’s settings.
  6. Optionally, send its summary emails from your own domain.
Every field is on the brand kit object.

1. Upload your images

Upload each image once, as multipart/form-data with purpose=brand_kit: a logo, and a 16:9 picture if you want your own video tile.
A file is a PNG, JPEG, GIF, WebP or SVG of at most 10 MB. Use a PNG for the logo the email shows: most mail clients don’t render SVG, and an SVG’s url downloads instead of displaying. A workspace takes 60 uploads a minute; past that, 429 rate_limited.

2. Create the kit

Send what you know; every group is optional and takes its default when left out.
The kit changes nothing yet: workspace_ids is empty until a workspace applies it in step 5. workspace_ids is read-only; settings decide which workspaces use a kit.

Which workspace owns it

workspace_id names the workspace that owns the files and the kit; send the same one on POST /files (as a form field) and on POST /brand_kits. Without it, both answer 400 missing on workspace_id, like every endpoint that acts in a workspace. workspace_id reads null when the key does not belong to the workspace that owns the kit.

3. Show the preview

Give preview_url to a human: it shows the notetaker’s tile in a call, its chat messages and the summary email, exactly as the kit is saved. It needs no sign-in and lasts 12 hours (preview_expires_at). Every GET or PATCH of the kit answers a fresh one:
An expired link shows that it expired; get a new one rather than retrying it.

4. Iterate

Send only what changes. Here the human wants their own picture on the tile:
The name, the chat and the email stay as they were, and the logo tile’s options stay stored: { "bot": { "tile": { "type": "logo" } } } switches back to it. Show the new preview_url. While no workspace uses the kit, nothing a customer sees changes. Once one does, every PATCH reaches its next calls and emails straight away.

5. Apply it

A workspace uses a kit through its settings, set on the workspace alone (["workspaces:wks_…"]). A new workspace has none of its own: it inherits your account’s. Give it settings that apply the kit:
If the workspace has its own settings already, that answers 409 scope_taken naming the assignment: PATCH its settings with the same branding instead. A kit is set on a workspace alone; on an account, a member or a meeting category it answers 422 not_supported. The kit’s read-only workspace_ids now lists the workspace. One kit can brand many workspaces: apply it to each. "brand_kit_id": "none" goes back to the default look. See Company settings. A single bot can still override the name, avatar and greeting when you send it.

6. Send from your domain

Summary emails come from summaries@aefer.ai until you give the kit an address on a domain you control. Use a subdomain such as mail.acme.com: your root domain’s SPF and DMARC stay as they are.
  1. Add the domain with your account key. The answer lists four DNS records: three CNAMEs and a TXT.
  2. Create the four records at your DNS provider, then call POST /email_domains/{id}/verify, or wait for the hourly check. The domain turns verified once all four resolve. Keep them in place after that. The email domain explains each status.
  3. Set the sender on the kit. You can do it right away: until the domain is verified, emails go out from summaries@aefer.ai under your name, so none waits on DNS.
The kit’s read-only email.sender.sending_as shows the From line that goes out right now. A domain that stops resolving turns failing, and emails fall back to summaries@aefer.ai until it resolves again. A domain a kit sends from can’t be deleted (409 domain_in_use): change the kit’s email.sender.address first.

What a kit holds

Each choice is a type plus an object named after it. A read returns only the chosen type’s object; the options of the others stay stored.

The bot

bot.tile.color.background_color and bot.tile.logo.background_color are one value: sending both with different colors is 422 invalid. The tile shows the same picture in every state of the bot (joining, recording, paused), so don’t put a state such as “Recording” in it. Write both chat messages in the brand’s voice, and keep {{user}}: it becomes the name of the person the notetaker records for, as you named them on the member. A message you don’t write reads as the standard one. The standard messages use bot.name.

The email

The email group is how the summary email looks. _æfer sends it after a meeting when summary.email.enabled is on in settings, which is off by default, from summaries@aefer.ai or your own domain: under a bot_name sent with the bot, else email.sender.name, else the bot’s name with the branded or custom email, and as “_æfer Notetaker” otherwise. The preview shows that same email. To write the email yourself and still have _æfer send it, use a custom email. To send it yourself, listen for bot.summary_ready and read the summary with GET /meetings/{meeting_id}/results (A finished meeting). email.branded.logo is the tile’s logo until you set one of its own. email.branded.cta is the button under the meeting’s name: If your users have no _æfer account, set cta to none or to a link. In link.url, {{meeting_id}} is replaced by the meeting’s mtg_id; write it exactly so, with no spaces. An email with no meeting to name shows the “Open meeting” button instead of alinkwhose url names{{meeting_id}}.

Your own HTML

With email.type: "custom", the email is your HTML, whole: _æfer adds no header, footer or unsubscribe link. Write email.custom.html and, optionally, email.custom.subject in Liquid:
The variables have the shapes of a meeting’s results:
  • Strict. An unknown variable or filter is an error, and so is reading a field of null: write {% if item.assignee %}{{ item.assignee.name }}{% endif %}. include and render aren’t available.
  • Escaped. Values are HTML-escaped where they land; summary.html is markup _æfer wrote.
  • What HTML is allowed. Inline style, <style>, tables and images. Every href and src is https:, mailto: or tel:. <script>, <form>, <iframe>, <object>, <embed>, <noscript>, SVG animation, <link rel="stylesheet">, @import and on* attributes are refused, never removed, so the preview is what’s sent.
  • Sizes. At most 100 KB as written and 102 KB rendered, where Gmail starts clipping. The subject is one line of at most 200 characters; null sends the standard one.
  • Checked when saved. A PATCH renders the email for a sample meeting, and again with no organizer, participants, time, meeting id or names, as a meeting may have. It refuses a template that fails either with a 422 saying what failed, with the line for a Liquid error. Check it in the preview.
  • Checked again when sent. A copy that can’t be rendered, such as a URL built from a meeting’s data that isn’t https, goes out as your branded email instead, and email.custom.last_error says why until the template changes.
PATCH email.type: "branded" goes back to the branded email and keeps your HTML for later.

Writing rules

  • Partial at every depth. On POST and PATCH, a group, an object or a field you leave out keeps its value. type can be left out: the current one stays.
  • null resets a text (bot.name, the chat messages, color, website, description) to its default.
  • A read’s bot and email can be sent back unchanged. Send those groups only, not the whole object: id, object, preview_url and the other read-only fields are 422 unknown_field. A name or message equal to the default the read showed stays unset, so it keeps following the default.
  • Files (bot.tile.logo.file, bot.tile.image.file, email.branded.logo) take a file_ id, null, or the { id, url } a read returned. From that object only id counts: the same id keeps the image, another id copies that file. The kit keeps its own copy, so it doesn’t depend on the file afterwards.
  • A file reads as { id, url }. url is the kit’s copy, short-lived (at most seven days, often less) and fresh on every read. id is null for an image uploaded in the dashboard.
  • null removes an image. email.branded.logo: null goes back to the tile’s logo. A logo or image tile can’t lose its file: choose another tile first.

Errors

Every error is { "errors": [{ "code", "field", "message" }] }. See Errors. field is the dotted path into your request, such as bot.tile.logo.background_color.