빠른 시작으로

푸시 알림 보내기 API

연결이 끝났다면 발송은 REST 한 번입니다. 이 문서는 요청 필드 전부와, 한도에 걸리기 «전에» 읽을 수 있는 숫자들을 다룹니다.

한 사람에게 보내기

to에 ext: 뒤 external_id를 주면 그 사람이 연결한 모든 기기로 갑니다. 아이폰과 안드로이드를 같이 쓰는 사람이면 두 건으로 나가고, 응답의 queued_deliveries가 그 수를 알려 줍니다. 전체에게 보낼 때는 broadcast를 씁니다.

API_KEY=<발급받은 api_key>

curl -X POST https://api.eosnoti.com/v1/messages \
  -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
  -d '{"to":"ext:user_8821","kind":"notify",
       "title":"결제 완료","body":"주문 #2043이 접수됐습니다",
       "url":"https://app.example.com/orders/2043","priority":"high"}'
# ← 201 {"message_id":"...","queued_deliveries":2}
#   queued_deliveries = 실제로 나간 기기 수 = 이번에 쓴 한도

# 구독자 전체에게 물어보기 (ask)
curl -X POST https://api.eosnoti.com/v1/messages \
  -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
  -d '{"to":"broadcast","kind":"ask",
       "body":"회의 참석하시겠습니까?","choices":["참석","불참"]}'

요청 필드

body만 필수입니다. choices와 expires_at은 ask에서만 쓰며, notify에 같이 보내면 400으로 거절됩니다.

필드설명
toext:<id> | broadcast한 사람 또는 구독자 전체
body문자열 (필수)알림 본문
title문자열알림 제목
kindnotify | ask일방 통보인지, 답을 받을 것인지
prioritynormal | highhigh는 잠금화면에 즉시 표시
url절대 주소알림을 탭했을 때 열 곳
iconhttps 주소발신자 아바타(왼쪽 동그라미)
imagehttps 주소내용 이미지(오른쪽·카드)
data임의 JSON앱으로 같이 실어 보낼 값
choices문자열 배열ask 전용 — 선택지
expires_atISO8601ask 전용 — 응답 마감
icon은 «누가 보냈는가» — 알림 왼쪽의 동그란 발신자 아바타입니다. image는 «무엇에 관한 것인가» — 오른쪽 썸네일이자 인박스 카드의 그림입니다. 둘 다 http(s) 절대 주소만 받고 메시지당 한 장입니다. 본문에 주소를 적어도 그림으로 뜨지 않습니다.

한도는 응답에 실려 옵니다

발송이 쿼터를 쓰면 201 응답에 남은 일별·월별 한도가 같이 옵니다. 같은 값이 응답 헤더에도 실립니다. 429를 만나고 나서 물러서는 대신, 이 숫자를 보고 미리 속도를 줄이십시오. remaining이 limit의 20% 아래로 내려가면 near_limit이 true가 됩니다.

# 201 응답 본문에 남은 한도가 같이 온다
{ "message_id": "...", "queued_deliveries": 2,
  "quota": { "limit": 100, "used": 42, "remaining": 58,
             "reset_at": "2026-07-08T15:00:00Z", "near_limit": false,
             "monthly": { "limit": 1500, "used": 1212, "remaining": 288,
                          "reset_at": "2026-08-02T15:00:00Z", "near_limit": false } } }

# 같은 값이 헤더로도 온다
X-Quota-Limit / X-Quota-Used / X-Quota-Remaining / X-Quota-Reset             (일별)
X-Quota-Month-Limit / X-Quota-Month-Used / X-Quota-Month-Remaining / …       (월별)

# 일별은 매일 00:00 KST에, 월별은 가입일과 같은 날짜에 리셋된다.
# 한 건도 안 나간 발송(연결 안 된 ext:<id> 등)은 한도를 쓰지 않고 quota도 안 싣는다.
한도는 API 호출 수가 아니라 «전달 건수»로 셉니다. 구독자 300명에게 보내는 broadcast 한 번은 300건입니다. 게다가 남은 한도를 넘기는 broadcast는 통째로 거절되니(일부만 나가지 않습니다), 큰 발송 전에는 remaining을 먼저 보십시오.

에러

2xx가 아닌 응답은 모두 error 객체에 code와 message를 담아 옵니다. 429가 두 종류인 것만 유의하십시오 — 잠깐 기다리면 풀리는 것과, 내일까지 기다려야 하는 것이 다릅니다.

코드상태무엇인가
rate_limited429짧은 순간의 과다 호출(앱당 60초에 약 600건). 잠깐 쉬면 풀립니다
quota_exceeded429요금제 한도. scope가 daily인지 monthly인지 알려 줍니다
plan_expired403체험 종료 — 기다려도 풀리지 않습니다
plan_required403요금제에 없는 기능
unauthorized401API 키가 없거나 틀렸습니다
invalid_target400to 형식 오류. 그 밖에 invalid_body·invalid_icon·invalid_image 등
# 한도를 넘긴 429 — 어느 축인지(scope)와 언제 풀리는지가 같이 온다
HTTP 429 Too Many Requests
Retry-After: <그 축이 리셋될 때까지 초>

{ "error": { "code": "quota_exceeded", "message": "daily delivery quota exceeded",
             "scope": "daily", "limit": 100, "used": 100, "remaining": 0,
             "reset_at": "2026-07-08T15:00:00Z" } }
403 plan_expired는 체험이 끝나고 요금제를 고르지 않은 상태입니다. 기다려도 풀리지 않으므로 429처럼 재시도하시면 안 됩니다. 응답의 upgrade_url로 안내하십시오. 채널·구독자·메시지는 그대로 보관됩니다.

다른 문서

붙여 보시겠습니까?

가입하면 애플리케이션과 API 키가 바로 발급됩니다. 첫 알림까지 5분이면 됩니다.

무료로 시작하기
푸시 알림 보내기 API — POST /v1/messages — EosNoti