Hotline: 0852 87 45 87
TÀI LIỆU API

Public API DybiCMS

Thêm, sửa bài viết và upload ảnh vào website từ phần mềm của doanh nghiệp: công cụ đăng bài, hệ thống nội bộ hoặc quy trình tự động.

Phiên bản v1JSON qua HTTPSXác thực bằng API keyTải OpenAPI (JSON)

Bắt đầu

Mọi endpoint nằm dưới địa chỉ gốc:

https://api.dybiweb.com/api/public/v1
  1. Đăng nhập CMS bằng tài khoản có quyền quản trị cấu hình, vào Cấu hình → Kết nối → API.
  2. Tạo API key: đặt tên gợi nhớ, chọn quyền cần dùng và thời hạn (30 ngày đến 2 năm).
  3. Sao chép key ngay khi tạo. Key chỉ hiển thị một lần; hệ thống không lưu bản gốc.
  4. Gọi thử endpoint kiểm tra key:
curl https://api.dybiweb.com/api/public/v1/me \
  -H "X-Api-Key: dybi_live_xxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
{
  "companyId": "5b0c…",
  "companyName": "Tên doanh nghiệp",
  "keyName": "Công cụ đăng bài",
  "scopes": ["articles:read", "articles:write", "files:read", "files:write"],
  "expiresUtc": "2027-10-28T04:37:31Z"
}

Xác thực và quyền

Gửi key trong header X-Api-Key ở mọi yêu cầu, chỉ qua HTTPS. Không đặt key trên địa chỉ URL hoặc trong mã chạy trên trình duyệt: yêu cầu có header Origin của trình duyệt sẽ bị từ chối.

Key thuộc về một doanh nghiệp và hoạt động với danh nghĩa người đã tạo key: bài tạo qua API ghi người đó là người tạo. Key chỉ đọc, ghi dữ liệu của doanh nghiệp mình.

Quyền (scope)Cho phép
articles:readXem danh mục và bài viết
articles:writeThêm và sửa bài viết
files:readXem danh sách ảnh trong thư viện
files:writeUpload ảnh

Key ngừng hoạt động ngay khi bị thu hồi trong CMS, hết hạn, hoặc khi người tạo bị khóa tài khoản hay không còn quyền quản trị cấu hình. Khi đó hãy tạo key mới. Nếu nghi key bị lộ, thu hồi ngay; lịch sử sử dụng key xem ở tab Lịch sử cùng màn hình.

Key chỉ sửa được bài do người tạo key viết. Muốn sửa bài của người khác, người tạo key cần quyền sửa nội dung của người khác trong CMS.

Giới hạn

MụcGiới hạn
Số yêu cầu60 yêu cầu/phút cho mỗi key
Upload ảnh20 file/phút cho mỗi key
Xác thực sai30 lần/phút cho mỗi địa chỉ IP, sau đó tạm chặn 1 phút
File ảnhJPG, PNG, WEBP, GIF; tối đa 5 MB; tối đa 8000px mỗi chiều, 25 triệu điểm ảnh, 300 khung hình
Bài viếtTiêu đề 300 ký tự; mô tả ngắn 2000 ký tự; nội dung 1.000.000 ký tự; tối đa 20 thẻ, mỗi thẻ 100 ký tự
Phân trangpageSize tối đa 100

Vượt giới hạn tần suất nhận mã 429 kèm header Retry-After (số giây cần chờ). Hãy chờ đúng thời gian đó rồi gửi lại.

Đăng bài có ảnh

  1. Upload từng ảnh bằng POST /files. Kết quả có url (ảnh gốc) và webpUrl (bản WebP do hệ thống tạo).
  2. Chèn url vào nội dung bài, ví dụ <img src="…" alt="Mô tả ảnh">.
  3. Lấy id danh mục bằng GET /categories.
  4. Tạo bài bằng POST /articles; dùng coverFile là fileName của ảnh muốn làm ảnh đại diện. Bài mới mặc định là nháp.
  5. Kiểm tra trong CMS, rồi đăng bằng PATCH /articles/{id} với "isPublished": true (hoặc gửi luôn khi tạo bài).

Danh sách endpoint

MethodĐường dẫnQuyềnMô tả
GET/mebất kỳThông tin key và doanh nghiệp
GET/categoriesarticles:readDanh mục bài viết
GET/articlesarticles:readDanh sách bài viết
GET/articles/{id}articles:readChi tiết bài viết
POST/articlesarticles:writeThêm bài viết
PATCH/articles/{id}articles:writeSửa bài viết
POST/filesfiles:writeUpload ảnh
GET/filesfiles:readDanh sách ảnh, kèm link

Bài viết

GET /categories

Tham số tùy chọn: language (mặc định vi) để lấy tên danh mục theo ngôn ngữ.

[
  { "id": "8f0e…", "parentId": null, "title": "Tin tức", "isPublished": true, "order": 1 }
]

GET /articles

Tham số tùy chọn: categoryId, q (tìm theo tiêu đề, gõ có dấu hoặc không dấu), language, page (mặc định 1), pageSize (mặc định 20). Bài mới nhất theo ngày hiển thị đứng trước.

{
  "items": [{
    "id": "3c1d…", "categoryId": "8f0e…", "title": "Bài viết đầu tiên",
    "isPublished": false, "displayDate": "2026-10-28T10:00:00", "order": 50,
    "coverUrl": "https://api.dybiweb.com/Files/…/Article/bai-viet-dau-tien_638….jpg",
    "path": "/bai-viet-dau-tien", "url": "https://ten-mien-cua-ban/bai-viet-dau-tien",
    "languages": ["vi"]
  }],
  "total": 1, "page": 1, "pageSize": 20
}

GET /articles/{id}

Tham số tùy chọn language. Trả về tiêu đề, mô tả ngắn, nội dung HTML, thẻ, ngày hiển thị, trạng thái đăng, ảnh đại diện, đường dẫn trên website và các ngôn ngữ đã có. Trả 404 nếu bài chưa có bản ngôn ngữ được yêu cầu.

POST /articles

curl -X POST https://api.dybiweb.com/api/public/v1/articles \
  -H "X-Api-Key: $DYBI_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "categoryId": "8f0e…",
    "title": "Bài viết đầu tiên",
    "brief": "Tóm tắt ngắn hiển thị ở danh sách bài.",
    "content": "<h2>Mở đầu</h2><p>Nội dung…</p>",
    "tags": ["website", "seo"],
    "coverFile": "20261028103000_a1b2c3d4_anh-bia.jpg",
    "isPublished": false
  }'
TrườngBắt buộcGhi chú
categoryIdCóDanh mục bài viết lấy từ GET /categories
titleCóVăn bản thuần, tối đa 300 ký tự; dùng để tạo đường dẫn SEO
briefCóVăn bản thuần, thẻ HTML sẽ bị bỏ
contentKhôngHTML, được làm sạch theo quy tắc nội dung
languageKhôngMặc định vi; phải là ngôn ngữ đã bật cho website
tagsKhôngDanh sách thẻ; thẻ trùng sẽ được gộp
displayDateKhôngNgày hiển thị, mặc định là thời điểm tạo
isPublishedKhôngMặc định false (nháp)
orderKhôngThứ tự sắp xếp, mặc định 50
coverFileKhôngfileName trả về từ POST /files; dùng làm ảnh đại diện
idKhôngGUID do bạn chọn. Gửi lại cùng id sau khi mất kết nối sẽ nhận 409 thay vì tạo bài trùng

Thành công trả 201, header Location và nội dung bài như GET /articles/{id}, gồm cả path/url trên website.

PATCH /articles/{id}

Chỉ gửi những trường cần đổi; trường không gửi hoặc null giữ nguyên. Gửi "content": "" để xóa nội dung, "tags": [] để xóa thẻ. Trường language chọn bản ngôn ngữ cần sửa (mặc định vi); gửi một ngôn ngữ bài chưa có để thêm bản dịch, khi đó cần title và brief.

curl -X PATCH https://api.dybiweb.com/api/public/v1/articles/3c1d… \
  -H "X-Api-Key: $DYBI_API_KEY" -H "Content-Type: application/json" \
  -d '{ "isPublished": true }'

File ảnh

POST /files

Gửi multipart/form-data với đúng một file trong trường file. Ảnh được kiểm tra nội dung thật, bỏ thông tin EXIF/vị trí và lưu với tên do hệ thống đặt.

curl -X POST https://api.dybiweb.com/api/public/v1/files \
  -H "X-Api-Key: $DYBI_API_KEY" \
  -F "[email protected]"
{
  "fileName": "20261028103000_a1b2c3d4_anh-bia.jpg",
  "url": "https://api.dybiweb.com/Files/…/20261028103000_a1b2c3d4_anh-bia.jpg",
  "webpUrl": "https://api.dybiweb.com/Files/…/20261028103000_a1b2c3d4_anh-bia.jpg.webp",
  "size": 182344, "contentType": "image/jpeg", "width": 1600, "height": 900,
  "modifiedUtc": "2026-10-28T03:30:00Z"
}

File lớn hơn giới hạn nhận 413. Với file lớn, curl tự gửi Expect: 100-continue nên nhận được thông báo lỗi trước khi gửi hết dữ liệu; thư viện khác nên bật tùy chọn tương tự hoặc kiểm tra kích thước trước khi gửi.

GET /files

Danh sách ảnh trong thư viện của website (cùng thư viện với trình chọn ảnh trong CMS), mới nhất trước. Tham số tùy chọn: q (tìm theo tên file), page, pageSize (mặc định 50). Mỗi ảnh có fileName, url, webpUrl, size, modifiedUtc.

HTML được phép trong nội dung

Nội dung được làm sạch về đúng định dạng trình soạn thảo của CMS để có thể tiếp tục sửa trong CMS:

  • Giữ: đoạn văn, tiêu đề h2–h6, in đậm/nghiêng/gạch chân/gạch ngang, chỉ số trên/dưới, danh sách, trích dẫn, khối mã, liên kết, ảnh và video YouTube/Vimeo nhúng.
  • h1 được đổi thành h2 vì tiêu đề bài là H1 duy nhất của trang.
  • Ảnh phải dùng địa chỉ https://; nên dùng url nhận từ POST /files và luôn có alt.
  • Chỉ giữ class căn lề/thụt lề của trình soạn thảo (ql-align-*, ql-indent-*…) và màu chữ/màu nền.
  • Bỏ: script, style, form, iframe khác YouTube/Vimeo, thuộc tính sự kiện (onclick…), liên kết javascript:. Thẻ bọc như div, section được bỏ nhưng giữ chữ bên trong.

Mã lỗi

Lỗi trả về JSON thống nhất; hiển thị hoặc ghi log trường message:

{ "codeResponse": 422, "codeError": 0, "message": "Danh mục bài viết … không tồn tại. Lấy danh sách bằng GET /categories." }
MãÝ nghĩa
400Dữ liệu thiếu hoặc sai định dạng
401Thiếu key, key sai, hết hạn, đã thu hồi, gọi qua HTTP hoặc từ trình duyệt
403Key thiếu quyền cho thao tác, hoặc sửa bài của người khác
404Không có bài viết hoặc bản ngôn ngữ (kể cả bài của doanh nghiệp khác)
409Đã có bài với id gửi lên
413File vượt quá 5 MB
415Không phải ảnh JPG/PNG/WEBP/GIF hợp lệ, hoặc không gửi multipart
422Danh mục, ngôn ngữ hoặc file ảnh đại diện không hợp lệ; ảnh quá lớn
429Vượt giới hạn tần suất; chờ theo Retry-After
502Không lưu được file vào kho lưu trữ; thử lại sau

Lịch sử thay đổi

v1 (28/10/2026): phát hành API key theo doanh nghiệp, bài viết (danh mục, danh sách, chi tiết, thêm, sửa) và file ảnh (upload, danh sách). Mô tả máy đọc được: OpenAPI public-v1.

Trao đổi nhu cầu của bạn với Dybi

Website theo yêu cầu, phần mềm POS hoặc một quy trình kết hợp cả hai.

Đăng ký tư vấn