# Exportando envios

> Baixe os envios em CSV pelo painel, ou exporte todos os envios com a API REST.

## CSV pelo painel

Abra **Submissions**, ou a aba de envios de um formulário, defina os filtros que quiser e escolha **Export CSV**. O arquivo segue os filtros da tela.

| Filtro | Valores |
| --- | --- |
| Formulário | Um formulário, ou todos |
| Status | Recebidos, spam ou ambos |
| Período | Últimas 24 horas, últimos 7 dias, últimos 30 dias ou todo o período |

- As colunas são `id`, `created_at`, `form`, `status` e depois uma coluna por campo. Para um único formulário, os campos definidos vêm primeiro, seguidos de quaisquer outros nomes de campo encontrados nas linhas exportadas.
- Arrays de valores simples são unidos com vírgula e espaço. Objetos são escritos como JSON.
- Valores que começam com `=`, `+`, `-`, `@`, uma tabulação ou um retorno de carro ganham um `'` na frente, para que planilhas não os executem como fórmulas.
- O arquivo é UTF-8 com byte order mark, então o Excel abre acentos corretamente.
- Uma exportação comporta até 100.000 linhas e 500 colunas de campo. Restrinja os filtros em workspaces maiores, ou use a API.

## Tudo com a API REST

Para um backup completo, uma sincronização agendada ou mais de 100.000 linhas, percorra as páginas da [API REST](https://ikiform.com/pt-br/docs/api.md#list-submissions) com uma chave secreta que tenha `submissions:read`. As listas vêm das mais recentes para as mais antigas e ficam estáveis enquanto novos envios chegam.

**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"]
```

> Cada chave pode fazer 100 requisições por minuto. Com `limit: 100`, isso dá até 10.000 envios por minuto. O iterador do SDK lança um `IkiformError` com `retryAfter` em caso de `429`; espere esse número de segundos e continue a partir do último cursor.
