# API organizer

Ambil data event, pesanan, dan tiket, lalu check-in tiket dari aplikasi kamu sendiri dengan kunci API.

> Sumber: https://help.nyebar.id/organizer/integrasi/api-organizer

Lewat API organizer, aplikasi atau sistem kamu sendiri bisa membaca data event, jenis tiket, pesanan, tiket, dan statistik, serta check-in tiket. Misalnya untuk menyalin daftar peserta ke Google Sheets, menampilkan jumlah tiket terjual di layar, atau memakai aplikasi pemindai buatan sendiri di pintu masuk.

Kalau sistem kamu perlu dikabari begitu ada pesanan atau check-in baru, pakai [Webhook](/organizer/integrasi/webhook) supaya tidak perlu bertanya terus ke API. Kunci API dibuat oleh owner atau Admin di menu **Integrasi**. Bagian kedua artikel ini ditujukan untuk developer yang memasang API-nya.

## Membuat kunci API

1. Buka menu **Integrasi** di sidebar, lalu klik **Buat kunci API**.

   ![Halaman Integrasi berisi daftar kunci API dan tombol Buat kunci API.](https://help.nyebar.id/screenshots/id/org-integrations.webp "Daftar kunci API di halaman Integrasi.")

2. Beri **Nama kunci** supaya mudah dikenali, misalnya nama aplikasi yang memakainya.
3. Pilih **Akses**: **Baca data** untuk melihat event, pesanan, tiket, dan statistik, dan **Check-in** untuk check-in tiket. Pilih seperlunya saja.
4. Klik **Buat kunci**.

   ![Jendela Buat kunci API dengan nama kunci dan pilihan akses.](https://help.nyebar.id/screenshots/id/org-api-key-create.webp "Beri nama dan pilih akses kunci.")

5. Klik tombol salin untuk menyalin kunci, lalu simpan di tempat aman. Kunci hanya ditampilkan sekali ini. Kalau hilang, cabut kuncinya lalu buat yang baru.

   ![Kunci API baru yang ditampilkan sekali dengan tombol salin.](https://help.nyebar.id/screenshots/id/org-api-key-created.webp "Kunci hanya ditampilkan sekali, langsung salin.")

Satu organizer bisa punya sampai 5 kunci aktif. Kunci milik organizer, jadi tetap berfungsi walaupun orang yang membuatnya sudah keluar dari tim.

> **Jaga kerahasiaan kunci**
>
> Siapa pun yang memegang kunci bisa membaca data peserta kamu. Simpan kunci hanya di server atau aplikasi internal, jangan di kode website yang bisa dilihat pengunjung. Kalau kunci bocor, langsung cabut.

## Mencabut kunci

Di halaman **Integrasi**, klik ikon tempat sampah di baris kunci, lalu konfirmasi dengan **Cabut kunci**. Aplikasi yang memakai kunci itu langsung tidak bisa mengakses API lagi. Kolom **Terakhir dipakai** membantu menemukan kunci yang sudah tidak dipakai.

## Untuk developer

### Alamat dan autentikasi

Semua request dikirim ke `https://api.nyebar.id/api/org/v1`, dengan kunci di header `Authorization`:

```bash
curl https://api.nyebar.id/api/org/v1/me \
  -H "Authorization: Bearer nyb_live_..."
```

```json
{
  "organizer": { "id": 19, "name": "Komunitas Lari Nusantara", "slug": "lari-nusantara" },
  "key": { "id": 1, "name": "Aplikasi pemindai gerbang", "scopes": ["read", "checkin"] }
}
```

Waktu ditulis dalam format RFC 3339 dengan zona UTC, dan semua nominal dalam rupiah tanpa desimal.

### Endpoint

| Method | Path | Akses | Isi |
| --- | --- | --- | --- |
| GET | `/me` | apa saja | Organizer dan kunci yang dipakai |
| GET | `/events` | Baca data | Daftar event. Filter: `status` (`draft`, `review`, `published`, `rejected`), `ended` (`true`/`false`) |
| GET | `/events/{id}` | Baca data | Detail event beserta jenis tiketnya |
| GET | `/events/{id}/stats` | Baca data | Tiket terjual, check-in, pendapatan kotor, add-on, dan jumlah dilihat |
| GET | `/events/{id}/orders` | Baca data | Daftar pesanan. Filter: `status` (`pending`, `confirmed`, `cancelled`, `awaiting_approval`, `rejected`) |
| GET | `/events/{id}/tickets` | Baca data | Daftar tiket terbit. Filter: `checked_in` (`true`/`false`) |
| POST | `/events/{id}/check-ins` | Check-in | Check-in tiket dengan kodenya |

Event milik organizer lain dijawab seperti event yang tidak ada (`404`).

### Check-in

```bash
curl -X POST https://api.nyebar.id/api/org/v1/events/134/check-ins \
  -H "Authorization: Bearer nyb_live_..." \
  -H "Content-Type: application/json" \
  -d '{"code": "NYED3NKXDBK"}'
```

```json
{
  "status": "checked_in",
  "ticket": {
    "id": 512,
    "code": "NYED3NKXDBK",
    "holder_name": "Rina Putri",
    "holder_email": "rina@contoh.com",
    "ticket_type": { "id": 235, "name": "Reguler" },
    "bib_number": null,
    "checked_in_at": "2026-10-11T14:11:05Z",
    "created_at": "2026-10-02T03:20:41Z"
  }
}
```

Kalau tiket sudah pernah di-check-in, `status` berisi `already_checked_in` dan `checked_in_at` menunjukkan waktu check-in pertama. Jadi aman memanggil ulang request yang sama.

### Halaman berikutnya

Endpoint daftar menerima `limit` (1 sampai 100, default 20) dan `cursor`. Responsnya:

```json
{ "data": [ ... ], "next_cursor": "eyJpZCI6...", "has_more": true }
```

Selama `has_more` bernilai `true`, kirim lagi request yang sama dengan `cursor` berisi `next_cursor`.

### Error

Error dijawab dengan status HTTP dan isi seperti ini. Gunakan `code` di aplikasi kamu, bukan `message`:

```json
{ "message": "event not found", "code": "event_not_found", "request_id": "99e8fa6b-..." }
```

| Status | `code` | Artinya |
| --- | --- | --- |
| 400 | `invalid_parameter`, `invalid_cursor`, `validation_failed` | Parameter atau isi request tidak valid |
| 401 | `invalid_api_key` | Kunci tidak ada, salah, atau sudah dicabut |
| 403 | `api_key_scope_missing` | Kunci tidak punya akses untuk endpoint ini |
| 404 | `event_not_found`, `ticket_not_found` | Event atau tiket tidak ada di organizer kamu |
| 409 | `order_not_confirmed`, `ticket_not_issued` | Tiket belum bisa di-check-in |
| 429 | `rate_limited` | Terlalu banyak request |

### Batas request

Setiap kunci bisa mengirim 120 request per menit. Setiap respons membawa header `X-RateLimit-Limit`, `X-RateLimit-Remaining`, dan `X-RateLimit-Reset` (waktu Unix saat jatah direset). Kalau melewati batas, tunggu sesuai header `Retry-After`.
