개발자 문서
한국어

봇 개발

Bot API 레퍼런스

파발의 HTTP Bot API 가 받는 메서드와 주고받는 객체, 오류를 빠짐없이 정리했습니다. 텔레그램 Bot API 와 호환됩니다.

파발의 HTTP Bot API 는 텔레그램 Bot API 와 같은 주소 형식·요청·응답·오류를 씁니다. 이 문서는 파발이 실제로 받는 것만 적습니다. 여기 없는 메서드는 404 Not Found: method not found 를 돌려줍니다. 처음이라면 봇 만들기 튜토리얼부터 보세요.

요청 보내기

https://pabal.me/bot<토큰>/<메서드>
  • HTTP 메서드: GET 과 POST 모두 됩니다.
  • 파라미터를 보내는 네 가지 방법 — 쿼리 문자열(?chat_id=1&text=hi), application/x-www-form-urlencoded, application/json, 파일을 올릴 때 multipart/form-data. 섞어 써도 됩니다.
  • 객체 파라미터(reply_markup, commands, allowed_updates)는 JSON 본문에서는 객체·배열 그대로, 폼·쿼리에서는 JSON 문자열로 넣습니다.
  • 메서드 이름은 대소문자를 가리지 않습니다(sendMessage = sendmessage).
  • 본문 크기는 12MB 까지입니다(넘으면 413).
  • 파일 내려받기는 따로 https://pabal.me/file/bot<토큰>/<file_path> 입니다(getFile).

응답과 오류

응답은 늘 JSON 입니다. 성공이면 HTTP 200 과 result, 실패면 그 HTTP 상태와 같은 error_code, 사람이 읽을 description 이 옵니다.

{"ok": true, "result": { … }}
{"ok": false, "error_code": 400, "description": "Bad Request: chat not found"}
error_code언제description 예
400파라미터가 틀림Bad Request: chat not found, Bad Request: message text is empty, Bad Request: message is not modified: …, Bad Request: message to edit not found, Bad Request: wrong file identifier/HTTP URL specified, Bad Request: query is too old and response timeout expired or query ID is invalid
401토큰이 틀림Unauthorized
403보낼 권한이 없음Forbidden: bot can't initiate conversation with a user, Forbidden: bot is not a member of the group chat
404없는 메서드·파일Not Found: method not found
409웹훅이 있는데 getUpdatesConflict: can't use getUpdates method while webhook is active; use deleteWebhook to delete the webhook first
413본문이 12MB 를 넘음Request Entity Too Large
500서버 내부 오류Internal Server Error

파발은 아직 요청 전체의 속도 제한을 두지 않지만, 음성 메서드에는 한 시간 한도가 있어 429 Too Many Requests: retry after N 이 옵니다(음성 통화). 429 를 받으면 parameters.retry_after 초만큼 기다렸다 다시 보내도록 짜 두세요.

업데이트 받기

두 방법 중 하나를 씁니다. 동시에 쓸 수는 없습니다.

getUpdates

POST/bot<토큰>/getUpdates

기다리는 업데이트를 가져옵니다(롱 폴링). 웹훅이 설정돼 있으면 409.

파라미터타입필수설명
offsetInteger선택이 번호 이상의 업데이트만. 이보다 작은 것은 "받았음"으로 지워집니다. 처리한 마지막 update_id + 1 을 주세요.
limitInteger선택1~100, 기본 100
timeoutInteger선택기다릴 초, 0~50, 기본 0. 25~30 을 권합니다.
allowed_updatesArray of String선택받을 종류(Update). 비우면 기본 종류(message, edited_message, callback_query) 전부. 음성 종류는 이름을 적어야만 옵니다. 준 목록은 봇의 설정으로 남아 다음 호출과 웹훅에도 쓰입니다(주지 않으면 이전 값 그대로)

돌려주는 것: Array of Update

setWebhook

POST/bot<토큰>/setWebhook

업데이트를 HTTPS 주소로 받습니다. 자세한 설명은 웹훅 문서에 있습니다.

파라미터타입필수설명
urlString예https:// 공인 주소. 빈 문자열이면 웹훅을 지움
secret_tokenString선택1~256자, A-Z a-z 0-9 _ -. 요청 헤더 X-Telegram-Bot-Api-Secret-Token 로 보냄
allowed_updatesArray of String선택message, edited_message, callback_query 중에서. 비우면 이 셋 전부. 음성 종류(voice_call, voice_call_tool_query, voice_call_transcript)는 이름을 적어야만 옵니다. 주지 않으면 이전 값 그대로
drop_pending_updatesBoolean선택기다리던 업데이트를 버림
max_connectionsInteger선택1~100, 기본 40. 보관만 하고, 전달은 봇마다 한 번에 하나씩
certificateInputFile안 됨400 — 공인 인증서를 쓰세요
ip_addressString무시

돌려주는 것: True

deleteWebhook

POST/bot<토큰>/deleteWebhook

웹훅을 지우고 getUpdates 로 돌아갑니다. 웹훅이 없어도 성공합니다.

파라미터타입필수설명
drop_pending_updatesBoolean선택기다리던 업데이트를 버림

돌려주는 것: True

getWebhookInfo

GET/bot<토큰>/getWebhookInfo

웹훅 상태. 파라미터 없음. 웹훅이 없으면 url 이 빈 문자열입니다.

돌려주는 것: WebhookInfo

메서드

메서드하는 일
getMe봇 자신의 정보
sendMessage글 보내기 (버튼 포함)
sendPhoto사진 보내기
sendDocument파일 보내기
sendLocation위치 보내기 (실시간 위치 포함)
sendVenue장소 보내기 (이름과 주소가 붙은 위치)
sendContact연락처 카드 보내기
editMessageLiveLocation · stopMessageLiveLocation실시간 위치 옮기기·멈추기
editMessageText보낸 메시지의 글·버튼 고치기
editMessageCaption사진 설명 고치기
editMessageReplyMarkup버튼만 고치기
deleteMessage메시지 지우기
answerCallbackQuery버튼 누름에 답하기
sendChatAction"입력 중" 표시 (받기만 함)
getChat대화 정보
getFile받은 사진의 내려받기 경로
setMyCommands · getMyCommands · deleteMyCommands명령어 메뉴
logOut · close호환용 (아무 일도 하지 않음)
getUpdates · setWebhook · deleteWebhook · getWebhookInfo업데이트 받기 (위)
setVoiceCallSettings · getVoiceCallSettings · endVoiceCall · sendVoiceCallContext · getVoiceCallUsage · startVoiceCall · answerVoiceCallToolQuery · setVoiceCallApiKey · setVoiceCallMcpServer …음성 봇 (아래 음성 통화)
chat_id 에 넣을 수 있는 것

1:1 대화면 사람의 ID(양수), 기본 그룹이면 그룹 ID(음수), 또는 사람의 사용자명("@hana_lee"). 모두 업데이트의 chat.id 로 알 수 있습니다. 채널·슈퍼그룹 ID(-100…)는 아직 없습니다(400 chat not found).

getMe

GET/bot<토큰>/getMe

토큰이 맞는지 확인할 때 씁니다. 파라미터 없음.

돌려주는 것: User — 봇에게는 can_join_groups(true), can_read_all_group_messages(true), supports_inline_queries(false), can_connect_to_business(false), has_main_web_app(false) 가 더 붙습니다.

sendMessage

POST/bot<토큰>/sendMessage

파라미터타입필수설명
chat_idInteger 또는 String예보낼 대화 (위 상자 참고)
textString예1~4,096자. 글자 그대로 보냅니다
reply_markupInlineKeyboardMarkup · ReplyKeyboardMarkup · ReplyKeyboardRemove · ForceReply선택버튼
disable_notificationBoolean선택소리 없이 보내기
parse_mode, entities, reply_parameters, link_preview_options …무시받지만 쓰지 않습니다. 서식은 적용되지 않습니다

돌려주는 것: 보낸 Message

사람에게 보내려면 그 사람이 먼저 봇에게 말을 걸었어야 합니다(403 Forbidden: bot can't initiate conversation with a user). 그룹에 보내려면 봇이 그 그룹의 멤버여야 합니다.

sendPhoto

POST/bot<토큰>/sendPhoto

파라미터타입필수설명
chat_idInteger 또는 String예보낼 대화
photoInputFile 또는 String예multipart/form-data 로 올린 파일(10MB 까지, JPEG·PNG·GIF), 또는 전에 받은 사진의 file_id. URL 은 아직 안 됨
captionString선택0~1,024자
reply_markupsendMessage 와 같음선택
disable_notificationBoolean선택

돌려주는 것: 보낸 Message (photo 에 새 file_id)

sendDocument

POST/bot<토큰>/sendDocument

파라미터타입필수설명
chat_idInteger 또는 String예보낼 대화
documentInputFile 또는 String예multipart/form-data 로 올린 파일(형식 제한 없음, 20MB 까지), 또는 전에 받은 파일의 file_id. URL 은 아직 안 됨
filenameString선택받는 쪽에 보일 이름. 없으면 올린 파일의 이름을 씁니다
captionString선택0~1,024자
reply_markupsendMessage 와 같음선택
disable_notificationBoolean선택
thumbnail, disable_content_type_detection무시받지만 쓰지 않습니다

돌려주는 것: 보낸 Message (document 에 새 file_id)

형식(mime_type)은 파일 이름의 확장자에서 정합니다. 앱 쪽에서 보낸 파일은 2GB 까지지만, 봇이 HTTP 로 올리거나 내려받는 것은 텔레그램과 같이 20MB 까지입니다.

sendLocation

POST/bot<토큰>/sendLocation

파라미터타입필수설명
chat_idInteger 또는 String예보낼 대화
latitude, longitudeFloat예위도(−90~90)와 경도(−180~180). 벗어나면 400 Bad Request: GEO_POINT_INVALID
horizontal_accuracyFloat선택오차 반경(미터, 0~1,500). 반올림해 정수로 저장합니다
live_periodInteger선택주면 실시간 위치가 됩니다: 60~86,400초, 또는 멈출 때까지 2147483647(0x7FFFFFFF). 그 밖의 값은 400 Bad Request: wrong live_period
headingInteger선택실시간 위치의 진행 방향, 1~360도
proximity_alert_radiusInteger선택실시간 위치의 접근 알림 반경(미터). 저장하고 보여 주지만 알림은 아직 보내지 않습니다
reply_markupsendMessage 와 같음선택
disable_notificationBoolean선택

돌려주는 것: 보낸 Message (location 에 Location)

sendVenue

POST/bot<토큰>/sendVenue

파라미터타입필수설명
chat_idInteger 또는 String예보낼 대화
latitude, longitudeFloat예장소의 위치 (sendLocation 과 같음)
titleString예장소 이름
addressString예주소
foursquare_id, foursquare_typeString선택Foursquare 의 장소 ID 와 종류. 받은 그대로 전합니다
google_place_id, google_place_typeString선택Google 장소 ID 와 종류. foursquare_id 가 없을 때만 씁니다
reply_markupsendMessage 와 같음선택
disable_notificationBoolean선택

돌려주는 것: 보낸 Message (venue 에 Venue, location 에도 같은 위치)

title 이나 address 가 없으면 400 Bad Request: title and address are required 입니다.

sendContact

POST/bot<토큰>/sendContact

파라미터타입필수설명
chat_idInteger 또는 String예보낼 대화
phone_numberString예전화번호. 적힌 그대로 전합니다
first_nameString예이름
last_nameString선택성
vcardString선택vCard 형식의 추가 정보, 64KB 까지
reply_markupsendMessage 와 같음선택
disable_notificationBoolean선택

돌려주는 것: 보낸 Message (contact 에 Contact)

봇이 보낸 연락처 카드에는 user_id 가 붙지 않습니다. 번호가 파발 계정의 것이어도 그렇습니다 — 봇에게는 연락처가 없고, 붙여 주면 번호마다 한 번씩 불러 그 번호가 누구의 것인지 알아낼 수 있기 때문입니다. phone_number 나 first_name 이 없으면 400 Bad Request: phone_number and first_name are required 입니다.

editMessageLiveLocation

POST/bot<토큰>/editMessageLiveLocation

파라미터타입필수설명
chat_idInteger 또는 String예메시지가 있는 대화
message_idInteger예옮길 실시간 위치 (봇이 보낸 것)
latitude, longitudeFloat예새 위치
horizontal_accuracyFloat선택오차 반경(미터, 0~1,500)
headingInteger선택진행 방향, 1~360도
proximity_alert_radiusInteger선택접근 알림 반경(미터). 0 이면 끕니다
live_periodInteger선택새 공유 기간: 메시지를 보낸 시각부터 센 초. 지금 기간보다 하루 넘게 늘릴 수는 없고, 2147483647 이면 멈출 때까지
reply_markupInlineKeyboardMarkup선택새 버튼
inline_message_idString안 됨인라인 모드가 없어 400

돌려주는 것: 고친 Message

이미 끝난 실시간 위치 — 멈췄거나 기간이 다 된 것 — 는 옮길 수도, 기간을 늘려 되살릴 수도 없습니다(400 Bad Request: message can't be edited). 실시간 위치가 아닌 메시지도 마찬가지입니다.

마지막으로 반영된 이동에서 10초가 지나지 않았거나 10m 도 움직이지 않은 이동은 서버가 저장하지 않고 넘깁니다. 멈추기와 기간·알림 반경의 변경은 언제나 반영됩니다. 넘긴 경우 돌려주는 Message 는 마지막으로 반영된 위치를 보여 주므로, 몇 초마다 보내도 괜찮습니다.

stopMessageLiveLocation

POST/bot<토큰>/stopMessageLiveLocation

파라미터는 chat_id, message_id, reply_markup(선택). 실시간 위치를 마지막 자리에서 멈춥니다. 공유 기간이 실제로 흐른 시간으로 줄어들어 모든 앱이 끝난 위치로 그립니다. 이미 멈췄거나 끝났으면 400 Bad Request: message is not modified: … 입니다. 돌려주는 것: 고친 Message.

editMessageText

POST/bot<토큰>/editMessageText

파라미터타입필수설명
chat_idInteger 또는 String예메시지가 있는 대화
message_idInteger예고칠 메시지 (봇이 보낸 것)
textString예새 글, 1~4,096자
reply_markupInlineKeyboardMarkup선택새 버튼. 빼면 버튼이 없어집니다(텔레그램과 같음)
inline_message_idString안 됨인라인 모드가 없어 400

돌려주는 것: 고친 Message. 앱에는 바로 반영되고, 사람이 고친 메시지는 봇에게 edited_message 로 옵니다.

글과 버튼이 전과 똑같으면 400 Bad Request: message is not modified: …, 남의 메시지를 고치려 하면 400 Bad Request: message can't be edited 입니다.

editMessageCaption

POST/bot<토큰>/editMessageCaption

파라미터는 chat_id, message_id, caption(0~1,024자, 빼면 설명을 지움), reply_markup. 돌려주는 것: 고친 Message.

editMessageReplyMarkup

POST/bot<토큰>/editMessageReplyMarkup

글은 그대로 두고 버튼만 바꿉니다. 파라미터는 chat_id, message_id, reply_markup(빼면 버튼을 지움). 돌려주는 것: 고친 Message.

deleteMessage

POST/bot<토큰>/deleteMessage

파라미터는 chat_id, message_id. 메시지를 대화의 양쪽에서 지웁니다. 없는 메시지면 400 Bad Request: message to delete not found. 돌려주는 것: True.

answerCallbackQuery

POST/bot<토큰>/answerCallbackQuery

사람이 누른 버튼(CallbackQuery)에 답합니다. 10초 안에, 한 번만 답할 수 있습니다.

파라미터타입필수설명
callback_query_idString예업데이트의 callback_query.id
textString선택화면 위에 잠깐 뜨는 문구
show_alertBoolean선택true 면 확인 버튼이 있는 창으로
urlString선택앱이 열 주소
cache_timeInteger선택앱이 이 답을 기억할 초

돌려주는 것: True. 너무 늦었거나 이미 답했으면 400 Bad Request: query is too old and response timeout expired or query ID is invalid.

sendChatAction

POST/bot<토큰>/sendChatAction

호환을 위해 받고 True 를 돌려주지만, 아직 앱에 "입력 중…" 을 표시하지는 않습니다.

getChat

GET/bot<토큰>/getChat?chat_id=…

파라미터는 chat_id(숫자). 사람이면 그 사람, 그룹이면 봇이 멤버인 그룹만. 돌려주는 것: Chat. 없거나 볼 수 없으면 400 Bad Request: chat not found.

getFile

GET/bot<토큰>/getFile?file_id=…

받은 사진의 file_id 로 내려받을 경로를 얻습니다. 돌려주는 것: File. 그다음 이 주소로 내려받습니다.

https://pabal.me/file/bot<토큰>/<file_path>

file_id 는 그 사진을 가져갈 권리이기도 합니다. 잘못된 값이면 400 Bad Request: wrong file identifier/HTTP URL specified.

setMyCommands

POST/bot<토큰>/setMyCommands

파라미터타입필수설명
commandsArray of BotCommand예최대 100개
language_codeString선택언어별 목록으로 저장. 앱에는 지금 언어 코드 없는 기본 목록만 보입니다
scopeBotCommandScope무시

돌려주는 것: True. 규칙에 맞지 않으면 아무것도 저장하지 않고 400 Bad Request: BOT_COMMAND_INVALID(명령어), BOT_COMMAND_DESCRIPTION_INVALID(빈 설명이나 256자 초과), BOT_COMMANDS_TOO_MUCH(100개 초과).

getMyCommands

GET/bot<토큰>/getMyCommands

파라미터는 language_code(선택). 돌려주는 것: Array of BotCommand.

deleteMyCommands

POST/bot<토큰>/deleteMyCommands

파라미터는 language_code(선택). 그 목록을 비웁니다. 돌려주는 것: True.

logOut · close

텔레그램에서는 로컬 Bot API 서버로 옮길 때 쓰는 메서드입니다. 파발에는 옮길 곳이 없으므로 받기만 하고 True 를 돌려줍니다. 토큰을 무효로 하려면 BotFather 의 /revoke 를 쓰세요.

객체

필드 옆 선택 은 없을 수도 있다는 뜻입니다. 여기 없는 텔레그램의 다른 필드는 파발이 보내지 않습니다.

Update

새 소식 하나. update_id 와 아래 가운데 하나가 들어 있습니다.

필드타입설명
update_idInteger1씩 커지는 번호. getUpdates 의 offset 에 씁니다
message 선택Message봇에게 온 새 메시지 (1:1, 또는 봇이 멤버인 그룹의 모든 메시지)
edited_message 선택Message고쳐진 메시지
callback_query 선택CallbackQuery인라인 버튼 누름
voice_call 선택VoiceCall음성 봇에 온 통화와 봇이 건 전화의 시작·끝 (이름으로 청해야 옴)
voice_call_tool_query 선택VoiceCallToolQuery통화 중 모델이 부른 봇의 도구 (이름으로 청해야 옴)
voice_call_transcript 선택VoiceCallTranscript통화 중 대화 기록의 한 마디 (이름으로 청해야 옴)

User

필드타입설명
idInteger사용자 ID (이 서버 안에서만 뜻이 있음)
is_botBoolean봇이면 true
first_nameString이름. 지워진 계정이면 Deleted Account
last_name 선택String성
username 선택String사용자명 (@ 없이)

Chat

필드타입설명
idInteger사람이면 그 사람의 ID(양수), 기본 그룹이면 음수
typeStringprivate 또는 group
title 선택String그룹 이름 (group)
first_name, last_name, username 선택String상대의 이름·사용자명 (private)

Message

필드타입설명
message_idInteger이 대화 안의 메시지 번호
from 선택User보낸 사람
chatChat메시지가 있는 대화
dateInteger보낸 시각 (유닉스 초)
edit_date 선택Integer마지막으로 고친 시각
text 선택String글 (사진·파일·위치·장소·연락처 메시지가 아니면 늘 있음)
entities 선택Array of MessageEntity글 속의 명령·멘션·URL·해시태그
photo 선택Array of PhotoSize사진 (파발은 원본 하나)
document 선택Document파일
location 선택Location위치나 실시간 위치. 장소 메시지에도 그 위치가 함께 옵니다
venue 선택Venue장소
contact 선택Contact연락처 카드
caption 선택String사진 설명
caption_entities 선택Array of MessageEntity설명 속의 명령·멘션·URL·해시태그
reply_markup 선택InlineKeyboardMarkup메시지에 달린 인라인 버튼

MessageEntity

필드타입설명
typeStringbot_command, mention, url, hashtag
offsetInteger시작 위치 (UTF-16 코드 단위)
lengthInteger길이 (UTF-16 코드 단위)

서버가 글에서 자동으로 찾아 붙입니다. 굵게·기울임 같은 서식 엔티티는 아직 없습니다.

PhotoSize

필드타입설명
file_idString내려받기(getFile)와 다시 보내기(sendPhoto)에 쓰는 ID
file_unique_idString같은 사진이면 봇이 달라도 같은 값. 내려받기에는 못 씀
width, heightInteger픽셀 크기
file_sizeInteger바이트

Document

필드타입설명
file_idString내려받기(getFile)와 다시 보내기(sendDocument)에 쓰는 ID
file_unique_idString같은 파일이면 봇이 달라도 같은 값. 내려받기에는 못 씀
file_nameString보낸 쪽이 준 이름
mime_typeString보낸 쪽이 말한 형식
file_sizeInteger바이트

Location

필드타입설명
latitude, longitudeFloat위도와 경도
horizontal_accuracy 선택Float오차 반경(미터)
live_period 선택Integer실시간 위치의 공유 기간: 메시지를 보낸 시각부터 센 초. 멈추면 실제로 흐른 시간으로 줄어듭니다
heading 선택Integer진행 방향, 1~360도
proximity_alert_radius 선택Integer접근 알림 반경(미터)

사람이 공유하는 실시간 위치는 서버가 반영할 때마다 edited_message 로 다시 옵니다.

Venue

필드타입설명
locationLocation장소의 위치
titleString장소 이름
addressString주소
foursquare_id, foursquare_type 선택StringFoursquare 의 장소 ID 와 종류
google_place_id, google_place_type 선택StringGoogle 장소 ID 와 종류

Contact

필드타입설명
phone_numberString보낸 쪽이 적은 그대로의 번호
first_nameString이름
last_name 선택String성
user_id 선택Integer그 번호의 파발 계정. 보낸 사람이 자기 연락처에 저장해 둔 사람이거나 자기 자신일 때만 붙습니다
vcard 선택StringvCard 형식의 추가 정보

File

필드타입설명
file_id, file_unique_idStringPhotoSize 와 같음
file_sizeInteger바이트
file_pathStringphotos/<file_id>.jpg 또는 documents/<file_id> 꼴. /file/bot<토큰>/ 뒤에 붙여 내려받습니다

CallbackQuery

필드타입설명
idStringanswerCallbackQuery 에 줄 ID
fromUser버튼을 누른 사람
message 선택Message버튼이 달린 메시지
chat_instanceString그 대화를 나타내는 값
data 선택String버튼의 callback_data

InlineKeyboardMarkup

inline_keyboard: Array of Array of InlineKeyboardButton — 바깥 배열이 줄, 안쪽 배열이 한 줄의 버튼입니다. 한 메시지에 최대 100줄·100개.

InlineKeyboardButton

필드타입설명
textString버튼 글자
callback_data 둘 중 하나String누르면 봇에게 가는 값, 1~64바이트
url 둘 중 하나String누르면 열 주소

switch_inline_query, web_app, login_url, pay 같은 다른 종류는 아직 없습니다(400).

ReplyKeyboardMarkup

필드타입설명
keyboardArray of Array of KeyboardButton입력창 아래 버튼 판
resize_keyboard, one_time_keyboard, is_persistent, selective 선택Boolean크기 맞춤 · 한 번 쓰면 숨김 · 늘 보임 · 특정 사람에게만
input_field_placeholder 선택String입력창 안내 글자

KeyboardButton

문자열 하나, 또는 text 와 선택 필드 request_contact(내 연락처 보내기)·request_location(내 위치 보내기, Boolean)를 가진 객체.

ReplyKeyboardRemove

{"remove_keyboard": true} — 버튼 판을 숨깁니다. selective 선택.

ForceReply

{"force_reply": true} — 앱이 이 메시지에 답장하는 상태로 입력창을 엽니다. selective, input_field_placeholder 선택.

BotCommand

필드타입설명
commandString영소문자·숫자·밑줄 1~32자 (/ 없이)
descriptionString1~256자

WebhookInfo

필드타입설명
urlString웹훅 주소, 없으면 빈 문자열
has_custom_certificateBoolean늘 false
pending_update_countInteger전달을 기다리는 업데이트 수
ip_address 선택String마지막으로 보낸 IP
last_error_date 선택Integer마지막 실패 시각 (유닉스 초)
last_error_message 선택String마지막 실패 이유 (목록)
max_connections 선택IntegersetWebhook 에 준 값
allowed_updates 선택Array of StringsetWebhook 에 준 값

음성 통화

파발에만 있는 메서드입니다. 음성 봇은 사람이 앱에서 전화를 걸면 AI 음성 모델이 받는 봇이고, 이 메서드들로 그 모델의 설정을 정하고 통화를 다룹니다. 무엇이 켜져 있어야 하는지, 켜는 법과 예제는 음성 봇 안내에 있습니다. 메서드는 음성이 꺼진 서버에도 있어 설정을 읽을 수 있지만, 음성이 꺼졌거나 운영자가 아직 허용하지 않은 봇은 끄기와 지우기 말고는 설정을 바꿀 수 없습니다(403 VOICE_NOT_AVAILABLE).

setVoiceCallSettings

POST/bot<토큰>/setVoiceCallSettings

봇의 음성 설정을 바꿉니다. 보낸 것만 바뀌고, 전체를 검사한 뒤 한 번에 쓰거나 전부 거절합니다. 봇마다 한 시간 30번(@BotFather 와 합쳐서).

파라미터타입필수설명
enabledBoolean선택켜기는 @BotFather 에서 음성 봇 규칙에 동의한 뒤에만(403 VOICE_RULES_NOT_ACCEPTED). 끄기는 언제나
instructionsString선택모델의 지시문, 8,192바이트까지. "" 는 지움(켜진 관리형 봇은 안 됨)
greetingString선택첫 인사, 512바이트까지. "" 면 모델이 알아서
voiceString선택목소리 id, 기본 kore (목록)
languageString선택ko-KR(기본) · en-US · ja-JP · cmn-CN · fr-FR · es-US · id-ID · vi-VN · ar-EG (목록). 대소문자를 가리지 않고, zh-CN 은 cmn-CN 으로 저장합니다. 한국어·영어가 아닌 봇은 운영자가 지시문·인사말을 읽고 허용한 뒤에 전화를 받습니다
max_call_durationInteger선택초, 60 ~ limits.max_call_duration
max_concurrent_callsInteger선택1 ~ limits.max_concurrent_calls
toolsArray of VoiceCallTool선택통화 중 모델이 부를 봇의 도구: {"name", "description", "parameters"?, "timeout_ms"?}. 규칙은 도구 정하기. 폼에서는 JSON 문자열
transcriptBoolean선택대화 기록 스위치. 켜기는 봇 주인 약관 뒤에만
modeString선택managed(파발의 AI 모델) 또는 stream(원음 모드)
stream_url, stream_secretString선택mode=stream 과 함께. 비밀은 요청 본문으로만

돌려주는 것: True

getVoiceCallSettings

GET/bot<토큰>/getVoiceCallSettings

파라미터 없음. 지금 설정과, 봇이 지금 전화를 받을 수 있는지(available, unavailable_reason), 서버의 한도, 목소리와 언어 목록, 도구 질의·대화 기록이 갈 곳, 자기 키·원음 모드·MCP 서버의 상태. 키와 비밀은 나오지 않고 지문만 나옵니다. 필드는 음성 봇 — 지금 설정 보기에 있습니다.

돌려주는 것: VoiceCallSettings (객체)

endVoiceCall

POST/bot<토큰>/endVoiceCall

파라미터타입필수설명
voice_call_idString예voice_call.id
farewellBoolean선택기본 true: 모델이 짧게 작별 인사를 하고 끊음(10초 안에 안 끊기면 서버가 끝냄). false 면 바로

돌려주는 것: True. 이 봇의 살아 있는 통화가 아니면 400 VOICE_CALL_NOT_FOUND.

sendVoiceCallContext

POST/bot<토큰>/sendVoiceCallContext

파라미터타입필수설명
voice_call_idString예켜져 있는 통화
textString예모델에게 주는 봇 주인의 메모. 2,000자·6,144바이트까지, 내용 규칙 검사
respondBoolean선택기본 false. true 면 모델이 곧바로 반응

돌려주는 것: True. 연결 전 VOICE_CALL_NOT_ACTIVE, 원음 통화 VOICE_CONTEXT_NOT_SUPPORTED, 너무 김 VOICE_CONTEXT_TOO_LONG, 통화마다 1분에 10개를 넘으면 429.

getVoiceCallUsage

GET/bot<토큰>/getVoiceCallUsage

파라미터타입필수설명
periodString선택today(기본) 또는 month
monthString선택YYYY-MM, period=month 와 함께만

돌려주는 것: period, from_date, to_date, calls, seconds, missed, refused(busy·budget·unavailable), platform_seconds, own_key_seconds, remaining_seconds_today(bot·owner), 발신을 켠 적이 있는 봇이면 outbound(today·limits) — 날짜 경계는 서버의 시간대

startVoiceCall

POST/bot<토큰>/startVoiceCall

봇이 사람에게 전화를 겁니다. 봇 주인이 @BotFather 에서 켜고 운영자가 검토한 봇이, 그 봇에게 전화를 허락한 사람에게만 걸 수 있습니다. 답과 판정은 음성 봇 — 걸기에 있습니다.

파라미터타입필수설명
user_idInteger예걸 사람
purposeString예reminder, wake_up, delivery, appointment 가운데 봇이 고른 것
contextString예모델에게만 주는 안내, 1,000자·3,072바이트까지, 내용 규칙 검사
max_durationInteger선택받은 뒤 최대 초, 30 ~ 300(봇의 상한까지). 기본 180
ring_timeoutInteger선택울리는 초, 30 ~ 45. 기본 40

돌려주는 것: {"voice_call_id": "…"} — 받아들였다는 뜻일 뿐이고, 울렸는지·받았는지는 voice_call 업데이트로 옵니다. 거절은 403 VOICE_OUTBOUND_OFF: <까닭>, 403 USER_UNAVAILABLE(늘 같은 몸), 429, 503 VOICE_UNAVAILABLE. 웹훅 응답으로는 부를 수 없습니다.

answerVoiceCallToolQuery

POST/bot<토큰>/answerVoiceCallToolQuery

파라미터타입필수설명
tool_query_idString예VoiceCallToolQuery 의 id
resultString · Object · Array둘 중 하나도구의 결과, 16,384바이트까지
errorString둘 중 하나봇의 실패 문구, 512바이트까지

돌려주는 것: True. 첫 답이 마지막입니다. 늦으면 400 TOOL_QUERY_EXPIRED: answered|timeout|cancelled|call_ended|unreachable, 모르는 id 는 TOOL_QUERY_ID_INVALID, 답이 거절되면 TOOL_RESULT_EMPTY·TOOL_RESULT_INVALID·TOOL_RESULT_TOO_LONG·TOOL_ERROR_TOO_LONG·TOOL_RESULT_REFUSED: <코드>. 웹훅의 도구 질의 POST 에는 응답 본문으로도 답할 수 있습니다.

setVoiceCallApiKey · deleteVoiceCallApiKey

POST/bot<토큰>/setVoiceCallApiKey

파라미터타입필수설명
providerString예google(Vertex AI 서비스 계정 JSON 키) 또는 openai(sk-…)
api_keyString예키. 요청 본문으로만(쿼리면 400), 8KiB 까지

돌려주는 것: True — 게이트웨이의 시험 세션을 통과한 뒤에만 보관합니다. API_KEY_INVALID, API_KEY_NO_REALTIME_ACCESS, 503 API_KEY_CHECK_UNAVAILABLE(보관하지 않음), 403 VOICE_OWN_KEY_NOT_AVAILABLE(이 서버는 자기 키를 받지 않음). deleteVoiceCallApiKey 는 파라미터 없이 언제나 True. 두 메서드 모두 bots.sendCustomRequest 로는 부를 수 없고, setVoiceCallApiKey 는 웹훅 응답으로도 부를 수 없습니다. 자세한 것은 자기 모델 키.

MCP 서버 메서드

메서드파라미터돌려주는 것
setVoiceCallMcpServerlabel, url, auth(객체), 선택 audience, allowed_tools, requested_level, timeout_ms, tools(분류 덧씌우기), declaration, auto_repin등록 결과(status, job_id). 받는 곳이 바뀌면 400 MCP_CHANGE_NEEDS_CONFIRMATION 뒤 @BotFather 에서 확인
refreshVoiceCallMcpServerlabel다시 검사(refreshing: true, job_id)
deleteVoiceCallMcpServerlabelTrue — MCP 가 꺼져 있어도 됨
getVoiceCallMcpBinding없음iss, sub(bot:<id>), issuer_document, jwks_uri, audiences
createVoiceCallMcpClientKeylabel공개 jwk, thumbprint (개인 키는 파발 밖으로 나오지 않음)

auth 와 비밀은 요청 본문으로만 보냅니다. MCP 가 꺼진 서버에서는 403 VOICE_NOT_AVAILABLE: MCP tools are not available on this server. 자세한 것은 음성 봇 — MCP 서버.

음성 업데이트를 받으려면

voice_call, voice_call_tool_query, voice_call_transcript 는 이름으로 청해야만 옵니다 — getUpdates 나 setWebhook 의 allowed_updates 에 적으세요. 빈 목록으로는 오지 않고, 청하기 전에 일어난 것은 쌓이지 않습니다. 도구 질의는 웹훅이 있으면 따로 보내는 POST 로, 최근 15초 안에 getUpdates 를 불렀으면 다음 getUpdates 의 맨 앞에 옵니다.

VoiceCall

필드타입설명
idString통화 id (부호 없는 10진수)
directionStringincoming(봇에게 온 전화) 또는 outgoing(봇이 건 전화). 늘 있음
eventStringstarted, ended, missed, refused, 봇이 건 전화는 started, ended, not_answered, failed
from 선택User봇에게 온 전화만 — 발신자: id, is_bot, first_name, last_name, language_code. 사용자명과 전화번호는 없음
to 선택Object봇이 건 전화만 — {"id": …}, 받는 사람의 id 하나
purpose 선택String봇이 건 전화만 — 요청의 목적
dateInteger일어난 시각 (유닉스 초). started 는 앱의 통화면 키 교환이 끝났을 때, 애플 워치의 통화면 워치의 소리가 연결됐을 때. ended 는 대화 기록을 기다리거나 대화 남기기가 켜진 서버면 최대 10초 늦게 옵니다. 봇이 건 전화는 서버 설정과 상관없이, 받은 통화의 ended 가 게이트웨이의 사용량을 기다리느라 최대 10초 늦게 옵니다
max_duration 선택Integer이 통화의 최대 길이(초) — started, ended
start_date, duration 선택Integer켜진 시각과 켜져 있던 초(서버 시계) — ended
end_reason 선택Stringcaller(봇이 건 전화는 callee), bot, max_length, failed, operator, suspended — ended, missed
refused_reason 선택Stringbusy, budget, unavailable — refused
transcript 선택Object{"turns": [{"role", "text", "offset_ms"}], "truncated"} — ended, 대화 기록이 켜졌을 때. 봇이 건 전화에는 없음

VoiceCall 에는 발신자가 대화 남기기를 골랐는지 알려 주는 필드가 없습니다. 의도한 것입니다 — 그 글은 발신자 자신의 것이고 봇에게 가지 않습니다. 그래서 대화 남기기가 켜진 서버에서는 원음 모드가 아닌 모든 통화의 ended 가 같은 만큼 기다리고, 통화 기록 다음 메시지 번호도 모든 통화에서 기록보다 31 이상 큽니다(번호를 미리 잡아 둠).

VoiceCallToolQuery

필드타입설명
idStringanswerVoiceCallToolQuery 에 줄 id
voice_call_idString통화 id
fromUser발신자 (VoiceCall 과 같은 필드)
nameString도구 이름
argumentsString인자, JSON 객체의 텍스트(서버가 검사함)
budget_msInteger받은 때부터 답이 서버에 닿아야 할 때까지의 밀리초

VoiceCallTranscript

필드타입설명
voice_call_idString통화 id
seqInteger마디 번호
roleStringcaller 또는 bot
textStringAI 가 적은 글. 카드·주민등록번호가 들면 숫자를 * 로
is_finalBoolean늘 true
offset_ms, dateInteger통화 소리가 시작된 때부터의 밀리초, 시각

HTTP Bot API 로만 옵니다. 통화 전체는 끝난 voice_call 의 transcript 에 있습니다.

원음 모드 (mode=stream)

원음 모드에서는 통화의 소리가 파발의 AI 모델 대신 봇 주인의 서버로 갑니다. setVoiceCallSettings 에 mode=stream, stream_url=wss://…, stream_secret=…(32~128자 출력 가능한 ASCII, 요청 본문으로만)을 보내면, 파발의 게이트웨이가 그 주소에 한 번 접속해 보고(사전 시험) 성공하면 켜집니다. 봇 주인 약관과, 원음 확인 창이 든 앱 빌드가 필요합니다. 설정·사전 시험 결과·예제는 음성 봇 — 원음 모드에 있습니다.

  • 연결: TLS 1.2 이상, URL 의 이름에 맞는 공인 인증서, 서브프로토콜 pabal.voice.v1, 압축 없음, 한 메시지 64KiB·글 4KiB 까지, 리다이렉트 없음.
  • 서명: X-Pabal-Voice-Signature: t=…,nonce=…,call=…,v1=HMAC-SHA256(stream_secret, "pabal-voice-stream/1\n<t>\n<nonce>\n<call>\n<host>\n<path?query>"). host 는 내가 알린 URL 의 호스트. 300초·nonce 한 번·바이트 비교·start.call_id 가 call 과 같은지 확인(자세히).
  • 소리: 글 메시지는 JSON 이벤트, 바이너리는 PCM16 little-endian·모노·24 kHz. 발신자 소리는 20 ms(960바이트) 조각.
  • 파발 → 봇: start(한 번) · live(AI 안내가 끝남) · 소리 · mark · cleared · buffer_full · stop(→ 닫기 1000).
  • 봇 → 파발: ready(start 뒤 3초 안, 맨 먼저) · 소리(live 뒤) · clear · mark · hangup.

메시지 하나하나의 모양은 음성 봇 — 규격 표에 있습니다.

음성 메서드의 오류

음성 메서드의 오류 코드와 뜻은 음성 봇 — 오류에 모아 두었습니다. 403 은 Forbidden: <코드>: <설명> 꼴이고(VOICE_RULES_NOT_ACCEPTED, VOICE_NOT_AVAILABLE, VOICE_SUSPENDED, VOICE_OWNER_TERMS_NOT_ACCEPTED, VOICE_OWN_KEY_NOT_AVAILABLE, VOICE_STREAM_NOT_AVAILABLE, VOICE_OUTBOUND_OFF), USER_UNAVAILABLE 만은 설명 없이 늘 Forbidden: USER_UNAVAILABLE 입니다. 한 시간 한도를 넘으면 429 와 retry_after 입니다.

텔레그램 Bot API 와 다른 점

  • 업데이트 종류: message, edited_message, callback_query 와, 파발에만 있는 음성 봇 종류(voice_call, voice_call_tool_query, voice_call_transcript)만 옵니다. 채널 글, 인라인 쿼리, 결제, 투표, 멤버 변경(my_chat_member) 등은 없습니다.
  • 서식: parse_mode·entities 를 무시하고 글자 그대로 보냅니다. 명령·멘션·URL·해시태그만 자동으로 표시됩니다.
  • 대화 종류: 1:1 과 기본 그룹만. 채널·슈퍼그룹·포럼 토픽은 없습니다.
  • 미디어: 사진, 파일(sendDocument), 위치·실시간 위치·장소·연락처만. 동영상·음성으로 재생되는 메시지, 스티커, 앨범(sendMediaGroup), 투표, URL 로 보내기는 없습니다. HTTP 로 올리고 내려받는 것은 20MB 까지입니다.
  • 위치: 실시간 위치의 접근 알림(proximity_alert_radius)은 저장만 하고 보내지 않습니다. 10초·10m 안쪽의 이동은 반영하지 않고 넘기며, 봇이 보낸 연락처 카드에는 user_id 가 붙지 않습니다.
  • 그룹의 봇: 프라이버시 모드가 없어 그룹의 모든 메시지를 받습니다.
  • 대기열: 가져가지 않은 업데이트는 봇마다 최근 1,000개까지 메모리에 두며, 서버 재시작 때 사라집니다(텔레그램은 24시간 보관).
  • 웹훅: 한 번에 하나씩 순서대로 보내고(max_connections 는 보관만), 자체 서명 인증서를 받지 않으며, 포트 제한이 없습니다.
  • ID: 사용자·메시지·파일 ID 는 이 서버 안에서만 뜻이 있습니다. 채널·슈퍼그룹이 없어 -100… 꼴의 ID 도 없습니다.
  • 없는 메서드: 위 목록에 없는 것(forwardMessage, copyMessage, sendVideo, sendPoll, getChatMember, banChatMember, answerInlineQuery …)은 404 Not Found: method not found.