본문 바로가기
Documentation menu

JavaScript / TypeScript / SDK REFERENCE

Node.js SDK Guide

The Node.js and TypeScript SDK for sending Kakao Alimtalk, Brand Message and SMS — fully typed, zero runtime dependencies.

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

The Node.js / TypeScript SDK for sending Kakao Alimtalk, Brand Message and SMS

@sendgo/node is the official Node.js SDK for the Sendgo messaging API. It is written in TypeScript, ships its own type declarations, and uses the built-in fetch — no runtime dependencies.

Server-side only. Your access key and secret key must never reach a browser. Use this SDK from a server process, a Next.js Server Action / Route Handler, a Nuxt server route, or a background worker.


Install

npm install @sendgo/node
# or
pnpm add @sendgo/node
yarn add @sendgo/node

Requires Node.js 18 or newer (for global fetch).


Quick start

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',
});

// Send an Alimtalk
await sendgo.alimtalk.send({
  templateCode: 'ORDER_CONFIRM_001',
  contacts: [
    { contact: '01012345678', name: 'Gildong Hong', var1: 'ORD-001', var2: '29,000 KRW' },
  ],
});

// Send an SMS
await sendgo.sms.sendSms({
  content: '[Sendgo] Your code is 123456 (valid for 5 minutes)',
  contacts: [{ contact: '01012345678' }],
});

Tokens are issued and refreshed automatically — you never handle them yourself.


Alimtalk in detail

// Multiple recipients
await sendgo.alimtalk.send({
  templateCode: 'ORDER_CONFIRM_001',
  contacts: [
    { contact: '01011111111', name: 'Gildong Hong', var1: 'ORD-001', var2: '29,000 KRW' },
    { contact: '01022222222', name: 'Chulsoo Kim', var1: 'ORD-002', var2: '15,000 KRW' },
  ],
});

// Scheduled send
await sendgo.alimtalk.send({
  templateCode: 'PROMO_SUMMER_2026',
  scheduleType: 'SCHEDULED',
  at: '2026-07-28 09:00:00',
  contacts: [{ contact: '01012345678', var1: 'Summer sale — 50% off' }],
});

// Fall back to SMS when the Alimtalk fails
await sendgo.alimtalk.send({
  templateCode: 'DELIVERY_START_001',
  replaceSms: 'Y',
  smsSubject: '[Shipping notice]',
  smsContent: 'Your order has shipped.\nTracking: #{var2}',
  contacts: [{ contact: '01012345678', var1: 'ORD-001', var2: '1234567890' }],
});

Friendtalk

⚠️ Deprecated — Friendtalk was discontinued on 2025-12-31 under Kakao's policy. Since 2026-01-01, Friendtalk send requests are automatically delivered as Brand Message (free-form) by Kakao. Calls still succeed, and this is still the only path for free-form types (FT/FI/FW) sent to individual recipients, so there is no need to change working code right now.

Use Brand Message instead for:

  • template-based rich types (FL/FC/FM/FP/FA)
  • recipients who are not channel friends (targeting = N / I)
  • broadcasts to every opted-in channel friend (targeting = F)

Message types map one-to-one and the server does the conversion — FT→BT, FI→BI, FW→BW, FL→BL, FC→BC, FM→BM, FP→BP, FA→BA.

// Text
await sendgo.friendtalk.send({
  content: 'Hello! Check out this month\'s deals.',
  contacts: [{ contact: '01012345678' }],
});

// Image
await sendgo.friendtalk.send({
  messageType: 'FI',
  content: 'This week\'s featured products.',
  imageUrl: 'https://cdn.example.com/banner.jpg',
  imageLink: 'https://example.com/event',
  contacts: [{ contact: '01012345678' }],
});

// With buttons
await sendgo.friendtalk.send({
  content: 'Your coupon has arrived. Use it now!',
  buttons: [{ name: 'Get coupon', type: 'WL', linkMo: 'https://example.com/coupon' }],
  contacts: [{ contact: '01012345678' }],
});

Brand Message

Brand Message is the successor channel to Friendtalk. Message types map one-to-one (FT→BT, FI→BI, FW→BW, FL→BL, FC→BC, FM→BM, FP→BP, FA→BA); pass the Friendtalk code and the server converts it.

Unlike Friendtalk it can also:

  • reach recipients who are not channel friends (targeting: 'N')
  • broadcast to every consenting channel friend (targeting: 'F', no recipient list needed)
  • send template-based rich messages — lists, carousels, commerce, video

v2 only. For plain text or images (FT/FI/FW) to channel friends, the Friendtalk API is simpler.

// Single send — channel friends
await sendgo.brandMessage.send({
  targeting: 'M',
  messageType: 'FL',
  friendTemplateUuid: '9cd5460b-6458-4edc-9b11-c26d3013c340',
  contacts: [{ contact: '01012345678', var1: '29,000 KRW' }],
});

// Broadcast — every consenting channel friend (no contacts)
await sendgo.brandMessage.broadcast({
  messageType: 'FW',
  friendTemplateUuid: '9cd5460b-6458-4edc-9b11-c26d3013c340',
});

// Campaign lookups
const list = await sendgo.brandMessage.campaigns({ count: 10 });
const one = await sendgo.brandMessage.campaign('1f0a6d0e-6b3b-4f0f-9b2f-2f6f6a1b7c11');

broadcast() omits contacts entirely rather than sending an empty array — an empty recipient list would be rejected as an invalid request.


SMS / LMS / MMS

// SMS (up to 90 bytes)
await sendgo.sms.sendSms({
  content: '[Sendgo] Your code is 123456 (valid for 5 minutes)',
  contacts: [{ contact: '01012345678' }],
});

// LMS (long text, up to 2,000 bytes)
await sendgo.sms.sendLms({
  subject: '[Important] Scheduled maintenance',
  content: 'Maintenance is scheduled.\n\n■ When: 2026-07-25 02:00–06:00\n■ Impact: all services',
  contacts: [{ contact: '01012345678' }],
});

// MMS (with an image)
await sendgo.sms.sendMms({
  subject: '[Event] July deals',
  content: 'Check out this month\'s deals!',
  contacts: [{ contact: '01012345678' }],
});

// Scheduled SMS
await sendgo.sms.sendSms({
  content: '[Reminder] Please confirm your appointment.',
  scheduleType: 'SCHEDULED',
  at: '2026-07-23 08:00:00',
  contacts: [{ contact: '01012345678' }],
});

Framework integration

Next.js — Server Action

For Next.js there is a dedicated package, @sendgo/react, which exposes ready-made Server Actions. To use this core SDK directly:

// app/actions/notify.ts
'use server';

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,
  apiVersion: 'v2',
});

export async function notifyOrderConfirmed(phone: string, orderNo: string) {
  return sendgo.alimtalk.send({
    templateCode: 'ORDER_CONFIRM_001',
    contacts: [{ contact: phone, var1: orderNo }],
  });
}

Express

import express from 'express';
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,
  apiVersion: 'v2',
});

const app = express();
app.use(express.json());

app.post('/notify', async (req, res, next) => {
  try {
    await sendgo.alimtalk.send({
      templateCode: 'ORDER_CONFIRM_001',
      contacts: [{ contact: req.body.phone, var1: req.body.orderNo }],
    });
    res.json({ ok: true });
  } catch (error) {
    next(error);
  }
});

NestJS

Use @sendgo/nestjs, which registers the client as an injectable provider:

constructor(private readonly sendgo: SendgoService) {}

await this.sendgo.brandMessage.send({ /* ... */ });

Error handling

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

try {
  await sendgo.alimtalk.send({
    templateCode: 'ORDER_CONFIRM_001',
    contacts: [{ contact: '01012345678' }],
  });
} catch (error) {
  if (!(error instanceof SendgoError)) throw error;

  switch (error.errorCode) {
    case 'INVALID_ACCESS_KEY':
    case 'INVALID_SECRET_KEY':
      await alertOps('Check the Sendgo API keys.');
      break;
    case 'PAYMENT_REQUIRED':
      await alertOps('Out of Sendgo credit.');
      break;
    case 'IP_NOT_ALLOWED':
      await alertOps('IP is not allow-listed.');
      break;
    case 'INVALID_TEMPLATE_CODE':
      logger.warn('Unknown template');
      break;
    default:
      if (error.statusCode >= 500) await retryQueue.push(job); // retryable
      else logger.error(`Sendgo error ${error.statusCode}: ${error.message}`);
  }
}

Branch on errorCode, not on the message text — messages can change, codes are the contract. TOKEN_EXPIRED and TOKEN_MISMATCH are handled inside the SDK: the token is reissued and the request retried once.


Configuration options

Option Type Required Default Description
accessKey string required — Sendgo access key
secretKey string required — Sendgo secret key
kakaoSenderKey string optional — Kakao sender profile key
smsSenderKey string optional — SMS caller ID key
apiVersion 'v1' | 'v2' optional 'v1' API version
baseUrl string optional 'https://sendgo.io' API base URL

TypeScript

Every request shape is exported, so payloads are checked at compile time.

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

Short URL

Short URLs shrink the links in your message body and count whether they were actually clicked. SMS is billed by byte, so a shorter link leaves more room for copy.

v2 only.

Shortening the same target URL again returns the existing link. Pass forceNew to mint a new code when you want per-campaign reaction figures kept separate.

deactivate does not delete the link — it only stops the redirect. Use it when a link in an already-sent message has to be killed; the accumulated stats stay, and visitors to a stopped link get 410 Gone.

const created = await sendgo.shortUrl.create({
  targetUrl: 'https://example.com/promotions/summer-sale',
  title: 'Summer sale landing',
});

const { code, shortUrl } = created.data;

// Reaction stats — daily series + device / referrer / country breakdowns
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);   // Stops the redirect only; the stats stay

stats returns a daily series (daily) plus breakdowns by device (byDevice), referrer (byReferer) and country (byCountry). The daily series is read from a pre-aggregated table, so response time stays flat no matter how many clicks accumulate.


Package information

Getting your API keys

Sign in to Sendgo and open API/SDK → API integration to issue an access key and secret key. Register a Kakao sender profile under Kakao channel to get your kakaoSenderKey, and a caller ID under Sender numbers for SMS.

이 패키지로 할 수 있는 것

관련 패키지

Focus on building. Leave messaging to Sendgo.Back to top ↑