Logo Apresiasi Mitra Promedia
Apresiasi Mitra Promedia
API Documentation Widget Integration

API Documentation

Dokumentasi lengkap REST API. Semua endpoint menggunakan JSON. Autentikasi menggunakan JWT Bearer Token kecuali endpoint Widget yang bersifat public.

Base URL

https://apresiasi.test/api

Cara memanggil endpoint

Path ditulis relatif (misal /auth/login). Ada dua format URL:

A. Pretty URL — Apache + mod_rewrite (htaccess aktif):

POST https://apresiasi.test/api/auth/login

B. Query route (fallback) — Nginx / Laravel Valet tanpa rewrite khusus:

POST https://apresiasi.test/api/index.php?route=auth/login
GET  https://apresiasi.test/api/index.php?route=transactions&page=1
GET  https://apresiasi.test/api/index.php?route=widget/check-status/INV-123
Tip Postman / curl: gunakan format B jika format A menghasilkan 404. Body tetap JSON; header Content-Type: application/json wajib disertakan.

🔒 Autentikasi JWT

Sertakan header Authorization: Bearer {token} pada setiap request yang membutuhkan autentikasi. Token didapat dari POST /auth/login.

🌐 CORS Whitelist

Hanya origin yang terdaftar di CORS_ALLOWED_ORIGINS pada .env yang diizinkan. Browser akan memblok response dari origin lain secara otomatis.

⚡ Rate Limiting Login

Maksimal 5 percobaan login gagal per IP dalam 15 menit. Jika melebihi, endpoint mengembalikan HTTP 429 Too Many Requests. Konfigurasi di .env via RATE_LIMIT_MAX_ATTEMPTS dan RATE_LIMIT_WINDOW_MINUTES.

📄 Export Token

Download CSV tidak menggunakan JWT di URL. Gunakan POST /export-tokens untuk mendapatkan one-time token (berlaku 60 detik, sekali pakai), lalu sertakan sebagai ?export_token=.

Format Response Standar

Sukses

{
  "status": true,
  "code": 200,
  "message": "Success",
  "data": { ... }
}

Error

{
  "status": false,
  "code": 422,
  "message": "Validasi gagal",
  "errors": {
    "email": "Email wajib diisi"
  }
}

Paginated

{
  "status": true,
  "code": 200,
  "message": "Success",
  "data": {
    "items": [ ... ],
    "total": 100,
    "page": 1,
    "per_page": 15,
    "last_page": 7
  }
}

1. Authentication

POST /auth/login

Login dan dapatkan access token + refresh token.

⚡ Rate-limited: maks 5 percobaan gagal per IP dalam 15 menit → HTTP 429.

URL lengkap (contoh)

POST https://apresiasi.test/api/index.php?route=auth/login

Request Body

{
  "email": "admin@apresiasi.test",
  "password": "admin123"
}

Response 200

{
  "status": true,
  "code": 200,
  "message": "Login berhasil",
  "data": {
    "token": "eyJhbGci...",
    "refresh_token": "eyJhbGci...",
    "user": {
      "id": 1,
      "name": "Administrator",
      "email": "admin@apresiasi.test",
      "role": "admin",
      "website_id": null
    }
  }
}

Response 429 (rate limit)

{
  "status": false,
  "code": 429,
  "message": "Terlalu banyak percobaan login. Coba lagi dalam 15 menit."
}
GET /auth/me 🔒 Auth — Profil user yang sedang login
POST /auth/refresh

Perbarui access token menggunakan refresh token.

{ "refresh_token": "eyJhbGci..." }
POST /auth/forgot-password
{ "email": "user@domain.com" }
POST /auth/reset-password
{ "token": "abc123...", "password": "newpassword" }

2. Export Tokens

One-time token untuk download file CSV. Digunakan agar JWT tidak perlu diekspos di URL browser (browser history, server log, Referer header). Token berlaku 60 detik dan hanya bisa dipakai sekali. Konfigurasi TTL via EXPORT_TOKEN_TTL_SECONDS di .env.

POST /export-tokens 🔒 Auth

Buat export token baru. Langkah ini dilakukan via AJAX (tetap pakai Authorization header), hasilnya digunakan untuk redirect download.

Request Body

{
  "endpoint": "transactions/export/csv",
  "params": {
    "status": "paid",
    "date_from": "2026-01-01",
    "date_to": "2026-12-31"
  }
}

Response 201

{
  "status": true,
  "code": 201,
  "message": "Export token berhasil dibuat",
  "data": {
    "token": "a1b2c3d4e5f6..."
  }
}

Contoh alur download CSV di frontend

// 1. Ambil export token via AJAX
apiPost('export-tokens', {
  endpoint: 'transactions/export/csv',
  params: { status: 'paid', date_from: '2026-01-01' }
}).done(function(res) {
  // 2. Redirect ke URL download dengan export_token
  window.location.href = apiUrl('transactions/export/csv')
    + '&status=paid&date_from=2026-01-01'
    + '&export_token=' + res.data.token;
});

3. Dashboard

🔒 Semua endpoint memerlukan autentikasi. User website_owner hanya melihat data websitenya sendiri.

Query params opsional: date_from, date_to, period (day / week / month / year).

GET
/dashboard/summary

Ringkasan: total pendapatan, jumlah transaksi, status breakdown, penghasilan bulan ini.

GET
/dashboard/chart

Data chart pendapatan per periode. Label format: dayYYYY-MM-DD, weekYYYY-Www, monthYYYY-MM, yearYYYY.

GET
/dashboard/top-websites

Top 10 website dengan penghasilan terbanyak.

GET
/dashboard/top-articles

Top 10 artikel/konten dengan penghasilan terbanyak. Digroup by article_url.

4. Transactions

GET /transactions 🔒 Auth

List transaksi dengan filter & pagination. website_owner hanya melihat transaksi websitenya.

ParamTipeKeterangan
pageintHalaman (default: 1)
per_pageintPer halaman (default: 15, maks: 100)
searchstringCari nama, email, invoice, judul artikel
statusstringpaid / pending / expired / failed
website_idintFilter per website (admin only)
date_fromdateDari tanggal (YYYY-MM-DD)
date_todateSampai tanggal (YYYY-MM-DD)
GET
/transactions/{id} — Detail satu transaksi
GET
/transactions/export/csv?export_token={token}

Download CSV. Gunakan Export Token (bukan JWT di URL). Mendukung filter params yang sama dengan list. Lihat seksi Export Tokens.

5. Websites

🔒 Semua endpoint memerlukan role admin.

GET/websites— List websites (search, pagination)
GET/websites/{id}— Detail website
GET
/websites/export?export_token={token}

Download CSV. Gunakan Export Token, bukan JWT di URL.

POST /websites
{
  "name": "Portal Berita XYZ",
  "domain": "https://beritaxyz.com",
  "api_endpoint": "https://beritaxyz.com/api/article",
  "share_website": 50,
  "share_platform": 50,
  "is_active": 1
}
PUT/websites/{id}— Update (body sama dengan POST)
DELETE/websites/{id}— Soft delete (nonaktifkan)

6. Users

🔒 Semua endpoint memerlukan role admin.

GET/users— List users (search, pagination)
GET/users/{id}— Detail user
POST /users
{
  "name": "Pemilik Web XYZ",
  "email": "owner@beritaxyz.com",
  "password": "password123",
  "role_id": 2,
  "website_id": 1,
  "is_active": 1
}
PUT/users/{id}— Update (field password opsional)
DELETE/users/{id}— Nonaktifkan user

7. Roles & Permissions

🔒 Admin only.

GET/roles— List semua role
GET/roles/{id}— Detail role beserta permissions
GET/roles/permissions— List semua permission tersedia di sistem
POST /roles
{
  "name": "editor",
  "description": "Editor konten",
  "permissions": ["dashboard.view", "transactions.view"]
}
PUT/roles/{id}— Update role + permissions
DELETE/roles/{id}— Hapus role (gagal jika masih ada user)

8. Config

🔒 Admin only. Konfigurasi bersifat key-value dengan pengelompokan (config_group).

GET/config— List semua config (grouped)
GET/config/{key}— Satu config by key
POST/config— Tambah config baru
PUT/config/{key}— Update satu config
PUT/config— Bulk update banyak config sekaligus

Bulk Update Body

{
  "configs": {
    "tax_percentage": "12",
    "app_name": "Nama Aplikasi Baru"
  }
}

9. Audit Logs

🔒 Admin only. Riwayat seluruh aktivitas pengguna di sistem (login, create, update, delete, export, dll). Setiap entry mencatat user, modul, aksi, IP address, dan user agent.

GET /audit-logs 🔒 Admin

List audit log dengan filter & pagination (25 per halaman).

ParamTipeKeterangan
pageintHalaman (default: 1)
per_pageintPer halaman (maks: 100)
searchstringCari nama user, detail, atau IP address
user_idintFilter per user
actionstringlogin / create / update / delete / export / dll
modulestringauth / transactions / websites / users / roles / config / dll
date_fromdateDari tanggal (YYYY-MM-DD)
date_todateSampai tanggal (YYYY-MM-DD)

Contoh Response

{
  "status": true,
  "data": {
    "items": [
      {
        "id": 42,
        "action": "login",
        "module": "auth",
        "reference_id": null,
        "detail": null,
        "ip_address": "127.0.0.1",
        "user_agent": "Mozilla/5.0 ...",
        "created_at": "2026-04-21 09:15:30",
        "user_name": "Administrator",
        "user_email": "admin@apresiasi.test"
      }
    ],
    "total": 200,
    "page": 1,
    "per_page": 25
  }
}
GET
/audit-logs/export?export_token={token}

Download CSV. Gunakan Export Token (seksi Export Tokens). Maks 10.000 baris.

GET /audit-logs/actions — Daftar nilai action unik untuk dropdown filter
GET /audit-logs/modules — Daftar nilai module unik untuk dropdown filter

10. Widget (Public)

Public Endpoint yang dipanggil JavaScript widget di website mitra. Tidak perlu JWT. Validasi dilakukan via domain (tabel websites).

Development / Simulasi: Jika domain belum terdaftar di DB dan APP_DEBUG=true, server akan fallback ke website pertama yang aktif — memudahkan testing lokal. Di production (APP_DEBUG=false) domain wajib terdaftar.
POST /widget/init

Inisialisasi widget: validasi domain, return config (nominal, nama app).

{ "domain": "beritaxyz.com" }

Response 200

{
  "status": true,
  "data": {
    "website_id": 1,
    "website_name": "Portal Berita XYZ",
    "app_name": "Apresiasi Mitra Promedia",
    "amounts": [5000, 10000, 20000, 50000, 100000],
    "tax_percent": 11
  }
}
POST /widget/create-transaction

Buat transaksi baru. Transaksi selalu tersimpan ke DB terlebih dahulu, lalu API Xendit dipanggil untuk generate QR code. Jika Xendit key belum valid, transaksi tetap tersimpan dengan qris_url kosong.

{
  "website_id": 1,
  "amount": 20000,
  "payment_method": "gopay",
  "donor_name": "John Doe",
  "donor_email": "john@email.com",
  "article_url": "https://beritaxyz.com/artikel-1",
  "article_title": "Judul Artikel",
  "author_name": "Nama Penulis"
}

Response 201

{
  "status": true,
  "code": 201,
  "message": "Transaksi berhasil dibuat",
  "data": {
    "invoice_no": "APR-20260421-A1B2C3D4",
    "transaction_id": 12,
    "amount": 20000,
    "tax_amount": 2200,
    "qris_string": "00020101021226...",
    "expired_at": "2026-04-21 10:00:00",
    "payment_url": "https://apresiasi.test/widget/payment.php?invoice=APR-20260421-A1B2C3D4"
  }
}
GET /widget/check-status/{invoice_no}

Polling status pembayaran, dipanggil setiap 3 detik oleh halaman payment. Auto-expire jika sudah melewati expired_at.

{
  "status": true,
  "data": {
    "invoice_no": "APR-20260421-A1B2C3D4",
    "status": "pending",
    "amount": 20000,
    "donor_name": "John Doe",
    "paid_at": null,
    "expired_at": "2026-04-21 10:00:00"
  }
}

11. Webhooks

POST /webhooks/payment

Endpoint callback dari Xendit. Konfigurasi URL ini di dashboard Xendit sebagai Webhook URL.

Verifikasi menggunakan header x-callback-token yang dicocokkan dengan nilai XENDIT_WEBHOOK_TOKEN di .env.

Event yang di-handle

Event / Status XenditStatus InternalEfek
qr.paymentpaidUpdate status + catat paid_at
status = COMPLETED / PAID / SUCCEEDEDpaidUpdate status + catat paid_at
status = EXPIRED / FAILEDexpired / failedUpdate status saja

URL yang perlu dikonfigurasi di Xendit

https://apresiasi.test/api/index.php?route=webhooks/payment

10. Reports

Laporan agregasi transaksi berdasarkan artikel, penulis, atau website. Permission: transactions.view / transactions.export.

GET /reports AUTH

List data yang di-group berdasarkan artikel, penulis, atau website.

ParameterTipeKeterangan
group_bystringarticle (default) | author | website
website_idintegerFilter per website (admin only)
authorstringFilter nama penulis (LIKE)
date_fromdateFilter tanggal mulai (Y-m-d)
date_todateFilter tanggal akhir (Y-m-d)
pageintegerNomor halaman (default: 1)
per_pageintegerData per halaman (default: 15)
GET /reports?group_by=author&date_from=2026-04-01&date_to=2026-04-30

{
  "status": true,
  "data": {
    "items": [
      {
        "author_name": "Ahmad Fauzi Santoso",
        "article_count": 3,
        "trx_count": 12,
        "paid_count": 8,
        "total_gross": 80000,
        "total_net": 71200,
        "total_website": 35600,
        "total_platform": 35600
      }
    ],
    "total": 1,
    "page": 1,
    "per_page": 15,
    "total_pages": 1
  }
}
GET /reports/summary AUTH

Ringkasan statistik dari hasil filter aktif (total transaksi, pendapatan, pembagian).

Parameter filter sama dengan GET /reports (kecuali group_by, page, per_page).

GET /reports/summary?date_from=2026-04-01&date_to=2026-04-30

{
  "status": true,
  "data": {
    "total_transactions": 20,
    "paid_count": 15,
    "pending_count": 3,
    "expired_count": 2,
    "author_count": 5,
    "article_count": 8,
    "website_count": 2,
    "total_gross": 150000,
    "total_tax": 16500,
    "total_net": 133500,
    "total_website": 66750,
    "total_platform": 66750
  }
}
GET /reports/export?export_token={token}&group_by={type} EXPORT TOKEN

Download CSV laporan. Gunakan export token one-time (POST ke /export-tokens terlebih dahulu).

// 1. Dapatkan export token
POST /export-tokens
{ "endpoint": "reports/export", "params": { "group_by": "author", "date_from": "2026-04-01" } }

// 2. Download CSV
GET /reports/export?export_token=TOKEN&group_by=author&date_from=2026-04-01

© 2026 Apresiasi Mitra Promedia

API v1.1  ·  Last updated Apr 2026

Widget Integration

Panduan memasang widget apresiasi di website mitra.

Cara Pasang Widget di Website

1. Tambahkan Script

Letakkan sebelum tag </body>:

<script src="https://apresiasi.test/widget/apresiasi-widget.js"></script>

2. Tambahkan Tombol Apresiasi

Tambahkan class obj-apresiasi-promedia pada element apapun:

<a href="#"
   class="obj-apresiasi-promedia"
   data-url="https://web.com/artikel-1"
   data-title="Judul Artikel"
   data-author="Nama Penulis">
  Beri Apresiasi
</a>

Data Attributes

AttributeKeterangan
data-urlURL artikel (default: URL halaman saat ini)
data-titleJudul artikel (default: document.title)
data-authorNama penulis

Prasyarat

3. Daftarkan Domain di CMS

Website wajib didaftarkan terlebih dahulu oleh admin melalui menu Websites di CMS. Domain yang didaftarkan harus cocok dengan domain tempat widget dipasang (misal beritaxyz.com).

Development / testing: Jika APP_DEBUG=true di .env dan domain belum terdaftar, server akan otomatis fallback ke website pertama yang aktif di database. Ini memudahkan pengujian lokal tanpa perlu mendaftarkan domain localhost atau apresiasi.test.

4. Whitelist CORS (untuk lingkungan production)

Pastikan domain website mitra sudah ditambahkan ke CORS_ALLOWED_ORIGINS di .env server:

[security]
CORS_ALLOWED_ORIGINS=https://apresiasi.test,https://beritaxyz.com,https://www.beritaxyz.com

Browser akan memblok request dari origin yang tidak terdaftar. Setiap subdomain perlu didaftarkan secara terpisah.


Flow Pembayaran

1. User klik tombol .obj-apresiasi-promedia
        ↓
2. Widget call POST /widget/init (validasi domain, ambil config)
        ↓
3. Popup terbuka — Step 1: pilih nominal apresiasi
        ↓
4. Step 2: pilih metode QRIS + isi nama & email (opsional)
        ↓
5. Klik "Lanjutkan Pembayaran"
   → Widget call POST /widget/create-transaction
   → Transaksi tersimpan di DB (status: pending)
   → Xendit API dipanggil untuk generate QR string
        ↓
6. Buka halaman payment.php?invoice=APR-xxx di tab baru
   → Tampil QR code (render dari qr_string Xendit)
   → Countdown timer berjalan
   → Polling GET /widget/check-status/{invoice} tiap 3 detik
        ↓
7. Setelah scan & bayar:
   → Xendit kirim webhook ke POST /webhooks/payment
   → Status transaksi update ke "paid"
   → Halaman payment auto-refresh → tampil pesan sukses

Halaman Payment

URL: https://apresiasi.test/widget/payment.php?invoice={invoice_no}


Simulasi Tanpa Payment Gateway

Untuk testing end-to-end sebelum Xendit API key tersedia:

  1. Pastikan APP_DEBUG=true di .env
  2. Pastikan ada minimal 1 row aktif di tabel websites
  3. Buka https://apresiasi.test/widget/index.html (halaman demo artikel)
  4. Klik "Beri Apresiasi" — widget akan berinteraksi dengan API nyata
  5. Transaksi tersimpan ke DB dengan status pending dan qris_url kosong
  6. Halaman payment tampil dengan placeholder QR

Tidak diperlukan modifikasi kode apapun — simulasi berjalan otomatis selama APP_DEBUG=true.


Pengaturan Xendit (Production)

  1. Login ke dashboard.xendit.co
  2. Buat akun dan dapatkan Secret API Key
  3. Set Webhook URL: https://apresiasi.test/api/index.php?route=webhooks/payment
  4. Copy Webhook Verification Token
  5. Update .env:
[payment]
XENDIT_SECRET_KEY=xnd_production_xxxxx
XENDIT_WEBHOOK_TOKEN=your_webhook_token
XENDIT_IS_PRODUCTION=true

Troubleshooting

MasalahPenyebabSolusi
Widget tidak muncul / tidak bisa diklik widgetConfig null (init gagal) Pastikan domain terdaftar di DB atau APP_DEBUG=true
Request diblok browser (CORS error) Domain tidak ada di whitelist Tambahkan domain ke CORS_ALLOWED_ORIGINS di .env
Halaman payment: Invoice tidak ditemukan create-transaction gagal sebelum redirect Cek network tab browser untuk error dari API
QR tidak muncul, placeholder tampil XENDIT_SECRET_KEY belum diisi / masih dummy Normal untuk simulasi. Isi key valid untuk production
Transaksi tidak masuk DB Domain widget/init gagal (403) Daftarkan domain di CMS, atau aktifkan APP_DEBUG=true

© 2026 Apresiasi Mitra Promedia

Widget Integration Guide  ·  Apr 2026