> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apimart.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Kueri biaya dan penggunaan

>  - Melihat biaya dan statistik panggilan untuk rentang waktu tertentu
- Memfilter model dan mengelompokkan berdasarkan model atau hari kalender
- Mendukung API Key saat ini atau seluruh akun
- Mengembalikan jumlah USD, kredit, panggilan, dan token 

Gunakan API Key untuk melihat biaya dalam rentang waktu tertentu, dengan filter model dan pengelompokan berdasarkan model, hari kalender, atau keduanya. Hasil agregasi dikembalikan langsung tanpa membuat tugas atau melakukan polling status.

<RequestExample>
  ```bash cURL theme={null}
  curl --get 'https://api.apimart.ai/v1/usage' \
    --header 'Authorization: Bearer <token>' \
    --data-urlencode 'start=2026-09-01T00:00:00+08:00' \
    --data-urlencode 'end=2026-09-08T00:00:00+08:00' \
    --data-urlencode 'group_by=model'
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      "https://api.apimart.ai/v1/usage",
      headers={"Authorization": "Bearer <token>"},
      params={
          "start": "2026-09-01T00:00:00+08:00",
          "end": "2026-09-08T00:00:00+08:00",
          "group_by": "model",
      },
      timeout=30,
  )

  payload = response.json()
  if not response.ok or not payload.get("success"):
      message = payload.get("error", {}).get("message", "Kueri penggunaan gagal")
      raise RuntimeError(f"HTTP {response.status_code}: {message}")

  print(payload["data"]["total"])
  print(payload["data"]["items"])
  ```

  ```javascript JavaScript theme={null}
  const url = new URL("https://api.apimart.ai/v1/usage");
  url.search = new URLSearchParams({
    start: "2026-09-01T00:00:00+08:00",
    end: "2026-09-08T00:00:00+08:00",
    group_by: "model",
  }).toString();

  const response = await fetch(url, {
    headers: { Authorization: "Bearer <token>" },
  });
  const payload = await response.json();

  if (!response.ok || !payload.success) {
    throw new Error(
      `HTTP ${response.status}: ${payload.error?.message ?? "Kueri penggunaan gagal"}`,
    );
  }

  console.log(payload.data.total);
  console.log(payload.data.items);
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "success": true,
    "data": {
      "scope": "key",
      "start": 1788192000,
      "end": 1788796800,
      "tz": "Asia/Shanghai",
      "group_by": "model",
      "total": {
        "amount_usd": 12.3456,
        "credits": 123.456,
        "requests": 1834,
        "prompt_tokens": 902311,
        "completion_tokens": 215044
      },
      "items": [
        {
          "model": "gpt-5.6-luna",
          "amount_usd": 9.1271,
          "credits": 91.271,
          "requests": 1520,
          "prompt_tokens": 880120,
          "completion_tokens": 201300
        },
        {
          "model": "sora-2",
          "amount_usd": 3.2185,
          "credits": 32.185,
          "requests": 314,
          "prompt_tokens": 22191,
          "completion_tokens": 13744
        }
      ]
    }
  }
  ```

  ```json 400 theme={null}
  {
    "success": false,
    "error": {
      "code": "range_too_large",
      "message": "Time range must not exceed 31 days.",
      "type": "usage_query_error"
    }
  }
  ```
</ResponseExample>

## Autentikasi

<ParamField header="Authorization" type="string" required>
  Gunakan API Key yang sama dengan panggilan model melalui autentikasi Bearer Token. Dapatkan kunci di [halaman pengelolaan API Key](https://apimart.ai/keys).

  ```
  Authorization: Bearer YOUR_API_KEY
  ```
</ParamField>

<Info>
  Kueri tetap dapat dilakukan saat saldo 0. Saldo tidak diperiksa, tetapi status dan masa berlaku API Key, daftar IP yang diizinkan, serta status akun tetap diperiksa.
</Info>

## Endpoint

```text theme={null}
GET /v1/usage
GET /usage
```

Kedua endpoint memiliki fungsi yang sama dan mendukung CORS. Simpan API Key dengan aman dan jangan tampilkan dalam kode frontend publik.

## Parameter permintaan

Semua parameter dikirim melalui query URL.

<ParamField query="start" type="integer | string">
  Waktu mulai, inklusif. Mendukung timestamp Unix dalam detik atau string RFC3339 dengan zona waktu, misalnya `2026-09-01T00:00:00+08:00`.

  Jika tidak diberikan, nilainya 24 jam sebelum `end`. Timestamp menggunakan detik, bukan milidetik.
</ParamField>

<ParamField query="end" type="integer | string">
  Waktu akhir, eksklusif. Format sama dengan `start`; jika tidak diberikan, menggunakan waktu saat ini.

  Harus setelah `start`, dan `end - start` tidak boleh melebihi 31 hari.
</ParamField>

<ParamField query="model" type="string">
  Nama model. Jika tidak diberikan, semua model dihitung. Pisahkan beberapa model dengan koma; maksimal `50`.

  Pencocokan persis tanpa membedakan huruf besar dan kecil. Wildcard tidak didukung.

  Contoh: `gpt-5.6-luna,sora-2`
</ParamField>

<ParamField query="group_by" type="string" default="none">
  Pengelompokan:

  * `none`: hanya total; `items` berupa array kosong
  * `model`: berdasarkan model
  * `date`: berdasarkan hari kalender
  * `model,date`: berdasarkan model dan hari kalender
</ParamField>

<ParamField query="tz" type="string" default="Asia/Shanghai">
  Nama zona waktu IANA. Default: `Asia/Shanghai`.

  Hanya memengaruhi batas hari jika `group_by` mencakup `date`, tanpa mengubah waktu mulai dan akhir kueri. Waktu RFC3339 dibaca menurut zona waktu dalam string tersebut.
</ParamField>

<ParamField query="scope" type="string" default="key">
  Cakupan statistik:

  * `key`: hanya API Key saat ini (default)
  * `account`: seluruh API Key pada akun pemilik kunci saat ini
</ParamField>

<Note>
  Rentang kueri adalah `[start, end)`: mencakup awal, tidak mencakup akhir. Gunakan waktu yang sama untuk `end` kueri sebelumnya dan `start` kueri berikutnya agar batas waktu tidak dihitung dua kali.

  Saat menyusun URL secara manual, enkode `+` dalam RFC3339 sebagai `%2B`. cURL `--data-urlencode`, Python `params`, dan JavaScript `URLSearchParams` pada contoh menanganinya secara otomatis.
</Note>

## Contoh permintaan

### Total biaya API Key saat ini selama 24 jam terakhir

Tanpa parameter query, rentang waktu, cakupan, dan pengelompokan default digunakan.

```bash theme={null}
curl 'https://api.apimart.ai/v1/usage' \
  --header 'Authorization: Bearer <token>'
```

### Biaya harian seluruh akun untuk model tertentu

Melihat biaya dari 11 hingga 18 September 2026, waktu Beijing, tidak termasuk 18 September.

```bash theme={null}
curl --get 'https://api.apimart.ai/v1/usage' \
  --header 'Authorization: Bearer <token>' \
  --data-urlencode 'start=1789056000' \
  --data-urlencode 'end=1789660800' \
  --data-urlencode 'model=gpt-5.6-luna' \
  --data-urlencode 'group_by=date' \
  --data-urlencode 'scope=account' \
  --data-urlencode 'tz=Asia/Shanghai'
```

### Mengelompokkan berdasarkan model dan hari kalender

```bash theme={null}
curl --get 'https://api.apimart.ai/v1/usage' \
  --header 'Authorization: Bearer <token>' \
  --data-urlencode 'start=2026-09-01T00:00:00+08:00' \
  --data-urlencode 'end=2026-09-08T00:00:00+08:00' \
  --data-urlencode 'model=gpt-5.6-luna,sora-2' \
  --data-urlencode 'group_by=model,date' \
  --data-urlencode 'tz=Asia/Shanghai'
```

Setiap elemen `items` pada pengelompokan ini memuat `model` dan `date`.

## Kolom respons

<ResponseField name="success" type="boolean">
  Keberhasilan kueri: `true` jika berhasil, `false` jika terjadi kesalahan kueri penggunaan.
</ResponseField>

<ResponseField name="data" type="object">
  Jika berhasil, mengembalikan cakupan kueri, total, dan rincian kelompok.

  <Expandable title="Properti data">
    <ResponseField name="scope" type="string">
      Cakupan statistik: `key` atau `account`.
    </ResponseField>

    <ResponseField name="start" type="integer">
      Waktu mulai aktual berupa timestamp Unix dalam detik, inklusif.
    </ResponseField>

    <ResponseField name="end" type="integer">
      Waktu akhir aktual berupa timestamp Unix dalam detik, eksklusif.
    </ResponseField>

    <ResponseField name="tz" type="string">
      Zona waktu untuk pengelompokan hari kalender.
    </ResponseField>

    <ResponseField name="group_by" type="string">
      Pengelompokan: `none`, `model`, `date`, atau `model,date`.
    </ResponseField>

    <ResponseField name="total" type="object">
      Total dalam rentang kueri. Lihat kolom statistik pada tabel berikut.
    </ResponseField>

    <ResponseField name="items" type="object[]">
      Rincian kelompok, diurutkan berdasarkan `amount_usd` dari terbesar. Array kosong jika `group_by=none`. Setiap elemen berisi kolom statistik pada tabel berikut.

      * Jika `group_by` mencakup `model`, elemen memuat `model`
      * Jika `group_by` mencakup `date`, elemen memuat `date` dalam format `YYYY-MM-DD`; batas hari mengikuti `tz`
    </ResponseField>
  </Expandable>
</ResponseField>

`data.total` dan `data.items[]` menggunakan kolom statistik yang sama:

| Kolom               | Tipe    | Keterangan                                                                                     |
| ------------------- | ------- | ---------------------------------------------------------------------------------------------- |
| `amount_usd`        | number  | Jumlah USD, dibulatkan ke 6 angka desimal                                                      |
| `credits`           | number  | Kredit layanan: `amount_usd × 10`, satuan sama dengan situs resmi                              |
| `requests`          | integer | Jumlah panggilan yang berhasil ditagihkan                                                      |
| `prompt_tokens`     | integer | Token input; biasanya 0 untuk model gambar dan video yang ditagihkan per panggilan atau detik  |
| `completion_tokens` | integer | Token output; biasanya 0 untuk model gambar dan video yang ditagihkan per panggilan atau detik |

<ResponseField name="error" type="object">
  Jika kueri penggunaan gagal, berisi `code`, `message`, dan `type`, dengan `type` bernilai `usage_query_error`. Kesalahan autentikasi 401 / 403 dikembalikan oleh lapisan autentikasi.
</ResponseField>

## Batas permintaan dan cache

* Maksimal `60` kueri per menit per API Key; batas API global juga berlaku
* Hasil dengan parameter sama disimpan dalam cache selama `60` detik; header respons `X-Usage-Cache` bernilai `hit` atau `miss`
* Catatan biaya biasanya tersedia dalam 1 detik, tetapi data 1 menit terakhir mungkin belum lengkap dan cache dapat menambah keterlambatan
* Interval kueri disarankan minimal 1 menit; jangan gunakan sebagai notifikasi penagihan real-time

## Dasar penghitungan

* Menggunakan catatan panggilan yang berhasil ditagihkan, sama dengan data dasbor situs resmi
* Panggilan gagal dan pengembalian dana setelah tugas gagal tidak dihitung; tidak perlu dikurangi sendiri. Batch gambar yang sebagian berhasil ditagihkan berdasarkan gambar yang benar-benar diberikan
* Berdasarkan waktu pencatatan tagihan. Tugas gambar dan video asinkron dicatat saat selesai, bukan saat dikirim; tugas yang melewati tengah malam masuk ke tanggal selesai
* API Key yang dibuat ulang setelah dihapus adalah kunci baru. Kueri `scope=key` pada kunci baru tidak mencakup riwayat kunci lama
* Penyesuaian saldo manual bukan biaya panggilan dan tidak termasuk statistik
* Data setelah 27 April 2026 tersedia

## Penanganan kesalahan

| Status HTTP | `error.code`                    | Keterangan                                                                        |
| ----------- | ------------------------------- | --------------------------------------------------------------------------------- |
| 400         | `invalid_start` / `invalid_end` | Format waktu mulai atau akhir tidak valid                                         |
| 400         | `invalid_range`                 | `end` tidak lebih besar dari `start`                                              |
| 400         | `range_too_large`               | Lebih dari 31 hari; bagi menjadi beberapa rentang kueri                           |
| 400         | `invalid_tz`                    | Zona waktu IANA tidak dikenal                                                     |
| 400         | `invalid_group_by`              | Pengelompokan tidak valid                                                         |
| 400         | `invalid_scope`                 | Cakupan statistik tidak valid                                                     |
| 400         | `too_many_models`               | Lebih dari 50 model                                                               |
| 401 / 403   | —                               | API Key tidak valid atau kedaluwarsa, IP tidak diizinkan, atau akun dinonaktifkan |
| 429         | —                               | Melebihi 60 kueri per kunci per menit atau batas API global                       |
| 503         | `usage_unavailable`             | Data sementara tidak tersedia; coba lagi nanti                                    |

<Warning>
  `503 usage_unavailable` tidak mengembalikan jumlah biaya. Artinya kueri tidak tersedia, bukan biaya 0. Jangan mengubah respons gagal menjadi nilai nol atau menimpa hasil sukses sebelumnya.
</Warning>

## Perbandingan dengan endpoint lain

| Endpoint                          | Kemampuan                                                                          |
| --------------------------------- | ---------------------------------------------------------------------------------- |
| `GET /v1/dashboard/billing/usage` | Hanya total biaya kumulatif; tanpa filter model atau waktu                         |
| `POST /v1/logs/export`            | Ekspor asinkron rincian panggilan (CSV / XLSX); perlu agregasi sendiri             |
| `GET /v1/usage`                   | Kueri berdasarkan waktu dan model dengan total biaya dan rincian kelompok langsung |

Untuk sisa kuota, gunakan [Kueri saldo token](/id/api-reference/account/token-balance) atau [Kueri saldo pengguna](/id/api-reference/account/user-balance).
