NuminaDevelopers
Dashboard
Book journal entry

Book journal entry

POST
/v1/journal-entries/{id}/book

Books this one draft to the ledger. Each call is your own approval of the entry: Numina does not review it, so make sure a person at your company has checked it or has approved the rules your system books by. It works whether or not Numina AI and Autopilot are on, and books nothing else. A booked entry is final: it can only be corrected in Numina, with reversing entries.

Not available to Fuld Service customers (403 booking_not_available), whose books Numina's bookkeepers keep.

The entry needs a document: upload one first with POST /v1/journal-entries/{id}/attachments, or put one on it with attachment_id on PUT. An entry linked to an invoice needs no other document. Booking does not wait for Numina to read the document.

The date decides the accounting year. A date after the latest accounting year creates the following year. A closed year, a date before the company's first accounting date, or an earlier date no accounting year covers returns 400. So does a line without an account, a line with a zero amount, or lines that do not sum to zero, also once VAT is split out.

Safe to retry: booking an entry that is already booked returns it unchanged with 200.

Requires one ofjournal:bookwrite:ledger

Path parameters

  • idstring (uuid)Required
    Journal entry ID, as returned when it was created

Errors

  • 400Invalid input or validation failed
  • 401Invalid or missing authentication
  • 403Missing scope, the company is archived, or the company is on Fuld Service
  • 404The resource does not exist in this company
  • 409The entry has no document (`attachment_required`), was canceled, or Numina's bookkeeping agent is working on it (`conflict`; retry in a few minutes).
  • 429Rate limit exceeded
  • 500Internal Server Error

Every error has the same shape. See Errors.

cURL
curl -X POST https://api.numina.app/v1/journal-entries/550e8400-e29b-41d4-a716-446655440000/book \
  -H "Authorization: Bearer numi_YOUR_API_KEY"
JavaScript
const response = await fetch("https://api.numina.app/v1/journal-entries/550e8400-e29b-41d4-a716-446655440000/book", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.NUMINA_API_KEY}`,
  },
});

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

import requests

response = requests.post(
    "https://api.numina.app/v1/journal-entries/550e8400-e29b-41d4-a716-446655440000/book",
    headers={
        "Authorization": f"Bearer {os.environ['NUMINA_API_KEY']}",
    },
)
data = response.json()
Response
200
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "date": "2026-01-15",
  "text": "Invoice payment from customer",
  "status": "open",
  "contact_id": "550e8400-e29b-41d4-a716-446655440000",
  "created_at": "2026-01-15T10:30:00Z",
  "external_reference": "payroll-run-2026-01",
  "lines": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "account_number": 3000,
      "account_id": "550e8400-e29b-41d4-a716-446655440001",
      "account_name": "Revenue",
      "amount": -1000,
      "text": "Invoice payment",
      "vat_code": "U25",
      "currency_code": "DKK",
      "currency_rate": 1
    }
  ],
  "state": "draft",
  "attachment": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "file_name": "string",
    "status": "string",
    "attachment_number": 42
  }
}