← Tất cả hướng dẫn

HƯỚNG DẪN 11 / 12

Xây dựng sàn thương mại tiền mã hóa của bạn.

Từ giỏ hàng chung đến việc trả tiền cho nhà bán hàng, với ví dụ thực tế $300 và mã phía máy chủ.

Kết quả bạn sẽ có

Một tích hợp thanh toán bạn có thể thử, đối soát và tự động hóa mà không nhầm khoản thanh toán của khách hàng với khoản chi trả cho nhà bán hàng.

1. Quyết định ai phụ trách việc gì

Cửa hàng của bạn quản lý danh mục, tài khoản người bán, giỏ hàng, vận chuyển và thực hiện đơn hàng. Wholly Crypto xử lý trang thanh toán, xác minh thanh toán, phân bổ cho nhà bán hàng và chi trả đã phê duyệt. Bản ghi nhà bán hàng không phải tài khoản đăng nhập người bán; plugin cửa hàng hiện có không tự động chia giỏ hàng nhiều nhà bán hàng.

  1. Một giỏ hàng chung
  2. Một hóa đơn khách hàng
  3. Phần của nhà bán hàng đã xác minh
  4. Khoản chi trả đã phê duyệt

Khách hàng trả vào ví dự án trước. Bạn kiểm soát khóa và giữ tiền nợ nhà bán hàng. Đây không phải phân chia trực tiếp từ khách đến nhà bán hàng hay dịch vụ không lưu ký cho người bán của bạn.

Marketplace hỗ trợ Bitcoin mainnet, đồng EVM được hỗ trợ và token ERC-20 tiêu chuẩn. Nhà bán hàng nhận tài sản trên mạng khách đã dùng, không tự động đổi sang tiền pháp định. Không phải cả 30 chuỗi nhận đều được hỗ trợ chi trả Marketplace.

2. Tính các số tiền

Ba nhà bán hàng mỗi người bán $100 hàng hóa. Đặt hoa hồng dự án 4%, không ghi đè theo cửa hàng hoặc nhà bán hàng trong ví dụ này.

Phần chiaTổng gộpHoa hồng của bạnNhà bán hàng nhận
Mỗi nhà bán hàng$100$4$96
Cả ba$300$12$288

Đây là giá trị tương đương theo báo giá đã khóa của hóa đơn, trả bằng tiền mã hóa. Không đảm bảo giá trị đô la tương lai. Phí xử lý thông thường 1% dùng $3 tín dụng trả trước trên hóa đơn $300 này, một lần, không phải mỗi nhà bán hàng một lần. Hoa hồng gộp $12 còn $9 trước chi phí mạng khi phí đó áp dụng.

Giữ riêng đồng gốc tự do để trả phí Bitcoin hoặc gas EVM. Phí không được tiêu vào tiền gốc được bảo vệ của nhà bán hàng. Gom tiền thông thường không thể tiêu tiền tại địa chỉ nhận Marketplace.

3. Chuẩn bị ví và nhà bán hàng

  1. Trong Dự án → Marketplace → Cài đặt, bật Marketplace, chọn cửa hàng và đặt hoa hồng. Giữ chi trả tạm dừng và chính sách tự động tắt trong khi thiết lập.
  2. Sao lưu ví dự án và cơ sở dữ liệu. Bật phương thức BTC/EVM dự định dùng trong cửa hàng, kiểm tra mức sẵn sàng của bộ quét và nạp tín dụng xử lý cùng tiền phí đồng gốc riêng.
  3. Thêm từng nhà bán hàng. Lưu UUID tương ứng với ID người bán trong cửa hàng của bạn; external_id có thể chứa tham chiếu người bán đó. Xác minh độc lập và phê duyệt từng địa chỉ chi trả trên đúng chuỗi và mạng.

Một phương thức thanh toán cần đích tương ứng đã phê duyệt cho mọi nhà bán hàng tham gia. Đổi địa chỉ nhà bán hàng sau này không âm thầm chuyển hướng nghĩa vụ hiện có.

Xác minh chi trả cần số xác nhận lớn hơn không và hai nhà cung cấp độc lập tương thích, ngay cả khi trang thanh toán cho phép không xác nhận hoặc một bộ quét.

Hướng dẫn thiết lập bảng điều khiển · Sao lưu và khôi phục

4. Kết nối giỏ hàng chung

Tạo thông tin xác thực Marketplace giới hạn theo dự án trong Cài đặt → Truy cập API. Cấp cho backend thanh toán marketplace.read và invoices.write, giới hạn theo cửa hàng khi phù hợp. Không cấp quyền phê duyệt địa chỉ và chi trả cho khóa đó.

Tính giá, giảm giá, thuế và vận chuyển trên máy chủ của bạn, rồi phân vào các phần của nhà bán hàng. Gửi 1–100 nhà bán hàng khác nhau với chuỗi thập phân dương; tổng số tiền gộp phải bằng chính xác hóa đơn. Không bao giờ tin phần chia do trình duyệt cung cấp hoặc dùng số thực dấu phẩy động cho tiền.

Thay tên máy chủ API và phần giữ chỗ UUID bên dưới. Nạp WHOLLY_TOKEN từ môi trường máy chủ. Yêu cầu kế thừa hoa hồng 4% đã cấu hình; không cần quyền ghi đè hoa hồng.

Mở yêu cầu bằng cURL, JavaScript, PHP hoặc Python
cURL
: "${WHOLLY_TOKEN:?Set WHOLLY_TOKEN to your server-side API token}"
# Keep this key and the exact body for retries; use a new key for each new operation.
curl --fail-with-body --max-time 30 \
  --request POST \
  --url "https://api.example.com/v1/marketplace/invoices" \
  --header "Authorization: Bearer $WHOLLY_TOKEN" \
  --header 'Idempotency-Key: cart-1042-marketplace-v1' \
  --header 'Content-Type: application/json' \
  --data-raw '{
  "project_id": "YOUR_PROJECT_ID",
  "store_id": "YOUR_STORE_ID",
  "amount": "300.00",
  "currency": "USD",
  "order_id": "cart-1042",
  "description": "One order from three vendors",
  "ipn_url": "https://shop.example.com/payments/wholly-ipn",
  "metadata": {
    "cart_id": "cart-1042"
  },
  "allocations": [
    {
      "vendor_id": "VENDOR_A_UUID",
      "gross_amount": "100.00"
    },
    {
      "vendor_id": "VENDOR_B_UUID",
      "gross_amount": "100.00"
    },
    {
      "vendor_id": "VENDOR_C_UUID",
      "gross_amount": "100.00"
    }
  ]
}'
JavaScript
// Node.js 18+ · run on your server, never in browser code.
const token = process.env.WHOLLY_TOKEN;
if (!token) throw new Error("Set WHOLLY_TOKEN");
// Keep this key and the exact body for retries; use a new key for each new operation.
const body = `{
  "project_id": "YOUR_PROJECT_ID",
  "store_id": "YOUR_STORE_ID",
  "amount": "300.00",
  "currency": "USD",
  "order_id": "cart-1042",
  "description": "One order from three vendors",
  "ipn_url": "https://shop.example.com/payments/wholly-ipn",
  "metadata": {
    "cart_id": "cart-1042"
  },
  "allocations": [
    {
      "vendor_id": "VENDOR_A_UUID",
      "gross_amount": "100.00"
    },
    {
      "vendor_id": "VENDOR_B_UUID",
      "gross_amount": "100.00"
    },
    {
      "vendor_id": "VENDOR_C_UUID",
      "gross_amount": "100.00"
    }
  ]
}`;
const response = await fetch("https://api.example.com/v1/marketplace/invoices", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${token}`,
    "Idempotency-Key": "cart-1042-marketplace-v1",
    "Content-Type": "application/json"
  },
  body,
  redirect: "error",
  signal: AbortSignal.timeout(30000)
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
console.log(await response.json());
PHP
<?php
// PHP 8+ with the cURL extension; run on your server.
$token = getenv('WHOLLY_TOKEN');
if (!$token) { throw new RuntimeException('Set WHOLLY_TOKEN'); }
// Keep this key and the exact body for retries; use a new key for each new operation.
$body = <<<'JSON'
{
  "project_id": "YOUR_PROJECT_ID",
  "store_id": "YOUR_STORE_ID",
  "amount": "300.00",
  "currency": "USD",
  "order_id": "cart-1042",
  "description": "One order from three vendors",
  "ipn_url": "https://shop.example.com/payments/wholly-ipn",
  "metadata": {
    "cart_id": "cart-1042"
  },
  "allocations": [
    {
      "vendor_id": "VENDOR_A_UUID",
      "gross_amount": "100.00"
    },
    {
      "vendor_id": "VENDOR_B_UUID",
      "gross_amount": "100.00"
    },
    {
      "vendor_id": "VENDOR_C_UUID",
      "gross_amount": "100.00"
    }
  ]
}
JSON;
$ch = curl_init("https://api.example.com/v1/marketplace/invoices");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => false,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $token, "Idempotency-Key: cart-1042-marketplace-v1", "Content-Type: application/json"],
    CURLOPT_POSTFIELDS => $body,
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($response === false) { throw new RuntimeException(curl_error($ch)); }
curl_close($ch);
if ($status < 200 || $status >= 300) { throw new RuntimeException("HTTP $status: $response"); }
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));
Python
# Python 3 · standard library; run on your server.
import json
import os
from urllib.request import Request, build_opener, HTTPRedirectHandler

class NoRedirect(HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        return None

# Keep this key and the exact body for retries; use a new key for each new operation.
headers = {
    "Idempotency-Key": "cart-1042-marketplace-v1",
    "Content-Type": "application/json"
}
headers["Authorization"] = "Bearer " + os.environ["WHOLLY_TOKEN"]
body = """{
  "project_id": "YOUR_PROJECT_ID",
  "store_id": "YOUR_STORE_ID",
  "amount": "300.00",
  "currency": "USD",
  "order_id": "cart-1042",
  "description": "One order from three vendors",
  "ipn_url": "https://shop.example.com/payments/wholly-ipn",
  "metadata": {
    "cart_id": "cart-1042"
  },
  "allocations": [
    {
      "vendor_id": "VENDOR_A_UUID",
      "gross_amount": "100.00"
    },
    {
      "vendor_id": "VENDOR_B_UUID",
      "gross_amount": "100.00"
    },
    {
      "vendor_id": "VENDOR_C_UUID",
      "gross_amount": "100.00"
    }
  ]
}""".encode("utf-8")
request = Request("https://api.example.com/v1/marketplace/invoices",
                  method="POST", headers=headers, data=body)
# Non-2xx responses raise HTTPError. Do not retry writes with a new key.
with build_opener(NoRedirect()).open(request, timeout=30) as response:
    print(json.load(response))

Lưu bền vững nội dung yêu cầu và Idempotency-Key trước khi gửi. Sau khi hết thời gian chờ, gửi lại cùng nội dung với cùng khóa. Lưu data.invoice_id tương ứng với đơn hàng và chuyển hướng đến links.checkout ở cấp cao nhất. Không bao giờ đưa khóa API vào trình duyệt của khách.

Nơi tìm UUID dự án và cửa hàng →

Thích dùng SDK? Bắt đầu với ví dụ Marketplace:

5. Theo dõi thanh toán và chi trả riêng biệt

URL quay lại từ trang thanh toán không phải bằng chứng thanh toán. Xác minh chữ ký callback trên nội dung thô, kiểm tra dấu thời gian và dự án dự kiến, rồi lưu event_id duy nhất trước khi xác nhận nhận. Dùng lớp bảo vệ riêng ở cấp đơn hàng để thử lại không thực hiện đơn hàng hai lần.

Sự kiệnThông tin bạn nhận được
invoice.settledHóa đơn khách hàng đã quyết toán. Kiểm tra cờ cần xem xét và các khoản giữ Marketplace trước khi thực hiện đơn hàng.
marketplace.allocations.availableCác phần đã xác minh sẵn sàng để chi trả. Chưa chắc nhà bán hàng nào đã được trả.
marketplace.payout.confirmedKhoản chi trả đã hoàn tất kiểm tra xác nhận.

IPN hóa đơn dùng bí mật IPN của cửa hàng. Webhook vòng đời Marketplace dùng bí mật ký endpoint riêng. Giữ hai bộ nhận tách biệt. Đọc hóa đơn hoặc khoản chi trả hiện tại qua API khi đối soát sự kiện bị bỏ lỡ hoặc sai thứ tự.

Callback hóa đơn và xác minh chữ ký · Sự kiện Marketplace và tài liệu API

6. Xem xét trước, tự động hóa sau

Khi các phần đã xác minh trở thành khả dụng, bỏ tạm dừng chi trả nhưng giữ chính sách tự động tắt. Trong Marketplace → Chi trả, chuẩn bị phân bổ, xem người nhận và giới hạn phí đồng gốc/gas, rồi phê duyệt đúng kế hoạch một lần. Theo dõi đến Đã trả, không chỉ Đã phát.

Bitcoin gom mọi phần chưa trả của hóa đơn được chọn trong cùng lô. Chi trả token EVM có thể cần cấp gas trước khi chuyển token. Đây là nhiều giao dịch, không phải phân chia nguyên tử được tất cả hoặc không có gì.

Sau khi thử số tiền nhỏ thành công, đặt một chính sách tự động cho mỗi tài sản: chi trả tối thiểu, giới hạn tiền gốc mỗi lần và hằng ngày, ngân sách phí đồng gốc/gas, khoảng thời gian và số xác nhận. Bật chính sách cho phép gửi mà không cần nhấp thêm. Tín dụng thấp hoặc cổng chuyển tiền máy chủ bị tắt vẫn có thể tạm dừng chi tiêu.

7. Xử lý các trường hợp khó

Thanh toán thiếu, muộn, trộn lẫn hoặc bị tổ chức lại chuỗi

Trang thanh toán đã quyết toán không đảm bảo phân chia cho nhà bán hàng có đủ tiền. Dung sai không thể tạo tiền còn thiếu. Kiểm tra phân bổ đang giữ, chờ thanh toán, hoàn tiền hoặc phê duyệt rõ ràng phân chia nhỏ hơn có đủ tiền bảo chứng. Thanh toán dư không tự động là doanh thu bổ sung của sàn.

Thanh toán thừa không chặn chi trả nhà bán hàng theo báo giá trên Bitcoin, đồng EVM hay token ERC-20 được hỗ trợ. Phần chia nhà bán hàng giữ nguyên và tiền thừa giữ riêng để đối soát.

Khoản chi trả bị kẹt hoặc yêu cầu hết thời gian chờ

Kiểm tra hash giao dịch đã lưu, số dư nguồn, gas và lý do cần xem xét. Tiếp tục hoặc đối soát khoản chi trả hiện có; đừng tạo giao dịch thứ hai vì mất phản hồi. Sau khi khôi phục bản sao lưu, giữ chi trả tạm dừng đến khi kết quả trên chuỗi khớp sổ cái.

Tiếp tục chỉ có thể thay giao dịch EVM thất bại sau khi hai nhà cung cấp độc lập chứng minh việc hoàn tác đã xác nhận trên chuỗi. Kết quả chưa rõ vẫn được giữ dự trữ và phí lần thử thất bại vẫn tính vào ngân sách ban đầu.

Khách hàng cần hoàn tiền

Xác minh địa chỉ hoàn tiền do khách kiểm soát. Hoàn tiền được hỗ trợ là hoàn toàn bộ bằng cùng tài sản. Sau khi đã trả tất cả nhà bán hàng, nạp riêng ví chính; Wholly Crypto không thể trừ tiền lại từ họ. Lô nhà bán hàng mới trả một phần cần đối soát thủ công, không phải mặc định có nút hoàn một phần.

8. Kiểm tra trước khi mở

  • Thực hiện khoản thanh toán BTC và/hoặc EVM nhỏ đến khi chi trả nhà bán hàng được xác nhận. Xác nhận chuỗi, hợp đồng token, địa chỉ đích, hoa hồng và phí riêng.
  • Thử callback lặp lại, phản hồi API hết thời gian chờ, thanh toán thiếu và khoản chi trả bị giữ. Xác minh không trường hợp nào gây thực hiện đơn hàng hoặc gửi tiền trùng.
  • Giữ bản sao lưu riêng ngoài máy chủ, theo dõi chi trả thất bại và thường xuyên đối soát nghĩa vụ với nhà bán hàng với tiền trên chuỗi.

Bắt đầu với chi trả được xem xét và ít nhà bán hàng. Chỉ tự động hóa tài sản, ngân sách và đích bạn đã thử.