Builder's guide · Appendix A
A complete request, end to end
Posting a manual journal: create the draft, then post it.
# 1. Create a draft (no balance changes yet)
curl -X POST https://books.internal.example/v1/ledger/manual-journals \
-H 'X-Source-System: console' \
-H "Authorization: Bearer $AK_WRITER_KEY" \
-H 'Idempotency-Key: 5d7f6a0e-2c1b-4c39-9a9e-3e0b6f1f9a11' \
-H 'Content-Type: application/json' \
-d '{ "company_id": "…", "entry_type": "adjusting",
"posting_date": "2026-11-06", "description": "Accrue November rent",
"prepared_by": "Sam Ortiz",
"lines": [ { "gl_account_id": "…rent expense…", "debit_amount": "900.00" },
{ "gl_account_id": "…accrued liabilities…", "credit_amount": "900.00" } ] }'
# 2. Post it, after the person confirms (a new key: this is a new action)
curl -X POST https://books.internal.example/v1/ledger/manual-journals/<id>/post \
-H 'X-Source-System: console' \
-H "Authorization: Bearer $AK_WRITER_KEY" \
-H 'Idempotency-Key: 9a2e1c44-7b0d-4f6e-8a51-c1d2e3f4a5b6'
# 3. Record in the console's audit table:
# person, route, X-Request-Id, journal id, journal entry id
The fields follow ManualJournalCreate in api/openapi.yaml at version 0.1.0. No journal_number is sent because the company has a number series (section 7). Generate your client from the OpenAPI file rather than copying this example.
The authentication checks, in order
| Step | Check | Failure |
|---|---|---|
| 1 | X-Source-System present | 400 SOURCE_SYSTEM_MISSING |
| 2 | Bearer credential present | 401 AUTHENTICATION_REQUIRED |
| 3 | Key well-formed and genuine | 401 CREDENTIAL_INVALID |
| 4 | The writer code exists | 403 SOURCE_SYSTEM_UNKNOWN |
| 5 | The header names the key's own writer | 403 SOURCE_SYSTEM_CREDENTIAL_MISMATCH |
| 6 | The writer is active | 403 SOURCE_SYSTEM_INACTIVE |
| 7 | Key not revoked or expired | 401 CREDENTIAL_INVALID |
| 8 | The role allows the route | 403 OPERATION_NOT_PERMITTED |
| 9 | The company is in scope | 403 COMPANY_NOT_IN_SCOPE |