# Eine Datei schicken und lesen

Schicken Sie ein PDF, ein Bild oder eine E-Rechnung, warten Sie, bis Ocost sie gelesen hat, und lesen Sie dann ihre Belege. Eine Datei kann mehrere Belege enthalten. Ein Scan von drei Rechnungen ist eine Datei mit drei Belegen.

## Die Datei schicken

Schicken Sie die Datei als `multipart/form-data` an `POST /public/v1/files`. Der Schlüssel braucht die Berechtigung `documents:write`.

```bash
curl -sS https://api.ocost.io/public/v1/files \
  -H "Authorization: Bearer $OCOST_KEY" \
  -F "file=@scan.pdf" -F "name=scan.pdf" -F "external_ref=account.move,42"
```

| Feld | Bedeutung |
| --- | --- |
| `file` | Pflicht. Ein PDF, ein Bild (JPEG, PNG, TIFF, WebP) oder das XML einer E-Rechnung (XRechnung, UBL, CII), bis 25 MB. Archive werden nicht gelesen. |
| `name` | Der Dateiname. Ohne ihn nimmt Ocost den des Uploads. |
| `external_ref` | Ihre eigene Kennung, bis 200 Zeichen, mit der Datei zurückgegeben. |

Eine neue Datei ergibt `202 Accepted` mit `"status": "received"`, und das Lesen beginnt sofort:

```json
{ "id": "01a1b08c-6e3a-7562-8f4a-7924722667b1", "name": "scan.pdf", "status": "received", "external_ref": "account.move,42", "documents": [] }
```

Jede Antwort trägt `X-Ocost-Documents-Left`, die Belege, die Ihr Tarif in diesem Monat noch hat. [Grenzen und Fehler](https://docs.ocost.io/de/limits.md) listet die Ablehnungen.

## Sicher erneut schicken

Ocost erkennt eine Datei am SHA-256 ihrer Bytes, nicht an ihrem Namen. Dieselben Bytes ergeben erneut `200 OK` mit dieser Datei, wie sie gerade ist. Ocost liest und zählt sie nicht noch einmal, und die Datei behält ihre erste `external_ref`. Nach einem Timeout schicken Sie die Datei also erneut.

## Warten, bis sie gelesen ist

Fragen Sie die Datei mit `GET /public/v1/files/{file_id}` ab, Berechtigung `documents:read`. Fragen Sie eine halbe Minute lang alle 2 bis 3 Sekunden, danach alle 10 bis 30 Sekunden. Die meisten PDFs brauchen unter einer Minute, lange einige.

```python
def wait_for(session, file_id, timeout=300):
    started = time.monotonic()
    while time.monotonic() - started < timeout:
        file = session.get(f"{API}/files/{file_id}", timeout=15).json()
        if file["status"] not in ("received", "reading"):
            return file
        time.sleep(3 if time.monotonic() - started < 30 else 15)
    return file
```

Die Datei ist fertig, wenn ihr `status` `read`, `not_read` oder `failed` ist. [Status und Gründe](https://docs.ocost.io/de/statuses.md) erklärt jeden. Für viele Dateien zugleich [bleiben Sie synchron](https://docs.ocost.io/de/sync.md), statt jede einzeln abzufragen.

## Ihre Belege lesen

Eine gelesene Datei listet ihre Belege in `documents`, jeden mit `id`, `kind`, `number` und `pages`. `GET /public/v1/files/{file_id}/document` liefert den ersten. `GET /public/v1/documents/{document_id}` liefert jeden davon.

```bash
curl -sS https://api.ocost.io/public/v1/documents/01a1b08c-7aa1-7b52-9d4e-2f1f1c0c4f11 \
  -H "Authorization: Bearer $OCOST_KEY"
```

Die Antwort ist der Beleg als `ocost.document.v1`. [Der Beleg](https://docs.ocost.io/de/document.md) zeigt einen ganzen und erklärt jedes Feld.

## Das Original holen

`GET /public/v1/files/{file_id}/content` liefert die Bytes, wie Sie sie geschickt haben.

```bash
curl -sS -o scan.pdf https://api.ocost.io/public/v1/files/$FILE_ID/content \
  -H "Authorization: Bearer $OCOST_KEY"
```

## Eine Datei löschen

`DELETE /public/v1/files/{file_id}` löscht die Datei sofort und endgültig. Das umfasst ihre Belege, alles Gelesene, ihren Suchindex und das Original. Der Schlüssel braucht `documents:write`.

```bash
curl -sS -X DELETE https://api.ocost.io/public/v1/files/$FILE_ID \
  -H "Authorization: Bearer $OCOST_KEY"
```

Ocost antwortet `204` und danach `404`. In zwei Fällen lehnt es ab:

| Antwort | Was tun |
| --- | --- |
| `409 urn:ocost:file:reading` | Die Datei wird gerade gelesen. Versuchen Sie es später erneut. |
| `409 urn:ocost:file:linked` | Ocost braucht die Datei noch, für eine gebuchte Rechnung, einen Kontoauszug, eine offene Frage oder ein Projekt. `detail` sagt, wofür. Löschen Sie sie in Ocost, sobald nichts sie mehr braucht. |
