================================================================================ BITUPGO 파트너 API 연동 가이드 ================================================================================ 목차 ---- 1. 개요 2. 인증 3. 파트너 API 엔드포인트 4. 심리스 월렛 콜백 5. 서명 검증 6. 에러 코드 7. 연동 플로우 8. 코드 예제 ================================================================================ 1. 개요 ================================================================================ 기본 URL: https://bet2.bitupgo.com 주요 기능: - 토큰 기반 iframe 로그인 (비밀번호 노출 없음) - 콜백을 통한 실시간 잔액 동기화 - 심리스 월렛 (파트너사가 유저 잔액 관리) ================================================================================ 2. 인증 ================================================================================ 모든 API 요청은 HTTP 헤더를 통한 인증이 필요합니다: 헤더 이름: X-Partner-Key 헤더 값: callback_secret_key (파트너 대시보드에서 확인) 예시: X-Partner-Key: sk_live_abc123def456... ================================================================================ 3. 파트너 API 엔드포인트 ================================================================================ ------------------------------------------------------------------------------ 3.1 로그인 - iframe용 토큰 URL 발급 ------------------------------------------------------------------------------ POST /api/partner.php?action=login 설명: 임시 로그인 토큰을 생성하고 iframe에 삽입할 URL을 반환합니다. 유저가 존재하지 않으면 자동 생성됩니다. 요청 헤더: Content-Type: application/json X-Partner-Key: {시크릿키} 요청 본문: { "user_id": "player123", // 필수: 유저 고유 식별자 "user_pw": "any_password", // 필수: 임의 문자열 (저장 안됨) "nickname": "닉네임" // 선택: 표시 이름 } 성공 응답 (200): { "success": true, "login_url": "https://bet2.bitupgo.com/auth/token_login.php?token=eyJ...", "expires_in": 60 } 오류 응답: { "success": false, "message": "Invalid partner key" } 사용법: login_url을 iframe src로 설정. 토큰은 60초 후 만료됩니다. ------------------------------------------------------------------------------ 3.2 잔액 조회 ------------------------------------------------------------------------------ GET /api/partner.php?action=balance&user_id={user_id} 설명: 유저의 현재 잔액을 반환합니다. 요청 헤더: X-Partner-Key: {시크릿키} 쿼리 파라미터: user_id - 필수: 유저 식별자 성공 응답 (200): { "success": true, "data": { "user_id": "player123", "nickname": "닉네임", "balance": 50000.00 } } ------------------------------------------------------------------------------ 3.3 배팅 결과 조회 ------------------------------------------------------------------------------ GET /api/partner.php?action=result&tx_id={transaction_id} 설명: 특정 배팅의 결과를 트랜잭션 ID로 조회합니다. 요청 헤더: X-Partner-Key: {시크릿키} 쿼리 파라미터: tx_id - 필수: debit 콜백에서 받은 트랜잭션 ID 성공 응답 (200): { "success": true, "data": { "tx_id": "tx_abc123", "user_id": "player123", "game_id": "202603180001", "bet_type": "UP", "amount": 10000, "approved_amount": 10000, "returned_amount": 0, "win_amount": 19500, "profit": 9500, "result": "win", "status": "settled", "created_at": "2026-03-18 15:30:00" } } result 값: - "win": 유저 승리 - "lose": 유저 패배 - "returned": 배팅 취소/환불 status 값: - "pending": 배팅 접수, 라운드 잠금 대기 - "approved": 배팅 승인, 라운드 잠금됨 - "settled": 라운드 종료, 결과 확정 ------------------------------------------------------------------------------ 3.4 배팅 내역 조회 ------------------------------------------------------------------------------ GET /api/partner.php?action=history&user_id={user_id}&limit={limit}&offset={offset} 설명: 유저의 배팅 내역을 페이지네이션으로 조회합니다. 요청 헤더: X-Partner-Key: {시크릿키} 쿼리 파라미터: user_id - 필수: 유저 식별자 limit - 선택: 조회 개수 (기본: 20, 최대: 100) offset - 선택: 건너뛸 개수 (기본: 0) 성공 응답 (200): { "success": true, "data": [ { "tx_id": "tx_abc123", "game_id": "202603180001", "bet_type": "UP", "amount": 10000, "approved_amount": 10000, "win_amount": 19500, "profit": 9500, "result": "win", "status": "settled", "created_at": "2026-03-18 15:30:00" }, ... ], "pagination": { "limit": 20, "offset": 0, "total": 150 } } ------------------------------------------------------------------------------ 3.5 하부 총판 생성 ------------------------------------------------------------------------------ POST /api/partner.php?action=create_partner 설명: 호출한 파트너의 하부에 새로운 총판(파트너)을 생성합니다. 생성된 총판은 자동으로 호출자의 하부 계층에 추가됩니다. 요청 헤더: Content-Type: application/json X-Partner-Key: {시크릿키} 요청 본문: { "user_id": "subtotal1", // 필수: 총판 로그인 ID "user_pw": "password123", // 필수: 비밀번호 (4자 이상) "nickname": "하부총판1", // 선택: 표시 이름 (기본: user_id) "commission_rate": 2.0, "payout_rate": 1.93, // 선택: 배당률 (상위 이하, 기본 1.95) // 선택: 수수료율 (호출자 요율 이하) "prefix": "SUBTOT" // 필수: 회원 접두어 (영문/숫자/_ 3~16자, 고유) } 성공 응답 (200): { "success": true, "partner": { "user_id": 11, "username": "PREFIX_subtotal1", "nickname": "하부총판1", "partner_code": "SUBTOT_a3f2", "commission_rate": 2.0 } } 오류 응답: { "success": false, "error": "Commission rate must be between 0 and 3%" } 참고: - prefix는 필수이며 고유해야 함 (한 번 설정 후 변경 불가) - prefix는 하부 회원의 아이디 앞에 자동 추가됨 (예: SUBTOT_player123) - commission_rate는 호출한 파트너의 요율을 초과할 수 없음 - 생성된 총판은 is_partner=1, can_invite=1로 설정됨 - 파트너 코드가 자동 생성됨 - 상위 파트너의 prefix가 username에 자동 prepend됨 ------------------------------------------------------------------------------ 3.6 커미션 내역 조회 ------------------------------------------------------------------------------ GET /api/partner.php?action=commission&date_from={시작일}&date_to={종료일} 설명: 호출한 파트너의 커미션 수익 내역을 조회합니다. 요청 헤더: X-Partner-Key: {시크릿키} 쿼리 파라미터: date_from - 선택: 시작일 (기본: 7일 전, 형식: YYYY-MM-DD) date_to - 선택: 종료일 (기본: 오늘, 형식: YYYY-MM-DD) game_type - 선택: 게임 타입 (30s / 60s, 기본: 전체) 성공 응답 (200): { "success": true, "summary": { "total_commission": 15000, "total_bet_amount": 500000, "total_count": 25 }, "data": [ { "round_number": 2490, "game_type": "30s", "bet_user": "devtest4", "bet_amount": 10000, "commission_rate": 3.0, "sub_rate": 2.0, "actual_rate": 1.0, "commission_amount": 100, "created_at": "2026-04-25 20:45:00" }, ... ] } ================================================================================ 4. 심리스 월렛 콜백 ================================================================================ 게임 이벤트 발생 시 BITUPGO가 파트너 서버로 HTTP POST 요청을 전송합니다. 파트너 서버에서 이 콜백 엔드포인트들을 구현해야 합니다. 파트너 대시보드에서 콜백 URL 설정: - Balance URL: 유저 잔액 확인용 - Debit URL: 배팅 차감용 - Credit URL: 당첨금 지급용 - Cancel URL: 배팅 취소/환불용 요청 헤더 (BITUPGO → 파트너): Content-Type: application/json X-Signature: {hmac_sha256_서명} X-Partner-Id: {파트너_id} ------------------------------------------------------------------------------ 4.1 잔액 콜백 ------------------------------------------------------------------------------ POST {callback_balance_url} 설명: 유저가 게임에 접속할 때 BITUPGO가 잔액을 요청합니다. 요청 본문: { "action": "balance", "user_id": "player123", "timestamp": 1710752400 } 응답 형식: { "success": true, "balance": 50000.00 } ------------------------------------------------------------------------------ 4.2 차감 콜백 (배팅 확정) ------------------------------------------------------------------------------ POST {callback_debit_url} 설명: 유저가 배팅 버튼을 클릭할 때 호출됩니다. 유저 잔액에서 배팅금액을 차감하세요. 요청 본문: { "action": "debit", "user_id": "player123", "game_id": "202603180001", "game_type": "30s", "amount": 10000.00, "tx_id": "tx_1710752400_123", "timestamp": 1710752400 } 성공 응답: { "success": true, "balance": 40000.00, "tx_id": "tx_1710752400_123" } 잔액 부족 응답: { "success": false, "error": "insufficient_balance", "balance": 5000.00 } 중요: - tx_id를 저장하여 정산에 사용 - 차감 후 잔액을 반환 - 잔액 부족 시 배팅이 취소됨 ------------------------------------------------------------------------------ 4.3 지급 콜백 (당첨금) ------------------------------------------------------------------------------ POST {callback_credit_url} 설명: 유저가 승리했을 때 호출됩니다. 당첨금을 유저 잔액에 추가하세요. 요청 본문: { "action": "credit", "user_id": "player123", "game_id": "202603180001", "game_type": "30s", "win_amount": 19500.00, "tx_id": "tx_1710752400_123", "start_price": 84521.50, "end_price": 84650.30, "result": "UP", "timestamp": 1710752430 } 응답 형식: { "success": true, "balance": 59500.00 } 참고: - win_amount = approved_amount × 1.95 (기본 배당률) - tx_id는 원래 debit 트랜잭션과 동일 - result는 "win" 또는 "returned" (취소된 배팅) ------------------------------------------------------------------------------ 4.4 취소 콜백 (환불) ------------------------------------------------------------------------------ POST {callback_cancel_url} 설명: 시스템 오류 등으로 배팅이 취소될 때 호출됩니다. 원래 배팅금액을 환불하세요. (고정배당 방식에서는 매칭 불발 환불이 없습니다) 요청 본문: { "action": "cancel", "user_id": "player123", "game_id": "202603180001", "amount": 10000.00, "tx_id": "tx_1710752400_123", "void_reason": "시스템 오류", "timestamp": 1710752430 } 응답 형식: { "success": true, "balance": 50000.00 } ================================================================================ 5. 서명 검증 ================================================================================ 모든 콜백 요청에는 보안을 위해 X-Signature 헤더가 포함됩니다. 반드시 이 서명을 검증하여 위조 요청을 방지하세요. 서명 알고리즘: HMAC-SHA256 시크릿 키: callback_secret_key 메시지: 원본 JSON 요청 본문 PHP 예제: ```php $requestBody = file_get_contents('php://input'); $receivedSignature = $_SERVER['HTTP_X_SIGNATURE'] ?? ''; $expectedSignature = hash_hmac('sha256', $requestBody, $your_secret_key); if (!hash_equals($expectedSignature, $receivedSignature)) { http_response_code(401); die(json_encode(['success' => false, 'error' => 'Invalid signature'])); } ``` Node.js 예제: ```javascript const crypto = require('crypto'); const requestBody = JSON.stringify(req.body); const receivedSignature = req.headers['x-signature']; const expectedSignature = crypto .createHmac('sha256', yourSecretKey) .update(requestBody) .digest('hex'); if (receivedSignature !== expectedSignature) { return res.status(401).json({ success: false, error: 'Invalid signature' }); } ``` ================================================================================ 6. 에러 코드 ================================================================================ HTTP 상태 코드: 200 - 성공 400 - 잘못된 요청 (파라미터 오류) 401 - 인증 실패 (파트너키 또는 서명 오류) 404 - 찾을 수 없음 (유저 또는 트랜잭션) 500 - 서버 오류 오류 응답 형식: { "success": false, "message": "오류 설명", "error_code": "ERROR_CODE" } 주요 에러 코드: INVALID_PARTNER_KEY - 파트너키가 없거나 비활성화됨 INVALID_SIGNATURE - HMAC 서명 검증 실패 USER_NOT_FOUND - 유저가 존재하지 않음 INSUFFICIENT_BALANCE - 잔액 부족 INVALID_TX_ID - 트랜잭션 ID를 찾을 수 없음 DUPLICATE_TX - 이미 처리된 트랜잭션 ================================================================================ 7. 연동 플로우 ================================================================================ 1단계: 초기 설정 (1회) ----------------------- 1. BITUPGO 관리자에게 파트너 계정 발급 요청 2. 파트너 대시보드에서 콜백 URL 설정 3. callback_secret_key를 안전하게 저장 2단계: 유저 로그인 플로우 ------------------------- 1. 유저가 귀사 사이트에서 "플레이" 클릭 2. 귀사 서버가 POST /api/partner.php?action=login 호출 3. login_url(임시 토큰 포함) 수신 4. login_url을 iframe에 로드 5. 유저 로그인 완료, 게임 플레이 가능 3단계: 게임 플로우 (고정배당 방식) ----------------------------------- 1. 유저가 배팅 (UP 또는 DOWN) 2. 배팅 접수 시: BITUPGO → 귀사 DEBIT 콜백 호출 (잔액 차감) 3. 라운드 종료 시 (30초/60초): - 승리: BITUPGO → 귀사 CREDIT 콜백 (배당금 지급) 지급액 = 배팅금 × 파트너 배당률 (예: 10,000 × 1.97 = 19,700) - 패배: 콜백 없음 (이미 차감 확정) - 시스템 오류 시: BITUPGO → 귀사 CANCEL 콜백 (전액 환불) 참고: - 매칭 없음: 한쪽만 배팅해도 정상 승부 - 배당률은 파트너 대시보드에서 설정 (기본 1.95) - 배당률 = 수수료 포함 (별도 수수료 없음) 4단계: 잔액 동기화 ------------------ - BITUPGO가 주기적으로 BALANCE 콜백 호출 - 귀사 응답으로 표시 잔액 업데이트 - 양측 시스템 간 잔액 동기화 유지 ================================================================================ 8. 코드 예제 ================================================================================ PHP - 로그인 API 호출: ```php $ch = curl_init('https://bet2.bitupgo.com/api/partner.php?action=login'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode([ 'user_id' => 'player123', 'user_pw' => 'temp_password', 'nickname' => '플레이어이름' ]), CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'X-Partner-Key: ' . $your_secret_key ], CURLOPT_RETURNTRANSFER => true ]); $response = json_decode(curl_exec($ch), true); $iframeUrl = $response['login_url']; ``` PHP - 콜백 핸들러: ```php false, 'error' => 'Invalid signature'])); } $data = json_decode($body, true); switch ($data['action']) { case 'balance': $balance = getUserBalance($data['user_id']); echo json_encode(['success' => true, 'balance' => $balance]); break; case 'debit': $result = deductBalance($data['user_id'], $data['amount'], $data['tx_id']); echo json_encode($result); break; case 'credit': $result = addBalance($data['user_id'], $data['win_amount'], $data['tx_id']); echo json_encode($result); break; case 'cancel': $result = refundBalance($data['user_id'], $data['amount'], $data['tx_id']); echo json_encode($result); break; } ``` ================================================================================