서버에서 특정 이벤트가 발생했을 때 — 예를 들면 결제 완료, 에러 알림, 크론 작업 결과 등 — 실시간으로 알림을 받고 싶었던 적이 있을 것이다. 슬랙이나 이메일도 방법이지만, 개인 프로젝트나 소규모 서비스에서는 텔레그램 봇이 가장 빠르고 간편한 선택지다.
다만 대부분의 개발자들은 BotFather로 봇을 만든 뒤 토큰만 받아놓고, 실제로 메시지를 보내는 코드나 Webhook을 세팅하는 부분에서 막히는 경우가 많다. 이번 글에서는 텔레그램 봇 생성부터 PHP로 메시지 보내기, 그리고 Webhook을 통해 사용자 메시지를 수신·처리하는 것까지 실무에서 바로 쓸 수 있도록 완벽하게 정리하겠다.
텔레그램 봇은 Telegram의 공식 봇인 @BotFather를 통해 생성한다. 텔레그램 앱에서 BotFather를 검색한 뒤 대화를 시작하면 된다.
봇 생성 절차:
① 텔레그램에서 @BotFather 검색 → /start 입력
② /newbot 입력 → 봇 이름(표시용) 입력 → 봇 username(고유, _bot으로 끝나야 함) 입력
③ 생성 완료 시 HTTP API 토큰이 발급된다. 이 토큰이 모든 API 호출의 핵심이다.
텔레그램 Bot API의 기본 엔드포인트는 다음과 같다:
https://api.telegram.org/bot{YOUR_BOT_TOKEN}/{METHOD_NAME}
여기서 METHOD_NAME에는 sendMessage, getUpdates, setWebhook 등 다양한 메서드가 들어간다. REST 스타일이라 HTTP GET/POST 요청만으로 모든 기능을 사용할 수 있다.
chat_id 확인 방법: 봇에게 아무 메시지나 보낸 뒤, 브라우저에서 아래 URL을 호출하면 chat_id를 확인할 수 있다.
https://api.telegram.org/bot{YOUR_BOT_TOKEN}/getUpdates
응답 JSON의 result[0].message.chat.id 값이 바로 메시지를 보낼 대상 chat_id다.
메시지 전송에는 크게 두 가지 방법이 있다. file_get_contents를 사용하는 간단한 방식과 cURL을 사용하는 실무 방식이다.
<?php
$token = 'YOUR_BOT_TOKEN';
$chat_id = 'YOUR_CHAT_ID';
$message = '서버 알림: 결제가 완료되었습니다.';
$url = "https://api.telegram.org/bot{$token}/sendMessage?"
. http_build_query([
'chat_id' => $chat_id,
'text' => $message,
]);
$result = file_get_contents($url);
echo $result;
이 방식은 빠르게 테스트할 때 유용하지만, allow_url_fopen이 꺼져 있는 서버에서는 동작하지 않고 타임아웃 제어도 어렵다.
<?php
function sendTelegramMessage(string $token, string $chatId, string $text, string $parseMode = ''): array
{
$url = "https://api.telegram.org/bot{$token}/sendMessage";
$params = [
'chat_id' => $chatId,
'text' => $text,
];
if ($parseMode !== '') {
$params['parse_mode'] = $parseMode; // 'HTML' 또는 'Markdown'
}
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $params,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return [
'http_code' => $httpCode,
'body' => json_decode($response, true),
];
}
// 사용 예시
$token = 'YOUR_BOT_TOKEN';
$chatId = 'YOUR_CHAT_ID';
$result = sendTelegramMessage(
$token,
$chatId,
"<b>서버 알림</b>n결제 ID: 20250101-0042n상태: ✅ 완료",
'HTML'
);
print_r($result);
위 코드의 출력 결과는 다음과 같은 형태다:
Array
(
[http_code] => 200
[body] => Array
(
[ok] => 1
[result] => Array
(
[message_id] => 15
[chat] => Array ( [id] => 123456789 ... )
[text] => 서버 알림 ...
)
)
)
봇이 메시지를 받으려면 두 가지 방식이 있다: getUpdates(폴링)와 Webhook(푸시). 실무에서는 서버 리소스를 아끼고 실시간 처리가 가능한 Webhook 방식을 쓴다.
HTTPS가 적용된 서버에 PHP 파일을 올린 뒤, 아래 URL을 브라우저에서 한 번만 호출하면 등록이 완료된다.
https://api.telegram.org/bot{YOUR_BOT_TOKEN}/setWebhook?url=https://yourdomain.com/telegram_webhook.php
성공하면 {"ok":true,"result":true,"description":"Webhook was set"}가 반환된다. 주의할 점은 반드시 HTTPS여야 한다는 것이다. 자체 서명 인증서(Self-signed)도 가능하지만 추가 설정이 필요하므로 Let's Encrypt 같은 무료 SSL을 쓰는 것이 편하다.
<?php
// telegram_webhook.php
$token = 'YOUR_BOT_TOKEN';
// 텔레그램이 보내는 JSON 데이터를 읽는다
$input = file_get_contents('php://input');
$update = json_decode($input, true);
if (!isset($update['message'])) {
exit; // 메시지가 아닌 업데이트는 무시
}
$chatId = $update['message']['chat']['id'];
$userName = $update['message']['from']['first_name'] ?? '사용자';
$text = $update['message']['text'] ?? '';
// 간단한 명령어 처리
switch ($text) {
case '/start':
$reply = "안녕하세요, {$userName}님! 봇이 정상 작동 중입니다.";
break;
case '/status':
$reply = "서버 상태: 정상nPHP 버전: " . PHP_VERSION . "n시간: " . date('Y-m-d H:i:s');
break;
default:
$reply = "입력하신 메시지: {$text}nn사용 가능한 명령어:n/start - 봇 시작n/status - 서버 상태 확인";
break;
}
// 응답 전송
sendTelegramMessage($token, $chatId, $reply);
function sendTelegramMessage(string $token, string $chatId, string $text): void
{
$ch = curl_init("https://api.telegram.org/bot{$token}/sendMessage");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => ['chat_id' => $chatId, 'text' => $text],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5,
]);
curl_exec($ch);
curl_close($ch);
}
| 구분 | ✗ 잘못된 방식 | ✓ 올바른 방식 |
|---|---|---|
| 토큰 관리 | 소스코드에 토큰을 하드코딩하고 Git에 커밋 | 환경변수나 별도 설정 파일(.env)로 분리, .gitignore에 추가 |
| Webhook URL | HTTP(비암호화) URL로 Webhook 등록 | 반드시 HTTPS URL 사용 (텔레그램이 HTTP를 거부함) |
| 에러 처리 | curl_exec 반환값을 확인하지 않고 넘어감 | HTTP 상태코드와 응답 body의 ok 필드를 확인하여 실패 시 로그 기록 |
| chat_id 타입 | chat_id를 int로만 처리 (그룹 채팅은 음수) | string으로 처리하거나 음수 값도 허용하도록 구현 |
| 메시지 길이 | 4096자 초과 메시지를 한 번에 전송 시도 | 4096자 단위로 잘라서 여러 번 전송 |
특히 Webhook을 등록한 뒤에는 getUpdates 메서드가 동작하지 않는다는 점을 기억해야 한다. 다시 폴링 방식으로 돌아가려면 Webhook을 해제해야 한다:
https://api.telegram.org/bot{YOUR_BOT_TOKEN}/deleteWebhook
또 하나 자주 빠지는 실수는 Webhook PHP 파일에서 200 OK를 반환하지 않는 경우다. 텔레그램은 200 응답을 받지 못하면 같은 업데이트를 반복 전송한다. PHP는 기본적으로 200을 반환하지만, 중간에 에러가 나서 500이 되면 무한 재전송에 빠질 수 있으니 try-catch 또는 조기 exit 처리를 해두자.
텔레그램 봇 API의 핵심 메서드를 정리하면 다음과 같다:
| 메서드 | 용도 | HTTP 방식 |
|---|---|---|
| sendMessage | 텍스트 메시지 전송 | POST |
| sendPhoto | 이미지 전송 | POST (multipart) |
| sendDocument | 파일 전송 | POST (multipart) |
| setWebhook | Webhook URL 등록 | GET/POST |
| deleteWebhook | Webhook 해제 | GET/POST |
| getUpdates | 폴링으로 업데이트 조회 (Webhook 미사용 시) | GET |
| getMe | 봇 정보 확인 | GET |
실무에서 가장 많이 쓰이는 패턴은 다음과 같다:
① 서버 모니터링 알림: 크론탭에서 헬스체크 스크립트를 돌리고, 이상 감지 시 sendMessage로 텔레그램 알림 발송
② 주문/결제 알림: 결제 완료 콜백에서 관리자 텔레그램으로 주문 정보 즉시 전송
③ 간단한 챗봇: Webhook으로 사용자 명령을 받아서 DB 조회 결과를 응답하는 관리용 봇
텔레그램 Bot API 연동은 외부 서비스 알림 중 가장 구현 비용이 낮으면서도 효과가 확실한 방법이다. 토큰 하나와 cURL 함수 하나면 바로 시작할 수 있다는 점이 핵심이고, Webhook까지 세팅하면 양방향 통신도 가능해진다. 이 글의 2단계 cURL 함수를 자신의 프로젝트 공통 유틸에 넣어두고, 필요한 곳에서 한 줄로 호출하는 습관을 들이면, 장애 대응 속도와 운영 편의성이 눈에 띄게 달라질 것이다.