WLJ Cloud Reseller API

Dokumentasi lengkap untuk integrasi dengan API ACBC Cloud

Perkenalan

Selamat datang di dokumentasi API ACBC Cloud. API ini memungkinkan Anda untuk mengelola server, membuat order, mengontrol VM, dan melakukan berbagai operasi lainnya secara programatik.

Base URL:
https://pre-production.wlj-cloud.id/v1

Semua endpoint API menggunakan format JSON untuk request dan response.

Autentikasi

API ACBC Cloud menggunakan Bearer Token authentication. Anda harus menyertakan API key Anda di header Authorization untuk setiap request.

Cara Mendapatkan API Key

  1. Login ke dashboard ACBC Cloud
  2. Buka halaman Profile/Settings
  3. Generate API key baru di bagian "API Access"
  4. Simpan API key dengan aman - tidak akan ditampilkan lagi
Header
Authorization: Bearer wlj_live_your_api_key_here

Contoh Request dengan cURL:

bash
curl -X GET "https://pre-production.wlj-cloud.id/v1/account/info" \
  -H "Authorization: Bearer wlj_live_your_api_key_here"
Keamanan: Jangan pernah membagikan API key Anda atau menyimpannya di repository publik. Gunakan environment variables untuk menyimpan API key.

Error Handling

API menggunakan HTTP status codes standar dan mengembalikan error dalam format JSON yang konsisten:

json
{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Deskripsi error yang mudah dipahami"
  }
}

HTTP Status Codes

Status Code Arti Deskripsi
200 OK Request berhasil diproses
201 Created Resource berhasil dibuat
400 Bad Request Request tidak valid atau parameter salah
401 Unauthorized API key tidak valid atau tidak ada
404 Not Found Resource tidak ditemukan

Error Codes Umum

Error Code Deskripsi
INVALID_API_KEY API key tidak valid atau sudah expired
INVALID_INPUT Parameter request tidak valid
INSUFFICIENT_BALANCE Saldo tidak cukup untuk melakukan transaksi
ORDER_NOT_FOUND Order dengan ID tersebut tidak ditemukan
PACKAGE_OUT_OF_STOCK Paket yang dipilih tidak tersedia
JOB_NOT_FOUND Job dengan ID tersebut tidak ditemukan

Rate Limiting

API menerapkan rate limiting untuk melindungi sistem dari penyalahgunaan. Informasi rate limit tersedia di response headers setiap request.

Rate Limit Headers

  • RateLimit-Limit: Jumlah maksimal request yang diizinkan per window
  • RateLimit-Remaining: Jumlah request yang tersisa dalam window saat ini
  • RateLimit-Reset: Waktu (dalam detik) hingga reset window
  • RateLimit-Policy: Kebijakan rate limit (format: limit;w=window_seconds)

Limit Per Endpoint

Kategori Endpoint Limit Window
General (Account, Orders, dll) 2000 requests 15 menit
Packages 500 requests 15 menit
Create Order 100 requests 1 jam
Perhatian: Jika Anda melampaui rate limit, API akan mengembalikan HTTP 429 (Too Many Requests). Tunggu hingga window reset sebelum melakukan request lagi.

Account - Info Akun

GET

Mendapatkan Informasi Akun

Endpoint ini mengembalikan informasi detail tentang akun reseller Anda.

https://pre-production.wlj-cloud.id/v1/account/info

Request

bash
curl -X GET "https://pre-production.wlj-cloud.id/v1/account/info" \
  -H "Authorization: Bearer wlj_live_your_api_key_here"

Response

json
{
  "success": true,
  "data": {
    "username": "testing_user",
    "email": "user@example.com",
    "balance": 9965996,
    "role": "reseller",
    "webhook_url": "http://localhost:3000",
    "whitelist_ips": "::1"
  }
}

Response Fields

Field Type Deskripsi
username string Username akun reseller
email string Email terdaftar
balance number Saldo akun dalam Rupiah
role string Role akun (reseller/admin)
webhook_url string URL webhook untuk notifikasi (jika ada)
whitelist_ips string IP whitelist untuk keamanan
json
{
  "success": false,
  "error": {
    "code": "INVALID_API_KEY",
    "message": "Invalid API key"
  }
}

Account - Transaksi

GET

Mendapatkan Daftar Transaksi

Endpoint ini mengembalikan riwayat transaksi akun dengan pagination.

https://pre-production.wlj-cloud.id/v1/account/transactions

Query Parameters

Parameter Type Required Deskripsi
limit number Optional Jumlah data per halaman (default: 10)
offset number Optional Offset data (default: 0)
type string Optional Filter tipe transaksi: order, renewal, deposit, refund

Request

bash
curl -X GET "https://pre-production.wlj-cloud.id/v1/account/transactions?limit=10&offset=0&type=order" \
  -H "Authorization: Bearer wlj_live_your_api_key_here"

Response

json
{
  "success": true,
  "data": [
    {
      "transaction_id": "7767a479-f7a1-4b52-8cad-23fd62db2068",
      "type": "order",
      "amount": 1,
      "description": "Order created: my-vps-server (monthly)",
      "orderid": "becb8fb1-edd2-4155-a244-1ce0c9443fd1",
      "status": "completed",
      "created_at": "2025-12-30T18:24:39.784Z"
    }
  ],
  "pagination": {
    "total": 5,
    "limit": 10,
    "offset": 0,
    "hasMore": false
  }
}

Servers - Daftar Server

GET

Mendapatkan Semua Server

Endpoint ini mengembalikan daftar semua server yang tersedia.

https://pre-production.wlj-cloud.id/v1/servers

Request

bash
curl -X GET "https://pre-production.wlj-cloud.id/v1/servers" \
  -H "Authorization: Bearer wlj_live_your_api_key_here"

Response

json
{
  "success": true,
  "data": [
    {
      "serverid": "jakarta-1",
      "server_name": "Jakarta DC1",
      "location": "Indonesia",
      "status": "active",
      "created_at": "2025-11-19T11:24:25.386Z"
    }
  ]
}

Servers - Template OS

GET

Mendapatkan Template OS

Endpoint ini mengembalikan daftar template OS yang tersedia untuk server tertentu.

https://pre-production.wlj-cloud.id/v1/servers/{serverid}/os-templates

Path Parameters

Parameter Type Required Deskripsi
serverid string Required ID server yang ingin dicek template OS-nya

Request

bash
curl -X GET "https://pre-production.wlj-cloud.id/v1/servers/jakarta-1/os-templates" \
  -H "Authorization: Bearer wlj_live_your_api_key_here"

Response

json
{
  "success": true,
  "data": [
    {
      "osid": "3cd7fdd4-802c-4af6-8efd-a8935d4a031f",
      "os_name": "Windows Server 2019",
      "type": "windows",
      "template_id": 9001,
      "created_at": "2025-11-22T02:49:24.335Z"
    },
    {
      "osid": "d2da8da1-0580-4939-8807-3a1fdfa95003",
      "os_name": "Ubuntu",
      "type": "linux",
      "template_id": 9000,
      "created_at": "2025-11-19T11:48:28.951Z"
    }
  ]
}
Tipe OS: windows, linux, windows_desktop, windows_desktop_custom

Packages - Daftar Paket

GET

Mendapatkan Semua Paket

Endpoint ini mengembalikan daftar semua paket VM yang tersedia.

https://pre-production.wlj-cloud.id/v1/packages

Query Parameters (Optional)

Parameter Type Deskripsi
serverid string Filter paket berdasarkan server tertentu
type string Filter paket berdasarkan tipe: linux atau windows

Request

bash
curl -X GET "https://pre-production.wlj-cloud.id/v1/packages?serverid=jakarta-1&type=linux" \
  -H "Authorization: Bearer wlj_live_your_api_key_here"

Response

json
{
  "success": true,
  "data": [
    {
      "package_id": "48d24c1f-1f03-49f5-90c3-c8138e5aa009",
      "name": "Si Mungil",
      "serverid": "jktcyber1",
      "server_name": "Jakarta DC1",
      "location": "Indonesia",
      "cpu": 1,
      "ram": 1024,
      "disk": "20G",
      "network_type": "nat",
      "enable_windows": false,
      "daily_price": null,
      "weekly_price": null,
      "monthly_price": 1,
      "stock": 4,
      "is_active": true
    }
  ]
}

Packages - Detail Paket

GET

Mendapatkan Detail Paket

Endpoint ini mengembalikan informasi detail tentang paket tertentu.

https://pre-production.wlj-cloud.id/v1/packages/{packageId}

Path Parameters

Parameter Type Required Deskripsi
packageId string (UUID) Required ID paket yang ingin dilihat detailnya

Request

bash
curl -X GET "https://pre-production.wlj-cloud.id/v1/packages/48d24c1f-1f03-49f5-90c3-c8138e5aa009" \
  -H "Authorization: Bearer wlj_live_your_api_key_here"

Response

json
{
  "success": true,
  "data": {
    "package_id": "48d24c1f-1f03-49f5-90c3-c8138e5aa009",
    "name": "Si Mungil",
    "serverid": "jktcyber1",
    "server_name": "Jakarta DC1",
    "location": "Indonesia",
    "server_status": "active",
    "cpu": 1,
    "ram": 1024,
    "disk": "20G",
    "network_type": "nat",
    "enable_windows": false,
    "enable_daily": false,
    "enable_weekly": false,
    "enable_monthly": true,
    "daily_price": null,
    "weekly_price": null,
    "monthly_price": 1,
    "stock": 4,
    "is_active": true,
    "created_at": "2025-11-28T14:44:35.915Z"
  }
}

Orders - Buat Order

POST

Membuat Order Baru

Endpoint ini digunakan untuk membuat order VM baru.

https://pre-production.wlj-cloud.id/v1/orders/create

Request Body

Field Type Required Deskripsi
vm_name string Required Nama VM yang akan dibuat
serverid string Required ID server tempat VM akan dibuat
osid string (UUID) Required ID template OS yang akan digunakan
package_id string (UUID) Required ID paket yang akan digunakan
billing_cycle string Required Siklus pembayaran: daily, weekly, atau monthly

Request

bash
curl -X POST "https://pre-production.wlj-cloud.id/v1/orders/create" \
  -H "Authorization: Bearer wlj_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "vm_name": "my-vps-server",
    "serverid": "jakarta-1",
    "osid": "3cd7fdd4-802c-4af6-8efd-a8935d4a031f",
    "package_id": "f1117f8f-85c3-49f7-8aa0-3b9b531788d0",
    "billing_cycle": "monthly"
  }'

Response

json
{
  "success": true,
  "data": {
    "orderid": "88b8ec89-560b-4bbc-baa9-f06b2944bb3b",
    "vm_name": "my-vps-server",
    "price": 70000,
    "status": "pending",
    "expired_at": "2026-02-01T06:45:17.612Z",
    "created_at": "2026-01-01T06:45:17.634Z"
  },
  "message": "Order created successfully"
}
json
{
  "success": false,
  "error": {
    "code": "INSUFFICIENT_BALANCE",
    "message": "Insufficient balance. Required: Rp 70.000, Available: Rp 0"
  }
}
json
{
  "success": false,
  "error": {
    "code": "PACKAGE_OUT_OF_STOCK",
    "message": "Selected package is out of stock"
  }
}

Orders - Daftar Order

GET

Mendapatkan Daftar Order

Endpoint ini mengembalikan daftar semua order dengan pagination.

https://pre-production.wlj-cloud.id/v1/orders

Query Parameters

Parameter Type Required Deskripsi
limit number Optional Jumlah data per halaman (default: 10)
offset number Optional Offset data (default: 0)
status string Optional Filter status: pending, active, suspended, expired, cancelled

Request

bash
curl -X GET "https://pre-production.wlj-cloud.id/v1/orders?limit=10&offset=0&status=active" \
  -H "Authorization: Bearer wlj_live_your_api_key_here"

Response

json
{
  "success": true,
  "data": [
    {
      "orderid": "674801fe-6b03-4a11-8e2f-e93e66a39b57",
      "vm_name": "my-vps-server1",
      "package_name": "Tes Package",
      "server_name": "Jakarta DC1",
      "os_name": "Windows Server 2019",
      "cpu": 2,
      "ram": 4096,
      "disk": "40G",
      "ipvm": "192.168.111.245",
      "network_type": "public_ip",
      "status": "active",
      "expired_at": "2026-02-01T07:09:55.386Z",
      "created_at": "2026-01-01T07:09:55.448Z"
    }
  ],
  "pagination": {
    "total": 3,
    "limit": 10,
    "offset": 0,
    "hasMore": false
  }
}

Orders - Detail Order

GET

Mendapatkan Detail Order

Endpoint ini mengembalikan informasi lengkap tentang order tertentu, termasuk credentials dan port forwarding (untuk NAT).

https://pre-production.wlj-cloud.id/v1/orders/{orderid}

Path Parameters

Parameter Type Required Deskripsi
orderid string (UUID) Required ID order yang ingin dilihat detailnya

Request

bash
curl -X GET "https://pre-production.wlj-cloud.id/v1/orders/674801fe-6b03-4a11-8e2f-e93e66a39b57" \
  -H "Authorization: Bearer wlj_live_your_api_key_here"

Response

json
{
  "success": true,
  "data": {
    "orderid": "674801fe-6b03-4a11-8e2f-e93e66a39b57",
    "vm_name": "my-vps-server1",
    "package_name": "Tes Package",
    "server_name": "Jakarta DC1",
    "location": "Indonesia",
    "os_name": "Windows Server 2019",
    "os_type": "windows",
    "cpu": 2,
    "ram": 4096,
    "disk": "40G",
    "ipvm": "192.168.111.245",
    "usernamevm": "admin/administrator",
    "passwordvm": "Tv8DevEg4lr2dkYW",
    "network_type": "public_ip",
    "status": "active",
    "expired_at": "2026-02-01T07:09:55.386Z",
    "created_at": "2026-01-01T07:09:55.448Z"
  }
}
json
{
  "success": true,
  "data": {
    "orderid": "becb8fb1-edd2-4155-a244-1ce0c9443fd1",
    "vm_name": "my-vps-server",
    "package_name": "Si Mungil",
    "server_name": "Jakarta DC1",
    "location": "Indonesia",
    "os_name": "Ubuntu",
    "os_type": "linux",
    "cpu": 1,
    "ram": 1024,
    "disk": "20G",
    "ipvm": null,
    "usernamevm": "debian/root",
    "passwordvm": "Au1OTqN3dnIa",
    "network_type": "nat",
    "status": "active",
    "expired_at": "2026-03-02T18:24:39.674Z",
    "created_at": "2025-12-30T18:24:39.696Z",
    "public_ip": "192.168.111.65",
    "private_ip": "10.10.10.14",
    "allocated_ports": [
      {
        "port_id": 19,
        "public_port": 50060,
        "private_port": 22,
        "protocol": "tcp",
        "description": "SSH",
        "is_used": true
      }
    ],
    "available_ports": [
      {
        "public_port": 50062,
        "is_used": false
      }
    ]
  }
}

Orders - Perpanjang Order

POST

Memperpanjang Order

Endpoint ini digunakan untuk memperpanjang masa aktif order.

https://pre-production.wlj-cloud.id/v1/orders/{orderid}/extend

Request Body

Field Type Required Deskripsi
billing_cycle string Required Durasi perpanjangan: daily, weekly, atau monthly

Request

bash
curl -X POST "https://pre-production.wlj-cloud.id/v1/orders/674801fe-6b03-4a11-8e2f-e93e66a39b57/extend" \
  -H "Authorization: Bearer wlj_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"billing_cycle": "monthly"}'

Response

json
{
  "success": true,
  "data": {
    "orderid": "674801fe-6b03-4a11-8e2f-e93e66a39b57",
    "new_expiry": "2026-03-01T07:09:55.386Z",
    "price_paid": 70000,
    "status": "active"
  },
  "message": "Order extended successfully"
}

Orders - Reinstall VM

POST

Reinstall Operating System

Endpoint ini digunakan untuk reinstall VM dengan OS yang berbeda. Proses ini akan menghapus semua data di VM.

https://pre-production.wlj-cloud.id/v1/orders/{orderid}/reinstall
Perhatian: Reinstall akan menghapus semua data di VM. Pastikan Anda telah melakukan backup terlebih dahulu.

Request Body

Field Type Required Deskripsi
osid string (UUID) Required ID template OS baru yang akan digunakan

Request

bash
curl -X POST "https://pre-production.wlj-cloud.id/v1/orders/674801fe-6b03-4a11-8e2f-e93e66a39b57/reinstall" \
  -H "Authorization: Bearer wlj_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"osid": "d7618e94-3ce1-4b8c-87c4-6708c2ef4b72"}'

Response

json
{
  "success": true,
  "data": {
    "jobId": "40b61076-9cfe-46b9-85aa-dab7c88efd13",
    "message": "VM reinstall has been queued. This may take a few minutes.",
    "new_os": "Windows 10 Pro"
  }
}
Catatan: Reinstall bersifat asynchronous. Gunakan endpoint Job Query untuk mengecek status proses reinstall.

VM Power - Start VM

POST

Menghidupkan VM

Endpoint ini digunakan untuk menghidupkan VM yang sedang mati.

https://pre-production.wlj-cloud.id/v1/orders/{orderid}/start

Request

bash
curl -X POST "https://pre-production.wlj-cloud.id/v1/orders/674801fe-6b03-4a11-8e2f-e93e66a39b57/start" \
  -H "Authorization: Bearer wlj_live_your_api_key_here"

Response

json
{
  "success": true,
  "data": {
    "jobId": "23db2133-13f8-4a40-9262-9fdba4e0c1d6",
    "message": "VM start action has been queued successfully"
  }
}

VM Power - Stop VM

POST

Mematikan VM (Force)

Endpoint ini melakukan hard stop pada VM (sama seperti mencabut kabel power).

https://pre-production.wlj-cloud.id/v1/orders/{orderid}/stop

Request

bash
curl -X POST "https://pre-production.wlj-cloud.id/v1/orders/674801fe-6b03-4a11-8e2f-e93e66a39b57/stop" \
  -H "Authorization: Bearer wlj_live_your_api_key_here"

Response

json
{
  "success": true,
  "data": {
    "jobId": "10211c58-339a-475a-87f5-59c52add402a",
    "message": "VM stop action has been queued successfully"
  }
}

VM Power - Restart VM

POST

Restart VM

Endpoint ini melakukan restart pada VM yang sedang berjalan.

https://pre-production.wlj-cloud.id/v1/orders/{orderid}/restart

Request

bash
curl -X POST "https://pre-production.wlj-cloud.id/v1/orders/674801fe-6b03-4a11-8e2f-e93e66a39b57/restart" \
  -H "Authorization: Bearer wlj_live_your_api_key_here"

Response

json
{
  "success": true,
  "data": {
    "jobId": "15f5b5bd-1d7c-473e-90e0-abae742b2f83",
    "message": "VM restart action has been queued successfully"
  }
}

VM Power - Shutdown VM

POST

Shutdown VM (Graceful)

Endpoint ini melakukan graceful shutdown pada VM (sistem operasi akan mematikan dengan benar).

https://pre-production.wlj-cloud.id/v1/orders/{orderid}/shutdown

Request

bash
curl -X POST "https://pre-production.wlj-cloud.id/v1/orders/674801fe-6b03-4a11-8e2f-e93e66a39b57/shutdown" \
  -H "Authorization: Bearer wlj_live_your_api_key_here"

Response

json
{
  "success": true,
  "data": {
    "jobId": "217c9d78-7a0a-4656-abec-3b3ef26ece09",
    "message": "VM shutdown action has been queued successfully"
  }
}

Port Forwarding - Tambah Port

POST

Menambahkan Port Forwarding

Endpoint ini digunakan untuk menambahkan rule port forwarding baru pada VM NAT.

https://pre-production.wlj-cloud.id/v1/orders/port-forward
Catatan: Endpoint ini hanya untuk VM dengan network_type "nat"

Request Body

Field Type Required Deskripsi
orderid string (UUID) Required ID order VM NAT
public_port number Required Port publik yang akan digunakan (dari available_ports)
private_port number Required Port di VM yang akan di-forward
protocol string Required Protokol: tcp atau udp
description string Optional Deskripsi port forwarding

Request

bash
curl -X POST "https://pre-production.wlj-cloud.id/v1/orders/port-forward" \
  -H "Authorization: Bearer wlj_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "orderid": "becb8fb1-edd2-4155-a244-1ce0c9443fd1",
    "public_port": 50062,
    "private_port": 80,
    "protocol": "tcp",
    "description": "Web Application"
  }'

Response

json
{
  "success": true,
  "data": {
    "id": 22,
    "jobId": "c4678292-3bad-4921-8304-4dc2aad01f76",
    "public_port": 50062,
    "private_port": 80,
    "protocol": "tcp",
    "message": "Port forward has been queued successfully"
  }
}

Port Forwarding - Daftar Port

GET

Mendapatkan Daftar Port Forwarding

Endpoint ini mengembalikan semua rule port forwarding yang sudah dikonfigurasi pada VM NAT.

https://pre-production.wlj-cloud.id/v1/orders/{orderid}/port-forwards

Request

bash
curl -X GET "https://pre-production.wlj-cloud.id/v1/orders/becb8fb1-edd2-4155-a244-1ce0c9443fd1/port-forwards" \
  -H "Authorization: Bearer wlj_live_your_api_key_here"

Response

json
{
  "success": true,
  "data": [
    {
      "id": 19,
      "public_port": 50060,
      "private_port": 22,
      "protocol": "tcp",
      "description": "SSH",
      "created_at": "2025-12-30T18:25:12.650Z"
    },
    {
      "id": 20,
      "public_port": 50061,
      "private_port": 80,
      "protocol": "tcp",
      "description": "Web Server",
      "created_at": "2025-12-30T18:37:09.851Z"
    }
  ]
}

Port Forwarding - Edit Port

PUT

Mengubah Port Forwarding

Endpoint ini digunakan untuk mengubah konfigurasi port forwarding yang sudah ada.

https://pre-production.wlj-cloud.id/v1/orders/port-forward/{portForwardId}

Request Body

Field Type Required Deskripsi
public_port number Optional Port publik baru (dari available_ports)
private_port number Optional Port private baru di VM
protocol string Optional Protokol: tcp atau udp
description string Optional Deskripsi baru

Request

bash
curl -X PUT "https://pre-production.wlj-cloud.id/v1/orders/port-forward/21" \
  -H "Authorization: Bearer wlj_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "private_port": 8080,
    "description": "Updated Web Application"
  }'

Response

json
{
  "success": true,
  "data": {
    "jobId": "03f798e5-e4fd-4173-8308-1b84decce15c",
    "message": "Port forward update has been queued successfully",
    "portForward": {
      "id": 21,
      "public_port": 50069,
      "private_port": 8080,
      "protocol": "tcp",
      "description": "Updated Web Application"
    }
  }
}

Job Status - Cek Status Job

GET

Mengecek Status Job

Endpoint ini digunakan untuk mengecek status dari operasi asynchronous (reinstall, VM power actions, port forwarding).

https://pre-production.wlj-cloud.id/v1/job/{jobid}

Path Parameters

Parameter Type Required Deskripsi
jobid string (UUID) Required ID job yang ingin dicek statusnya

Request

bash
curl -X GET "https://pre-production.wlj-cloud.id/v1/job/40b61076-9cfe-46b9-85aa-dab7c88efd13" \
  -H "Authorization: Bearer wlj_live_your_api_key_here"

Response

json
{
  "success": true,
  "data": {
    "jobid": "40b61076-9cfe-46b9-85aa-dab7c88efd13",
    "orderid": "674801fe-6b03-4a11-8e2f-e93e66a39b57",
    "vm_name": "my-vps-server1",
    "action": "reinstall",
    "status": "completed",
    "payload": {
      "osid": "d7618e94-3ce1-4b8c-87c4-6708c2ef4b72",
      "os_name": "Windows 10 Pro",
      "old_osid": "3cd7fdd4-802c-4af6-8efd-a8935d4a031f",
      "old_os_name": "Windows Server 2019"
    },
    "note": null,
    "created_at": "2026-01-01T07:35:54.875Z",
    "updated_at": "2026-01-01T07:36:28.553Z"
  }
}

Job Status Values

Status Deskripsi
pending Job sedang dalam antrian
processing Job sedang diproses
completed Job selesai dengan sukses
failed Job gagal diproses

Console - VNC Access

Sistem console kami mendukung dua metode akses VNC untuk memberikan fleksibilitas maksimal kepada reseller.

Metode Akses Console

Penting: Ticket console bersifat one-time use only dan akan expired setelah digunakan atau dalam waktu tertentu.

1. HTTP Method (Direct Access)

Metode ini memberikan akses langsung ke server console kami. URL yang digenerate akan membawa user langsung ke console interface yang di-host di server kami. Cocok untuk reseller yang ingin memberikan akses console cepat tanpa setup tambahan.

Use Case: Redirect user langsung ke console web kami. Tidak perlu setup server atau implementasi WebSocket di sisi reseller.

2. WebSocket Method (VNC Behind Proxy)

Metode ini memungkinkan reseller untuk membuat console interface sendiri dan menghubungkan ke server kami melalui WebSocket. Ticket yang digenerate berisi informasi WebSocket connection untuk terhubung ke VNC server.

Use Case: Untuk reseller yang ingin mengintegrasikan console ke dalam platform mereka sendiri dengan branding custom.

Alur Koneksi WebSocket (VNC Behind Proxy)

flow
Client Browser → Your Server → WSS Connection to Our Backend → WSS VNC to VM Server

1. Client membuka halaman console di website reseller
2. Reseller's server request ticket dengan method "websocket"
3. Reseller's frontend connect ke WSS endpoint kami menggunakan ticket
4. Backend kami meneruskan koneksi ke VNC server VM
5. Client dapat mengakses VM console melalui interface reseller
Catatan: Untuk metode WebSocket, reseller perlu mengimplementasikan VNC client di frontend mereka. Kami merekomendasikan menggunakan library noVNC.
POST

Membuat Ticket Console

Endpoint ini digunakan untuk membuat ticket console dengan metode HTTP atau WebSocket.

https://pre-production.wlj-cloud.id/v1/vnc/ticket/request

Request Body

Field Type Required Deskripsi
orderid string (UUID) Required UUID dari order yang ingin diakses console-nya
method string Optional Metode akses: "http" atau "websocket". Default: "http"

Request Example - HTTP Method

bash
curl -X POST "https://pre-production.wlj-cloud.id/v1/vnc/ticket/request" \
  -H "Authorization: Bearer wlj_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "orderid": "bea2eda4-f186-46f9-ab6a-7bb44727d48d",
    "method": "http"
  }'

Response - HTTP Method

json
{
  "success": true,
  "data": {
    "ticket": "d55d56d6-25a2-4c04-a16e-88df0055a881",
    "orderid": "bea2eda4-f186-46f9-ab6a-7bb44727d48d",
    "vm_name": "test-cross-os",
    "http_url": "https://id-jakarta-cy1-console-http.wlj-cloud.id/ticket/d55d56d6-25a2-4c04-a16e-88df0055a881"
  },
  "message": "VNC ticket generated successfully. This ticket is one-time use only."
}

Request Example - WebSocket Method

bash
curl -X POST "https://pre-production.wlj-cloud.id/v1/vnc/ticket/request" \
  -H "Authorization: Bearer wlj_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "orderid": "bea2eda4-f186-46f9-ab6a-7bb44727d48d",
    "method": "websocket"
  }'

Response - WebSocket Method

json
{
  "success": true,
  "data": {
    "ticket": "a8f3b2c1-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
    "orderid": "bea2eda4-f186-46f9-ab6a-7bb44727d48d",
    "vm_name": "test-cross-os",
    "websocket_url": "ws://id-jakarta-cy1-console-ws.wlj-cloud.id/vnc/ticket/d45419b0-7cb3-46d5-a636-c19c8c5b081a
  },
  "message": "VNC ticket generated successfully. This ticket is one-time use only."
}

Response Fields

Field Type Deskripsi
ticket string (UUID) Ticket ID untuk akses console (one-time use)
orderid string (UUID) Order ID yang terkait dengan console
vm_name string Nama VM
http_url string (HTTP Method) URL untuk akses console langsung
websocket_url string (WebSocket Method) WSS URL untuk koneksi VNC client

Implementasi WebSocket Client (noVNC)

javascript
import RFB from '@novnc/novnc/core/rfb.js';

// 1. Request ticket dari API
const response = await fetch('https://api.your-reseller.com/vnc/ticket', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    orderid: 'bea2eda4-f186-46f9-ab6a-7bb44727d48d',
    method: 'websocket'
  })
});

const { data } = await response.json();

// 2. Connect ke VNC menggunakan noVNC
const rfb = new RFB(
  document.getElementById('vnc-screen'),
  data.websocket_url,
  { credentials: { password: '' } }
);

// 3. Handle events
rfb.addEventListener('connect', () => {
  console.log('Connected to VNC');
});

rfb.addEventListener('disconnect', () => {
  console.log('Disconnected from VNC');
});

Webhooks

Webhook memungkinkan aplikasi Anda menerima notifikasi real-time ketika terjadi event tertentu di sistem kami. Anda dapat mengkonfigurasi webhook URL di halaman profile untuk menerima notifikasi otomatis.

Cara Kerja Webhook

  1. Konfigurasi webhook URL di halaman profile Anda
  2. Ketika event terjadi (VM created, status changed, dll), sistem akan mengirim POST request ke URL Anda
  3. Server Anda harus merespons dengan HTTP status 200 dalam waktu 10 detik
  4. Jika gagal, sistem akan melakukan retry hingga 3 kali dengan exponential backoff
Catatan: Webhook URL harus menggunakan HTTPS untuk keamanan. HTTP tidak didukung untuk production.

Webhook Request Format

Setiap webhook request akan dikirim sebagai POST request dengan format JSON:

json
{
  "event_type": "vm_created",
  "timestamp": "2026-02-14T03:38:57.076Z",
  "data": {
    // Event-specific data
  }
}

Available Events

Event Type Deskripsi
order_created Dipicu ketika order baru dibuat
vm_created Dipicu ketika VM berhasil dibuat dan siap digunakan
vm_status_changed Dipicu ketika status VM berubah
vm_started Dipicu ketika VM berhasil di-start
vm_stopped Dipicu ketika VM berhasil di-stop
vm_shutdown Dipicu ketika VM berhasil di-shutdown
vm_rebooted Dipicu ketika VM berhasil di-reboot
vm_suspended Dipicu ketika VM di-suspend (expired/nonaktif)
vm_unsuspended Dipicu ketika VM di-unsuspend (diaktifkan kembali)
vm_reinstalled Dipicu ketika VM berhasil di-reinstall dengan OS baru
vm_terminated Dipicu ketika VM dihapus/diterminasi
package_stock_updated Dipicu ketika stock package diupdate oleh admin
port_forward_created Dipicu ketika port forwarding baru dibuat
port_forward_edited Dipicu ketika port forwarding diedit
port_forward_deleted Dipicu ketika port forwarding dihapus

Event Payloads

vm_created

Event ini dipicu ketika VM berhasil dibuat dan siap digunakan. Payload berisi informasi lengkap VM termasuk credentials akses.

Payload Example - NAT VPS

json
{
  "event_type": "vm_created",
  "timestamp": "2026-02-14T03:38:57.076Z",
  "data": {
    "order_id": "bea2eda4-f186-46f9-ab6a-7bb44727d48d",
    "package_name": "Nat Base",
    "os": "Ubuntu",
    "cpu": 2,
    "ram": 4096,
    "disk": "50G",
    "ip_address": "192.168.111.65:50030",
    "username_vm": "ubuntu / root",
    "password": "ewQ3lZe7Hj9b",
    "expires_at": "2026-03-16T03:38:23.731Z",
    "allocated_ports": [
      "192.168.111.65:50030",
      "192.168.111.65:50031",
      "192.168.111.65:50032",
      "192.168.111.65:50033",
      "192.168.111.65:50034",
      "192.168.111.65:50035",
      "192.168.111.65:50036",
      "192.168.111.65:50037",
      "192.168.111.65:50038",
      "192.168.111.65:50039"
    ]
  }
}

Payload Example - Regular VPS

json
{
  "event_type": "vm_created",
  "timestamp": "2026-02-12T00:07:46.149Z",
  "data": {
    "order_id": "3bdf31b1-673b-4da1-ae1b-7902928eb9a6",
    "package_name": "VPS Basic",
    "os": "Ubuntu",
    "cpu": 1,
    "ram": 1024,
    "disk": "20G",
    "ip_address": "192.168.111.250",
    "username_vm": "ubuntu / root",
    "password": "qvEvsbC5Oj9c7yUo",
    "expires_at": "2026-03-14T00:05:21.128Z"
  }
}

Payload Fields

Field Type Deskripsi
order_id string (UUID) UUID order yang terkait dengan VM
package_name string Nama package yang digunakan
os string Nama OS yang diinstall
cpu number Jumlah CPU cores
ram number RAM dalam MB
disk string Ukuran disk (e.g., "20G", "50G")
ip_address string IP address VM (untuk NAT: IP:Port, untuk VPS: IP saja)
username_vm string Username untuk akses VM
password string Password untuk akses VM
expires_at string (ISO 8601) Tanggal expirasi VM
allocated_ports array (Hanya untuk NAT) Array port yang dialokasikan ke VM

order_created

Event ini dipicu ketika order baru dibuat. Payload berisi informasi lengkap order yang baru dibuat.

Payload Example

json
{
  "event": "order_created",
  "timestamp": "2026-02-11T10:54:02.459Z",
  "data": {
    "orderid": "96b1d5eb-c651-465a-ac9d-35b3e5efb45b",
    "vm_name": "my-vps-server1",
    "package_name": "Tes Package",
    "os_name": "Windows Server 2019",
    "cpu": 2,
    "ram": 4096,
    "disk": "40G",
    "network_type": "public_ip",
    "billing_cycle": "monthly",
    "price": 70000,
    "status": "pending",
    "created_at": "2026-02-11T10:54:02.023Z",
    "expired_at": "2026-03-11T10:54:01.956Z"
  }
}

Payload Fields

Field Type Deskripsi
orderid string (UUID) UUID order yang baru dibuat
vm_name string Nama VM yang dipilih user
package_name string Nama package yang dipesan
os_name string Nama OS yang dipilih
cpu number Jumlah CPU cores
ram number RAM dalam MB
disk string Ukuran disk (e.g., "40G", "50G")
network_type string Tipe network: "public_ip" atau "nat"
billing_cycle string Siklus billing: "daily", "weekly", atau "monthly"
price number Harga yang dibayar dalam rupiah
status string Status order: "pending" (VM sedang dibuat)
created_at string (ISO 8601) Tanggal order dibuat
expired_at string (ISO 8601) Tanggal expirasi order

vm_status_changed

Event ini dipicu ketika status VM berubah (running, stopped, dll).

Payload Example

json
{
  "event_type": "vm_status_changed",
  "timestamp": "2026-02-14T10:24:24.836Z",
  "data": {
    "order_id": "bea2eda4-f186-46f9-ab6a-7bb44727d48d",
    "vmid": 1000,
    "ip_address": "192.168.111.65:10",
    "old_status": "stopped",
    "new_status": "running"
  }
}

Payload Fields

Field Type Deskripsi
order_id string (UUID) UUID order yang terkait dengan VM
vmid number ID VM di server
ip_address string IP address VM (untuk NAT: IP:Port, untuk VPS: IP saja)
old_status string Status VM sebelumnya (e.g., "stopped", "running")
new_status string Status VM yang baru (e.g., "running", "stopped")
Catatan: Status VM yang mungkin: "running", "stopped", "paused"

vm_started

Event ini dipicu ketika VM berhasil di-start.

Payload Example

json
{
  "event_type": "vm_started",
  "timestamp": "2026-02-14T10:23:40.988Z",
  "data": {
    "order_id": "bea2eda4-f186-46f9-ab6a-7bb44727d48d",
    "vmid": 1000,
    "ip_address": "192.168.111.65:10",
    "status": "running"
  }
}

Payload Fields

Field Type Deskripsi
order_id string (UUID) UUID order yang terkait dengan VM
vmid number ID VM di server
ip_address string IP address VM (untuk NAT: IP:Port, untuk VPS: IP saja)
status string Status VM setelah start: "running"

vm_stopped

Event ini dipicu ketika VM berhasil di-stop (force stop / hard stop).

Payload Example

json
{
  "event_type": "vm_stopped",
  "timestamp": "2026-02-12T00:08:47.867Z",
  "data": {
    "order_id": "3bdf31b1-673b-4da1-ae1b-7902928eb9a6",
    "vmid": 1002,
    "ip_address": "192.168.111.250",
    "status": "stopped"
  }
}

Payload Fields

Field Type Deskripsi
order_id string (UUID) UUID order yang terkait dengan VM
vmid number ID VM di server
ip_address string IP address VM (untuk NAT: IP:Port, untuk VPS: IP saja)
status string Status VM setelah stop: "stopped"

vm_shutdown

Event ini dipicu ketika VM berhasil di-shutdown (graceful shutdown).

Payload Example

json
{
  "event_type": "vm_shutdown",
  "timestamp": "2026-02-12T00:08:47.867Z",
  "data": {
    "order_id": "3bdf31b1-673b-4da1-ae1b-7902928eb9a6",
    "vmid": 1002,
    "ip_address": "192.168.111.250",
    "status": "stopped"
  }
}

Payload Fields

Field Type Deskripsi
order_id string (UUID) UUID order yang terkait dengan VM
vmid number ID VM di server
ip_address string IP address VM (untuk NAT: IP:Port, untuk VPS: IP saja)
status string Status VM setelah shutdown: "stopped"

vm_rebooted

Event ini dipicu ketika VM berhasil di-reboot.

Payload Example

json
{
  "event_type": "vm_rebooted",
  "timestamp": "2026-02-12T00:08:47.867Z",
  "data": {
    "order_id": "3bdf31b1-673b-4da1-ae1b-7902928eb9a6",
    "vmid": 1002,
    "ip_address": "192.168.111.250",
    "status": "stopped"
  }
}

Payload Fields

Field Type Deskripsi
order_id string (UUID) UUID order yang terkait dengan VM
vmid number ID VM di server
ip_address string IP address VM (untuk NAT: IP:Port, untuk VPS: IP saja)
status string Status VM saat reboot dimulai (VM akan restart otomatis)
Catatan: Event ini dikirim ketika reboot dimulai. VM akan restart otomatis dan status akan menjadi "running" setelah reboot selesai.

vm_suspended

Event ini dipicu ketika VM di-suspend karena expired, abuse, atau alasan lainnya.

Payload Example

json
{
  "event_type": "vm_suspended",
  "timestamp": "2026-02-15T03:23:14.208Z",
  "data": {
    "order_id": "bea2eda4-f186-46f9-ab6a-7bb44727d48d",
    "vmid": 1000,
    "ip_address": "192.168.111.65:10",
    "status": "suspended",
    "note": "abuse test webhook"
  }
}

Payload Fields

Field Type Deskripsi
order_id string (UUID) UUID order yang terkait dengan VM
vmid number ID VM di server
ip_address string IP address VM (untuk NAT: IP:Port, untuk VPS: IP saja)
status string Status VM: "suspended"
note string Alasan VM di-suspend (e.g., "expired", "abuse", dll)
Penting: VM yang di-suspend tidak dapat diakses hingga di-unsuspend kembali.

vm_unsuspended

Event ini dipicu ketika VM di-unsuspend (diaktifkan kembali).

Payload Example

json
{
  "event_type": "vm_unsuspended",
  "timestamp": "2026-02-15T03:22:14.899Z",
  "data": {
    "order_id": "bea2eda4-f186-46f9-ab6a-7bb44727d48d",
    "vmid": 1000,
    "ip_address": "192.168.111.65:10",
    "status": "running"
  }
}

Payload Fields

Field Type Deskripsi
order_id string (UUID) UUID order yang terkait dengan VM
vmid number ID VM di server
ip_address string IP address VM (untuk NAT: IP:Port, untuk VPS: IP saja)
status string Status VM setelah unsuspend: "running"
Catatan: VM akan otomatis di-start setelah unsuspend dan status menjadi "running".

vm_reinstalled

Event ini dipicu ketika VM berhasil di-reinstall dengan OS baru. VM akan mendapatkan password baru.

Payload Example

json
{
  "event_type": "vm_reinstalled",
  "timestamp": "2026-02-15T03:36:38.039Z",
  "data": {
    "order_id": "37416e93-18c0-413b-be1e-2a6bd22d5fa1",
    "package_name": "Tes Package",
    "os": "Debian",
    "old_os": "Ubuntu",
    "new_os": "Debian",
    "old_os_type": "linux",
    "new_os_type": "linux",
    "cross_os_reinstall": false,
    "cpu": 2,
    "ram": 4096,
    "disk": "40G",
    "ip_address": "192.168.111.245",
    "username_vm": "root",
    "password": "Sd9dUJOgHBGE3Qbr",
    "expires_at": "2026-03-15T03:32:52.139Z"
  }
}

Payload Fields

Field Type Deskripsi
order_id string (UUID) UUID order yang terkait dengan VM
package_name string Nama package
os string Nama OS yang baru diinstall
old_os string Nama OS sebelumnya
new_os string Nama OS yang baru (sama dengan os)
old_os_type string Tipe OS lama: "linux" atau "windows"
new_os_type string Tipe OS baru: "linux" atau "windows"
cross_os_reinstall boolean Apakah reinstall lintas tipe OS (Linux ↔ Windows)
cpu number Jumlah CPU cores
ram number RAM dalam MB
disk string Ukuran disk
ip_address string IP address VM
username_vm string Username untuk akses VM
password string Password baru setelah reinstall
expires_at string (ISO 8601) Tanggal expirasi VM
Penting: Semua data di VM akan terhapus setelah reinstall. Password VM akan berubah.

vm_terminated

Event ini dipicu ketika VM dihapus/diterminasi secara permanen.

Payload Example

json
{
  "event_type": "vm_terminated",
  "timestamp": "2026-02-15T03:30:22.213Z",
  "data": {
    "order_id": "a48757f6-73ce-49fc-8f9f-e86e4b2117c3",
    "package_name": "Tes Package",
    "os": "Windows Server 2019",
    "cpu": 2,
    "ram": 4096,
    "disk": "40G",
    "ip_address": "192.168.111.251",
    "username_vm": "admin/administrator",
    "password": "Fm8VR8b003yND2KK",
    "expires_at": "2026-03-15T03:27:05.724Z",
    "note": "Hard abuse brute force detected"
  }
}

Payload Fields

Field Type Deskripsi
order_id string (UUID) UUID order yang terkait dengan VM
package_name string Nama package yang digunakan
os string Nama OS yang terinstall
cpu number Jumlah CPU cores
ram number RAM dalam MB
disk string Ukuran disk
ip_address string IP address VM yang diterminasi
username_vm string Username VM (untuk referensi)
password string Password VM (untuk referensi)
expires_at string (ISO 8601) Tanggal expirasi sebelum terminasi
note string Alasan terminasi (e.g., "expired", "abuse", dll)
Penting: VM yang diterminasi tidak dapat dipulihkan. Semua data akan hilang permanen.

package_stock_updated

Event ini dipicu ketika admin mengupdate stock package (set, add, atau subtract).

Payload Example

json
{
  "event_type": "package_stock_updated",
  "timestamp": "2026-02-15T03:43:22.099Z",
  "data": {
    "package_id": "58611adf-ff99-4c53-b07d-396257740e1a",
    "package_name": "test",
    "server_id": "axsazx1",
    "server_name": "asxax",
    "cpu": 1,
    "ram": 1024,
    "disk": "50G",
    "network_type": "public_ip",
    "daily_price": 1,
    "weekly_price": 1,
    "monthly_price": 1,
    "old_stock": 1,
    "new_stock": 5,
    "action": "set",
    "amount": 5,
    "is_active": true
  }
}

Payload Fields

Field Type Deskripsi
package_id string (UUID) UUID package yang diupdate
package_name string Nama package
server_id string ID server tempat package berada
server_name string Nama server
cpu number Jumlah CPU cores
ram number RAM dalam MB
disk string Ukuran disk
network_type string Tipe network: "public_ip" atau "nat"
daily_price number Harga daily (null jika tidak tersedia)
weekly_price number Harga weekly (null jika tidak tersedia)
monthly_price number Harga monthly (null jika tidak tersedia)
old_stock number Stock sebelum diupdate
new_stock number Stock setelah diupdate
action string Tipe aksi: "set", "add", atau "subtract"
amount number Jumlah perubahan stock
is_active boolean Status package (aktif/nonaktif)
Action types:
  • set: Set stock ke nilai tertentu
  • add: Tambah stock
  • subtract: Kurangi stock

port_forward_created

Event ini dipicu ketika port forwarding baru berhasil dibuat.

Payload Example

json
{
  "event_type": "port_forward_created",
  "timestamp": "2026-02-15T03:53:02.613Z",
  "data": {
    "order_id": "eb680f18-c9c8-4e25-a886-9a4cfc497489",
    "public_ip": "192.168.111.65",
    "private_ip": "10.10.10.21",
    "public_port": 50030,
    "private_port": 22,
    "protocol": "tcp"
  }
}

Payload Fields

Field Type Deskripsi
order_id string (UUID) UUID order yang terkait dengan VM
public_ip string IP public dari NAT
private_ip string IP private VM
public_port number Port public yang dialokasikan
private_port number Port VM yang di-forward
protocol string Protocol: "tcp" atau "udp"

port_forward_configured

Event ini dipicu ketika port forwarding berhasil dikonfigurasi di sistem.

Payload Example

json
{
  "event_type": "port_forward_configured",
  "timestamp": "2026-02-15T03:56:23.639Z",
  "data": {
    "order_id": "eb680f18-c9c8-4e25-a886-9a4cfc497489",
    "public_ip": "192.168.111.65",
    "private_ip": "10.10.10.21",
    "public_port": 50031,
    "private_port": 9999,
    "protocol": "tcp"
  }
}

Payload Fields

Field Type Deskripsi
order_id string (UUID) UUID order yang terkait dengan VM
public_ip string IP public dari NAT
private_ip string IP private VM
public_port number Port public yang dikonfigurasi
private_port number Port VM yang di-forward
protocol string Protocol: "tcp" atau "udp"
Catatan: Event ini dikirim setelah port forwarding berhasil dikonfigurasi di firewall/NAT.

port_forward_edited

Event ini dipicu ketika konfigurasi port forwarding berhasil diubah.

Payload Example

json
{
  "event_type": "port_forward_edited",
  "timestamp": "2026-02-15T03:57:44.436Z",
  "data": {
    "order_id": "eb680f18-c9c8-4e25-a886-9a4cfc497489",
    "port_forward_id": 36,
    "old_config": {
      "public_ip": "192.168.111.65",
      "private_ip": "10.10.10.21",
      "public_port": 50031,
      "private_port": 9999,
      "protocol": "tcp"
    },
    "new_config": {
      "public_ip": "192.168.111.65",
      "private_ip": "10.10.10.21",
      "public_port": 50031,
      "private_port": 1121,
      "protocol": "tcp"
    }
  }
}

Payload Fields

Field Type Deskripsi
order_id string (UUID) UUID order yang terkait dengan VM
port_forward_id number ID port forward rule yang diedit
old_config object Konfigurasi port forwarding sebelum diubah
old_config.public_ip string IP public lama
old_config.private_ip string IP private lama
old_config.public_port number Port public lama
old_config.private_port number Port private lama
old_config.protocol string Protocol lama
new_config object Konfigurasi port forwarding setelah diubah
new_config.public_ip string IP public baru
new_config.private_ip string IP private baru
new_config.public_port number Port public baru
new_config.private_port number Port private baru
new_config.protocol string Protocol baru
Catatan: Biasanya hanya private_port yang berubah karena public_port tidak bisa diubah setelah dibuat.

Webhook Headers

Setiap webhook request akan menyertakan header berikut:

Header Deskripsi
x-webhook-timestamp ISO 8601 timestamp ketika webhook dikirim (e.g., "2026-02-14T03:41:42.425Z")
x-webhook-signature HMAC-SHA256 signature untuk verifikasi authenticity webhook
user-agent User agent kami: "WLJ-Reseller-API/1.0"
content-type application/json

Webhook Signature Verification

Untuk memastikan webhook berasal dari server kami, Anda harus memverifikasi signature di header x-webhook-signature. Signature dibuat menggunakan HMAC-SHA256 dengan API key Anda sebagai secret.

Cara Verifikasi Signature

  1. Ambil signature dari header x-webhook-signature
  2. Gunakan API key Anda (bukan webhook secret) sebagai secret key
  3. Buat HMAC-SHA256 hash dari request body (raw JSON string) menggunakan API key Anda
  4. Bandingkan hash yang Anda buat dengan signature yang diterima menggunakan timing-safe comparison
Important: Gunakan API key Anda (format: wlj_live_xxx atau wlj_test_xxx) sebagai secret untuk verifikasi signature, bukan password atau webhook secret.

Example Signature Verification (Node.js)

javascript
const crypto = require('crypto');

// Your webhook endpoint
app.post('/webhook', (req, res) => {
  const payload = req.body;
  const receivedSignature = req.headers['x-webhook-signature'];
  const yourApiKey = 'wlj_abc123xyz'; // Your API key (secret)

  // Generate expected signature
  const expectedSignature = crypto
    .createHmac('sha256', yourApiKey)
    .update(JSON.stringify(payload))
    .digest('hex');

  // Compare signatures (timing-safe comparison)
  if (crypto.timingSafeEqual(
    Buffer.from(receivedSignature, 'hex'),
    Buffer.from(expectedSignature, 'hex')
  )) {
    // Signature valid - process webhook
    console.log('✅ Webhook verified:', payload);
    res.status(200).send('OK');
  } else {
    // Signature invalid - reject
    console.log('❌ Invalid signature');
    res.status(401).send('Invalid signature');
  }
});

Example Signature Verification (PHP)

php
<?php
// Your webhook endpoint
$yourApiKey = 'wlj_abc123xyz'; // Your API key (secret)

// Get headers
$receivedSignature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';

// Get raw POST body
$payload = file_get_contents('php://input');
$payloadData = json_decode($payload, true);

// Generate expected signature
$expectedSignature = hash_hmac('sha256', $payload, $yourApiKey);

// Compare signatures (timing-safe comparison)
if (hash_equals($expectedSignature, $receivedSignature)) {
    // Signature valid - process webhook
    error_log('✅ Webhook verified');
    http_response_code(200);
    echo 'OK';
    
    // Process your webhook here
    // $eventType = $payloadData['event_type'];
    // $data = $payloadData['data'];
} else {
    // Signature invalid - reject
    error_log('❌ Invalid signature');
    http_response_code(401);
    echo 'Invalid signature';
}
?>

Security Best Practices

1. Always Verify Signature

Selalu verifikasi x-webhook-signature untuk memastikan webhook berasal dari server kami. Jangan pernah proses webhook tanpa verifikasi signature.

2. Check Timestamp

Periksa x-webhook-timestamp untuk mencegah replay attacks. Tolak webhook yang timestampnya sudah terlalu lama (misalnya lebih dari 5 menit).

3. Use HTTPS

Selalu gunakan HTTPS untuk webhook URL Anda untuk mencegah man-in-the-middle attacks.

4. Implement Idempotency

Webhook mungkin dikirim lebih dari sekali. Implementasikan idempotency key (gunakan event_type + timestamp atau order_id) untuk mencegah duplikasi proses.

5. Fast Response

Respond dengan status 200 sesegera mungkin (dalam 10 detik). Lakukan proses yang kompleks secara asynchronous menggunakan queue atau background job.

6. Store Webhook Secret Securely

Simpan webhook secret di environment variable atau secret manager. Jangan hardcode di source code atau commit ke repository.

Example Complete Webhook Handler (Node.js/Express)

javascript
app.post('/webhook', express.json(), async (req, res) => {
  try {
    const { event_type, timestamp, data } = req.body;
    
    // Respond immediately
    res.status(200).json({ received: true });
    
    // Process webhook asynchronously
    processWebhook(event_type, data).catch(err => {
      console.error('Webhook processing error:', err);
    });
    
  } catch (error) {
    res.status(500).json({ error: 'Internal server error' });
  }
});

async function processWebhook(event_type, data) {
  switch (event_type) {
    case 'vm_created':
      // Handle VM creation
      await sendEmailToCustomer(data.order_id);
      break;
    case 'vm_suspended':
      // Handle VM suspension
      await notifyCustomer(data.order_id);
      break;
    // Handle other events...
  }
}