Vào /start → API → Tạo API Key. Mọi người đều tự tạo được, không cần Admin duyệt hoặc tạo hồ sơ trước.
API dành cho Đại lý
Kết nối sản phẩm LUONGMMO vào bot bán hàng đang có. Khách trả tiền cho Đại lý; hệ thống nguồn chỉ trừ ví nhập hàng theo giá sỉ và giao sản phẩm trực tiếp bằng bot shop đã liên kết.
https://www.luongmmo.io.vn/api/v1/index.phpKích hoạt từ A đến Z
API Key lấy tại bot nguồn được dùng để kích hoạt connector một lần. Sau khi đăng ký thành công, key tự thu hồi; file TXT hướng dẫn không chứa key.
Bấm Tạo key kết nối. Sao chép key và giữ riêng, không đưa vào file TXT.
Gửi POST HTTPS từ đúng máy production. IP gọi lần đầu sẽ được ràng buộc.
Lưu api_url, api_key, api_secret ngoài web root với quyền 0600.
Gọi products, lưu namespace riêng và đặt giá bán không thấp hơn giá sỉ.
Chỉ gọi create_order sau khi bot Đại lý xác nhận đã nhận tiền khách.
Request kích hoạt
Endpoint đăng ký nằm sẵn trong file TXT tạo ở cuối trang. Đại lý chỉ cần lấy key riêng trong bot.
POST https://www.luongmmo.io.vn/reseller/register.phpContent-Type: application/json
{
"registration_key": "APK_KEY_VUA_TAO_TRONG_BOT",
"client_id": "bot-dai-ly-id-on-dinh-32-ky-tu",
"version": "connector-1.0",
"delivery_bot_token": "BOT_TOKEN_DANG_CHAY_CUA_DAI_LY",
"shop_name": "Tên shop Đại lý",
"owner_telegram_id": "123456789",
"owner_username": "username_khong_co_dau_at",
"product_events_callback_url": "https://partner.example.com/webhooks/mloder",
"product_events_enabled": true,
"product_events_events": ["product.created", "product.restocked", "product.updated"]
}product_events_callback_url, hệ thống tự tạo webhook, bật 3 sự kiện và trả product_events.shared_secret đúng một lần trong response. Bot đối tác chỉ cần lưu secret đó ngoài web root rồi nhận callback; không cần Admin tạo webhook thủ công.Ký mỗi request bằng HMAC
raw_json = chuỗi JSON chính xác sẽ gửi
timestamp = Unix time hiện tại
nonce = chuỗi ngẫu nhiên mới cho từng request
body_hash = SHA256(raw_json)
canonical = timestamp + "\n" + nonce + "\n" + body_hash
signature = HMAC_SHA256(canonical, api_secret)Gửi các header: X-ML612-Key, X-ML612-Timestamp, X-ML612-Nonce, X-ML612-Signature và tùy chọn X-ML612-Client-Version.
Các action được phép
| Action | Mục đích | Field chính |
|---|---|---|
products | Đọc sản phẩm được Admin cấp, giá sỉ/giá bán. | Không cần field thêm. |
balance | Đọc số dư ví nhập hàng. | Không cần field thêm. |
shop_config | Đọc tên shop, hỗ trợ và trạng thái nhận đơn. | Không cần field thêm. |
set_retail_price | Đặt giá bán của Đại lý. | product_id, retail_price |
create_order | Trừ ví giá sỉ và giao qua bot shop. | ID đơn, idempotency, sản phẩm, số lượng, khách. |
order_status | Tra đơn khi timeout hoặc theo dõi giao hàng. | external_order_id hoặc order_code |
commission_summary | Đối soát doanh thu, giá vốn và lãi. | from, to |
Ví dụ: products / balance
{"action":"products"}
{"action":"balance"}Ví dụ: đặt giá bán
{
"action": "set_retail_price",
"product_id": 12,
"retail_price": 150000
}Ví dụ: báo cáo lãi
{
"action": "commission_summary",
"from": "2026-08-01",
"to": "2026-08-29"
}wallet.balance, wallet.recent_transactions,
commission.month_earned, commission.month_credited,
commission.lifetime_credited và commission.lifetime_payable.
auto_credit_to_wallet=true cho biết hoa hồng được tự động cộng sau khi giao thành công.Luồng tạo đơn đúng
- Bot Đại lý tạo đơn local và nhận tiền khách theo giá bán.
- Lưu cố định
external_order_idvàidempotency_keytrước lần gọi đầu. - Gọi
create_order. Retry phải dùng lại đúng hai giá trị cũ và body cũ. - Nếu timeout, gọi
order_status; không sinh một đơn mới. - Hệ thống nguồn giao trực tiếp cho khách bằng bot Đại lý đã liên kết.
{
"action": "create_order",
"external_order_id": "SHOP-ORDER-20260829-0001",
"idempotency_key": "order-20260829-0001-product-12-qty-1",
"product_id": 12,
"quantity": 1,
"buyer_telegram_id": 123456789,
"buyer_username": "khachhang"
}Hoa hồng và ví nhập hàng
Hoa hồng được tính từ đúng snapshot của đơn, không bị thay đổi khi Admin cập nhật giá sản phẩm.
Tự động: chỉ khi giao hàng thành công, phần chênh lệch mới được cộng vào ví nhập hàng. Mỗi đơn chỉ cộng một lần, kể cả khi worker retry hoặc callback lặp.
- Đơn đang chờ, giao lỗi hoặc bị hủy không được cộng hoa hồng.
- Số dư ví, hoa hồng tháng này, tổng đã tự động cộng và phần còn chờ đối soát có trong
dashboard/commission_summary. - Lịch sử cộng/trừ được lưu trong sổ giao dịch ví; chốt thủ công chỉ áp dụng cho phần cũ chưa được cộng, không thể thanh toán trùng.
Thông báo cho cả hai Admin
Sau mỗi mốc đơn hàng, cùng một bộ metadata an toàn được gửi đồng thời cho chủ Đại lý qua bot Đại lý và Admin nguồn qua bot chính.
- Có đơn mới, giao thành công hoặc giao thất bại.
- Mã đơn, mã phía Đại lý, sản phẩm, SKU và số lượng.
- Giá sỉ, giá bán, hoa hồng dự kiến/đã ghi nhận.
- Hoa hồng đang chờ đối soát, số dư còn lại và trạng thái.
- Thiếu số dư: cả hai bên nhận số dư hiện tại, số cần và số còn thiếu; không trừ ví, không lấy kho, không giao hàng.
/start bot đối tác; Admin nguồn nhận qua các Admin notification targets đã cấu hình.Code PHP hoàn chỉnh
Trong gói tích hợp có sẵn examples/register_connector.php và examples/reseller_client.php. Ví dụ ký request tối thiểu:
<?php
$body = ['action' => 'balance'];
$raw = json_encode($body, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
$timestamp = (string)time();
$nonce = bin2hex(random_bytes(16));
$canonical = $timestamp."\n".$nonce."\n".hash('sha256', $raw);
$signature = hash_hmac('sha256', $canonical, getenv('ML612_API_SECRET'));
// POST $raw tới https://www.luongmmo.io.vn/api/v1/index.php với 4 header HMAC.Hai file mẫu đầy đủ nằm trong gói bàn giao tại examples/reseller_client.php và examples/register_connector.php. Không đặt source chứa secret trong thư mục web công khai.
Xử lý lỗi
| HTTP / code | Cách xử lý |
|---|---|
| 401 AUTH_REQUIRED / INVALID_SIGNATURE | Kiểm tra key, secret, timestamp, nonce và raw JSON đã ký. |
| 403 IP_NOT_ALLOWED | Connector đang gọi từ IP khác. Tạo key mới và kích hoạt lại từ VPS đúng. |
| 402 INSUFFICIENT_BALANCE | Nạp thêm ví nhập hàng; không tạo mã đơn mới khi retry. |
| 409 IDEMPOTENCY_CONFLICT | ID/key cũ đang gắn với body khác. Dừng và đối chiếu đơn local. |
| 409 RETAIL_PRICE_OUTDATED | Đồng bộ sản phẩm và đặt lại giá bán ≥ giá sỉ mới. |
| 429 RATE_LIMITED | Backoff có giới hạn, không spam retry. |
| 5xx / timeout | Giữ nguyên idempotency và gọi order_status. |
Quy tắc bảo mật bắt buộc
- Không commit Registration Key, API key, API secret hoặc Bot Token.
- Secret file nằm ngoài web root, quyền
0600. - Không log raw body chứa credential, chữ ký hoặc nội dung giao hàng.
- Luôn xác minh TLS; không tự đi theo redirect với request đã ký.
- Đồng bộ giờ VPS bằng NTP. Timeout đề xuất: connect 5 giây, tổng 20 giây.
- Sản phẩm nguồn nằm trong namespace riêng; không ghi đè sản phẩm cũ của bot Đại lý.
Checklist nghiệm thu
☐ Domain/HTTPS và health endpoint hoạt động · ☐ Kích hoạt từ VPS production thành công · ☐ Credentials lưu riêng · ☐ Sản phẩm cũ không bị đổi · ☐ Đồng bộ sản phẩm nguồn · ☐ Giá bán không dưới giá sỉ · ☐ Đọc đúng số dư · ☐ Đơn nhỏ giao đúng bot · ☐ Retry không trừ/giao lặp · ☐ Báo cáo lãi đúng.
📄 Tạo file TXT hướng dẫn tích hợp
File được tạo ngay trên trình duyệt và chứa toàn bộ thông tin kỹ thuật liên kết bot. File không chứa Registration Key, API Secret, Bot Token hoặc dữ liệu khách.
1. Tạo file hướng dẫn
Bấm nút dưới đây để xuất file TXT hoàn chỉnh dành cho AI hoặc người tích hợp.
2. Cách liên kết bot
Chuẩn bị đúng ba phần sau rồi gửi cho AI/người code:
- Full source bot của bạn.
- Key lấy riêng tại /start → API → Tạo API Key trong bot nguồn.
- File TXT hướng dẫn vừa tạo tại đây.
Đồng bộ sản phẩm tự động
Đây là callback riêng cho catalog, không thay thế Order API. Khi đăng ký connector, bot đối tác gửi callback HTTPS để hệ thống tự lưu webhook, secret và 3 loại sự kiện. Catalog sản phẩm đang bán cũng được đồng bộ tự động; dự án thông báo vẫn có công tắc bật/tắt riêng để Admin kiểm soát nơi gửi.
Response sau khi đăng ký
{
"product_events": {
"enabled": true,
"callback_url": "https://partner.example.com/webhooks/mloder",
"events": ["product.created", "product.restocked", "product.updated"],
"shared_secret": "mlevt_SECRET_CHI_TRA_MOT_LAN",
"secret_once": true
}
}Lưu shared_secret vào secret/env của bot đối tác. Nếu đăng ký lại có callback URL, secret mới được cấp lại; cập nhật secret mới trước khi bật connector.
Header và chữ ký bắt buộc
Content-Type: application/json
Accept: application/json
User-Agent: MLoder-Product-Events/1.0
X-MLoder-Event-Id: evt_xxx
X-MLoder-Timestamp: 1790000000
X-MLoder-Nonce: nonce-moi-moi-lan
X-MLoder-Signature: hex-hmac-sha256
X-MLoder-Version: product-events-v1
body_hash = SHA256(raw_json_body)
canonical = timestamp + "\n" + nonce + "\n" + body_hash
signature = HMAC_SHA256(canonical, shared_secret)Payload mẫu
{
"version": "product-events-v1",
"event_id": "evt_xxx_partner_12",
"event_type": "product.restocked",
"occurred_at": 1790000000,
"source": {"name": "ML Oder", "bot_username": "mloder_bot"},
"product": {
"external_id": "12",
"code": "SP-001",
"name": "Ten san pham",
"price": 275000,
"currency": "VND",
"stock": 8,
"added_stock": 5,
"active": true,
"description": "Mo ta",
"image_url": "https://...",
"product_url": "https://..."
}
}PHP receiver tối thiểu
<?php
$raw = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_MLODER_TIMESTAMP'] ?? '';
$nonce = $_SERVER['HTTP_X_MLODER_NONCE'] ?? '';
$signature = $_SERVER['HTTP_X_MLODER_SIGNATURE'] ?? '';
if (!ctype_digit($timestamp) || abs(time() - (int)$timestamp) > 300) {
http_response_code(401); exit;
}
$canonical = $timestamp . "\n" . $nonce . "\n" . hash('sha256', $raw);
$expected = hash_hmac('sha256', $canonical, getenv('MLODER_EVENT_SECRET'));
if (!hash_equals($expected, $signature)) { http_response_code(401); exit; }
$event = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
// Luu nonce/event_id de chong replay, sau do dua vao queue noi bo.
header('Content-Type: application/json');
echo json_encode(['ok' => true]);Sự kiện gồm product.created, product.restocked, product.updated; system.test chỉ để kiểm tra callback. Lưu event_id và nonce để chống xử lý trùng/replay. Trả 2xx là đã nhận; 408/425/429/5xx/timeout sẽ retry có backoff, lỗi 400/401/403/404/410 chuyển failed để Admin retry.