KakaoTalk
TypeScript SDK reference for KakaoTalk — client, credential management, and types.
Installation
npm install agent-messengerimport { KakaoTalkClient, KakaoCredentialManager } from 'agent-messenger/kakaotalk'KakaoTalkClient
The main client for interacting with KakaoTalk via the LOCO protocol. Unlike Discord/Slack which use stateless HTTP, KakaoTalk maintains a persistent TCP connection. Call close() when done.
import { KakaoTalkClient } from 'agent-messenger/kakaotalk'
const client = await new KakaoTalkClient().login({ oauthToken, userId, deviceUuid })
// deviceUuid is optional — defaults to `agent-messenger-${userId}`Or use automatic credential extraction — credentials are read from stored login state:
import { KakaoTalkClient } from 'agent-messenger/kakaotalk'
const client = await new KakaoTalkClient().login()Chat Rooms
// List recent chat rooms (from login snapshot)
const chats = await client.getChats()
// → KakaoChat[]
// List ALL chats (paginate beyond login snapshot)
const allChats = await client.getChats({ all: true })
// Search chats by display name
const results = await client.getChats({ search: 'Alice' })Messages
// Get recent messages from a chat (default: 20)
const messages = await client.getMessages('9876543210')
// → KakaoMessage[]
// Get more messages
const more = await client.getMessages('9876543210', { count: 100 })
// Get messages after a known log ID
const newer = await client.getMessages('9876543210', { from: '123456789' })Sending
// Send a text message
const result = await client.sendMessage('9876543210', 'Hello from SDK!')
// → KakaoSendResult { success, status_code, chat_id, log_id, sent_at }Cleanup
// Close the LOCO connection (MUST call when done)
client.close()Once closed, any subsequent method call throws a KakaoTalkError with code client_closed. Create a new client if you need to reconnect.
KakaoTalkListener
Real-time event listener that receives push events from KakaoTalk via the LOCO protocol. Manages its own LOCO session with automatic reconnection.
import { KakaoTalkClient, KakaoTalkListener } from 'agent-messenger/kakaotalk'
const client = await new KakaoTalkClient().login()
const listener = new KakaoTalkListener(client)
listener.on('connected', (info) => {
console.log(`Connected as ${info.userId}`)
})
listener.on('message', (event) => {
console.log(`[${event.chat_id}] ${event.author_id}: ${event.message}`)
})
listener.on('member_joined', (event) => {
console.log(`User ${event.member.user_id} joined ${event.chat_id}`)
})
listener.on('member_left', (event) => {
console.log(`User ${event.member.user_id} left ${event.chat_id}`)
})
listener.on('read', (event) => {
console.log(`User ${event.user_id} read ${event.chat_id} up to ${event.watermark}`)
})
listener.on('disconnected', () => console.log('Reconnecting...'))
listener.on('error', (err) => console.error(err))
await listener.start()
// listener.stop() to disconnectEvents
| Event | Payload | Description |
|---|---|---|
message | KakaoTalkPushMessageEvent | New message received |
member_joined | KakaoTalkPushMemberEvent | Member joined a chat |
member_left | KakaoTalkPushMemberEvent | Member left a chat |
read | KakaoTalkPushReadEvent | Read receipt (unread count decreased) |
kakaotalk_event | KakaoTalkPushGenericEvent | Catch-all for all push events |
connected | { userId: string } | Connected to LOCO server |
disconnected | — | Disconnected (will auto-reconnect) |
error | Error | Connection or protocol error |
Reconnection
The listener automatically reconnects with exponential backoff (1s → 2s → 4s → ... → 30s max) when the connection drops. Server-requested migrations (CHANGESVR) trigger immediate reconnection. If the session is kicked by another device (KICKOUT), the listener stops and emits an error.
KakaoCredentialManager
Manages KakaoTalk credentials stored at ~/.config/agent-messenger/kakaotalk-credentials.json. Files are written with 0o600 permissions.
import { KakaoCredentialManager } from 'agent-messenger/kakaotalk'
const manager = new KakaoCredentialManager()// Load full config from disk (returns defaults if file doesn't exist)
const config = await manager.load()
// → KakaoConfig { current_account, accounts }
// Save full config to disk
await manager.save(config)
// Get the current account's credentials
const account = await manager.getAccount()
// → KakaoAccountCredentials | null
// Get a specific account by ID
const specific = await manager.getAccount('1234567890')
// → KakaoAccountCredentials | null
// Store account credentials
await manager.setAccount(credentials)
// Remove an account
await manager.removeAccount('1234567890')
// Switch the current account
await manager.setCurrentAccount('1234567890')Types
import type {
KakaoChat,
KakaoMessage,
KakaoSendResult,
KakaoAccountCredentials,
KakaoConfig,
KakaoDeviceType,
PendingLoginState,
} from 'agent-messenger/kakaotalk'Zod Schemas
Runtime-validated schemas are also exported for parsing API responses:
import {
KakaoChatSchema,
KakaoMessageSchema,
KakaoSendResultSchema,
KakaoAccountCredentialsSchema,
KakaoConfigSchema,
} from 'agent-messenger/kakaotalk'Examples
Chat Summary
List all chats, count unread, and print a summary.
import { KakaoTalkClient, KakaoCredentialManager } from 'agent-messenger/kakaotalk'
const manager = new KakaoCredentialManager()
const account = await manager.getAccount()
if (!account) throw new Error('Not authenticated')
const client = await new KakaoTalkClient().login({
oauthToken: account.oauth_token,
userId: account.user_id,
deviceUuid: account.device_uuid,
})
try {
const chats = await client.getChats({ all: true })
const unread = chats.filter((c) => c.unread_count > 0)
console.log(`${unread.length} chats with unread messages:`)
for (const chat of unread) {
console.log(` ${chat.display_name} — ${chat.unread_count} unread`)
}
} finally {
client.close()
}Send Notification
Send a message to a specific chat.
import { KakaoTalkClient, KakaoCredentialManager } from 'agent-messenger/kakaotalk'
const manager = new KakaoCredentialManager()
const account = await manager.getAccount()
if (!account) throw new Error('Not authenticated')
const client = await new KakaoTalkClient().login({
oauthToken: account.oauth_token,
userId: account.user_id,
deviceUuid: account.device_uuid,
})
try {
const chats = await client.getChats({ search: 'Team' })
const teamChat = chats[0]
if (teamChat) {
const result = await client.sendMessage(teamChat.chat_id, '🚀 Deployment complete!')
console.log(`Sent (log_id: ${result.log_id})`)
}
} finally {
client.close()
}Message Monitor
Poll for new messages in a chat room.
import { KakaoTalkClient, KakaoCredentialManager } from 'agent-messenger/kakaotalk'
const manager = new KakaoCredentialManager()
const account = await manager.getAccount()
if (!account) throw new Error('Not authenticated')
const client = await new KakaoTalkClient().login({
oauthToken: account.oauth_token,
userId: account.user_id,
deviceUuid: account.device_uuid,
})
const chatId = '9876543210'
let lastLogId: string | undefined
const poll = async () => {
try {
const messages = lastLogId
? await client.getMessages(chatId, { from: lastLogId })
: await client.getMessages(chatId, { count: 1 })
for (const msg of messages) {
if (msg.log_id !== lastLogId) {
console.log(`[${msg.author_id}] ${msg.message}`)
lastLogId = msg.log_id
}
}
} catch (error) {
console.error('Poll failed:', error)
}
}
const timer = setInterval(poll, 10_000)
// To stop: clearInterval(timer); client.close()