Books

The books family (43 methods) is the agent lane of the finance desk: the same domain services the app calls, so floors, holds, and the signature law behave identically whether a human clicks or an agent calls. Scopes: books.read / books.write — and scope alone cannot move money.

The signature law

Six acts complete only on proof of a human decision, no matter who calls or what scope they hold:

| Signature act | What it releases | | --- | --- | | payrollSign | A drafted pay run | | taxSignLodge | A prepared tax lodgement | | billScheduleRun | A scheduled payment run | | invoiceChaseStep (step ≥ 2) | Escalating dunning beyond the first nudge | | onboardingAdvance (contract step) | An employment contract | | matchHoldResolve (above-floor) | A held bank-feed match above the materiality floor |

Called from the agent lane without proof, these do not error — they return a hold frame and append one books.signature.hold event to the ledger:

{
  "ok": true,
  "result": {
    "status": "approval_required",
    "approval": {
      "actionClass": "books.payroll_sign",
      "payloadHash": "b3a9…",
      "subject": { "kind": "books.signature", "subjectId": "run_…", "summary": "Sign the August pay run" },
      "expiresInMs": 259200000
    },
    "subjectId": "run_…",
    "message": "Sign the August pay run — held for a human signature. File approval.request with this actionClass, payloadHash and subject; once a human approves it, retry with the approvalId (or the minted signatureToken) and a fresh idempotency key."
  }
}

The frame tells you exactly what to file. Request the approval, wait for the human, then retry the same call with approvalId (or the minted signatureToken) and a fresh x-idempotency-key — the full loop is worked through in Governance. The proof is cryptographically bound to exactly this act (org, action class, subject row, payload hash) and is single-use: a second act on the same approval refuses.

Related floor releases behave the same way by refusal: billApprove on a bill held for ABOVE FLOOR or NEW PAYEE (PB-B1) refuses the bare agent lane with GOVERNANCE_NOT_READY until a human signature backs it.

Work the desk

| Area | Methods | | --- | --- | | Reconciliation | feedLines, matchAccept, matchHoldResolve, receiptsRegister, lineRecode, journalPost | | Receivables | invoiceDraft, invoiceSend, invoiceChaseStep, invoiceRecordPayment, invoiceCreditNote, invoiceVoid, invoicePromise, statementRun | | Payables | billCapture, billApprove, billHold, billReturn, billScheduleRun | | Expenses | expenseClaim, expenseApprove | | Payroll and people | payrollDraft, payrollSign, payrollRecall, onboardingStart, onboardingAdvance, leaveRequest, leaveApprove, stpResubmit | | Tax | taxPrepare, taxHold, taxReturn, taxSignLodge | | Assets | assetDepreciationRun, assetDispose | | Reads | accounts, journals, invoices, bills, taxObligations, reports, assets, ask |

A typical receivables flow:

# Draft, then send — each returns { ledgerId, … }
curl -X POST https://os.cohortapp.com/api/v1/books.invoiceDraft \
  -H "Authorization: Bearer $COHORT_API_KEY" -H "Content-Type: application/json" \
  -H "x-idempotency-key: inv-acme-aug" \
  -d '{"params": {"payeeName": "Acme Pty Ltd", "description": "August retainer", "totalCents": 450000, "dueDays": 14}}'

curl -X POST https://os.cohortapp.com/api/v1/books.invoiceSend \
  -H "Authorization: Bearer $COHORT_API_KEY" -H "Content-Type: application/json" \
  -H "x-idempotency-key: inv-acme-aug-send" \
  -d '{"params": {"id": "inv_812"}}'

Results quote a ledgerId — the chain reference for the act (see The event ledger). Relay held and refused outcomes verbatim; a held lodgement reported as "lodged" is the one failure mode the desk cannot forgive.

Retries

Books writes are idempotent by state on top of the idempotency header: a replayed transition against an already-transitioned row no-ops rather than double-posting. The exceptions, where each run is deliberately a new act: lineRecode, invoicePromise, statementRun, taxReturn, stpResubmit.

Ask the books

books.ask answers a grounded question over the ledger and desks ("what did we spend on hosting last quarter?") on the read scope, with its model call self-audited through the AI gateway. Use it for analysis; use the typed reads for anything you will act on.