Lewati ke konten
kenari.

Perubahan model

kenari mengumumkan setiap perubahan pada daftar model dan harganya: model baru, model yang dihapus, harga yang berubah, diskon yang mulai atau berakhir, perubahan harga yang sudah dijadwalkan, dan model yang akan dihentikan. Kamu bisa membaca perubahan ini di halaman web, di channel Telegram, atau lewat endpoint publik yang bisa dipanggil berkala oleh skrip atau agen. Ketiganya menampilkan perubahan yang sama.

kindYang terjadi
addedAda model baru di daftar.
removedSebuah model hilang dari daftar.
price_changedHarga model berubah, atau model menjadi gratis atau tidak lagi gratis.
discount_startedHarga pasar model sekarang di atas harga kenari pada sisi input atau output, padahal sebelumnya tidak.
discount_endedHarga pasar tidak lagi di atas harga kenari pada suatu sisi.
price_scheduledPerubahan harga dijadwalkan, lengkap dengan tanggal berlakunya.
sunset_scheduledSebuah model dijadwalkan berhenti, lengkap dengan tanggalnya.

Harga pasar adalah harga pembanding yang ditampilkan GET /api/public/pricing di samping harga kenari. Lihat Model & harga.

Perubahan yang bukan soal harga, misalnya model yang menjadi khusus pelanggan, tidak diumumkan.

Sebuah perubahan baru diumumkan setelah kenari yakin perubahan itu nyata. Daftar diperiksa setiap 5 menit.

kindMuncul
price_changed, discount_started, discount_endedSetelah perubahan bertahan sekitar 10 menit.
addedSetelah model terdaftar selama sekitar satu jam.
removedSetelah model hilang selama sekitar satu jam.
price_scheduled, sunset_scheduledLangsung, karena tanggalnya adalah beritanya.

Perubahan yang cepat kembali seperti semula tidak pernah diumumkan. Harga yang salah ketik dan diperbaiki dalam 10 menit tidak muncul, dan model yang hilang beberapa menit lalu kembali tidak dilaporkan sebagai dihapus. Jika harga berubah dari A ke B lalu ke C dalam 10 menit, yang diumumkan adalah perubahan dari A ke C.

Model yang sudah diumumkan lewat sunset_scheduled tetap mendapat entri removed di feed saat benar-benar hilang dari daftar. Channel Telegram tidak mengumumkannya untuk kedua kalinya.

  • Halaman kenari.id/models/changes menampilkan daftar perubahan. Kamu tidak perlu login.
  • Channel Telegram t.me/kenari_updates menerima perubahan yang sama. Postingannya berbahasa Inggris, paling banyak satu postingan untuk setiap pemeriksaan. Setiap postingan mengelompokkan perubahan menurut jenisnya, dengan harga dalam Rupiah per 1M token dan tanggal dalam WIB. Perubahan harga menampilkan persentase perubahannya, baris diskon menampilkan harga pasar pembandingnya, dan model yang akan dihentikan atau sudah dihapus menyebut penggantinya bila ada. Postingan yang terlalu panjang dipecah menjadi beberapa pesan.
  • GET /v1/models/changes mengembalikan perubahan dalam bentuk JSON.

GET /v1/models/changes

Endpoint ini publik. Kamu tidak butuh API key, dan browser bisa memanggilnya dari origin mana pun (CORS terbuka). Response bisa di-cache selama 30 detik, jadi memanggil lebih sering dari itu mengembalikan jawaban yang sama.

ParameterTipeWajibKeterangan
sinceintegerTidakWaktu unix dalam detik. Hanya kembalikan perubahan yang dikonfirmasi pada atau setelah saat ini. Bawaannya 0, artinya tanpa batas bawah.
limitintegerTidakJumlah perubahan yang dikembalikan, dari 1 sampai 200. Bawaannya 50. Nilai di luar rentang dipindahkan ke ujung rentang yang terdekat.

Response berupa daftar: {"object": "list", "channel": ..., "data": [...]}.

FieldTipeKeterangan
objectstringSelalu list.
channelstring atau nullHandle Telegram publik yang menerima perubahan yang sama, misalnya @kenari_updates. null bila tidak ada.
dataarrayPerubahan, yang terbaru lebih dulu menurut confirmed_at. Kosong bila tidak ada apa pun pada atau setelah since.

Setiap item di data punya field berikut:

FieldTipeKeterangan
modelstringId model, sama seperti di GET /v1/models.
kindstringSalah satu jenis di Yang dihitung sebagai perubahan.
oldobject, integer, atau nullKeadaan sebelum perubahan. Bentuknya bergantung pada kind. Lihat Old dan new menurut jenis.
newobject, integer, atau nullKeadaan setelah perubahan, dengan bentuk yang sama seperti old.
effective_atinteger atau nullWaktu unix dalam detik saat perubahan terjadwal berlaku. Terisi untuk price_scheduled dan sunset_scheduled, null untuk jenis lainnya.
detected_atintegerWaktu unix dalam detik saat kenari pertama kali melihat perubahan.
confirmed_atintegerWaktu unix dalam detik saat perubahan tampil di daftar ini. Untuk perubahan terjadwal nilainya sama dengan detected_at. Sekitar 10 menit kemudian untuk perubahan harga dan diskon, dan sekitar satu jam kemudian untuk added dan removed.
successorstring atau nullModel yang ditetapkan sebagai pengganti model ini, untuk sunset_scheduled dan removed. null untuk jenis lainnya. Adanya pengganti tidak dengan sendirinya berarti request dialihkan ke model itu.
{
"object": "list",
"channel": "@kenari_updates",
"data": [
{
"model": "step-3-7-flash",
"kind": "price_changed",
"old": { "free": false, "price_in": 1000000000, "price_out": 4000000000, "image": null },
"new": { "free": false, "price_in": 1200000000, "price_out": 4000000000, "image": null },
"effective_at": null,
"detected_at": 1791529200,
"confirmed_at": 1791532800,
"successor": null
}
]
}

Harga berupa bilangan bulat dalam micro-Rupiah, dengan Rp 1 sama dengan 1.000.000 micro-Rupiah. Harga token berlaku per 1 juta token, jadi 1200000000 berarti Rp 1.200 per 1 juta token. Lihat Cara penagihan.

Objek harga. Dipakai oleh added, removed, price_changed, dan price_scheduled. Selalu punya empat field:

FieldKeterangan
freetrue bila model gratis.
price_inHarga input per 1 juta token.
price_outHarga output per 1 juta token.
imageHarga per gambar, untuk model yang dihargai per gambar.

Field harga bernilai null bila model tidak punya harga jenis itu, misalnya image pada model chat.

Objek diskon. Dipakai oleh discount_started dan discount_ended. Punya field in untuk sisi input, field out untuk sisi output, atau keduanya. Hanya sisi yang diskonnya mulai atau berakhir yang ada. Setiap sisi berbentuk {"price": ..., "market": ...}:

FieldKeterangan
priceHarga kenari per 1 juta token pada sisi itu.
marketHarga pasar per 1 juta token pada sisi itu, atau null bila tidak ada.

Bentuk menurut jenis:

kindoldneweffective_at
addednullObjek harga.null
removedObjek harga sebelum model hilang.nullnull
price_changedObjek harga sebelumnya.Objek harga sesudahnya.null
discount_startedObjek diskon sebelumnya.Objek diskon sesudahnya, dengan market di atas price.null
discount_endedObjek diskon sebelumnya, dengan market di atas price.Objek diskon sesudahnya.null
price_scheduledObjek harga dengan harga hari ini.Objek harga dengan harga yang berlaku mulai effective_at.Waktu unix dalam detik saat harga baru berlaku.
sunset_scheduledWaktu penghentian sebelumnya dalam detik unix, atau null bila belum pernah diatur.Waktu penghentian dalam detik unix.Waktu penghentian yang sama.

Panggilan pertama mengembalikan perubahan terbaru. Panggilan berikutnya memakai since agar hanya mendapat yang baru.

Terminal window
curl "https://kenari.id/v1/models/changes?limit=20"
curl "https://kenari.id/v1/models/changes?since=1791532800"

Loop ini memanggil endpoint setiap 10 menit. Ia menyimpan confirmed_at terbaru yang pernah dilihat dan memakainya sebagai since pada panggilan berikutnya.

let since = 0;
const seen = new Set();
async function poll() {
const response = await fetch(`https://kenari.id/v1/models/changes?since=${since}&limit=200`);
if (!response.ok) return;
const { data } = await response.json();
// Yang terbaru lebih dulu, jadi dibaca dari belakang agar perubahan tertua diproses lebih dulu.
for (const change of [...data].reverse()) {
const key = `${change.confirmed_at}:${change.model}:${change.kind}`;
if (seen.has(key)) continue;
seen.add(key);
console.log(change.kind, change.model, change.old, "->", change.new);
}
if (data.length > 0) since = data[0].confirmed_at;
}
await poll();
setInterval(poll, 10 * 60 * 1000);

since ikut menghitung detiknya sendiri, jadi perubahan terbaru muncul sekali lagi pada panggilan berikutnya. Set seen membuangnya.

since dan urutan daftar memakai confirmed_at, yaitu saat perubahan tampil di daftar, bukan detected_at. Sebuah perubahan dilihat lebih dulu, lalu dikonfirmasi 10 menit atau satu jam kemudian. Jika since memakai waktu pertama kali dilihat, perubahan yang dilihat sesaat sebelum polling terakhirmu dan dikonfirmasi sesaat sesudahnya akan tampak lebih lama dari since-mu, dan kamu tidak akan pernah menerimanya. Sebuah perubahan mendapat confirmed_at tepat saat ia tampil di daftar, jadi nilainya tidak pernah lebih lama dari polling yang belum memilikinya. Poller yang memakai confirmed_at terbaru yang pernah dilihat sebagai since karena itu tidak melewatkan perubahan.

detected_at tetap ada di setiap item, sebagai waktu perubahan itu pertama kali terjadi.

Jika lebih dari limit perubahan dikonfirmasi di antara dua polling, hanya limit yang terbaru yang dikembalikan. Pakai limit=200 dan panggil minimal sekali dalam satu jam.

since atau limit yang bukan bilangan bulat mendapat error 400. Error lainnya ada di Error.