Skip to content
Beta

Reference Conventions

Conventions

The notation these docs use, and the rules every response follows: ids, timestamps, empty values, amounts, enums, versions, stability, errors and untrusted text.

Notation

  • GET /v1/leads/{id} is a method and a path under https://api.totemstudio.ai. A word in braces is a placeholder.
  • … stands for a value left out of an example.
  • $TOTEM_API_KEY is an environment variable that holds your secret key.
  • Field names appear as they are in the JSON. A dot reaches into an object: contact_permissions.do_not_contact.

Requests and responses

  • HTTPS only. Request and response bodies are JSON in UTF-8, and field names are snake_case.
  • Every resource, such as a lead, a call or a team, has an object field that names its type, and a livemode field. livemode is true on everything the API returns; only the example data of these docs has livemode: false.
  • A collection comes in a list envelope with object: "list", data, has_more and next_cursor. Lists and pagination explains it.
  • A few bodies have shapes of their own. The items of the changes feed carry kind, and the record sits inside them under object, or a removal under removed. GET /v1/health answers {"object": "health", "status": "ok"}. Errors follow the format described under Errors.

Ids

Ids are strings with a prefix that names the type of record:

PrefixRecord
team_Team
mem_Team member
svc_Bookable service
brd_Board
stg_Stage
lead_Lead, and its lead_attribution and lead_response facets
act_Lead activity
call_Call
conv_Conversation
bkg_Booking
prn_Integration

Treat an id as opaque: store it whole, compare it exactly and never parse it. An id stays the same while its record exists. A record that is removed and later created again can come back with a new id.

Member ids belong to one team: the same person has a different mem_ id in each team.

Timestamps

Timestamps are ISO 8601 strings in UTC, such as 2026-10-15T09:30:00Z, and may carry fractional seconds. Each team's time zone comes with GET /v1/teams/{id}; use it to display times, never to store them.

Empty values

In API objects, a field with no value is null, never an empty string. Some fields say why they are empty:

  • a lead's phone is null with phone_status set to missing or invalid;
  • a lead's pipeline fields are null with pipeline_cleared: true when someone converted the lead and cleared its pipeline data.

Phones and amounts

  • Phones are E.164 strings, such as +12025550123.
  • A lead's estimated_value and value_at_conversion are amounts as Totem stores them: in major units, such as euros or dollars rather than cents, possibly with decimals. estimated_value_currency is always null, because Totem stores no currency with these values.
  • No field of version 1.0a carries an amount in minor units.

Enums can grow

Fields with a fixed set of values, such as status or archive_reason, can gain values in any version, and so can error codes. When you meet a value you do not know, keep the record, treat the value as "other", and carry on with the sync. New kinds of record can also appear in the changes feed: store or skip an item whose kind you do not know, and keep syncing.

The OpenAPI document lists the values known today. If you generate a client from it, make sure the client accepts a value it does not know instead of rejecting the whole object.

Record versions

Every record the changes feed delivers carries version, an integer that grows each time the record changes, and updated_at, the time of that version. That covers leads and their two facets, activities, calls, conversations, bookings and boards. Apply a record only when its version is greater than the one you hold. The feed can deliver a record more than once; its version tells you which copy is newer.

Teams, members and bookable services have no version. When you read them again, replace your copy as a whole.

API versions and stability

/v1 is the current API version. New fields, enum values, endpoints and error codes can appear, so ignore what you do not use.

Every operation states its stability in this reference and, in the OpenAPI document, as x-totem-stability. In version 1.0a every operation is beta. Read the changelog for updates.

What Beta means

While the API is in Beta, Totem can change or remove fields, values and behavior, with no fixed notice period. The changelog lists changes under the date they shipped, and an entry that asks you to change your integration or to run a full resync starts with Action required. Additive changes, such as new fields, enum values, endpoints or error codes, can appear at any time, so build your integration to ignore what it does not know.

Request ids

Every response from the API carries a Totem-Request-Id header, such as req_0f6b2c1e-8d4a-4b7e-9c3f-5a2d1e7b9c40, and an error body repeats it as request_id. Log it, and quote it when you ask Support for help.

Errors

Errors follow RFC 9457 and come as application/problem+json:

JSON
{
  "type": "https://totemstudio.ai/developers/errors#team_required",
  "title": "Team required",
  "status": 400,
  "code": "team_required",
  "request_id": "req_0f6b2c1e-8d4a-4b7e-9c3f-5a2d1e7b9c40",
  "param": "Totem-Team",
  "doc_url": "https://totemstudio.ai/developers/errors#team_required"
}
  • code says what went wrong. Branch on code, never on title, which can change. type and doc_url both link to the code's entry on the Errors page, which says when it happens and what to do.
  • param, when present, names the header, parameter or field at fault. It never repeats the value you sent.
  • New codes can appear. Handle a code you do not know by its HTTP status.
  • A 401 also carries the header WWW-Authenticate: Bearer realm="Totem API".
  • A 429 carries Retry-After, a whole number of seconds: wait at least that long. Two codes use it, rate_limited and quota_exceeded; Rate limits explains both. Retry a 5xx with exponential backoff.

During Beta, the firewall in front of the API answers some requests itself with a plain 403, 404 or 429 that is not in this format: no JSON error body, no Retry-After and no Totem-Request-Id. It answers 404 to any path outside /v1/ and to any method other than GET and POST, HEAD included. Handle its answer by its status; Errors lists when each one happens.

Personal data in URLs

Never put a phone number, an email address or a name in a URL: URLs end up in logs on both sides. To find a lead by phone or email, send them in the JSON body of POST /v1/leads/search.

Text fields are untrusted input

Text fields such as a lead's name, surname, company, email and tags, a member's display_name, and attribution values such as UTM parameters and ad, campaign and form names come from web forms, the links visitors arrive from, ad platforms, messaging profiles and the team's own members, and Totem returns them as they were stored. Anyone who fills in a form or edits a link chooses what they contain. Escape them wherever you display them, and never interpret them as HTML, Markdown or a template. When you export them to CSV or a spreadsheet, put a single quote before any value that starts with =, +, -, @, a tab or a carriage return, so that no cell runs as a formula.

API version 1.0a