StabisoDocs

API reference

Recurring journals

Journal entries that repeat (rent, allocations, accruals) monthly, quarterly or yearly, optionally reversed on the first day of the next period: posted on demand by a run that is idempotent, each entry through the approval policy.

Operation Summary Scope Idempotency-Key
GET /v1/recurring-journals List recurring journals read
POST /v1/recurring-journals Create a recurring journal draft required
POST /v1/recurring-journals/run Post the recurring journals that are due draft required
GET /v1/recurring-journals/{recurring_journal_id} Get a recurring journal read
PATCH /v1/recurring-journals/{recurring_journal_id} Change a recurring journal draft
POST /v1/recurring-journals/{recurring_journal_id}/activate Activate a recurring journal draft
POST /v1/recurring-journals/{recurring_journal_id}/pause Pause a recurring journal draft
GET /v1/recurring-journals/{recurring_journal_id}/runs List the entries a recurring journal made read

GET /v1/recurring-journals

List recurring journals

Recurring journals, the one that falls due first at the top (the ended ones last). due_through is the due list: the recurring journals a run through that day would make entries for, the same rule as the Role Center cue. Read-only.

Required scope read (admin implies every scope)
Operation id list_recurring_journals_v1_recurring_journals_get

Parameters

In Name Type Required Description
query entity string or null Only this entity's recurring journals (code or id).
query status "active" | "draft" | "ended" | "paused" or null Only those with this status: draft, active, paused or ended.
query due_through string (date) or null Only those a run through this day would make entries for: active, with a next due date on or before it (ISO 8601). This is the list the Role Center's recurring_journals_due counts.
query limit integer How many to return, next due first. (min 1; max 1000; default 100)

Example request

curl "$ERP_URL/v1/recurring-journals" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK array of RecurringJournalOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

[
  {
    "activated_at": "2026-09-29T08:10:00Z",
    "activated_by": {
      "id": "user:alice",
      "name": "Alice",
      "type": "human"
    },
    "created_at": "2026-09-29T08:05:00Z",
    "created_by": {
      "id": "user:alice",
      "name": "Alice",
      "type": "human"
    },
    "description": "Accrued office rent",
    "entity": "CH01",
    "entries_made": 1,
    "frequency": "monthly",
    "id": "5b1c7e2a-9d34-4f6b-a8e1-3c2d4e5f6a7b",
    "lines": [
      {
        "account": "6000",
        "credit": "0.00",
        "debit": "4500.00",
        "description": "Office rent Zürich",
        "dimensions": {}
      },
      {
        "account": "2300",
        "credit": "4500.00",
        "debit": "0.00",
        "description": "Accrued rent",
        "dimensions": {}
      }
    ],
    "name": "Office rent accrual",
    "next_due": "2026-10-31",
    "reverse_next_period": true,
    "start_date": "2026-09-30",
    "status": "active"
  }
]

POST /v1/recurring-journals

Create a recurring journal

Create a recurring journal as a draft: the description and lines of a journal entry that repeats, how often, from when until when, and whether each entry is reversed on the first day of the next period (an accrual). Nothing is posted until a person activates it and a run makes the entries that are due (POST /v1/recurring-journals/run). The first entry is built without being kept, so a missing account, lines that do not balance or a closed period are refused now (404, 409, 422) instead of at the first run. Needs an Idempotency-Key.

Required scope draft (admin implies every scope)
Idempotency-Key required
Operation id create_recurring_journal_v1_recurring_journals_post

Request body

application/json (required): RecurringJournalInput

Field Type Required Description
entity string yes Code (or id) of the entity whose books the entries are in.
name string yes What the recurring journal is called in lists, e.g. Office rent accrual. (min length 1; max length 200)
description string yes The description of every entry it makes, shown in the journal and the general ledger. (min length 1; max length 500)
frequency "monthly" | "quarterly" | "yearly" yes monthly, quarterly (every 3 months) or yearly. The due dates are counted from start_date and keep its day of the month; a month that is too short takes its last day (start on the 31st: 31 Jan, 28 Feb, 31 Mar, 30 Apr).
start_date string (date) yes The first due date (ISO 8601): the date of the first entry. It may lie in the past, in an open period.
end_date string (date) or null The last day an entry may fall due, inclusive (ISO 8601); null for no end. After the last due date the recurring journal ends by itself.
reverse_next_period boolean An accrual: each entry is reversed on the first day of the period after its own (the entry's auto_reverse_on), when it posts. (default false)
lines array of RecurringJournalLineInput yes The lines of every entry, at least two. Debits and credits must balance. (min items 2)

Example request

curl -X POST "$ERP_URL/v1/recurring-journals" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "description": "Accrued office rent",
  "entity": "CH01",
  "frequency": "monthly",
  "lines": [
    {
      "account": "6000",
      "debit": "4500.00",
      "description": "Office rent Zürich"
    },
    {
      "account": "2300",
      "credit": "4500.00",
      "description": "Accrued rent"
    }
  ],
  "name": "Office rent accrual",
  "reverse_next_period": true,
  "start_date": "2026-09-30"
}'

Responses

Status Meaning Body
201 Created RecurringJournalOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "activated_at": "2026-09-29T08:10:00Z",
  "activated_by": {
    "id": "user:alice",
    "name": "Alice",
    "type": "human"
  },
  "created_at": "2026-09-29T08:05:00Z",
  "created_by": {
    "id": "user:alice",
    "name": "Alice",
    "type": "human"
  },
  "description": "Accrued office rent",
  "entity": "CH01",
  "entries_made": 1,
  "frequency": "monthly",
  "id": "5b1c7e2a-9d34-4f6b-a8e1-3c2d4e5f6a7b",
  "lines": [
    {
      "account": "6000",
      "credit": "0.00",
      "debit": "4500.00",
      "description": "Office rent Zürich",
      "dimensions": {}
    },
    {
      "account": "2300",
      "credit": "4500.00",
      "debit": "0.00",
      "description": "Accrued rent",
      "dimensions": {}
    }
  ],
  "name": "Office rent accrual",
  "next_due": "2026-10-31",
  "reverse_next_period": true,
  "start_date": "2026-09-30",
  "status": "active"
}

POST /v1/recurring-journals/run

Post the recurring journals that are due

Make the entry of every due date on or before through (never after today where the entity is) of every active recurring journal, in date order, each dated its due date.

Each entry is submitted like an entry typed by hand: the approval policy decides for the caller whether it posts or waits for a second person (pending_approval). An accrual's entry is reversed on the first day of the next period when it posts. It is idempotent: a repeated, retried or simultaneous run makes nothing twice (one entry per recurring journal and due date, enforced by the database); an Idempotency-Key replays the first answer. A period that cannot be made (a closed period, an inactive account) is failed with its error, stops that recurring journal at that date and leaves the others running; the next run tries it again. An entry the second person rejects is made again by the next run the same way. At most twelve due dates per recurring journal in one run: more_due says to run again. Needs an Idempotency-Key.

Required scope draft (admin implies every scope)
Idempotency-Key required
Operation id run_recurring_journals_v1_recurring_journals_run_post

Request body

application/json (required): RecurringJournalRunInput

Field Type Required Description
through string (date) yes Make the entries that fall due on or before this day (ISO 8601, inclusive); never after today where the entity is.
entity string or null Only the recurring journals of this entity (code or id).
template string (uuid) or null Only this recurring journal (it must be active).

Example request

curl -X POST "$ERP_URL/v1/recurring-journals/run" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "entity": "CH01",
  "through": "2026-10-31"
}'

Responses

Status Meaning Body
200 OK RecurringJournalRunResult
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "failed": 0,
  "items": [
    {
      "due_date": "2026-10-31",
      "entry_id": "8e4f2a1b-3c5d-4e6f-9a7b-1c2d3e4f5a6b",
      "entry_number": "JE-2026-000123",
      "status": "posted",
      "template_id": "5b1c7e2a-9d34-4f6b-a8e1-3c2d4e5f6a7b",
      "template_name": "Office rent accrual"
    }
  ],
  "made": 1,
  "more_due": false,
  "through": "2026-10-31"
}

GET /v1/recurring-journals/{recurring_journal_id}

Get a recurring journal

One recurring journal: its lines, schedule, status, next due date and how many entries it has made. 404 when it does not exist.

Required scope read (admin implies every scope)
Operation id get_recurring_journal_v1_recurring_journals__recurring_journal_id__get

Parameters

In Name Type Required Description
path recurring_journal_id string (uuid) yes Id of the recurring journal (GET /v1/recurring-journals).

Example request

curl "$ERP_URL/v1/recurring-journals/5b1c7e2a-9d34-4f6b-a8e1-3c2d4e5f6a7b" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK RecurringJournalOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "activated_at": "2026-09-29T08:10:00Z",
  "activated_by": {
    "id": "user:alice",
    "name": "Alice",
    "type": "human"
  },
  "created_at": "2026-09-29T08:05:00Z",
  "created_by": {
    "id": "user:alice",
    "name": "Alice",
    "type": "human"
  },
  "description": "Accrued office rent",
  "entity": "CH01",
  "entries_made": 1,
  "frequency": "monthly",
  "id": "5b1c7e2a-9d34-4f6b-a8e1-3c2d4e5f6a7b",
  "lines": [
    {
      "account": "6000",
      "credit": "0.00",
      "debit": "4500.00",
      "description": "Office rent Zürich",
      "dimensions": {}
    },
    {
      "account": "2300",
      "credit": "4500.00",
      "debit": "0.00",
      "description": "Accrued rent",
      "dimensions": {}
    }
  ],
  "name": "Office rent accrual",
  "next_due": "2026-10-31",
  "reverse_next_period": true,
  "start_date": "2026-09-30",
  "status": "active"
}

PATCH /v1/recurring-journals/{recurring_journal_id}

Change a recurring journal

Change a recurring journal. Omitted fields keep their value; lines replaces every line. The next entry is built without being kept to check the change. frequency and start_date cannot change once an entry was made (409): end it and create a new one. A change of lines, end_date or reverse_next_period returns an active or paused recurring journal to draft, so a person activates it again. An end date before the next due date ends it. 409 for an ended recurring journal; 404, 422 as when creating.

Required scope draft (admin implies every scope)
Idempotency-Key not used
Operation id update_recurring_journal_v1_recurring_journals__recurring_journal_id__patch

Parameters

In Name Type Required Description
path recurring_journal_id string (uuid) yes Id of the recurring journal (GET /v1/recurring-journals).

Request body

application/json (required): RecurringJournalUpdate

Field Type Required Description
name string or null What it is called. (min length 1; max length 200)
description string or null The description of the entries. (min length 1; max length 500)
frequency "monthly" | "quarterly" | "yearly" or null monthly, quarterly or yearly; before the first entry.
start_date string (date) or null The first due date (ISO 8601); before the first entry.
end_date string (date) or null The last due date, inclusive; null removes the end.
reverse_next_period boolean or null Whether each entry is reversed in the next period.
lines array of RecurringJournalLineInput or null The new lines; they replace all existing lines. (min items 2)

Example request

curl -X PATCH "$ERP_URL/v1/recurring-journals/5b1c7e2a-9d34-4f6b-a8e1-3c2d4e5f6a7b" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "end_date": "2027-12-31",
  "reverse_next_period": true
}'

Responses

Status Meaning Body
200 OK RecurringJournalOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "activated_at": "2026-09-29T08:10:00Z",
  "activated_by": {
    "id": "user:alice",
    "name": "Alice",
    "type": "human"
  },
  "created_at": "2026-09-29T08:05:00Z",
  "created_by": {
    "id": "user:alice",
    "name": "Alice",
    "type": "human"
  },
  "description": "Accrued office rent",
  "entity": "CH01",
  "entries_made": 1,
  "frequency": "monthly",
  "id": "5b1c7e2a-9d34-4f6b-a8e1-3c2d4e5f6a7b",
  "lines": [
    {
      "account": "6000",
      "credit": "0.00",
      "debit": "4500.00",
      "description": "Office rent Zürich",
      "dimensions": {}
    },
    {
      "account": "2300",
      "credit": "4500.00",
      "debit": "0.00",
      "description": "Accrued rent",
      "dimensions": {}
    }
  ],
  "name": "Office rent accrual",
  "next_due": "2026-10-31",
  "reverse_next_period": true,
  "start_date": "2026-09-30",
  "status": "active"
}

POST /v1/recurring-journals/{recurring_journal_id}/activate

Activate a recurring journal

Make a draft or paused recurring journal run, so that runs make its entries. A person's step: an agent is refused (403). The next entry is built without being kept first. Each entry a run makes still goes through the approval policy. 409 unless it is a draft or paused.

Required scope draft (admin implies every scope)
Idempotency-Key not used
Operation id activate_recurring_journal_v1_recurring_journals__recurring_journal_id__activate_post

Parameters

In Name Type Required Description
path recurring_journal_id string (uuid) yes Id of the recurring journal (GET /v1/recurring-journals).

Example request

curl -X POST "$ERP_URL/v1/recurring-journals/5b1c7e2a-9d34-4f6b-a8e1-3c2d4e5f6a7b/activate" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK RecurringJournalOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "activated_at": "2026-09-29T08:10:00Z",
  "activated_by": {
    "id": "user:alice",
    "name": "Alice",
    "type": "human"
  },
  "created_at": "2026-09-29T08:05:00Z",
  "created_by": {
    "id": "user:alice",
    "name": "Alice",
    "type": "human"
  },
  "description": "Accrued office rent",
  "entity": "CH01",
  "entries_made": 1,
  "frequency": "monthly",
  "id": "5b1c7e2a-9d34-4f6b-a8e1-3c2d4e5f6a7b",
  "lines": [
    {
      "account": "6000",
      "credit": "0.00",
      "debit": "4500.00",
      "description": "Office rent Zürich",
      "dimensions": {}
    },
    {
      "account": "2300",
      "credit": "4500.00",
      "debit": "0.00",
      "description": "Accrued rent",
      "dimensions": {}
    }
  ],
  "name": "Office rent accrual",
  "next_due": "2026-10-31",
  "reverse_next_period": true,
  "start_date": "2026-09-30",
  "status": "active"
}

POST /v1/recurring-journals/{recurring_journal_id}/pause

Pause a recurring journal

Stop an active recurring journal from making entries, with a reason kept in the audit trail, until it is activated again. 409 unless it is active.

Required scope draft (admin implies every scope)
Idempotency-Key not used
Operation id pause_recurring_journal_v1_recurring_journals__recurring_journal_id__pause_post

Parameters

In Name Type Required Description
path recurring_journal_id string (uuid) yes Id of the recurring journal (GET /v1/recurring-journals).

Request body

application/json (required): RecurringJournalPause

Field Type Required Description
reason string yes Why; kept with it and in the audit trail. (min length 1; max length 500)

Example request

curl -X POST "$ERP_URL/v1/recurring-journals/5b1c7e2a-9d34-4f6b-a8e1-3c2d4e5f6a7b/pause" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "reason": "Lease under renegotiation"
}'

Responses

Status Meaning Body
200 OK RecurringJournalOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "activated_at": "2026-09-29T08:10:00Z",
  "activated_by": {
    "id": "user:alice",
    "name": "Alice",
    "type": "human"
  },
  "created_at": "2026-09-29T08:05:00Z",
  "created_by": {
    "id": "user:alice",
    "name": "Alice",
    "type": "human"
  },
  "description": "Accrued office rent",
  "entity": "CH01",
  "entries_made": 1,
  "frequency": "monthly",
  "id": "5b1c7e2a-9d34-4f6b-a8e1-3c2d4e5f6a7b",
  "lines": [
    {
      "account": "6000",
      "credit": "0.00",
      "debit": "4500.00",
      "description": "Office rent Zürich",
      "dimensions": {}
    },
    {
      "account": "2300",
      "credit": "4500.00",
      "debit": "0.00",
      "description": "Accrued rent",
      "dimensions": {}
    }
  ],
  "name": "Office rent accrual",
  "next_due": "2026-10-31",
  "reverse_next_period": true,
  "start_date": "2026-09-30",
  "status": "active"
}

GET /v1/recurring-journals/{recurring_journal_id}/runs

List the entries a recurring journal made

Every period a run has made or tried for the recurring journal, oldest first: the due date, what came of it (posted, pending_approval, rejected, failed), the entry with its number and status now, its reversal (an accrual's), the error of a failed period, and who ran it. 404 when the recurring journal does not exist.

Required scope read (admin implies every scope)
Operation id list_recurring_journal_runs_v1_recurring_journals__recurring_journal_id__runs_get

Parameters

In Name Type Required Description
path recurring_journal_id string (uuid) yes Id of the recurring journal (GET /v1/recurring-journals).

Example request

curl "$ERP_URL/v1/recurring-journals/5b1c7e2a-9d34-4f6b-a8e1-3c2d4e5f6a7b/runs" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK array of RecurringJournalRunOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

[
  {
    "created_at": "2026-10-01T08:30:00Z",
    "created_by": {
      "id": "user:alice",
      "name": "Alice",
      "type": "human"
    },
    "due_date": "2026-09-30",
    "entry_id": "8e4f2a1b-3c5d-4e6f-9a7b-1c2d3e4f5a6b",
    "entry_number": "JE-2026-000123",
    "entry_status": "posted",
    "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
    "reversal_id": "0f1e2d3c-4b5a-4968-8776-655443322110",
    "reversal_number": "JE-2026-000124",
    "status": "posted",
    "template_id": "5b1c7e2a-9d34-4f6b-a8e1-3c2d4e5f6a7b"
  }
]

Schemas

RecurringJournalInput

Field Type Required Description
entity string yes Code (or id) of the entity whose books the entries are in.
name string yes What the recurring journal is called in lists, e.g. Office rent accrual. (min length 1; max length 200)
description string yes The description of every entry it makes, shown in the journal and the general ledger. (min length 1; max length 500)
frequency "monthly" | "quarterly" | "yearly" yes monthly, quarterly (every 3 months) or yearly. The due dates are counted from start_date and keep its day of the month; a month that is too short takes its last day (start on the 31st: 31 Jan, 28 Feb, 31 Mar, 30 Apr).
start_date string (date) yes The first due date (ISO 8601): the date of the first entry. It may lie in the past, in an open period.
end_date string (date) or null The last day an entry may fall due, inclusive (ISO 8601); null for no end. After the last due date the recurring journal ends by itself.
reverse_next_period boolean An accrual: each entry is reversed on the first day of the period after its own (the entry's auto_reverse_on), when it posts. (default false)
lines array of RecurringJournalLineInput yes The lines of every entry, at least two. Debits and credits must balance. (min items 2)

RecurringJournalLineInput

Field Type Required Description
account string yes Account code (or id) in the entity, e.g. 6000.
debit decimal string Debit amount in the line's currency, e.g. 4500.00; zero or omitted on a credit line. Exactly one of debit and credit must be above zero. (min 0; default "0")
credit decimal string Credit amount; zero or omitted on a debit line. (min 0; default "0")
currency string or null ISO 4217 currency of the line; default the entity's functional currency. Each entry converts it at the rate of its own date. (pattern ^[A-Z]{3}$)
description string or null Text of this line; may be null.
dimensions map of string Analysis tags of the line, as on a journal entry, e.g. {"cost_centre": "ADMIN"}; empty when omitted.

RecurringJournalLineOut

A line of a recurring journal as stored.

Field Type Required Description
account string yes Account code.
debit string yes Debit amount in the line's currency.
credit string yes Credit amount in the line's currency.
currency string or null yes Currency of the line; null: the functional one.
description string or null yes Text of the line.
dimensions map of string yes Analysis tags of the line.

RecurringJournalOut

Field Type Required Description
id string (uuid) yes Id of the recurring journal.
entity string yes Code of the entity.
name string yes What it is called in lists.
description string yes The description of every entry it makes.
status "active" | "draft" | "ended" | "paused" yes draft (never activated, or its lines, start, frequency, end date or reversal changed since), active (runs make entries), paused or ended (the end date has passed).
frequency "monthly" | "quarterly" | "yearly" yes monthly, quarterly or yearly.
start_date string (date) yes The first due date.
end_date string (date) or null yes The last due date, inclusive; null for none.
next_due string (date) or null yes The next due date an entry is to be made for; null once it has ended.
reverse_next_period boolean yes Whether each entry is reversed on the first day of the next period.
lines array of RecurringJournalLineOut yes The lines of every entry.
activated_by object or null yes Who last activated it; null for a draft.
activated_at string (date-time) or null yes When it was last activated (UTC); null for a draft.
paused_by object or null yes Who paused it.
paused_at string (date-time) or null yes When it was paused (UTC).
pause_reason string or null yes Why it was paused.
created_by object yes Who created it.
created_at string (date-time) yes When it was created (UTC).
entries_made integer yes How many entries its runs have made so far (a rejected entry not counted).

RecurringJournalPause

Field Type Required Description
reason string yes Why; kept with it and in the audit trail. (min length 1; max length 500)

RecurringJournalRunInput

Field Type Required Description
through string (date) yes Make the entries that fall due on or before this day (ISO 8601, inclusive); never after today where the entity is.
entity string or null Only the recurring journals of this entity (code or id).
template string (uuid) or null Only this recurring journal (it must be active).

RecurringJournalRunItem

Field Type Required Description
template_id string (uuid) yes The recurring journal the entry was made from.
template_name string yes Its name.
due_date string (date) yes The due date of the period; also the entry date.
status "failed" | "pending_approval" | "posted" | "rejected" yes posted, pending_approval (the approval policy asked for a second person; the run record becomes posted or rejected when the entry is decided) or failed (nothing was made; error says why, the next run tries again). A rejected entry's period is due again: the next run makes it again.
entry_id string (uuid) or null yes The journal entry; null when it failed.
entry_number string or null yes Its number once posted.
error string or null yes Why a failed attempt failed; null otherwise.

RecurringJournalRunOut

Field Type Required Description
id string (uuid) yes Id of the run record.
template_id string (uuid) yes The recurring journal.
due_date string (date) yes The due date of the period.
status "failed" | "pending_approval" | "posted" | "rejected" yes What came of the period; see the run result.
entry_id string (uuid) or null yes The journal entry; null when it failed.
entry_number string or null yes Its number once posted.
entry_status string or null yes The entry's status now (pending_approval, posted, rejected...).
reversal_id string (uuid) or null yes The entry that reversed it (an accrual's reversal); null when none.
reversal_number string or null yes The reversal's number.
error string or null yes Why a failed attempt failed.
created_by object yes Who ran it (type, id, name).
created_at string (date-time) yes When (UTC).

RecurringJournalRunResult

Field Type Required Description
through string (date) yes The day the run went through.
made integer yes Entries made by this run (posted or waiting for approval).
failed integer yes Periods that failed; they stay due.
items array of RecurringJournalRunItem yes One item per period made or failed, by recurring journal and due date.
more_due boolean yes True when a recurring journal still has due dates after this run (twelve per run at most, and a run stops at a failed period): run again.

RecurringJournalUpdate

Changes to a recurring journal. Omitted fields keep their value; null removes the end date. frequency and start_date can change only before the first entry was made. A change of lines, end_date or reverse_next_period returns an active or paused recurring journal to draft (its activation cleared): a person activates it again.

Field Type Required Description
name string or null What it is called. (min length 1; max length 200)
description string or null The description of the entries. (min length 1; max length 500)
frequency "monthly" | "quarterly" | "yearly" or null monthly, quarterly or yearly; before the first entry.
start_date string (date) or null The first due date (ISO 8601); before the first entry.
end_date string (date) or null The last due date, inclusive; null removes the end.
reverse_next_period boolean or null Whether each entry is reversed in the next period.
lines array of RecurringJournalLineInput or null The new lines; they replace all existing lines. (min items 2)
Stabiso, the Enterprise System of Record · generated from the code and its guides · release 6f03a5e846b3