Dokumentasi API RubrikPulsa

Panduan untuk Mengintegrasikan API ke Aplikasi Android (VPS: 149.129.241.211)

Persiapan Server

API RubrikPulsa dijalankan di VPS Alibaba Cloud dengan IP publik 149.129.241.211. Ikuti langkah berikut untuk menyiapkan server:

1. Prasyarat

2. Instalasi Dependensi

Masuk ke VPS dan instal dependensi:

ssh user@149.129.241.211
cd /home/user/rubrikpulsa-api
pip3 install fastapi uvicorn python-jose[cryptography] pydantic bcrypt psycopg2-binary python-telegram-bot requests tenacity python-dotenv

3. Konfigurasi Lingkungan

Buat file .env di /home/user/rubrikpulsa-api:

TELEGRAM_BOT_TOKEN=your_bot_token
POSTGRES_DB=rubrikpulsa
POSTGRES_USER=your_user
POSTGRES_PASSWORD=your_password
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
API_SECRET_KEY=your_secret_key
OWNER_USER_ID=your_owner_user_id
DIGIFLAZZ_USERNAME=your_digiflazz_username
DIGIFLAZZ_API_KEY=your_digiflazz_api_key
BANK_ACCOUNT="BCA 1234567890"
WHATSAPP_NUMBER="081111222333"

Ganti your_* dengan nilai sebenarnya. Buat API_SECRET_KEY:

python3 -c "import secrets; print(secrets.token_hex(32))"

4. Siapkan PostgreSQL

Instal dan konfigurasikan database:

sudo apt install postgresql postgresql-contrib
sudo systemctl start postgresql
sudo systemctl enable postgresql
sudo -u postgres psql
CREATE USER your_postgres_user WITH PASSWORD 'your_postgres_password';
CREATE DATABASE rubrikpulsa;
GRANT ALL PRIVILEGES ON DATABASE rubrikpulsa TO your_postgres_user;
\q
psql -U your_postgres_user -d rubrikpulsa
CREATE TABLE agents (
    id SERIAL PRIMARY KEY,
    phone_number VARCHAR(15) UNIQUE NOT NULL,
    telegram_id VARCHAR(50),
    email VARCHAR(100) UNIQUE,
    name VARCHAR(100) NOT NULL,
    address VARCHAR(255),
    pin VARCHAR(255) NOT NULL,
    password_hash VARCHAR(255),
    balance DECIMAL(15,2) DEFAULT 0,
    upline_id INTEGER REFERENCES agents(id),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE transactions (
    id SERIAL PRIMARY KEY,
    agent_id INTEGER REFERENCES agents(id),
    type VARCHAR(50) NOT NULL,
    amount DECIMAL(15,2) NOT NULL,
    status VARCHAR(20) NOT NULL,
    digiflazz_ref_id VARCHAR(50),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE commissions (
    id SERIAL PRIMARY KEY,
    agent_id INTEGER REFERENCES agents(id),
    downline_id INTEGER REFERENCES agents(id),
    transaction_id INTEGER REFERENCES transactions(id),
    amount DECIMAL(15,2) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE products (
    sku_code VARCHAR(50) PRIMARY KEY,
    product_name VARCHAR(100) NOT NULL,
    price DECIMAL(15,2) NOT NULL,
    category VARCHAR(50),
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

5. Jalankan Server

Jalankan FastAPI:

cd /home/user/rubrikpulsa-api
uvicorn main:app --host 0.0.0.0 --port 8000

Buka port 8000 di Alibaba Cloud Console (ECS > Security Groups > Tambah aturan TCP 8000).

Gunakan supervisor untuk produksi:

sudo apt install supervisor
sudo nano /etc/supervisor/conf.d/rubrikpulsa.conf
[program:rubrikpulsa]
directory=/home/user/rubrikpulsa-api
command=/usr/bin/python3 -m uvicorn main:app --host 0.0.0.0 --port 8000
autostart=true
autorestart=true
stderr_logfile=/var/log/rubrikpulsa.err.log
stdout_logfile=/var/log/rubrikpulsa.out.log
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start rubrikpulsa

Akses dokumentasi di http://149.129.241.211:8000/docs.

6. Aktifkan HTTPS

Instal Nginx dan SSL:

sudo apt install nginx certbot python3-certbot-nginx
sudo nano /etc/nginx/sites-available/rubrikpulsa
server {
    listen 80;
    server_name 149.129.241.211;
    location / {
        proxy_pass http://localhost:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
sudo ln -s /etc/nginx/sites-available/rubrikpulsa /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
sudo certbot --nginx -d api.rubrikpulsa.com

Daftarkan domain api.rubrikpulsa.com untuk menggantikan 149.129.241.211.

Daftar Endpoint

API diakses melalui http://149.129.241.211:8000/api (nanti https://api.rubrikpulsa.com/api setelah SSL). Berikut semua endpoint:

1. Pendaftaran (/api/register)

Metode: POST

Deskripsi: Mendaftarkan agen baru.

Body:

{
    "name": "Asep",
    "phone_number": "082321214369",
    "email": "asep@example.com",
    "address": "Subang",
    "password": "password123",
    "pin": "123456",
    "referral_code": null
}

Respons Sukses (200):

{"message": "Pendaftaran berhasil"}

Respons Error:

400: {"detail": "Nomor telepon atau email sudah terdaftar"}
400: {"detail": "Nomor telepon tidak valid"}
400: {"detail": "PIN harus 6 digit"}
400: {"detail": "Kata sandi minimal 8 karakter"}
400: {"detail": "Kode referral tidak valid"}
500: {"detail": "Internal server error"}

2. Login (/api/login)

Metode: POST

Deskripsi: Autentikasi agen untuk mendapatkan token JWT.

Body:

{
    "identifier": "082321214369",
    "password": "password123"
}

Respons Sukses (200):

{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "token_type": "bearer"
}

Respons Error:

400: {"detail": "Silakan atur kata sandi di aplikasi"}
401: {"detail": "Kata sandi salah"}
404: {"detail": "Agen tidak ditemukan"}
500: {"detail": "Internal server error"}

3. Pengaturan Kata Sandi (/api/set_password)

Metode: POST

Deskripsi: Mengatur kata sandi baru dengan verifikasi PIN.

Body:

{
    "phone_number": "082321214369",
    "password": "newpassword123",
    "pin": "123456"
}

Respons Sukses (200):

{"message": "Kata sandi berhasil diatur"}

Respons Error:

401: {"detail": "PIN salah"}
404: {"detail": "Agen tidak ditemukan"}
500: {"detail": "Internal server error"}

4. Cek Saldo (/api/ceksaldo)

Metode: GET

Deskripsi: Mengambil saldo agen.

Header: Authorization: Bearer <access_token>

Respons Sukses (200):

{"balance": 100000.0}

Respons Error:

401: {"detail": "Invalid token"}
500: {"detail": "Internal server error"}

5. Deposit (/api/deposit)

Metode: POST

Deskripsi: Mengajukan permintaan deposit.

Header: Authorization: Bearer <access_token>

Body:

{
    "amount": 50000,
    "pin": "123456"
}

Respons Sukses (200):

{"message": "Silakan transfer Rp50000 ke BCA 1234567890..."}

Respons Error:

400: {"detail": "Jumlah minimal Rp50.000"}
401: {"detail": "PIN salah"}
401: {"detail": "Invalid token"}
500: {"detail": "Internal server error"}

6. Daftar Harga (/api/pricelist)

Metode: GET

Deskripsi: Mengambil daftar produk.

Header: Authorization: Bearer <access_token>

Respons Sukses (200):

{
    "data": [
        {"sku_code": "TL5", "product_name": "Telkomsel 5K", "price": 5500.0, "category": "Pulsa"}
    ]
}

Respons Error:

400: {"detail": "Gagal mengambil daftar harga"}
401: {"detail": "Invalid token"}
500: {"detail": "Internal server error"}

7. Top-up (/api/topup)

Metode: POST

Deskripsi: Melakukan transaksi top-up.

Header: Authorization: Bearer <access_token>

Body:

{
    "customer_no": "081234567890",
    "product_code": "TL5",
    "pin": "123456"
}

Respons Sukses (200):

{"ref_id": "REF123", "new_balance": 94500.0}

Respons Error:

400: {"detail": "Saldo tidak cukup"}
400: {"detail": "Produk tidak ditemukan"}
401: {"detail": "PIN salah"}
401: {"detail": "Invalid token"}
500: {"detail": "Internal server error"}

8. Laporan Transaksi (/api/report)

Metode: GET

Deskripsi: Mengambil riwayat transaksi.

Header: Authorization: Bearer <access_token>

Respons Sukses (200):

{
    "data": [
        {"id": 1, "type": "TOPUP", "amount": 5500.0, "status": "SUCCESS", "digiflazz_ref_id": "REF123", "created_at": "2025-05-20T12:00:00"}
    ]
}

Respons Error:

400: {"detail": "Gagal mengambil laporan"}
401: {"detail": "Invalid token"}
500: {"detail": "Internal server error"}

9. Downline (/api/downline)

Metode: GET

Deskripsi: Mengambil daftar downline dan total komisi.

Header: Authorization: Bearer <access_token>

Respons Sukses (200):

{
    "downlines": [
        {"phone_number": "081234567891", "name": "Budi", "balance": 20000.0}
    ],
    "total_commission": 5000.0
}

Respons Error:

401: {"detail": "Invalid token"}
500: {"detail": "Internal server error"}

10. Reset PIN (/api/resetpin)

Metode: POST

Deskripsi: Mengganti PIN.

Header: Authorization: Bearer <access_token>

Body:

{
    "old_pin": "123456",
    "new_pin": "654321"
}

Respons Sukses (200):

{"message": "PIN berhasil diubah"}

Respons Error:

400: {"detail": "PIN baru harus 6 digit"}
401: {"detail": "PIN lama salah"}
401: {"detail": "Invalid token"}
500: {"detail": "Internal server error"}

11. Tambah Saldo (/api/addbalance)

Metode: POST

Deskripsi: Menambah saldo agen (khusus pemilik).

Header: owner_id: <OWNER_USER_ID>

Body:

{
    "phone_number": "082321214369",
    "amount": 100000
}

Respons Sukses (200):

{"message": "Balance added successfully", "new_balance": 200000.0}

Respons Error:

403: {"detail": "Unauthorized"}
404: {"detail": "Agen tidak ditemukan"}
500: {"detail": "Internal server error"}

Catatan: Endpoint ini hanya untuk pemilik (memerlukan owner_id dari .env).

Integrasi ke Aplikasi Android

API di http://149.129.241.211:8000/ diintegrasikan menggunakan Retrofit. Berikut panduan untuk menghubungkan endpoint ke aplikasi Android.

1. Tambahkan Dependensi

Di build.gradle:

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'

2. Buat Model Data

Untuk /api/login dan /api/ceksaldo:

data class LoginRequest(
    val identifier: String,
    val password: String
)

data class LoginResponse(
    val access_token: String,
    val token_type: String
)

data class BalanceResponse(
    val balance: Float
)

3. Buat Interface Retrofit

Definisikan endpoint:

interface RubrikPulsaApi {
    @POST("api/login")
    suspend fun login(@Body request: LoginRequest): LoginResponse

    @GET("api/ceksaldo")
    suspend fun cekSaldo(@Header("Authorization") token: String): BalanceResponse
}

4. Inisialisasi Retrofit

Konfigurasikan Retrofit:

object ApiClient {
    private const val BASE_URL = "http://149.129.241.211:8000/"

    val retrofit: Retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    val api: RubrikPulsaApi = retrofit.create(RubrikPulsaApi::class.java)

    suspend fun login(identifier: String, password: String): LoginResponse? {
        return try {
            api.login(LoginRequest(identifier, password))
        } catch (e: Exception) {
            null
        }
    }
}

5. Panggil Endpoint Login

Contoh pemanggilan /api/login dari Activity atau ViewModel:

suspend fun login(identifier: String, password: String): LoginResponse? {
    val response = ApiClient.login(identifier, password)
    if (response != null) {
        val sharedPreferences = context.getSharedPreferences("RubrikPulsa", Context.MODE_PRIVATE)
        sharedPreferences.edit().putString("access_token", response.access_token).apply()
    }
    return response
}

Gunakan Coroutines untuk memanggil fungsi ini:

lifecycleScope.launch {
    val response = login("082321214369", "password123")
    if (response != null) {
        // Pindah ke halaman utama
    } else {
        // Tampilkan pesan error
    }
}

6. Tangani Token JWT

Gunakan token untuk endpoint autentikasi:

val sharedPreferences = context.getSharedPreferences("RubrikPulsa", Context.MODE_PRIVATE)
val token = sharedPreferences.getString("access_token", "") ?: ""
val response = ApiClient.api.cekSaldo("Bearer $token")

7. Tangani Error

Parsir respons error:

if (response.isSuccessful) {
    // Proses data
} else {
    val error = response.errorBody()?.string()
    // Tampilkan pesan seperti "Kata sandi salah" atau "Agen tidak ditemukan"
}

8. Izinkan HTTP (Sementara)

Karena belum HTTPS, tambahkan ke res/xml/network_security_config.xml:



    
        149.129.241.211
    

Di AndroidManifest.xml:



Praktik Keamanan