Dokumentasi Open API (Headless E-commerce)

Selamat datang di dokumentasi pengembang Akunfy. Open API Akunfy memungkinkan seller menjual produk instan mereka (Akun/Kredensial, Link, Lisensi) secara headless melalui platform pihak ketiga seperti Bot Telegram, Bot WhatsApp, Custom Website, atau Discord, dengan memanfaatkan sistem manajemen stok dan payment gateway Akunfy secara dinamis.

1. Otentikasi & Base URL

Seluruh request ke Open API wajib dikirim ke base URL berikut menggunakan protokol HTTPS:

https://akunfy.com/api

Gunakan API Key yang telah Anda generate di halaman Dashboard Seller sebagai Bearer Token pada header request Anda:

Authorization: Bearer YOUR_API_KEY
Accept: application/json
Content-Type: application/json

2. Referensi API Endpoints

GET

/v1/seller/products

Menarik katalog produk seller berstatus active yang siap dijual (hanya mendukung tipe *Instant Delivery*, tipe Jasa diecualikan). Endpoint ini mengembalikan harga dinamis terhitung dan sisa stok riil saat ini.

Query Parameters

  • per_page (integer, optional) - Jumlah produk per halaman. Default: 15, Max: 100.
  • page (integer, optional) - Halaman keberapa yang ingin ditarik.

Contoh Response

{
  "success": true,
  "data": [
    {
      "id": 43,
      "name": "Netflix Premium 1 Bulan Resmi",
      "slug": "netflix-premium-1-bulan-resmi-43",
      "price": 15000,
      "stock_count": 12,
      "thumbnail": "https://akunfy.com/storage/products/example.webp",
      "category": {
        "id": 5,
        "name": "Streaming",
        "slug": "streaming"
      },
      "created_at": "2026-08-05T09:49:46.000000Z",
      "updated_at": "2026-08-05T09:49:46.000000Z"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 3,
    "per_page": 15,
    "total": 42
  }
}
POST

/v1/seller/checkout

Membuat tagihan transaksi pembelian baru. Sistem akan secara otomatis mengunci (*lockForUpdate*) stok unit termurah (*auto-pick*) dan memanggil API Payment Gateway (Paprika QRIS/lainnya) untuk menerbitkan URL QRIS/VA.

Request Body (JSON)

FieldTipeWajibDeskripsi
product_idIntegerYaID produk yang ingin dibeli.
quantityIntegerYaJumlah unit pembelian (min 1).
payment_methodStringYaMetode pembayaran. Contoh: paprika, duitku, manual.
payment_codeStringTidakKode sub-metode/channel pembayaran jika dibutuhkan.
guest_nameStringYaNama pembeli pihak ketiga (guest).
guest_emailStringYaEmail pembeli pihak ketiga.
guest_phoneStringYaNomor HP pembeli pihak ketiga (format WA aktif).
buyer_noteStringTidakCatatan tambahan dari pembeli.

Contoh Response

{
  "success": true,
  "message": "Checkout successfully created.",
  "data": {
    "merchant_ref": "INV-ZXYABC050826",
    "reference_id": "PAP-992178229",
    "amount": 15000,
    "fee": 500,
    "total_amount": 15500,
    "payment_url": "00020101021226620016COM.CO.PAPRIKA...",
    "payment_method": "paprika",
    "payment_channel": "Paprika QRIS",
    "status": "unpaid",
    "expired_time": "2026-08-05T10:49:46.000000Z"
  }
}
GET

/v1/seller/transactions/{merchant_ref}

Melakukan pengecekan status tagihan transaksi tertentu secara aktif (*polling*). Jika status transaksi telah terbayar (paid atau completed), response akan secara otomatis memuat array berisi kredensial atau link download unit produk digital yang dibeli.

Contoh Response (Setelah Lunas)

{
  "success": true,
  "data": {
    "merchant_ref": "INV-ZXYABC050826",
    "reference_id": "PAP-992178229",
    "amount": 15000,
    "fee": 500,
    "total_amount": 15500,
    "payment_url": "00020101021226620016COM.CO.PAPRIKA...",
    "payment_method": "paprika",
    "payment_channel": "Paprika QRIS",
    "status": "paid",
    "expired_time": "2026-08-05T10:49:46.000000Z",
    "paid_at": "2026-08-05T09:55:12.000000Z",
    "credentials": [
      {
        "data_type": "login",
        "data_1": "[email protected]",
        "data_2": "rahasiaseller123"
      }
    ]
  }
}

3. Outbound Webhook & Keamanan HMAC Signature

Ketika status transaksi berubah menjadi paid (lunas) atau expired (kedaluwarsa), server Akunfy akan menembakkan request POST secara asinkron ke URL Webhook Anda.

Header Webhook

Setiap request webhook dari Akunfy memuat header tanda tangan keamanan berikut:

Content-Type: application/json
X-Akunfy-Signature: <SHA256_HMAC_SIGNATURE>

Struktur Payload Webhook

{
  "event": "transaction.paid",
  "timestamp": 1785835772,
  "data": {
    "merchant_ref": "INV-ZXYABC050826",
    "reference_id": "PAP-992178229",
    "status": "paid",
    "amount": 15000,
    "fee": 500,
    "total_amount": 15500,
    "payment_method": "paprika",
    "payment_channel": "Paprika QRIS",
    "buyer_note": null,
    "guest_name": "Budi Santoso",
    "guest_email": "[email protected]",
    "guest_phone": "6281234567890",
    "paid_at": "2026-08-05T09:55:12.000000Z",
    "expired_time": "2026-08-05T10:49:46.000000Z",
    "credentials": [
      {
        "data_type": "login",
        "data_1": "[email protected]",
        "data_2": "rahasiaseller123"
      }
    ]
  }
}

Verifikasi Signature

Untuk menjamin request benar-benar datang dari Akunfy, Anda harus memvalidasi header X-Akunfy-Signature dengan mere-generate signature menggunakan payload mentah (*raw body*) dan Webhook Secret Anda.

Contoh Kode PHP
<?php

$rawPayload = file_get_contents('php://input');
$receivedSignature = $_SERVER['HTTP_X_AKUNFY_SIGNATURE'] ?? '';
$webhookSecret = 'YOUR_WEBHOOK_SECRET';

$calculatedSignature = hash_hmac('sha256', $rawPayload, $webhookSecret);

if (hash_equals($calculatedSignature, $receivedSignature)) {
    // Tanda tangan valid! Proses data webhook.
    $payload = json_decode($rawPayload, true);
    
    // Kirim respons 200 OK
    http_response_code(200);
    echo json_encode(['status' => 'success']);
} else {
    // Tanda tangan TIDAK valid! Tolak request.
    http_response_code(401);
    echo json_encode(['status' => 'unauthorized']);
}
Contoh Kode Node.js (Express)
const crypto = require('crypto');
const express = require('express');
const app = express();

app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
    const signature = req.headers['x-akunfy-signature'];
    const webhookSecret = 'YOUR_WEBHOOK_SECRET';

    const hmac = crypto.createHmac('sha256', webhookSecret);
    const calculatedSignature = hmac.update(req.body).digest('hex');

    if (calculatedSignature === signature) {
        const payload = JSON.parse(req.body.toString());
        console.log('Webhook valid:', payload.event);
        
        res.status(200).json({ status: 'success' });
    } else {
        res.status(401).json({ status: 'unauthorized' });
    }
});