REST API
Konsol dibangun di atas REST API JSON di https://zenavo.app/api. Apa pun yang bisa Anda lakukan di konsol, bisa Anda lakukan dengan API ini.
Autentikasi
Kirim API key sebagai bearer token:
curl -H "Authorization: Bearer $ZENAVO_API_KEY" https://zenavo.app/api/auth/meIzin dan batas proyek kunci menentukan endpoint mana yang boleh dipanggilnya; yang lain menjawab 403. Tagihan, pembelian, keanggotaan tim, dan /api/account/* hanya untuk sesi browser.
Permintaan dari sesi browser juga memerlukan header X-Zenavo-Request: 1 pada apa pun selain GET; permintaan dengan bearer token tidak.
Permintaan hanya memerlukan sesi atau API key yang valid dengan peran yang sesuai; tidak ada aksi yang meminta konfirmasi kedua. Akun yang belum memverifikasi email mendapat 403 dengan {"email_unverified": true} untuk perubahan di luar akunnya sendiri.
Konvensi
- Body berupa JSON. Waktu dalam detik Unix.
- ID diberi prefiks:
team_,srv_,proj_,job_,bak_,tok_. - Error mengembalikan kode status dan
{"detail": …}. Error validasi (422) mencantumkan setiap field. - Operasi panjang (deploy, restart, backup) mengembalikan job:
{"id": "job_…"}. PollGET /api/jobs/{id}untukstatus(queued,running,succeeded,failed),log, danprogressper layanan.
Endpoint
Akun
| Metode | Path | |
|---|---|---|
GET | /api/auth/me | Pengguna yang sedang masuk, timnya, dan email_verified |
PATCH | /api/account | Nama dan avatar |
GET POST | /api/account/tokens | Daftar atau buat API key (hanya sesi browser). Buat dengan {name, days, scope, project_ids}: scope adalah read, deploy, atau full (bawaan); project_ids membatasi kunci ke proyek tersebut (hilangkan atau null untuk semua) |
DELETE | /api/account/tokens/{id} | Hapus API key |
GET | /api/account/sessions | Sesi yang sedang masuk |
POST | /api/auth/2fa | Langkah masuk kedua: {code} setelah /api/auth/login menjawab {two_factor: true} |
POST | /api/account/verify | Konfirmasi bahwa ini Anda: {code} dengan autentikasi dua faktor, selain itu {password}. Saat ini tidak ada aksi yang memerlukannya |
POST | /api/auth/verify-email | Buka tautan verifikasi email: {token} (berlaku sekali, selama 24 jam) |
POST | /api/account/email/verify | Kirim tautan verifikasi baru; {verified: true} bila alamat sudah terverifikasi |
GET | /api/account/2fa | Status dua faktor: enabled (aplikasi atau passkey), totp, kode pemulihan yang tersisa, jumlah passkey |
POST | /api/account/2fa/setup /enable /disable /recovery-codes | Kelola autentikasi dua faktor (hanya sesi browser) |
POST | /api/auth/2fa/passkey/options lalu /api/auth/2fa/passkey | Langkah masuk kedua dengan passkey: opsi permintaan WebAuthn ({options: null} tanpa passkey) dan apakah akun punya aplikasi autentikator (totp), lalu {credential} |
GET | /api/account/passkeys | Passkey Anda: nama, AAGUID, disinkronkan, dibuat, terakhir dipakai |
POST | /api/account/passkeys/options lalu /api/account/passkeys | Daftarkan passkey: opsi pembuatan, lalu {name, credential} (faktor kedua pertama akun juga mengembalikan recovery_codes) |
DELETE | /api/account/passkeys/{id} | Hapus passkey (menghapus faktor kedua terakhir mematikan autentikasi dua faktor) |
GET | /api/account/audit?before=&limit= | Aktivitas keamanan Anda sendiri |
POST | /api/auth/device/code | Mulai login CLI (device flow): {client_name, scope, client} → {device_code, user_code, verification_uri, expires_in, interval}. scope bawaannya full; client adalah cli (bawaan) atau mcp, dan menamai kunci "CLI on …" atau "MCP on …" |
POST | /api/auth/device/token | Poll dengan {device_code}: 202 selama menunggu, 429 bila di-poll lebih cepat dari interval, 200 {token, scope, project_ids} setelah disetujui (penyetuju mungkin mempersempit cakupannya) |
Tim
| Metode | Path | |
|---|---|---|
GET POST | /api/teams | Daftar atau buat tim |
PATCH | /api/teams/{tid} | Ganti nama |
GET | /api/teams/{tid}/members | Anggota |
PATCH DELETE | /api/teams/{tid}/members/{uid} | Ubah peran, hapus anggota |
GET POST | /api/teams/{tid}/invites | Undangan |
GET | /api/teams/{tid}/audit?before=&limit= | Log audit (admin) |
GET POST | /api/teams/{tid}/notification-channels | Channel notifikasi (admin). Buat dengan {kind, name, events, url} (Slack, Discord, webhook) atau {kind: "telegram", name, events, bot_token, chat_id}; secret webhook dikembalikan sekali |
PATCH DELETE | /api/teams/{tid}/notification-channels/{cid} | Ubah name, events, enabled, atau tujuan; hapus |
POST | /api/teams/{tid}/notification-channels/{cid}/test | Kirim pesan uji sekarang |
POST | /api/teams/{tid}/notification-channels/{cid}/secret | Signing secret baru untuk webhook (dikembalikan sekali) |
GET POST | /api/teams/{tid}/log-drains | Log drain (admin; membuat memerlukan paket Pro ke atas). Buat dengan {kind: "http", name, url}, {kind: "datadog", name, site, api_key}, atau {kind: "loki", name, url, username, password, tenant_id}, ditambah projects (kosong untuk semua); secret drain HTTP dikembalikan sekali |
PATCH DELETE | /api/teams/{tid}/log-drains/{did} | Ubah name, projects, enabled, atau tujuan; hapus |
POST | /api/teams/{tid}/log-drains/{did}/test | Kirim baris uji sekarang |
POST | /api/teams/{tid}/log-drains/{did}/secret | Signing secret baru untuk drain HTTP (dikembalikan sekali) |
Penggunaan dan tagihan
| Metode | Path | |
|---|---|---|
GET | /api/teams/{tid}/usage?period=YYYY-MM | Batas paket, server, anggota, menit build per proyek, layanan, dan hari |
GET | /api/teams/{tid}/usage/builds.csv?period= | Setiap build terukur dalam sebulan, sebagai CSV |
GET | /api/teams/{tid}/transfer | Transfer image periode ini: bytes, included_bytes, overage_cents, limit_cents, blocked, percent, serta awal dan akhir periode |
GET | /api/teams/{tid}/billing | Paket, status langganan, kursi, dan katalog paket (admin) |
GET | /api/teams/{tid}/billing/invoices | Faktur terbaru dengan tautan halaman Stripe dan PDF (admin) |
GET | /api/teams/{tid}/server-billing | Server yang dibeli beserta bulan yang sudah dibayar dan perpanjangan otomatisnya, dan tagihan server terbaru (admin) |
POST | /api/teams/{tid}/billing/checkout | Mulai langganan: {plan} → {url} Stripe Checkout (pemilik) |
POST | /api/teams/{tid}/billing/change | Ganti langganan ke paket lain: {plan} (pemilik) |
POST | /api/teams/{tid}/billing/cancel /resume | Batalkan di akhir periode, atau urungkan (pemilik) |
PUT | /api/teams/{tid}/billing/spend-limit | Atur batas pengeluaran: {cents}, 0 hingga 1.000.000 (pemilik) |
POST | /api/teams/{tid}/billing/portal | {url} Customer Portal Stripe untuk kartu, detail tagihan, dan faktur (pemilik) |
Server
| Metode | Path | |
|---|---|---|
GET | /api/servers?team_id= | Daftar server |
POST | /api/servers?team_id= | Tambahkan server: {name, host, port, user, password | private_key} |
GET PATCH | /api/servers/{sid} | Baca, ganti nama |
POST | /api/servers/{sid}/bootstrap | Jalankan penyiapan lagi: {password | private_key}, atau body kosong dalam sehari setelah penyiapan gagal untuk memakai lagi kredensial yang disimpan |
PATCH | /api/servers/{sid}/billing | Perpanjangan otomatis server yang dibeli: {auto_renew} (admin). GET /api/servers/{sid} menampilkannya di bought, dengan paid_until |
POST | /api/servers/{sid}/renew | Bayar bulan berikutnya server yang dibeli sekarang (admin) |
GET | /api/servers/{sid}/usage?hours= | Riwayat CPU, memori, dan disk |
GET | /api/servers/{sid}/system | Komponen platform |
GET | /api/servers/{sid}/ports | Pemeriksaan port |
GET | /api/servers/{sid}/jobs | Penyiapan dan job lainnya |
POST | /api/servers/{sid}/delete | Hapus: {confirmation: "<server name>"} |
POST | /api/servers/{sid}/reinstall | Copot K3s dan siapkan server dari awal: {confirmation: "<server name>", password | private_key} (admin; server tidak boleh punya proyek). Menjawab dengan server, yang penyiapannya masuk antrean |
POST | /api/servers/{sid}/reinstall-os | Pasang ulang sistem operasi server yang dibeli dan siapkan dari awal, tanpa kredensial SSH; kata sandi login baru dikirim ke email pemanggil: {confirmation: "<server name>"} (admin; server tidak boleh punya proyek, dan bought.reinstall_os-nya harus true). Menjawab dengan server, yang pemasangan ulangnya masuk antrean |
GET | /api/servers/{sid}/ssh-logins?hours=&failed= | Riwayat login SSH (member) |
POST | /api/servers/{sid}/agent | Pindahkan server yang ditambahkan sebelum ada agen ke agen (admin) |
POST | /api/servers/{sid}/agent/update | Perbarui agen (admin; mengembalikan job) |
GET | /api/servers/{sid}/firewall | Firewall server (member). Untuk server yang dibeli: aturan tetap Zenavo (web, HTTPS, ping, SSH untuk penyiapan) dan aturan tim, diterapkan di penyedia; untuk server yang Anda hubungkan: port yang perlu dibuka di sana |
POST | /api/servers/{sid}/firewall/rules | Tambahkan aturan izin ke server yang dibeli: {protocol, ports, sources, note}, dengan protocol tcp, udp, atau icmp, ports seperti 8080 atau 30000-30100, dan sources daftar alamat atau rentang CIDR (admin; hingga 30 aturan) |
PUT DELETE | /api/servers/{sid}/firewall/rules/{rid} | Ubah aturan (body yang sama) atau hapus (admin) |
POST | /api/servers/{sid}/firewall/apply | Terapkan lagi aturan di penyedia setelah gagal (admin) |
Proyek
| Metode | Path | |
|---|---|---|
GET | /api/projects?team_id= | Daftar proyek |
POST | /api/projects | Buat: {team_id, server_id, manifest} |
GET | /api/projects/{pid} | Ringkasan, layanan, dan status |
GET | /api/projects/{pid}/manifest | Konfigurasi lengkap, dengan variabel |
PUT | /api/projects/{pid} | Simpan konfigurasi: {manifest, server_id, revision} |
POST | /api/projects/{pid}/deploy | Deploy semua layanan (mengembalikan job) |
POST | /api/projects/{pid}/rollback | {target_job} |
POST | /api/projects/{pid}/services/{service}/rollback | {target_job}: kembalikan satu layanan ke deployment itu; yang lain tetap seperti yang ter-deploy (mengembalikan job) |
POST | /api/projects/{pid}/restart /stop | Restart atau hentikan semua layanan |
GET | /api/projects/{pid}/runtime | Status langsung setiap layanan |
POST | /api/projects/{pid}/clone /transfer | Kloning: {name, team_id, server_id}; atau pindahkan proyek yang belum pernah di-deploy ke tim lain: {team_id, server_id} (admin kedua tim) |
GET | /api/projects/{pid}/move | Pemindahan ke server lain terbaru |
GET | /api/projects/{pid}/move/preflight?server_id= | Periksa pemindahan tanpa mengubah apa pun (admin) |
POST | /api/projects/{pid}/move | Pindahkan, beserta datanya, ke server lain di tim: {server_id, confirmation: "<project name>"} (admin; mengembalikan job) |
POST | /api/projects/{pid}/move/finish /move/rollback | Hapus salinan lama, atau kembali ke server lama (admin; mengembalikan job) |
POST | /api/projects/{pid}/delete | {confirmation: "<project name>"} |
PUT | /api/projects/{pid}/checklist | Checklist migrasi: {source_backup, data_restored, application_verified, dns_switched, rollback_ready}, masing-masing true atau false (member) |
Layanan
{service} adalah ID layanan; nama saat ini juga bisa dipakai. Di konfigurasi proyek, setiap layanan punya id dan hostname opsional; hilangkan keduanya untuk layanan baru dan Zenavo memberinya id svc-… acak dan hostname yang dibuat dari namanya.
| Metode | Path | |
|---|---|---|
POST | /api/projects/{pid}/services/{service}/deploy | Deploy layanan ini saja; yang lain tetap seperti yang ter-deploy (mengembalikan job) |
PUT | /api/projects/{pid}/services/{service}/source?create=&port=&deploy=&acknowledge_init= | Unggah tar terkompresi gzip dari sebuah direktori (hingga 500 MB) sebagai sumber layanan dan deploy (mengembalikan {upload_id, service, created, job}); create=1 menambahkan layanan yang belum ada, deploy=0 hanya menyimpannya |
POST | /api/projects/{pid}/services/{service}/restart /suspend /resume | |
POST | /api/projects/{pid}/services/{service}/exec | Jalankan perintah di kontainer |
GET | /api/projects/{pid}/services/{service}/terminal | WebSocket: terminal interaktif (member). Frame biner membawa input dan output; frame teks membawa JSON: {"type":"resize","cols","rows"} dari klien, {"type":"exit","code"} atau {"type":"error","message"} dari server. Browser harus mengirim Origin konsol |
GET | /api/projects/{pid}/services/{service}/files?path= | Daftar isi folder di kontainer (member) |
GET | /api/projects/{pid}/services/{service}/files/content?path= | 256 KB pertama sebuah file, sebagai teks |
GET | /api/projects/{pid}/services/{service}/files/download?path= | Unduh file (hingga 500 MB) |
PUT | /api/projects/{pid}/services/{service}/files/upload?dir=&name= | Unggah body mentah (hingga 50 MB, Content-Length wajib); &overwrite=1 mengganti |
POST | /api/projects/{pid}/services/{service}/files/mkdir | Buat folder: {"path"} |
POST | /api/projects/{pid}/services/{service}/files/rename | Ganti nama di tempat: {"path", "name"} |
POST | /api/projects/{pid}/services/{service}/files/delete | Hapus file atau folder: {"path"} |
GET | /api/projects/{pid}/services/{service}/usage?hours= | Riwayat CPU dan memori |
GET | /api/projects/{pid}/logs/{service} | Log runtime terbaru |
GET | /api/projects/{pid}/logs/{service}/stream | Log runtime langsung (Server-Sent Events) |
GET | /api/projects/{pid}/logs/{service}/history?from=&to=&q=&cursor=&limit= | Log runtime tersimpan, dari yang terlama: baris yang berisi q (tanpa membedakan huruf besar-kecil) antara from dan to (RFC 3339 atau detik Unix; bawaannya satu jam terakhir). Kembalikan next sebagai cursor untuk mendapatkan lebih banyak |
GET | /api/projects/{pid}/logs/{service}/download?from=&to=&q= | Log runtime tersimpan dalam suatu rentang sebagai file teks |
POST | /api/projects/{pid}/services/{service}/domains | Buat domain otomatis |
DELETE | /api/projects/{pid}/domains/{domain} | Hapus domain otomatis |
Tampilan database
Tampilan database layanan database. Member boleh membaca; penulisan memerlukan admin tim. Setiap permintaan berjalan di dalam kontainer database dan dicatat di log audit tanpa SQL, kunci, nilai, atau dokumennya. … adalah /api/projects/{pid}/services/{service}.
| Metode | Path | |
|---|---|---|
GET | …/database/tables | PostgreSQL, MySQL, MariaDB: tabel dan view, dengan perkiraan baris dan kolom |
GET | …/database/rows?schema=&table=&offset=&limit= | Satu halaman baris tabel |
POST | …/database/query | Jalankan satu statement SQL: {sql, allow_writes, max_rows}. Read-only kecuali allow_writes (admin) |
POST | …/database/keys | Redis, Valkey: daftar kunci dengan SCAN: {db, match, cursor, count} |
POST | …/database/key | Nilai satu kunci: {db, key, cursor, count}, atau key_b64 untuk kunci yang bukan UTF-8 |
POST | …/database/command | Jalankan satu perintah: {db, command, allow_writes}. Hanya perintah baca kecuali allow_writes (admin) |
GET | …/database/collections | MongoDB: database dan koleksi, dengan perkiraan jumlah dokumen |
POST | …/database/find | Cari dokumen: {db, collection, filter, sort, projection, skip, limit}, semuanya string JSON; 50 per halaman secara bawaan |
POST | …/database/document | Ubah satu dokumen: {op, db, collection, filter, update, document}, dengan op insert, update, atau delete (admin) |
Backup
| Metode | Path | |
|---|---|---|
GET | /api/backups?project_id= | Daftar backup |
POST | /api/projects/{pid}/backups | Backup sebuah layanan: {service, engine} |
GET | /api/backups/{bid}/download | Unduh |
POST | /api/backups/{bid}/restore | Pulihkan: {confirmation}, seperti yang diketik di konsol |
Git dan GitHub
| Metode | Path | |
|---|---|---|
POST | /api/git/refs | Branch dan tag repositori publik: {url} |
POST | /api/git/plan | Pratinjau rencana build: {team_id, url, ref, context} |
GET | /api/github/repos?team_id= | Repositori yang bisa dibaca instalasi GitHub tim |
GET | /api/github/branches?team_id=&repo= | Branch salah satunya |
Image dan domain
| Metode | Path | |
|---|---|---|
GET | /api/images/ports?team_id=&image= | Port yang di-EXPOSE image publik, dibaca dari registry-nya tanpa menarik image |
GET | /api/images/mirror?image= | Apakah mirror Zenavo untuk Tiongkok daratan memiliki suatu image, dan alamatnya di sana |
GET | /api/images/mirror/search?q= | Image di mirror yang namanya mengandung q |
GET | /api/domains/available?name= | Apakah nama domain otomatis masih tersedia: {available, reason} |
Template
| Metode | Path | |
|---|---|---|
GET | /api/templates | Galeri template (publik, tanpa kunci) |
GET | /api/templates/{code} | Satu template dan manifest-nya (publik) |
POST | /api/imports/preview | Periksa template Zeabur atau ekspor Zenavo: {text, team_id, variables}, atau template galeri: {template, team_id, variables} |
POST | /api/imports/{did}/commit | Buat proyek: {server_id} |
Contoh: deploy lalu tunggu
JOB=$(curl -s -X POST -H "Authorization: Bearer $ZENAVO_API_KEY" \
-H "Content-Type: application/json" -d '{}' \
https://zenavo.app/api/projects/$PROJECT/deploy | jq -r .id)
until curl -s -H "Authorization: Bearer $ZENAVO_API_KEY" https://zenavo.app/api/jobs/$JOB \
| jq -e '.status == "succeeded" or .status == "failed"' >/dev/null; do sleep 5; done