본문 바로가기
Documentation menu

JavaScript / TypeScript / SDK REFERENCE

React / Next.js SDK Guide

The official React SDK for sending Kakao Alimtalk, Brand Message and SMS from Next.js Server Actions and Route Handlers — server-side only.

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

The official React SDK for sending Kakao Alimtalk, Brand Message and SMS from Next.js

@sendgo/react wraps the @sendgo/node core as ready-made Server Actions for the Next.js App Router.

Server-side only. These functions are marked 'use server'. Your access key and secret key must never reach the browser — if you call them from a Client Component, Next.js sends the invocation to the server, not the keys, which is exactly what you want. Never construct a client inside a 'use client' module.

Requires React 18+ and Next.js 14+.


Install

npm install @sendgo/react

The core @sendgo/node comes along as a dependency.


Configure

The Server Actions read these environment variables, so there is no client construction to wire up:

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

Do not prefix these with NEXT_PUBLIC_ — that would inline them into the browser bundle.


Quick start — Server Action

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

import { sendAlimtalk } from '@sendgo/react';

export async function notifyOrderConfirmed(phone: string, orderNo: string) {
  return sendAlimtalk({
    templateCode: 'ORDER_CONFIRM_001',
    contacts: [{ contact: phone, name: 'Gildong Hong', var1: orderNo }],
  });
}
// app/orders/[id]/page.tsx
import { notifyOrderConfirmed } from '../actions';

export default function OrderPage({ params }: { params: { id: string } }) {
  return (
    <form action={async () => { await notifyOrderConfirmed('01012345678', params.id); }}>
      <button type="submit">Send confirmation</button>
    </form>
  );
}

Available Server Actions

Action Channel
sendAlimtalk(params) Kakao Alimtalk
sendFriendtalk(params) Kakao Friendtalk
sendBrandMessage(params) Kakao Brand Message
broadcastBrandMessage(params) Brand Message broadcast (targeting: 'F')
listBrandMessages(params?) Brand Message campaign list
getBrandMessage(campaignId) Brand Message campaign detail
sendSms(params) SMS
sendLms(params) LMS
sendMms(params) MMS
createSendgoClient(config?) the raw Sendgo client, for anything above

Brand Message

Friendtalk was discontinued on 2025-12-31. Since 2026-01-01 Kakao delivers Friendtalk requests as Brand Message (free-form) automatically. friendtalk still works and is still the only path for free-form FT/FI/FW to individual recipients — use Brand Message for template-based rich types (FL/FC/FM/FP/FA), non-friend targeting (N/I) and broadcasts (F). Brand Message is the successor channel to Friendtalk: it reaches recipients who are not channel friends (targeting: 'N') and can broadcast to every consenting channel friend (targeting: 'F'). Message types map one-to-one with Friendtalk (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.

v2 only. Set SENDGO_API_VERSION=v2.

'use server';

import {
  sendBrandMessage,
  broadcastBrandMessage,
  listBrandMessages,
  getBrandMessage,
} from '@sendgo/react';

// Single send — channel friends
export async function promoteToFriends(phone: string) {
  return sendBrandMessage({
    targeting: 'M',
    messageType: 'FL',
    friendTemplateUuid: '9cd5460b-6458-4edc-9b11-c26d3013c340',
    contacts: [{ contact: phone, var1: '29,000 KRW' }],
  });
}

// Broadcast — every consenting channel friend (no recipient list)
export async function announce() {
  return broadcastBrandMessage({
    messageType: 'FW',
    friendTemplateUuid: '9cd5460b-6458-4edc-9b11-c26d3013c340',
  });
}

// A broadcast is asynchronous upstream, so poll for the result
export async function broadcastStatus(campaignId: string) {
  return getBrandMessage(campaignId);
}

export async function recentCampaigns() {
  return listBrandMessages({ count: 10 });
}

broadcastBrandMessage takes Omit<BrandMessageParams, 'targeting' | 'contacts'>, so TypeScript rejects passing a recipient list to a broadcast rather than letting the API do it at runtime.


Route Handler

When you need a plain HTTP endpoint — for a webhook or a non-React caller:

// app/api/notify/route.ts
import { NextResponse } from 'next/server';
import { sendAlimtalk } from '@sendgo/react';
import { 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 });
  } catch (error) {
    if (error instanceof SendgoError) {
      // Don't leak provider detail to the caller; log it and return a generic status.
      console.error(`Sendgo ${error.statusCode} [${error.errorCode}]: ${error.message}`);

      return NextResponse.json({ ok: false }, { status: error.statusCode >= 500 ? 502 : 400 });
    }

    throw error;
  }
}

Client-side hook

useAlimtalk gives a Client Component pending/error state around a Server Action, without ever touching the keys. It returns { send, loading, error, data, reset }:

'use client';

import { useAlimtalk } from '@sendgo/react';

export function SendButton({ 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 ? 'Sending…' : 'Send'}
      </button>
      {error && (
        <p role="alert">
          {error.message} <button onClick={reset}>Dismiss</button>
        </p>
      )}
      {data && <p>Sent.</p>}
    </>
  );
}

Custom configuration

If your keys do not come from environment variables — a multi-tenant app resolving them per request, for instance — build the client yourself:

'use server';

import { createSendgoClient } from '@sendgo/react';

export async function sendForTenant(tenant: Tenant, phone: string) {
  const sendgo = createSendgoClient({
    accessKey: tenant.sendgoAccessKey,
    secretKey: tenant.sendgoSecretKey,
    kakaoSenderKey: tenant.kakaoSenderKey,
    apiVersion: 'v2',
  });

  return sendgo.alimtalk.send({
    templateCode: 'ORDER_CONFIRM_001',
    contacts: [{ contact: phone }],
  });
}

Called with no argument, createSendgoClient() returns the shared environment-configured singleton.


Types

Every request shape is re-exported from the core, so payloads are checked at compile time:

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

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.

'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 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 SENDGO_KAKAO_SENDER_KEY, and a caller ID under Sender numbers for SMS.

이 패키지로 할 수 있는 것

관련 패키지

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