기업회원 신청 서류 안내
신청자 구분에 따라 재직증명서 또는 위임장을 함께 제출해 주세요.
신청자 구분에 따라 재직증명서 또는 위임장을 함께 제출해 주세요.
Dart / SDK REFERENCE
The official Dart SDK for sending Kakao Alimtalk, Brand Message and SMS from a Dart server — server-side only, never bundle keys into an app.
dart pub add sendgo_flutterThe official Dart SDK for sending Kakao Alimtalk, Brand Message and SMS from a Dart server
sendgo_flutter is the official Dart SDK for the Sendgo messaging API.
Server-side only. Never put your access key and secret key in a Flutter app — anything shipped to a device can be extracted from the bundle. Use this SDK from a Dart backend (Shelf, Serverpod, Dart Frog), Cloud Functions, or your own API, and have the app call your endpoint instead.
Requires Dart 3.3 or newer.
dart pub add sendgo_flutter
# pubspec.yaml
dependencies:
sendgo_flutter: ^1.0.2
import 'dart:io';
import 'package:sendgo_flutter/sendgo_flutter.dart';
final client = SendgoClient(
accessKey: Platform.environment['SENDGO_ACCESS_KEY']!,
secretKey: Platform.environment['SENDGO_SECRET_KEY']!,
kakaoSenderKey: Platform.environment['SENDGO_KAKAO_SENDER_KEY'],
smsSenderKey: Platform.environment['SENDGO_SMS_SENDER_KEY'],
apiVersion: 'v2',
);
// Send an Alimtalk
await client.alimtalk.send(AlimtalkRequest(
templateCode: 'ORDER_CONFIRM_001',
contacts: [
Contact(contact: '01012345678', name: 'Gildong Hong', var1: 'ORD-001'),
],
));
Each channel is a field on the client: alimtalk, friendtalk, brandMessage, sms.
Tokens are issued and refreshed inside the SDK.
// Multiple recipients
await client.alimtalk.send(AlimtalkRequest(
templateCode: 'ORDER_CONFIRM_001',
contacts: [
Contact(contact: '01011111111', name: 'Gildong Hong', var1: 'ORD-001'),
Contact(contact: '01022222222', name: 'Chulsoo Kim', var1: 'ORD-002'),
],
));
// Scheduled send
await client.alimtalk.send(AlimtalkRequest(
templateCode: 'PROMO_SUMMER_2026',
scheduleType: 'SCHEDULED',
at: '2026-07-28 09:00:00',
contacts: [Contact(contact: '01012345678', var1: 'Summer sale')],
));
// Fall back to SMS when the Alimtalk fails
await client.alimtalk.send(AlimtalkRequest(
templateCode: 'DELIVERY_START_001',
replaceSms: 'Y',
smsSubject: '[Shipping notice]',
smsContent: 'Your order has shipped.',
contacts: [Contact(contact: '01012345678', var1: 'ORD-001')],
));
For named template variables beyond var1–var8, Contact also takes a map:
Contact(contact: '01012345678', variables: {'title': 'Order', 'date': '2026-08-10'});
Contact.toJson() merges variables into the payload, so named and numbered variables can be mixed.
⚠️ 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.
await client.friendtalk.send(FriendtalkRequest(
messageType: 'FI',
content: "This week's featured products.",
imageUrl: 'https://cdn.example.com/banner.jpg',
imageLink: 'https://example.com/event',
contacts: [Contact(contact: '01012345678')],
));
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') and broadcast to every consenting channel friend (targeting: 'F').
v2 only. Set
apiVersion: 'v2'.
// Single send — channel friends
await client.brandMessage.send(BrandMessageRequest(
targeting: 'M',
messageType: 'FL',
friendTemplateUuid: '9cd5460b-6458-4edc-9b11-c26d3013c340',
contacts: [Contact(contact: '01012345678', var1: '29,000 KRW')],
));
// Broadcast — every consenting channel friend (no contacts)
await client.brandMessage.broadcast(BrandMessageRequest(
messageType: 'FW',
friendTemplateUuid: '9cd5460b-6458-4edc-9b11-c26d3013c340',
));
// Campaign lookups
final list = await client.brandMessage.campaigns(count: 10);
final one = await client.brandMessage.campaign('1f0a6d0e-6b3b-4f0f-9b2f-2f6f6a1b7c11');
broadcast() calls request.asBroadcast(), which returns a copy with targeting: 'F' and no contacts. toJson() then omits the contacts key entirely rather than sending an empty list, which the API would reject.
// SMS (up to 90 bytes)
await client.sms.sendSms(SmsRequest(
content: '[Sendgo] Your code is 123456 (valid for 5 minutes)',
contacts: [Contact(contact: '01012345678')],
));
// LMS (long text, up to 2,000 bytes)
await client.sms.sendLms(SmsRequest(
subject: '[Important] Scheduled maintenance',
content: 'Maintenance: 2026-07-25 02:00–06:00',
contacts: [Contact(contact: '01012345678')],
));
// MMS
await client.sms.sendMms(SmsRequest(
subject: '[Event] July deals',
content: "Check out this month's deals!",
contacts: [Contact(contact: '01012345678')],
));
The app must not hold Sendgo keys. Put the SDK behind your own endpoint and call that:
// server/bin/server.dart — Shelf
import 'package:shelf/shelf.dart';
import 'package:shelf_router/shelf_router.dart';
import 'package:sendgo_flutter/sendgo_flutter.dart';
final client = SendgoClient(
accessKey: Platform.environment['SENDGO_ACCESS_KEY']!,
secretKey: Platform.environment['SENDGO_SECRET_KEY']!,
kakaoSenderKey: Platform.environment['SENDGO_KAKAO_SENDER_KEY'],
apiVersion: 'v2',
);
final router = Router()
..post('/notify', (Request request) async {
final body = jsonDecode(await request.readAsString()) as Map<String, dynamic>;
await client.alimtalk.send(AlimtalkRequest(
templateCode: 'ORDER_CONFIRM_001',
contacts: [Contact(contact: body['phone'] as String, var1: body['orderNo'] as String)],
));
return Response.ok('{"ok":true}');
});
The Flutter app then calls POST /notify on your server, authenticated with your own session — the Sendgo keys never leave the backend.
try {
await client.alimtalk.send(request);
} on SendgoException catch (e) {
switch (e.errorCode) {
case 'INVALID_ACCESS_KEY':
case 'INVALID_SECRET_KEY':
log.severe('Check the Sendgo API keys');
case 'PAYMENT_REQUIRED':
log.severe('Out of Sendgo credit');
case 'IP_NOT_ALLOWED':
log.severe('IP is not allow-listed');
case 'INVALID_TEMPLATE_CODE':
log.warning('Unknown template');
default:
if (e.statusCode >= 500) {
await retryLater(request); // transient
} else {
log.severe('Sendgo ${e.statusCode}: ${e.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.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
accessKey |
String |
required | — | Sendgo access key |
secretKey |
String |
required | — | Sendgo secret key |
kakaoSenderKey |
String? |
optional | null |
Kakao sender profile key |
smsSenderKey |
String? |
optional | null |
SMS caller ID key |
apiVersion |
String |
optional | 'v1' |
API version (v1 | v2) |
baseUrl |
String |
optional | 'https://sendgo.io' |
API base 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.
final created = await sendgo.shortUrl.create(const ShortUrlRequest(
targetUrl: 'https://example.com/promotions/summer-sale',
title: 'Summer sale landing',
));
final code = created['data']['code'] as String;
final link = created['data']['shortUrl'] as String;
// Reaction stats — daily series + device / referrer / country breakdowns
final 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.
sendgo_flutter (pub.dev)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.
From issuing an access key to sending a Kakao Alimtalk, with working code in Node.js, Python, PHP, Laravel, Java and Go.
Pick the organisation, issue API keys, register sender numbers and templates from a coding agent. Everything except topping up credit works without the console.
Kakao Alimtalk, Kakao Brand Message and SMS/LMS/MMS differ in what content they allow, what they cost and what you must set up first. Which to pick, by situation.
Pick the right Sendgo package for PHP, Laravel, Symfony, WordPress, Node.js, Next.js, NestJS, Python, Django, FastAPI, Java, Spring Boot, Go, Ruby, Rails, .NET, ASP.NET Core or Flutter.
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.
Korean law requires the caller ID to be pre-registered. How to register an SMS sending number and connect a Kakao channel, and where registrations usually get rejected.