개인화 변수 가이드
알마니는 트리거 이벤트(주문완료, 배송시작 등)가 발생할 때
수신자별 데이터를 템플릿에 치환해 발송합니다.
이 가이드는 그 치환이 어떤 구조로 동작하는지(세 층위),
템플릿 신청 시 mappingData를 어떻게 작성하는지,
사용 가능한 변수를 GET /variables로 어떻게 조회하는지,
그리고 매핑 실수를 막아 주는 검증 규칙 3가지를 설명합니다.
https://docs.almani-center.com/open/v1 입니다.
모든 요청에는 인증에서 발급한
API 키(Authorization: Bearer ak_live_xxxx — 예시는 더미 키)와
대상 사이트를 지정하는 X-Site-Id 헤더가 필요합니다.
템플릿 API 전체 규격은 템플릿 API 레퍼런스를 참고하세요.
세 층위 구조
개인화 발송에는 세 층위가 관여합니다. 트리거가 발생하면 ① 트리거 데이터에서 ② 개인화 변수 값을 추출하고, 매핑을 따라 ③ 템플릿 변수를 치환한 뒤 발송합니다.
| 층위 | 표현 형태 | 설명 |
|---|---|---|
| ① 트리거 데이터 | 이벤트 원본 값 | 주문·배송·쿠폰 이벤트가 실어오는 수신자별 실제 값 (사이트 플랫폼에 따라 제공 범위가 다름) |
| ② 개인화 변수 | 한글 표준명 | 알마니가 표준화한 변수 — 고객명, 주문번호, 결제금액, 송장번호, 쿠폰명 등. 트리거별 사용 가능 목록은 GET /variables로 조회 |
| ③ 템플릿 변수 | #{변수명} |
템플릿 본문·버튼 URL에 쓰는 치환 자리 — 예: #{고객명}, #{주문번호} |
mappingData 작성법
Open API에서 매핑은
템플릿 신청
(POST /templates) 시 mappingData 객체로 지정합니다.
이 템플릿을 발송에 연결하는 작업(캠페인 설정)은 알마니 콘솔에서 수행하며,
그때 이 매핑이 기본값으로 상속됩니다.
- 키에는 템플릿 본문·버튼 URL에 쓴 템플릿 변수명(
#{ }안의 이름)을 적습니다. - 값에는 개인화 변수명(한글 표준명)을 적습니다. 사용 가능한 이름은 GET /variables로 조회합니다.
- 템플릿 변수명과 개인화 변수명이 같으면 그 항목은 생략할 수 있습니다(자동 매핑). 이름이 다를 때만 명시합니다.
"mappingData": {
"고객명": "고객명", // #{고객명} ← 개인화 변수 '고객명'
"주문번호": "주문번호",
"상품명": "첫번째상품명" // #{상품명} ← 개인화 변수 '첫번째상품명' (이름이 다른 케이스)
}
아래는 mappingData를 포함한 템플릿 신청 전체 예시입니다.
본문의 #{고객명}, #{주문번호}, #{결제금액}과
버튼 URL의 #{주문번호}가 모두 매핑 대상입니다.
curl -X POST "https://docs.almani-center.com/open/v1/templates" \
-H "Authorization: Bearer ak_live_xxxx" \
-H "X-Site-Id: 1024" \
-H "Content-Type: application/json" \
-d '{
"templateName": "주문완료 안내 v3",
"templateType": "BA",
"category": "004001",
"content": "#{고객명}님, 주문이 완료되었습니다.\n\n▶ 주문번호: #{주문번호}\n▶ 결제금액: #{결제금액}원\n\n배송이 시작되면 다시 알려드릴게요.",
"buttons": [
{
"name": "주문 상세 보기",
"type": "WL",
"urlMobile": "https://shop.example.com/orders/#{주문번호}"
}
],
"mappingData": {
"고객명": "고객명",
"주문번호": "주문번호",
"결제금액": "결제금액"
}
}'
// 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 TemplateButton(String name, String type, String urlMobile) {}
record CreateTemplateRequest(
String templateName, String templateType, String category,
String content, List<TemplateButton> buttons,
Map<String, String> mappingData) {}
var request = new CreateTemplateRequest(
"주문완료 안내 v3", "BA", "004001",
"#{고객명}님, 주문이 완료되었습니다.\n\n▶ 주문번호: #{주문번호}\n"
+ "▶ 결제금액: #{결제금액}원\n\n배송이 시작되면 다시 알려드릴게요.",
List.of(new TemplateButton("주문 상세 보기", "WL",
"https://shop.example.com/orders/#{주문번호}")),
Map.of("고객명", "고객명", "주문번호", "주문번호", "결제금액", "결제금액"));
String response = restClient.post()
.uri("/templates")
.contentType(MediaType.APPLICATION_JSON)
.body(request)
.retrieve()
.body(String.class);
mappingData를 통째로 생략해도 동일하게 동작합니다.
이름이 다른 변수(예: #{상품명} ← 첫번째상품명)가
하나라도 있으면 그 항목만 명시하면 됩니다.
개인화 변수 카탈로그 조회
/variables
필요 스코프: template:read
템플릿 매핑에 사용할 수 있는 개인화 변수 목록을 반환합니다.
사이트 플랫폼 기준으로 필터되어 반환되며,
triggerEvent를 지정하면 해당 트리거가 제공하는 변수만 반환합니다.
Query Parameters
트리거 값입니다 (예: orderComplete, deliveryStart).
미지정 시 전체 변수를 반환합니다.
Response
사용 가능한 개인화 변수 목록입니다.
개인화 변수명(한글 표준명)입니다.
mappingData의 값과 #{변수명}에 이 이름을 사용합니다.
변수 그룹입니다 (예: 고객, 주문, 배송).
변수 설명입니다.
이 변수를 제공하는 트리거 목록입니다.
4000)를 한 번에 통과할 수 있습니다.
# 트리거별 필터: /variables?triggerEvent=deliveryStart
curl "https://docs.almani-center.com/open/v1/variables" \
-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();
String response = restClient.get()
.uri("/variables")
// 트리거별 필터:
// .uri(b -> b.path("/variables")
// .queryParam("triggerEvent", "deliveryStart").build())
.retrieve()
.body(String.class);
HTTP/1.1 200 OK
{
"code": "0000",
"message": "OK",
"data": {
"variables": [
{ "name": "고객명", "group": "고객",
"description": "주문자 이름",
"triggers": ["orderComplete", "deliveryStart"] },
{ "name": "주문번호", "group": "주문",
"description": "플랫폼 주문번호",
"triggers": ["orderComplete", "deliveryStart"] },
{ "name": "송장번호", "group": "배송",
"description": "택배 송장번호",
"triggers": ["deliveryStart"] }
]
},
"meta": {
"requestId": "req_7c20d9b4",
"quota": {
"rateLimit": {
"limit": 120,
"remaining": 119,
"resetAt": "2026-07-25T14:31:00+09:00"
}
}
}
}
HTTP/1.1 403 Forbidden
{
"code": "4005",
"message": "API 키에 template:read 스코프가 없습니다. 콘솔에서 키 스코프를 확인해 주세요.",
"data": null,
"meta": {
"requestId": "req_5e8a1c22",
"quota": {
"rateLimit": {
"limit": 120,
"remaining": 118,
"resetAt": "2026-07-25T14:31:00+09:00"
}
}
}
}
검증 규칙 3가지
매핑 실수로 변수가 빈 채 발송되는 사고를 막기 위해, 알마니는 신청 시점부터 발송 시점까지 세 단계에서 매핑을 검사합니다.
1. 신청 시점 검사
템플릿 신청
(POST /templates)에서 매핑 대상 개인화 변수가 표준 카탈로그
(GET /variables)에 없으면
4000 에러와 함께 사용 가능한 변수 목록을 반환합니다.
usedFor(대상 트리거)를 함께 보내면 해당 트리거가 제공하는
변수 기준으로 더 엄격히 검사합니다.
2. 매핑 미지정 변수 경고
본문의 #{변수} 중 매핑(자동 매핑 포함)이 해석되지 않는 것이 있으면
응답의 data.unmappedVariables: ["송장번호"] 형태로 알려줍니다.
발송 연결 전까지 매핑을 완성해야 합니다.
3. 발송 시점 빈 값 보호
수신자 데이터에 매핑 값이 비어 있으면 해당 수신자는 발송을 건너뜁니다. 변수가 빈 채로 발송되는 사고를 방지하기 위한 보호 장치입니다.
| 검사 시점 | 무엇을 검사하나 | 결과 |
|---|---|---|
| 템플릿 신청 시 ( POST /templates) |
매핑 대상 개인화 변수가 표준 카탈로그에 있는지
(usedFor 지정 시 해당 트리거 제공 변수 기준) |
4000 에러 + 사용 가능한 변수 목록 반환 |
| 템플릿 신청 응답 | 본문 #{변수} 중 매핑(자동 매핑 포함)이 해석되지 않는 변수 |
data.unmappedVariables로 경고 —
발송 연결 전까지 매핑 완성 필요 |
| 발송 시점 | 수신자별 매핑 값이 비어 있는지 | 해당 수신자는 발송 건너뜀 (빈 변수 발송 방지) |
unmappedVariables)를 해소하지 않은 채
발송에 연결하면, 발송 시점 빈 값 보호에 의해 해당 변수 값이 비는 수신자들이
조용히 제외될 수 있습니다. 경고 목록이 비어 있는 상태로 만든 뒤 연결하세요.
다음 단계
- 매핑을 포함해 템플릿을 등록하고 검수를 요청하려면 — 템플릿 신청
- 카카오 검수 상태 흐름과 반려 대응 방법은 — 템플릿 심사 가이드
-
승인된 템플릿을 발송에 연결하는 작업(캠페인 설정)은 알마니 콘솔에서 수행합니다.
이때 템플릿의
mappingData가 기본값으로 상속됩니다.