인앱결제 get-order-status API 호출 시 TCP 즉시 종료 (SocketError: other side closed)

이 글의 성격은 무엇인가요?

질문 / 문제 해결

내용을 설명해주세요

안녕하세요. 앱인토스 미니앱 인앱결제 연동 중인데 서버에서 토스 API 호출 시 응답을 받지 못합니다.

환경:

  • 서버: Node.js 22 (서버리스 환경)
  • SDK: @apps-in-toss/web-framework@2.5.1
  • 모드: 샌드박스 테스트

흐름:

  1. 클라이언트: IAP.createOneTimePurchaseOrder 호출 → 결제 성공
  2. SDK가 processProductGrant({orderId}) 콜백 발화
  3. 서버 → 토스 API에 주문 상태 조회 요청
  4. 응답 못 받고 연결 끊김 → false 반환 → 자동 환불 처리됨

요청:
POST https://apps-in-toss-api.toss.im/api-partner/v1/apps-in-toss/order/get-order-status
Headers:
Content-Type: application/json
Authorization: Bearer <콘솔 API 키>
Body: {“orderId”:“<UUID 형식>”}

서버 에러 로그:
SocketError: other side closed
code: ‘UND_ERR_SOCKET’
bytesWritten: 403
bytesRead: 0
TLS 핸드셰이크 후 HTTP 응답을 한 바이트도 못 받고 끊깁니다. 401/403 같은 HTTP 에러도 아니라 진단이 어렵습니다.

질문:

  1. Authorization 헤더 형식이 Bearer <콘솔 API 키>가 맞나요? 공식 docs에 명시가 없어 추정으로 사용 중입니다. 헤더가 잘못돼도 보통 401/403 응답일 텐데 0바이트로 끊기는 게 의아합니다. 정확한 인증 명세 부탁드립니다.
  2. 샌드박스 환경 orderId를 같은 production base URL(apps-in-toss-api.toss.im)에서 조회 가능한가요? 샌드박스 전용 endpoint가 따로 있다면 알려주세요.
  3. 서버 측 IP 화이트리스트 같은 설정이 필요한가요? 응답을 받지도 못하는 게 인프라 단계에서 차단되는 느낌입니다.
  4. 샌드박스에서 발급되는 orderId가 UUID 형식(예: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)으로 오고 있습니다. 이 값을 그대로 get-order-status API의 body에 넣어도 되는 것이 맞나요? 혹시 production 환경에서는 형식이 달라지나요?

확인 부탁드립니다. 감사합니다.

해결됐습니다. 콘솔에서 mTLS 인증서 발급받아서 Cloud Functions에 적용하니 정상 동작합니다. (샌드박스에선 NOT_FOUND 반환되는 게 정상이라고 다른 글에서 확인했고, production 실결제로 E2E 검증 진행 중)