# API Hosting, Storage và Project

API quản lý dùng key tài khoản wpc_, chỉ đặt ở backend hoặc công cụ riêng của bạn.

Nguồn: https://whypik.com/docs/cloud-api
Nhóm: Lập trình viên
Phiên bản tài liệu: 2026-10-14.10
Ngôn ngữ: vi

## Bắt đầu

Liên kết mục: https://whypik.com/docs/cloud-api#section-0

Tạo API key tại Gói & API tài khoản, chọn scopes tối thiểu và giới hạn Project nếu phù hợp. Base https://app.whypik.com/api/v1/cloud. Dùng Authorization:Bearer wpc_..., JSON hoặc multipart đúng endpoint. Không đặt key trong link tải/query string hay frontend public.


## Khóa triển khai CI/CD

Liên kết mục: https://whypik.com/docs/cloud-api#section-1

Tạo API key → Loại key → CI/CD · Hosting hoặc CI/CD · Mini Server → chọn Dự án và Tài nguyên triển khai. Secret chỉ xuất hiện một lần. CLI đọc WHYPIK_DEPLOY_KEY; bộ sinh CI dùng secret nguồn WHYPIK_HOSTING_DEPLOY_KEY hoặc WHYPIK_API_DEPLOY_KEY rồi map vào biến này; whypik.toml chỉ lưu UUID Project và site/service. Không cấp khóa quản lý toàn tài khoản cho pipeline.

Khóa CI chỉ POST deployment, tải bytes Hosting và GET trạng thái đúng tài nguyên. Không được bật/tắt dịch vụ, rollback, xóa, quản lý tên miền, đọc logs, đọc Database, đọc/sửa Variables hoặc tạo key. Với Hosting phải truyền site_id; Mini Server phải truyền service_id, kể cả tài nguyên mặc định. Khóa quá hạn/thu hồi hoặc tài nguyên tạm dừng/vượt gói không được triển khai.

API tạo khóa dành cho phiên chủ tài khoản + CSRF: POST /api/v1/seller/cloud/keys nhận name, days, project_id, deploy_target (hosting/api), deploy_resource_id. Không kèm scopes quản lý; scopes đọc/ghi dịch vụ được gán kèm giới hạn route và tài nguyên. GET keys trả deploy_target và deploy_resource_id; null nghĩa là khóa quản lý cũ. Khóa quản lý hiện có giữ nguyên quyền.

WHYPIK_DEPLOY_KEY ưu tiên hơn WHYPIK_CLOUD_KEY khi CLI gọi Cloud. Để dùng logs/rollback bằng khóa quản lý trên máy riêng, bỏ WHYPIK_DEPLOY_KEY khỏi terminal và đặt WHYPIK_CLOUD_KEY với quyền Mini Server tương ứng. Không đưa khóa Admin Database vào CI chỉ để deploy.

```
// JSON gửi từ phiên chủ tài khoản đã đăng nhập, kèm X-CSRFToken
{
  "name": "GitHub production API",
  "days": 90,
  "project_id": "PROJECT_UUID",
  "deploy_target": "api",
  "deploy_resource_id": "SERVICE_UUID"
}
```


## Thứ tự pipeline, trạng thái và retry

Liên kết mục: https://whypik.com/docs/cloud-api#section-2

CLI nhận GitHub Actions, GitLab CI hoặc Bitbucket Pipelines từ metadata môi trường. Chỉ deploy pipeline của branch, không deploy pull/merge request hay tag. Cần git, quyền đọc origin và UUID tài nguyên trong cấu hình. CLI so HEAD local với commit CI và HEAD hiện tại của branch trên origin trước khi gửi; không in URL remote hay credential khi kiểm tra lỗi.

CLI dùng một Idempotency-Key ổn định theo Project, tài nguyên và lần pipeline; GitHub dùng run_number, GitLab dùng pipeline IID, Bitbucket dùng build number. Cùng lần chạy phải gửi lại cùng nội dung. API chặn số thứ tự cũ trong cùng luồng repository/workflow/branch; không suy diễn thứ tự commit giữa hai repository hoặc branch khác nhau. Worker chỉ tự kích hoạt phiên bản được nhận mới nhất của tài nguyên, nên bản cũ xử lý chậm không đè bản mới.

GET /projects/ID/deployments/DEPLOYMENT_ID?site_id=UUID hoặc GET /projects/ID/mini/deployments/DEPLOYMENT_ID?service_id=UUID trả {deployment,active}. HTTP 201/202 chỉ nhận yêu cầu; ready chưa đủ, cần active=true. CLI trả lỗi khi bản ready nhưng không được kích hoạt, và không tự bật lại backend tạm dừng.

Mất kết nối: gửi lại cùng Idempotency-Key và bytes để đọc/tiếp tục receipt. Mini Server chỉ tiếp tục lượt uploading còn hạn; không tăng quota deployment lần nữa. Receipt failed/deleting/deleted không hồi sinh: khắc phục nguyên nhân rồi tạo lần pipeline mới. GitHub Re-run jobs giữ run_number nên vẫn dùng receipt cũ. Với deploy thủ công, lưu UUID CLI in ra và dùng --idempotency-key UUID khi chưa biết kết quả.


## Ghim bộ cài WhyPik CLI

Liên kết mục: https://whypik.com/docs/cloud-api#section-3

GET /api/v1/public/sdk/mini/manifest.json trả package, version, sha256 và path tải theo checksum của release hiện tại. Lưu URL và SHA256 cụ thể vào pipeline khi thiết lập; không lấy manifest latest ở mỗi lần chạy. Kiểm SHA256 của bytes tải về trước khi cài. ZIP tại URL chứa checksum được giữ qua những lần cập nhật WhyPik.

URL /api/v1/public/sdk/mini/whypik-mini.zip luôn là bản hiện tại, phù hợp cài tương tác. Ghim ZIP không tự ghim dependency build của pip, Node, image CI hoặc thư viện ứng dụng; các thành phần này cần cấu hình riêng theo project. Không tải hay thực thi script từ URL người dùng cuối cung cấp.

- [Manifest WhyPik CLI](https://whypik.com/api/v1/public/sdk/mini/manifest.json)

## Chọn thời hạn khóa

Liên kết mục: https://whypik.com/docs/cloud-api#section-4

Trong mục tạo khóa, chọn Thời hạn khóa: 90 ngày, 1, 3, 5, 10 năm hoặc Không hết hạn. Tùy chọn số ngày nhận từ 1 đến 3650 ngày. Áp dụng cho khóa Cloud, khóa Auth public/BFF, khóa Data API public/server và API key Storage cửa hàng.

Không hết hạn nghĩa là khóa không tự hết hạn theo ngày; bạn vẫn có thể thu hồi trong trang quản lý. Quyền, Project, origin và trạng thái dịch vụ vẫn được kiểm tra như trước. Khóa đã tạo trước đây giữ nguyên ngày hết hạn; muốn đổi thời hạn, tạo khóa mới và cập nhật ứng dụng.

API tạo khóa nhận days là số nguyên 1–3650 hoặc null để chủ động chọn không hết hạn. Metadata expires_at trả null cho khóa không hết hạn. Bỏ days không có nghĩa là không hết hạn: Auth/Data mặc định 90 ngày; Cloud/Storage cửa hàng yêu cầu trường này. Không dùng chuỗi "null" hay số 0.

Thời hạn khóa độc lập với phiên đăng nhập, OTP và URL tải có chữ ký. Các thông tin này vẫn hết hạn theo cơ chế riêng.

```
// Trường days trong JSON gửi endpoint tạo khóa
{ "days": 3650 } // 10 năm
{ "days": null } // Không hết hạn
```


## Tìm contract đang chạy

Liên kết mục: https://whypik.com/docs/cloud-api#section-5

Trang Gói & API tài khoản có ví dụ gọi API. Danh sách endpoint dưới đây theo bản hiện tại. Project dùng UUID công khai; không tự ghép raw R2 key/bucket. Các request tạo upload/deploy cần Idempotency-Key. Khi trả job/operation, theo dõi status thay vì coi HTTP accepted là hoàn tất.


## Chọn website hoặc bucket

Liên kết mục: https://whypik.com/docs/cloud-api#section-6

Mọi ID dưới đây là UUID API trả về. GET /projects/ID/sites hoặc /buckets trả {resources,limits}; mỗi resource có id,name,slug,is_default,enabled,status,locked,version. limits gồm used,limit,scope=account và trial. Resource mặc định được tạo cùng Project nhưng chỉ dùng được sau kích hoạt dịch vụ.

POST /projects/ID/sites nhận {name,slug,spa_mode?}; /buckets nhận {name,slug,allow_public?}. Kích hoạt mặc định trước khi tạo thêm. PATCH /sites/RESOURCE_ID nhận {version,name?,spa_mode?}; /buckets/RESOURCE_ID nhận {version,name?,allow_public?,cors_origins?}. DELETE chỉ nhận tài nguyên bổ sung, xếp hàng dọn toàn bộ nội dung. Mã và địa chỉ không tái sử dụng.

GET /projects/ID/sites/identity?slug=portal trả {available,slug,hostname}. Hostname là duy nhất giữa Project, Hosting và Mini Server. Kiểm tra không giữ chỗ; POST không âm thầm đổi slug. Mã storage dành cho máy chủ tải file.

Truyền ?site_id=UUID cho deployments, activate, rollback, xóa deployment và mọi domains endpoint. Truyền ?bucket_id=UUID cho objects, metadata, signed-url, download và xóa file. Bỏ tham số dùng tài nguyên mặc định, không trả gộp mọi tài nguyên. ID không thuộc Project bị từ chối.

Vượt số lượng: tạo trả 409 resource_limit; ghi/serving bị khóa trả resource_plan_locked hoặc không tìm thấy ở hostname website. Danh sách metadata vẫn dùng đúng quyền quản lý. Khi tài nguyên bị khóa, chỉ phiên đăng nhập của chủ tài khoản được xuất hoặc xóa để dọn dữ liệu; API key và phiên quản trị nền tảng không được dùng để xóa tài nguyên bị khóa. Dung lượng account dùng chung, không nhân theo resource.

Xuất dữ liệu khi bị khóa chỉ dành cho phiên chủ tài khoản: GET /api/v1/seller/cloud/projects/ID/deployments/DEPLOYMENT_ID/export?site_id=UUID trả ZIP; GET /objects/OBJECT_ID/download?bucket_id=UUID trả URL xuất ký 5 phút. API key và phiên staff không có quyền xuất vượt khóa.

```
// API quản lý phía server; KEY không đưa vào frontend
const base = `https://app.whypik.com/api/v1/cloud/projects/${projectUuid}`;
const headers = {Authorization: `Bearer ${process.env.WHYPIK_CLOUD_KEY}`};
const {resources: buckets} = await (await fetch(`${base}/buckets`, {headers})).json();
const bucket = buckets.find(x => x.is_default);
const files = await (await fetch(`${base}/objects?bucket_id=${bucket.id}`, {headers})).json();
```


## Endpoint theo nhóm

Liên kết mục: https://whypik.com/docs/cloud-api#section-7

| Endpoint sau /api/v1/cloud | Method và công dụng |
| --- | --- |
| /usage | GET: tổng số dự án và dung lượng/quota riêng từng dịch vụ |
| /projects | GET danh sách; POST {name,slug,default_language?,timezone?,country_code?,province_code?} tạo Project |
| /projects/ID | GET chi tiết; PATCH cài đặt/kích hoạt dịch vụ; DELETE xếp hàng xóa |
| /projects/ID/deployments | GET lịch sử; POST đặt trước lượt upload ZIP |
| /projects/ID/uploads/UPLOAD_ID | PUT bytes file; GET tiến độ; DELETE hủy lượt upload |
| /projects/ID/deployments/DEPLOYMENT_ID/activate hoặc /rollback | POST kích hoạt bản đã sẵn sàng |
| /projects/ID/deployments/DEPLOYMENT_ID | GET {deployment,active}; DELETE bản cũ được phép xóa |
| /projects/ID/objects | GET danh sách; POST đặt trước lượt upload file |
| /projects/ID/objects/OBJECT_ID | GET metadata; PATCH thuộc tính; DELETE file |
| /projects/ID/objects/OBJECT_ID/signed-url | POST {expires:300} → {url,expires_at} |
| /projects/ID/objects/OBJECT_ID/download | GET → URL tải ngắn hạn; không trả bytes trực tiếp |
| /projects/ID/domains | GET danh sách; POST {hostname} thêm domain |
| /projects/ID/domains/DOMAIN_ID/verify | POST yêu cầu kiểm tra DNS |
| /projects/ID/domains/DOMAIN_ID | DELETE gỡ domain |
| /jobs /audit | GET tiến độ công việc / lịch sử theo scope |


## Danh tính và tùy chọn dự án

Liên kết mục: https://whypik.com/docs/cloud-api#section-8

POST /projects nhận default_language là vi hoặc en (mặc định vi); timezone là Asia/Ho_Chi_Minh, Asia/Bangkok, Asia/Taipei hoặc UTC (mặc định Asia/Ho_Chi_Minh). Đây là tùy chọn ngôn ngữ mặc định cho cửa hàng mới và hiển thị thời gian tổng quan, không phải vùng lưu dữ liệu. Không gửi region để chọn máy chủ.

Khu vực hoạt động: country_code dùng ISO 3166-1 alpha-2 (VN, SG, US…); province_code là chuỗi mã hành chính Việt Nam 2 chữ số, giữ số 0 đầu (ví dụ Hà Nội: 01). GET base Cloud trả project_locations gồm countries và vietnam_provinces. POST /projects với country_code=VN bắt buộc province_code hiện hành; ngoài VN, province_code phải rỗng. Client cũ bỏ cả hai trường vẫn được chấp nhận với vị trí chưa thiết lập. GET/list/detail trả hai trường này; PATCH /projects/ID gửi {version,country_code,province_code} cần projects:write, đúng account/project. Khi đổi VN sang quốc gia khác, gửi province_code rỗng cùng request. Đây là metadata hoạt động, không phải region hạ tầng.

GET /projects/identity?slug=spa cần projects:write ở cấp tài khoản, trả {available,slug,default_hostname}. available=true nếu mã chuẩn hóa còn dùng được; khi false, slug và default_hostname là cặp gợi ý khả dụng. Kiểm tra cả mã trong tài khoản và hostname toàn hệ thống, bao gồm dự án đã xóa. Endpoint không giữ chỗ và không tạo dự án.

POST /projects dùng chính xác slug đã chọn làm hostname_label. Nếu địa chỉ bị lấy sau khi kiểm tra, trả 409 hostname_unavailable; mã trùng trong tài khoản trả 409 project_slug_taken. Kiểm tra lại và yêu cầu người dùng xác nhận mã mới, không tự gửi lại bằng mã khác.

Response Project có id (UUID), slug (mã trong tài khoản), default_language, timezone, shop_id nullable và default_hostname nullable. default_hostname có thể được trả cả khi Hosting chưa bật; hostname chỉ có khi Hosting bật. Dự án cũ giữ nguyên mã và địa chỉ đã được cấp, kể cả trường hợp địa chỉ có hậu tố khác mã; luôn dùng default_hostname do API trả.

POST /api/v1/seller/shops cần phiên chủ tài khoản + CSRF, bắt buộc project_id (UUID), name, slug và default_language; template_id nhận một trong 10 ID do GET /api/v1/seller/shop-templates trả, mặc định standard; software được nhận như alias của standard. Project phải thuộc chủ tài khoản và đang active. Không dùng Cloud API key hoặc phiên staff. GET /api/v1/seller/shops trả project_id, account_id, template_id để nhóm cửa hàng theo dự án. Project.shop_id là liên kết cửa hàng chính tương thích cũ; shop_count là số cửa hàng từng gắn với dự án, kể cả đã đóng.

GET /api/v1/seller/shops/identity?project_id=UUID&slug=spa trả {available,slug,hostname}; kiểm tra cả ID và hostname toàn hệ thống, kể cả cửa hàng đã đóng. Endpoint không giữ chỗ. POST dùng đúng slug đã xác nhận, trả 409 slug_taken khi có xung đột; kiểm tra lại và để người dùng xác nhận, không tự gửi bằng ID mới. GET /api/v1/seller/shop-templates trả registry 10 mẫu miễn phí gồm id, name, description, pricing:{kind:free}, preview/catalog và preview_en/catalog_en. GET preview không ghi dữ liệu. Khi POST tạo cửa hàng, standard nhận nội dung khởi đầu nhưng không tạo Product/Plan; tám mẫu ngành mới nhận nội dung và danh mục theo content_language. Chi tiết tại API mẫu cửa hàng. ID mẫu không hỗ trợ bị từ chối.

Liên kết cửa hàng độc lập cũ dùng PATCH /api/v1/seller/cloud/projects/ID với {version,shop_id}, chỉ chấp nhận phiên chủ tài khoản + CSRF. Cửa hàng phải cùng tài khoản và chưa thuộc dự án khác; liên kết không thể tháo/đổi. Không cần thao tác này với cửa hàng mới.

DELETE /projects/ID đóng và dọn tất cả cửa hàng thuộc dự án; cửa hàng độc lập hoặc thuộc dự án khác được giữ. Theo dõi status và cleanup thay vì coi HTTP accepted là hoàn tất. Mã dự án, địa chỉ mặc định và địa chỉ cửa hàng đã đóng không tái sử dụng; tên miền riêng có thể thêm/xác minh lại sau khi gỡ xong. Giữ biên nhận tài chính/audit, không xóa tài khoản WhyPik.

PATCH /projects/ID nhận {version,name} để đổi tên hiển thị hoặc {version,timezone} để đổi múi giờ. timezone nhận Asia/Ho_Chi_Minh, Asia/Bangkok, Asia/Taipei hoặc UTC; giá trị khác trả invalid_project_preferences. Cần projects:write và quyền dự án; version cũ trả cloud_version_changed (409). Response {project} chứa metadata mới, version tăng 1; id, slug và default_hostname không đổi. Ví dụ: {"version":3,"name":"Website chính","timezone":"Asia/Ho_Chi_Minh"}.


## Sử dụng an toàn

Liên kết mục: https://whypik.com/docs/cloud-api#section-9

GET /usage trả usage.projects gồm used và limit cho toàn tài khoản, kể cả dự án chưa bật dịch vụ, tạm ngưng hoặc đang xóa. POST /projects trả 409 project_limit khi hết suất. Dự án đang xóa chỉ trả lại suất sau khi dọn xong. Hãy đọc lại usage khi gặp lỗi này; lọc danh sách không làm giảm số dự án đã dùng.

Hosting nhận ZIP đã build, chuẩn hóa application root; deployment versioned rồi mới kích hoạt. Storage phân quyền public/private, signed URL có thời hạn; kiểm tra quota và loại đối tượng trước khi upload. API không cấp quyền tùy ý với Project người khác.


## Phân biệt các API

Liên kết mục: https://whypik.com/docs/cloud-api#section-10

| Loại | Credential |
| --- | --- |
| Quản lý Project/Hosting/Storage/Database/Auth | wpc_ trên backend |
| Data API cho ứng dụng | wpk_public_ + user access token hoặc anonymous policy |
| Server Data API | wpk_secret_ + server policies |
| Project Auth BFF | wpk_bff_ tại backend + public Auth key |
| Licensing phần mềm | activation code / device token theo API version |


## Tải tiếp tục Hosting và Object Storage (chunks-v1)

Liên kết mục: https://whypik.com/docs/cloud-api#section-11

POST /projects/ID/deployments?site_id=UUID hoặc /projects/ID/objects?bucket_id=UUID: giữ các trường hiện có và thêm transport:"chunks-v1"; gửi Idempotency-Key UUID. Cần hosting:write hoặc objects:write. Upload trả transport, chunk_size (tối đa 8388608), chunk_count, sha256, parts:[{index,size,sha256}], expires_at. Không truyền transport vẫn dùng PUT nguyên file như trước; không trộn hai giao thức trong cùng lượt tải.

PUT /projects/ID/uploads/UPLOAD_ID/parts/INDEX gửi bytes nguyên phần, Content-Length chính xác và X-Chunk-SHA256 là SHA-256 hex chữ thường. INDEX bắt đầu 0; phần cuối có thể ngắn hơn chunk_size. Gửi lại cùng vị trí/nội dung là idempotent; nội dung khác trả 409 chunk_conflict. Phần lỗi hash/kích thước không làm mất các phần đã nhận. GET /projects/ID/uploads/UPLOAD_ID với quyền đọc tương ứng trả biên nhận bền để tiếp tục.

POST /projects/ID/uploads/UPLOAD_ID/complete trả 202 và upload.state; đây là tiếp nhận tác vụ nền, chưa phải thành công cuối cùng. Poll GET upload: receiving đang ghép/kiểm tra, queued là Hosting chờ xử lý ZIP, completed là hoàn tất nhận file; finish_state và finish_error phản ánh tác vụ ghép. Với Hosting, tiếp tục GET deployment và chỉ coi deploy thành công khi status=ready và active=true.

Sau lỗi mạng, giữ cùng UUID, file và các tùy chọn; gọi lại reservation để lấy parts hiện có. Complete có thể gửi lại; tác vụ đã hoàn tất không công bố lần thứ hai. Nếu finish_state=failed, xem finish_error rồi gọi lại Complete sau khi xử lý nguyên nhân. Khóa dùng đặt lượt tải phải còn hiệu lực khi tác vụ nền hoàn tất; thu hồi khóa không cho phép dùng một khóa khác để tiếp quản tác vụ đó. Chủ tài khoản có thể hủy và tạo lượt mới.

Thời hạn cố định 48 giờ từ reservation, không gia hạn khi thử lại; tối đa 4096 phần và vẫn theo hạn mức file/dung lượng hiện có. Trạng thái chưa hoàn tất giữ đúng một reservation logic; hết hạn không trả dung lượng cho tới khi dọn xác nhận. DELETE upload yêu cầu quyền ghi phù hợp. Khóa CI Hosting chỉ được PUT phần/POST Complete/GET upload của đúng website; luôn kèm ?site_id=UUID. Không dùng khóa quản trị trong mã frontend công khai.

Kho xử lý thiếu dung lượng hoặc đang có lần ghi chưa rõ kết quả có thể trả cloud_io_busy/cloud_io_settling hoặc chờ nền; thử lại cùng mã, không tạo hàng loạt reservation mới. Đây không phải S3 multipart URL trực tiếp; phần được xác thực qua API WhyPik. Các SDK Data không được bổ sung upload API mới trong thay đổi này.

```
# Cài requests; WHYPIK_CLOUD_KEY là biến môi trường chỉ ở backend.
python examples/cloud/resumable_upload.py \
  --project PROJECT_UUID --bucket BUCKET_UUID --file ./report.pdf \
  --path reports/report.pdf --idempotency-key REQUEST_UUID
# Khi mất mạng, chạy lại đúng lệnh, file và REQUEST_UUID.
```


## Đọc tiếp

- [Đưa website lên Static Hosting](https://whypik.com/docs/hosting)
- [Storage cửa hàng và Object Storage](https://whypik.com/docs/storage)
- [Auth SDK: đăng ký, phiên và khôi phục](https://whypik.com/docs/auth-reference)
- [REST quản lý Database và import](https://whypik.com/docs/management-api)
- [API mẫu cửa hàng và danh mục dịch vụ, sản phẩm](https://whypik.com/docs/store-template-api)
- [CI/CD với GitHub, GitLab và Bitbucket](https://whypik.com/docs/cicd)
- [Python SDK: license và cập nhật phần mềm](https://whypik.com/docs/python-sdk)
