API 레퍼런스 — 공통 규약

알마니 Open API의 모든 엔드포인트에 공통으로 적용되는 규약입니다. 인증 방법, 요청·응답 규격, 응답 래퍼와 쿼터, 에러 코드, 처리율 제한, 커서 페이지네이션, 멱등성 처리를 다룹니다.

Base URL 모든 API 경로는 https://docs.almani-center.com/open/v1 을 기준으로 합니다. 예시의 ak_live_xxxx 는 더미 키이며, 실제 키는 알마니 콘솔에서 발급합니다.

인증

모든 요청은 Authorization 헤더의 API 키로 인증합니다. 키는 알마니 콘솔에서 발급하며 ak_live_ 로 시작합니다. 발급 사이트가 속한 계정의 사이트에 접근할 수 있고, 키마다 template:read, template:write 같은 허용 스코프를 가집니다.

요청 헤더

Authorization 필수 string

Bearer ak_live_xxxx 형식의 시크릿 키입니다. 알마니 콘솔에서 발급하며, 키마다 허용된 스코프를 가집니다.

X-Site-Id 필수 string

대상 사이트입니다. 서버가 사이트 소유권을 검증한 뒤 요청 컨텍스트를 구성합니다. 단, GET /sites, GET /me 만 생략할 수 있습니다.

Idempotency-Key 선택 string

쓰기 API 재시도 안전장치입니다. 최대 100자입니다. 멱등성 (Idempotency-Key) 를 참고하세요.

검증 순서

서버는 매 요청을 다음 순서로 검증합니다.

  1. 키 유효성 확인 (활성·만료 여부) — 실패 시 4001 / 4002
  2. API 키 단위 rate limit 차감 — 초과 시 4290
  3. 스코프 확인 — 실패 시 4005
  4. X-Site-Id 소유권 — 실패 시 4003 / 4004

실패 지점별 에러 코드의 의미와 대응은 에러 형식과 코드 표를 참고하세요.

인증 요청 예시
curl "https://docs.almani-center.com/open/v1/templates" \
  -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("/templates")
        .retrieve()
        .body(String.class);
응답 예시
HTTP/1.1 200 OK

{
  "code": "0000",
  "message": "OK",
  "data": { ... },
  "meta": {
    "requestId": "req_9f83ab21",
    "quota": {
      "rateLimit": {
        "limit": 120,
        "remaining": 119,
        "resetAt": "2026-07-25T14:31:00+09:00"
      }
    }
  }
}

요청·응답 규격

모든 엔드포인트에 공통 적용되는 기본 규약입니다.

항목규약
Base URL https://docs.almani-center.com/open/v1
Content-Type 요청/응답 모두 application/json; charset=utf-8
날짜/시간 ISO-8601, KST 오프셋 포함 — 2026-07-25T14:30:00+09:00
ID 표기 템플릿은 코드 문자열(templateCode, 예: TPL_20260725143012)이 조회 키
Y/N 필드 Y/N 형태의 상태 값은 API에서 boolean으로 제공 (예: "active": true)
버저닝 URL 경로 버전(/open/v1). 하위호환 깨지는 변경은 /open/v2

응답 래퍼와 meta.quota

모든 응답(에러 포함)은 공통 래퍼를 따릅니다. code 는 결과 코드("0000" = 성공), data 는 엔드포인트별 페이로드(에러 시 null), meta.requestId 는 추적용 ID입니다.

쿼터는 매 응답에 항상 포함됩니다 쿼터는 매 응답의 meta.quota 에 항상 포함되며, 유효한 API 키가 식별된 요청에는 동일 정보가 RateLimit-* 헤더로도 제공됩니다. 에이전트/클라이언트는 별도 쿼터 조회 없이 매 응답에서 잔여치를 확인할 수 있습니다.
블록포함 범위설명
rateLimit 모든 응답 API 키 단위 분당 요청 한도 — 항상 포함
templateReview 템플릿 신청/재검수/취소 + GET /quota 사이트 단위 일일 템플릿 검수 한도 (일자 집계)
points GET /quota 포인트 잔액 — 발송·과금 관련 API 응답에 포함

사이트 기준 전체 쿼터를 한 번에 조회하려면 계정 API를 참고하세요.

커서 페이지네이션

목록 API는 커서 방식입니다. 응답의 data.nextCursornull 이면 마지막 페이지입니다.

limit 선택 int

기본 20, 최대 100.

cursor 선택 string

이전 응답의 data.nextCursor 값 (opaque). 없으면 첫 페이지.

멱등성 (Idempotency-Key)

템플릿 생성·검수 요청과 발신프로필 인증번호 요청·등록에 Idempotency-Key 헤더(UUID 권장)를 보내면 같은 API 키·엔드포인트·사이트에서 동일한 키와 요청 바디로 재요청할 때 최초 성공 결과를 그대로 반환합니다(24시간 보관). 네트워크 재시도로 인한 중복 템플릿 신청을 방지합니다.

같은 조건에서 동일한 키에 다른 요청 바디를 사용하거나 첫 요청이 아직 처리 중이면 4091 을 반환합니다. 에러 형식과 코드를 참고하세요.

래퍼 응답 예시
{
  "code": "0000",                        // 결과 코드 — "0000" = 성공
  "message": "OK",
  "data": { ... },                       // 엔드포인트별 페이로드 (에러 시 null)
  "meta": {
    "requestId": "req_9f83ab21",         // 추적용 ID — 문의 시 함께 전달
    "quota": {
      "rateLimit": {                     // 항상 포함 (키 단위)
        "limit": 120,                    // API 키당 분당 허용 요청 수
        "remaining": 118,
        "resetAt": "2026-07-25T14:31:00+09:00"
      },
      "templateReview": {                // 템플릿 쓰기 API 응답에 포함 (사이트 단위)
        "dailyLimit": 30,
        "usedToday": 4,
        "remaining": 26,
        "resetAt": "2026-07-26T00:00:00+09:00"
      },
      "points": { "balance": 1523000 }   // 발송·과금 관련 API 응답에 포함
    }
  }
}

에러 형식과 코드

에러 응답도 공통 래퍼를 따릅니다. code 에 결과 코드, message 에 사유가 담기며 datanull 입니다. 문의 시에는 meta.requestId 를 함께 전달해 주세요.

코드HTTP의미대응
0000200성공
4000400요청 형식 오류 (필드 누락/타입/제약 위반)message에 필드별 사유
4001401키 없음/형식 오류/존재하지 않는 키키 확인
4002401키 만료 또는 비활성콘솔에서 재발급
4003400X-Site-Id 헤더 누락GET /sites로 사이트 선택
4004403키 소유자의 사이트가 아님사이트 ID 확인
4005403스코프 부족 (예: template:write 없음)키 스코프 확인
4040404리소스 없음 (템플릿 코드 불일치)
4090409상태 전이 불가 (예: APR 템플릿에 검수 요청)message에 현재 상태 포함
4091409중복 (템플릿명 중복, Idempotency 충돌)
4290429분당 rate limit 초과Retry-After 후 재시도
4291429일일 템플릿 검수 요청 한도 초과다음 날 자정 이후 재시도
5000500서버 내부 오류meta.requestId로 문의
6000502카카오 검수·채널 연동 오류 (상세 사유 message에 포함)재시도 또는 문의
6001502발신프로필 미등록 또는 유효하지 않음발신프로필 등록
에러 응답 예시
HTTP/1.1 400 Bad Request

{
  "code": "4000",
  "message": "templateName: 필수 항목이 누락되었습니다.",
  "data": null,
  "meta": {
    "requestId": "req_9f83ab21",
    "quota": {
      "rateLimit": {
        "limit": 120,
        "remaining": 117,
        "resetAt": "2026-07-25T14:31:00+09:00"
      }
    }
  }
}

처리율 제한

요청 한도는 API 키별로 분당 120회입니다. 잔여치는 매 응답의 meta.quota.rateLimit 에 항상 포함되고, 유효한 API 키가 식별된 요청에는 동일 정보가 RateLimit-* 응답 헤더로도 제공됩니다.

  • 4290 — 분당 rate limit 초과. Retry-After 헤더(초 단위)만큼 기다린 뒤 재시도하세요.
  • 4291 — 일일 템플릿 검수 요청 한도 초과. 다음 날 자정 이후 재시도하세요.
429 응답 처리 Retry-After 헤더는 분당 한도 초과(4290) 응답에만 포함됩니다. 해당 시간(초) 이후에 재시도하도록 클라이언트를 구현하세요.
RateLimit-* 헤더 예시
RateLimit-Limit: 120
RateLimit-Remaining: 118
RateLimit-Reset: 42            # 초 단위
Retry-After: 42                # 4290 응답에만
429 응답 예시
HTTP/1.1 429 Too Many Requests
RateLimit-Limit: 120
RateLimit-Remaining: 0
RateLimit-Reset: 42
Retry-After: 42

{
  "code": "4290",
  "message": "분당 요청 한도를 초과했습니다.",
  "data": null,
  "meta": {
    "requestId": "req_9f83ab21",
    "quota": {
      "rateLimit": {
        "limit": 120,
        "remaining": 0,
        "resetAt": "2026-07-25T14:31:00+09:00"
      }
    }
  }
}