# Hubungkan Agen AI ke APIPedia dengan Kode

> Ketik "hubungkan platformku ke apipedia.id" di agen AI, buka link yang muncul, lalu tekan Setujui. Agen mendapat API key tanpa salin-tempel.

- Minta kode: `POST https://api.apipedia.id/v1/device/code`
- Poll token: `POST https://api.apipedia.id/v1/device/token`
- Halaman persetujuan: https://console.apipedia.id/device
- Halaman: https://apipedia.id/docs/device-code
- Panduan umum (autentikasi, format respons, kode error): https://apipedia.id/docs.md

## Cara kerja singkat

Alur ini memakai **OAuth 2.0 Device Authorization Grant (RFC 8628)**, cara yang sama seperti login TV atau CLI dengan kode. Cocok untuk agen yang tidak bisa membuka browser atau menerima redirect OAuth: Claude Code, agen CLI, runtime agen di server, dan sejenisnya.

1. Agen meminta kode ke `POST /v1/device/code` (tanpa token).
2. Agen menampilkan link persetujuan berisi kode 8 karakter, mis. `2WKM-NH3C`.
3. Kamu membuka link, login, memeriksa nama agen, lalu menekan **Setujui**.
4. Sementara itu agen mem-poll `POST /v1/device/token` dan, setelah disetujui, menerima satu **API key baru** (`apk_...`) khusus untuknya.

Tanpa salin-tempel API key dan tanpa redirect URI. Kunci yang diterima berlaku untuk REST maupun [server MCP](https://apipedia.id/docs/mcp).

## Langkah-langkah

1. Di agenmu (Claude, Cursor, agen CLI, dsb.) ketik: **"hubungkan platformku ke apipedia.id"**.
2. Agen memanggil `POST https://api.apipedia.id/v1/device/code` lalu berkata kepadamu: "Buka link ini: https://console.apipedia.id/device?code=2WKM-NH3C — login, cek nama agent-nya, centang kotaknya, lalu tekan Setujui."
3. Buka link itu. Kalau belum masuk, console meminta login lalu kembali ke halaman persetujuan dengan kodenya.
4. Periksa rinciannya: **nama agen**, **platform**, **kode** (harus sama dengan yang ditampilkan agen), waktu permintaan, dan asal permintaan (negara + IP tersamar).
5. Centang kotak **"Saya mengenali agent ini dan memberi akses penuh ke akun APIPedia saya"**, lalu tekan **Setujui**. Kalau tidak mengenali permintaannya, tekan **Tolak**.
6. Kembali ke agen. Dalam beberapa detik agen menerima aksesnya dan melanjutkan tugas secara otomatis.

Kode berlaku **10 menit**. Kalau kedaluwarsa, minta agen membuat kode baru.

## Tiga cara menyetujui

| Cara | Langkah |
|---|---|
| **Link dari agen** | Buka `https://console.apipedia.id/device?code=XXXX-XXXX` yang ditampilkan agen. Cara tercepat. |
| **Notifikasi lonceng** | Setelah kode dibuka saat kamu login, permintaannya masuk ke notifikasi lonceng di console. Klik notifikasi itu untuk kembali ke halaman persetujuan, mis. dari perangkat lain, selama kode masih berlaku. |
| **Ketik kodenya** | Buka [Pengaturan](https://console.apipedia.id/settings) → tab **Keamanan** → kartu **Hubungkan agent dengan kode**, isi **Kode dari agent** (mis. `ABCD-EF23`), lalu klik **Tinjau**. Bisa juga langsung di [https://console.apipedia.id/device](https://console.apipedia.id/device). |

Kode tidak peka huruf besar/kecil; spasi dan tanda hubung boleh dihilangkan (`2wkm nh3c` = `2WKM-NH3C`).

## Prompt siap tempel

Agen yang sudah memakai [Skill APIPedia](https://apipedia.id/docs/skill) tahu alurnya dari kalimat "hubungkan platformku ke apipedia.id". Untuk agen lain, tempel prompt ini:

```text
Hubungkan platform ini ke akun APIPedia saya (apipedia.id) dengan alur kode perangkat (RFC 8628). Jangan minta saya menyalin API key.

1. POST https://api.apipedia.id/v1/device/code dengan JSON {"client_name":"<nama platform/agen ini>","agent_name":"<nama agen>"}.
2. Tampilkan ke saya isi field "message" apa adanya (berisi link verification_uri_complete). Jangan tampilkan device_code.
3. Tiap "interval" detik (awalnya 5), POST https://api.apipedia.id/v1/device/token dengan JSON {"grant_type":"urn:ietf:params:oauth:grant-type:device_code","device_code":"<device_code>"}.
   - authorization_pending: tunggu lalu poll lagi.
   - slow_down: tambah jeda 5 detik (pakai nilai "interval" di respons).
   - access_denied atau expired_token: berhenti dan beri tahu saya.
4. Kalau berhasil, simpan access_token (apk_...) sebagai APIPEDIA_TOKEN tanpa menampilkannya ulang, lalu kirim header "Authorization: Bearer <token>" ke https://api.apipedia.id/v1 atau ke server MCP https://api.apipedia.id/v1/mcp.

Petunjuk lengkap: https://api.apipedia.id/v1/device dan https://apipedia.id/docs/device-code.md
```

## API: minta kode

`POST https://api.apipedia.id/v1/device/code`, tanpa token. Body JSON:

| Field | Wajib | Keterangan |
|---|---|---|
| `client_name` | Ya (boleh diganti `agent_name`) | Nama platform atau agen yang meminta akses, maks. 80 karakter. Ditampilkan di halaman persetujuan. |
| `agent_name` | Tidak | Nama agen, mis. `Agent Toko Budi`. Dipakai untuk nama kunci `Agent: <nama>`. |
| `scope` | Tidak | Hanya dicatat. Akses yang diberikan selalu penuh (`all`). |

```bash
curl -s -X POST https://api.apipedia.id/v1/device/code \
  -H "Content-Type: application/json" \
  -d '{"client_name":"Claude Code","agent_name":"Agent Toko Budi"}'
```

Respons **200**:

```json
{
  "device_code": "Gm3c9V…(rahasia, 43 karakter)",
  "user_code": "2WKM-NH3C",
  "verification_uri": "https://console.apipedia.id/device",
  "verification_uri_complete": "https://console.apipedia.id/device?code=2WKM-NH3C",
  "expires_in": 600,
  "interval": 5,
  "message": "Buka link ini: https://console.apipedia.id/device?code=2WKM-NH3C - login, cek nama agent-nya, centang kotaknya, lalu tekan Setujui."
}
```

- `device_code` rahasia: dipakai hanya untuk poll, jangan ditampilkan ke pengguna.
- `user_code` 8 karakter `XXXX-XXXX` dari huruf dan angka tanpa `I L O U 0 1` supaya tidak tertukar.
- `expires_in` 600 detik (10 menit), `interval` 5 detik.
- Gagal: **400** `invalid_request` bila `client_name` dan `agent_name` kosong; **429** `slow_down` bila lebih dari 20 permintaan kode per 15 menit dari satu IP.

Petunjuk mesin-terbaca untuk agen (amplop `{ is_success, message, data }` berisi endpoint, grant type, dan langkah): `GET https://api.apipedia.id/v1/device`.

## API: poll token

`POST https://api.apipedia.id/v1/device/token`, tanpa token, tiap `interval` detik. Body JSON atau form: `device_code` (wajib) dan `grant_type` (opsional, bila diisi harus `urn:ietf:params:oauth:grant-type:device_code`).

```bash
curl -s -X POST https://api.apipedia.id/v1/device/token \
  -H "Content-Type: application/json" \
  -d '{"grant_type":"urn:ietf:params:oauth:grant-type:device_code","device_code":"<device_code>"}'
```

Selama belum selesai, server menjawab **HTTP 400** dengan `{ "error", "error_description" }`:

| `error` | Arti | Yang dilakukan agen |
|---|---|---|
| `authorization_pending` | Pengguna belum menyetujui | Tunggu `interval` detik, lalu poll lagi |
| `slow_down` | Poll lebih cepat dari `interval` | Tambah jeda 5 detik; nilai baru dikirim di field `interval` |
| `access_denied` | Pengguna menekan **Tolak** | Berhenti |
| `expired_token` | Kode lewat 10 menit | Berhenti, minta kode baru lewat `/v1/device/code` |
| `invalid_grant` | `device_code` tidak dikenal, atau kuncinya sudah diserahkan | Berhenti, minta kode baru |
| `invalid_request` / `unsupported_grant_type` | `device_code` kosong / `grant_type` salah | Perbaiki request |

```json
{ "error": "authorization_pending", "error_description": "Menunggu pengguna menyetujui di halaman /device." }
```

```json
{ "error": "slow_down", "error_description": "Terlalu sering. Tunggu 10 detik di antara poll.", "interval": 10 }
```

Setelah disetujui, respons **200**:

```json
{
  "access_token": "apk_...",
  "token_type": "Bearer",
  "scope": "all",
  "api_key": "apk_...",
  "key_prefix": "apk_xxxxxxxx",
  "mcp_url": "https://api.apipedia.id/v1/mcp",
  "api_base_url": "https://api.apipedia.id/v1"
}
```

`access_token` (sama dengan `api_key`) adalah API key `apk_` biasa dan **hanya diserahkan sekali** ke poll pertama. Tidak ada `expires_in`: kunci berlaku sampai dicabut. Simpan sebagai `APIPEDIA_TOKEN`, lalu kirim `Authorization: Bearer apk_...` ke `https://api.apipedia.id/v1` atau `https://api.apipedia.id/v1/mcp`.

## Contoh kode

Seluruh alur dalam satu skrip:

```js
// Node.js 18+ (fetch bawaan)
const API = 'https://api.apipedia.id/v1';
const start = await fetch(`${API}/device/code`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ client_name: 'Skrip Toko Budi', agent_name: 'Agent Toko Budi' }),
}).then((r) => r.json());
console.log(start.message); // tampilkan link ke pengguna

let wait = start.interval;
for (;;) {
  await new Promise((r) => setTimeout(r, wait * 1000));
  const res = await fetch(`${API}/device/token`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ grant_type: 'urn:ietf:params:oauth:grant-type:device_code', device_code: start.device_code }),
  });
  const body = await res.json();
  if (res.ok) {
    process.env.APIPEDIA_TOKEN = body.access_token; // simpan, jangan dicetak
    break;
  }
  if (body.error === 'authorization_pending') continue;
  if (body.error === 'slow_down') { wait = body.interval ?? wait + 5; continue; }
  throw new Error(`${body.error}: ${body.error_description}`); // access_denied, expired_token, invalid_grant
}
```

## Akses yang diberikan dan cara mencabut

- Menekan **Setujui** membuat **satu API key baru** bernama `Agent: <nama agen>` dengan **akses penuh** ke seluruh API dan tool MCP APIPedia, tanpa masa berlaku.
- Kunci yang sama berlaku untuk REST dan [MCP](https://apipedia.id/docs/mcp). Setiap panggilan dihitung ke kuota dan saldo akunmu.
- **Mencabut akses**: buka halaman [Token API](https://console.apipedia.id/api/token) dan cabut kunci `Agent: <nama>`. Agen langsung terputus.
- Sebelum disetujui, **Tolak** membuat agen menerima `access_denied`. Setelah disetujui, permintaan tidak bisa ditolak lagi; cabut kuncinya.
- Butuh akses yang lebih sempit? Buat token berlingkup sendiri dan pakai [Via prompt token](https://apipedia.id/docs/prompt-token).

## Keamanan

- **Setujui hanya permintaan yang kamu mulai sendiri.** Kalau menerima link atau notifikasi yang tidak kamu minta, tekan **Tolak**.
- **Cocokkan kodenya.** Kode di halaman persetujuan harus sama dengan yang ditampilkan agen, dan nama agen serta platformnya harus kamu kenali.
- **Kode berumur pendek.** Berlaku 10 menit dan sekali pakai; kunci diserahkan ke satu poll saja.
- **Hanya sesi console yang bisa menyetujui.** API key tidak bisa dipakai untuk menyetujui agen lain, dan percobaan kode dibatasi 40 kali per 5 menit per akun supaya kode tidak bisa ditebak.
- **Kode perangkat adalah rahasia agen.** `device_code` tidak boleh ditampilkan agen; yang dibagikan ke pengguna hanya link dan `user_code`.

## Cara lain menghubungkan agen

- **[Via MCP](https://apipedia.id/docs/mcp)**: tempel URL server MCP `https://api.apipedia.id/v1/mcp` ke Claude, ChatGPT, Cursor, atau VS Code lalu login OAuth. Cocok untuk klien yang mendukung MCP.
- **[Via prompt token](https://apipedia.id/docs/prompt-token)**: buat token API sendiri lalu berikan ke agen di prompt atau environment variable. Cocok untuk agen apa pun yang bisa melakukan HTTP request.

Ketiga cara berujung pada kredensial yang sama jenisnya: API key `apk_` dengan kuota, penagihan, dan amplop respons yang sama. Tambahkan [Skill APIPedia](https://apipedia.id/docs/skill) supaya agen mengenal setiap endpoint.
