Untuk developer. Panduan ini butuh sedikit pemrograman. Kalau Anda hanya memakai console, mulai dari App Hosting: Online-kan Aplikasi Pertama Anda.
Panduan ini membawa Anda dari nol sampai aplikasi berjalan, hanya dengan HTTP request. Semua contoh memakai https://pfnapp.id. Daftar lengkap endpoint ada di API Reference.
Perhatian: langkah 4 memotong saldo organisasi Anda dengan uang sungguhan. Cek harga dan saldo dulu (langkah 2 dan 3).
flowchart LR A[1. Buat API key] --> B[2. Cek saldo] B --> C[3. Pilih plan dan template] C --> D[4. Kirim pesanan] D --> E[5. Pantau status] E --> F[6. Batalkan bila perlu]
1. Buat API key
- Buka Console > Kunci API (
/console/api-keys) dan klik Buat kunci API. - Isi Nama (misalnya
order-app-hosting), pilih produk App Hosting atau Semua produk, dan akses Tulis. - Klik Buat kunci, lalu salin kunci yang muncul. Kunci hanya ditampilkan sekali.



Aturan key:
- Akses Tulis diperlukan untuk memesan dan membatalkan. Akses Baca hanya bisa melihat data, dan mencoba memesan dengan key Baca menghasilkan
403 API_KEY_ACCESS_NOT_ALLOWED. - Hanya Owner organisasi yang bisa membuat key Tulis.
- Key produk lain (misalnya WhatsApp) ditolak dengan
403 API_KEY_PRODUCT_NOT_ALLOWED.
Simpan key di variabel lingkungan, jangan di kode atau repositori:
export PFN_API_KEY="app_live_..."
Semua request berikutnya memakai header Authorization: Bearer $PFN_API_KEY.
2. Cek saldo
curl -s https://pfnapp.id/api/billing/account \
-H "Authorization: Bearer $PFN_API_KEY"
Respons:
{ "ok": true, "currency": "IDR", "balance": "7107659.35" }
Bila saldo kurang saat memesan, API menjawab 402 INSUFFICIENT_BALANCE beserta topupUrl, dan tidak ada yang dibuat.
3. Pilih plan, region, dan template
Harga dan plan
curl -s https://pfnapp.id/api/billing/catalog \
-H "Authorization: Bearer $PFN_API_KEY"
Cari produk dengan code APP_HOSTING. Dari sana ambil dua hal:
plans[].id, untukresourcePlanId. Perhatikan jugaplans[].resources.provisioning.storage(GB), karena sebagian template butuh ruang minimum.plans[].offers[].regionId, untukregionId. Tiap offer juga memuatbillingPerioddanperiodPrice.
Ringkasan bentuk respons (dipotong):
Template
curl -s https://pfnapp.id/api/templates \
-H "Authorization: Bearer $PFN_API_KEY"
Endpoint ini mengembalikan array polos (tanpa ok). Gunakan slug template sebagai templateId, misalnya 9router.
Plan terlalu kecil untuk template menghasilkan
422 INSUFFICIENT_PLAN_STORAGEdan tidak ada biaya. Template9routerbutuh 10 GB, jadi plan 5 GB (Small, Starter) ditolak dan plan Pro ke atas diterima.
4. Kirim pesanan
Endpoint: POST /api/deploy/submit. Header Idempotency-Key wajib untuk API key. Buat satu nilai unik per pesanan, misalnya UUID.
cURL
Node.js / TypeScript
Isi body
| Field | Keterangan |
|---|---|
sourceType | TEMPLATE, MANAGED_TEMPLATE, atau PUBLIC. GITHUB ditolak dengan 422 SOURCE_TYPE_NOT_ALLOWED_FOR_KEY. |
templateId | slug dari GET /api/templates. |
name | Nama aplikasi. |
resourcePlanId | plans[].id dari katalog. |
billingPeriod, periodMonths | Misalnya MONTHLY dan 1. |
regionId | offers[].regionId dari katalog. |
Mode tagihan ditentukan server dari katalog, jadi billingMode yang Anda kirim diabaikan.
Respons sukses
Saldo dipotong dan deployment pertama langsung berjalan.
5. Idempotency: aman untuk retry
| Situasi | Hasil |
|---|---|
Request sama dengan Idempotency-Key sama | Jawaban pertama dikembalikan, dengan header Idempotent-Replayed: true. Tidak memesan dua kali. |
Idempotency-Key sama dengan body berbeda | 422 IDEMPOTENCY_KEY_REUSED |
| Request pertama masih berjalan | 409 IDEMPOTENCY_IN_PROGRESS |
| Pesanan gagal | Key dibebaskan, Anda boleh mengulang dengan key yang sama |
Key disimpan 24 jam. Jika koneksi putus setelah mengirim pesanan, kirim ulang request yang sama persis dengan Idempotency-Key yang sama. Jangan membuat key baru, karena itu akan memesan lagi.
6. Pantau status
curl -s https://pfnapp.id/api/deploy/apps/app-saya \
-H "Authorization: Bearer $PFN_API_KEY"
Respons memuat data.stack (status aplikasi, resourcePlanId, subdomain) dan data.latestDeployment (status deployment terbaru). Ulangi sampai status menjadi running.
Aplikasi yang sama juga muncul di console:

7. Batalkan
curl -X POST "https://pfnapp.id/api/deploy/apps/app-saya/cancel" \
-H "Authorization: Bearer $PFN_API_KEY" \
-H "Content-Type: application/json"
Tidak perlu body. Pembatalan dijadwalkan di akhir periode berjalan. Aplikasi tetap aktif sampai tanggal itu, lalu semua resource-nya dihapus permanen, dan tidak ada refund. Ekspor data penting sebelum tanggal itu.
8. Biaya periode pertama
Periode pertama dihitung prorata sampai akhir bulan. Contoh dari uji coba: plan Pro dengan harga bulanan Rp75.000 yang dipesan pada tanggal 16 (16 dari 31 hari) ditagih Rp38.709,68. Setelah itu penagihan mengikuti periode yang Anda pilih.
9. Daftar error
| Status | Kode | Artinya |
|---|---|---|
| 400 | IDEMPOTENCY_KEY_REQUIRED, IDEMPOTENCY_KEY_INVALID, atau PARSE_ERROR | Header Idempotency-Key tidak ada atau formatnya salah, atau JSON rusak. |
| 401 | UNAUTHORIZED | Key tidak ada, salah, atau sudah dicabut. |
| 402 | INSUFFICIENT_BALANCE | Saldo kurang. Buka topupUrl dari respons. |
| 403 | API_KEY_PRODUCT_NOT_ALLOWED | Key milik produk lain (misalnya VPN-only atau WhatsApp), bukan App Hosting. |
| 403 | API_KEY_ACCESS_NOT_ALLOWED | Key akses Baca dipakai untuk memesan atau membatalkan. |
| 409 | IDEMPOTENCY_IN_PROGRESS | Request dengan key yang sama masih diproses. |
| 422 | IDEMPOTENCY_KEY_REUSED | Key yang sama dipakai dengan body berbeda. |
| 422 | SOURCE_TYPE_NOT_ALLOWED_FOR_KEY | GITHUB tidak boleh lewat API key. |
| 422 | INSUFFICIENT_PLAN_STORAGE | Plan terlalu kecil untuk template. |
| 429 | RATE_LIMITED | Maksimal 60 request per menit per key. |
10. Praktik aman
- Simpan key di secret manager atau variabel lingkungan, bukan di kode.
- Pakai key Baca untuk dashboard atau monitoring, dan key Tulis hanya untuk proses yang memesan.
- Buat
Idempotency-Keybaru untuk setiap pesanan, dan pakai ulang hanya saat me-retry pesanan yang sama. - Cabut key yang tidak dipakai di Console > Kunci API. Panggilan dengan key yang dicabut langsung menjawab
401.