빠른 시작
5분 안에 첫 알림톡 템플릿을 등록하고 카카오 검수 요청 → 승인 확인까지 완주하는 가이드입니다. 순서는 다음과 같습니다.
- 콘솔에서 API 키 발급 — 코드 없이 콘솔에서 준비
- 사이트 ID 확인 —
GET /sites - 템플릿 신청 —
POST /templates(등록 즉시 검수 요청) - 승인 확인 —
GET /templates/{templateCode}폴링 - 반려 시 재검수 —
POST /templates/{templateCode}/review
https://docs.almani-center.com/open/v1 입니다.
문서의 ak_live_xxxx 는 더미 키이며, 실행 전에 1단계에서 발급받은
실제 키로 바꿔 주세요. 인증 상세 규칙은
공통 규약 — 인증을 참고하세요.
6001 에러로 거절됩니다.
발신프로필 레퍼런스에서 먼저 등록을
마쳐 주세요.
① 콘솔에서 API 키 발급
이 단계는 코드가 필요 없습니다. 알마니 콘솔에 로그인해 API 키를 발급받습니다.
-
키 발급 — 콘솔의 API 키 발급 화면에서 새 키를 만듭니다.
키는 계정에 속한 사이트에 접근하는 시크릿 키로,
ak_live_로 시작합니다. -
스코프 확인 — 키마다 허용 스코프가 지정됩니다.
이 가이드를 완주하려면
template:read와template:write두 스코프가 모두 허용된 키가 필요합니다. 스코프가 부족하면 요청이4005에러로 거절됩니다. -
요청 한도 확인 — Open API는 호출 IP를 제한하지 않으며,
API 키당 분당 120회까지 호출할 수 있습니다. 초과 시
4290과Retry-After가 반환됩니다. -
키 상태 관리 — 만료되었거나 비활성화된 키는
4002에러가 반환되며, 콘솔에서 재발급합니다.
② 사이트 ID 확인
/sites
거의 모든 API는 대상 사이트를 지정하는 X-Site-Id 헤더가
필수입니다. 발급받은 키로 접근할 수 있는 사이트 목록을 조회해,
이후 단계에서 사용할 siteId 를 확인합니다.
이 목록에는 키를 발급한 사이트 하나만이 아니라 키 소유 계정의 삭제되지 않은
전체 사이트가 포함됩니다.
전체 규격은 사이트 목록 조회 레퍼런스를
참고하세요.
GET /sites 는 GET /me 와 함께
X-Site-Id 헤더를 생략할 수 있는 엔드포인트입니다.
연동 초기, 사이트 ID를 아직 모르는 상태에서 호출하세요.
키 자체 검증에는 계정 정보 조회도
사용할 수 있습니다.
Response
키 소유 계정의 삭제되지 않은 전체 사이트 목록입니다.
사이트 ID입니다. 이후 모든 요청의 X-Site-Id 헤더에
이 값을 넣습니다.
사이트 이름입니다.
사이트의 쇼핑몰 플랫폼입니다. 사용 가능한 개인화 변수의 제공 범위는 플랫폼에 따라 다릅니다.
# X-Site-Id 없이 호출할 수 있는 엔드포인트입니다
curl "https://docs.almani-center.com/open/v1/sites" \
-H "Authorization: Bearer ak_live_xxxx"
// Java 17 + Spring Framework 6 RestClient
// GET /sites 는 X-Site-Id 없이 호출할 수 있습니다
RestClient restClient = RestClient.builder()
.baseUrl("https://docs.almani-center.com/open/v1")
.defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer ak_live_xxxx")
.build();
String response = restClient.get()
.uri("/sites")
.retrieve()
.body(String.class);
HTTP/1.1 200 OK
{
"code": "0000",
"message": "OK",
"data": {
"items": [
{
"siteId": 1024,
"siteName": "알마니몰",
"platform": "cafe24",
"siteUrl": "https://almanimall.example.com",
"active": true,
"registeredAt": "2026-06-10T09:12:00+09:00",
"senderProfileRegistered": true
}
],
"nextCursor": null
},
"meta": {
"requestId": "req_1d72e0a4",
"quota": {
"rateLimit": {
"limit": 120,
"remaining": 119,
"resetAt": "2026-07-25T15:21:00+09:00"
}
}
}
}
HTTP/1.1 401 Unauthorized
{
"code": "4001",
"message": "유효하지 않은 API 키입니다. Authorization 헤더를 확인해 주세요.",
"data": null,
"meta": {
"requestId": "req_83f5c1b9",
"quota": {
"rateLimit": {
"limit": 120,
"remaining": 118,
"resetAt": "2026-07-25T15:21:00+09:00"
}
}
}
}
③ 템플릿 신청
/templates
필요 스코프: template:write
첫 템플릿을 신청합니다. autoReview 는 기본값이
true 이므로, 별도 옵션 없이 이 요청 한 번으로
등록과 동시에 카카오 검수까지 즉시 요청됩니다.
성공 시 templateCode 가 발급되고 상태는 곧바로
REQ(검수중)가 됩니다.
초안(REG)으로만 저장하려면
autoReview: false 를 보내세요.
Request Body (필수 필드)
템플릿 이름입니다. 최대 30자, 사이트 내 중복 불가(중복 시 4091).
템플릿 유형입니다.
BA 기본형 · IM 이미지형 ·
EX 강조표기형 · IT 아이템리스트형.
이 가이드는 기본형(BA)을 사용합니다.
알림톡 템플릿 카테고리 코드입니다.
메시지 본문입니다. 변수는 #{변수명} 형식으로 넣습니다.
기본형 최대 1,000자. 변수만으로 구성된 본문은 반려됩니다.
버튼·강조표기·이미지 등 선택 필드의 전체 규격은
템플릿 신청 레퍼런스를
참고하세요. 예시 본문의 #{고객명}, #{주문번호} 처럼
표준 개인화 변수명을 그대로 쓰면
mappingData 없이 자동 매핑됩니다.
autoReview: true(기본값) 신청은 사이트 단위 일일 검수 한도를
소모합니다. 잔여 한도는 응답의 meta.quota.templateReview 에서
확인하세요. 한도를 초과하면 4291 에러(HTTP 429)가 반환됩니다.
주요 에러
| 코드 | HTTP | 설명 |
|---|---|---|
4000 | 400 | 필수 필드 누락 등 요청 형식 오류 |
4091 | 409 | 템플릿명 중복 |
4291 | 429 | 일일 템플릿 검수 요청 한도 초과 |
6001 | 502 | 발신프로필 미등록 또는 유효하지 않음 — 발신프로필 참조 |
curl -X POST "https://docs.almani-center.com/open/v1/templates" \
-H "Authorization: Bearer ak_live_xxxx" \
-H "X-Site-Id: 1024" \
-H "Idempotency-Key: 2f8f4d1a-6c3b-4e0d-9a52-b71c0e5d8f36" \
-H "Content-Type: application/json" \
-d '{
"templateName": "주문완료 안내 (빠른 시작)",
"templateType": "BA",
"category": "004001",
"content": "#{고객명}님, 주문이 완료되었습니다.\n\n▶ 주문번호: #{주문번호}\n\n배송이 시작되면 다시 알려드릴게요."
}'
// Java 17 + Spring Framework 6 RestClient
RestClient restClient = RestClient.builder()
.baseUrl("https://docs.almani-center.com/open/v1")
.defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer ak_live_xxxx")
.defaultHeader("X-Site-Id", "1024")
.build();
record CreateTemplateRequest(
String templateName, String templateType,
String category, String content) {}
var request = new CreateTemplateRequest(
"주문완료 안내 (빠른 시작)", "BA", "004001",
"#{고객명}님, 주문이 완료되었습니다.\n\n▶ 주문번호: #{주문번호}\n\n"
+ "배송이 시작되면 다시 알려드릴게요.");
String response = restClient.post()
.uri("/templates")
.header("Idempotency-Key", UUID.randomUUID().toString())
.contentType(MediaType.APPLICATION_JSON)
.body(request)
.retrieve()
.body(String.class);
HTTP/1.1 200 OK
{
"code": "0000",
"message": "OK",
"data": {
"templateId": 5812,
"templateCode": "TPL_20260725153000",
"approveStatus": "REQ",
"requestedAt": "2026-07-25T15:30:00+09:00"
},
"meta": {
"requestId": "req_a1c94e07",
"quota": {
"rateLimit": {
"limit": 120,
"remaining": 118,
"resetAt": "2026-07-25T15:31:00+09:00"
},
"templateReview": {
"dailyLimit": 30,
"usedToday": 6,
"remaining": 24,
"resetAt": "2026-07-26T00:00:00+09:00"
}
}
}
}
HTTP/1.1 400 Bad Request
{
"code": "4000",
"message": "category: 필수 항목이 누락되었습니다.",
"data": null,
"meta": {
"requestId": "req_50be27d3",
"quota": {
"rateLimit": {
"limit": 120,
"remaining": 117,
"resetAt": "2026-07-25T15:31:00+09:00"
}
}
}
}
④ 승인(APR) 상태 확인
/templates/{templateCode}
필요 스코프: template:read
3단계에서 발급받은 templateCode 로 검수 결과를 확인합니다.
이 API는 AL_TEMPLATE.APPROVE_STATUS에 저장된 현재 검수 상태를 반환합니다.
REQ 상태여도 요청을 처리하면서
비즈톡 상태를 실시간으로 재조회하지 않습니다.
-
approveStatus가 APR이면 승인 완료 —sendable: true가 되어 발송에 사용할 수 있습니다. -
REJ면 반려 —
rejectReason으로 사유를 확인하고 5단계로 진행합니다.
Path 파라미터
템플릿 코드입니다 (예: TPL_20260725153000).
Response (핵심 필드)
현재 상태입니다 — REG/REQ/APR/REJ/UPT.
REJ일 때 카카오 심사 코멘트 전문(최신)입니다.
APR 여부 — 발송에 사용할 수 있는지를 나타냅니다.
전체 응답 필드는 템플릿 조회 레퍼런스를 참고하세요.
RateLimit-* 응답 헤더를 기준으로 호출 주기를 정하세요.
# 필요한 시점에 저장된 approveStatus를 조회합니다
curl "https://docs.almani-center.com/open/v1/templates/TPL_20260725153000" \
-H "Authorization: Bearer ak_live_xxxx" \
-H "X-Site-Id: 1024"
// Java 17 + Spring Framework 6 RestClient
RestClient restClient = RestClient.builder()
.baseUrl("https://docs.almani-center.com/open/v1")
.defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer ak_live_xxxx")
.defaultHeader("X-Site-Id", "1024")
.build();
// 필요한 시점에 저장된 data.approveStatus를 조회합니다
String response = restClient.get()
.uri("/templates/{templateCode}", "TPL_20260725153000")
.retrieve()
.body(String.class);
HTTP/1.1 200 OK
{
"code": "0000",
"message": "OK",
"data": {
"templateCode": "TPL_20260725153000",
"templateName": "주문완료 안내 (빠른 시작)",
"approveStatus": "APR",
"rejectReason": null,
"templateType": "BA",
"category": "004001",
"securityEnabled": false,
"content": "#{고객명}님, 주문이 완료되었습니다.\n\n▶ 주문번호: #{주문번호}\n\n배송이 시작되면 다시 알려드릴게요.",
"buttons": [],
"mappingData": {
"고객명": "고객명",
"주문번호": "주문번호"
},
"sendable": true,
"recentHistory": [
{
"status": "APR",
"comment": "승인되었습니다.",
"at": "2026-07-25T16:11:52+09:00"
},
{
"status": "REQ",
"comment": "주문 완료 시 발송되는 정보성 메시지입니다.",
"at": "2026-07-25T15:30:00+09:00"
}
]
},
"meta": {
"requestId": "req_7e30ba9c",
"quota": {
"rateLimit": {
"limit": 120,
"remaining": 119,
"resetAt": "2026-07-25T16:13:00+09:00"
}
}
}
}
HTTP/1.1 404 Not Found
{
"code": "4040",
"message": "템플릿을 찾을 수 없습니다: TPL_20260725159999",
"data": null,
"meta": {
"requestId": "req_c95d13e8",
"quota": {
"rateLimit": {
"limit": 120,
"remaining": 118,
"resetAt": "2026-07-25T16:13:00+09:00"
}
}
}
}
⑤ 반려(REJ) 시 — 수정 후 재검수 요청
/templates/{templateCode}/review
필요 스코프: template:write
4단계 폴링 결과가 REJ라면
rejectReason(카카오 심사 코멘트 전문)을 확인하고, 사유를 반영해
수정한 뒤 재검수를 요청합니다. 요청 바디에 수정할 필드
(content / buttons 등,
템플릿 신청과 동일 규격)를
함께 보내면 수정과 재검수를 한 번에 처리합니다.
성공 시 상태는 다시 REQ가 되며,
4단계 폴링으로 돌아가
결과를 확인합니다.
Path 파라미터
템플릿 코드입니다.
Request Body
템플릿 신청과 동일 규격입니다. 보낸 필드만 수정한 뒤 검수를 요청합니다.
카카오 심사 담당자에게 전달되는 의견입니다. 반려 사유에 대한 소명을 권장합니다.
주요 에러
| 코드 | HTTP | 설명 |
|---|---|---|
4090 | 409 | 상태 전이 불가 — 재검수는 REG·REJ·UPT
상태에서만 가능 (message에 현재 상태 포함) |
4291 | 429 | 일일 템플릿 검수 요청 한도 초과 |
meta.quota.templateReview 에서 확인하세요.
재검수 전에 사전 정책 검증으로
반려 위험을 먼저 진단하면 한도 소모를 줄일 수 있습니다(검증은 한도를 소모하지 않습니다).
반려 사유 확인 방법과 대응 절차 전체는
템플릿 심사 가이드를 참고하세요.
curl -X POST "https://docs.almani-center.com/open/v1/templates/TPL_20260725153000/review" \
-H "Authorization: Bearer ak_live_xxxx" \
-H "X-Site-Id: 1024" \
-H "Idempotency-Key: 9b41e7d2-5a80-4c6f-b3e9-2c7f0d8a6e15" \
-H "Content-Type: application/json" \
-d '{
"content": "#{고객명}님, 주문이 완료되었습니다.\n\n▶ 주문번호: #{주문번호}\n\n배송이 시작되면 알림톡으로 다시 안내드립니다.",
"comments": "반려 사유를 반영해 본문을 수정했습니다."
}'
// Java 17 + Spring Framework 6 RestClient
RestClient restClient = RestClient.builder()
.baseUrl("https://docs.almani-center.com/open/v1")
.defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer ak_live_xxxx")
.defaultHeader("X-Site-Id", "1024")
.build();
record ReviewRequest(String content, String comments) {}
var request = new ReviewRequest(
"#{고객명}님, 주문이 완료되었습니다.\n\n▶ 주문번호: #{주문번호}\n\n"
+ "배송이 시작되면 알림톡으로 다시 안내드립니다.",
"반려 사유를 반영해 본문을 수정했습니다.");
String response = restClient.post()
.uri("/templates/{templateCode}/review", "TPL_20260725153000")
.header("Idempotency-Key", UUID.randomUUID().toString())
.contentType(MediaType.APPLICATION_JSON)
.body(request)
.retrieve()
.body(String.class);
HTTP/1.1 200 OK
{
"code": "0000",
"message": "OK",
"data": {
"templateCode": "TPL_20260725153000",
"approveStatus": "REQ",
"requestedAt": "2026-07-25T16:25:31+09:00"
},
"meta": {
"requestId": "req_e62f18ad",
"quota": {
"rateLimit": {
"limit": 120,
"remaining": 117,
"resetAt": "2026-07-25T16:26:00+09:00"
},
"templateReview": {
"dailyLimit": 30,
"usedToday": 7,
"remaining": 23,
"resetAt": "2026-07-26T00:00:00+09:00"
}
}
}
}
HTTP/1.1 409 Conflict
{
"code": "4090",
"message": "현재 상태(APR)에서는 검수를 요청할 수 없습니다. 재검수는 REG·REJ·UPT 상태에서만 가능합니다.",
"data": null,
"meta": {
"requestId": "req_31da95f0",
"quota": {
"rateLimit": {
"limit": 120,
"remaining": 116,
"resetAt": "2026-07-25T16:26:00+09:00"
}
}
}
}
다음 단계
승인(APR)된 템플릿은
sendable: true 가 되어 발송에 사용할 수 있습니다.
발송 연결(캠페인 설정)은 알마니 콘솔에서 수행합니다. 이어서 읽어 보세요.
- 템플릿 심사 가이드 — 검수 상태 흐름, 반려 사유 확인법, 사전 정책 검증, 일일 검수 한도
-
개인화 변수 가이드 —
#{변수명}으로 수신자별 값을 채우는 방법 - 템플릿 API 레퍼런스 — 버튼·이미지형·아이템리스트형 등 전체 규격
-
공통 규약 —
인증, 응답 래퍼와
meta.quota, 에러 코드, 처리율 제한, 멱등성 - 발신프로필 레퍼런스 — 카카오톡 채널 발신프로필 등록