Files
llm-wiki/raw/company-tech-blogs/idempotency-toss-payments-techblog.md

115 lines
9.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: 토스페이먼츠 — 멱등키 가이드 (Using API / Idempotency-Key)
source_type: official-doc
url: https://docs.tosspayments.com/guides/using-api/idempotency-key
archive_url:
status: raw
confidence: high
tags: [ca-idempotency, toss-payments, korean-fintech, payment-domain]
related_projects: [ca-skeleton-operational-contract]
related_branches: [feature-rate-limit-idempotency-contract, feature-api-contract-baseline]
created: 2026-05-22
last_reviewed: 2026-05-27
---
# 토스페이먼츠 — 멱등키 가이드
> Layer: `raw/company-tech-blogs/` (디렉토리 정정 후보: 토스페이먼츠 공식 개발자 가이드이므로 `raw/official-docs/` 로 이관 적절. 본 migration 에서는 자동 mv 금지 규칙에 따라 위치 유지 — 후속 정리 권고).
> 한국 결제 도메인 표준 구현. ca-tmpl 의 idempotency contract 비교 기준.
> 검증된 요약은 `/ingest` 후 `wiki/concepts/`에 별도 작성.
## Parent / 활용 branch (필수)
> 이 자료가 정당화하는 결정 매핑.
| Branch | 이 자료가 정당화하는 결정 |
| -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| [[raw/branch-notes/feature-rate-limit-idempotency-contract]] | Idempotency contract 의 key scope 4-tuple vs 3-tuple 비교 + TTL 정책 (15일) 비교 + in-flight 충돌 처리 (409 vs wait) 비교 근거 |
| [[raw/branch-notes/feature-api-contract-baseline]] | API contract surface 에 `Idempotency-Key` 헤더 노출 표준 정립 시 vendor 표준 사례로 인용 |
| [[raw/project-notes/ca-skeleton-operational-contract]] | §13. API Contract Surface (Idempotency-Key) + §18. Control Plane Contract (Rate Limit/Idempotency) 의 한국 결제망 reference |
## 출처 / Source
- 원본 URL: https://docs.tosspayments.com/guides/using-api/idempotency-key
- 보조: https://docs.tosspayments.com/blog/what-is-idempotency (개념 설명 블로그)
- 참고: astor-dev "결제 도메인에서의 멱등성 보장" (개인 블로그, 사례 분석)
- 아카이브 URL: (미수집)
- 저자 / 조직: 토스페이먼츠 (TossPayments) Developer Documentation
- 발행일: rolling docs (페이지 자체에 명시 없음)
- 마지막 확인일: 2026-05-27
## 왜 저장했는지 / Why archived
한국 결제 도메인의 vendor 표준 구현. ca-tmpl 이 한국 환경에서 운영된다면 토스의 정책 (4-tuple scope, 15일 TTL, 409 in-flight) 이 직접 비교 대상.
## 핵심 인용 / Key quotes (verbatim)
> [§Idempotency-Key 사용] "요청 헤더에 `Idempotency-Key`를 추가하면 멱등한 요청을 보낼 수 있습니다"
> [§Idempotency-Key 사용] "멱등키는 UUID(/resources/glossary/uuid)와 같이 충분히 무작위적인 고유 값으로 생성해주세요"
> [§멱등성 보장 메커니즘] "토스페이먼츠 서버는 상점에서 API 요청 헤더로 보낸 멱등키와 API 키, API 주소, HTTP 메서드 조합이 같은 요청이 있는지 확인해서 멱등성을 보장합니다"
> [§TTL] "멱등키는 처음 요청에 사용한 날부터 15일간 유효합니다"
> [§에러] "HTTP `400 - INVALID_IDEMPOTENCY_KEY`"
> [§에러] "HTTP `409 - IDEMPOTENT_REQUEST_PROCESSING`"
> [§주의] "멱등한 요청에서 에러가 반환되었을 때 멱등키를 변경해서 동일한 요청을 재시도하는 것은 위험이 있습니다"
## Claims Extracted / 추출된 주장
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|---|---|---|---|---|---|
| TOSS-IDEMP-C1 | 모든 POST API 에 `Idempotency-Key` 헤더를 추가하여 멱등 요청 가능, 값은 UUID 등 충분히 무작위 고유 값 권장 | [§Idempotency-Key 사용] "요청 헤더에 `Idempotency-Key`를 추가하면 멱등한 요청을 보낼 수 있습니다" + "멱등키는 UUID(/resources/glossary/uuid)와 같이 충분히 무작위적인 고유 값으로 생성해주세요" | `official-vendor-doc` | TossPayments API 의 POST endpoint | UUID 외 다른 형식 (예: 비즈니스 키, hash) 사용 시 충돌 위험은 별도 — 본 인용은 권장만 |
| TOSS-IDEMP-C2 | 멱등성 보장 범위는 **(멱등키, API 키, API 주소, HTTP 메서드) 4-tuple** 조합 | [§멱등성 보장 메커니즘] "토스페이먼츠 서버는 상점에서 API 요청 헤더로 보낸 멱등키와 API 키, API 주소, HTTP 메서드 조합이 같은 요청이 있는지 확인해서 멱등성을 보장합니다" | `official-vendor-doc` | TossPayments 가맹점 × endpoint × method 단위 | request body 가 다를 때의 처리 정책은 인용 범위에 없음 — body fingerprint 정책 부재 |
| TOSS-IDEMP-C3 | 멱등키 유효 기간은 첫 요청일로부터 **15일** | [§TTL] "멱등키는 처음 요청에 사용한 날부터 15일간 유효합니다" | `official-vendor-doc` | TossPayments idempotency store | 15일 정책이 모든 결제 도메인의 표준이라는 뜻은 아님. Stripe v1 24h / v2 30일과 다른 vendor-specific 결정 |
| TOSS-IDEMP-C4 | 잘못된 멱등키 형식 (예: 300자 초과 등) 은 `400 - INVALID_IDEMPOTENCY_KEY`, in-flight 동일 요청은 `409 - IDEMPOTENT_REQUEST_PROCESSING` | [§에러] "HTTP `400 - INVALID_IDEMPOTENCY_KEY`" + "HTTP `409 - IDEMPOTENT_REQUEST_PROCESSING`" | `official-vendor-doc` | TossPayments 의 표준 에러 매핑 | 409 가 즉시 반환되므로 클라이언트가 backoff 책임. wait/poll 동작 안 함 |
| TOSS-IDEMP-C5 | 멱등 요청 에러 시 키 변경 후 재시도는 위험이 있다 (공식적으로 권장 안 됨) | [§주의] "멱등한 요청에서 에러가 반환되었을 때 멱등키를 변경해서 동일한 요청을 재시도하는 것은 위험이 있습니다" | `official-vendor-doc` | retry 로직 설계 | 동일 키로 재시도해야 하는 정확한 조건 / 결과 코드별 분기는 본 인용에 없음 — 별도 가이드 확인 필요 |
| TOSS-IDEMP-C6 | 동일 키 + 동일 4-tuple + 다른 body 의 처리 정책은 본 인용 범위 내에 **명시 없음** | (부재 자체가 claim) | `needs-confirmation` | body fingerprint mismatch 처리 | 토스가 body diff 를 무시한다는 뜻도, 거부한다는 뜻도 아님. 문서가 직접 다루지 않음 |
## Usage Boundaries / 적용 경계
- **이 자료가 직접 증명하는 것**:
- `TOSS-IDEMP-C1` ~ `C5`: TossPayments idempotency API 의 헤더 사용법, key scope 4-tuple, TTL 15일, 에러 매핑, retry 위험 안내
- **이 자료가 증명하지 않는 것**:
- `TOSS-IDEMP-C6`: same-key + different-body 시 동작 (body fingerprint 정책)
- idempotency store 의 backend (DB vs Redis vs 그 외) — 외부 관찰 불가
- 다른 한국 결제사 (KG이니시스, 카카오페이 등) 도 동일 정책을 사용하는지
- in-flight 409 가 race condition 의 짧은 window 도 흡수하는지 (즉시 거부이므로 클라이언트 backoff 필수로 추정)
- **내 프로젝트에 적용하려면 추가 확인이 필요한 것**:
- ca-tmpl 의 3-tuple `(principal, key, useCaseName)` 과 토스의 4-tuple `(account, key, URL, method)` 매핑 시 `useCaseName` 이 URL+method 역할을 충분히 대체하는지 (비즈니스 식별자 일관성)
- ca-tmpl 의 15일이 아닌 24h TTL 결정의 위험 (긴 retry window 손실 vs 저장소 부하)
## 메모 / Notes
> 검증되지 않은 내 해석은 여기에 두지 말 것 — wiki source-summary 단계에서.
- **key scope**: 4-tuple = `(API 키 = 가맹점, idempotency-key, API 주소, HTTP 메서드)`. ca-tmpl 의 3-tuple `(principal, key, useCaseName)` 와 유사하나 토스는 method 까지 명시.
- **TTL**: 15일 (Stripe v1 24h 보다 길고, v2 30일보다 짧음).
- **저장소**: 명시 안됨 — 외부에서 알 수 없음. 결제 도메인 특성상 영속 저장 추정 (검증 불가).
- **duplicate 처리**:
- 완료 후 동일 키 재요청 → first 응답 그대로 replay (`C2` 의 일반적 동작).
- in-flight 동일 키 재요청 → `409 IDEMPOTENT_REQUEST_PROCESSING` (즉시 거부, ca-tmpl 처럼 wait 안 함).
- **fingerprint (same key, different body)**: 공식 문서에 명시 없음 (`C6` 참조).
- **장점 (추론)**: 가맹점 × endpoint × method 까지 분리되어 사고 범위가 좁음. 15일 긴 TTL.
- **단점 (추론)**: body fingerprint 정책 부재. in-flight 409 → 클라이언트 backoff 책임.
- **ca-tmpl 과의 차이 (대안 비교 후보, wiki/projects 추출 시 활용)**:
- 토스 4-tuple ↔ ca-tmpl 3-tuple. `useCaseName` 이 URL+method 역할 통합. 동일 사상.
- TTL: 토스 15일 ≫ ca-tmpl 24h. ca-tmpl 이 더 짧고 보수적.
- in-flight: 토스 즉시 409 vs ca-tmpl 200ms wait → ca-tmpl 이 클라이언트 친화적.
- fingerprint: 토스 미명시 vs ca-tmpl 명시적 422 → ca-tmpl 이 더 엄격.
## Related / 관련
- 같은 주제 다른 raw:
- [[raw/company-tech-blogs/idempotency-brandur-stripe-postgres]]
- [[raw/company-tech-blogs/idempotency-redis-vs-db-storage]]
- 인용하는 branch:
- [[raw/branch-notes/feature-rate-limit-idempotency-contract]]
- [[raw/branch-notes/feature-api-contract-baseline]]
- 인용하는 project:
- [[raw/project-notes/ca-skeleton-operational-contract]] (§13, §18)
- 인용한 wiki 요약: (미작성)