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.
POST /api/v2/notices/sendAlimtalk works by filling in an approved template. You do not compose the body at send time; you fill the blanks in wording that already passed review.
[#{var2}] Your order is confirmed.
Order number: #{var1}
Total: #{var3}
If that is approved as ORDER_CONFIRM_001, your code only supplies var1, var2 and var3.
Prerequisites
- An approved template code
- A Kakao sender profile key (
kakaoSenderKey) - An access key and secret key
Required fields
POST /api/v2/notices/send
| Field | Required | Notes |
|---|---|---|
templateCode |
✅ | Approved template code |
contacts |
✅ | Recipient array. Empty gives EMPTY_CONTACTS |
contacts[].contact |
✅ | Phone number, digits only (01012345678) |
contacts[].name |
Recipient name | |
contacts[].var1–var8 |
Template variables | |
kakaoSenderKey |
✅ | Sender profile key (can live on the client instead) |
senderKey |
SMS sending number, needed for SMS fallback | |
scheduleType |
DIRECTLY (default) or SCHEDULED |
|
at |
Y-m-d H:i:s, KST, when scheduleType is SCHEDULED |
|
replaceSms |
Y to fall back to SMS |
|
smsSubject / smsContent |
Fallback body. Required when replaceSms is Y |
Examples by language
Node.js / TypeScript
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',
});
await sendgo.alimtalk.send({
templateCode: 'ORDER_CONFIRM_001',
contacts: [{
contact: '01012345678',
name: 'Hong Gildong',
var1: 'ORD-001',
var2: 'MacBook Pro',
var3: '3,490,000원',
}],
});
Python
client.alimtalk.send(
template_code="ORDER_CONFIRM_001",
contacts=[
{"contact": "01012345678", "name": "Hong Gildong", "var1": "ORD-001", "var2": "MacBook Pro"}
],
)
Django users want sendgo-django; FastAPI users want sendgo-fastapi.
PHP
<?php
$sendgo->alimtalk->send([
'templateCode' => 'ORDER_CONFIRM_001',
'contacts' => [
['contact' => '01012345678', 'name' => 'Hong Gildong', 'var1' => 'ORD-001'],
],
]);
Laravel
<?php
namespace App\Services;
use Sendgo\Php\Sendgo;
use Sendgo\Php\Exception\SendgoException;
use Illuminate\Support\Facades\Log;
class OrderNotifier
{
public function __construct(private Sendgo $sendgo) {}
public function confirmed(Order $order): void
{
try {
$this->sendgo->alimtalk->send([
'templateCode' => 'ORDER_CONFIRM_001',
'contacts' => [[
'contact' => $order->user->phone,
'var1' => $order->number,
'var3' => number_format($order->total).'원',
]],
]);
} catch (SendgoException $e) {
// A failed notification must not roll back the order.
Log::error('Alimtalk send failed', ['order' => $order->id, 'message' => $e->getMessage()]);
}
}
}
Queue this. An external call inside the request cycle ties your latency to Kakao's.
Java / Spring Boot
sendgo.alimtalk().send(AlimtalkRequest.builder()
.templateCode("ORDER_CONFIRM_001")
.contacts(List.of(
Contact.builder().contact("01012345678").name("Hong Gildong").var1("ORD-001").build()
))
.build());
Go
result, err := client.Alimtalk.Send(sendgo.AlimtalkRequest{
TemplateCode: "ORDER_CONFIRM_001",
Contacts: []sendgo.Contact{
{Contact: "01012345678", Name: "Hong Gildong", Var1: "ORD-001"},
},
})
if err != nil {
log.Printf("alimtalk send failed: %v", err)
}
Ruby
client.alimtalk.send(
template_code: 'ORDER_CONFIRM_001',
contacts: [{ contact: '01012345678', name: 'Hong Gildong', var1: 'ORD-001' }]
)
C# / .NET
await client.SendAlimtalkAsync(new AlimtalkRequest
{
TemplateCode = "ORDER_CONFIRM_001",
Contacts = [new Contact { PhoneNumber = "01012345678", Name = "Hong Gildong", Var1 = "ORD-001" }],
});
REST
curl -X POST https://sendgo.io/api/v2/notices/send \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"templateCode": "ORDER_CONFIRM_001",
"scheduleType": "DIRECTLY",
"replaceSms": "N",
"kakaoSenderKey": "your_kakao_sender_key",
"senderKey": "your_sms_sender_key",
"contacts": [{ "contact": "01012345678", "var1": "ORD-001" }]
}'
Why sends fail
| Code | Cause | Retry helps |
|---|---|---|
INVALID_TEMPLATE_CODE |
Unknown or unapproved template | ❌ |
INVALID_KAKAO_SENDER_KEY |
Wrong sender profile key | ❌ |
EMPTY_CONTACTS |
Empty recipient array | ❌ |
PAYMENT_REQUIRED |
Out of credit | ❌ (top up) |
ACCESS_KEY_NOT_APPROVED |
App not approved | ❌ |
IP_NOT_ALLOWED |
Outside the IP allowlist | ❌ |
| Network timeout | Transient | ✅ |
Almost every failure fails identically on retry. Log it and move on rather than looping. See Error codes and retry strategy.
Easy to get wrong
- No hyphens in phone numbers.
01012345678, not010-1234-5678. - Missing variables render literally. If the template has
#{var4}and you omitvar4, the recipient sees that text. - Promotional content will not go out as Alimtalk. Informational only.
- Do not build a new client per request — you throw away the cached token every time.
Next
자주 묻는 질문
- Can I write the Alimtalk body in code?
- No. Alimtalk delivers only to templates approved by Kakao. Your code picks a templateCode and fills that template's variables (var1 to var8). For free-form text use LMS or Brand Message.
- How many template variables are there?
- Eight: var1 through var8. If the template defines a variable and you do not supply it, the recipient sees the raw placeholder, so fill all of them.
- How many recipients can one call take?
- Put multiple entries in the contacts array and they go in one request, each with its own variable values. For large sends, split into batches of a few hundred so a timeout does not leave you unsure what was delivered.
- What if the recipient does not use KakaoTalk?
- The Alimtalk fails. Set replaceSms to Y and supply smsSubject and smsContent and it falls back to a text message automatically.