# Quickstart

Five steps from nothing to your first invoice as JSON. You need an Ocost account as its owner or accountant.

## 1. Sign up

Sign up at `https://app.ocost.io/auth/sign-up`, or sign in. Files you send through the API show in **Files**, like any upload.

## 2. Make a key

1. Open **[Settings › API](https://app.ocost.io/settings/api)** and choose **Make key**.
2. Name the key after its user, for example "Odoo production".
3. Keep the scopes it ticks and choose **Make key**.
4. Choose **Copy key**. The key starts with `ocost_sk_`, and Ocost shows it only once.

Keep it in your shell for the next steps:

```bash
export OCOST_KEY="ocost_sk_…"
```

## 3. Send a PDF

Send the file as `multipart/form-data` in the field `file`. `external_ref` is your own id, and Ocost gives it back.

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

```python
import os

import requests

API = "https://api.ocost.io/public/v1"
auth = {"Authorization": f"Bearer {os.environ['OCOST_KEY']}"}

with open("invoice.pdf", "rb") as f:
    sent = requests.post(
        f"{API}/files",
        headers=auth,
        files={"file": ("invoice.pdf", f, "application/pdf")},
        data={"external_ref": "account.move,42"},
        timeout=30,
    )
sent.raise_for_status()
file = sent.json()
```

```javascript
import { readFile } from 'node:fs/promises';

const API = 'https://api.ocost.io/public/v1';
const auth = { Authorization: `Bearer ${process.env.OCOST_KEY}` };

const form = new FormData();
form.append(
  'file',
  new Blob([await readFile('invoice.pdf')], { type: 'application/pdf' }),
  'invoice.pdf',
);
form.append('external_ref', 'account.move,42');
const sent = await fetch(`${API}/files`, { method: 'POST', headers: auth, body: form });
let file = await sent.json();
```

Ocost answers `202 Accepted` and starts reading:

```json
{
  "id": "01a1b08c-6e3a-7562-8f4a-7924722667b1",
  "name": "invoice.pdf",
  "status": "received",
  "reason": null,
  "external_ref": "account.move,42",
  "documents": [],
  "sha256": "0edd5593…"
}
```

## 4. Wait until it is read

Ask for the file every few seconds while its `status` is `received` or `reading`. Most PDFs take under a minute.

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

```python
import time

for wait in [2, 2, 3, 5, 5, 10, 10, 15, 30, 30]:
    file = requests.get(f"{API}/files/{file['id']}", headers=auth, timeout=15).json()
    if file["status"] not in ("received", "reading"):
        break
    time.sleep(wait)
```

```javascript
while (file.status === 'received' || file.status === 'reading') {
  await new Promise((done) => setTimeout(done, 3000));
  file = await (await fetch(`${API}/files/${file.id}`, { headers: auth })).json();
}
```

A read file lists its documents:

```json
{
  "id": "01a1b08c-6e3a-7562-8f4a-7924722667b1",
  "status": "read",
  "documents": [
    {
      "id": "01a1b08c-7aa1-7b52-9d4e-2f1f1c0c4f11",
      "kind": "invoice",
      "number": "RE-2026-1187",
      "pages": [1]
    }
  ]
}
```

A file that ends `not_read` or `failed` says why in `reason`. [Statuses and reasons](https://docs.ocost.io/en/statuses.md) lists them.

## 5. Read the document

Ask for the file's first document.

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

```python
document = requests.get(
    f"{API}/files/{file['id']}/document", headers=auth, timeout=15
).json()
print(document["number"], document["totals"]["gross"], document["currency"])
```

```javascript
const document = await (
  await fetch(`${API}/files/${file.id}/document`, { headers: auth })
).json();
console.log(document.number, document.totals.gross, document.currency);
```

The answer is the invoice as `ocost.document.v1`, shortened here:

```json
{
  "schema": "ocost.document.v1",
  "kind": "invoice",
  "number": "RE-2026-1187",
  "issue_date": "2026-11-03",
  "due_date": "2026-12-03",
  "currency": "EUR",
  "seller": { "name": "Musterbüro Lieferant GmbH", "vat_id": "DE123456789" },
  "totals": { "net": "1068.00", "tax": "202.92", "gross": "1270.92" }
}
```

## Next

- [Send a file and read it](https://docs.ocost.io/en/files.md) covers resending and deleting.
- [Stay in sync](https://docs.ocost.io/en/sync.md) collects every change with one call.
- [The document](https://docs.ocost.io/en/document.md) explains every field.
- [Search](https://docs.ocost.io/en/search.md) finds documents by words and by meaning.
- [Connect Odoo](https://docs.ocost.io/en/odoo.md) fills draft vendor bills.
