Đến nội dung chính
Nạp tiền
GekiStore
GEKISTORE / DEVELOPERSPartner API v1

Tài liệu Partner API.

Tích hợp Robux 120H vào shop của bạn: giá, stock, đặt đơn và đối soát.

Dashboard API ↗
01 / TỔNG QUAN

Từ kết nối đến đơn đầu tiên

Mọi tài khoản GekiStore đang hoạt động đều có thể tự tạo key. API dùng chung số dư ví hiện tại, mỗi đơn xử lý một Gamepass, từ 10 đến 10.000 Robux trước thuế.

  1. Tạo key tại Dashboard API và nạp tiền vào ví GekiStore.
  2. Tra cứu Username, Gamepass và tier giá.
  3. Gọi orders/quote, lấy data.total làm maxTotal.
  4. Lưu body và Idempotency-Key ở shop, rồi gọi orders.
  5. Lưu orderId của GekiStore, tra cứu mỗi 15–30 giây đến khi terminal=true.

URL gọi API

https://gekistore.com/api/partner/v1/index.php?endpoint=balance

Thay balance bằng endpoint trong bảng bên dưới. Dạng URL này hoạt động không cần cấu hình rewrite. Khi hosting bật rewrite, có thể dùng https://gekistore.com/api/partner/v1/balance.

Tích hợp giữa hai máy chủ. Không đặt API Key trong JavaScript giao diện hoặc gửi qua URL. API không mở CORS cho trình duyệt shop khác.

02 / XÁC THỰC

Authorization: Bearer

curl 'https://gekistore.com/api/partner/v1/index.php?endpoint=balance' \
  -H "Authorization: Bearer $GEKISTORE_API_KEY"

Tất cả endpoint yêu cầu API Key. Mỗi tài khoản có tối đa 5 key đang hoạt động; mỗi key có hạn 365 ngày và chỉ hiện đầy đủ một lần khi tạo. Tạo key mới, cập nhật máy chủ shop rồi thu hồi key cũ khi cần thay.

Key đã thu hồi không dùng được, nhưng đơn đã thanh toán vẫn tiếp tục xử lý. Tài khoản bị khóa sẽ không thể gọi API.

03 / GIÁ

Cùng rate GekiStore, ưu đãi theo doanh số Robux

shopRate dùng đúng giá đang bán ở trang Robux 120H. tierId là mã chọn mức giá; truyền lại nguyên chuỗi hoặc chọn auto. Tier chọn thủ công hết stock hoặc đổi giá sẽ trả lỗi để shop báo giá lại.

Khi tổng Robux 120H đã xác minh thành công vượt 20.000, các đơn API đặt sau đó được giảm 2%. Tổng tính toàn bộ đơn 120H của tài khoản trên web và API, theo giá trị Gamepass trước thuế. Đúng 20.000 chưa được giảm. Không tính đơn đang xử lý, thất bại, hủy, hoàn tiền hoặc chỉ có nhãn thành công chưa xác minh.

retailTotal = giá checkout Robux 120H của GekiStore
discountAmount = floor(retailTotal × 2 / 100), nếu đủ điều kiện
total = retailTotal − discountAmount

Tiền làm tròn nguyên VND; giao diện shop hiển thị G với cùng giá trị số. partnerRate là giá tham khảo mỗi Robux sau ưu đãi; tổng chính xác lấy từ orders/quote. Số Robux người nhận được sau thuế phụ thuộc cơ chế Roblox; không dùng giá sau thuế làm robuxAmount.

Ưu đãi không cộng dồn với chương trình khác. Đơn đưa tổng vượt mốc sẽ mở ưu đãi cho các đơn API tiếp theo sau khi được xác minh thành công.

04 / ENDPOINTS

Các chức năng hỗ trợ

Methodendpoint=Mô tả
GETbalanceSố dư ví và điều kiện ưu đãi.
GETratesGiá bán, các tier và mức giảm của tài khoản.
GETstockTổng kho, giới hạn đơn và các tier.
GETstock/detailedtierId, shopRate, partnerRate, stock, maxOrderRobux.
GETroblox/user&username=TenRobloxTra cứu tài khoản Roblox.
GETgamepasses&username=TenRobloxGamepass đang bán: gamepassId, price, placeId.
POSTorders/quoteKiểm tra đầu vào và báo tổng tiền; không trừ ví.
POSTordersTạo đơn, trừ ví một lần. Bắt buộc Idempotency-Key.
GETorders&page=1&limit=20Liệt kê đơn API của tài khoản; lọc thêm clientOrderId.
GETorders/{orderId}Chi tiết một đơn API thuộc tài khoản.
GETtransactions&page=1&limit=20Biên nhận trừ/hoàn ví của đơn API; phân trang theo đơn.

page bắt đầu từ 1, limit từ 1 đến 100. orders và transactions chỉ gồm đơn tạo qua Partner API của tài khoản hiện tại. Không cần key cũ để tra cứu đơn được tạo bởi key đó: key mới cùng tài khoản vẫn tra cứu được.

Đồng bộ dùng tiến trình đối soát GekiStore hiện có. Phiên bản này dùng polling; chưa có webhook gửi tới shop đối tác.

05 / CHECKOUT

Báo giá trước khi trừ ví

curl 'https://gekistore.com/api/partner/v1/index.php?endpoint=orders/quote' \
  -H "Authorization: Bearer $GEKISTORE_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{
    "robloxUsername": "TenRoblox",
    "gamepassId": "123456789",
    "robuxAmount": 100,
    "tierId": "auto"
  }'
TrườngKiểuQuy tắc
robloxUsernamestringBắt buộc; tên đăng nhập, không phải tên hiển thị.
gamepassIdstringBắt buộc; ID Gamepass đang bán, thuộc đúng người nhận.
robuxAmountintegerBắt buộc; bằng giá Gamepass trước thuế, từ 10–10.000.
tierIdstringMặc định auto; hoặc mã từ stock/detailed. Không gửi rate nguồn.
inputMethodstringusername (mặc định); manual nếu cần xác minh trực tiếp Gamepass.
placeIdstringTùy chọn; ID Experience chứa Gamepass.
maxTotalintegerBắt buộc khi tạo đơn. Tổng VND cao nhất shop đồng ý trả.
clientOrderIdstringTùy chọn; mã đơn riêng của shop, tối đa 80 ký tự, duy nhất trong tài khoản.

Tạo đơn

curl 'https://gekistore.com/api/partner/v1/index.php?endpoint=orders' \
  -H "Authorization: Bearer $GEKISTORE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: shop-order-20260924-0001' \
  --data '{
    "robloxUsername": "TenRoblox",
    "gamepassId": "123456789",
    "robuxAmount": 100,
    "tierId": "auto",
    "maxTotal": 15000,
    "clientOrderId": "SHOP-0001"
  }'

Username, Gamepass và tổng tiền trong ví dụ là minh họa. Thay bằng dữ liệu thực và maxTotal từ báo giá. Header Idempotency-Key bắt buộc, 8–128 ký tự chữ, số hoặc . _ : -.

Phản hồi tạo đơn: HTTP 202

{
  "success": true,
  "data": {
    "order": {
      "orderId": "ORD_example123456",
      "clientOrderId": "SHOP-0001",
      "robloxUsername": "TenRoblox",
      "gamepassId": "123456789",
      "robuxAmount": 100,
      "amount": 14700,
      "currency": "VND",
      "retailAmount": 15000,
      "discountPercent": 2,
      "discountAmount": 300,
      "status": "processing",
      "terminal": false,
      "refundAmount": 0
    },
    "replayed": false
  },
  "error": null,
  "requestId": "gkp_example",
  "timestamp": "2026-09-24T00:00:00Z"
}

HTTP 202 xác nhận giao dịch đã được ghi nhận để xử lý; không có nghĩa là Robux đã giao. orderId là mã ổn định tại GekiStore. Nếu tiến trình lưu/gửi đơn bị ngắt sau khi trừ ví, hệ thống dùng biên nhận để khôi phục đúng đơn đó.

06 / CHỐNG TRÙNG

Một đơn shop, một Idempotency-Key

  • Lưu key và body vào database shop trước khi gửi lần đầu.
  • Mất kết nối, HTTP 409 REQUEST_IN_PROGRESS hoặc 503: gửi lại đúng key và body. Không sinh key mới.
  • Cùng key và nội dung sau khi đã trừ ví: trả cùng orderId, không trừ lần hai; header X-Idempotent-Replay: true.
  • Cùng key nhưng đổi username, Gamepass, số Robux, tier, maxTotal hoặc clientOrderId: HTTP 409 IDEMPOTENCY_CONFLICT.
  • Key chống trùng áp dụng cho toàn bộ tài khoản, không phụ thuộc API Key. Bản ghi được giữ cùng lịch sử giao dịch, không tự hết hạn sau 24 giờ.
  • clientOrderId đã dùng không được tạo lại bằng key khác. Có thể tra cứu orders&clientOrderId=SHOP-0001.
  • Một tài khoản chỉ có một yêu cầu tạo đơn đang chạy; các yêu cầu đồng thời nhận REQUEST_IN_PROGRESS và cần retry.

Nếu lần gọi chưa đi đến bước trừ ví (đầu vào sai, thiếu tiền, giá thay đổi), chưa có đơn được ghi nhận. Hãy xử lý lỗi trước; khi chưa rõ kết quả giao dịch, luôn giữ nguyên key và body.

07 / ĐỐI SOÁT

Trạng thái đơn và hoàn tiền

statusterminalÝ nghĩa
processingfalseĐã ghi nhận, đang xử lý gửi đơn.
deliveringfalseĐơn được tiếp nhận, đang giao.
reviewingfalseCần xác minh/đối soát; chưa kết luận hoàn tiền.
completedtrueHoàn thành đã được xác minh; không hoàn ví.
refundedtrueVí đã được hoàn đúng số tiền thực trả, một lần.

Không tự hoàn cho khách của shop chỉ vì timeout, HTTP lỗi, quá 120 giờ hoặc chưa có OrderID. Chỉ coi giao dịch đã hoàn khi API trả status=refunded và refundAmount>0.

Cơ chế đối soát và thao tác Admin hiện có của GekiStore tiếp tục áp dụng, gồm Admin tự xác minh đơn chưa có OrderID. Partner không được quyền tự xác nhận đã hoàn hay tự cộng tiền. Phiên bản API này không cung cấp endpoint hủy/hoàn trực tiếp; liên hệ hỗ trợ kèm orderId khi cần xử lý.

08 / GIỚI HẠN & LỖI

Giới hạn truy cập theo tài khoản

120 request/phút cho các GET thông thường; 20 request/phút dùng chung cho POST và tra cứu Roblox/Gamepass. Các API Key cùng tài khoản dùng chung hạn mức. Theo dõi X-RateLimit-* và Retry-After. Body JSON tối đa 16 KB.

HTTPMã tiêu biểuCách xử lý
401UNAUTHORIZEDKiểm tra key, hạn dùng và trạng thái tài khoản.
404ORDER_NOT_FOUNDKiểm tra orderId thuộc đúng tài khoản và tạo qua API.
409PRICE_CHANGED / TIER_CHANGEDBáo giá lại và xác nhận tổng tiền; ví chưa bị trừ nếu đây là lần tạo mới.
409REQUEST_IN_PROGRESSĐợi vài giây, retry đúng key và body.
409IDEMPOTENCY_CONFLICT / CLIENT_ORDER_EXISTSTra cứu đơn cũ; không tạo key mới để đặt lại.
409GAMEPASS_ORDER_PENDINGGamepass đã có đơn chưa kết thúc của tài khoản.
422INVALID_* / INSUFFICIENT_BALANCESửa đầu vào hoặc nạp thêm tiền.
423SALES_LOCKEDCửa hàng đang tạm khóa nhận đơn mới.
429RATE_LIMITEDChờ số giây trong Retry-After.
503WALLET_BUSY / SERVICE_UNAVAILABLERetry đúng key và body; không tự kết luận chưa trừ tiền.
{
  "success": false,
  "data": null,
  "error": {"code": "INSUFFICIENT_BALANCE", "message": "Số dư ví GekiStore không đủ.", "details": {}},
  "requestId": "gkp_example",
  "timestamp": "2026-09-24T00:00:00Z"
}

Lưu requestId để gửi hỗ trợ khi có lỗi. Không ghi API Key vào log.

09 / VÍ DỤ

PHP cURL trên máy chủ shop

<?php
// Chạy trên máy chủ shop. Lưu key trong biến môi trường.
$key = getenv('GEKISTORE_API_KEY');
function requestGeki(string $endpoint, ?array $body = null, string $idem = ''): array {
    global $key;
    $url = 'https://gekistore.com/api/partner/v1/index.php?endpoint=' . rawurlencode($endpoint);
    $ch = curl_init($url);
    $headers = ['Authorization: Bearer ' . $key, 'Accept: application/json'];
    if ($body !== null) {
        $headers[] = 'Content-Type: application/json';
        if ($idem !== '') $headers[] = 'Idempotency-Key: ' . $idem;
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body, JSON_THROW_ON_ERROR));
    }
    curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => $headers, CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_TIMEOUT => 90, CURLOPT_FOLLOWLOCATION => false]);
    $raw = curl_exec($ch);
    if ($raw === false) {
        curl_close($ch);
        throw new RuntimeException('Kết nối gián đoạn: tra cứu hoặc retry cùng key + body.');
    }
    $http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    return ['http' => $http, 'body' => json_decode($raw, true, 512, JSON_THROW_ON_ERROR)];
}
$cart = ['robloxUsername' => 'TenRoblox', 'gamepassId' => '123456789',
         'robuxAmount' => 100, 'tierId' => 'auto'];
$quote = requestGeki('orders/quote', $cart);
if (empty($quote['body']['success'])) {
    throw new RuntimeException('Chưa có báo giá hợp lệ; không tạo đơn.');
}
$body = $cart + ['maxTotal' => $quote['body']['data']['total'],
                 'clientOrderId' => 'SHOP-0001'];
$idem = 'shop-order-20260924-0001';
// BẮT BUỘC lưu $body + $idem vào DB shop TRƯỚC lần gửi đầu tiên.
// Khi retry, nạp đúng body và key đã lưu, không tạo key mới.
$result = requestGeki('orders', $body, $idem);
if (!empty($result['body']['success'])) {
    $orderId = $result['body']['data']['order']['orderId'];
    // Lưu $orderId; job nền gọi requestGeki('orders/' . $orderId) mỗi 15–30 giây.
}