API cho nhà phát triển tool
Mọi thứ đội phát triển cần để tự quản lý một tool: sửa thông tin hiển thị, đăng ảnh minh hoạ, viết hướng dẫn sử dụng và phát hành phiên bản mới — không cần vào trang quản trị, không cần ai mở cửa.
Nếu bạn đang nhúng phần xác thực license vào bản cài gửi cho khách thì phần bạn cần nằm ở tài liệu tích hợp cho bản cài: đăng nhập, kiểm hạn license, quản lý thiết bị.
https://cyanpro.app
Header X-Dev-Token
Danh sách endpoint
| Method | Đường dẫn | Dùng để |
|---|---|---|
| GET | /api/v1/dev/product | Đọc thông tin tool và bản phát hành mới nhất |
| PATCH | /api/v1/dev/product | Sửa mô tả, nền tảng, link tải, hướng dẫn sử dụng |
| GET | /api/v1/dev/releases | Lịch sử phát hành (100 bản gần nhất) |
| POST | /api/v1/dev/releases | Phát hành phiên bản mới |
| GET | /api/v1/dev/images | Danh sách ảnh minh hoạ |
| POST | /api/v1/dev/images | Thêm ảnh minh hoạ (tải tệp lên hoặc trỏ tới địa chỉ https) |
| DELETE | /api/v1/dev/images/:id | Xoá một ảnh minh hoạ |
| POST | /api/v1/dev/icon | Đặt biểu tượng phần mềm (tải tệp lên hoặc trỏ tới https) |
| DELETE | /api/v1/dev/icon | Gỡ biểu tượng, quay về chữ viết tắt |
| POST | /api/v1/dev/cover | Đặt ảnh bìa (tải tệp lên hoặc trỏ tới https) |
| DELETE | /api/v1/dev/cover | Gỡ ảnh bìa |
Khoá nhà phát triển
Lấy trong Quản trị → Tool → Khoá nhà phát triển. Khoá hiện đúng một lần lúc tạo; mất thì thu hồi và tạo khoá mới chứ không xem lại được, vì hệ thống chỉ lưu bản băm.
- Mỗi khoá gắn với đúng một tool. Đội làm tool này không chạm được vào tool khác.
- Không bao giờ nhúng khoá này vào bản cài gửi khách. Nó sửa được nội dung và link tải; ai moi được nó ra khỏi tệp thực thi là đổi được link tải phần mềm của bạn.
- Chỗ của nó là máy đội phát triển và biến bí mật trong hệ thống dựng bản (GitHub Actions secrets hoặc tương đương).
- Nhánh này không nhận
X-Api-Keycủa bản cài, và ngược lại khoá dev không đăng nhập hộ khách được. Hai cửa hoàn toàn riêng. - Thu hồi khoá có hiệu lực ngay. Tạo nhiều khoá cho nhiều hệ thống dựng bản để thu hồi một cái không làm chết cái còn lại.
Bắt đầu nhanh
Ba lệnh dưới đây đủ để kiểm tra khoá và đẩy một bản phát hành.
1. Đọc thông tin tool hiện tại
curl -s https://cyanpro.app/api/v1/dev/product \ -H "X-Dev-Token: $CYAN_DEV_TOKEN"
2. Sửa một trường
curl -s -X PATCH https://cyanpro.app/api/v1/dev/product \
-H "X-Dev-Token: $CYAN_DEV_TOKEN" \
-H "Content-Type: application/json" \
-d '{"tagline":"Bộ công cụ desktop cho công việc hằng ngày"}'
3. Phát hành phiên bản mới
curl -s -X POST https://cyanpro.app/api/v1/dev/releases \
-H "X-Dev-Token: $CYAN_DEV_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"version": "1.1.0",
"notes": "- Sửa lỗi đăng nhập\n- Tăng tốc khởi động",
"download_url": "https://example.com/setup-1.1.0.exe"
}'
Sửa thông tin tool
Chỉ gửi những trường muốn đổi; trường không có trong body thì giữ nguyên. Phản hồi trả về danh sách trường đã đổi để hệ thống dựng bản ghi log.
| Trường | Kiểu | Ghi chú |
|---|---|---|
| name | string | Tên tool, tối đa 120 ký tự. Không được để trống. |
| tagline | string | Mô tả một dòng, tối đa 200 ký tự. Hiện dưới tên ở trang danh mục. |
| tagline_en | string | Bản tiếng Anh của mô tả một dòng. Để trống thì trang tiếng Anh dùng bản tiếng Việt. |
| description | string | Mô tả dài, tối đa 4000 ký tự. Hiện ở trang chi tiết. |
| description_en | string | Bản tiếng Anh của mô tả dài. |
| guide | string | Hướng dẫn sử dụng đầy đủ, viết bằng Markdown, tối đa 40000 ký tự. |
| guide_en | string | Bản tiếng Anh của hướng dẫn. |
| icon | string | Một emoji hoặc 1–2 chữ cái, chỉ dùng khi chưa có ảnh biểu tượng. |
| icon_url | string | Ảnh biểu tượng, bắt buộc https. Muốn tải tệp lên thì dùng POST /dev/icon. |
| cover_url | string | Ảnh bìa, bắt buộc https. Muốn tải tệp lên thì dùng POST /dev/cover. |
| platforms | string[] | Mảng chuỗi. Chỉ nhận: Windows, macOS, Linux, Android, iOS, Web. Giá trị lạ bị bỏ qua. |
| download_url | string | Link tải mặc định. Bắt buộc là https. |
PATCH https://cyanpro.app/api/v1/dev/product
X-Dev-Token: cyd_live_xxxxxxxx
Content-Type: application/json
{
"tagline": "Bộ công cụ desktop cho công việc hằng ngày",
"tagline_en": "A desktop toolkit for everyday work",
"description": "Mô tả dài hơn, hiện ở trang chi tiết.",
"platforms": ["Windows", "macOS"],
"download_url": "https://example.com/setup.exe"
}
200 OK
{
"ok": true,
"updated": ["tagline", "tagline_en", "description", "platforms", "download_url"],
"product": { "slug": "cyan-studio", "name": "CYAN Studio", ... }
}
Những trường API không sửa được
Gửi lên cũng bị bỏ qua, không báo lỗi. Đây là lựa chọn có chủ ý, không phải thiếu tính năng:
slug— nằm trong đường dẫn công khai/tools/<slug>. Đổi là hỏng mọi liên kết cũ và mọi kết quả tìm kiếm đã lập chỉ mục.status— ẩn hay hiện một tool là quyết định kinh doanh, làm trong trang quản trị nơi có cảnh báo đi kèm.kind,is_free,free_max_devices— phân loại và chính sách giá, cũng thuộc trang quản trị.
Hướng dẫn sử dụng
Trường guide là nội dung của trang /tools/<slug>/guide. Viết bằng Markdown; mục lục bên trái tự sinh từ các tiêu đề nên hãy chia bài bằng tiêu đề thay vì bằng chữ in đậm.
Cú pháp dùng được: tiêu đề, danh sách, đoạn mã, chữ đậm, chữ nghiêng, liên kết, bảng, trích dẫn.
Biểu tượng phần mềm
Biểu tượng là thứ đầu tiên người ta nhìn ở trang sản phẩm và ở danh mục. Chưa đặt thì hệ thống hiện chữ viết tắt của tên — đủ dùng nhưng trông như ô chưa kịp điền.
Tải tệp lên
curl -s -X POST https://cyanpro.app/api/v1/dev/icon \ -H "X-Dev-Token: $CYAN_DEV_TOKEN" \ -F "file=@icon-512.png"
201 Created
{ "ok": true, "icon_url": "/media/3b7e…a1.png", "uploaded": true }
Hoặc trỏ tới ảnh có sẵn
POST https://cyanpro.app/api/v1/dev/icon
X-Dev-Token: cyd_live_xxxxxxxx
Content-Type: application/json
{ "url": "https://cdn.example.com/icon-512.png" }
Gỡ biểu tượng
DELETE https://cyanpro.app/api/v1/dev/icon X-Dev-Token: cyd_live_xxxxxxxx
- Ảnh vuông, cạnh tối thiểu 256px. Trang sản phẩm hiện ở 88px, danh mục ở 48px, nên ảnh nhỏ hơn sẽ bị kéo nhoè.
- Nền trong suốt (PNG) hoặc nền đặc đều được — khung bo góc 20px sẽ cắt theo.
- Đặt biểu tượng mới là thay cái cũ. Tệp cũ được dọn khỏi hệ thống, trừ khi nó đang đồng thời là một ảnh minh hoạ.
- Cùng giới hạn tệp với ảnh minh hoạ: PNG, JPEG, WebP, GIF và tối đa 3MB; loại tệp xác định bằng nội dung chứ không theo tên.
Ảnh bìa
Dải ảnh ngang ở đầu trang sản phẩm, và ảnh đại diện của tool trong danh mục. Khác ảnh minh hoạ: đây là ảnh dựng riêng, có tên phần mềm và khoảng thở, nên cắt kiểu gì cũng vẫn đọc được.
Tải tệp lên
curl -s -X POST https://cyanpro.app/api/v1/dev/cover \ -H "X-Dev-Token: $CYAN_DEV_TOKEN" \ -F "file=@cover-1024x500.png"
201 Created
{ "ok": true, "cover_url": "/media/8d12…7c.png", "uploaded": true }
Gỡ ảnh bìa
DELETE https://cyanpro.app/api/v1/dev/cover X-Dev-Token: cyd_live_xxxxxxxx
- Dựng đúng 1920×640 (tỉ lệ 3:1). Ảnh khác tỉ lệ vẫn nhận nhưng sẽ bị cắt cho vừa khung, vì khung có tỉ lệ cố định — để khung chạy theo ảnh thì mỗi phần mềm một chiều cao.
- Chữ và logo nằm trong vùng giữa rộng 1140px. Khung hẹp dần theo màn hình (3:1 → 2:1 → 16:9) và luôn cắt từ hai mép vào, nên vùng giữa là phần duy nhất chắc chắn còn nguyên.
- Chưa đặt thì đầu trang không có dải ảnh, và danh mục mượn tạm ảnh minh hoạ đầu tiên.
Ảnh minh hoạ
Ảnh hiện ở trang chi tiết tool và ảnh đầu tiên làm ảnh bìa trong danh mục. Hai cách thêm: tải tệp lên hệ thống, hoặc trỏ tới ảnh đặt ở CDN riêng của bạn.
Tải tệp lên
curl -s -X POST https://cyanpro.app/api/v1/dev/images \ -H "X-Dev-Token: $CYAN_DEV_TOKEN" \ -F "file=@screenshot-1.png" \ -F "caption=Màn hình chính" \ -F "caption_en=Main window" \ -F "sort_order=1"
Trỏ tới ảnh đặt ở nơi khác
POST https://cyanpro.app/api/v1/dev/images
X-Dev-Token: cyd_live_xxxxxxxx
Content-Type: application/json
{
"url": "https://cdn.example.com/shots/main.png",
"caption": "Màn hình chính",
"caption_en": "Main window",
"sort_order": 1
}
201 Created
{
"ok": true,
"image": {
"id": "img_7f3a…",
"url": "/media/9c1f…c4.png",
"caption": "Màn hình chính",
"width": 1920,
"height": 1200,
"bytes": 184320,
"sort_order": 1
}
}
- Chỉ nhận PNG, JPEG, WebP, GIF. Loại tệp xác định bằng nội dung, không bằng phần mở rộng hay
Content-Typekhai trong request. - Tối đa 3MB mỗi tệp và 12 ảnh mỗi tool.
- Ảnh trỏ từ nơi khác bắt buộc là https.
- Dùng
sort_orderđể quyết định thứ tự hiện; số nhỏ lên trước. - Chú thích nên nói ảnh cho thấy điều gì — nó cũng là chữ thay thế cho người dùng trình đọc màn hình.
DELETE https://cyanpro.app/api/v1/dev/images/img_7f3a… X-Dev-Token: cyd_live_xxxxxxxx
Xoá ảnh bằng id lấy từ GET /api/v1/dev/images. Khoá dev chỉ xoá được ảnh của đúng tool nó quản.
Phát hành phiên bản mới
Gọi từ hệ thống dựng bản sau khi đã đóng gói và tải bản cài lên nơi lưu trữ. Mỗi số hiệu chỉ phát hành một lần.
| Trường | Kiểu | Ghi chú |
|---|---|---|
| version | string | Bắt buộc. Chỉ gồm chữ, số và các dấu . - +, phải có ít nhất một chữ số. Tối đa 40 ký tự. |
| notes | string | Nội dung thay đổi, tối đa 20000 ký tự. Phần mềm hiện lại cho người dùng khi báo có bản mới. |
| notes_en | string | Bản tiếng Anh của nội dung thay đổi. |
| download_url | string | Link tải bản này. Bắt buộc https. Để trống thì dùng link tải mặc định của tool. |
| is_mandatory | boolean | true nếu bản này buộc phải cập nhật. Phần mềm nên chặn sử dụng cho tới khi cập nhật xong — chỉ dùng cho bản vá lỗi bảo mật hoặc đổi giao thức. |
201 Created
{
"ok": true,
"release": {
"version": "1.1.0",
"is_latest": true,
"is_mandatory": false,
"download_url": "https://example.com/setup-1.1.0.exe",
"released_at": 1792470000
}
}
Thứ tự phiên bản được so sánh theo số
So theo từng đoạn số, nên 1.10.0 mới hơn 1.9.0 (so chuỗi thuần sẽ cho kết quả ngược). Bản thử nghiệm nhỏ hơn bản chính thức: 1.0.0-beta.1 < 1.0.0. Phần sau dấu + không tham gia so sánh.
Phát hành một bản CŨ HƠN bản hiện hành vẫn được lưu vào lịch sử nhưng không kéo lùi bản mới nhất: trả về is_latest: false kèm note giải thích. Nhờ vậy vá cho nhánh cũ không rủ khách đang chạy bản mới hạ cấp.
Lịch sử phát hành
GET https://cyanpro.app/api/v1/dev/releases X-Dev-Token: cyd_live_xxxxxxxx
Bản mới tới tay khách thế nào
- Bạn gọi
POST /api/v1/dev/releases. Nếu phiên bản mới hơn bản hiện hành,latest_versioncủa tool nhảy theo ngay. - Bản cài trên máy khách gọi
GET /api/v1/version?current=<phiên bản đang chạy>bằngX-Api-Keycủa nó — endpoint duy nhất liên quan tới phát hành mà khoá của bản cài được phép gọi. - Phản hồi cho biết
update_available,latest_version,download_url,notesvàis_mandatory. - Không có hệ thống đẩy thông báo: máy khách tự hỏi. Nên gọi lúc khởi động, và thêm một lần mỗi vài giờ nếu phần mềm mở lâu.
Gắn vào hệ thống dựng bản
Ví dụ cho GitHub Actions: sau khi đóng gói, đẩy bản phát hành bằng khoá lấy từ secret. Đừng in khoá ra log — curl nhận khoá qua biến môi trường, không viết thẳng vào dòng lệnh.
# .github/workflows/release.yml
- name: Phát hành lên cyanpro.app
env:
CYAN_DEV_TOKEN: ${{ secrets.CYAN_DEV_TOKEN }}
VERSION: ${{ github.ref_name }}
run: |
curl -sS --fail-with-body -X POST https://cyanpro.app/api/v1/dev/releases \
-H "X-Dev-Token: $CYAN_DEV_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg v "${VERSION#v}" \
--arg notes "$(cat CHANGELOG-latest.md)" \
--arg url "https://downloads.example.com/setup-${VERSION#v}.exe" \
'{version: $v, notes: $notes, download_url: $url}')"
Lệnh trên dừng với mã lỗi khác 0 khi máy chủ trả lỗi, nhờ --fail-with-body: một bản phát hành thất bại phải làm đỏ cả lần dựng, chứ không im lặng đi qua.
Mã lỗi
Mọi phản hồi lỗi có cùng khuôn: { "ok": false, "error": "mã_lỗi", "message": "mô tả" }. Xử lý theo error chứ đừng so khớp message — phần chữ có thể đổi, mã thì không.
| Mã | HTTP | Nghĩa và cách xử lý |
|---|---|---|
| missing_dev_token | 401 | Thiếu header X-Dev-Token. Lưu ý API key của bản cài không dùng được ở nhánh này. |
| invalid_dev_token | 401 | Khoá sai hoặc đã bị thu hồi. Kiểm tra secret trong hệ thống dựng bản. |
| product_not_found | 404 | Tool gắn với khoá này đã bị xoá. Tạo khoá mới cho tool hiện tại. |
| invalid_json | 400 | Thân request không phải JSON hợp lệ. |
| nothing_to_update | 400 | Không có trường nào hợp lệ trong body. Kiểm tra lại tên trường. |
| invalid_name | 400 | Tên tool để trống. |
| invalid_platforms | 400 | platforms phải là một mảng chuỗi. |
| invalid_download_url | 400 | Link tải phải là địa chỉ https đầy đủ. |
| missing_version | 400 | Thiếu trường version. |
| invalid_version | 400 | Chuỗi phiên bản không hợp lệ. |
| version_exists | 409 | Số hiệu này đã phát hành. Dùng số mới cho bản sửa — đừng phát hành đè. |
| image_too_large | 413 | Ảnh vượt 3MB. Nén lại trước khi tải lên. |
| not_an_image | 400 | Tệp không phải ảnh thuộc các loại được nhận. |
| invalid_icon_url | 400 | Địa chỉ biểu tượng phải là https. |
| invalid_cover_url | 400 | Địa chỉ ảnh bìa phải là https. |
| too_many_images | 409 | Tool đã đủ số ảnh cho phép. Xoá ảnh cũ trước khi thêm. |
| image_not_found | 404 | Không có ảnh với id đó trong tool này. |
| rate_limited | 429 | Gọi quá nhiều. Chờ đúng số giây trong header Retry-After rồi thử lại. |
Giới hạn gọi
120 lần mỗi giờ cho mỗi khoá dev. Chạm ngưỡng thì nhận HTTP 429 kèm header Retry-After tính bằng giây. Giới hạn này thưa vì đây là thao tác phát hành, không phải thao tác chạy trong vòng lặp; nếu hệ thống dựng bản của bạn chạm ngưỡng thì gần như chắc chắn nó đang gọi lặp vì một lỗi khác.
Trước khi phát hành bản đầu tiên
- Khoá dev nằm trong secret của hệ thống dựng bản, không nằm trong mã nguồn, không nằm trong bản cài.
- Link tải là https và tải về được từ máy ngoài mạng nội bộ.
- Số hiệu phiên bản lớn hơn
latest_versionhiện tại. - Nội dung thay đổi viết cho người dùng cuối đọc, không phải danh sách commit.
- Đã thử gọi
GET /api/v1/versionbằng API key của bản cài và thấy đúng bản vừa phát hành.