# Mengekspor kiriman

> Unduh kiriman sebagai CSV dari dashboard, atau ekspor setiap kiriman dengan REST API.

## CSV dari dashboard

Buka **Submissions**, atau tab kiriman milik sebuah formulir, atur filter yang Anda inginkan, lalu pilih **Export CSV**. File-nya mengikuti filter di layar.

| Filter | Nilai |
| --- | --- |
| Formulir | Satu formulir, atau semua formulir |
| Status | Diterima, spam, atau keduanya |
| Rentang tanggal | 24 jam terakhir, 7 hari terakhir, 30 hari terakhir, atau semua waktu |

- Kolomnya adalah `id`, `created_at`, `form`, `status`, lalu satu kolom per field. Untuk satu formulir, field yang didefinisikan muncul lebih dulu, diikuti nama field lain yang ditemukan di baris yang diekspor.
- Array berisi nilai biasa digabung dengan koma dan spasi. Objek ditulis sebagai JSON.
- Nilai yang diawali `=`, `+`, `-`, `@`, tab, atau carriage return diberi awalan `'`, agar aplikasi spreadsheet tidak menjalankannya sebagai rumus.
- File-nya UTF-8 dengan byte order mark, jadi Excel membuka huruf beraksen dengan benar.
- Satu ekspor memuat hingga 100.000 baris dan 500 kolom field. Persempit filter untuk workspace yang lebih besar, atau gunakan API.

## Semuanya dengan REST API

Untuk backup lengkap, sinkronisasi terjadwal, atau lebih dari 100.000 baris, telusuri halaman demi halaman lewat [REST API](https://ikiform.com/id/docs/api.md#list-submissions) dengan secret key yang punya `submissions:read`. Daftar diurutkan dari yang terbaru dan tetap stabil saat kiriman baru masuk.

**Node** (`export.ts`)

```ts
import { createWriteStream } from "node:fs";
import { createClient } from "@ikiform/sdk";

const ikiform = createClient({ apiKey: process.env.IKIFORM_SECRET_KEY! });
const out = createWriteStream("submissions.jsonl");

for await (const submission of ikiform.submissions.iterate({
  formId: "frm_xxxxxxxxxxxxxxxx",
  status: "received",
  limit: 100,
})) {
  out.write(`${JSON.stringify(submission)}\n`);
}

out.end();
```

**Python** (`export.py`)

```python
import csv
import os

import requests

session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['IKIFORM_SECRET_KEY']}"
params = {"form_id": "frm_xxxxxxxxxxxxxxxx", "status": "received", "limit": 100}

with open("submissions.csv", "w", newline="", encoding="utf-8") as file:
    writer = None
    while True:
        page = session.get("https://ikiform.com/api/v1/submissions", params=params, timeout=30).json()
        for submission in page["data"]:
            row = {"id": submission["id"], "created_at": submission["created_at"], **submission["fields"]}
            if writer is None:
                writer = csv.DictWriter(file, fieldnames=list(row), extrasaction="ignore")
                writer.writeheader()
            writer.writerow(row)
        if not page["has_more"]:
            break
        params["cursor"] = page["next_cursor"]
```

> Setiap key bisa membuat 100 request per menit. Dengan `limit: 100`, itu berarti hingga 10.000 kiriman per menit. Iterator SDK melempar `IkiformError` dengan `retryAfter` pada `429`; tunggu selama jumlah detik itu dan lanjutkan dari cursor terakhir.
