Menu

SDKs

As bibliotecas oficiais de TypeScript e Python: um método tipado por operação, com novas tentativas, idempotência, paginação e prévia incluídas. Para outras linguagens, o contrato OpenAPI.

LinguagemPacoteStatus
TypeScript / JavaScript@mb-suite/sdkVersão preliminar sobre o contrato 2026-11-01. Ainda não publicado no npm.
Pythonmb-suiteVersão preliminar sobre o contrato 2026-11-01. Ainda não publicado no PyPI. Veja SDK de Python.
O pacote ainda não está no npm: este guia conta como funciona. O contrato OpenAPI já pode ser baixado (no fim desta página).

Instalação

npm install @mb-suite/sdk
import { MBSuite } from "@mb-suite/sdk";

// Sem apiKey, lê a variável de ambiente MB_API_KEY
const mb = new MBSuite({ apiKey: process.env.MB_API_KEY });
  • Node.js 20 ou posterior, ou qualquer ambiente com fetch global: Deno, Bun, Cloudflare Workers, funções da Vercel. Sem dependências.
  • Só no seu servidor: uma API key é um segredo e a API não aceita pedidos de um navegador, então o cliente não inicia em um.
  • Uma API key (mbs_live_…) ou um token OAuth (mbo_…): veja Autenticação.

Seu primeiro pedido

const me = await mb.platform.me(); // GET /v1/me

console.log(me.actor.uid, me.org.id);
console.log(me.lastResponse.requestId); // req_…: inclua-o se escrever para nós

Cada operação tem um id estável e o método o segue: crm.deals.create é mb.crm.deals.create(). Cada trecho vai em camelCase: crm.custom_fields.list é mb.crm.customFields.list() e task_management.tasks.complete é mb.taskManagement.tasks.complete(). A Referência mostra o id de cada uma.

  1. 1Primeiro, os parâmetros de rota, como texto e na ordem da rota: mb.crm.deals.get("deal_123").
  2. 2Depois, os parâmetros: um objeto em snake_case, igual à API (a query de um GET, o corpo do resto).
  3. 3No fim, as opções do pedido: organization, idempotencyKey, confirmToken, timeout, maxRetries, signal e headers.

Listar, criar e editar

const { data, has_more } = await mb.crm.deals.list({ status: "open", limit: 50 });

const { deal_id } = await mb.crm.deals.create({
  title: "Plan anual — Acme",
  value: 4800,
  currency: "USD",
  pipeline_id: "PIPELINE_ID",
  stage_id: "STAGE_ID",
});

await mb.crm.deals.move(deal_id, { stage_id: "NEXT_STAGE_ID" });
await mb.crm.deals.update(deal_id, { updates: { value: 5200 } });
const deal = await mb.crm.deals.get(deal_id);

Os parâmetros e os resultados são tipados a partir do contrato, e cada método traz a descrição da sua operação: o seu editor a mostra ao passar o cursor.

Paginação

Cada lista paginada tem um gêmeo …All() que percorre todas as páginas e entrega os itens um por um. Uma página pode vir vazia com has_more em true: o percurso continua. Saia do laço quando tiver o que precisa. Veja Paginação.

// Segue next_cursor até has_more ser false; limit é o tamanho de cada página
for await (const deal of mb.crm.deals.listAll({ status: "open", limit: 200 })) {
  console.log(deal.id, deal.title);
}

Prévia e confirmação

As operações que pedem confirmação —as em massa, as irreversíveis, as que enviam ou mudam algo fora do MB Suite ou têm um custo à parte, e as que sempre pedem— têm .dryRun(): não escreve nada e devolve a prévia e confirm(), que executa a mesma operação com os mesmos parâmetros e o confirm_token da prévia (vale 10 minutos). A sua idempotencyKey, passe-a para .dryRun() ou para confirm(): ela vai com a confirmação, nunca com a prévia, que não escreve nada. Veja Prévia e confirmação.

const { preview, confirm } = await mb.crm.deals.bulk.delete.dryRun({
  deal_ids: ["DEAL_A", "DEAL_B"],
});

console.log(preview.summary, preview.counts, preview.warnings); // nada foi excluído ainda

const { deleted } = await confirm(); // dentro de 10 minutos
  • Chamá-la sem token lança ConfirmationRequiredError.
  • Se o confirm_token chegar por outro caminho (uma aprovação, um agente), passe-o como opção: mb.crm.deals.bulk.delete(params, { confirmToken }).
  • Com uma API key, o DELETE simples de um registro que vai para a lixeira executa direto: await mb.crm.deals.delete("deal_123"). Com um token OAuth também passa por .dryRun().

Novas tentativas e idempotência

  • Cada mutação sai com uma Idempotency-Key (um UUID que o SDK gera, ou a sua) e a mantém nas novas tentativas: se uma resposta se perde, a nova tentativa devolve a guardada em vez de executar duas vezes.
  • São repetidos sozinhos, até 3 vezes com espera exponencial (0,5 s, 1 s, 2 s): os erros de rede, os timeouts, um 429 (rate_limited, external_rate_limited, um cooldown_active curto), um 409 idempotency_in_progress e os 5xx (os 503 external_unavailable e pdf_unavailable incluídos). Se a resposta traz Retry-After, espera exatamente isso.
  • Não são repetidos: o resto dos 4xx (um 409 external_rejected, por exemplo: a plataforma já disse que não; ou um 409 external_outcome_unknown: um envio que pode ter saído, verifique antes de repeti-lo), um 429 quota_exceeded (a cota diária volta às 00:00 UTC), um 502 ai_generation_failed (repetir chama a IA de novo e gasta créditos se ela responder: decida você) nem um Retry-After de mais de 60 segundos (um daily_limit_reached). O erro volta com retryAfter para você reprogramar.

Para que uma operação lógica seja segura entre as suas próprias novas tentativas, dê a ela a sua própria chave (vale 24 horas). A mesma chave com outro corpo lança IdempotencyError. Veja Idempotência.

// A mesma chave numa nova tentativa sua (outro processo, outro deploy) devolve a resposta guardada
await mb.crm.deals.create(newDeal, { idempotencyKey: `import-${row.id}` });

Erros

Todo erro herda de MBSuiteError e traz o formato único da API: type, code (estável: decida com ele), message, status, param, requestId, docUrl e details. A classe depende do type:

ClassetypeHTTP
InvalidRequestErrorinvalid_request400
AuthenticationErrorauthentication401
PaymentRequiredErrorpayment_required402
PermissionErrorpermission403
NotFoundErrornot_found404
ConflictErrorconflict409
ConfirmationRequiredErrorconfirmation_required409
IdempotencyErroridempotency422
RateLimitErrorrate_limit429
QuotaExceededErrorquota429
UpstreamErrorupstream502
ServiceUnavailableErrorunavailable503
MaintenanceErrormaintenance503
InternalServerErrorinternal5xx
ConnectionError, TimeoutErrorconnection—
import { MBSuiteError, NotFoundError, RateLimitError } from "@mb-suite/sdk";

try {
  await mb.crm.deals.get(dealId);
} catch (err) {
  if (err instanceof NotFoundError) return null;
  if (err instanceof RateLimitError) console.log(`Tente de novo em ${err.retryAfter} s`);
  if (err instanceof MBSuiteError) console.error(err.code, err.requestId, err.docUrl);
  throw err;
}

InvalidRequestError soma issues (qual campo e por quê), ConfirmationRequiredError soma reason (expired, mismatch), RateLimitError e ServiceUnavailableError somam retryAfter, QuotaExceededError é um RateLimitError com quota e MaintenanceError é um ServiceUnavailableError. Todos os códigos estão em Erros.

Contas

Uma API key de workspace trabalha nas Contas do seu alcance com MB-Organization. Escolha a Conta para todo o cliente, para um pedido ou com um cliente preso a ela. mb.platform.orgs.list() devolve as que a API key alcança. Veja Workspaces e Contas.

// Para todos os pedidos do cliente
const mb = new MBSuite({ apiKey: process.env.MB_API_KEY, organization: "ACCOUNT_ID" });

// Para um pedido (null = a organização da API key)
await mb.crm.deals.list({}, { organization: "OTHER_ACCOUNT_ID" });

// Um cliente para essa Conta; o original não muda
const account = mb.withOptions({ organization: "ACCOUNT_ID" });

O que cada resposta traz

Cada resultado leva lastResponse, que não aparece em JSON.stringify nem ao copiar o objeto: o request_id, a versão, a rajada e a cota do dia (para frear antes de um 429, veja Limites) e se foi a resposta guardada de um pedido anterior.

const page = await mb.crm.deals.list();

page.lastResponse.requestId;          // "req_…"
page.lastResponse.rateLimit;          // { limit, remaining, reset }: a rajada da API key (10 s)
page.lastResponse.quota;              // { limit, remaining, reset }: as chamadas de hoje
page.lastResponse.idempotentReplayed; // true se é a resposta guardada de um pedido anterior

Versões

O SDK envia MB-Version: 2026-11-01 em cada pedido: a versão que os seus tipos descrevem, não importa em qual a sua organização ficou fixada. Quando sai uma versão nova da API sai uma do SDK; a anterior continua ativa por 12 meses, e se uma resposta vier de uma versão em retirada, o SDK avisa uma vez com a data de Sunset. Veja Versões e o Registro de mudanças.

Tipos e pedidos manuais

import type { Item, Params } from "@mb-suite/sdk";

type NewDeal = Params<"crm.deals.create">; // o corpo de POST /v1/crm/deals
type Deal = Item<"crm.deals.list">;        // um elemento de data[]

// Qualquer endpoint por método e rota, com as mesmas novas tentativas e erros
await mb.request({ method: "POST", path: "/crm/deals/DEAL_ID/archive", body: { archived: true } });

Por padrão o cliente fala com https://api.mb-suite.com/v1; baseUrl o aponta para outro endereço (a mesma API responde em https://mb-suite.com/api/platform/v1). Os tipos crus do contrato são exportados como paths, operations e components.

Outras linguagens: o contrato OpenAPI

O contrato completo, em OpenAPI 3.1, está em GET /v1/openapi.json (com a sua API key ou o seu token, como qualquer pedido). É dele que saem os SDKs de TypeScript e Python, e serve para gerar um cliente em outra linguagem.

curl https://api.mb-suite.com/v1/openapi.json \
  -H "Authorization: Bearer $MB_API_KEY" \
  -o mb-suite-openapi.json

Cada operação do contrato traz extensões x-mb-*: a classe (x-mb-kind), se é idempotente, o lote, os eventos que emite, a tool do MCP e a permissão. Dentro de uma versão, o contrato só soma: veja Versões.