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
이메일 문의
contact@ginzaplay.com 으로 연락. 사이트 주소·예상 규모·원하는 게임(부스트 / 5분 / 둘 다)을 알려주시면 됩니다.
- 2
검토
이메일 커뮤니케이션으로 진행합니다.
- 3
정보 상호 전달
아래 4절의 두 표를 채웁니다. 저희가 키를 발급하고, 귀사가 지갑 주소·출처·IP·한도를 알려주십니다. 키는 안전한 경로로 따로 전달합니다.
- 4
연동 테스트
샌드박스에서 전체 루프를 돌립니다. 귀사 지갑을 구현하기 전에도 레퍼런스 지갑으로 먼저 확인할 수 있습니다 (13절 체크리스트).
- 5
연동 완료 · 오픈
라이브 오퍼레이터로 전환하고 실제 출처·IP를 잠급니다. 이후 한도·환수율은 포털에서 직접 조정하십니다.
4주고받는 값
① GinzaPlay → 귀사
| 값 | 예시 | 성격 | 쓰임 |
|---|---|---|---|
| operator_id | op_yoursite | 공개 | 귀사 식별자. 임베드 URL의 ?op= 와 모든 요청 본문에 들어갑니다 |
| secret | 43자 랜덤 문자열 | 1급 비밀 | HMAC-SHA256 서명 키. 양방향(귀사→저희 launch, 저희→귀사 콜백)에 같은 키를 씁니다. 서버 환경변수에만 두세요 |
| 포털 비밀번호 | 계정 생성 시 1회 발급 | 비밀 | 관리 포털 로그인용. 첫 접속 후 포털에서 변경하세요 |
| 포털 주소 | /op/crypto | 공개 | 귀사 전용 백오피스 |
| 샌드박스 계정 | 테스트용 operator_id + 키 | 비밀 | 라이브 전 검증용. 레퍼런스 지갑이 붙어 있어 귀사 지갑 없이도 테스트됩니다 |
② 귀사 → GinzaPlay
| 값 | 예시 | 필수 | 쓰임 |
|---|---|---|---|
| walletUrl | https://api.yoursite.com/mc/wallet | 필수 | 지갑 콜백 베이스 URL. 뒤에 /balance /bet /win /rollback /status 가 붙습니다 (8절). HTTPS 필수 |
| allowedOrigins | https://*.yoursite.com | 선택 | 위젯을 임베드할 사이트 출처. 와일드카드·쉼표 나열 가능. 비워두면 임베드 제한을 걸지 않습니다 — 아래에서 고르세요 |
| ipAllowlist | 1.2.3.4, 5.6.7.8 | 라이브 필수 | Launch를 호출할 귀사 서버의 공인 IP. 샌드박스에서는 비워도 되지만, 라이브는 비면 전부 차단됩니다 (아래) |
| currency / 라벨 | KRW / 원 | 필수 | 정산 통화와 화면 표시 단위 |
| 한도 | 최소·최대 베팅, 최대 당첨, 미결 노출 상한 | 필수 | 12절 참조. 이후 포털에서 직접 조정합니다 |
| payoutRatePct | 100 | 선택 | 5분 업다운 환수율(%). 기본 100이며, 낮추면 그만큼 귀사 마진이 됩니다 |
| 기술 담당자 | 이메일 · 연락 수단 | 필수 | 지급 실패·기록 불일치 경보를 받을 곳 |
도메인은 두 곳에 쓰입니다 — 귀사 사이트 주소는 allowedOrigins(브라우저가 임베드를 허용할 출처), 귀사 API 주소는 walletUrl(저희 서버가 돈을 호출할 곳)입니다. 서로 다른 도메인이어도 됩니다.
임베드 출처 제한 — 두 가지 중 선택
브라우저가 임베드를 막는 유일한 수단은 frame-ancestors 헤더이고, 이건 도메인만 받습니다. IP로는 불가능합니다 — iframe을 불러오는 것은 엔드유저의 브라우저라, 그 요청에 귀사 서버 IP가 등장하지 않습니다.
| 등록 | 미등록 | |
|---|---|---|
| 아무 사이트가 임베드 | 막힘 | 가능 |
| 위조 토큰으로 세션 시작 | 401 | 401 |
| 사용한 토큰 재사용 | 401 | 401 |
| 관리 부담 | 도메인 바뀌면 갱신 | 없음 |
고르는 기준은 루트 도메인입니다. 서브도메인이 아무리 많아도 루트가 고정이면 등록이 한 줄로 끝나고, 반대로 루트가 여러 개이면서 자주 바뀌면 등록은 계속 따라다니는 작업이 됩니다. 후자라면 미등록이 맞습니다 — 갱신을 놓쳐 임베드가 죽는 쪽이 실제로 더 위험합니다.
등록하시는 경우 — 와일드카드가 됩니다. 서브도메인이 몇 개든, 새로 생겨도 재등록이 필요 없습니다. 루트 도메인이 여러 개면 쉼표로 나열하세요.
allowedOrigins: https://*.yoursite.com, https://www.other.co.kr → 응답 헤더: frame-ancestors 'self' https://*.yoursite.com https://www.other.co.kr
미등록으로 두시는 경우 — 이 업계의 일반적인 구성입니다. 임베드에는 여전히 유효한 1회용 launch 토큰이 필요하고 그건 귀사 백엔드만 발급하므로, 토큰 없이 붙인 위젯은 빈 화면이 뜹니다. 돈이 걸린 관문은 그대로입니다.
미등록일 때 남는 위험 좁히기
남는 위험이 launch URL 유출 하나뿐이므로, 그 URL이 브라우저 밖으로 나가지 않게 하는 것으로 대부분 닫힙니다. 서버 비용도 추가 작업도 들지 않습니다.
- ☑ 페이지를 렌더할 때 서버에서 발급해 곧바로 iframe
src에 넣으세요. 미리 만들어 두면 쓰이기 전까지 120초가 흘러갑니다. - ☑ launch URL을 리다이렉트·링크·공유 버튼에 쓰지 마세요. 사용자가 복사할 수 있는 형태가 되면 그게 유출 경로입니다.
- ☑ 접근 로그·APM에서 제외하세요. 토큰은 프래그먼트(#)에 있어 서버 로그에는 안 남지만, 프런트에서 URL 전체를 수집하는 도구에는 남습니다.
- ☑ 사용자 한 명당 필요할 때 한 번만 발급하세요. 1회용이라 여러 개를 미리 뽑아두면 쓰이지 않은 토큰이 살아 있는 시간만 늘어납니다.
③ 귀사 방화벽에 열어주실 IP
지갑 콜백은 저희 서버 두 대에서 나갑니다(웹·정산). walletUrl로 들어오는 연결을 제한하신다면 두 IP를 모두 허용해 주세요 — 두 주소는 온보딩 시 이메일로 개별 전달드립니다.
403 ip_not_allowed로 떨어지고, 바뀐 것은 모드 하나뿐이라 원인을 찾기 어렵습니다. 전환 전에 등록하세요.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분 |
거절 응답
| HTTP | error | 원인 |
|---|---|---|
| 401 | bad_signature | 서명 불일치 (본문 문자열 확인) |
| 401 | unknown_operator | operator_id 오타 또는 비활성 |
| 401 | stale_or_replayed | timestamp 5분 초과 또는 nonce 재사용 |
| 403 | ip_not_allowed | 등록 IP 밖에서 호출 |
| 403 | operator_suspended | 계정 정지 |
| 429 | rate_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>
| 파라미터 | 값 | 설명 |
|---|---|---|
| op | operator_id | 필수. Launch 응답에 이미 들어 있습니다 |
| only | pro · updown | 생략하면 미니사이트(게임 목록 포함)로 뜹니다 |
| asset | btc · eth | only=updown 일 때만 |
| skin | 아래 표 | 생략 시 terminal |
| #lt | launch 토큰 | 반드시 프래그먼트. 쿼리에 두지 마세요 |
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 /status | 3분마다 | 이 거래들을 갖고 계신지 — 양쪽 기록 대조 |
공통 필드
| 필드 | 타입 | 설명 |
|---|---|---|
| operator_id | string | 귀사 식별자 |
| currency | string | 온보딩 시 등록한 통화 |
| request_uuid | string | 이 호출의 ID — 응답에 그대로 echo 하세요 |
| user | string | 귀사 사용자 ID |
| token | string | Launch 때 넘긴 세션 토큰 (balance·bet에만 옵니다) |
| transaction_uuid | string | 멱등키 — 이 값으로 중복을 막으세요 |
| reference_transaction_uuid | string? | win·rollback이 참조하는 원래 bet의 uuid |
| round | string | 마켓/라운드 식별자 — 5분·예측은 내부 마켓 ID, 부스트는 pro:<포지션ID> |
| amount | integer | minor unit. rollback에는 없습니다 |
표시용 선택 필드 (bet · win)
귀사 베팅내역 UI를 위한 참고 정보입니다. 정산·검증에는 위의 필수 필드만 쓰시고, 아래는 없거나 null일 수 있다는 전제로 저장만 해두세요. 가격은 USD(체인링크·정산 기준)와 원화 트윈(_krw)이 함께 갑니다 — 원화 값은 게임 화면과 동일한 고정 환율로 계산되어 유저가 본 숫자와 정확히 일치합니다.
| 필드 | 값 | 설명 |
|---|---|---|
| game | updown · pro · predict | 게임 구분 (5분 / BTC 부스트 / 예측마켓) |
| asset | btc · eth · sol · xrp | 5분·부스트의 기초자산 |
| market_slug | btc-updown-5m-1786286700 | 회차 슬러그 — 끝 숫자가 시작 epoch(초) |
| round_start_at | ISO 8601 (UTC) | 회차 시작 — 귀사 타임존으로 포맷해 "07:20 회차"로 표시 |
| round_end_at | ISO 8601 (UTC) | 회차 종료 |
| side | up · down · long · short | 베팅 방향 (예측마켓은 아웃컴 라벨) |
| odds | number (예: 1.6458) | 확정 배당배율 = 적중 지급 ÷ 베팅액 (환수율 반영) |
| entry_price | number (USD) | 베팅/진입 시점 가격 |
| target_price | number (USD) | 5분 회차 타겟. 예정 회차 베팅은 null (아직 미확정) |
| entry_price_krw · target_price_krw | integer (원) | 위 USD × fx_rate — 게임 화면에 표시된 바로 그 원화 금액 |
| fx_rate | number | 고정 표시 환율 (게임 상수). 정산에는 쓰이지 않습니다 |
| leverage | integer | 부스트 전용 |
응답 — 모든 콜백 공통
{ "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는 가상머니 시뮬레이터입니다 — 실제 예치·환전·상품 교환이 없습니다. 표시되는 시세는 있는 그대로 제공되며 지연될 수 있습니다. 본 문서는 개발자 안내용이며 사전 고지 없이 갱신될 수 있습니다.