Giao thức CLV1 đã công khaiĐọc đặc tả

/seller/v1

Seller API

Bán key, quản lý khách và đại lý từ hệ thống của bạn, đúng quyền, không làm hai lần

Đặc tả kỹ thuật hiện được viết bằng tiếng Anh để giữ chính xác từng thuật ngữ

Authentication

Create a key in Settings › API keys. It is shown once; only an HMAC of it is stored. Send it in the header on every call, never in the URL (a key in the query string is refused with key_in_url).

curl https://<your API host>/seller/v1/apps \
  -H "Authorization: Bearer clv_live_…"

Keys can be limited to some apps, to a list of IPs or CIDR ranges, and given an expiry. Rotating a key creates a new one and keeps the old one working for 7 days; revoking is immediate.

Scopes

A key does only what its scopes allow; a key with no scope can do nothing. *:read scopes never change anything. Presets: read only, Discord bot (licenses, users, devices), store (licenses), full access.

Writes and idempotency

POST creates or acts, PATCH and PUT change, DELETE removes (licenses are soft-deleted). Send Idempotency-Key with any write: repeating it within 24 hours returns the first answer (marked Idempotent-Replayed: true) instead of acting twice. The same key with a different body is refused.

curl -X POST https://<host>/seller/v1/apps/app_…/licenses \
  -H "Authorization: Bearer clv_live_…" \
  -H "Idempotency-Key: order-1001" \
  -H "Content-Type: application/json" \
  -d '{ "policyId": "pol_…", "count": 1, "email": "buyer@example.com" }'

Full license keys are returned once, in that answer. Store them or send them to the buyer right away.

Rate limits and pages

120 requests per minute per key, 600 on Premium. Every answer carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset. Lists take ?limit=50&cursor=… and answer { data, nextCursor }. Every call is logged and visible in the dashboard.

Errors

{ "error": { "code": "forbidden_scope", "message": "…", "details": {}, "requestId": "…" } }
unauthorized401Missing, malformed, expired or revoked key
key_in_url400A key was sent in the query string; use the header
forbidden_scope403The key lacks the scope this endpoint needs
ip_not_allowed403The caller is outside the key's allow list
not_found404Unknown id, or outside the key's apps
validation_failed400The body or query did not match the schema
conflict409Duplicate (username taken, already exists)
idempotency_mismatch422Same Idempotency-Key, different request
idempotency_in_progress409The first request with this key is still running
rate_limited429Over the per-key limit; see RateLimit-* headers
plan_limit402The workspace plan does not allow this
insufficient_credit402A reseller order costs more than the balance

Endpoints

The machine-readable reference is GET /seller/v1/openapi.json (OpenAPI 3.1, generated from the same schemas that validate requests).

MethodPathScope
GET/meany
GET/appsany
GET/apps/{appId}/licenseslicenses:read
POST/apps/{appId}/licenseslicenses:write
GET/licenses/{id}licenses:read
POST/licenses/lookuplicenses:read
POST/licenses/{id}/actionslicenses:write
DELETE/licenses/{id}licenses:write
GET/apps/{appId}/usersusers:read
POST/apps/{appId}/usersusers:write
GET/users/{id}users:read
POST/users/{id}/actionsusers:write
DELETE/users/{id}users:write
GET/apps/{appId}/devicesdevices:read
GET/devices/{id}devices:read
POST/devices/{id}/actionsdevices:write
GET/apps/{appId}/sessionssessions:read
POST/sessions/{id}/revokesessions:write
POST/apps/{appId}/sessions/revoke-allsessions:write
GET/apps/{appId}/variablesvariables:read
PUT/apps/{appId}/variablesvariables:write
DELETE/variables/{id}variables:write
GET/apps/{appId}/rulesrules:read
POST/apps/{appId}/rulesrules:write
DELETE/rules/{id}rules:write
GET/apps/{appId}/webhookswebhooks:read
POST/apps/{appId}/webhookswebhooks:write
DELETE/webhooks/{id}webhooks:write
POST/webhooks/{id}/testwebhooks:write
GET/apps/{appId}/statsstats:read
GET/apps/{appId}/protect/summaryprotect:read
GET/apps/{appId}/protect/eventsprotect:read
GET/resellersresellers:read
POST/resellers/{id}/creditresellers:write
GET/resellers/{id}/ledgerresellers:read

Webhooks

Each delivery is { id, type, createdAt, appId, data } with the header Clavis-Signature: t=<unix>,v1=<hex>, an HMAC-SHA256 of t.body with your signing secret. Check the time is within 5 minutes. Failed deliveries are retried about 15 times over 3 days and can be resent from the dashboard.

import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(rawBody, header, secret) {
  const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  return timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}

Resellers

A reseller key (created by the reseller in their desk) sees and acts only on the keys that reseller issued, and every key it creates is paid from their credit in the same transaction: an order larger than the balance is refused with insufficient_credit and nothing is charged.

Bạn cần giúp gì?

Câu hỏi thường gặp

ClavisAUH là gì?

Dịch vụ bản quyền và xác thực cho phần mềm desktop: license key, khoá thiết bị, đăng nhập người dùng và phản hồi có chữ ký. Tất cả quản lý trên một dashboard

Vì sao kẻ crack không làm giả được server?

SDK chỉ tin câu trả lời ký bằng khoá bí mật của ứng dụng. Khoá đó không bao giờ rời server của chúng tôi, nên server giả không ký được và bị từ chối

Trong file chạy của tôi có gì?

Mã ứng dụng và khoá công khai. Không có bí mật nào, vì mỗi thiết bị tự tạo cặp khoá riêng ở lần chạy đầu

Có chạy được khi offline không?

Có. Mọi gói đều có token offline có chữ ký dùng được 7 ngày, ứng dụng tự kiểm tra tại máy. Premium cho bạn chọn bao lâu. License đã thu hồi vẫn có thể chạy offline trong khoảng đó, trừ khi Chế độ chỉ online đang bật

Hỗ trợ những ngôn ngữ nào?

Hiện có JavaScript và TypeScript. Tiếp theo là C++, C# và Python, cùng một giao thức công khai

Gói Basic có miễn phí thật không?

Có. Không giới hạn thời gian, không cần thẻ. Cần nhiều hơn thì lên Premium

Liên hệ