Documentation menu
Dart / SDK REFERENCE
Flutter / Dart SDK Guide
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.
이 문서의 목차
- 패키지
- sendgo_flutter
- 언어
- Dart
- 레지스트리
- pub.dev
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.
Install
dart pub add sendgo_flutter
# pubspec.yaml
dependencies:
sendgo_flutter: ^1.0.2
Quick start
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.
Alimtalk in detail
// 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.
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.
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
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 / LMS / MMS
// 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')],
));
Using it from a Flutter app safely
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.
Error handling
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.
Configuration options
| 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 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.
Package information
- Package:
sendgo_flutter(pub.dev) - Repository: send-go/flutter
- Registry: https://pub.dev/packages/sendgo_flutter
- License: MIT
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.
이 패키지로 할 수 있는 것
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.
Alimtalk, Brand Message or SMS — choosing a messaging channel in Korea →
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.
Which Sendgo SDK should I install? — 20 official packages →
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.
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.
Registering a sending number in South Korea — required before you can send →
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.