Louvin API Documentation

Louvin API memungkinkan Anda menerima pembayaran digital (QRIS, GoPay, ShopeePay, Virtual Account) tanpa memerlukan identitas bisnis. Semua request menggunakan JSON melalui HTTPS.

Base URL: https://api.louvin.dev

Version: v1.0

Overview

Endpoints2 — create-transaction, check-status
AuthAPI Key via header x-api-key
FormatJSON (Request & Response)

Quick Start

  1. Buat Project di Dashboard — Masuk ke Dashboard → Proyek → Buat Proyek. Anda akan mendapat API key yang dimulai dengan lv_.
  2. Buat Transaksi
    const res = await fetch("https://api.louvin.dev/create-transaction", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "x-api-key": "lv_your_api_key_here"
      },
      body: JSON.stringify({
        amount: 50000,
        payment_type: "qris",
        customer_name: "John Doe"
      })
    });
    
    const data = await res.json();
    // data.payment.qr_string → tampilkan sebagai QR code
    // data.payment.va_number → tampilkan nomor VA ke customer
  3. Terima Notifikasi — Set Webhook URL di pengaturan proyek. Louvin akan kirim HTTP POST setiap kali status transaksi berubah.

Louvin SDK

SDK JavaScript ringan untuk integrasi cepat. Tanpa dependency, bekerja di browser dan Node.js.

Instalasi

<!-- CDN -->
<script src="https://louvin.dev/sdk/louvin.min.js"></script>

<!-- ES Module -->
<script type="module">
  import { Louvin } from 'https://louvin.dev/sdk/louvin.js';
</script>

Buat Pembayaran

const louvin = new Louvin('lv_your_api_key');

const result = await louvin.createPayment({
  amount: 50000,
  payment_type: 'qris',
  customer_name: 'John Doe',
  description: 'Order #123'
});

console.log(result.payment.qr_string);
console.log(result.transaction.id);

Shortcut Methods

await louvin.createQRIS(50000, { customer_name: 'John' });
await louvin.createBNI(100000);
await louvin.createBRI(100000);
await louvin.createPermata(100000);
await louvin.createCIMB(100000);

Cek Status & Polling

const status = await louvin.checkStatus('transaction-uuid');
console.log(status.transaction.status); // 'pending' | 'settled' | 'failed'

const final = await louvin.waitForPayment('transaction-uuid', {
  interval: 3000,
  timeout: 600000,
  onStatusChange: (data) => console.log('Status:', data.transaction.status)
});

Authentication

Setiap request harus menyertakan API key di header. API key didapat dari Dashboard → Proyek → Detail Proyek.

HeaderValue
Content-Typeapplication/json
x-api-keyAPI key proyek Anda (dimulai dengan lv_)
curl -X POST https://api.louvin.dev/create-transaction \
  -H "Content-Type: application/json" \
  -H "x-api-key: lv_your_api_key_here" \
  -d '{"amount": 50000, "payment_type": "qris"}'
⚠️ Jangan expose API key di client-side production. Gunakan backend proxy.

Biaya Transaksi

Fee dihitung otomatis. Tidak ada biaya bulanan atau biaya setup.

MetodeFeeKeterangan
QRIS / E-Wallet0.7% + Rp 400Min transaksi Rp 1.500
Virtual AccountRp 6.500Flat fee per transaksi

Contoh Perhitungan

ContohAmountFeeCustomer BayarMerchant Terima
QRIS Rp 50.00050.00075050.75050.000
BNI VA Rp 100.000100.0006.500106.500100.000

Jika fee_on_customer aktif (default), fee ditambahkan ke total yang dibayar customer. Merchant menerima penuh net_amount.

Create Transaction

POST /create-transaction

Request Body

ParameterTypeRequiredDescription
amountnumberJumlah pembayaran dalam Rupiah (min: 1, QRIS min: 1500)
payment_typestringMetode pembayaran (lihat Payment Types)
customer_namestringNama pelanggan
customer_emailstringEmail pelanggan
descriptionstringDeskripsi transaksi
referencestringID referensi unik (auto-generated jika kosong)

Contoh Request

const response = await fetch("https://api.louvin.dev/create-transaction", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-api-key": "lv_your_api_key_here"
  },
  body: JSON.stringify({
    amount: 50000,
    payment_type: "qris",
    customer_name: "John Doe",
    customer_email: "john@example.com",
    description: "Pembelian Produk A"
  })
});

const data = await response.json();

Response — QRIS (201 Created)

{
  "success": true,
  "transaction": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "amount": 50750,
    "fee": 750,
    "net_amount": 50000,
    "status": "pending",
    "reference": "550e8400-1711234567890-a1b2c3",
    "fee_on_customer": true,
    "created_at": "2026-03-09T10:30:00Z"
  },
  "payment": {
    "order_id": "550e8400-1711234567890-a1b2c3",
    "payment_type": "qris",
    "qr_string": "00020101021226...",
    "payment_number": "00020101021226...",
    "expired_at": "2026-03-09T10:45:00Z",
    "total_payment": 50750
  }
}

Response — Virtual Account

{
  "success": true,
  "transaction": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "amount": 106500,
    "fee": 6500,
    "net_amount": 100000,
    "status": "pending",
    "reference": "550e8400-1711234567890-x1y2z3",
    "fee_on_customer": true,
    "created_at": "2026-03-09T10:30:00Z"
  },
  "payment": {
    "order_id": "550e8400-1711234567890-x1y2z3",
    "payment_type": "bni_va",
    "va_number": "8810123456789012",
    "bank": "bni",
    "payment_number": "8810123456789012",
    "expired_at": "2026-03-10T10:30:00Z",
    "total_payment": 106500
  }
}
Penting: amount di response = total yang dibayar customer (termasuk fee). Gunakan net_amount untuk jumlah merchant terima.

Check Status

GET /check-status?id=TRANSACTION_ID

Cek status pembayaran. Juga mendukung POST dengan body {"id": "..."}.

Response

{
  "success": true,
  "transaction": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "settled",
    "amount": 50750,
    "fee": 750,
    "net_amount": 50000,
    "reference": "550e8400-1711234567890-a1b2c3",
    "created_at": "2026-03-09T10:30:00Z",
    "updated_at": "2026-03-09T10:35:00Z"
  }
}

Payment Types

CodeMetodeFeeResponse Field
qrisQRIS0.7% + Rp 400qr_string
gopayGoPay0.7% + Rp 400qr_string, deeplink_url
shopeepayShopeePay0.7% + Rp 400deeplink_url
bni_vaBNI Virtual AccountRp 6.500va_number, bank
bri_vaBRI Virtual AccountRp 6.500va_number, bank
permata_vaPermata Virtual AccountRp 6.500va_number, bank
cimb_niaga_vaCIMB Niaga Virtual AccountRp 6.500va_number, bank

Status Flow

Setiap transaksi memiliki siklus: pending → settled atau pending → failed

StatusDeskripsi
pendingTransaksi dibuat, menunggu customer menyelesaikan pembayaran
settledPembayaran berhasil dikonfirmasi oleh payment gateway
failedPembayaran gagal, ditolak, atau expired

Webhooks

Jika proyek memiliki Webhook URL, Louvin akan mengirim HTTP POST setiap kali status transaksi berubah.

Webhook Payload

{
  "event": "payment.settled",
  "data": {
    "transaction_id": "550e8400-e29b-41d4-a716-446655440000",
    "gateway_transaction_id": "gateway-uuid",
    "project_id": "project-uuid",
    "order_id": "550e8400-1711234567890-a1b2c3",
    "amount": 50750,
    "fee": 750,
    "net_amount": 50000,
    "payment_type": "qris",
    "status": "settled",
    "customer_name": "John Doe",
    "customer_email": "john@example.com"
  }
}

Event Types

EventDeskripsi
payment.settledPembayaran berhasil dikonfirmasi
payment.failedPembayaran gagal, ditolak, atau expired
payment.pendingStatus masih menunggu pembayaran

Contoh Handler (Express.js)

app.post('/webhook/louvin', (req, res) => {
  const { event, data } = req.body;

  if (event === 'payment.settled') {
    console.log('Pembayaran berhasil:', data.order_id);
    console.log('Jumlah diterima:', data.net_amount);
  }

  if (event === 'payment.failed') {
    console.log('Pembayaran gagal:', data.order_id);
  }

  // PENTING: selalu return 200
  res.status(200).json({ received: true });
});
⚠️ Selalu return HTTP 200 dari endpoint webhook. Response selain 200 akan dicatat sebagai gagal.

Error Handling

Semua error dikembalikan dalam format JSON dengan field error dan opsional details.

StatusPenyebabSolusi
400Parameter tidak validCek amount > 0, payment_type valid, QRIS min Rp 1.500
401API key tidak validPastikan header x-api-key benar dan proyek aktif
404Transaksi tidak ditemukanCek transaction ID
500Server errorCoba lagi atau hubungi support

Contoh Error Response

{
  "error": "Invalid amount. Must be a positive number."
}

// Dengan detail dari payment gateway:
{
  "error": "Payment gateway error",
  "gateway_status_code": "406",
  "details": "Order ID has been utilized."
}

Louvin Payment Gateway — louvin.dev — API v1.0