Roblox Studio monetization tool
Developer Product 영수증 핸들러 점검기
판매 중인 상품 ID와 현재 지급 방식을 입력하면 영수증 누락·중복 지급·잘못된 완료 응답 위험을 찾고, 배포 전에 확인할 테스트 매트릭스를 만듭니다. 입력은 브라우저 안에서만 처리하며 Roblox 계정이나 Creator Hub에 연결하지 않습니다.
현재 구현 상태 입력
이 도구가 확인하는 범위
이 점검기는 실제 결제나 Roblox API 호출을 대신하지 않습니다. 사용자가 입력한 설계를 공식 영수증 규칙과 비교해 라우팅 누락, 잘못된 완료 응답, PurchaseId 기록 부재, 교차 서버 중복 지급을 먼저 찾습니다. 상품 가격, 매출, 환불 여부를 판정하거나 특정 구매가 실제로 결제됐다고 인증하지 않습니다.
관련 글인 ProcessReceipt 보상 누락 점검법은 장애가 난 뒤 로그와 반환값을 따라가는 글입니다. 이 페이지는 배포 전에 상품 목록과 처리 방식을 입력해 테스트할 시나리오를 만드는 도구라서 사용 목적을 분리했습니다.
ProcessReceipt와 BindReceiptHandler의 차이
2026년 10월 7일 확인한 MarketplaceService API에는 기존 ProcessReceipt와 새 BindReceiptHandler()가 함께 설명돼 있습니다. ProcessReceipt는 서버 Script 한 곳에서 모든 Developer Product 영수증을 처리하는 콜백입니다. BindReceiptHandler는 Enum.ReceiptType.DeveloperProduct에 핸들러를 바인딩하고, 선택적으로 ProductId 필터를 넣어 상품별 라우팅을 나눌 수 있습니다.
필터와 일치하는 바인딩이 있으면 그것이 우선하고, 일치하는 바인딩이 없으면 ProcessReceipt로 넘어갑니다. 이 때문에 점진적 이전이 가능하지만, 기존 ProcessReceipt와 새 바인딩이 각각 어떤 상품을 맡는지 적어 두지 않으면 누락을 발견하기 어렵습니다. 순수 Bind 방식에서는 등록하지 않은 ID를 처리할 catch-all을 둘지, 안전하게 미처리 상태로 남기며 경고할지 명확히 결정해야 합니다.
Enum.ProductPurchaseDecision.PurchaseGranted 또는 NotProcessedYet를 반환합니다. BindReceiptHandler의 핸들러는 Enum.ReceiptDecision.Processed 또는 NotProcessedYet를 반환합니다. 이름이 비슷하지만 서로 다른 Enum입니다.PromptProductPurchaseFinished는 지급 확인이 아닙니다
구매 프롬프트가 닫혔다는 이벤트를 실제 보상 지급 근거로 사용하면 취소·오류·지연 상태와 서버 영수증 처리가 엇갈릴 수 있습니다. 프롬프트 이벤트는 버튼 상태나 안내 문구를 정리하는 UI 신호로만 다루고, 재화·아이템·부활 같은 실제 혜택은 서버 영수증 핸들러에서 지급해야 합니다.
도구에서 “PromptProductPurchaseFinished에서 실제 보상 지급”을 체크하면 즉시 차단 항목으로 표시합니다. UI가 성공처럼 보이는 것과 Roblox 백엔드가 구매 영수증을 전달하고 서버가 지급을 끝내는 것은 별개의 단계입니다.
PurchaseId가 중복 지급 방지의 기준입니다
공식 ProcessReceipt 문서는 PurchaseId를 특정 구매의 고유 식별자로 설명합니다. 같은 PlayerId가 같은 ProductId를 여러 번 살 수 있는 Developer Product에서는 사용자 ID와 상품 ID만 조합해 기록하면 정상적인 두 번째 구매까지 중복으로 오인할 수 있습니다. 각 구매의 PurchaseId를 기준으로 처리 완료 여부를 저장해야 합니다.
DataStore 모범 사례는 두 서버가 같은 값을 바꿀 수 있을 때 최신 값을 읽고 갱신하는 UpdateAsync()가 손실 업데이트를 줄인다고 설명합니다. 먼저 GetAsync로 확인하고 나중에 SetAsync로 기록하면 두 서버가 동시에 “아직 처리 안 됨”을 볼 수 있습니다. 영수증 지급은 보상 데이터와 처리 기록을 어떻게 원자적으로 묶을지 게임 데이터 구조에 맞춰 설계해야 하며, 이 점검기의 안전 판정이 완전한 트랜잭션을 보장하지는 않습니다.
NotProcessedYet는 타이머 재시도가 아닙니다
공식 문서에 따르면 ProcessReceipt가 NotProcessedYet를 반환해도 같은 서버에서 몇 초마다 자동 재시도되는 구조는 아닙니다. 사용자가 다른 Developer Product 구매를 성공적으로 시작하거나 같은 게임의 서버에 다시 들어오는 등 다음 전달 기회에 호출될 수 있습니다. 따라서 “잠깐 기다리면 다시 온다”는 가정으로 UI 타이머만 붙이지 말고, 다음 접속에서도 지급을 완성할 수 있는 영구 상태를 남겨야 합니다.
구매자가 현재 서버에 없거나 DataStore 호출이 실패했거나 상품 지급 조건을 확인할 수 없다면 완료 결정을 서둘러 반환하지 않습니다. 이미 보상을 지급하고 기록만 실패하는 경계 상황도 있으므로, 지급 함수 자체가 같은 PurchaseId를 두 번 실행해도 결과가 한 번만 반영되는 멱등 구조인지 별도로 검토합니다.
재현 가능한 테스트 순서
- 정적 목록 대조: Creator Hub의 Monetization → Shop에 표시된 Developer Product ID와 서버의 상품 맵을 한 줄씩 대조합니다. 외부 판매를 켠 Listed 상품도 같은 영수증 흐름을 사용합니다.
- 함수 분리: 실제 구매를 만들기 전에 영수증 딕셔너리를 받는 라우팅 함수와 각 상품 지급 함수를 분리합니다. 고정한 테스트 PurchaseId로 같은 입력을 두 번 전달해 두 번째 지급이 생기지 않는지 확인합니다.
- 서버 관점 확인: Studio testing modes의 Test 또는 Server & Clients에서 클라이언트 UI가 아니라 서버 Output과 저장 함수의 결과를 봅니다. 테스트용 데이터와 운영 DataStore가 섞이지 않게 별도 이름·환경을 사용합니다.
- 실패 주입: 구매자 없음, 알 수 없는 ProductId, 저장 함수 오류, 지급 함수 false를 순서대로 재현하고 모두 미처리 결정을 반환하는지 확인합니다.
- 동시 처리 검토: 같은 PurchaseId를 두 작업에서 거의 동시에 호출해 영구 기록이 한 번만 성공하는지 확인합니다. 단순 boolean 메모리 잠금은 다른 서버를 막지 못합니다.
- 통제된 공개 확인: 게시된 테스트 환경에서 실제 영수증 전달을 확인해야 한다면 최소 범위로 진행하고, PurchaseId·ProductId·결정·저장 결과만 기록합니다. 인증 정보나 전체 사용자 데이터를 로그에 남기지 않습니다.
Creator Hub의 경고 보고서가 보일 때
Developer Products 공식 문서는 Listed 상품의 ProcessReceipt 문제를 Roblox가 감지하면 Creator Hub → Monetization → Shop에 배너와 영향받은 상품 보고서를 표시한다고 안내합니다. 보고서의 ProductId를 이 도구에 입력하고 라우팅·저장·완료 응답을 수정한 뒤 게임을 게시하고, 보고서에서 고친 상품을 선택해 Mark as fixed를 누르는 순서입니다.
배너가 없다는 사실은 모든 예외 경로가 완벽하다는 인증이 아닙니다. 반대로 경고된 상품은 외부 노출 자격에 영향을 받을 수 있지만 기존 게임 안 구매 흐름 자체가 즉시 사라진다는 뜻도 아닙니다. 실제 Creator Hub 화면과 최신 공식 안내를 우선하세요.
직접 확인한 범위와 제한
2026년 10월 7일 Windows 데스크톱 브라우저에서 Roblox Creator Hub의 MarketplaceService API, Developer Products, DataStore 모범 사례, Studio testing modes 공개 HTML과 Markdown 원문을 대조했습니다. Markdown 메타데이터의 마지막 갱신 시각은 각각 2026-10-06 20:16:05 UTC, 20:16:02 UTC, 20:15:54 UTC, 20:16:10 UTC로 표시됐습니다.
- BindReceiptHandler의 필터 우선 처리와 ProcessReceipt 폴백, 두 API의 서로 다른 반환 Enum, PurchaseId·PlayerId·ProductId 필드, 미처리 영수증의 전달 조건과 교차 서버 동시 실행 가능성을 문서에서 확인했습니다.
- Robux를 쓰거나 실제 Developer Product를 만들지 않았고, 공개 서버 영수증·Creator Hub 경고 보고서·외부 판매를 직접 실행하지 않았습니다.
- 입력한 ProductId는 Roblox에 존재하는지 조회하지 않습니다. 숫자 형식과 중복만 검사하며 상품 소유 게임·가격·Listed 상태는 Creator Hub에서 따로 확인해야 합니다.
- 생성되는 등록 코드는 라우팅 뼈대입니다. 지급 함수, DataStore 스키마, 재시도 큐, 분석 로그, 환불·운영 절차를 자동 생성하지 않습니다.
- 초기화하면 ProcessReceipt 1곳, UpdateAsync 기록, 지급·저장 뒤 완료, 구매자 부재 시 재전달, 교차 서버 보호와 catch-all 켜짐 상태로 돌아갑니다.