# @bzapper/client 中文文档

规范地址：https://npmcn.com/package/%40bzapper/client/

版本：0\.16\.0
npm 元数据更新时间：2026-10-21T12:10:35.088Z
中文译文更新时间：2026-11-08T22:24:56.506Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40bzapper/client
原文对照：https://npmcn.com/package/%40bzapper/client/?lang=original
项目主页：https://bzapper.com.br/
源码仓库：https://github.com/bernisoftware/bzapper-node

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：472 kB，44 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=18
- 运行依赖：0 个
- 首次发布：2026-06-26T00:55:27.723Z
- 最新版本发布：2026-10-21T12:10:34.687Z
- 近 30 天下载量：2376（2026-10-09 至 2026-11-07，npm 官方下载统计）
- 已发布版本数：27（近 12 个月 27 个）

## 中文简介

SDK official do bZapper para Node/TypeScript——网关德WhatsApp多租户.

## 安装

```sh
npm install @bzapper/client
```

也可以使用：`pnpm add @bzapper/client`、`yarn add @bzapper/client`、`bun add @bzapper/client`

## README

# @bzapper/ 客户端

SDK的官职 **b 泽珀** 第11段 节点/节点-网关-WhatsApp 多用户:cenecte números, envie mensages, gerencie instâncias, API keys e companyhe o uso.

-   无害环境管理+类型
-   **运行时间零度** (苏萨) `fetch` 节点18+)
-   埃尔罗斯·皮卡多斯(Erros tipados)`BzapperError` + 子类 por 状态) com `code` 报告e `requestId`
-   诺瓦斯自制帐篷`Idempotency-Key` (原始内容存档于2013-10-12) (英语). em toda escrita). – paderão Berni Software
-   Um Método para cada operação pública da API (159), pestado contra a suíte de conferidade (禁止遵守)

## 英斯特拉桑

```bash
npm i @bzapper/client
```

重新定义 **节点18+** (fetch nativo) (英语).

**修复一个 versão exata** 没有 `package.json` (单位:千美元)`"@bzapper/client": "0.16.0"`中标 `^`: 卡达释放 (原始内容存档于2013-10-12). declara nas notas se muda a superfície pública ou se é só aditiva.

## 哈罗世界

```ts
import { Bzapper } from "@bzapper/client";

const bz = new Bzapper({ apiKey: "bz_live_..." });

await bz.sendText({ to: "+5511999999999", body: "Olá!" });
```

欧 `baseUrl` tem 默认`https://api.bzapper.com.br`页:1 **逻辑** —— 说 通知 def/self-host: `new Bzapper({ apiKey: "bz_live_...", baseUrl: "http://localhost:8080" })`。 。 。 .

Também há uma 工厂:

```ts
import { createClient } from "@bzapper/client";
const bz = createClient({ apiKey: "bz_live_..." });
```

## 厄立特里亚

Crie a API 密钥无 pael do bZapper (**配置- API 密钥**{\\fn黑体\\fs22\\bord1\\shad0\\3ahbe\\4ah00\\fscx67\\fscy66\\2chffffff\\3ch808080}你该死 `bz.createKey(...)`键`bz_live_...`低调一个嗯 **专业** (números,收件箱e 数据) 伊索拉多斯·普罗耶托(英语:isolados por projeto); para agir em outro projeto da conta, passe `projectId` (没有标题) `X-Project-Id`Nunca exponha 一把钥匙,不是无名小卒.

## 配置

```ts
new Bzapper({
  apiKey: "bz_live_...",
  locale: "pt-BR",   // opcional → header Accept-Language (mensagens de erro traduzidas)
  timeout: 30_000,   // opcional, ms por tentativa (default 30000)
  maxRetries: 2,     // opcional, novas tentativas além da primeira (default 2; 0 desliga)
  projectId: "…",    // opcional → header X-Project-Id
  baseUrl: "http://localhost:8080", // opcional, só em dev/self-host
});
```

托达·恩维亚 `Authorization: Bearer <apiKey>`, (中文(简体) ), `Accept: application/json`, (中文(简体) ), `X-Bzapper-Client: bzapper-node/<versão>` (音乐) `User-Agent`), um (中文(简体) ) `X-Request-Id` 波尔 沙玛达, `Idempotency-Key` 纳斯·埃斯克丽塔斯, `Content-Type: application/json` (夸多哈科波)e `Accept-Language`编号 :`X-Project-Id` (原始内容存档于2017-09-27). quando configurados. 托多·梅多·阿西塔(英语: **乌尔蒂莫争论 逻辑** `{ idempotencyKey?, timeout?, maxRetries?, signal? }`。 。 。 .

## 门生

活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活`SendBase`: `to` (obrigatório, E.164 ou JID), (中文(简体) ), `instance_id?`, (中文(简体) ), `pool_id?`, (中文(简体) ), `quoted_message_id?`, (中文(简体) ), `quoted_participant?` (c) 国家妇女发展委员会, `client_reference?`, (中文(简体) ), `mentions?` (JIDs ou Telefones) (美国英语). 托多斯重毁 `{ message_id, status, client_reference? }`。 。 。 .

重试seguro:通过 `{ idempotencyKey }` 科莫 2o artigo de qualquer envio. 中国植物物种信息数据库. 重回原地 重回原地 `idempotency_in_progress` se a a amda roda; 422 单相机 `idempotency_key_reused` {\\fn黑体\\fs22\\bord1\\shad0\\3ahbe\\4ah00\\fscx67\\fscy66\\2chffffff\\3ch808080}我...

```ts
await bz.sendText({ to: "+5511999999999", body: "Pedido #42 confirmado" }, { idempotencyKey: "pedido-42" });
```

### 文本

```ts
await bz.sendText({ to: "+5511999999999", body: "Olá!" });
```

### 图像

```ts
await bz.sendImage({
  to: "+5511999999999",
  media: { url: "https://example.com/foto.jpg", caption: "Veja isto" },
});
```

### 维多

```ts
await bz.sendVideo({
  to: "+5511999999999",
  media: { url: "https://example.com/video.mp4", caption: "Demo" },
});
```

### 文档

```ts
await bz.sendDocument({
  to: "+5511999999999",
  media: {
    url: "https://example.com/contrato.pdf",
    filename: "contrato.pdf",
    mimetype: "application/pdf",
  },
});
```

### 阿乌迪奥(法语:Nota de voz com) `ptt`(中文(简体) )

```ts
await bz.sendAudio({
  to: "+5511999999999",
  media: { url: "https://example.com/audio.ogg", ptt: true },
});
```

### 贴纸

```ts
await bz.sendSticker({
  to: "+5511999999999",
  media: { url: "https://example.com/sticker.webp" },
});
```

> **弥陀曰:** 使用情况 `url` **尔** `base64`{\\fn黑体\\fs22\\bord1\\shad0\\3ahbe\\4ah00\\fscx67\\fscy66\\2chffffff\\3ch808080}那又怎样.

### 当地

```ts
await bz.sendLocation({
  to: "+5511999999999",
  latitude: -23.5613,
  longitude: -46.6565,
  name: "Av. Paulista",
  address: "São Paulo, SP",
});
```

### 康塔托( vCard) Name

```ts
await bz.sendContact({
  to: "+5511999999999",
  contact_name: "Suporte bZapper",
  // telefone DO CONTATO do cartão, não o destino
  contact_phone: "+5511977776666",
});
```

### 组合

```ts
await bz.sendPoll({
  to: "+5511999999999",
  name: "Qual seu plano?",
  options: ["Free", "Pro", "Enterprise"],
  selectable_count: 1,
});
```

### 目标

`quoted_message_id` {\\fn黑体\\fs22\\bord1\\shad0\\3ahbe\\4ah00\\fscx67\\fscy66\\2chffffff\\3ch808080}请说.

```ts
await bz.sendReaction({
  to: "+5511999999999",
  quoted_message_id: "WA_MESSAGE_ID",
  emoji: "👍",
});
```

### 瓶装

```ts
await bz.sendButtons({
  to: "+5511999999999",
  body: "Confirma o pedido?",
  footer: "bZapper",
  buttons: [
    { id: "yes", title: "Sim" },
    { id: "no", title: "Não" },
  ],
});
```

### 名单a

```ts
await bz.sendList({
  to: "+5511999999999",
  body: "Escolha uma opção",
  button_text: "Abrir menu",
  footer: "bZapper",
  sections: [
    {
      title: "Planos",
      rows: [
        { id: "pro", title: "Pro", description: "R$ 99/mês" },
        { id: "ent", title: "Enterprise", description: "Sob consulta" },
      ],
    },
  ],
});
```

> **卡维特·佩特里奥:** 单数 **圣孔菲亚韦斯** 无"什么"(por em grupos). API( API ) **启动** {\\fn华文仿宋\\fs16\\1chd1d1d1}嗯,嗯.. **文本数字菜单** {\\fn黑体\\fs22\\bord1\\shad0\\3ahbe\\4ah00\\fscx67\\fscy66\\2chffffff\\3ch808080}等等 {\\fn黑体\\fs22\\bord1\\shad0\\3ahbe\\4ah00\\fscx67\\fscy66\\2chffffff\\3ch808080}等等...

### Editar, apagar, encaminhar, marcar lido e agendaler 互联网档案馆的存檔,存档日期2013-12-21

```ts
await bz.editMessage(msg.message_id, { text: "Texto corrigido" });
await bz.revokeMessage(msg.message_id, { for_everyone: true });
await bz.forwardMessage({ instance_id: inst.id, to: "+5511988887777", from_chat: jid, wa_message_id: "3EB0…" });
await bz.markRead("3EB0…", { instance_id: inst.id, chat: jid });

// Qualquer envio aceita `scheduled_at` (RFC3339).
const s = await bz.sendText({ to: "+5511999999999", body: "Lembrete", scheduled_at: "2026-10-01T12:00:00Z" });
const { data: pending } = await bz.listScheduled({ limit: 50 });
await bz.cancelScheduled(s.scheduled_id!);
```

## 因斯通克(números)

```ts
const { data } = await bz.listInstances();

const inst = await bz.createInstance({
  phone: "+5511999999999",
  nickname: "Suporte",
  proxy_url: "http://user:pass@proxy.example:8080", // opcional
});

await bz.getInstance(inst.id);
const up = await bz.getInstanceUptime(inst.id); // up.windows["24h"] / ["7d"] / ["30d"] (null = sem histórico ainda), up.events

// Conexão por QR (default) ou código de pareamento.
const qr = await bz.connectInstance(inst.id, "qr");
console.log(qr.qr_code);

const code = await bz.connectInstance(inst.id, "code");
console.log(code.pair_code);

await bz.disconnectInstance(inst.id);
await bz.logoutInstance(inst.id);          // exige novo QR
await bz.clearInstanceSession(inst.id);    // pareamento travado: apaga a credencial do dispositivo

// Arquivar mantém o histórico; `archived: "1"` lista os arquivados.
await bz.archiveInstance(inst.id);
const archived = await bz.listInstances({ archived: "1" });
await bz.unarchiveInstance(inst.id);

// Rede, filtros de entrada e privacidade.
await bz.setInstanceProxy(inst.id, { proxy_url: "http://user:pass@proxy.example:8080" });
await bz.setInboundFilters(inst.id, { ignore_groups: true, ignore_status: true });
await bz.setPrivacy(inst.id, { setting: "last", value: "contacts" });

await bz.deleteInstance(inst.id); // encerra a sessão e remove
await bz.getHealth();             // { status: "ok", version }
```

### API 官方网站(WhatsApp Cloud API)

```ts
// Conexão: Embedded Signup (normal) ou credenciais manuais (phone_number_id opcional).
const { enabled, app_id, config_id } = await bz.getOfficialSignupConfig();
const { account, warning } = await bz.completeOfficialSignup({ code, waba_id: "…" });
await bz.connectOfficialAccount({ waba_id: "…", access_token: "…" });
const official = await bz.getOfficialAccount();
const { can_send, live } = await bz.getOfficialStatus(); // conferido ao vivo na Meta

// Vários números na mesma conta comercial.
const { numbers: available } = await bz.listAvailableOfficialNumbers();
const added = await bz.addOfficialNumber({ phone_number_id: available[0].id! });
const { numbers } = await bz.listOfficialNumbers(); // cada um com instance_id e is_default
await bz.setDefaultOfficialNumber(added.id!);
await bz.disconnectOfficialNumber(added.id!); // UM número; o histórico fica

// Perfil comercial (envie o perfil INTEIRO: campo vazio limpa na Meta).
const profile = await bz.getOfficialProfile();
await bz.updateOfficialProfile({ ...profile, about: "Atendimento 24/7" });
await bz.uploadOfficialProfilePhoto(await fileFromPath("./logo.png", "image/png"));
await bz.reregisterOfficialProfile(); // depois que a Meta aprova um nome novo
// Por número: getOfficialNumberProfile / updateOfficialNumberProfile /
// uploadOfficialNumberProfilePhoto / reregisterOfficialNumberProfile (id do número).

// Templates: validados ANTES de ir para a Meta; a decisão chega por webhook.
const { url } = await bz.uploadTemplateMedia(await fileFromPath("./amostra.png", "image/png"));
const { template, advice } = await bz.createTemplate({
  name: "pedido_enviado",
  language: "pt_BR",
  category: "UTILITY",
  header: { type: "image", media_url: url },
  body: { text: "Olá {{1}}, seu pedido {{2}} saiu para entrega.", example: ["Ana", "#123"] },
});
const { templates } = await bz.listTemplates();
await bz.syncTemplates(); // importa os que existem só na Meta
await bz.sendTemplate({ to: "+5511999999999", template: "pedido_enviado", variables: ["Ana", "#123"] });

// Alternativa: com a janela de 24h fechada, o sendText sai como este template
// e a resposta conta o desvio em `delivery` ({ via: "template_fallback", template, note }).
await bz.setFallbackTemplate({ template_id: template!.id });
const sent = await bz.sendText({ to: "+5511999999999", body: "Oi!" });
if (sent.delivery) console.log(sent.delivery.note);

await bz.disconnectOfficialAccount(); // TODOS os números
```

### 游泳池

```ts
const pool = await bz.createPool({ name: "Vendas", strategy: "health_weighted" });
await bz.addPoolNumber(pool.id, { instance_id: inst.id });
await bz.getPool(pool.id);
const { data: pools } = await bz.listPools();
await bz.sendText({ to: "+5511999999999", body: "Oi!", pool_id: pool.id });
```

### Perfil do número( 白色标签)

```ts
await bz.setProfile(inst.id, {
  display_name: "Suporte bZapper",
  status_message: "Atendimento 24/7",
  picture: "<base64>", // opcional
});
```

> `status_message` 联合会; `display_name` 电子 `picture` são experienceais (o servidor pode responseer) (英语: `501`) (中文(简体) ).

## 格鲁波斯语, 普森萨语 e conversas

作为歌剧 vançadas exigem um número específico。 说明o `instance_id` 发音:na **查询** (grups/conversas)你没有 **机构** (presença/chats/contatos)——o SDK já cuida disso pela Assinatura de cada método. 中国植物物种信息数据库.

### Presença (funciona em grupos!) (英语)

`to` 脚踏车,嗯 **JID 德克鲁波** ——"数字和"("digitalando")的索引 funciona em grupos.

```ts
// Presença num grupo
await bz.presenceChat({
  instance_id: inst.id,
  to: "120363000000000000@g.us", // JID de grupo
  state: "typing", // typing | recording | paused
});

// Também em 1:1
await bz.presenceChat({ instance_id: inst.id, to: "+5511999999999", state: "recording" });
```

### 对话( 插件)

```ts
const { data: threads } = await bz.listConversations(inst.id);

const history = await bz.conversationHistory("120363000000000000@g.us", {
  instance_id: inst.id,
  before: "2026-06-01T00:00:00Z", // opcional, RFC3339
  limit: 100,                     // opcional, ≤ 200
});

await bz.archiveChat("120363000000000000@g.us", { instance_id: inst.id, on: true });
await bz.pinChat("120363000000000000@g.us", { instance_id: inst.id, on: true });
await bz.markChat("120363000000000000@g.us", { instance_id: inst.id, on: true }); // lido
```

### 咕噜声

```ts
const { data: groups } = await bz.listGroups(inst.id);

const group = await bz.createGroup(inst.id, {
  name: "Equipe bZapper",
  participants: ["+5511988887777", "+5511977776666"],
});

await bz.getGroup(group.jid, inst.id);

await bz.updateGroupParticipants(group.jid, inst.id, {
  action: "promote", // add | remove | promote | demote
  participants: ["+5511988887777"],
});

const invite = await bz.groupInvite(group.jid, inst.id);
console.log(invite.invite_link);

await bz.previewGroupInvite(inst.id, { code: "AbCdEf123456" }); // nome/tamanho SEM entrar
await bz.joinGroup(inst.id, { code: "AbCdEf123456" });
await bz.leaveGroup(group.jid, inst.id);

await bz.updateGroup(group.jid, inst.id, { name: "Equipe", announce: true });
const fresh = await bz.groupInvite(group.jid, inst.id, { reset: true }); // revoga o link antigo
await bz.listJoinRequests(group.jid, inst.id);
await bz.updateJoinRequests(group.jid, inst.id, { participants: ["+5511988887777"], approve: true });
```

### 聊天、礼仪、礼仪

```ts
await bz.muteChat(jid, { instance_id: inst.id, on: true });
const label = await bz.createLabel({ instance_id: inst.id, name: "VIP" });
await bz.applyChatLabel(jid, { instance_id: inst.id, label_id: label.id!, apply: true });
await bz.listLabels(inst.id);
await bz.deleteLabel(label.id!, inst.id);

await bz.blockContact("5511988887777@s.whatsapp.net", { instance_id: inst.id });
await bz.getBlocklist(inst.id);
await bz.unblockContact("5511988887777@s.whatsapp.net", { instance_id: inst.id });

await bz.rejectCall({ instance_id: inst.id, call_from: "5511988887777@s.whatsapp.net", call_id: "…" });
```

### 孔塔多斯语Name

```ts
const { data } = await bz.contactsCheck({
  instance_id: inst.id,
  phones: ["+5511988887777", "+5511977776666"],
});
for (const c of data) console.log(c.query, c.in_whatsapp, c.jid);
```

### Base de contatos(CRM),标签,grupos e supressão

O vínculo contato Projeto/número é mantido) 互联网档案馆的存檔,存档日期2013-12-02 **自动降温** pela API; os filtros só leem. 中国植物物种信息数据库.

```ts
const page = await bz.listContacts({ tags: ["vip"], status: "active", has_email: true, limit: 50 });
const contact = await bz.createContact({ phone: "+5511988887777", name: "Ana", email: "ana@exemplo.com" });
await bz.updateContact(contact.id!, { address: { city: "São Paulo", state: "SP" } });
await bz.getContactHistory(contact.id!, { limit: 20 });
await bz.addContactNote(contact.id!, { body: "Pediu retorno à tarde" });

await bz.createTag({ key: "vip", name: "VIP" });
await bz.mutateContactTags(contact.id!, { add: ["vip"] });
await bz.createContactGroup({ key: "clientes", name: "Clientes" });
await bz.mutateContactGroups(contact.id!, { add: ["clientes"] });

await bz.optOutContact(contact.id!);   // LGPD
await bz.optInContact(contact.id!);
await bz.createSuppression({ phone: "+5511977776666", reason: "pediu" });
await bz.deleteSuppression("+5511977776666");
await bz.deleteContact(contact.id!);
```

#### 进口地块( E)`importContacts`(中文(简体) )

腾讯风,até **1000林纳** 鸡尾酒 林哈·鲁伊姆·瓦伊(Linha ruim vai para) `errors` 电子 **无** drruba o reso do lote; supresso/ opt-out/ 口述 平分 em `skipped_rows` (原始内容存档于2013-10-12). não resuscita. (原始内容存档于2018-09-29). Tags e grupos são criados sob requesta. 新的香肠 `pending_validation` (中文(简体) ) (原始内容存档于2013-10-12). otto- in antes de campanha.

```ts
const rows = [
  { phone: "+5511988887777", name: "Ana", email: "ana@exemplo.com", tags: ["vip"], groups: ["clientes"] },
  { phone: "+5511977776666", name: "Bruno", address: { city: "São Paulo", state: "SP" } },
];

const dry = await bz.importContacts({ contacts: rows, dry_run: true }); // valida, não escreve
if (dry.failed === 0) {
  const res = await bz.importContacts({ contacts: rows });
  console.log(res.created, res.updated, res.skipped, res.failed);
  for (const row of res.skipped_rows ?? []) console.warn(row.index, row.phone, row.reason);
}
```

#### 出口 em CSV (`exportContacts`(中文(简体) )

阿西塔奥斯 **膜膜** 页:1 `listContacts` (声) `offset`· ; `limit` o teto de linhas) e e e a 维基语录链接:名人名言 - 文学作品 - 谚语 (原始内容存档于2018-03-21) (英语). unica Rota da SDK que **jSON系统**页:1 **文本 CSV crus** (单位:千美元)`string`(原始内容存档于2018-09-21) (中文(简体) ) (b) 国家、领土、领土、领土和领土.

```ts
import { writeFile } from "node:fs/promises";

const csv = await bz.exportContacts({ tags: ["vip"], status: "active", limit: 50_000 });
await writeFile("contatos.csv", csv, "utf8");
// phone,name,email,status,source,tags,groups,created_at,last_activity_at
// +5511988887777,"Silva, Ana",ana@exemplo.com,active,import,vip;novo,clientes,2026-09-21T12:00:00Z,…
```

标记 e grupos vêm unidos por `;` e 作为数据em RFC 3339(UTC). (原始内容存档于2018-09-21) (英语). Campos com vírgula ou Aspas vêm escapados pelo paperão CSV——使用um parser de verdade se来再进口.

## 坎潘哈斯语Name

```ts
const camp = await bz.createCampaign({
  name: "Black Friday",
  pacing_profile: "conservative",
  variations: [{ body: "Oi {nome}! {Oferta|Promoção} só hoje." }],
});
await bz.addCampaignRecipients(camp.id, { contact_filter: { tags: ["vip"] } });
await bz.getCampaignEligibility();          // números aptos (conexão e tempo de conexão)
const dry = await bz.dryRunCampaign(camp.id);
console.log(dry.estimated_human, dry.warnings);
await bz.startCampaign(camp.id);
await bz.pauseCampaign(camp.id);
await bz.resumeCampaign(camp.id);

// Imagem de cabeçalho (multipart).
import { fileFromPath } from "@bzapper/client";
const { url } = await bz.uploadCampaignMedia(await fileFromPath("./banner.png", "image/png"));
```

## Projetos, marca, conta e usuários 互联网档案馆的存檔,存档日期2013-12-21

```ts
const proj = await bz.createProject({ name: "Loja 2" });
await bz.updateProject(proj.id, { name: "Loja SP", color: "#0a7" });
await bz.getProjectsHealth();                       // semáforo de números por projeto
await bz.setProjectBrand(proj.id, { about: "Atendimento Loja SP" });
await bz.uploadProjectLogo(proj.id, { content: bytes, filename: "logo.png", contentType: "image/png" });
await bz.uploadBrandLogo(await fileFromPath("./logo.png", "image/png"));

const me = await bz.getMe();
await bz.updateProfile({ name: "Ana", job_title: "Suporte" });
await bz.updateAccount({ name: "Minha Empresa" });
await bz.inviteUser({ email: "joao@exemplo.com", role: "agent" });
```

## Plano, 添加到e- faturas (英语)

```ts
const ent = await bz.getMyEntitlements();
await bz.upgradePlan();                               // Pro no carrinho
await bz.changeAddon({ kind: "number", delta: 2 });   // +2 números
const cart = await bz.getAddonCart();
const { client_secret } = await bz.checkoutAddonCart({ save_card: true });
const { data: invoices } = await bz.listMyInvoices();
await bz.getPricing();
```

## API 密钥( 自服务器)

```ts
const { data } = await bz.listKeys();

const created = await bz.createKey({ name: "CI", role: "agent" });
console.log(created.api_key); // guarde — mostrada só uma vez!

await bz.revokeKey(created.key.id);
```

### \* 部署`rotateKey`(中文(简体) )

`rotateKey` 克里亚·马沙夫 **诺瓦** (赫尔达·帕佩尔、埃斯科波斯、诺梅) **反藻类** (原始内容存档于2018-03-25) (英语). funcionando por um período de carência - padrão 24 h, máximo 30 dias, `0` (原始内容存档于2013-10-12). Revoga na hora. 二级a rova, roque o segredo onde a integração roda, e a antga morre sozinha (depois do prazo ela) 互联网档案馆的存檔,存档日期2013-12-02 响应 `401 key_expired`) (中文(简体) ). Só admin; a chave crua vem uma única vez. 中国植物物种信息数据库.

```ts
const rot = await bz.rotateKey(keyId, { revoke_in_seconds: 3600 }); // 1h de carência
console.log(rot.api_key);              // guarde — mostrada só uma vez!
console.log(rot.old_key_expires_at);   // quando a antiga para (null = revogada na hora)
console.log(rot.previous_key?.rotated_to === rot.key.id); // true
```

(bZapper Connection) 转接站 `partner.rotateConnectionKey`。 。 。 .

## 网络呼号

**格伦西** 网路上的相片:

```ts
const hook = await bz.createWebhook({
  url: "https://seuapp.com/webhooks/bzapper",
  event_types: ["message.received", "instance.banned"], // omita = todos os eventos
});
console.log(hook.secret); // segredo de assinatura — devolvido UMA vez, guarde agora

await bz.listWebhooks();
await bz.updateWebhook(hook.id, { active: false });        // pausar
await bz.updateWebhook(hook.id, { secret: "regenerate" }); // rotacionar segredo
await bz.deleteWebhook(hook.id);
```

**Receba e 处理e** 作为谷类 `Webhooks` assinatura HMAC, 维基百科中的相关条目: 活塞活塞, e. even to tipado e roteia para seus 处理器(零) 依赖; usa o `crypto` nativo do 节点 :

```ts
import { Webhooks } from "@bzapper/client";

const hooks = new Webhooks(process.env.BZAPPER_WEBHOOK_SECRET!); // o secret do createWebhook

hooks.on("message.received", (event) => {
  console.log(event.sender?.name, event.payload.body);
});

hooks.on("instance.banned", (event) => {
  alert(event.instanceId);
});

// No seu endpoint HTTP. Passe o corpo CRU e o header X-Bzapper-Signature.
// Lança WebhookSignatureError se a assinatura for inválida — não processe nesse caso.
await hooks.handle(rawBody, signature);
```

欧 `event` tipado tem 电话 `id`, (中文(简体) ), `type`, (中文(简体) ), `timestamp`, (中文(简体) ), `instanceId`, (中文(简体) ), `clientReference`, (中文(简体) ), `group`, (中文(简体) ), `sender`, (中文(简体) ), `mentions`, (中文(简体) ), `payload` e 个 `raw` 原文 (JSON做信封,EM蛇 case). 使用 `event.id` a API pode) 互联网档案馆的存檔,存档日期2013-12-02 (原始内容存档于2018-10-21). Reentregar. {\\fn黑体\\fs22\\bord1\\shad0\\3aHBE\\4aH00\\fscx67\\fscy66\\2cHFFFFFF\\3cH808080}我们的新浪微博 `verifyWebhook(secret, rawBody, signature)` 电子 `constructWebhookEvent(secret, rawBody, signature)`。 。 。 .

### 快递

`Webhooks#middleware()` 调出 um 中间软件 Estilo Express。 伊莱·普里西萨 **铜屑**,该寺 `express.raw()` 旋转正弦 `req.body` {\\fn黑体\\fs22\\bord1\\shad0\\3ahbe\\4ah00\\fscx67\\fscy66\\2chffffff\\3ch808080}嗯 谢佳 嗯 `Buffer` (法语:não um objeto ja parseado):

```ts
import express from "express";
import { Webhooks } from "@bzapper/client";

const app = express();
const hooks = new Webhooks(process.env.BZAPPER_WEBHOOK_SECRET!);

hooks.on("message.received", (e) => console.log(e.payload.body));

app.post(
  "/webhooks/bzapper",
  express.raw({ type: "application/json" }), // entrega req.body como Buffer cru
  hooks.middleware(),                        // verifica, dispara e responde 200/400
);

app.listen(3000);
```

### 无本地主机( T)`bzapper listen`(中文(简体) )

哦,帕科特特特车,嗯,执行。 URL pública Nenhuma, ele abre o 溪流 事件 e **本地服务中心**时,屁股 igualzinho à produção(无埃斯皮里多) `stripe listen`:

```bash
npx @bzapper/client listen --forward-to http://localhost:3000/webhooks/bzapper
```

```
bZapper v0.16.0 — relay de webhooks para o localhost
  ouvindo    https://api.bzapper.com.br/webhooks/listen
  reenviando http://localhost:3000/webhooks/bzapper
  secret     whsec_Hs3…

✓ conectado ao stream de eventos. Ctrl+C para sair.

14:02:11  message.received           evt_01HZX…  →  200 12ms
14:02:19  message.sent               evt_01HZY…  →  500 8ms
```

| 页:1 |  |
| --- | --- |
| `-f`, (中文(简体) ), `--forward-to <url>` | URL 本地 que recebe os POSTs (obrigatória, salvo com) (英语) `--print-only`(中文(简体) ) |
| `--api-key <key>` | 键 `bz_live_…`页:1 `$BZAPPER_API_KEY` |
| `--base-url <url>` | 基础 da API; 父版 `$BZAPPER_BASE_URL` {\\fn黑体\\fs22\\bord1\\shad0\\3ahbe\\4ah00\\fscx67\\fscy66\\2chffffff\\3ch808080}你为我辩护 |
| `--project <id>` | 塞西昂-塞西昂-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁-塞西翁 |
| `--events <a,b,c>` | só estes tipos (前: `message.received,message.sent`(中文(简体) ) |
| `--secret <whsec_…>` | segredo de assinatura; padrão: um novo, 有印象的动画 |
| `--print-only` | 不,不,不,不,不,不,不 |
| `--help`, (中文(简体) ), `--version` |  |

**网络地图**: o stream esppelha (英语: **待办事宜** 连做 猪笼草(projeto, exista ou nuão uma assinatura)——由牛笼草(justamente o modo de senvolver antes)组成 de ter URL pública. 互联网档案馆的存檔,存档日期2014-12-02. 密钥无信头 `Authorization`尼尼卡纳URL.

卡达 POST 列瓦 Os **mesmos headers da produção 互联网档案馆的存檔,存档日期2013-10-02** —— 说 `X-Bzapper-Signature: sha256=<hmac do corpo cru>`, (中文(简体) ), `X-Bzapper-Event-Id`, (中文(简体) ), `X-Bzapper-Event-Type` 电子 `Content-Type: application/json` ——,腾讯 `Webhooks` 中继代码 有效参数 a bZapper :

```ts
const hooks = new Webhooks(process.env.BZAPPER_WEBHOOK_SECRET!); // o secret que a CLI imprimiu
```

> ⚠️ **哦,秘密的,诺索.** 萨姆 `--secret`一个CLI Gera um na hora e o (原始内容存档于2012-10-12) (英语). primate: use-o no sue app durante o teste. Assinatura Prova que o POST veio (英语) **脱去CLI**, não da b Zapper—— la vale exatamente o que o secret vale. 中国植物物种信息数据库. 额 秘密 o do webhook cadastrado (英语:`createWebhook`) (中文(简体) ).

背对一个部分 `retry` 对 (一) 服务员; `Ctrl+C` {\\fn黑体\\fs22\\bord1\\shad0\\3aHBE\\4aH00\\fscx67\\fscy66\\2cHFFFFFF\\3cH808080}哦! {\\fn黑体\\fs22\\bord1\\shad0\\3aHBE\\4aH00\\fscx67\\fscy66\\2cHFFFFFF\\3cH808080}哦! Credencial 回避 (原始内容存档于2018-03-21). encerra na hora, com código de saida diferente de 0.

## b Zapper 连接

段落 **软件**(原始内容存档于2018-03-26) (英语). o seu produto deixa os SEUS clients assinarem o bZapper Pro e conectarem o WhatsApp sem sair dele, e recebe uma API 键 (单位:千美元)`bz_live_...`自动服务员 {\\fn黑体\\fs22\\bord1\\shad0\\3aHBE\\4aH00\\fscx67\\fscy66\\2cHFFFFFF\\3cH808080}哦 客户 {\\fn黑体\\fs22\\bord1\\shad0\\3aHBE\\4aH00\\fscx67\\fscy66\\2cHFFFFFF\\3cH808080}哦 bZapper serrata; a conexão só funciona enquanto o Pro dele estivers pago. 中国植物物种信息数据库.

O通量:

1.  苏 **后端** (cria uma sessão com o partners (cria uma sessão com com o partners secret)) 秘密合作(cria uma sessão com com o partners 秘密合作) 秘密合作(cria uma sessão com com o 伙伴合作(c`bz_partner_...`) (中文(简体) ).
2.  苏 **前面** abre 组件 com `session_token`。 。 。 .
3.  Ao concluir (Pro pago + número conectado), 构件 emite um 等 `code` (10分钟).
4.  Seu 后端为 troca o `code` pela API 密钥用于客户端 e guarda 密钥 .
5.  Dali em diante , 请使用 `Bzapper` 普通的相机 essa 密钥.

> O 搭档秘密 e **só de 后端** ——"无所事事"("dunica o mande par o navegador").

### 后端( Express)

```ts
import express from "express";
import {
  Bzapper,
  BzapperError,
  BzapperPartner,
  Webhooks,
  isConnectEvent,
  type PartnerWebhookEvent,
} from "@bzapper/client";

const app = express();
const partner = new BzapperPartner({ partnerSecret: process.env.BZAPPER_PARTNER_SECRET! });

// 1) Cria a sessão do componente para o cliente logado no SEU produto.
app.post("/bzapper/session", express.json(), async (req, res) => {
  const user = req.user; // seu usuário autenticado
  const session = await partner.createConnectSession({
    external_id: user.id, // o id do cliente no SEU sistema (mesmo id = mesma conexão)
    customer: {
      name: user.name,
      email: user.email,
      phone: user.phone,     // opcional, E.164 — pré-preenche o número
      company: user.company, // opcional — vira o nome da conta/projeto
      country: "BR",         // opcional — define a moeda
    },
    locale: "pt-BR",
  });
  res.json({ session: session.session_token });
});

// 2) Troca o code emitido pelo componente pela API key do cliente.
app.post("/bzapper/exchange", express.json(), async (req, res) => {
  const connection = await partner.exchangeCode(req.body.code);
  // Guarde agora — a key não é mostrada de novo (use rotateConnectionKey se perder).
  await db.saveBzapperKey(connection.external_id, connection.id, connection.api_key);
  res.json({ status: connection.status });
});

// 3) Webhook do parceiro: mesma assinatura HMAC (X-Bzapper-Signature) dos webhooks
//    normais, com o segredo do webhook do parceiro. Toda entrega traz `connection`.
const hooks = new Webhooks(process.env.BZAPPER_PARTNER_WEBHOOK_SECRET!);

hooks.onAny(async (event) => {
  if (!isConnectEvent(event)) return; // mensagens/status dos números também chegam aqui
  const { connection } = event as PartnerWebhookEvent;
  switch (event.type) {
    case "connect.completed":
    case "connect.resumed":
      await db.setBzapperStatus(connection.externalId, "active");
      break;
    case "connect.suspended": // Pro do cliente sem pagamento — volta sozinho ao pagar
      await db.setBzapperStatus(connection.externalId, "suspended");
      break;
    case "connect.revoked": // encerrada — a key não vale mais
      await db.deleteBzapperKey(connection.externalId);
      break;
  }
});

app.post(
  "/webhooks/bzapper-partner",
  express.raw({ type: "application/json" }), // corpo CRU, obrigatório para a assinatura
  hooks.middleware(),
);

// 4) Usando a key do cliente: trate a suspensão (402) e a revogação (401).
app.post("/avisar", express.json(), async (req, res) => {
  const bz = new Bzapper({ apiKey: await db.getBzapperKey(req.user.id) });
  try {
    await bz.sendText({ to: req.body.to, body: req.body.text });
    res.sendStatus(202);
  } catch (err) {
    if (err instanceof BzapperError && err.code === "connect_suspended") {
      // 402: o Pro do cliente está sem pagamento. Peça para ele regularizar.
      return res.status(402).json({ error: "Regularize sua assinatura do bZapper." });
    }
    if (err instanceof BzapperError && err.code === "connect_revoked") {
      // 401: a conexão acabou. Ofereça conectar de novo (nova sessão).
      return res.status(409).json({ error: "Conecte o WhatsApp novamente." });
    }
    throw err;
  }
});

app.listen(3000);
```

### 前线

```html
<script src="https://widget.bzapper.com.br/v1/connect.js"></script>
<script>
  async function conectarWhatsApp() {
    const { session } = await fetch("/bzapper/session", { method: "POST" }).then((r) => r.json());

    BzapperConnect.open({
      session,
      onComplete: ({ code }) =>
        fetch("/bzapper/exchange", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ code }),
        }),
    });
  }
</script>
```

### 激素锥形

```ts
const me = await partner.me(); // de quem é o partner secret

const { data } = await partner.listConnections({ status: "suspended" }); // ou { external_id }
const conn = await partner.getConnection(data[0].id); // status, conta, números

const rotated = await partner.rotateConnectionKey(conn.id); // nova key; a anterior para de valer
console.log(rotated.api_key);

await partner.revokeConnection(conn.id); // revoga a key (NÃO cancela o plano do cliente)
```

埃斯塔多斯·达孔克桑(Estados da Conexão)`status`: `pending_account`, (中文(简体) ), `pending_payment`, (中文(简体) ), `pending_number`, (中文(简体) ), `active`, (中文(简体) ), `suspended` 电子 `revoked`. eventos entlegues ao webhook (英语) 做小说: `connect.completed`, (中文(简体) ), `connect.suspended`, (中文(简体) ), `connect.resumed` 电子 `connect.revoked` (名单 `CONNECT_EVENT_TYPES`)),"活"(além dos eventos oldais),"活"(活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活"活 (原始内容存档于2018-09-30). dos números das conexõs antives. 欧 `event.connection` 调试 `id`, (中文(简体) ), `externalId`, (中文(简体) ), `accountId`, (中文(简体) ), `projectId` 电子 `status`。 。 。 .

### Lado do客户端 : apps conectados

API key da própria conta, o cliente vê e desconecta os parceiros: 互联网档案馆的存檔,存档日期2011-12-04

```ts
const { data: apps } = await bz.listConnectedApps(); // com partner_name / partner_logo_url
await bz.revokeConnectedApp(apps[0].id);             // admin; a key do parceiro para na hora
```

### Conector de IA (多功能软件公司)

Apps de IA (前: Claude) que uma pessoa autorizou a operator a conta pelo conector MCP: 水晶相机: 水晶相机:

```ts
const { data: conns } = await bz.listAIConnections(); // client_name, user_email, user_role, scopes, last_used_at
await bz.revokeAIConnection(conns[0].id);             // os tokens dele param na próxima chamada
```

## 乌苏

```ts
const usage = await bz.getUsage({
  from: "2026-06-01T00:00:00Z",
  to: "2026-06-30T23:59:59Z",
});
console.log(usage.total, usage.delivery_rate);
```

## 诺瓦斯山地帐篷

Em qualquer resposta não-2xx o SDK lança (英语) `BzapperError` (ou uma sub classe.) (中文(简体) ). **拉米菲克铸币局 皮罗 `code`** (stável),尼尼卡·皮洛(英语: `message` (文本为traduzido).

| 状态 | 类 |  |
| --- | --- | --- |
| 400,422 (中文(简体) ) | `ValidationError` | 铜矿/铜矿 |
| 401 (中文(简体) ) | `AuthenticationError` | 密钥 inválida/ revogada(重排)`connect_revoked`(中文(简体) ) |
| 403 (韩语) | `PermissionDeniedError` | `requiredScope` diz o escopo que faltou (法语) |
| 404 (韩语) | `NotFoundError` |  |
| 409个 | `ConflictError` | 实例: `not_connected`, (中文(简体) ), `idempotency_in_progress` |
| 429个 | `RateLimitError` | `retryAfter` 自动交换 |
| 5 (简体中文) | `ServerError` |  |
| sem reposta (中文(简体) ) | `NetworkError` | `status = 0`, (中文(简体) ), `code = "NETWORK_ERROR"` |
| (前402页) | `BzapperError` | 实例: `connect_suspended` |

托达斯牧民 `BzapperError`缩写: `code`, (中文(简体) ), `message`, (中文(简体) ), `status` (= (单位:千美元) `statusCode`, (中文(简体) ), `locale`, (中文(简体) ), `requestId` (通知ao suporte),(请回答), `retryAfter`, (中文(简体) ), `requiredScope` 电子 `body` (公司解码器). 2xxx que não é JSON vira (英语) `code = "INVALID_RESPONSE"`. . . . . , `"."` 尔 `".."` 总统府 `TypeError` (原始内容存档于2018-03-26). antes de qualquer requisição.

```ts
import { Bzapper, BzapperError, RateLimitError } from "@bzapper/client";

try {
  await bz.sendText({ to: "+5511999999999", body: "Olá!" });
} catch (err) {
  if (err instanceof RateLimitError) {
    console.error(`aguarde ${err.retryAfter}s`);
  } else if (err instanceof BzapperError) {
    console.error(err.code, err.status, err.requestId); // ex.: "not_connected" 409 "a1b2…"
    // Key de bZapper Connect: "connect_suspended" (402) e "connect_revoked" (401).
  } else {
    throw err;
  }
}
```

**诺瓦斯帐篷:** (原始内容存档于2012-10-12) (英语). SDK tenta de novo sozinho em wrongo de rede/time out, `429`, (中文(简体) ), `502`, (中文(简体) ), `503` 电子 `504` (nada mais——嗯) `500` 尔 `4xx` (原始内容存档于2018-09-21). volta na hora, até `maxRetries` 韦兹(padrão 2),埃斯佩兰多o `Retry-After` (计到60分) `min(8, 0,5 × 2^n)` s + 25% de jitter.

**同上:** (POST/PUT/PATCH/DELETE) (波兰语) `Idempotency-Key` 盖拉多波尔 沙玛达e **重复** 鼻涕虫 `X-Request-Id`)——一个API递出一个mesma 重新定义歌剧`Idempotent-Replayed: true`) (中文(简体) ). 龙卷风再现 接通地铁站:

```ts
await bz.sendText({ to: "+5511999999999", body: "Pedido #42 confirmado" }, { idempotencyKey: "pedido-42" });
await bz.createContact({ phone: "+5511999999999" }, { idempotencyKey: "crm-import-42" });
```

## 实例

韦雅 [`examples/quickstart.ts`](https://npmcn.com/package/%40bzapper/client/examples/quickstart.ts)。 。 。 .

## 语法

麻省理工学院伯尼软件

## 常见问题

### @bzapper/client 是什么？

SDK official do bZapper para Node/TypeScript——网关德WhatsApp多租户\.

### 如何安装 @bzapper/client？

在项目目录运行 npm install @bzapper/client，或使用 pnpm add / yarn add / bun add。它还提供命令行工具 bzapper，可以用 npx bzapper 直接运行。

### @bzapper/client 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @bzapper/client 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @bzapper/client 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=18。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @bzapper/client 可以商用吗？

@bzapper/client 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @bzapper/client 的下载量有多少？

根据 npm 官方下载统计，@bzapper/client 在 2026/10/09 – 2026/11/07 这 30 天内被下载 2,376 次，日均约 79 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @bzapper/client 还在维护吗？

最新版本 0\.16\.0 发布于 2026/10/21（18 天前）；至今共发布 27 个版本，其中过去 12 个月发布了 27 个；首次发布于 2026/06/26。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

