文档菜单
JavaScript / TypeScript / SDK REFERENCE
React / Next.js SDK 指南
用于从 Next.js Server Action 与 Route Handler 发送 Kakao 通知消息、好友消息、品牌消息与 SMS 的官方 React SDK —— 仅限服务端。
이 문서의 목차
- 패키지
- @sendgo/react
- 언어
- JavaScript / TypeScript
- 레지스트리
- npm
npm install @sendgo/react用于从 Next.js 服务端发送 Kakao 通知消息、品牌消息与短信的官方 React SDK
@sendgo/react 把 @sendgo/node 核心包装为服务端函数(可用作 Server Action 或在 Route Handler 中调用),并附带一个用于调用你自己接口的客户端 Hook。
⚠️ 仅限服务端使用。 访问密钥与私密密钥绝不可进入浏览器。请只在带
'use server'的文件、Route Handler 或其他 Node 环境中调用发送函数。若把它们导入客户端组件,密钥就会被打进客户端 bundle。
安装
npm install @sendgo/react
核心 @sendgo/node 会作为依赖一并安装。
配置
发送函数直接读取环境变量,因此无需在代码里初始化:
# .env.local
SENDGO_ACCESS_KEY=your_access_key
SENDGO_SECRET_KEY=your_secret_key
SENDGO_KAKAO_SENDER_KEY=your_kakao_sender_key
SENDGO_SMS_SENDER_KEY=your_sms_sender_key
SENDGO_API_VERSION=v2
变量名不要加 NEXT_PUBLIC_ 前缀 —— 那会把密钥暴露给浏览器。
SENDGO_API_VERSION 未设置时默认为 v1;品牌消息需要 v2。
Server Action
// app/actions/notify.ts
'use server';
import { sendAlimtalk, SendgoError } from '@sendgo/react';
export async function notifyOrderConfirmed(phone: string, orderNo: string) {
try {
await sendAlimtalk({
templateCode: 'ORDER_CONFIRM_001',
contacts: [{ contact: phone, var1: orderNo }],
});
return { ok: true as const };
} catch (error) {
if (error instanceof SendgoError) {
// 上游细节记录到日志,返回给客户端的信息保持通用。
console.error(`Sendgo ${error.statusCode} [${error.errorCode}]: ${error.message}`);
return { ok: false as const, error: '消息发送失败' };
}
throw error;
}
}
返回结构化结果而不是直接抛出:Server Action 抛出的异常在生产构建下会变成不带信息的通用错误。
可用的服务端函数:
| 函数 | 渠道 |
|---|---|
sendAlimtalk |
Kakao 通知消息 |
sendFriendtalk |
Kakao 好友消息 |
sendBrandMessage / broadcastBrandMessage |
Kakao 品牌消息(仅 v2) |
listBrandMessages / getBrandMessage |
品牌消息活动查询 |
sendSms / sendLms / sendMms |
SMS / LMS / MMS |
createSendgoClient |
需要完整核心客户端时使用 |
Route Handler
// app/api/notify/route.ts
import { NextResponse } from 'next/server';
import { sendAlimtalk, SendgoError } from '@sendgo/react';
export async function POST(request: Request) {
const { phone, orderNo } = await request.json();
try {
await sendAlimtalk({
templateCode: 'ORDER_CONFIRM_001',
contacts: [{ contact: phone, var1: orderNo }],
});
return NextResponse.json({ ok: true }, { status: 202 });
} catch (error) {
if (error instanceof SendgoError) {
console.error(`Sendgo ${error.statusCode} [${error.errorCode}]: ${error.message}`);
// 5xx 是上游问题,4xx 是请求问题。
return NextResponse.json(
{ error: error.errorCode },
{ status: error.statusCode >= 500 ? 502 : 400 },
);
}
throw error;
}
}
品牌消息
好友消息已于 2025-12-31 停止服务。 自 2026-01-01 起,Kakao 会将好友消息请求 自动改以品牌消息(自由形式)发出。
friendtalk仍可调用,且自由文本类型FT/FI/FW发往单个接收者的路径目前仍只有这一条 —— 基于模板的富文本类型 (FL/FC/FM/FP/FA)、非好友定向(N/I)与群发(F)请使用品牌消息。 品牌消息是好友消息的后继渠道:可触达非频道好友的接收者(targeting: 'N'),也可向已同意接收的全部频道好友群发(targeting: 'F')。消息类型与好友消息一一对应(FT→BT、FI→BI、FW→BW、FL→BL、FC→BC、FM→BM、FP→BP、FA→BA)—— 传入好友消息的代码,服务端会自动转换。
仅 v2 支持。请设置
SENDGO_API_VERSION=v2。
// app/actions/campaign.ts
'use server';
import {
sendBrandMessage,
broadcastBrandMessage,
listBrandMessages,
getBrandMessage,
} from '@sendgo/react';
// 单条发送 —— targeting 为 M/N/I 时必须提供 contacts
export async function promote(phone: string) {
return sendBrandMessage({
targeting: 'M',
messageType: 'FL',
friendTemplateUuid: '9cd5460b-6458-4edc-9b11-c26d3013c340',
contacts: [{ contact: phone, var1: '29,000元' }],
});
}
// 群发 —— 已同意接收的全部频道好友(不传 contacts)
export async function announce() {
return broadcastBrandMessage({
messageType: 'FW',
friendTemplateUuid: '9cd5460b-6458-4edc-9b11-c26d3013c340',
});
}
// 群发在上游为异步处理,需轮询查看进度
export async function status(campaignId: string) {
return getBrandMessage(campaignId);
}
export async function recent() {
return listBrandMessages({ count: 10 });
}
群发可能触达你的整个好友列表。请在 Server Action 内先做权限校验 —— Server Action 本质上是一个可被任意调用方 POST 的端点,不会因为 UI 里没有按钮就受到保护。
targeting 的取值含义:
| 值 | 含义 |
|---|---|
M |
频道好友中的指定接收者 |
N |
非频道好友的接收者 |
I |
按标识符指定的接收者 |
F |
已同意接收的全部频道好友(群发) |
客户端 Hook
useAlimtalk 用于调用你自己的接口,并附带 pending / error 状态。它返回 { send, loading, error, data, reset }:
'use client';
import { useAlimtalk } from '@sendgo/react';
export function NotifyButton({ phone, orderNo }: { phone: string; orderNo: string }) {
const { send, loading, error, data, reset } = useAlimtalk();
return (
<>
<button
disabled={loading}
onClick={() =>
send({
templateCode: 'ORDER_CONFIRM_001',
contacts: [{ contact: phone, var1: orderNo }],
})
}
>
{loading ? '发送中…' : '发送'}
</button>
{error && (
<p role="alert">
{error.message}
<button onClick={reset}>关闭</button>
</p>
)}
{data && <p>已发送。</p>}
</>
);
}
这个 Hook 只负责请求你的服务端端点 —— 它不会持有任何密钥。
短信 / 长短信 / 多媒体短信
'use server';
import { sendSms, sendLms, sendMms } from '@sendgo/react';
await sendSms({
content: '[Sendgo] 验证码:123456(请在 5 分钟内输入)',
contacts: [{ contact: '01012345678' }],
});
await sendLms({
subject: '[重要] 服务维护通知',
content: '服务将于 2026-07-25 02:00 ~ 06:00 进行维护。',
contacts: [{ contact: '01012345678' }],
});
await sendMms({
subject: '[活动] 7 月特惠',
content: '欢迎查看本月特价商品。',
contacts: [{ contact: '01012345678' }],
});
三个函数的参数类型都是 Omit<SmsParams, 'messageType'> —— 消息类型由函数本身决定,因此不会发错类型。
需要完整客户端时
'use server';
import { createSendgoClient } from '@sendgo/react';
// 不传参数时从环境变量读取配置。
const sendgo = createSendgoClient();
// 也可以显式覆盖(例如多租户)
const tenantClient = createSendgoClient({
accessKey: tenant.accessKey,
secretKey: tenant.secretKey,
apiVersion: 'v2',
});
await sendgo.alimtalk.send({ /* ... */ });
类型
import type {
AlimtalkParams,
FriendtalkParams,
BrandMessageParams,
BrandMessageListParams,
BrandMessageTargeting,
SmsParams,
Contact,
SendgoConfig,
SendgoResponse,
} from '@sendgo/react';
SendgoError 以值的形式导出,可用于 instanceof 判断。
环境变量
| 变量 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|
SENDGO_ACCESS_KEY |
必填 | — | Sendgo 访问密钥 |
SENDGO_SECRET_KEY |
必填 | — | Sendgo 私密密钥 |
SENDGO_KAKAO_SENDER_KEY |
选填 | undefined |
Kakao 发送者资料密钥 |
SENDGO_SMS_SENDER_KEY |
选填 | undefined |
短信主叫号码密钥 |
SENDGO_API_VERSION |
选填 | v1 |
API 版本(v1 | v2) |
短链接
短链接会缩短消息正文中的链接,并统计该链接是否被真正点击。 短信按字节计费,因此链接更短就意味着正文可以写更多内容。
仅 v2 支持。
再次缩短同一个原始 URL 会直接返回已有的链接。若希望按活动分别统计反应,
请使用 forceNew 生成新的短码。
deactivate 不会删除链接,只停止重定向。当已发送消息中的链接必须失效时使用它;
累计统计会保留,访问已停止的链接会返回 410 Gone。
'use server';
import { createShortUrl, shortUrlStats } from '@sendgo/react';
export async function shorten(targetUrl: string) {
const created = await createShortUrl({ targetUrl });
return created.data.shortUrl;
}
export async function reactions(code: string) {
return shortUrlStats(code, { from: '2026-08-01' });
}
stats 返回按日趋势(daily)以及按设备(byDevice)、来源(byReferer)、国家(byCountry)的分解。按日趋势读取的是预聚合表,因此点击量再大响应时间也保持稳定。
包信息
- 包名:
@sendgo/react(npm) - 仓库:send-go/react
- 注册表:https://www.npmjs.com/package/@sendgo/react
- 许可:MIT
如何获取 API 密钥
登录 Sendgo 后,在 API/SDK → API 对接 菜单中签发访问密钥与私密密钥。
使用通知消息/好友消息需在 Kakao 渠道 登记发送者资料以获取 SENDGO_KAKAO_SENDER_KEY;使用短信需在 发送号码 菜单登记主叫号码。
이 패키지로 할 수 있는 것
Send your first Kakao Alimtalk in 5 minutes →
From issuing an access key to sending a Kakao Alimtalk, with working code in Node.js, Python, PHP, Laravel, Java and Go.
Finish the Sendgo integration from your AI agent — MCP server and Account API →
Pick the organisation, issue API keys, register sender numbers and templates from a coding agent. Everything except topping up credit works without the console.
Sendgo API authentication — access keys and bearer tokens →
Exchange an accessKey and secretKey for a bearer token, and call the Sendgo API with it. Differences between v1 and v2, token caching, and the 401/403 codes.
Send a Kakao Alimtalk — PHP, Node.js, Python, Java, Go examples →
Send Kakao Alimtalk with an approved template code. Runnable code for Laravel, Node.js, Python, PHP, Java, Go, Ruby and .NET, plus every required field and why sends fail.
Send SMS, LMS and MMS in South Korea — code examples →
Send Korean SMS (90 bytes), LMS (long text) and MMS (with images) through Sendgo. Type selection, byte counting, verification-code patterns and advertising rules.
Send a Kakao Brand Message — the successor to Friendtalk →
Send Brand Messages to channel friends, non-friends, or every consenting friend at once. How targeting splits the request path, and when to keep using the Friendtalk endpoint.
SMS fallback when a Kakao Alimtalk fails →
Use replaceSms so a text message goes out when the Alimtalk cannot be delivered. Required fields, cost implications, and the mistake that silently sends nothing.
Bulk Alimtalk sending and per-recipient variables →
Send one template to many recipients with different values each, in batches. Batch sizing, partial failures, queue patterns and the data hygiene that prevents most incidents.
Scheduling an Alimtalk or SMS — scheduleType and at →
Send at a specific time with scheduleType SCHEDULED. Timestamp format, the KST timezone trap, and how scheduling interacts with the advertising night ban.
Doing everything over the API — operations automation for resellers →
Register Kakao channels, submit Alimtalk templates for review, file sender numbers, and sync opt-outs without ever sending anyone to sendgo.io. Includes webhook delivery of review outcomes.
Sendgo API error codes and retry strategy →
Every error code returned by the Sendgo send endpoints, and how to tell a failure worth retrying from one that will fail identically every time.
Short links in SMS and Alimtalk, with click tracking →
Shorten long URLs to fit inside an SMS and measure who clicked. Creating short links, reading click stats, and splitting stats per campaign.
Advertising message rules in Korea — (광고) prefix, opt-out, night ban →
What Korean law requires of promotional SMS and Kakao messages, and how to enforce it in code: the (광고) prefix, a free opt-out, and no sending between 21:00 and 08:00 KST.
Kakao Friendtalk shut down (2025-12-31) — migrating to Brand Message →
What happens to existing Friendtalk code now that the channel has ended, when you must migrate to Brand Message, and the one case where the Friendtalk endpoint is still the right call.
관련 패키지
Node.js →
用于发送 Kakao 通知消息、好友消息、品牌消息与 SMS 的官方 Node.js SDK —— 完整 TypeScript 类型,零运行时依赖。
npm install @sendgo/nodeVue / Nuxt →
用于从 Nuxt server route 发送 Kakao 通知消息、好友消息、品牌消息与 SMS 的官方 Vue SDK —— 仅限服务端。
npm install @sendgo/vueNestJS →
用于发送 Kakao 通知消息、好友消息、品牌消息与 SMS 的官方 NestJS 扩展包 —— 可注入的模块与服务。
npm install @sendgo/nestjs