Book journal entry
/v1/journal-entries/{id}/bookBooks 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
- Journal entry ID, as returned when it was created
Errors
400Invalid input or validation failed401Invalid or missing authentication403Missing scope, the company is archived, or the company is on Fuld Service404The resource does not exist in this company409The 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 exceeded500Internal Server Error
Every error has the same shape. See Errors.
curl -X POST https://api.numina.app/v1/journal-entries/550e8400-e29b-41d4-a716-446655440000/book \
-H "Authorization: Bearer numi_YOUR_API_KEY"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();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(){
"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
}
}