NuminaDevelopers
Dashboard
Upload document to the inbox

Upload document to the inbox

POST
/v1/attachments

Uploads a document (PDF, PNG, JPG, or JPEG; max 10MB) without a journal entry, so it waits in the inbox. Put it on a draft later with attachment_id on PUT /v1/journal-entries/{id}. Numina reads it only with run_ocr "true", and the bookkeeping agent does not run on it. Uploading a file the company already has returns the existing document with 200 and duplicate: true.

Requires one ofdocuments:writewrite:draftwrite:ledger

Body

multipart/form-data

  • filefileRequired
    File to upload (PDF, PNG, JPG, or JPEG; max 10MB). Its content must match its declared type.
  • run_ocrstring
    If "true", Numina reads the file (OCR) so the document becomes searchable. Defaults to "false".
    One oftruefalse

Errors

  • 400The upload is missing, too large, or not a valid file
  • 401Invalid or missing authentication
  • 403Missing scope, or the company is archived
  • 429Rate limit exceeded
  • 500Internal Server Error

Every error has the same shape. See Errors.

cURL
curl -X POST https://api.numina.app/v1/attachments \
  -H "Authorization: Bearer numi_YOUR_API_KEY" \
  -F file=@receipt.pdf
JavaScript
import { openAsBlob } from "node:fs";

const form = new FormData();
form.append("file", await openAsBlob("receipt.pdf"), "receipt.pdf");

const response = await fetch("https://api.numina.app/v1/attachments", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.NUMINA_API_KEY}`,
  },
  body: form,
});

const data = await response.json();
Python
import os

import requests

response = requests.post(
    "https://api.numina.app/v1/attachments",
    headers={
        "Authorization": f"Bearer {os.environ['NUMINA_API_KEY']}",
    },
    files={"file": open("receipt.pdf", "rb")},
)
data = response.json()
Response
200
{
  "attachment": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "file_name": "string",
    "status": "uploaded",
    "created_at": "string",
    "attachment_number": 185,
    "year": "2026",
    "is_empty": false,
    "file_count": 0,
    "booked_accounting_year": "2026",
    "content_sha256": "string",
    "journal_entry_ids": [
      "550e8400-e29b-41d4-a716-446655440000"
    ]
  },
  "duplicate": false
}
201
{
  "attachment": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "file_name": "string",
    "status": "uploaded",
    "created_at": "string",
    "attachment_number": 185,
    "year": "2026",
    "is_empty": false,
    "file_count": 0,
    "booked_accounting_year": "2026",
    "content_sha256": "string",
    "journal_entry_ids": [
      "550e8400-e29b-41d4-a716-446655440000"
    ]
  },
  "duplicate": false
}