# Dokumentasi API ArtaPay

ArtaPay API memungkinkan Anda membuat invoice pembayaran, mengecek status, dan menerima notifikasi webhook secara real-time.

**Base URL:**
`https://artapay.michaelk.fun/api/v1`

Semua request dan response menggunakan format `application/json`.

---

## 1. Autentikasi

Setiap request ke API v1 harus menyertakan API key dan signature di header.

### Header yang diperlukan:
- `X-ArtaPay-Api-Key` *(string, wajib)*: API key merchant Anda (format: artapay_test_xxx)
- `X-ArtaPay-Secret` *(string, wajib)*: Secret key merchant Anda (sk_test_xxx)
- `X-ArtaPay-Timestamp` *(number, wajib)*: Unix timestamp dalam detik (toleransi ±5 menit)
- `X-ArtaPay-Signature` *(string, wajib)*: HMAC-SHA256 signature (lihat bagian Signature)
- `X-Idempotency-Key` *(string, opsional)*: Key unik untuk mencegah duplikasi request (TTL 24 jam)

> **Catatan:** API key dan Secret key hanya ditampilkan sekali saat merchant diapprove. Simpan dengan aman — jika hilang, gunakan fitur Regenerate di dashboard.

---

## 2. Buat Invoice

`POST /api/v1/payments`

Membuat invoice pembayaran baru. Mengembalikan payment URL yang bisa diberikan ke customer.

### Request Body
- `amount` *(integer, wajib)*: Jumlah pembayaran dalam IDR (satuan rupiah)
- `customerName` *(string, wajib)*: Nama customer (maks 100 karakter)
- `customerEmail` *(string, opsional)*: Email customer
- `customerPhone` *(string, opsional)*: Nomor telepon customer (format Indonesia)
- `merchantReference` *(string, opsional)*: Referensi order dari sistem Anda (maks 100 karakter)
- `description` *(string, opsional)*: Deskripsi pembayaran (maks 500 karakter)
- `expiredMinutes` *(integer, opsional)*: Durasi kadaluarsa dalam menit (default: 60, maks: 43200)
- `currency` *(string, opsional)*: Kode mata uang (default: IDR)

### Contoh Request (cURL)
```bash
curl -X POST https://artapay.michaelk.fun/api/v1/payments \
  -H "Content-Type: application/json" \
  -H "X-ArtaPay-Api-Key: artapay_test_abc123" \
  -H "X-ArtaPay-Secret: sk_test_xyz789" \
  -H "X-ArtaPay-Timestamp: 1717123456" \
  -H "X-ArtaPay-Signature: a1b2c3d4..." \
  -H "X-Idempotency-Key: order-001" \
  -d '{
    "amount": 150000,
    "customerName": "Budi Santoso",
    "customerEmail": "budi@email.com",
    "merchantReference": "ORDER-001",
    "expiredMinutes": 60
  }'
```

### Response (201 Created)
```json
{
  "success": true,
  "data": {
    "invoiceId": "clx1abc123def456",
    "invoiceNumber": "INV-20250528-0001",
    "paymentUrl": "https://arta-pay.vercel.app/pay/clx1abc123def456",
    "amount": 150000,
    "feeAmount": 2250,
    "netAmount": 147750,
    "currency": "IDR",
    "status": "WAITING_PAYMENT",
    "expiredAt": "2025-05-28T13:00:00.000Z",
    "createdAt": "2025-05-28T12:00:00.000Z"
  }
}
```

---

## 3. Cek Status Invoice

`GET /api/v1/payments/:invoiceId`

Mengecek status invoice berdasarkan invoice ID. Lazy expiration dijalankan otomatis.

### Contoh Request (cURL)
```bash
curl https://artapay.michaelk.fun/api/v1/payments/clx1abc123def456 \
  -H "X-ArtaPay-Api-Key: artapay_test_abc123" \
  -H "X-ArtaPay-Secret: sk_test_xyz789" \
  -H "X-ArtaPay-Timestamp: 1717123456" \
  -H "X-ArtaPay-Signature: a1b2c3d4..."
```

### Response (200 OK)
```json
{
  "success": true,
  "data": {
    "invoiceId": "clx1abc123def456",
    "invoiceNumber": "INV-20250528-0001",
    "status": "PAID",
    "amount": 150000,
    "paidAt": "2025-05-28T12:30:00.000Z"
  }
}
```

---

## 4. Cek Invoice by Referensi

`GET /api/v1/payments/by-reference/:merchantReference`

Mencari invoice berdasarkan referensi order dari sistem Anda.

### Contoh Request (cURL)
```bash
curl https://artapay.michaelk.fun/api/v1/payments/by-reference/ORDER-001 \
  -H "X-ArtaPay-Api-Key: artapay_test_abc123" \
  -H "X-ArtaPay-Secret: sk_test_xyz789" \
  -H "X-ArtaPay-Timestamp: 1717123456" \
  -H "X-ArtaPay-Signature: a1b2c3d4..."
```

---

## 5. Batalkan Invoice

`POST /api/v1/payments/:invoiceId/cancel`

Membatalkan invoice yang masih berstatus `WAITING_PAYMENT`.

> **Catatan:** Invoice yang sudah PAID, EXPIRED, atau CANCELLED tidak bisa dibatalkan.

### Contoh Request (cURL)
```bash
curl -X POST https://artapay.michaelk.fun/api/v1/payments/clx1abc123def456/cancel \
  -H "X-ArtaPay-Api-Key: artapay_test_abc123" \
  -H "X-ArtaPay-Secret: sk_test_xyz789" \
  -H "X-ArtaPay-Timestamp: 1717123456" \
  -H "X-ArtaPay-Signature: a1b2c3d4..."
```

---

## 6. Webhook Events

ArtaPay mengirim HTTP POST ke webhook URL Anda setelah event pembayaran terjadi.

### Event yang tersedia:
- `payment.paid` : Invoice berhasil dibayar
- `payment.created` : Invoice baru dibuat
- `payment.failed` : Pembayaran gagal
- `payment.expired` : Invoice kadaluarsa

### Contoh Payload (POST ke webhook URL Anda)
```json
{
  "event": "payment.paid",
  "invoiceId": "clx1abc123def456",
  "invoiceNumber": "INV-20250528-0001",
  "merchantReference": "ORDER-001",
  "amount": 150000,
  "feeAmount": 2250,
  "netAmount": 147750,
  "currency": "IDR",
  "status": "PAID",
  "customerName": "Budi Santoso",
  "customerEmail": "budi@email.com",
  "paidAt": "2025-05-28T12:30:00.000Z",
  "timestamp": 1717123456
}
```

### Header yang dikirim bersama webhook:
```text
X-ArtaPay-Signature: a1b2c3d4e5f6...
X-ArtaPay-Event: payment.paid
X-ArtaPay-Timestamp: 1717123456
```

> **Tips:** Balas dengan HTTP 2xx untuk konfirmasi penerimaan. Jika tidak, webhook akan ditandai FAILED dan bisa di-retry manual dari dashboard.

> **⚠️ PENTING:** Mulai v1.1, setiap webhook menyertakan header `X-ArtaPay-Signature` (HMAC-SHA256). Merchant **wajib** mengkonfigurasi Webhook Secret di Developer Settings agar webhook terkirim. Lihat bagian **Verifikasi Signature** di bawah untuk implementasi verifikasi.

---

## 7. Verifikasi Signature

Setiap request dan webhook menggunakan HMAC-SHA256 untuk memastikan keaslian data.

### Cara Membuat Signature (Request)
```text
payload = timestamp + ":" + SHA256(requestBody)
signature = HMAC-SHA256(secretKey, payload)
```

### Contoh JavaScript
```javascript
const crypto = require('crypto');

function createSignature(secretKey, timestamp, body) {
  const bodyHash = crypto
    .createHash('sha256')
    .update(body)
    .digest('hex');
  
  const payload = `${timestamp}:${bodyHash}`;
  
  return crypto
    .createHmac('sha256', secretKey)
    .update(payload)
    .digest('hex');
}

// Penggunaan
const timestamp = Math.floor(Date.now() / 1000);
const body = JSON.stringify({ amount: 150000, customerName: 'Budi' });
const sig = createSignature('sk_test_xyz789', timestamp, body);
```

### Verifikasi Webhook (PHP)
```php
<?php
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_ARTAPAY_SIGNATURE'];
$secretKey = 'your_webhook_secret_key'; // Webhook Secret dari Developer Settings

$expected = hash_hmac('sha256', $payload, $secretKey);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Invalid signature');
}

$data = json_decode($payload, true);
// Proses event...
http_response_code(200);
echo 'OK';
```

> **PENTING:** Gunakan Webhook Secret Anda secara utuh (termasuk awalan `whsec_`) saat memverifikasi signature. **Jangan** memotong atau menghilangkan awalan tersebut karena akan menyebabkan verifikasi signature selalu gagal (tidak cocok).

> **Info:** Timestamp harus dalam toleransi ±5 menit dari waktu server. Gunakan NTP untuk sinkronisasi waktu.

---

## 8. Real-time Payment Status (WebSocket)

Fitur WebSocket memberikan update status secara *real-time* kepada sistem frontend Anda (misalnya di halaman checkout) tanpa harus memuat ulang halaman atau melakukan *polling*.

> **PENTING:** Fitur WebSocket harus diaktifkan oleh Admin ArtaPay untuk setiap merchant. Anda dapat mengecek status fitur ini di menu **Developer Settings**. Koneksi akan ditolak (Disconnect Code: `1008`) jika fitur belum aktif.

### Endpoint WebSocket
Koneksi WebSocket tidak memerlukan header *Authorization* atau API Key, sehingga aman dipanggil langsung dari sisi klien (browser). Parameter yang dibutuhkan hanya `invoiceId`.

**WSS URL:** 
`wss://artapay.michaelk.fun/api/v1/payments/{invoiceId}/ws`

### Struktur Pesan (Payload)
Setiap kali status invoice berubah, server akan mengirimkan pesan berformat JSON ke klien yang terhubung. Saat pertama kali koneksi terbuka, server juga akan mengirimkan 1 pesan berisi status terkini.

**Contoh Payload Diterima:**
```json
{
  "event": "INVOICE_STATUS",
  "invoiceId": "clx1abc123def456",
  "status": "PAID",
  "paidAt": "2025-05-28T12:30:00.000Z"
}
```

### Contoh Implementasi JavaScript (Klien)

```javascript
const invoiceId = "clx1abc123def456";
const ws = new WebSocket(\`wss://artapay.michaelk.fun/api/v1/payments/\${invoiceId}/ws\`);

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  if (data.event === "INVOICE_STATUS" && data.status === "PAID") {
    alert("Pembayaran berhasil!");
    // Lakukan redirect atau update UI
    ws.close();
  }
};

ws.onclose = (event) => {
  if (event.code === 1008) {
    console.warn("Fitur WebSocket belum aktif untuk merchant ini.");
  }
};
```

> **Tips:** Objek `WebSocket` bawaan browser tidak memiliki fitur auto-reconnect secara otomatis. Anda disarankan untuk menambahkan logika reconnect manual atau menggunakan library seperti `partysocket`. Selalu sediakan tombol "Cek Status" sebagai *fallback* jika koneksi WebSocket terblokir.

---

## 9. Web Popup / Modal Checkout Integration

Fitur **Web Popup** memungkinkan Anda menampilkan halaman pembayaran (invoice) ArtaPay secara langsung di dalam website Anda menggunakan tampilan *overlay/modal*. Dengan fitur ini, pelanggan Anda tidak perlu berpindah tab atau diarahkan ke luar dari website Anda saat melakukan pembayaran.

> **PENTING:** Fitur Web Popup harus diaktifkan oleh Admin ArtaPay untuk setiap merchant. Anda dapat mengecek status fitur ini di menu **Developer Settings**. Jika fitur ini belum aktif, popup akan ditolak dan dialihkan ke halaman error.

### Cara Integrasi

Integrasi fitur ini sangat mudah, Anda tidak perlu menginstall library tambahan apa pun. Cukup sisipkan script bawaan ArtaPay ke dalam HTML website Anda.

**Langkah 1: Tambahkan Script ArtaPay**
Letakkan tag `<script>` berikut di dalam `<head>` atau di bagian bawah `<body>` website Anda.

```html
<script src="https://arta-pay.vercel.app/artapay.js"></script>
```

**Langkah 2: Panggil Fungsi Checkout**
Gunakan objek global `window.ArtaPay` untuk memicu munculnya popup. Anda harus meneruskan `invoiceId` atau `paymentUrl` penuh yang didapatkan dari respons API Create Invoice.

```javascript
// Anda bisa mendaftarkan fungsi callback ketika pembayaran berhasil (Opsional)
ArtaPay.onSuccess = function(invoiceId) {
  console.log("Hore! Pembayaran berhasil untuk invoice:", invoiceId);
  // Lakukan aksi lanjutan, misalnya refresh status pesanan di UI Anda
  // atau alihkan ke halaman Thank You.
  window.location.href = "/order-success?id=" + invoiceId;
};

// Menampilkan popup pembayaran
// Anda bisa mempassing invoiceId langsung:
ArtaPay.checkout("clx1abc123def456");

// Atau mempassing paymentUrl:
// ArtaPay.checkout("https://arta-pay.vercel.app/pay/clx1abc123def456");
```

### Cara Kerja
1. Ketika `ArtaPay.checkout()` dipanggil, script akan merender sebuah `<iframe>` melayang di layar pelanggan Anda.
2. Pelanggan melakukan pembayaran.
3. Setelah pembayaran dinyatakan sukses (dikombinasikan dengan fitur WebSocket), ArtaPay akan secara aman mengirimkan sinyal penutupan ke website Anda.
4. Iframe akan otomatis tertutup, dan fungsi `ArtaPay.onSuccess` milik Anda akan tereksekusi.

---

## 10. Error Codes

### Daftar Error Code
| HTTP Status | Error Code | Keterangan |
| :--- | :--- | :--- |
| **400** | `VALIDATION_ERROR` | Request body tidak valid atau parameter kurang |
| **400** | `INVALID_JSON` | Request body bukan JSON yang valid |
| **400** | `DATE_RANGE_TOO_LARGE` | Rentang tanggal melebihi 30 hari |
| **401** | `UNAUTHORIZED` | API key tidak ada atau tidak valid |
| **401** | `INVALID_SIGNATURE` | Signature tidak cocok atau timestamp kadaluarsa |
| **403** | `FORBIDDEN` | Tidak punya akses ke resource ini |
| **403** | `MERCHANT_NOT_ACTIVE` | Akun merchant tidak aktif |
| **404** | `NOT_FOUND` | Resource tidak ditemukan |
| **409** | `PAYMENT_IN_PROGRESS` | Pembayaran sedang diproses (double payment) |
| **422** | `INVOICE_EXPIRED` | Invoice sudah kadaluarsa |
| **422** | `INVOICE_PAID` | Invoice sudah dibayar |
| **422** | `INVOICE_CANCELLED` | Invoice sudah dibatalkan |
| **422** | `INVALID_STATUS` | Operasi tidak valid untuk status invoice saat ini |
| **429** | `RATE_LIMIT_EXCEEDED` | Terlalu banyak request. Coba lagi nanti. |
| **500** | `INTERNAL_SERVER_ERROR` | Kesalahan internal server |

### Format Error Response
```json
{
  "success": false,
  "error": {
    "code": "INVALID_SIGNATURE",
    "message": "Signature mismatch"
  }
}
```
