Portal NewsAPI Documentationv1← Ke website

Pengenalan

API ini memungkinkan aplikasi lain (skrip otomatis, CMS pihak ketiga, automation tool, atau layanan AI) membuat artikel dan mengunggah gambar ke Portal News tanpa membuka panel CMS. Semua permintaan dan respons memakai JSON.

Base URL

https://haitangerang.com/api/v1

Mulai cepat

  1. Minta administrator membuka CMS → User → Edit pada akun Anda, lalu di kartu API Key klik Buat API Key. Salin key-nya, karena hanya tampil sekali.
  2. Simpan key sebagai variabel lingkungan, misalnya API_KEY. Jangan menaruhnya di kode front-end atau repositori publik.
  3. Cek key dengan memanggil GET /me, lalu kirim artikel pertama dengan POST /articles.
curl "https://haitangerang.com/api/v1/me" \
  -H "Authorization: Bearer $API_KEY"

Autentikasi

Kirim API key pada setiap permintaan lewat header Authorization dengan skema Bearer. Header X-API-Key: <key> juga diterima sebagai alternatif.

Header
Authorization: Bearer pn_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • Key diawali pn_live_ dan terikat pada satu user. Artikel yang dibuat tercatat atas nama user tersebut.
  • Key memiliki izin yang sama dengan pemiliknya. Contoh: user dengan level Author hanya bisa membuat draft, sedangkan Editor boleh langsung mempublikasikan.
  • Key bisa dicabut kapan saja dari halaman edit user. Key juga berhenti berfungsi jika akun pemiliknya dinonaktifkan.
  • Di server kami hanya tersimpan hash dari key. Jika key hilang, buat yang baru.

Format & rate limit

  • Kirim body JSON dengan header Content-Type: application/json (kecuali unggah gambar yang memakai multipart/form-data).
  • Semua respons berbentuk { "success": true | false, ... }.
  • Waktu memakai ISO 8601 (UTC pada respons). Untuk scheduled_at sertakan zona waktu, mis. +07:00.
  • Batas 60 permintaan per menit per API key. Sisa kuota ada di header X-RateLimit-Limit dan X-RateLimit-Remaining. Jika terlampaui Anda menerima 429 beserta header Retry-After (detik).

Kode error

Saat gagal, respons berformat:

Respons error
{
  "success": false,
  "message": "Validasi gagal.",
  "errors": { "title": "title wajib diisi." }
}
400Body bukan JSON/multipart yang valid.
401API key tidak ada, tidak valid, atau sudah dicabut.
403Akun pemilik tidak aktif, atau tidak punya izin untuk aksi tersebut (mis. mempublikasikan).
422Data tidak lolos validasi. Rinciannya ada di objek errors per field.
429Rate limit terlampaui. Tunggu sesuai header Retry-After.
500Kesalahan di server. Coba lagi nanti.

GET /me

GET/api/v1/meIzin: (key valid)

Menampilkan pemilik key dan daftar izinnya. Berguna untuk memverifikasi bahwa key bekerja.

curl "https://haitangerang.com/api/v1/me" \
  -H "Authorization: Bearer $API_KEY"
Respons 200
{
  "success": true,
  "data": {
    "id": 3,
    "name": "Redaksi Bot",
    "username": "bot",
    "email": "bot@example.com",
    "access_level": "Editor",
    "permissions": ["articles.view", "articles.create", "articles.publish", "media.upload"]
  }
}

GET /categories

GET/api/v1/categoriesIzin: articles.create

Daftar kategori aktif. Gunakan id atau slug-nya pada POST /articles.

curl "https://haitangerang.com/api/v1/categories" \
  -H "Authorization: Bearer $API_KEY"
Respons 200
{
  "success": true,
  "data": [
    { "id": 1, "name": "Berita", "slug": "berita" },
    { "id": 2, "name": "Ekonomi", "slug": "ekonomi" }
  ]
}

GET /tags

GET/api/v1/tagsIzin: articles.create

Daftar tag aktif. Anda juga bisa langsung mengirim nama tag pada POST /articles tanpa memanggil endpoint ini.

curl "https://haitangerang.com/api/v1/tags" \
  -H "Authorization: Bearer $API_KEY"
Respons 200
{
  "success": true,
  "data": [{ "id": 5, "name": "Taman Kota", "slug": "taman-kota" }]
}

POST /media

POST/api/v1/mediaIzin: media.upload

Mengunggah satu gambar ke Media Library. Hasilnya (url) dipakai sebagai featured_image atau og_image. Format: JPG, PNG, WEBP, SVG; maksimal 5 MB. Gambar raster dikonversi ke WEBP dan ukurannya dibatasi 2400 px.

ParameterTipeKeterangan
fileWAJIBfile (multipart)Berkas gambar yang akan diunggah.
curl -X POST "https://haitangerang.com/api/v1/media" \
  -H "Authorization: Bearer $API_KEY" \
  -F "file=@./cover.jpg"
Respons 201
{
  "success": true,
  "message": "Gambar berhasil diupload",
  "data": {
    "id": 12,
    "url": "/uploads/2026/10/a1b2c3-taman-kota.webp",
    "absolute_url": "https://haitangerang.com/uploads/2026/10/a1b2c3-taman-kota.webp",
    "mime_type": "image/webp",
    "size": 184320,
    "width": 1600,
    "height": 900
  }
}

POST /articles

POST/api/v1/articlesIzin: articles.create

Membuat artikel baru atas nama pemilik key. Konten disanitasi di server (lihat Konten HTML), slug dibuat otomatis dari judul dan dijamin unik.

Body

ParameterTipeKeterangan
titleWAJIBstringJudul artikel, maks. 255 karakter.
contentstring (HTML)Isi artikel. Wajib terisi bila status bukan draft.
excerptstringRingkasan, maks. 1000 karakter. Jika kosong diambil dari 200 karakter pertama konten.
slugstringSlug kustom. Jika kosong dibuat dari judul; bila sudah dipakai ditambah akhiran -2, -3, dst.
statusdraft | published | scheduledDefault draft. published dan scheduled memerlukan izin articles.publish pada pemilik key.
scheduled_atstring (ISO 8601)Wajib bila status = scheduled. Harus di masa depan, mis. 2026-11-01T08:00:00+07:00. Artikel terbit otomatis pada waktu itu.
category_idintegerID kategori (lihat GET /categories).
categorystringSlug kategori. Alternatif dari category_id.
tagsstring[]Nama tag, maks. 10. Tag yang sudah ada dipakai ulang (tanpa membedakan huruf besar/kecil); tag baru dibuat jika pemilik key punya izin tags.create.
tag_idsinteger[]ID tag yang sudah ada, maks. 20.
featured_imagestringURL gambar utama: /uploads/... dari POST /media atau URL http(s).
is_featuredbooleanTampilkan di slider utama halaman depan. Default false.
meta_titlestringSEO title, maks. 200 karakter.
meta_descriptionstringSEO description, maks. 500 karakter.
meta_keywordsstringKata kunci dipisah koma.
canonical_urlstringURL kanonis (http/https).
og_title / og_description / og_imagestringOverride Open Graph untuk artikel ini.
curl -X POST "https://haitangerang.com/api/v1/articles" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Pemkot Resmikan Taman Kota Baru",
  "content": "<p>Taman seluas dua hektare itu resmi dibuka...</p><h2>Fasilitas</h2><p>Jogging track, area bermain...</p>",
  "excerpt": "Taman seluas dua hektare resmi dibuka untuk umum.",
  "status": "published",
  "category": "berita",
  "tags": ["Taman Kota", "Pemkot"],
  "featured_image": "/uploads/2026/10/a1b2c3-taman-kota.webp",
  "meta_title": "Taman Kota Baru Resmi Dibuka",
  "meta_description": "Pemkot meresmikan taman kota baru seluas dua hektare."
}'
Respons 201
{
  "success": true,
  "message": "Artikel berhasil dibuat",
  "data": {
    "id": 42,
    "title": "Pemkot Resmikan Taman Kota Baru",
    "slug": "pemkot-resmikan-taman-kota-baru",
    "status": "published",
    "url": "https://haitangerang.com/news/pemkot-resmikan-taman-kota-baru",
    "admin_url": "https://haitangerang.com/marimo/articles?edit=42",
    "published_at": "2026-10-29T13:45:10.000Z",
    "scheduled_at": null,
    "created_at": "2026-10-29T13:45:10.000Z"
  }
}

url bernilai null untuk draft karena artikel belum tampil publik. Header Location berisi alamat artikel.

Contoh respons 422
{
  "success": false,
  "message": "Validasi gagal.",
  "errors": {
    "title": "title wajib diisi.",
    "scheduled_at": "scheduled_at harus ISO 8601 dengan zona waktu, mis. 2026-11-01T08:00:00+07:00."
  }
}

Konten HTML

Field content berisi HTML. Demi keamanan, server membersihkan konten sebelum disimpan: tag, atribut, dan skema URL di luar daftar berikut dibuang (termasuk <script>, atribut on*, dan tautan javascript:).

  • Tag: h2 h3 h4 p br hr strong b em i u s a ul ol li blockquote pre code img figure figcaption div span, serta iframe hanya untuk YouTube dan Vimeo.
  • Atribut: href (+ target, rel) pada link, src alt width height pada gambar, dan text-align pada gaya.
  • Skema URL: http, https, mailto, tel. Link eksternal otomatis dibuka di tab baru dengan rel="noopener noreferrer".
  • Gunakan <h2> dan seterusnya untuk subjudul. Judul utama (h1) berasal dari field title.

Changelog

  • v1: rilis awal dengan /me, /categories, /tags, /media, dan /articles (POST).