GINZAPLAY B2B · CRYPTO 패키지

Crypto 연동 가이드

이 문서 하나로 연동이 끝납니다. Launch 핸드셰이크부터 지갑 콜백·보안·한도까지 전부 여기 있고, 다른 문서를 참조하지 않습니다.

1무엇을 연동하나

Crypto 패키지에는 게임 2종이 들어 있습니다. 둘은 같은 연동을 공유합니다 — Launch·지갑·보안이 동일하고 임베드 URL만 다릅니다. 한쪽만 붙였다가 다른 쪽을 추가할 때 추가 작업이 없습니다.

게임무엇임베드
BTC 부스트실시간 BTC 롱/숏 · 1~1000배 레버리지?only=pro
5분 업다운5분 뒤 오를지 내릴지 · BTC / ETH?only=updown&asset=btc

귀사 사용자는 GinzaPlay가입하지 않습니다. 귀사가 인증한 사용자를 서명된 토큰으로 넘기면 됩니다. 잔고도 귀사 것이 기준이고, GinzaPlay는 베팅 원장만 갖습니다.

2돈은 어떻게 흐르나

카지노 게임은 보통 라운드가 눈앞에서 끝나므로 잠금(lock) → 정산 → 해제모델을 씁니다. 여기는 다릅니다 — 5분 업다운은 5분 뒤, 부스트 포지션은 며칠 뒤에 끝날 수 있고, 그 사이 사용자는 iframe을 닫습니다. 그래서 스포츠북과 같은 지연 정산(Seamless Wallet)을 씁니다.

베팅/진입   GinzaPlay ──▶ 귀사 /bet       스테이크 즉시 차감 (홀드 아님)
결과 확정   GinzaPlay ──▶ 귀사 /win       적립 · 낙첨이면 amount 0 · refTxUuid로 원 베팅 참조
차감 실패   GinzaPlay ──▶ 귀사 /rollback  되돌림 (무효·환불 포함)
기록 대조   GinzaPlay ──▶ 귀사 /status    3분마다 양쪽 기록 비교

모든 베팅은 정확히 한 번의 종결 콜백을 받습니다 /win(낙첨·전액손실이면 amount 0) 또는 /rollback(무효). 귀사 원장에서 /bet만 있고 종결이 없는 라운드는 “아직 진행 중”이라는 뜻입니다.

  • 잔고의 기준은 귀사입니다. GinzaPlay는 사용자 잔고를 보관하지 않습니다.
  • • 정산은 세션과 무관합니다. 사용자가 접속 중이 아니어도 서버 간 통신으로 적립됩니다.
  • • 손실은 베팅액까지만입니다. 부스트도 청산이 포지션별이라 잔고가 음수로 빠지지 않습니다.

3계약부터 오픈까지

첫 문의에서 오픈까지 다섯 단계입니다. 각 단계는 무엇이 끝나야 다음으로 넘어가는지로 적었습니다.

  1. 1

    이메일 문의

    contact@ginzaplay.com 으로 연락. 사이트 주소·예상 규모·원하는 게임(부스트 / 5분 / 둘 다)을 알려주시면 됩니다.

  2. 2

    검토

    이메일 커뮤니케이션으로 진행합니다.

  3. 3

    정보 상호 전달

    아래 4절의 두 표를 채웁니다. 저희가 키를 발급하고, 귀사가 지갑 주소·출처·IP·한도를 알려주십니다. 키는 안전한 경로로 따로 전달합니다.

  4. 4

    연동 테스트

    샌드박스에서 전체 루프를 돌립니다. 귀사 지갑을 구현하기 전에도 레퍼런스 지갑으로 먼저 확인할 수 있습니다 (13절 체크리스트).

  5. 5

    연동 완료 · 오픈

    라이브 오퍼레이터로 전환하고 실제 출처·IP를 잠급니다. 이후 한도·환수율은 포털에서 직접 조정하십니다.

기술 작업은 3단계부터입니다. 1~2단계에는 개발 리소스가 필요하지 않습니다. 연동 자체는 지갑 콜백 4개와 Launch 호출 하나가 전부라, 보통 며칠 규모입니다.

4주고받는 값

GinzaPlay → 귀사

예시성격쓰임
operator_idop_yoursite공개귀사 식별자. 임베드 URL의 ?op= 와 모든 요청 본문에 들어갑니다
secret43자 랜덤 문자열1급 비밀HMAC-SHA256 서명 키. 양방향(귀사→저희 launch, 저희→귀사 콜백)에 같은 키를 씁니다. 서버 환경변수에만 두세요
포털 비밀번호계정 생성 시 1회 발급비밀관리 포털 로그인용. 첫 접속 후 포털에서 변경하세요
포털 주소/op/crypto공개귀사 전용 백오피스
샌드박스 계정테스트용 operator_id + 키비밀라이브 전 검증용. 레퍼런스 지갑이 붙어 있어 귀사 지갑 없이도 테스트됩니다
secret과 포털 비밀번호는 이메일 본문에 넣지 않습니다. 별도 안전 경로로 전달하고, 유출이 의심되면 포털에서 즉시 재발급하십시오 — 재발급하면 이전 키로 오는 요청은 그 순간부터 거절됩니다.

② 귀사 → GinzaPlay

예시필수쓰임
walletUrlhttps://api.yoursite.com/mc/wallet필수지갑 콜백 베이스 URL. 뒤에 /balance /bet /win /rollback /status 가 붙습니다 (8절). HTTPS 필수
allowedOriginshttps://*.yoursite.com선택위젯을 임베드할 사이트 출처. 와일드카드·쉼표 나열 가능. 비워두면 임베드 제한을 걸지 않습니다 — 아래에서 고르세요
ipAllowlist1.2.3.4, 5.6.7.8라이브 필수Launch를 호출할 귀사 서버의 공인 IP. 샌드박스에서는 비워도 되지만, 라이브는 비면 전부 차단됩니다 (아래)
currency / 라벨KRW / 원필수정산 통화와 화면 표시 단위
한도최소·최대 베팅, 최대 당첨, 미결 노출 상한필수12절 참조. 이후 포털에서 직접 조정합니다
payoutRatePct100선택5분 업다운 환수율(%). 기본 100이며, 낮추면 그만큼 귀사 마진이 됩니다
기술 담당자이메일 · 연락 수단필수지급 실패·기록 불일치 경보를 받을 곳

도메인은 두 곳에 쓰입니다 — 귀사 사이트 주소는 allowedOrigins(브라우저가 임베드를 허용할 출처), 귀사 API 주소는 walletUrl(저희 서버가 돈을 호출할 곳)입니다. 서로 다른 도메인이어도 됩니다.

임베드 출처 제한 — 두 가지 중 선택

브라우저가 임베드를 막는 유일한 수단은 frame-ancestors 헤더이고, 이건 도메인만 받습니다. IP로는 불가능합니다 — iframe을 불러오는 것은 엔드유저의 브라우저라, 그 요청에 귀사 서버 IP가 등장하지 않습니다.

등록미등록
아무 사이트가 임베드막힘가능
위조 토큰으로 세션 시작401401
사용한 토큰 재사용401401
관리 부담도메인 바뀌면 갱신없음

고르는 기준은 루트 도메인입니다. 서브도메인이 아무리 많아도 루트가 고정이면 등록이 한 줄로 끝나고, 반대로 루트가 여러 개이면서 자주 바뀌면 등록은 계속 따라다니는 작업이 됩니다. 후자라면 미등록이 맞습니다 — 갱신을 놓쳐 임베드가 죽는 쪽이 실제로 더 위험합니다.

등록하시는 경우 — 와일드카드가 됩니다. 서브도메인이 몇 개든, 새로 생겨도 재등록이 필요 없습니다. 루트 도메인이 여러 개면 쉼표로 나열하세요.

allowedOrigins:  https://*.yoursite.com, https://www.other.co.kr
→ 응답 헤더:     frame-ancestors 'self' https://*.yoursite.com https://www.other.co.kr

미등록으로 두시는 경우 — 이 업계의 일반적인 구성입니다. 임베드에는 여전히 유효한 1회용 launch 토큰이 필요하고 그건 귀사 백엔드만 발급하므로, 토큰 없이 붙인 위젯은 빈 화면이 뜹니다. 돈이 걸린 관문은 그대로입니다.

미등록을 고르실 때 알고 계셔야 할 것 두 가지입니다. 첫째, launch URL이 외부로 새어 나간 120초 안에는 그 URL을 다른 사이트에 끼워 클릭재킹이 가능합니다. 둘째, 나중에 켜시려면 그 시점의 도메인을 전부 열거해야 해서, 트래픽이 붙은 뒤에는 사실상 그대로 가게 됩니다. 그래서 오픈 전에 정하시는 편이 좋습니다.

미등록일 때 남는 위험 좁히기

남는 위험이 launch URL 유출 하나뿐이므로, 그 URL이 브라우저 밖으로 나가지 않게 하는 것으로 대부분 닫힙니다. 서버 비용도 추가 작업도 들지 않습니다.

  • ☑ 페이지를 렌더할 때 서버에서 발급해 곧바로 iframe src에 넣으세요. 미리 만들어 두면 쓰이기 전까지 120초가 흘러갑니다.
  • ☑ launch URL을 리다이렉트·링크·공유 버튼에 쓰지 마세요. 사용자가 복사할 수 있는 형태가 되면 그게 유출 경로입니다.
  • 접근 로그·APM에서 제외하세요. 토큰은 프래그먼트(#)에 있어 서버 로그에는 안 남지만, 프런트에서 URL 전체를 수집하는 도구에는 남습니다.
  • ☑ 사용자 한 명당 필요할 때 한 번만 발급하세요. 1회용이라 여러 개를 미리 뽑아두면 쓰이지 않은 토큰이 살아 있는 시간만 늘어납니다.

③ 귀사 방화벽에 열어주실 IP

지갑 콜백은 저희 서버 두 대에서 나갑니다(웹·정산). walletUrl로 들어오는 연결을 제한하신다면 두 IP를 모두 허용해 주세요 — 두 주소는 온보딩 시 이메일로 개별 전달드립니다.

ipAllowlist를 비운 채로 라이브에 올리지 마세요. 이 값이 비어 있으면 샌드박스에서는 전부 허용이지만 라이브에서는 전부 차단됩니다 — 같은 빈 값이 모드에 따라 정반대로 동작합니다(fail-closed). 등록하지 않고 전환하면 Launch가 그 순간부터 403 ip_not_allowed로 떨어지고, 바뀐 것은 모드 하나뿐이라 원인을 찾기 어렵습니다. 전환 전에 등록하세요.
한쪽만 열면 조용히 실패합니다. 베팅은 정상으로 보이는데 정산 적립이 도착하지 않고, 저희는 성공할 때까지 30초마다 무기한 재시도합니다 — 로그를 보기 전까지 아무도 눈치채지 못하는 상태가 됩니다.

5Launch 핸드셰이크

사용자가 게임을 열 때 귀사 백엔드가 호출합니다. 브라우저에서 직접 부르면 안 됩니다 — 서명 키가 노출됩니다.

POST /api/op/v1/launch — 요청 본문

{
  "operator_id": "op_yoursite",
  "user":        "귀사 사용자 고유 ID",
  "token":       "귀사 사용자 세션 토큰 — 지갑 콜백 때 그대로 돌려드립니다",
  "currency":    "KRW",
  "lang":        "ko",              // ko | en | ja
  "timestamp":   1785500000000,     // 유닉스 ms · ±5분 벗어나면 거절
  "nonce":       "1회성 임의값"      // 8~200자 · 10분 내 재사용 거절
}

본문 원문 문자열 그대로를 secret으로 HMAC-SHA256 하고, hex 결과를 X-MC-Signature 헤더에 넣습니다. 직렬화한 문자열과 실제 전송 본문이 한 글자라도 다르면 서명이 깨집니다.

200 OK — 응답

{
  "url": "https://ginzaplay.com/widget?op=op_yoursite#lt=lt_xxxxx&lang=ko",
  "lt":  "lt_xxxxx"
}
url을 직접 조립하지 마세요 — 받은 값을 그대로 쓰세요. ?op=가 빠지면 위젯이 “임베드 주소에 op 파라미터가 없습니다”로 멈춥니다. lt는 프래그먼트(#)에 있어야 하고요 — 프래그먼트는 Referer 헤더에도 서버 접근 로그에도 남지 않습니다.
성질
lt 유효기간120초 · 1회용 (두 번째 교환은 invalid_or_used_token)
세션 유효기간12시간
세션 전달쿠키 아님 — X-MC-Session 헤더 (3rd-party 쿠키 차단 환경 대응)
timestamp 허용±5분
nonce 기억10분

거절 응답

HTTPerror원인
401bad_signature서명 불일치 (본문 문자열 확인)
401unknown_operatoroperator_id 오타 또는 비활성
401stale_or_replayedtimestamp 5분 초과 또는 nonce 재사용
403ip_not_allowed등록 IP 밖에서 호출
403operator_suspended계정 정지
429rate_limited분당 600회 초과

lt는 iframe이 알아서 세션으로 교환합니다. 프론트에서 직접 교환해야 할 때만 POST /api/op/v1/session { lt, op }를 보내 { session }을 받으세요.

6코드 — Launch 요청

Node.js — 위젯 URL 받기

import crypto from "crypto";

const OPERATOR_ID = "op_yoursite";
const SECRET      = process.env.MC_SECRET;      // 온보딩 시 발급
const MC_BASE     = "https://ginzaplay.com";

export async function getWidgetUrl(user, userToken) {
  const body = {
    operator_id: OPERATOR_ID,
    user,                                        // 귀사 사용자 ID
    token: userToken,                            // 귀사 사용자 세션 토큰
    currency: "KRW",
    lang: "ko",
    timestamp: Date.now(),
    nonce: crypto.randomUUID(),
  };

  // 서명 대상은 '보내는 본문 문자열' 그 자체 — 다시 stringify 하지 마세요.
  const payload = JSON.stringify(body);
  const sig = crypto.createHmac("sha256", SECRET).update(payload).digest("hex");

  const res = await fetch(MC_BASE + "/api/op/v1/launch", {
    method: "POST",
    headers: { "content-type": "application/json", "X-MC-Signature": sig },
    body: payload,
  });
  if (!res.ok) throw new Error("launch failed: " + (await res.text()));

  const { url } = await res.json();
  return url;            // 그대로 iframe src 로. 재조립 금지 (?op= 가 필요합니다)
}

게임을 고르려면 — 받은 url에 only 파라미터만 추가

function withGame(url, game) {
  const u = new URL(url);                        // 프래그먼트(#lt=)는 그대로 보존됩니다
  if (game === "boost")  u.searchParams.set("only", "pro");
  if (game === "btc5") { u.searchParams.set("only", "updown"); u.searchParams.set("asset", "btc"); }
  if (game === "eth5") { u.searchParams.set("only", "updown"); u.searchParams.set("asset", "eth"); }
  u.searchParams.set("skin", "minimal");         // 선택
  return u.toString();
}

7임베드 URL

<iframe
  src="https://ginzaplay.com/widget?op=op_yoursite&only=pro#lt=LAUNCH_TOKEN"
  style="width:100%;height:100%;border:0"
  allow="clipboard-write"
  title="GinzaPlay BTC 부스트"
></iframe>
파라미터설명
opoperator_id필수. Launch 응답에 이미 들어 있습니다
onlypro · updown생략하면 미니사이트(게임 목록 포함)로 뜹니다
assetbtc · ethonly=updown 일 때만
skin아래 표생략 시 terminal
#ltlaunch 토큰반드시 프래그먼트. 쿼리에 두지 마세요

skin

skin이름느낌
terminal터미널다크 트레이딩 터미널 톤 · skin 생략 시 기본
exchange익스체인지거래소풍 다크
minimal미니멀 / 라이트밝은 화이트 톤
game게임 / 네온네온 액센트

크기 — 반응형이라 폭 320px부터 동작합니다. 세로는 임베드가 스스로 스크롤하므로 고정 높이(예: 100dvh 또는 컨테이너 높이)를 주세요. 부모 페이지가 늘어나지 않습니다.

8Wallet 콜백 5종

GinzaPlay → 귀사 walletUrl. 등록한 베이스 URL 뒤에 아래 경로가 붙습니다. 모든 호출은 Launch와 같은 방식·같은 키로 서명되어 오고 (X-MC-Signature), 검증은 필수입니다. 금액은 전부 정수 minor unit(1원 = 1)이며 소수점은 없습니다.

경로언제하는 일
POST /balance위젯 로드·주기적현재 잔고 조회
POST /bet베팅·포지션 진입차감. 부족하면 NOT_ENOUGH_MONEY
POST /win정산·청산·캐시아웃적립. 낙첨·전액손실이면 amount 0 (라운드 종결 신호). refTxUuid로 원 베팅 참조
POST /rollback차감 후 실패그 차감을 되돌림
POST /status3분마다이 거래들을 갖고 계신지 — 양쪽 기록 대조

공통 필드

필드타입설명
operator_idstring귀사 식별자
currencystring온보딩 시 등록한 통화
request_uuidstring이 호출의 ID — 응답에 그대로 echo 하세요
userstring귀사 사용자 ID
tokenstringLaunch 때 넘긴 세션 토큰 (balance·bet에만 옵니다)
transaction_uuidstring멱등키 — 이 값으로 중복을 막으세요
reference_transaction_uuidstring?win·rollback이 참조하는 원래 bet의 uuid
roundstring마켓/라운드 식별자 — 5분·예측은 내부 마켓 ID, 부스트는 pro:<포지션ID>
amountintegerminor unit. rollback에는 없습니다

표시용 선택 필드 (bet · win)

귀사 베팅내역 UI를 위한 참고 정보입니다. 정산·검증에는 위의 필수 필드만 쓰시고, 아래는 없거나 null일 수 있다는 전제로 저장만 해두세요. 가격은 USD(체인링크·정산 기준)원화 트윈(_krw)이 함께 갑니다 — 원화 값은 게임 화면과 동일한 고정 환율로 계산되어 유저가 본 숫자와 정확히 일치합니다.

필드설명
gameupdown · pro · predict게임 구분 (5분 / BTC 부스트 / 예측마켓)
assetbtc · eth · sol · xrp5분·부스트의 기초자산
market_slugbtc-updown-5m-1786286700회차 슬러그 — 끝 숫자가 시작 epoch(초)
round_start_atISO 8601 (UTC)회차 시작 — 귀사 타임존으로 포맷해 "07:20 회차"로 표시
round_end_atISO 8601 (UTC)회차 종료
sideup · down · long · short베팅 방향 (예측마켓은 아웃컴 라벨)
oddsnumber (예: 1.6458)확정 배당배율 = 적중 지급 ÷ 베팅액 (환수율 반영)
entry_pricenumber (USD)베팅/진입 시점 가격
target_pricenumber (USD)5분 회차 타겟. 예정 회차 베팅은 null (아직 미확정)
entry_price_krw · target_price_krwinteger (원)위 USD × fx_rate — 게임 화면에 표시된 바로 그 원화 금액
fx_ratenumber고정 표시 환율 (게임 상수). 정산에는 쓰이지 않습니다
leverageinteger부스트 전용

응답 — 모든 콜백 공통

{ "status": "RS_OK", "balance": 990000, "request_uuid": "req_…" }

상태 코드

  • RS_OK · 정상
  • RS_ERROR_NOT_ENOUGH_MONEY · 잔고 부족
  • RS_ERROR_DUPLICATE_TRANSACTION · 멱등 중복
  • RS_ERROR_TRANSACTION_DOES_NOT_EXIST · 참조한 bet 없음
  • RS_ERROR_INVALID_SIGNATURE · 서명 오류
  • RS_ERROR_LIMIT_REACHED · 한도 초과
  • RS_ERROR_USER_DISABLED · 정지된 사용자
  • RS_ERROR_WRONG_SYNTAX · 형식 오류

POST /status — 기록 대조 전용 (요청/응답)

요청  { operator_id, currency, request_uuid, transaction_uuids: ["tx_a", "tx_b", …] }

응답  { "status": "RS_OK", "request_uuid": "req_…",
        "transactions": [
          { "transaction_uuid": "tx_a", "found": true,  "amount": 10000, "type": "bet" },
          { "transaction_uuid": "tx_b", "found": false }
        ] }

Node.js (Express) — 콜백 핸들러 요지

app.post("/wallet/:action", async (req, res) => {
  // 1) 서명 검증 — 원문 바디로. JSON.parse 후 다시 stringify 하면 깨집니다.
  if (!verifyHmac(req.rawBody, req.header("X-MC-Signature"))) {
    return res.json({ status: "RS_ERROR_INVALID_SIGNATURE" });
  }
  const b = req.body;

  // 2) 멱등 — 이미 처리한 uuid면 '그때의 결과'를 그대로 반환. 다시 반영 금지.
  const prev = await findTxn(b.transaction_uuid);
  if (prev) return res.json({ ...prev.result, request_uuid: b.request_uuid });

  if (req.params.action === "bet") {
    const bal = await getBalance(b.user);
    if (bal < b.amount)
      return res.json({ status: "RS_ERROR_NOT_ENOUGH_MONEY", balance: bal,
                        request_uuid: b.request_uuid });
    const after = await debit(b.user, b.amount, b.transaction_uuid, b.round);
    return res.json(save(b, { status: "RS_OK", balance: after }));
  }

  if (req.params.action === "win") {
    // 참조된 bet이 실제로 존재할 때만 적립하세요.
    // (user, refTxUuid)만 믿고 적립하면 정산 위조에 그대로 노출됩니다.
    const bet = await findTxn(b.reference_transaction_uuid);
    if (!bet) return res.json({ status: "RS_ERROR_TRANSACTION_DOES_NOT_EXIST",
                                request_uuid: b.request_uuid });
    const after = await credit(b.user, b.amount, b.transaction_uuid, bet.id);
    return res.json(save(b, { status: "RS_OK", balance: after }));
  }

  if (req.params.action === "rollback") {
    const bet = await findTxn(b.reference_transaction_uuid);
    // 되돌릴 차감이 없으면 이 코드로 답하세요 → '정상 종료'로 처리됩니다.
    if (!bet) return res.json({ status: "RS_ERROR_TRANSACTION_DOES_NOT_EXIST",
                                request_uuid: b.request_uuid });
    const after = await revert(b.user, bet, b.transaction_uuid);
    return res.json(save(b, { status: "RS_OK", balance: after }));
  }
});

9재시도와 거래 대조

  • 🔁 적립 재시도는 무기한입니다. /win·/rollback이 실패하거나 응답이 끊기면 같은 transaction_uuid로 30초마다 성공할 때까지 다시 호출합니다. 반복 호출을 예외가 아니라 정상 흐름으로 처리하세요 — 멱등이 되어 있으면 두 번 반영되지 않습니다.
  • 🧾 되돌릴 게 없으면 명확히 답하세요. /rollback의 참조 차감이 없다면 RS_ERROR_TRANSACTION_DOES_NOT_EXIST를 주세요. “애초에 차감이 없었으니 되돌릴 것도 없음 = 정상 종료”로 처리합니다. 다른 에러를 주면 영원히 재시도합니다.
  • 🔍 3분마다 양쪽 기록을 대조합니다. /status로 최대 100건씩 묶어 물어보고, 귀사에 없는 차감·적립이 있으면 경보로 잡습니다. 지갑이 응답하지 않는 것과 “없다”고 답하는 것은 다르게 처리하니, 불확실할 때는 응답하지 마세요.

10보안 체크리스트

  • 서명은 원문 바디로 검증 — 파싱 후 재직렬화하면 공백·키 순서가 달라져 깨집니다.
  • 멱등은 uuid + 종류 + 금액까지 확인. 재시도에는 그때의 결과를 반환.
  • 적립은 참조 bet이 있을 때만. (user, refTxUuid)만으로 승인하면 정산 위조가 됩니다.
  • ipAllowlist 등록 (Launch 호출 서버). allowedOrigins는 선택이며, 미등록을 고르셨다면 그 상태가 의도된 것인지만 확인하세요.
  • Launch는 백엔드에서만. 서명 키가 브라우저에 나가면 누구나 아무 사용자로 세션을 열 수 있습니다.
  • 금액은 정수 minor unit. 음수·과대값 가드.
  • ☑ 참고 — 잔고는 클라이언트가 바꿀 수 없습니다. 모든 차감·적립은 서버 간 통신이고, 위젯이 보내는 값으로 잔고가 움직이지 않습니다.

11한도 · 수수료

한도 (오퍼레이터별 설정)

항목기본설명
최소 베팅1,000원이 미만은 거절
최대 베팅설정값베팅 1건당 스테이크 상한
최대 당첨1,000만원1건이 지급받을 수 있는 최대 — 초과 베팅은 거절
미결 노출 상한설정값귀사 전체 미결 지급의무 합계 상한
부스트 포지션동시 20개사용자당

5분 업다운

  • 환수율 98.75% — 하우스 마진 1.25%. 오퍼레이터별로 더 낮출 수 있습니다 (payoutRatePct).
  • 마감 15초 전 신규 베팅 차단 — 지연 봇이 굳어진 결과에 진입하는 것을 막습니다. 청산은 마감까지 열려 있습니다.
  • • 배당은 실제 호가창 기준입니다. 금액이 크면 호가를 더 걸어 사게 되어 배당이 내려가며, 그 값이 베팅 전에 화면에 표시됩니다.

BTC 부스트

  • 수익컷 2~10% — 이익 청산 시 순이익에서. 레버리지에 비례(×1 2% → ×1000 10%)하고 손실·본전 청산은 0입니다. 티켓에 실시간 표시됩니다.
  • 펀딩 시간당 0.1% — 명목가 기준, 1시간까지 무료. 초·분 단위 매매는 사실상 0입니다.
  • 최대 수익 20배 — 포지션당 이익 상한(지급 상한 = 원금×21). 오퍼레이터 지갑의 최악 노출을 베팅액으로 묶습니다.
  • 스프레드 0 — 직접 누른 진입·현금화는 화면가 그대로 체결됩니다.
  • 손절·익절은 시장가 체결 — 설정가에 닿는 순간의 실제 체인링크 시세로 체결됩니다(거래소의 stop-market과 동일). 설정가는 트리거이지 보장 가격이 아니며, 급변동 시 슬리피지가 생길 수 있습니다. 청산 손실은 증거금까지입니다.
  • 포지션 방향 — 기본 원웨이 — 플레이어는 한 번에 한 방향만 보유합니다. 보유 중인 방향과 반대 주문은 one_way_mode로 거부되며, 방향을 바꾸려면 먼저 청산해야 합니다. 같은 방향 추가(최대 20건)와 청산·축소는 항상 가능합니다. 거래소의 원웨이 모드와 동일합니다.
  • 헤지 모드 (선택, 포털에서 ON) — 켜면 롱·숏 동시 보유가 허용되고, 이때 반대 방향 진입에 헤지 수수료가 붙습니다: 겹치는 명목가 × 설정 bp (같은 방향 추가·축소·청산은 없음). 명목가 기준이라 레버리지에 비례합니다 (1bp → ×10은 증거금의 0.1%, ×1000은 10%). 청산 시 손익에서 차감되며 펀딩과 함께 내역에 남습니다. 주문 전 티켓에 금액이 표시되고, 게임 내 규칙 패널 문구도 설정에 따라 자동으로 바뀝니다.
  • • 시세는 체인링크 BTC/USD. 화면가 = 정산가입니다.

12관리 포털

ginzaplay.com/op/crypto operator_id + 비밀번호로 로그인합니다. 비밀번호를 설정하기 계정 생성 시 발급되며, 첫 접속 후 포털에서 바꾸실 수 있습니다. 등록된 IP에서만 접속됩니다.

  • 대시보드 — 미결 노출·베팅액·정산 상태, 지급 실패(STRANDED) 경보
  • 유저 / 베팅 — 사용자별 집계, 상태별 베팅, 최근 내역
  • 설정 — 한도·환수율·walletUrl·키(마스킹) 조회 및 변경

13샌드박스 → 라이브

GinzaPlay레퍼런스 지갑을 호스팅합니다. 귀사 지갑을 구현하기 전에도 launch → 차감 → 정산 적립 → 재시도까지 전체 루프를 돌려볼 수 있습니다. 아래가 전부 확인되면 라이브로 전환합니다.

  • ☑ 서명 검증 — 잘못된 서명을 실제로 거절하는지
  • ☑ 멱등 — 같은 transaction_uuid 재호출에 잔고가 두 번 움직이지 않는지
  • ☑ 세션 없는 정산 — iframe을 닫은 뒤 들어온 /win이 적립되는지
  • ☑ 재시도 — 지갑을 잠깐 내렸다 올렸을 때 결국 적립되는지
  • ☑ rollback 없음 응답 — TRANSACTION_DOES_NOT_EXIST를 주는지
  • ☑ /status 대조 — 물어본 거래를 정확히 답하는지
  • ipAllowlist 등록 완료 — 라이브 전환의 전제조건입니다. 비어 있으면 전환 즉시 Launch가 전부 403이 됩니다
  • ☑ 임베드 출처 제한 여부를 정하고 합의

연동 문의: contact@ginzaplay.com

GinzaPlay는 가상머니 시뮬레이터입니다 — 실제 예치·환전·상품 교환이 없습니다. 표시되는 시세는 있는 그대로 제공되며 지연될 수 있습니다. 본 문서는 개발자 안내용이며 사전 고지 없이 갱신될 수 있습니다.