Menelusuri seluruh notulen milik pemilik API key, terbaru lebih dulu, dengan paginasi cursor. Transkrip TIDAK PERNAH disertakan di sini karena ukurannya bisa ratusan kilobyte per baris; ambil lewat GET /notes/{id}?include=transcript kalau memang dibutuhkan. Filter status berguna untuk memantau antrean: recording_ready dan processing berarti pekerjaan masih berjalan, completed berarti hasilnya siap diambil, dan failed berarti perlu dilihat failure_code-nya. Parameter q mencari di judul dan ringkasan, tidak di dalam transkrip.
#Endpoint
GET https://se-hari.com/api/v1/notesButuh scope notulen:read. Scope ditetapkan saat key dibuat dan tidak bisa ditambahkan belakangan — kalau key Anda kurang izin, buat key baru lalu cabut yang lama. Kekakuan ini disengaja: scope yang bisa dinaikkan diam-diam berarti key yang bocor hari ini bisa menjadi lebih berbahaya besok. Beri setiap integrasi key sendiri dengan scope sesempit mungkin, supaya mencabut satu integrasi tidak pernah berarti mematikan yang lain.
Daftar ini memakai paginasi cursor, bukan offset. Ambil next_cursor dari respons lalu kirim kembali sebagai starting_after untuk halaman berikutnya, dan berhenti saat has_more bernilai false. Cursor dipilih karena offset melewatkan baris begitu ada data baru masuk di tengah penelusuran — pada daftar yang bertambah setiap hari itu bukan kasus langka melainkan kejadian harian, dan gejalanya adalah baris yang hilang tanpa satu pun error.
Filter tanggal menerima ISO-8601. Perlu diingat seluruh jadwal Se-Hari memakai zona WIB (UTC+7): meeting yang tampil pukul 09:00 di dashboard adalah 02:00 UTC, dan menyaring dengan tanggal UTC polos akan memotong tujuh jam pertama setiap hari tanpa memberi tahu Anda.
#Parameter query
| Parameter | Tipe | Wajib | Keterangan |
|---|---|---|---|
limit | integer | ya | Jumlah baris per halaman (1-100). min 1, maks 100 |
starting_after | string | tidak | — |
status | pending | recording_ready | processing | completed | failed | tidak | — |
q | string | tidak | min 1 karakter, maks 120 karakter |
from | string | tidak | Timestamp ISO-8601, contoh 2026-08-01T00:00:00Z |
to | string | tidak | Timestamp ISO-8601, contoh 2026-08-01T00:00:00Z |
#Contoh
curl -X GET "https://se-hari.com/api/v1/notes?limit=10&starting_after=nilai" \
-H "Authorization: Bearer $SEHARI_API_KEY"const res = await fetch('https://se-hari.com/api/v1/notes', {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.SEHARI_API_KEY}`,
}
});
if (!res.ok) {
const { error } = await res.json();
// error.code stabil dan bisa dicabang; error.message untuk manusia.
throw new Error(`${error.code}: ${error.message}`);
}
const data = await res.json();import os, requests
res = requests.get(
"https://se-hari.com/api/v1/notes",
headers={"Authorization": f"Bearer {os.environ['SEHARI_API_KEY']}"},
timeout=30,
)
if not res.ok:
err = res.json()["error"]
raise RuntimeError(f"{err['code']}: {err['message']}")
data = res.json()#Field tiap item di `data`
| Field | Tipe | Keterangan |
|---|---|---|
id | string | — |
title | string | — |
status | string | — |
source_type | string | — |
job_source | string | null | — |
recording_id | string | null | — |
meeting_id | string | null | — |
meeting_date | string | — |
duration_minutes | number | null | — |
speaker_count | number | null | — |
word_count | number | null | — |
language | string | null | — |
transcript_source | string | null | — |
processing_stage | string | null | — |
attempts | integer | — |
credits_deducted | number | null | — |
failure_code | string | null | — |
error_message | string | null | — |
created_at | string | — |
updated_at | string | — |
#Menelusuri semua halaman
Satu request hanya mengembalikan maksimum 100 baris. Untuk mengambil semuanya, ikuti next_cursor sampai has_more bernilai false — jangan menghitung sendiri posisinya.
async function ambilSemua() {
const semua = [];
let cursor = null;
do {
const qs = new URLSearchParams({ limit: "100" });
if (cursor) qs.set("starting_after", cursor);
const res = await fetch(`https://se-hari.com/api/v1/notes?${qs}`, {
headers: { Authorization: `Bearer ${process.env.SEHARI_API_KEY}` }
});
const page = await res.json();
semua.push(...page.data);
cursor = page.has_more ? page.next_cursor : null;
} while (cursor);
return semua;
}#Kalau gagal
Setiap kegagalan memakai amplop yang sama, dan code di dalamnya stabil — cabangkan logika Anda ke sana, jangan ke message yang teksnya bisa diperbaiki sewaktu-waktu.
{
"error": {
"code": "invalid_parameter",
"message": "Penjelasan untuk manusia.",
"docs_url": "https://se-hari.com/docs/error/invalid-parameter",
"request_id": "req_a1b2c3d4e5f6",
"details": {}
}
}| Status | Kode | Artinya di endpoint ini |
|---|---|---|
| 400 | invalid_parameter | Ada parameter query yang salah bentuk atau di luar rentang. |
| 401 | invalid_api_key | Key salah, sudah dicabut, atau kedaluwarsa. |
| 403 | insufficient_scope | Key valid, tapi tidak punya scope yang dibutuhkan endpoint ini. |
| 429 | rate_limited | Terlalu banyak request. Hormati header Retry-After. |
| 500 | internal_error | Kesalahan di sisi kami. Sertakan request_id saat melapor. |
Simpan request_id dari setiap respons gagal. Itu satu-satunya cara kami menemukan kembali request Anda di log ketika Anda melapor, dan ia juga ada di header X-Request-Id pada respons yang berhasil. |
#Alur khas
Notulen selalu berawal dari sebuah rekaman. Rekaman itu bisa datang sendiri (meeting Zoom yang direkam diarsipkan otomatis) atau Anda unggah sendiri. Setelah rekaman ada, pembuatan notulen berjalan asinkron: endpoint mengantre pekerjaan lalu langsung menjawab, dan hasilnya menyusul beberapa menit kemudian.
GET /recordings?has_note=false— cari rekaman yang belum pernah diprosesPOST /notesdenganrecording_iddari langkah 1 — antrekan pekerjaannya- Tunggu webhook
note.completed, atau pollingGET /notes/{id}sampaistatusmenjadicompleted GET /notes/{id}?include=summary,action_items— ambil hasilnya
Polling bukan pilihan pertama. Rekaman satu jam butuh beberapa menit untuk diproses, dan menanyakan statusnya setiap detik hanya menghabiskan kuota rate limit Anda. Daftarkan webhook note.completed sekali, lalu biarkan Se-Hari yang memberi tahu.
#Yang sering keliru
- Key disalin sebagian. API key Se-Hari panjangnya tetap:
sh_live_diikuti 43 karakter. Kalau panjangnya berbeda, yang salah adalah proses penyalinannya, bukan key-nya — dan pesan 401 tidak akan mengatakan itu. - Scope kurang, bukan key salah. 403 di sini berarti key-nya dikenali. Periksa scope-nya lewat
GET /me, lalu buat key baru kalau memang kurang; scope tidak bisa ditambahkan ke key yang sudah jadi. - Hormati
Retry-After. Mencoba lagi lebih cepat dari yang disebutkan hanya memperpanjang masa tunggu. Kalau Anda sering menyentuhnya, kemungkinan besar Anda sedang polling sesuatu yang seharusnya ditangani webhook.
#Selanjutnya
- Autentikasi dan API key — cara membuat key dan memilih scope
- Kode error — arti setiap kode dan cara memperbaikinya
- Idempotency — kenapa retry aman kalau dilakukan dengan benar
- Spesifikasi OpenAPI — kontrak mesin, cocok untuk men-generate klien