SAI AccountingDokumentasiMasuk ke aplikasi

API: membaca buku ini dari sistem lain

Cara sebuah program menarik data perusahaan Anda — token, alamatnya, bentuk jawabannya, dan apa arti setiap penolakan.

±5 menit baca

Sebuah program lain — kasir di toko, marketplace, lembar kerja yang menarik angka setiap pagi — bisa membaca buku perusahaan ini tanpa seorang pun menyalin data dengan tangan. Jalannya API: alamat web yang mengembalikan data sebagai JSON, bukan sebagai halaman. Yang dipakai untuk masuk bukan nama pengguna dan kata sandi, melainkan TOKEN yang Anda terbitkan sendiri di layar Token API.

Satu hal yang perlu diketahui sebelum yang lain: API ini MEMBACA, tidak menulis. Tidak ada cara menerbitkan faktur atau memindahkan stok lewat jalur ini. Itu bukan fitur yang belum sempat dibuat, melainkan keputusan: setiap dokumen yang masuk lewat aplikasi melewati mesin akuntansi yang sama — jurnal berpasangan, ambang persetujuan, periode terkunci, kuota modul. Pintu tulis yang melewati semuanya akan menghasilkan buku yang tidak bisa dipertanggungjawabkan oleh orang yang menandatanganinya.

Token BERPERAN, jadi izinnya bukan izin baru

Sebuah token tidak punya daftar izinnya sendiri. Ia diterbitkan SEBAGAI salah satu peran yang ada di perusahaan ini, dan mendapat persis apa yang peran itu dapat — tidak lebih, dan ikut kehilangan akses ketika modulnya dimatikan atau izin perannya ditimpa. Karena itu pertanyaan “token ini boleh membaca apa” selalu punya satu jawaban yang sama dengan pertanyaan “peran ini boleh membaca apa”.

  • Terbitkan token untuk peran yang PALING SEDIKIT cukup. Sebuah penarik faktur tidak perlu peran yang juga boleh melihat gaji.
  • Satu token per sistem yang menyambung, bukan satu untuk semuanya — kalau salah satu bocor, yang dicabut hanya yang itu.
  • Token diperlihatkan sekali saat diterbitkan; yang tersimpan hanya sidik jarinya. Yang hilang tidak bisa dilihat lagi, hanya dicabut lalu diterbitkan ulang.
  • Mencabut berlaku seketika, pada permintaan berikutnya — bukan setelah tokennya kedaluwarsa, sebab token di sini memang tidak punya masa berlaku.

Perusahaannya ditentukan token, bukan alamat

Alamat API tidak memuat nama tenant maupun nama PT. Sebuah token diterbitkan DI DALAM satu perusahaan dan selamanya membaca buku perusahaan itu saja. Konsekuensinya: kalau Anda memegang tiga PT, Anda memerlukan tiga token, dan sebuah program yang menarik ketiganya menyimpan ketiganya. Itu disengaja — alamat yang bisa menyebut PT lain adalah satu salah ketik antara buku yang benar dan buku tetangganya.

Satu permintaan, dari awal sampai jawabannya

Token dikirim di header Authorization dengan skema Bearer. Tidak ada bentuk lain: tidak lewat parameter kueri (ia tercatat di log server dan riwayat peramban), tidak lewat cookie.

bash
curl -H "Authorization: Bearer sai_12_xxxxxxxxxxxxxxxxxxxxxxxx" \
  "https://buku.contoh.co.id/api/v1/customers?limit=50&offset=0"

Jawabannya selalu berbentuk sama: sebuah larik `data`, dan sebuah `meta` yang memberi tahu ada berapa seluruhnya dan apakah masih ada halaman berikutnya.

json
{
  "data": [
    { "id": 7, "name": "PT Contoh Sejahtera", "isActive": true, "updatedAt": "2026-08-21T09:14:02.000Z" }
  ],
  "meta": { "total": 128, "limit": 50, "offset": 0, "hasMore": true }
}
  • Ambil `meta.hasMore` apa adanya; jangan menghitung sendiri dari `total` dan `limit`. Yang menghitung sendiri berhenti satu halaman terlalu awal, diam-diam, dan kehilangan baris terakhir setiap kali.
  • Nilai kueri yang salah ditolak, bukan diperbaiki: `?limit=abc` menjawab 400, bukan diam-diam kembali ke bawaan. Parameter yang salah ketik dan tetap “berhasil” menghasilkan program yang tampak bekerja sambil menarik halaman yang salah selama berbulan-bulan.
  • `limit` di atas batas juga ditolak, bukan dipotong — penarik yang meminta 10.000 lalu menerima 200 tanpa diberi tahu akan menyimpulkan datanya memang cuma 200.
  • Tidak ada bentuk “kembalikan semuanya”. Daftar yang muat hari ini adalah daftar yang tidak muat setelah pelanggan keseratus.

Endpoint yang ada hari ini

Endpoint yang tersedia

AlamatIsinyaIzin yang dituntut
GET /api/v1/customersDaftar pelanggancustomer.read
GET /api/v1/suppliersDaftar pemasoksupplier.read
GET /api/v1/itemsDaftar baranginventory.read
GET /api/v1/accountsBagan akunaccount.read
GET /api/v1/invoicesDaftar faktur penjualaninvoice.read

Menarik hanya yang berubah

Setiap baris membawa `updatedAt`, dan setiap daftar menerima `?updatedSince=` berisi waktu ISO-8601. Simpan `updatedAt` tertinggi yang pernah Anda terima, lalu kirimkan kembali pada penarikan berikutnya: yang datang hanya yang berubah sejak itu. Itulah selisih antara satu permintaan kecil per jam dan seluruh daftar per jam — dan pada buku yang sudah besar, selisih antara integrasi yang tetap cepat dan integrasi yang lama-lama ditinggalkan orang.

bash
curl -H "Authorization: Bearer $SAI_TOKEN" \
  "https://buku.contoh.co.id/api/v1/invoices?updatedSince=2026-08-21T09:14:02Z&limit=200"

Urutannya `updatedAt` menaik dengan `id` sebagai pemutus seri. Itu yang membuat penarikan bertahap tidak pernah melewatkan atau menggandakan baris ketika dua dokumen berubah pada detik yang sama.

Kalau jawabannya bukan 200

  • 400 — permintaannya yang salah: parameter yang bukan angka, tanggal yang tidak terbaca, `limit` di luar batas. Pesannya menyebut parameter mana.
  • 401 — kredensialnya bermasalah: tidak ada, salah, atau sudah dicabut. Ketiganya dijawab sama persis, dan itu disengaja — jawaban yang membedakannya menjadikan endpoint ini alat menebak token yang masih hidup.
  • 403 — tokennya sah, tetapi perannya tidak berhak. Jawabannya menyebut izin yang kurang, supaya yang perlu diminta adalah token berperan lain, bukan tebakan peran satu per satu.
  • 429 — terlalu banyak permintaan. Batasnya dihitung per TOKEN, bukan per alamat IP: dua sistem dengan tokennya masing-masing tidak saling menghabiskan jatah, dan satu program yang mengamuk tidak mematikan yang lain.
  • Ulangi permintaan yang gagal karena 429 atau galat jaringan dengan jeda yang membesar, bukan seketika. Penarik yang mengulang tanpa jeda adalah penarik yang menghabiskan jatahnya sendiri lalu menyalahkan servernya.

Spesifikasi mesin, untuk yang membangkitkan kode

Seluruh bentuk di atas juga tersedia sebagai dokumen OpenAPI 3.1 di alamat `/api/v1/openapi.json` — setiap endpoint, setiap kolom, setiap tipe, beserta izin yang dituntutnya. Ia bisa dibuka pembangkit klien (kode penarik yang ditulis mesin), penguji API, atau alat dokumentasi apa pun yang membaca OpenAPI.

Alamat spesifikasi itu TIDAK menuntut token, dan itu disengaja: seseorang harus bisa membaca bentuk API ini sebelum memutuskan meminta kredensial. Yang publik hanyalah BENTUKNYA — nama kolom dan tipe. Satu baris data pun tidak bisa dibaca tanpa token yang sah.

Yang tidak akan Anda temukan di sini: janji waktu tanggap, jaminan ketersediaan, dan versi kedua. `v1` di alamatnya adalah janji yang sudah dibuat — bentuk jawaban yang sudah terbit tidak diubah diam-diam; kolom baru boleh muncul, kolom yang ada tidak dicabut tanpa alamat versi baru.