Idempotency-Key로 결제 API 중복 요청 막기
결제 API에서 멱등키가 왜 필요한지, Idempotency-Key 헤더를 어떻게 만들고 재시도할 때 어떻게 다뤄야 하는지 설명합니다.
결제 API를 호출했는데 응답을 받기 전에 연결이 끊겼다고 해 봅시다. 다시 보내야 할까요? 첫 요청이 이미 처리됐다면 다시 보내는 순간 같은 금액이 두 번 결제됩니다. 이 문제를 푸는 장치가 멱등키(Idempotency-Key)입니다.
멱등키란
같은 요청을 여러 번 보내도 결과가 한 번 보낸 것과 같게 만드는 고유한 값입니다. 빌링플러스 공개 API는 모든 POST 요청에 Idempotency-Key 헤더를 요구하고, 없으면 400으로 거부합니다.
같은 키로 다시 보내면
| 상황 | 응답 |
|---|---|
| 이전 요청이 처리 완료 | 저장된 응답을 그대로 반환(다시 실행하지 않음) |
| 이전 요청이 아직 처리 중 | 409와 Retry-After |
| 같은 키인데 본문이 다름 | 422(키 재사용 오류) |
| 같은 키인데 경로·메서드가 다름 | 422 |
처리 결과는 일정 시간 보관되므로, 그 안에 같은 키로 재시도하면 안전하게 처음 결과를 받습니다.
키를 만드는 규칙
- 업무 단위로 하나: "주문 1024번 결제"처럼 한 번의 의도에 한 키를 씁니다.
- 재시도에는 같은 키: 응답을 못 받아 다시 보낼 때는 반드시 처음 키를 재사용합니다. 새 키로 보내면 새 요청이 됩니다.
- 새 의도에는 새 키: 다른 결제, 다른 취소에는 다른 키를 씁니다. 키를 고정값으로 두면 두 번째 요청이 422로 막히거나 엉뚱한 응답을 받습니다.
- 키는 요청 전에 자체 DB에 저장해 두면 서버가 재시작돼도 같은 키로 재시도할 수 있습니다.
재시도 흐름 예시
- 결제 요청 전에 멱등키를 만들어 저장합니다.
- 요청을 보냅니다. 시간 초과가 나면 같은 키로 다시 보냅니다.
- 409가 오면 Retry-After만큼 기다렸다 같은 키로 다시 보냅니다.
- 2xx나 결제 실패 응답을 받으면 결과를 저장하고 끝냅니다.
결제 결과 대기와의 관계
같은 청구서에 결과를 기다리는 결제가 있으면 새 승인이 결제사로 나가기 전에 422로 막히고, 응답의 detail.kind로 그 이유를 구분할 수 있습니다. 이때는 다시 승인하지 말고 결제 조회로 결과를 확인합니다. 내부적으로도 결제사 응답이 없는 거래는 미확정으로 두고 조회로 확정합니다.
자주 하는 실수
- 요청 시각이나 난수로 키를 매번 새로 만들어 재시도가 새 요청이 되는 경우
- 같은 키에 본문을 조금 바꿔 다시 보내 422를 받는 경우
- 409를 실패로 보고 새 키로 다시 보내는 경우
키 형식은 영문·숫자로 된 충분히 긴 고유값이면 됩니다. 주문 번호와 동작 이름을 이어 만들면 사람이 로그에서 찾기도 쉽습니다.
GET 요청에는 멱등키가 필요하지 않습니다.
