본문 바로가기
文档菜单

JavaScript / TypeScript / SDK REFERENCE

Node.js SDK 指南

用于发送 Kakao 通知消息、好友消息、品牌消息与 SMS 的官方 Node.js SDK —— 完整 TypeScript 类型,零运行时依赖。

이 문서의 목차
패키지
@sendgo/node
언어
JavaScript / TypeScript
레지스트리
npm
설치
npm install @sendgo/node

用于发送 Kakao 通知消息、品牌消息与短信的官方 Node.js SDK

@sendgo/node 是不依赖任何框架的核心客户端,附带完整的 TypeScript 类型定义。React、Vue、NestJS 扩展包都构建在它之上。

要求 Node.js 18 及以上(内部使用原生 fetch)。


安装

npm install @sendgo/node

快速上手

import Sendgo from '@sendgo/node';

const sendgo = new Sendgo({
  accessKey: process.env.SENDGO_ACCESS_KEY!,
  secretKey: process.env.SENDGO_SECRET_KEY!,
  kakaoSenderKey: process.env.SENDGO_KAKAO_SENDER_KEY,
  smsSenderKey: process.env.SENDGO_SMS_SENDER_KEY,
  apiVersion: 'v2',
});

await sendgo.alimtalk.send({
  templateCode: 'ORDER_CONFIRM_001',
  contacts: [{ contact: '01012345678', name: '洪吉童', var1: 'ORD-001' }],
});

各发送渠道都是客户端上的属性:

属性 渠道
sendgo.alimtalk Kakao 通知消息
sendgo.friendtalk Kakao 好友消息
sendgo.brandMessage Kakao 品牌消息(仅 v2)
sendgo.sms SMS / LMS / MMS

仅限服务端使用。 访问密钥与私密密钥绝不可打包进浏览器。请只在 Node 进程中创建客户端。

请在模块作用域创建一次客户端并复用,令牌缓存才能跨请求生效;每次请求都 new Sendgo(...) 会导致每次都重新签发令牌。


通知消息

// 批量发送
await sendgo.alimtalk.send({
  templateCode: 'ORDER_CONFIRM_001',
  contacts: [
    { contact: '01011111111', var1: 'ORD-001', var2: '29,000元' },
    { contact: '01022222222', var1: 'ORD-002', var2: '15,000元' },
  ],
});

// 预约发送
await sendgo.alimtalk.send({
  templateCode: 'PROMO_SUMMER_2026',
  scheduleType: 'SCHEDULED',
  at: '2026-07-28 09:00:00',
  contacts: [{ contact: '01012345678', var1: '夏季限定 5 折' }],
});

// 失败时自动回退为短信
await sendgo.alimtalk.send({
  templateCode: 'DELIVERY_START_001',
  replaceSms: 'Y',
  smsSubject: '[发货通知]',
  smsContent: '您购买的商品已出库。',
  contacts: [{ contact: '01012345678', var1: 'ORD-001' }],
});

好友消息

⚠️ 已停用 —— 按 Kakao 政策,好友消息已于 2025-12-31 停止服务。 自 2026-01-01 起,好友消息的发送请求由 Kakao 侧自动改以**品牌消息(自由形式)**发出。 调用仍会成功;而且自由文本类型(FT/FI/FW)发往单个接收者的路径目前仍只有这一条, 因此现有代码无需立即改动。

以下情形请改用品牌消息:

  • 基于模板的富文本类型(FL/FC/FM/FP/FA)
  • 非频道好友的接收者(targeting = N / I)
  • 向已同意接收的全部频道好友群发(targeting = F)

消息类型一一对应,转换由服务端处理 —— FT→BT、FI→BI、FW→BW、FL→BL、 FC→BC、FM→BM、FP→BP、FA→BA。

// 文本型
await sendgo.friendtalk.send({
  content: '7 月限时特惠开始了,欢迎查看。',
  contacts: [{ contact: '01012345678' }],
});

// 图片型
await sendgo.friendtalk.send({
  messageType: 'FI',
  content: '本周特价商品',
  imageUrl: 'https://cdn.example.com/banner.jpg',
  imageLink: 'https://example.com/event',
  contacts: [{ contact: '01012345678' }],
});

品牌消息

品牌消息是好友消息的后继渠道:可触达非频道好友的接收者(targeting: 'N'),也可向已同意接收的全部频道好友群发(targeting: 'F')。消息类型与好友消息一一对应(FT→BT、FI→BI、FW→BW、FL→BL、FC→BC、FM→BM、FP→BP、FA→BA)—— 传入好友消息的代码,服务端会自动转换。

仅 v2 支持。请设置 apiVersion: 'v2'。

// 单条发送 —— targeting 为 M/N/I 时必须提供 contacts
await sendgo.brandMessage.send({
  targeting: 'M',
  messageType: 'FL',
  friendTemplateUuid: '9cd5460b-6458-4edc-9b11-c26d3013c340',
  contacts: [{ contact: '01012345678', var1: '29,000元' }],
});

// 群发 —— 已同意接收的全部频道好友(不传接收者列表)
const result = await sendgo.brandMessage.broadcast({
  messageType: 'FW',
  friendTemplateUuid: '9cd5460b-6458-4edc-9b11-c26d3013c340',
});

// 群发在上游为异步处理,需轮询查看进度
await sendgo.brandMessage.campaign(result.data.campaignId);
await sendgo.brandMessage.campaigns({ from: '2026-08-01', count: 10 });

targeting 的取值含义:

值 含义
M 频道好友中的指定接收者
N 非频道好友的接收者
I 按标识符指定的接收者
F 已同意接收的全部频道好友(群发)

短信 / 长短信 / 多媒体短信

// SMS(90 字节以内)
await sendgo.sms.sendSms({
  content: '[Sendgo] 验证码:123456(请在 5 分钟内输入)',
  contacts: [{ contact: '01012345678' }],
});

// LMS(长文,2,000 字节以内)
await sendgo.sms.sendLms({
  subject: '[重要] 服务维护通知',
  content: '服务将于 2026-07-25 02:00 ~ 06:00 进行维护。',
  contacts: [{ contact: '01012345678' }],
});

// MMS(含图片)
await sendgo.sms.sendMms({
  subject: '[活动] 7 月特惠',
  content: '欢迎查看本月特价商品。',
  contacts: [{ contact: '01012345678' }],
});

错误处理

import { SendgoError } from '@sendgo/node';

try {
  await sendgo.alimtalk.send({ /* ... */ });
} catch (error) {
  if (!(error instanceof SendgoError)) throw error;

  console.error(`Sendgo ${error.statusCode} [${error.errorCode}]: ${error.message}`);

  switch (error.errorCode) {
    case 'INVALID_ACCESS_KEY':
    case 'INVALID_SECRET_KEY':
      // 是我们的配置有误,而非调用方的请求有误。
      alertOps('请检查 Sendgo 密钥');
      break;
    case 'IP_NOT_ALLOWED':
      alertOps('该 IP 未在白名单中');
      break;
    case 'PAYMENT_REQUIRED':
      alertOps('Sendgo 余额不足');
      break;
    default:
      // 5xx 为临时故障,可重试;4xx 重试不会成功。
      if (error.statusCode >= 500) throw error;
  }
}

请根据 errorCode 分支,而不要匹配错误消息文本 —— 消息文案可能变更,错误代码才是契约。 TOKEN_EXPIRED 与 TOKEN_MISMATCH 已在 SDK 内部处理:会重新签发令牌并自动重试该请求一次。


TypeScript 类型

import type {
  AlimtalkParams,
  FriendtalkParams,
  BrandMessageParams,
  BrandMessageListParams,
  BrandMessageTargeting,
  SmsParams,
  Contact,
  SendgoConfig,
  SendgoResponse,
} from '@sendgo/node';

Sendgo(客户端类)与 SendgoError 以值的形式导出,而非仅类型。


配置项

键 是否必填 默认值 说明
accessKey 必填 — Sendgo 访问密钥
secretKey 必填 — Sendgo 私密密钥
kakaoSenderKey 选填 undefined Kakao 发送者资料密钥
smsSenderKey 选填 undefined 短信主叫号码密钥
apiVersion 选填 v1 API 版本(v1 | v2)
baseUrl 选填 https://sendgo.io API 基础地址

短链接

短链接会缩短消息正文中的链接,并统计该链接是否被真正点击。 短信按字节计费,因此链接更短就意味着正文可以写更多内容。

仅 v2 支持。

再次缩短同一个原始 URL 会直接返回已有的链接。若希望按活动分别统计反应, 请使用 forceNew 生成新的短码。

deactivate 不会删除链接,只停止重定向。当已发送消息中的链接必须失效时使用它; 累计统计会保留,访问已停止的链接会返回 410 Gone。

const created = await sendgo.shortUrl.create({
  targetUrl: 'https://example.com/promotions/summer-sale',
  title: '夏季促销落地页',
});

const { code, shortUrl } = created.data;

// 反应统计 —— 按日趋势 + 设备/来源/国家分解
const stats = await sendgo.shortUrl.stats(code, { from: '2026-08-01' });

await sendgo.shortUrl.list({ count: 10 });
await sendgo.shortUrl.show(code);
await sendgo.shortUrl.deactivate(code);   // 仅停止重定向,统计保留

stats 返回按日趋势(daily)以及按设备(byDevice)、来源(byReferer)、国家(byCountry)的分解。按日趋势读取的是预聚合表,因此点击量再大响应时间也保持稳定。


包信息

  • 包名:@sendgo/node(npm)
  • 仓库:send-go/node
  • 注册表:https://www.npmjs.com/package/@sendgo/node
  • 许可:MIT

如何获取 API 密钥

登录 Sendgo 后,在 API/SDK → API 对接 菜单中签发访问密钥与私密密钥。 使用通知消息/好友消息需在 Kakao 渠道 登记发送者资料以获取 kakaoSenderKey;使用短信需在 发送号码 菜单登记主叫号码。

이 패키지로 할 수 있는 것

관련 패키지

专注构建,消息交给 Sendgo。返回顶部 ↑