1. Panduan Pengguna (UI)

1.1 Dashboard

Halaman utama setelah login (/dashboard).

Fitur:

1.2 Manajemen Kontak

URL: /contacts

Fitur

Import CSV

Header: name, phone, email, company, tags, notes
Baris:  John Doe,6281234567890,john@mail.com,ACME Corp,premium,Customer baru

Webhook

POST /api/webhooks/lists/{listId}?token={jwt}
{ "name": "...", "phone": "62812...", "email": "...", "company": "...", "tags": "...", "notes": "..." }

1.3 WhatsApp

URL: /whatsapp

1.3.1 Device Management

1.3.2 Broadcast WA

URL: /whatsapp/broadcasts

1.3.3 Jadwal WA

URL: /whatsapp/schedules

1.4 Email

URL: /email

1.4.1 Akun & Domain

1.4.2 Broadcast Email

URL: /email/broadcasts

1.4.3 Konfigurasi Email Client

URL: /email/config

Informasi SMTP/IMAP untuk menggunakan email client eksternal (Outlook, Thunderbird, dll):

1.5 Auto Copy Funnel

URL: /funnels

Fitur unggulan — rangkaian pesan otomatis multi-channel dengan bantuan AI.

1.5.1 Membuat Funnel

  1. Buka Funnels → Buat Funnel
  2. Isi: nama, goal, deskripsi produk, target audience, channel (WA/Email/Campuran), jumlah pesan, nada bicara
  3. Klik Generate dengan AI
  4. Review hasil generate, edit jika perlu, lalu simpan

Contoh hasil AI:

Step 1 (WA) — Langsung dikirim
  "Halo {nama}! Masih ingat dengan {produk}? Ada penawaran spesial!"
  Delay: 0 detik | Kondisi: sent

Step 2 (Email) — +1 hari
  Subject: Tips maksimalin {produk}
  "Halo {nama}, kami punya tips..."
  Delay: 86400 detik | Kondisi: timeout

1.5.2 Aktivasi Funnel

  1. Pilih target: Contact list atau Form Opt-in
  2. Klik Aktivasi
  3. Sistem enroll contacts & jalankan step otomatis via queue

1.5.3 Analytics

URL: /funnels/{id}/analytics

Statistik: total sent, opened, clicked, converted per step + activity log.

1.6 Landing Pages

URL: /landing-pages

1.7 Form Opt-in

URL: /form-optins

<div id="ngirimpesan-form-{formId}"></div>
<script src="{app_url}/public/form-embed.js" data-form-id="{formId}"></script>

1.8 Pricing & Subscription

URL: /pricing

1.9 Admin Panel

URL: http://admin.ngirimpesan.id:6060

1.10 Webmail

URL: /mailbox/{accountId}

Webmail client: inbox, sent, compose, vacation auto-reply, filters.


2. Dokumentasi API

2.1 API Server

Ngirimpesan memiliki API server terpisah untuk integrasi eksternal:

ServerPortAuthDigunakan Untuk
Main App5555Cookie auth_idInertia SPA pages (Dashboard, dll)
API Server5566Authorization: Bearer <token>Integrasi eksternal (semua endpoint /api/*)

Base URL API Server: https://api.ngirimpesan.id

Semua endpoint /api/* di bawah menggunakan API server dengan Bearer token.

Endpoint tanpa prefix /api/ (misal /contacts/store, /whatsapp/broadcast) hanya tersedia di Main App (port 5555) dengan cookie auth — digunakan oleh Inertia UI, bukan untuk integrasi eksternal.

2.2 Autentikasi

Login (Web UI)

POST /login
Content-Type: application/json

{ "email": "user@example.com", "password": "password123" }

Response: 302 Found dengan cookie auth_id={jwt}

Register

POST /register
Content-Type: application/json

{
  "name": "John Doe",
  "email": "john@example.com",
  "password": "password123",
  "password_confirmation": "password123"
}

Google OAuth

GET /google/redirect          → Redirect ke Google login
GET /google/callback?code=xxx → Proses callback

Verify Email

GET /verify-email/{token}
POST /verify-email/resend

Password Reset

POST /forgot-password
{ "email": "user@example.com" }

POST /reset-password
{ "token": "...", "password": "newpassword", "password_confirmation": "newpassword" }

API Token Authentication

Untuk mengakses API server (port 5566), gunakan Authorization: Bearer header:

GET /api/funnels
Authorization: Bearer np_a1b2c3d4e5f6...

Token didapatkan dari halaman Profile → API Tokens di aplikasi utama.

2.3 API Token Management

Kelola token API dari halaman Profile atau via endpoint berikut (cookie auth di port 5555):

List Tokens

GET /api/tokens

Response:

{
  "success": true,
  "tokens": [
    { "id": "uuid", "name": "Production API", "token_prefix": "np_a1b2c3d4...", "last_used_at": 1690000000, "created_at": 1690000000 }
  ]
}

Create Token

POST /api/tokens
{ "name": "Production API" }

Response: {"success": true, "token": {"id": "uuid", "name": "Production API", "token_prefix": "np_a1b2c3d4...", "plain_token": "np_a1b2c3d4e5f6..."}}

Penting: plain_token hanya ditampilkan sekali. Simpan di tempat aman.

Revoke Token

DELETE /api/tokens/{id}

Response: {"success": true}

2.4 Contacts API

Endpoint kontak tanpa prefix /api/ (seperti /contacts/store) menggunakan cookie auth di Main App (port 5555) — digunakan oleh Inertia UI.

Untuk integrasi eksternal, gunakan endpoint Webhook (/api/webhooks/...) di API server (port 5566) dengan Authorization: Bearer.

Create Contact

POST /contacts/store
Cookie: auth_id={token}

{
  "name": "John Doe",
  "phone": "6281234567890",
  "email": "john@example.com",
  "company": "ACME Corp",
  "tags": "premium",
  "notes": "Customer baru",
  "list_id": "uuid-list-id"
}

Response: {"success": true, "contact": {"id": "uuid", "name": "John Doe"}}

Note: Jika nomor sudah ada, data akan di-update (merge).

Update Contact

POST /contacts/{id}/update

Delete Contact

POST /contacts/{id}/destroy

Contact List

POST  /contacts/lists/store          → { "name": "...", "description": "..." }
POST  /contacts/lists/{id}/destroy
POST  /contacts/lists/{id}/members   → { "contact_ids": ["uuid1", "uuid2"] }
POST  /contacts/lists/{id}/members/{contactId}/remove
GET   /contacts/lists/{id}/members   → { "members": [...] }

Import CSV

POST /contacts/lists/{id}/import
Content-Type: multipart/form-data

File: data.csv (header: name,phone,email,company,tags,notes)

Response: {"success": true, "imported": 45, "failed": 2, "errors": [...]}

Webhook Add Member (API Server)

POST /api/webhooks/lists/{listId}?token={jwt}
Authorization: Bearer {your_api_token}

{ "name": "...", "phone": "62812...", "email": "...", "company": "...", "tags": "...", "notes": "..." }

Response: {"success": true, "contact_id": "uuid"}

2.5 WhatsApp API

Endpoint device & broadcast (tanpa prefix /api/) menggunakan cookie auth di Main App — digunakan oleh Inertia UI. Hanya callback WA server yang melalui API server.

Device (Main App — Cookie Auth)

GET   /whatsapp                     → Inertia page
POST  /whatsapp                     → { "name": "Marketing Device" }
POST  /whatsapp/{id}/activate       → { "status": "connecting", ... }
GET   /whatsapp/{id}/qr             → { "qr": "base64..." }
POST  /whatsapp/{id}/logout
POST  /whatsapp/{id}/destroy
POST  /whatsapp/{id}/test

Broadcast (Main App — Cookie Auth)

POST /whatsapp/broadcast
{
  "name": "Promo July",
  "wa_device_id": "device-uuid",
  "message": "Halo {nama}! Promo spesial...",
  "media_url": "https://...",
  "contact_list_id": "list-uuid",
  "contact_ids": ["uuid1"],
  "scheduled_at": "2026-07-22T10:00:00Z"
}

Response: {"success": true, "broadcast": {"id": "uuid", "status": "queued"}}

Schedule (Main App — Cookie Auth)

POST /whatsapp/schedule
{
  "name": "Weekly Newsletter",
  "whatsapp_id": "device-uuid",
  "message": "Halo {nama}!...",
  "contact_list_id": "list-uuid",
  "schedule_type": "repeating",
  "scheduled_at": "2026-07-22T08:00:00Z",
  "repeat_cron": "0 8 * * 1"
}

Callback dari WA Server (Public)

POST /api/whatsapp/notify
{ "id": "device-uuid", "status": "qr", "qr": "base64..." }

Status: qr, connected, sleep, restricted

SSE Real-time QR (Main App)

GET /whatsapp/sse

Server-Sent Events untuk streaming QR code.

Single Send (API Server — Bearer Token)

Kirim satu pesan WhatsApp ke satu nomor secara langsung:

POST /api/whatsapp/send
Authorization: Bearer {your_api_token}

{
  "wa_device_id": "device-uuid",
  "phone": "6281234567890",
  "message": "Halo {nama}! Promo spesial cuma hari ini!",
  "media_url": "https://example.com/image.jpg"    // optional
}

Response: {"success": true, "data": {...}}

Error: {"error": "WhatsApp device is not connected"} atau {"error": "Failed to send message", "detail": "..."}

2.6 Email API

Endpoint akun & domain (tanpa prefix /api/) menggunakan cookie auth di Main App. Berikut endpoint di API server:

Akun & Domain (Main App — Cookie Auth)

POST /email/accounts         → { "name": "...", "localPart": "info", "password": "...", "domain": "..." }
POST /email/accounts/{id}/destroy
POST /email/accounts/{id}/update
POST /email/accounts/{id}/test
POST /email/domains           → { "name": "mycompany.com" }
POST /email/domains/{id}/destroy
GET  /email/domains/{id}/dns
POST /email/domains/{id}/verify-dns

Broadcast (API Server — Bearer Token)

POST /api/email/broadcasts
Authorization: Bearer {your_api_token}

{
  "email_account_id": "uuid",
  "name": "Newsletter July",
  "subject": "Newsletter Bulan Ini",
  "text_body": "Halo {nama}!...",
  "html_body": "<h1>Halo {nama}</h1><p>...</p>",
  "from_name": "Info Perusahaan",
  "contact_list_id": "list-uuid",
  "contact_ids": ["uuid1"],
  "scheduled_at": "2026-07-25T09:00:00Z"
}
GET   /api/email/broadcasts
GET   /api/email/broadcasts/{id}
POST  /api/email/broadcasts/{id}/cancel

Schedule (API Server — Bearer Token)

POST /api/email/schedules
Authorization: Bearer {your_api_token}

{
  "email_account_id": "uuid",
  "name": "Monthly Newsletter",
  "subject": "...",
  "text_body": "...",
  "html_body": "...",
  "contact_list_id": "list-uuid",
  "schedule_type": "repeating",
  "scheduled_at": "2026-08-01T08:00:00Z",
  "repeat_cron": "0 8 1 * *"
}
GET    /api/email/schedules
GET    /api/email/schedules/{id}
PUT    /api/email/schedules/{id}
DELETE /api/email/schedules/{id}

Single Send (API Server — Bearer Token)

Kirim satu email ke satu alamat secara langsung (tidak melalui broadcast queue):

POST /api/email/send
Authorization: Bearer {your_api_token}

{
  "email_account_id": "account-uuid",
  "to": "user@example.com",
  "to_name": "John Doe",              // optional
  "subject": "Halo {nama}!",
  "text_body": "Halo John, ini pesan dari kami.",           // optional
  "html_body": "<h1>Halo John</h1><p>Ini pesan dari kami.</p>"  // optional
}

Response: {"success": true, "message": "Email sent successfully"}

Error: {"error": "Email quota exceeded", "quota": {...}} atau {"error": "Failed to send email", "detail": "..."}

Minimal salah satu dari text_body atau html_body harus diisi. Email dikirim langsung via SMTP ke server Stalwart tanpa melalui antrian.

2.7 Funnel API

Semua endpoint funnel menggunakan API server (port 5566) dengan Bearer token:

Generate dengan AI

POST /api/funnels/generate
Authorization: Bearer {your_api_token}
{
  "goal": "Konversi trial ke paid",
  "product_description": "Aplikasi kirim pesan otomatis",
  "audience": "Pemilik UKM",
  "messageCount": 4,
  "channel": "campuran",
  "tone": "santai"
}

Response:

{
  "success": true,
  "steps": [
    { "stepOrder": 1, "channel": "wa", "body": "Halo {nama}!...", "condition": "sent", "delaySeconds": 0 },
    { "stepOrder": 2, "channel": "email", "subject": "Tips...", "body": "...", "condition": "timeout", "delaySeconds": 86400 }
  ]
}

CRUD Funnel

Authorization: Bearer {your_api_token}

POST   /api/funnels                → Buat funnel (dengan steps)
GET    /api/funnels                → Daftar funnel
GET    /api/funnels/{id}           → Detail + steps
PUT    /api/funnels/{id}           → Update
DELETE /api/funnels/{id}           → Hapus
POST   /api/funnels/{id}/activate  → Aktifkan
POST   /api/funnels/{id}/pause     → Jeda
PUT    /api/funnels/{id}/steps/{stepId} → Update step

Create Funnel

POST /api/funnels
Authorization: Bearer {your_api_token}

{
  "name": "Konversi Trial",
  "goal": "Konversi trial ke paid",
  "product_description": "Aplikasi kirim pesan",
  "audience": "Pemilik UKM",
  "channel": "campuran",
  "tone": "santai",
  "contact_list_id": "list-uuid",
  "source_type": "contact_list",
  "steps": [
    { "stepOrder": 1, "channel": "wa", "condition": "sent", "delaySeconds": 0, "body": "Halo {nama}!...", "fallbackAction": null }
  ]
}

Analytics

GET /api/funnels/{id}/analytics
Authorization: Bearer {your_api_token}

Response:

{
  "summary": {
    "totalSent": 150,
    "totalOpened": 89,
    "totalClicked": 45,
    "totalConverted": 12,
    "steps": [
      { "stepOrder": 1, "channel": "wa", "sent": 150, "opened": 89, "clicked": 45, "converted": 12 }
    ],
    "recentActivity": [...]
  }
}

Templates

Authorization: Bearer {your_api_token}

POST   /api/funnels/templates   → Simpan template
GET    /api/funnels/templates   → Daftar template
GET    /api/funnels/templates/{id}
DELETE /api/funnels/templates/{id}

2.8 Landing Page API

Semua endpoint landing page menggunakan API server (port 5566) dengan Bearer token:

Generate dengan AI

POST /api/landing-pages/generate
{
  "title": "Aplikasi Kirim Pesan Otomatis",
  "description": "Kirim pesan WA & Email otomatis dengan AI",
  "audience": "Pemilik bisnis UKM",
  "colors": "biru",
  "style": "modern",
  "form_optin_id": "form-uuid"
}

Response: {"success": true, "html": "<script src=...><div...", "form_optin_id": "form-uuid"}

CRUD

Authorization: Bearer {your_api_token}

POST   /api/landing-pages    → { "title": "...", "slug": "...", "html_content": "...", "form_optin_id": "..." }
PUT    /api/landing-pages/{id}
DELETE /api/landing-pages/{id}
POST   /api/landing-pages/{id}/publish

Public Preview

GET /lp/{slug}   → HTML (public, no auth)

2.9 Form Opt-in API

Endpoint CRUD menggunakan API server (port 5566) dengan Bearer token. Endpoint embed & submit bersifat publik (CORS).

CRUD

Authorization: Bearer {your_api_token}

POST   /api/form-optins
{
  "name": "Form Download Ebook",
  "description": "...",
  "fields": "[{\"key\":\"name\",\"label\":\"Nama\",\"type\":\"text\",\"required\":true},{\"key\":\"email\",\"label\":\"Email\",\"type\":\"email\",\"required\":true}]",
  "redirect_url": "https://example.com/thanks",
  "submit_button_text": "Download",
  "success_message": "Terima kasih!",
  "list_id": "list-uuid",
  "is_active": 1
}

PUT    /api/form-optins/{id}
DELETE /api/form-optins/{id}

Leads

GET /api/form-optins/{id}/leads?page=1&limit=50

Response:

{
  "leads": [{ "id": "uuid", "data": "{...}", "parsed_data": {...}, "ip_address": "...", "created_at": "..." }],
  "pagination": { "page": 1, "limit": 50, "total": 120, "totalPages": 3 }
}

Embed (Public, CORS)

GET /api/form-optins/{id}/embed?access_key=xxx

Response: {"id": "...", "name": "...", "fields": [...], "submit_button_text": "...", "success_message": "..."}

Submit (Public, CORS)

POST /api/form-optins/{id}/submit
{ "name": "John", "email": "john@mail.com", "phone": "6281234567890" }

Response: {"success": true, "message": "Terima kasih!", "redirect_url": "https://..."}

2.10 Admin API

Admin panel berjalan di Main App (port 6060). Semua endpoint admin membutuhkan cookie auth_id dengan is_admin: true.

Dashboard

GET /admin/api/dashboard/stats

Users

GET    /admin/users
GET    /admin/users/{id}
POST   /admin/api/users/{id}/plan           → { "plan_id": "uuid" }
POST   /admin/api/users/{id}/limits         → { "whatsapp_limit": 10, "email_accounts_limit": 50, ... }
POST   /admin/api/users/{id}/toggle
POST   /admin/api/users/{id}/toggle-admin
DELETE /admin/api/users/{id}

Plans

GET    /admin/plans
POST   /admin/api/plans
{
  "name": "Pro",
  "price": 150000,
  "whatsapp_limit": 5,
  "email_accounts_limit": 20,
  "email_domains_limit": 3,
  "email_messages_limit": 5000,
  "broadcasts_limit_per_month": 5000,
  "funnels_limit": 10
}

PUT    /admin/api/plans/{id}
DELETE /admin/api/plans/{id}

Mail Server

GET    /admin/api/mail/stats
GET    /admin/api/mail/domains
POST   /admin/api/mail/domains    → { "name": "example.com", "description": "..." }
DELETE /admin/api/mail/domains/{id}
GET    /admin/api/mail/domains/{id}/dns-zone
GET    /admin/api/mail/domains/{id}/accounts

2.11 Upload API

Upload & S3 endpoint menggunakan API server (port 5566) dengan Bearer token:

POST /api/upload/image   (multipart) → Upload & proses gambar (sharp)
POST /api/upload/file    (multipart) → Upload file (PDF, DOC, XLS)

S3

Authorization: Bearer {your_api_token}

POST /api/s3/signed-url    → { "fileName": "...", "contentType": "..." }
GET  /api/s3/public-url/{fileKey}
GET  /api/s3/health