Changelog
Breaking changes to a released version are announced before they ship. Additive changes — a new field, a new endpoint, a new error code — can arrive at any time, so parse defensively: ignore fields you do not recognise.
Unreleased — first delivery
Section titled “Unreleased — first delivery”Version v1 has not been released to partners yet. Everything below is the shape
of the first delivery.
-
Product access now uses persisted company features and owner permissions equally for direct and partner accounts. Partner commercial offers do not revoke granted features. New tokens require the requesting app’s feature; issued tokens keep their normal TTL, with credential revocation still immediate.
-
Meeting and call ownership follows the owner’s current default company for direct and partner accounts alike; historical event markers do not fix ownership. Credential company and visibility restrictions remain in place. WhatsApp uses saved session ownership consistently; sessions without a company keep their authorized legacy resolution.
-
Meeting template names outside the current company scope now use the stable label
Template; historical answers and company-scoped template references remain available. Personal and currently authorized template names are preserved. -
WhatsApp responses and source visibility include
umbler_talkandantonellaalongside WhatsApp Web and RD Conversas, using the account’s enabled integration and the owner’s permissions. -
The OAuth protected resource metadata names the resource
MCP serverinresource_name, and the/oauth/authorizeerror page anderror_descriptiontexts no longer name a brand.
Tooling
- An official MCP server ships alongside v1:
@salesbud/mcpon npm, one tool per public read operation, for Claude Desktop, Claude Code and Cursor. It is a client of this API and adds no capability of its own. See MCP server. - MCP server 0.2.0: new
list_accounts,list_teamsandlist_tagstools; the list tools accept the new filters; list text names every account of each record, up to three (its name, else its domain), including email conversations, which previously printed a blank account. - MCP server:
get_api_contextsays whether the credential belongs to the company or to a user, and names the owner. - MCP server 0.3.0: it authenticates with OAuth (Bearer), so Claude and ChatGPT can
connect by signing a person in. With no credential,
POST /mcpanswers401with aWWW-Authenticatechallenge whoseresource_metadatapoints to/.well-known/oauth-protected-resource. An invalid, expired or revoked token reads as a request to reconnect, and a connection awaiting administrator approval is reported as such by the tools. FixedX-Client-Id/X-Client-Secretheaders keep working. See Connect Claude or ChatGPT. - MCP server 0.4.0: new
find_meetingsandfind_callsfind one account’s records by name, domain, CNPJ or id; one call reads at most 30 pages in 20 seconds and hands back its ownnext_cursorwhen a ceiling stops it. A call the client cancels stops the reads it started, and every date parameter declaresformat: "date-time". The text of the existing tools’ answers is unchanged. See MCP server. GET /mcp/toolslists the MCP tools without a credential — the same fieldstools/listreturns, plusserverVersion— cacheable for five minutes. See MCP server.- MCP server 0.3.1: every tool declares
destructiveHint: falseandopenWorldHint: falsealongsidereadOnlyHint: true, so assistants know the tools only read the connected Salesbud workspace.
- Salesbud is listed in Claude’s connector directory: Claude users connect it from the directory, with the custom connector as a fallback. See Connect Claude or ChatGPT.
Resources
- Calls are their own collection at
/v1/calls, withcall_identifiers. A record captured from a VoIP integration hasobject: "call"; everything else is ameeting. Ids do not resolve across collections. - All five routes are mirrored for both collections: list, retrieve, transcript, template answers and overall evaluation.
- A call does not carry
bot_historyat all: a VoIP capture has no recording bot, so the field is omitted rather than returned empty, and a schema that validates a call rejects it.enablement.meeting_typestays and is oftennull— that null is legitimate, unlike the bot. - WhatsApp conversations of the company’s sellers are a collection at
/v1/whatsapp, withwa_identifiers andwamsg_messages, behindwhatsapp.read(metadata) andwhatsapp.content.read(sanitized text, media metadata, audio transcriptions).last_message_atmoves only on a new message, so re-read messages to observe edits and deletions; deleted messages stay as tombstones. Date filters compare in whole seconds. See WhatsApp. - Added
GET /v1/accounts,GET /v1/teamsandGET /v1/tags: paginated catalogs of the company’s own accounts (searchable by name or domain withq, 2 to 100 characters), teams and tags, with the opaque ids the list filters accept. Accounts without a usable domain and tags with an empty name are not listed. - Account references in meetings, calls, emails and WhatsApp conversations now
carry
name(nullwhen the account has no name yet).
Errors
- The error envelope is
{ type, title, detail, code, request_id }. Every field is snake_case; the HTTP status stays in the status line and is not repeated in the body. Branch oncode. POST /oauth/tokenkeeps the OAuth 2.0 error shape required by RFC 6749 §5.2.- A malformed
account_id,team_idortag_id, ascore_minorscore_maxthat is not an integer from 0 to 10,score_mingreater thanscore_max, or aqoutside 2 to 100 characters isINVALID_FILTER. A well-formed id the company does not own returns an empty page, not an error. Reusing a cursor with a different filter isINVALID_CURSOR. POST /oauth/tokenanswersinvalid_clientwith the error_description “The credential has no active owner.” for a user credential whose owner is no longer an active member of the company. User credentials add no other error code: a resource outside the owner’s view is404.- New error
403 API_CLIENT_PENDING_APPROVAL(“The API client is waiting for administrator approval.”): the token belongs to a connection that is still awaiting administrator approval. - The existing
403 API_ACCESS_DISABLED(the company has no API access) is now documented onPOST /oauth/token. It uses the error envelope above, not the OAuth error format.
Pagination and filters
- Cursors are signed and ordered by ascending id; they bind the filters of the request that produced them.
updated_after,updated_beforeandsnapshot_atwere removed. Without a dedicated visibility timestamp there is no honest incremental sync; re-query by period instead.updated_atremains in responses as informative only.- The date filters are
meeting_afterandmeeting_before. Earlier drafts also acceptedmeeting_at_fromandmeeting_at_to; those never reached a partner and were removed rather than shipped as deprecated on day one. - Added
account_idandteam_idto/v1/meetings,/v1/calls,/v1/emailsand/v1/whatsapp, andtag_id,score_minandscore_maxto/v1/meetingsand/v1/calls. See Filtering by account, team, tag and score. team_idmeans the sellers whose default team it is: a seller in several teams counts for their default team only, so a seller’s meetings, calls and WhatsApp chats land in at most one team. Sellers with no team, and RD Conversas chats, belong to no team, so summing the teams can fall short of the unfiltered total. The assignment is the current one, not the team on the date of the record. A team with no members returns an empty page. On emails it matches a conversation when any of its threads is in a team member’s mailbox, so a conversation shared across teams can appear under more than one. On WhatsApp it covers only numbers a team member connected directly; RD Conversas chats have no owner and are excluded whenteam_idis set.score_minandscore_maxare inclusive and count completed evaluations only: a meeting being re-evaluated drops out of a score-filtered list until the new evaluation completes.- Cursors issued before this change stay valid: the new filters enter the cursor only when present.
Access
- The API is gated by the
API_ACCESScompany feature, checked at token issuance and at credential creation. - Emails and account domains are normalised to lower case in every field, so an address can be used as a join key regardless of where it appears.
- The catalogs are open to any collection read scope:
meetings.read,calls.read,emails.readorwhatsapp.read. - Added user credentials: requested by any member of a company with
API_ACCESSwho does not approve credentials, approved by an administrator, 3 active and 1 pending per user in each company, valid for 30, 90, 180 or 365 days counted from the approval, and limited to what their owner can see in Salesbud, including meetings shared with them. Company credentials are unchanged. See Two kinds of credential, Requesting a user credential and User credentials see what their owner sees. - Rotating a user credential, which only its owner can do, stops the previous secret at once and sets a new validity.
GET /v1/contextnow returnsclient.kind(companyoruser) andclient.owner, the owner of a user credential (nullfor a company credential).- A user credential’s token carries only the scopes its owner can use at issuance time, and changes to the owner’s teams, shares or permissions reach the API within 60 seconds.
- With the ACCOUNTS feature off, a user credential gets an empty
/v1/accounts,accounts: []on meetings, calls, email and WhatsApp conversations, and an empty page when filtering byaccount_id. - Added OAuth sign-in for connectors:
GET /oauth/authorize, theauthorization_codeandrefresh_tokengrants ofPOST /oauth/token(the token response carries a rotatingrefresh_tokenfor them, and the OAuth errorinvalid_grantis new), and discovery metadata at/.well-known/oauth-authorization-serverand/.well-known/oauth-protected-resource. The connection is a user credential that reads what the person who signed in can see, waits for administrator approval when that person does not approve credentials, and is listed on the API credentials screen with the app’s name.client_credentialsis unchanged. See Connect Claude or ChatGPT. - Salesbud‘s own apps, such as the AI collaborators, connect through the same OAuth sign-in
under the AI collaborators feature instead of API access, and
POST /oauth/tokenanswers403 AI_COLLABORATORS_DISABLEDwithout it. Their connection is active without approval and stays out of the per-user limits. See Requesting a user credential. - Added
POST /oauth/revoke(RFC 7009): a refresh token or an access token of a connection made by signing in revokes the whole connection, and the answer is200with an empty body even for an unknown token. The authorization server metadata announces it inrevocation_endpoint. See/oauth/revoke. - Renewing a connection an administrator disabled answers
invalid_grantwith"error_description": "The connection was disabled by a company administrator."; it renews again once it is enabled. POST /oauth/revokeand the owner’s revoke no longer turn a connection an administrator disabled into a revoked one: its refresh tokens end and it stays disabled until an administrator revokes it.