API ini memungkinkan aplikasi lain (skrip otomatis, CMS pihak ketiga, automation tool, atau layanan AI) membuat artikel dan mengunggah gambar ke Haijakarta.id tanpa membuka panel CMS. Semua permintaan dan respons memakai JSON.
Base URL
https://staging.haijakarta.id/api/v1API_KEY. Jangan menaruhnya di kode front-end atau repositori publik.GET /me, lalu kirim artikel pertama dengan POST /articles.curl "https://staging.haijakarta.id/api/v1/me" \
-H "Authorization: Bearer $API_KEY"Kirim API key pada setiap permintaan lewat header Authorization dengan skema Bearer. Header X-API-Key: <key> juga diterima sebagai alternatif.
Authorization: Bearer pn_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxpn_live_ dan terikat pada satu user. Artikel yang dibuat tercatat atas nama user tersebut.Content-Type: application/json (kecuali unggah gambar yang memakai multipart/form-data).{ "success": true | false, ... }.scheduled_at sertakan zona waktu, mis. +07:00.X-RateLimit-Limit dan X-RateLimit-Remaining. Jika terlampaui Anda menerima 429 beserta header Retry-After (detik).Saat gagal, respons berformat:
{
"success": false,
"message": "Validasi gagal.",
"errors": { "title": "title wajib diisi." }
}| 400 | Body bukan JSON/multipart yang valid. |
| 401 | API key tidak ada, tidak valid, atau sudah dicabut. |
| 403 | Akun pemilik tidak aktif, atau tidak punya izin untuk aksi tersebut (mis. mempublikasikan atau membuat kategori baru). |
| 422 | Data tidak lolos validasi. Rinciannya ada di objek errors per field. |
| 429 | Rate limit terlampaui. Tunggu sesuai header Retry-After. |
| 500 | Kesalahan di server. Coba lagi nanti. |
/api/v1/meIzin: (key valid)Menampilkan pemilik key dan daftar izinnya. Berguna untuk memverifikasi bahwa key bekerja.
curl "https://staging.haijakarta.id/api/v1/me" \
-H "Authorization: Bearer $API_KEY"{
"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"]
}
}/api/v1/categoriesIzin: articles.createDaftar kategori aktif. Gunakan id atau slug-nya pada POST /articles.
curl "https://staging.haijakarta.id/api/v1/categories" \
-H "Authorization: Bearer $API_KEY"{
"success": true,
"data": [
{ "id": 1, "name": "Berita", "slug": "berita" },
{ "id": 2, "name": "Ekonomi", "slug": "ekonomi" }
]
}/api/v1/mediaIzin: media.uploadMengunggah 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.
| Parameter | Tipe | Keterangan |
|---|---|---|
fileWAJIB | file (multipart) | Berkas gambar yang akan diunggah. |
curl -X POST "https://staging.haijakarta.id/api/v1/media" \
-H "Authorization: Bearer $API_KEY" \
-F "file=@./cover.jpg"{
"success": true,
"message": "Gambar berhasil diupload",
"data": {
"id": 12,
"url": "/uploads/2026/10/a1b2c3-taman-kota.webp",
"absolute_url": "https://staging.haijakarta.id/uploads/2026/10/a1b2c3-taman-kota.webp",
"mime_type": "image/webp",
"size": 184320,
"width": 1600,
"height": 900
}
}/api/v1/articlesIzin: articles.createMembuat artikel baru atas nama pemilik key. Konten disanitasi di server (lihat Konten HTML), slug dibuat otomatis dari judul dan dijamin unik.
| Parameter | Tipe | Keterangan |
|---|---|---|
titleWAJIB | string | Judul artikel, maks. 255 karakter. |
content | string (HTML) | Isi artikel. Wajib terisi bila status bukan draft. |
excerpt | string | Ringkasan, maks. 1000 karakter. Jika kosong diambil dari 200 karakter pertama konten. |
slug | string | Slug kustom. Jika kosong dibuat dari judul; bila sudah dipakai ditambah akhiran -2, -3, dst. |
status | draft | published | scheduled | Default draft. published dan scheduled memerlukan izin articles.publish pada pemilik key. |
scheduled_at | string (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_id | integer | ID kategori (lihat GET /categories). |
category | string | Slug atau nama kategori (huruf besar/kecil dan spasi berlebih diabaikan). Jika belum ada, kategori dibuat otomatis asalkan pemilik key punya izin categories.create. Diabaikan bila category_id diisi. |
category_name | string | Alias dari category, maks. 120 karakter. |
tags | string[] | 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_ids | integer[] | ID tag yang sudah ada, maks. 20. |
featured_image | string | URL gambar utama: /uploads/... dari POST /media atau URL http(s). |
is_featured | boolean | Tampilkan di slider utama halaman depan. Default false. |
meta_title | string | SEO title, maks. 200 karakter. |
meta_description | string | SEO description, maks. 500 karakter. |
meta_keywords | string | Kata kunci dipisah koma. |
canonical_url | string | URL kanonis (http/https). |
og_title / og_description / og_image | string | Override Open Graph untuk artikel ini. |
curl -X POST "https://staging.haijakarta.id/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."
}'{
"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://staging.haijakarta.id/pemkot-resmikan-taman-kota-baru",
"admin_url": "https://staging.haijakarta.id/marimo/articles?edit=42",
"category": { "id": 7, "name": "Berita", "slug": "berita", "created": false },
"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.
Objek category pada respons menunjukkan kategori yang dipakai (null bila artikel dikirim tanpa kategori). created: true berarti kategori tersebut baru dibuat oleh permintaan ini. Aturannya:
Kesehatan Ibu, kesehatan ibu, dan kesehatan-ibu menunjuk ke kategori yang sama.categories.create, permintaan ditolak 403 dan tidak ada kategori yang dibuat. Memakai kategori yang sudah ada tetap diperbolehkan.{
"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."
}
}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:).
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.href (+ target, rel) pada link, src alt width height pada gambar, dan text-align pada gaya.http, https, mailto, tel. Link eksternal otomatis dibuka di tab baru dengan rel="noopener noreferrer".<h2> dan seterusnya untuk subjudul. Judul utama (h1) berasal dari field title./me, /categories, /tags, /media, dan /articles (POST).