se-hari.com se-hari.com

POST /notes/uploads

Siapkan unggahan rekaman. POST /notes/uploads — butuh scope notulen:write.

3 menit baca Diperbarui 15 Agustus 2026 Lihat sebagai Markdown

Langkah pertama dari alur unggah tiga tahap: presign, PUT, confirm. Endpoint ini membuat baris rekaman dan notulen, lalu mengembalikan URL bertanda tangan untuk melakukan PUT langsung ke penyimpanan objek. Byte file TIDAK PERNAH melewati server Se-Hari — batasnya 500 MB dan memuatnya ke memori akan menjatuhkan seluruh situs, bukan hanya request ini. Format yang didukung: mp3, m4a, wav, ogg, oga, flac, aac, webm, mp4, mov, mkv. Saat melakukan PUT, header Content-Type WAJIB sama persis dengan nilai content_type yang dikembalikan di sini; kalau berbeda, tanda tangannya tidak cocok dan penyimpanan menolak dengan 403. URL berlaku satu jam. Setelah PUT selesai, panggil endpoint confirm supaya notulen masuk antrean.

#Endpoint

bash
POST https://se-hari.com/api/v1/notes/uploads

Butuh scope notulen:write. 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. Kirim header Idempotency-Key berisi nilai unik milik Anda sendiri; UUID sudah cukup. Kalau request diulang dengan key yang sama — karena timeout jaringan, retry otomatis n8n, atau tombol yang terklik dua kali — kami mengembalikan hasil yang pertama alih-alih mengerjakannya lagi. Key yang sama dengan body berbeda ditolak idempotency_key_reused, karena itu hampir selalu berarti bug di sisi pemanggil, bukan permintaan yang sah. Operasi ini memakai kredit. Panggil POST /credits/estimate lebih dulu kalau perlu tahu biayanya di depan, dan pasang batas kredit harian pada API key di dashboard. Batas itu adalah pengaman termurah yang tersedia: kalau key bocor atau sebuah loop salah tulis, kerugian Anda berhenti di angka yang Anda tentukan sendiri, bukan di saldo yang habis.

#Body request

FieldTipeWajibKeterangan
file_namestringyamin 1 karakter, maks 200 karakter
size_bytesintegeryamin 1
duration_secondsintegertidakmin 1
titlestringtidakmin 1 karakter, maks 200 karakter
meeting_idstringtidak

#Contoh

bash
curl -X POST "https://se-hari.com/api/v1/notes/uploads" \
  -H "Authorization: Bearer $SEHARI_API_KEY"
javascript
const res = await fetch('https://se-hari.com/api/v1/notes/uploads', {
	method: 'POST',
	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();
python
import os, requests

res = requests.post(
    "https://se-hari.com/api/v1/notes/uploads",
    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 respons

FieldTipeKeterangan
upload_urlstring
content_typestring
recording_idstring
note_idstring | null
expires_ininteger

#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.

json
{
  "error": {
    "code": "invalid_request",
    "message": "Penjelasan untuk manusia.",
    "docs_url": "https://se-hari.com/docs/error/invalid-request",
    "request_id": "req_a1b2c3d4e5f6",
    "details": {}
  }
}
StatusKodeArtinya di endpoint ini
400invalid_requestBody tidak lolos validasi. Field yang bermasalah disebut di details.
401invalid_api_keyKey salah, sudah dicabut, atau kedaluwarsa.
403insufficient_scopeKey valid, tapi tidak punya scope yang dibutuhkan endpoint ini.
404not_foundData tidak ada, atau ada tapi milik akun lain — keduanya dijawab sama.
413file_too_largeUkuran berkas melebihi batas.
415unsupported_media_typeContent-Type tidak didukung.
429rate_limitedTerlalu banyak request. Hormati header Retry-After.
500internal_errorKesalahan di sisi kami. Sertakan request_id saat melapor.
503service_unavailableLayanan sedang tidak tersedia sementara.
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.

  1. GET /recordings?has_note=false — cari rekaman yang belum pernah diproses
  2. POST /notes dengan recording_id dari langkah 1 — antrekan pekerjaannya
  3. Tunggu webhook note.completed, atau polling GET /notes/{id} sampai status menjadi completed
  4. 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.
  • 404 tidak selalu berarti data tidak ada. Data milik akun lain juga dijawab 404, bukan 403 — kami tidak mengonfirmasi keberadaan id milik orang lain. Kalau Anda yakin id-nya benar, periksa apakah key yang dipakai milik akun yang sama.
  • Batas ukuran dicek sebelum diunggah. Kalau berkas Anda melebihi batas, memecahnya jadi beberapa bagian tidak membantu — yang dibutuhkan adalah rekaman dengan bitrate lebih rendah atau durasi lebih pendek.

#Selanjutnya

Siap mencoba?

Buat API key gratis di dashboard — tidak ada biaya berlangganan, kredit terpakai hanya saat Anda benar-benar memproses rekaman atau membuat meeting.

Buat API Key