콘텐츠로 이동

안전 모델

상태를 바꾸는 요청은 네 관문을 전부 통과해야 나갑니다.

관문 내용
동의 객체 상태변경 메서드는 키워드 전용 consent 를 받습니다. 갓 만든 MutationConsent()allow_* 가 전부 False 이고, 없거나 범주가 다르면 요청을 만들기도 전에 SrtMutationNotAllowedError 입니다
범주 reserve, cancel, payment, refund, coupon 을 하나씩 켭니다. 동의는 경로에도 묶입니다
dry_run=True(기본) 폼을 만들어 검증한 뒤 MutationPreview 로 돌려주고 보내지 않습니다. 카드번호·비밀번호·생년월일·PNR·쿠폰번호·NetFunnel 키는 [REDACTED] 이며 repr 에서도 빠집니다
전송 차단 스위치 safety.SRT_LIVE_MUTATION_CATEGORIES 가 동의와 무관하게 아래 표대로 검사합니다
범주 전송 실제로 확인된 범위
reserve 성인 1명·1여정·일반실·직통 하나뿐. 다인원·예약대기·좌석지정은 미확인
cancel 위와 같은 홀드의 해제뿐
payment 개인카드 일시불 한 건뿐. 단체·법인카드·할부는 미확인
refund 위에서 결제한 그 승차권 한 건뿐
coupon 아니오 구현과 미리보기는 되지만, 답을 받아 본 적이 없습니다

허용목록은 검토된 읽기 전용 경로 26개가 전부입니다. 상태변경 경로 다섯은 그 바깥이라 assert_read_only_request 가 구조적으로 거절합니다. 카드 비밀값(stlCrCrdNo1, vanPwd1, crdVlidTrm1, athnVal1)은 경로가 아니라 본문에서 단속해서 payment 로만 나갑니다.

from srt_mobile_api import MutationConsent

preview = client.reserve(train, consent=MutationConsent(allow_reserve=True))
print(preview.route, preview.payload, preview.note)   # "dry-run: not sent"

# 아래는 미리보기가 아니라 실계정에 진짜로 좌석을 잡는 호출
hold = client.reserve(train, consent=MutationConsent(allow_reserve=True, dry_run=False))
print(hold.pnr_no)      # 미결제 홀드 — 이제 호출자 책임

결제는 카드 종류를 하나 더 밝혀야 합니다. fake_card_only=True(과금 없는 테스트 카드, 기본값)와 real_card_acknowledged=True(실제 PAN, 돈이 움직임) 중 정확히 하나여야 하고, 둘 다 비거나 둘 다 세우면 거절합니다.

NetFunnel 키를 다시 받는 경우 말고는 스스로 재시도하지 않습니다. 예약은 절대로요 — 재시도한 예약은 이중예약입니다.

한계

SRT 앱은 WebView 껍데기입니다. 화면 대부분이 서버 렌더링 HTML 이고, 결제 단계는 TransKey 키패드와 RaonSecure FIDO SDK 를 지나서 HTTP 클라이언트로는 재현할 수 없습니다.

  • 단체 예약 — 일부러 뺐습니다. 엔드포인트가 PNR 홀드가 아니라 서버 렌더링 결제 페이지를 돌려줍니다. 조회는 그대로 남아 있습니다.
  • 예약대기·왕복 — 구현되었고 실서비스로 확인된 적은 없습니다.
  • 환승 예약 — 조회만 확인되었고, 둘째 슬롯 필드명 다섯 개는 유추입니다.
  • 할인쿠폰 등록 — 구현되어 있으나 전송 관문이 닫혀 있습니다.
  • 할인 승차권·청소년 조회 — 요청 형태에는 근거가 있고 효과는 미확인입니다.
  • 앱의 WebView 결제 경로(TransKey + FIDO), 네이티브 브리지, 외부 코레일 좌석도 — 제외.

무엇을 하면 각각이 확인되는지는 docs/VERIFICATION.md 에 있습니다.

조회는 NetFunnel 대기열 뒤에 있고, 서버가 보기에 이 클라이언트는 앱과 구별되지 않습니다. 반복문으로 두드리면 본인은 IP 차단을, 남들은 대기열 오염을 얻습니다.

동의 객체와 범주 이름은 API 레퍼런스 에 있습니다 — MutationConsent, MutationCategory, require_mutation_consent.