---
title: GET /credits
source: https://se-hari.com/docs/api/api-credits-balance
updated: 2026-08-15T18:52:39.774874+00:00
---

> Cek saldo kredit. GET /credits — butuh scope credits:read.

Mengembalikan sisa kredit yang bisa dipakai beserta rincian per paket dan tanggal hangusnya. Kredit dipakai FIFO berdasarkan tanggal hangus terdekat, jadi paket yang paling cepat kedaluwarsa akan terpotong lebih dulu. Paket yang sudah lewat tanggal hangusnya tidak ikut dihitung ke dalam `balance` dan tidak muncul di `packages`. Endpoint ini murni baca dan tidak punya efek samping apa pun.
## Endpoint
```bash
GET https://se-hari.com/api/v1/credits
```
Butuh scope `credits: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.
## Contoh
```bash
curl -X GET "https://se-hari.com/api/v1/credits" \
  -H "Authorization: Bearer $SEHARI_API_KEY"
```
```javascript
const res = await fetch('https://se-hari.com/api/v1/credits', {
	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();
```
```python
import os, requests

res = requests.get(
    "https://se-hari.com/api/v1/credits",
    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()
```
## Respons 200

```json
{
  "balance": 47,
  "packages": [
    {
      "credits_total": 50,
      "credits_used": 3,
      "credits_remaining": 47,
      "expires_at": "2026-11-13T00:00:00Z",
      "source_type": "topup"
    }
  ]
}
```

## Field respons

| Field | Tipe | Keterangan |
|---|---|---|
| `balance` | `integer` | — |
| `packages` | `array<object>` | — |

## 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_api_key",
    "message": "Penjelasan untuk manusia.",
    "docs_url": "https://se-hari.com/docs/error/invalid-api-key",
    "request_id": "req_a1b2c3d4e5f6",
    "details": {}
  }
}
```
| Status | Kode | Artinya di endpoint ini |
|---|---|---|
| 401 | [`invalid_api_key`](/docs/error/invalid-api-key) | Key salah, sudah dicabut, atau kedaluwarsa. |
| 403 | [`insufficient_scope`](/docs/error/insufficient-scope) | Key valid, tapi tidak punya scope yang dibutuhkan endpoint ini. |
| 429 | [`rate_limited`](/docs/error/rate-limited) | Terlalu banyak request. Hormati header `Retry-After`. |
| 500 | [`internal_error`](/docs/error/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.
## Seberapa sering boleh dipanggil

Saldo berubah setiap kali ada meeting dibuat atau notulen selesai diproses — jadi menyimpannya lama berisiko memberi angka yang salah kepada pengguna Anda. Tapi memanggilnya di setiap iterasi perulangan juga salah: kalau Anda memproses 300 rekaman, 300 pemeriksaan saldo tidak mencegah apa pun yang tidak dicegah oleh satu pemeriksaan di awal ditambah penanganan `insufficient_credits` yang benar.

Pola yang tepat: periksa sekali sebelum memulai pekerjaan besar, lalu andalkan kode error untuk berhenti di tengah jalan. Untuk tampilan di antarmuka, cache 30–60 detik sudah cukup dan tidak akan pernah terlihat basi oleh manusia.

Perhatikan `packages` di respons, bukan hanya `balance`. Kredit dipotong dari paket yang paling cepat hangus lebih dulu, jadi saldo 50 yang seluruhnya hangus minggu depan adalah situasi yang sangat berbeda dari saldo 50 yang berlaku setahun — dan hanya rincian per paket yang bisa membedakannya.

## Alur khas

Kredit adalah satuan penagihan Se-Hari. Ia dibeli sekali pakai, punya masa berlaku, dan dipotong dengan urutan paling cepat hangus lebih dulu — sehingga saldo total saja tidak cukup untuk merencanakan pemakaian sebulan ke depan.

1. `GET /credits` — saldo total beserta rincian per paket dan tanggal hangusnya
2. `POST /credits/estimate` — hitung biaya sebuah operasi sebelum menjalankannya
3. `GET /credits/usage` — telusuri ke mana kredit terpakai

Estimasi untuk notulen adalah **perkiraan**, bukan angka final: yang ditagih nanti adalah durasi asli hasil transkripsi, yang bisa berbeda dari durasi yang Anda sebutkan. Estimasi untuk meeting bersifat pasti, karena diambil dari paket harga yang sudah tetap.

## 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](/docs/autentikasi) — cara membuat key dan memilih scope
- [Kode error](/docs/error) — arti setiap kode dan cara memperbaikinya
- [Idempotency](/docs/idempotency) — kenapa retry aman kalau dilakukan dengan benar
- [Spesifikasi OpenAPI](https://se-hari.com/api/v1/openapi.json) — kontrak mesin, cocok untuk men-generate klien