LedgerBee Developer
  • Getting started
  • Conventions
  • Products
  • Configuration
  • API Reference
Information
Accounts
    List accountsget
API Key
    Get current API keyget
Authority Extracts
    Submit authority extract datapost
Billing Groups
    Form a billing grouppostGet a billing groupgetAdd members to a billing grouppostRemove a member from a billing groupdeleteCheck billing group eligibilitypost
Budgets
    List budgetsgetGet a budgetgetGet the budget vs actuals comparisongetList a budget's frozen baselinesgetGet a frozen baseline with its snapshot cellsgetList a budget's re-baseline proposalsgetList a budget's scenariosgetResolve a budget's grid under a scenariogetGet the variance report vs a frozen baselinegetGet the runway headlineget
Checkout
    Confirm the checkoutpostQuote a first periodpostIntegration readinessgetMint a checkout sessionpostRehydrate a sessiongetRelease the card hold (edit-after-card)postPoll card statusgetOpen the card windowpostOpen a card-update window for a live subscriptionpost
Company
    Get company detailsget
Connected app OAuth
    JSON Web Key Set used to verify OAuth access-token signaturesgetRFC 8414 authorization-server metadata for the connected-app OAuth servergetRFC 9728 protected-resource metadata for an MCP resourcegetRFC 9728 protected-resource metadata for an MCP resourcegetOpenID Connect discovery document for the connected-app OAuth serverget
Credit Notes
    List credit notesgetCreate a credit notepostGet a credit notegetGet the delivery status of a credit notegetDownload the credit note PDFgetSend a credit note to the customerpostCredit a whole invoicepost
Customers
    List customersgetCreate a customerpostGet a customergetUpdate a customerpatchList a customer's contactsgetList a customer's departmentsgetList customer groupsget
Dimensions
    List all dimensionsgetCreate a new dimension categorypostGet a dimensiongetUpdate a dimension categoryputDelete a dimension categorydeleteList distribution keys (paginated)getCreate a distribution keypostGet a distribution keygetList dimension values (paginated)getCreate a new dimension valuepostUpdate a dimension valueputDelete a dimension valuedelete
Document Templates
    List document templatesget
Download Links
    Mint a download link for a document PDFgetDownload a minted linkget
Draft Journal Entries
    Create multiple draft journal entries in batchpostList draft journal entriesgetCreate a draft journal entrypostGet a draft journal entrygetDelete a draft journal entrydeleteBook a draft journal entrypost
Draft Journal Entries (v2)
    Create draft journal entries in batch (v2)postList draft journal entries (v2)getCreate a draft journal entry (v2)postGet a draft journal entry (v2)getDelete a draft journal entry (v2)deleteUpdate a draft journal entry (v2)patchBook a draft journal entry (v2)post
Entitlements
    List entitlementsgetCreate an entitlementpostGet an entitlementgetDelete an entitlementdeleteUpdate an entitlementpatch
Invoices
    List invoicesgetCreate a draft invoicepostGet an invoicegetGet the delivery status of an invoicegetDownload the invoice PDFgetSend an invoice to the customerpost
Journal Categories
    List journal categoriesgetCreate a journal categorypostUpdate a journal categoryputDelete a journal categorydelete
Journal Entries
    List journal entriesgetGet a journal entrygetUpdate a journal entry — correct the reference and/or set your external system idpatchGet attachments for a journal entrygetPreview a correction without posting itpostMove postings to different accounts, keeping the document intactpostReverse a posted entry and open a draft to re-enter itpostReverse posted journal entries in batchpostReverse a posted journal entrypost
Journal Entries (v2)
    Create a journal entry (v2)postCreate journal entries in batch (v2)post
MCP
    LedgerBee Developer MCP Serverpost
Meters
    List meter subscriptions by IDgetReport usagepostList meter subscriptions by nameget
Open Entries
    List a counterparty’s open entriesget
Order Confirmations
    List order confirmationsgetCreate a draft order confirmationpostGet an order confirmationgetUpdate a draft order confirmationpatchConvert an order confirmation into an invoicepostDownload an order confirmation as PDFgetSend an order confirmationpost
Payment Methods
    List saved payment methods for a customergetCancel a saved card on the payment providerdeleteUnassign a payment method from a customerdeleteGenerate a link for the customer to save a card for future paymentspostSet a saved payment method as the customer defaultput
Portal Plans
    List the full plan cataloguegetGet a plangetResolve the gated pricing catalogue for an identified buyer (partner display)post
Portal SSO
    Get a tenant's SSO signing keys (JWKS)getMint a checkout-vouch token (partner-vouched anonymous checkout)postMint a customer-portal SSO handoff referencepostProvision a customer + grant portal access (partner JIT provisioning)postRevoke (force-refresh) a user's customer-portal sessionspost
Product Groups
    List product groupsgetCreate a product grouppostGet a product groupgetDelete a product groupdeleteUpdate a product grouppatch
Product Prices
    Create a product pricepostGet a product pricegetDelete a product pricedeleteUpdate a product pricepatchActivate a product pricepostArchive a product pricepostDisable a product pricepostSet a price as the product defaultpost
Products
    List productsgetCreate a productpostGet a productgetDelete a productdeleteUpdate a productpatchArchive a productpost
Projects
    List all projectsgetCreate or update a project by external referenceputCreate a projectpostGet a projectgetUpdate a projectputGet project profitgetAdd a subprojectpostUpdate a subprojectputDelete a subprojectdelete
Quotes
    List quotesgetCreate a draft quotepostGet a quotegetUpdate a draft quotepatchConvert a quotepostDownload a quote as PDFgetSend a quotepost
Settlements
    List a counterparty’s settlementsgetSettle open entries against each otherpostGet a settlementgetCheck what settling these entries would dopost
Subscriptions
    List customer subscriptionsgetAssign a subscription to a customerpostGet a customer subscription by its stable idgetUpdate a customer subscriptionpatchRetry a failed card paymentpostList a subscription's pending scheduled changesgetCancel a single pending scheduled changedeleteCancel a customer subscriptionpostList subscription plansgetCreate a subscription planpostArchive a subscription planpost
Suppliers
    List suppliersgetCreate a supplierpostList supplier contactsgetList supplier departmentsgetList supplier groupsget
VAT Codes
    List VAT codesget
Vendors
    List vendorsgetCreate a vendorpostList vendor contactsgetList vendor departmentsgetList vendor groupsget
Webhook Endpoints
    List webhook endpointsgetCreate a webhook endpointpostRetrieve a webhook endpointgetUpdate a webhook endpointputDelete a webhook endpointdeleteRoll the signing secretpostSend a test eventpost
Schemas
LedgerBee Public API
LedgerBee Public API

Journal Entries (v2)

Download schema

Create a journal entry (v2)

POST
https://api.ledgerbee.com/api
/v2/journal-entries
x-api-key (header)
or
OAuth 2.0

Create a journal entry. For CUSTOMER_INVOICE / CUSTOMER_PAYMENT / SUPPLIER_INVOICE / SUPPLIER_PAYMENT, submit only the counter-side lines (revenue, expense, bank, etc.). The server appends the AR/AP leg on the customer's or vendor's group default account, with side derived from the sign of originalAmount (positive = invoice/payment, negative = credit-note/refund). Including a line on the group default account explicitly will be rejected.

For all other journal types this endpoint behaves identically to v1: pass through whatever lines you supply.

Attachments: include up to 10 base64-encoded files in the optional attachments[] field — same shape and limits as v1. Each becomes a Document linked to the created entry and surfaces via GET /api/v1/journal-entries/:id/attachments. Rejection paths: an invalid MIME type rejects at DTO validation with 400 SHARED_VALIDATION_FAILED; malformed base64 reaches the service and rejects with 400 JOURNAL_ENTRY_INVALID_ATTACHMENT_TYPE. Total request body must stay under 15MB.

Required Scope

  • journal-entries-write

Create a journal entry (v2) › Headers

x-api-idempotency-key
​string · maxLength: 255

Optional idempotency key for safely retrying mutating requests.

Create a journal entry (v2) › Request Body

CreateJournalEntryV2Dto
entryType
​string · enum · required

Journal type. For CUSTOMER_INVOICE / CUSTOMER_PAYMENT / SUPPLIER_INVOICE / SUPPLIER_PAYMENT the AR/AP leg is appended automatically; do not include it in lines.

Enum values:
journal
invoice
payment
supplier_invoice
supplier_payment
customer_invoice
customer_payment
date
​string · required

Posting date (YYYY-MM-DD).

originalAmount
​number · required

Face value of the document — what the counterparty is invoiced or pays. NOT the sum of lines. On CUSTOMER_INVOICE / CUSTOMER_PAYMENT / SUPPLIER_INVOICE / SUPPLIER_PAYMENT this value IS the appended AR/AP leg (its absolute value), so an account that appears on both sides of the entry — a clearing or pass-through account — must not be counted into it. Sign carries direction: positive = invoice / payment, negative = credit-note / refund.

​SplitEntryLine[] · minItems: 1 · maxItems: 1000 · required

Counter-side lines (revenue / expense / bank / outlay). For locked types do NOT include the AR/AP leg. The cap is per ENTRY, not per request or per journal category — nothing accumulates across entries, so a company with many unposted drafts is never refused for that reason.

customerId
​string

Customer reference. Required for CUSTOMER_* types.

supplierId
​string

Supplier reference. Required for SUPPLIER_* types.

description
​string · maxLength: 2000

Optional human-readable description.

reference
​string

Invoice number / external reference.

externalSystemId
​string · maxLength: 255

Your own system's id for this entry. Leading and trailing whitespace is trimmed before storage, and a value that is only whitespace is stored as no id at all — the list filter trims what it is given too, so an untrimmed value would be stored under an id no lookup could match. It is a lookup key, not a deduplication key: LedgerBee enforces no uniqueness on it and never compares it between requests, so several entries may carry the same id and repeating a request creates another entry. Filter GET /journal-entries by externalSystemId to find what an earlier run posted. For retries that must not post twice, send x-api-idempotency-key.

Example: erp-7f3a2c91
currency
​string | null · minLength: 3 · maxLength: 3 · pattern: ^[A-Za-z]{3}$

ISO 4217 alpha-3 currency code.

Example: DKK
exchangeRate
​number

Exchange rate from currency to the company base currency, e.g. 7.4612 for EUR to DKK. Must be greater than zero; a non-positive rate is rejected whatever the entry currency, so the same body is accepted or refused identically for every tenant. Omit the field to have the rate resolved from the rate feed at the posting date — supplying one lets an integrator that already converted the amount itself post both legs of a settlement against the same rate. Not applied when the entry is already denominated in the company base currency, where the conversion is the identity.

Example: 7.4612
tagIds
​string[]

Tag IDs applied at the entry level.

journalCategoryId
​string

Journal category ID (UUID). Must belong to the API key's app company; cross-tenant or unknown IDs are rejected with 400 JOURNAL_CATEGORY_NOT_FOUND. When omitted the entry uses the company's default category.

​AttachmentRequest[] · maxItems: 10

Inline file attachments (base64-encoded). Same shape and limits as v1: maximum 10 attachments per entry, a 10MB ceiling on each file measured AFTER base64 decoding (over it is rejected with DOCUMENT_UPLOAD_FILE_TOO_LARGE), and a 15MB ceiling on the total request body (JSON + base64 payload). Either can be the binding one: base64 inflates a payload by about a third, so two 6MB files each clear the per-file bound and exceed the request one. Each attachment becomes a Document linked to the created journal entry — equivalent to what GET /api/v1/journal-entries/:id/attachments returns. An invalid MIME type rejects at DTO validation with 400 SHARED_VALIDATION_FAILED; malformed base64 reaches the service and rejects with 400 JOURNAL_ENTRY_INVALID_ATTACHMENT_TYPE. Either rejects the whole entry, and in a batch the whole batch rolls back.

vendorId
​string · deprecated

Deprecated — use supplierId. Legacy alias; sending both with different values returns 400.

Create a journal entry (v2) › Responses

Journal entry created successfully

JournalEntryResponse
id
​string · required

Unique identifier of the created journal entry

Example: 550e8400-e29b-41d4-a716-446655440000
entryNumber
​string · required

Entry number assigned to the journal entry

Example: JE-00001
date
​string · required

Date of the journal entry

Example: 2026-01-15
amount
​number · required

Amount of the line accountId names, in that line's account currency (currency). On a two-line entry this is the entry total. On a wider entry it is one line of several — sum lines[].functionalAmount on either side for the total.

Example: 1000
currency
​string · required

Currency amount is denominated in — the operating currency of that first line's account.

Example: DKK
journalType
​string · required

Journal type

Example: JOURNAL_ENTRY
type
​string · required

Transaction type

Example: debit
status
​string · required

Status of the journal entry

Example: POSTED
accountId
​string · required

One non-VAT line of the entry, paired with contraAccountId as a two-line summary. On a two-line entry the pair describes the whole entry. On a wider one it describes two of its lines and nothing about the rest — read lines for the full picture. Which two are picked is not part of this contract and differs by endpoint (a read takes them in posting order; the draft-booking response takes a debit and a credit), so do not infer a line's position from it.

Example: 550e8400-e29b-41d4-a716-446655440000
createdAt
​string · required

Timestamp when the entry was created

Example: 2026-01-15T10:30:00.000Z
documentDate
​string

Document date (date on the invoice/voucher). Null for legacy entries.

Example: 2026-01-15
originalAmount
​number | null

What you posted, in the currency you posted it in — the document figure, before any conversion. Distinct from amount, which is denominated in the ACCOUNT currency (currency): a EUR entry against DKK accounts reports originalAmount: 200 / originalCurrency: "EUR" and amount: 1492.24 / currency: "DKK". Null on historical entries that stored no document amount.

Example: 200
originalCurrency
​string | null

The currency the entry was posted in: what originalAmount is denominated in, and what exchangeRate converts FROM. Present independently of originalAmount — an entry can name a currency and store no document amount, which is the historical shape, and the currency still says what its rate converts from. Null only on an entry that names no currency at all.

Example: EUR
exchangeRate
​number | null

Rate converting originalCurrency to the company base currency — 7.45 on a EUR entry of a DKK-based company means 1 EUR = 7.45 DKK, so originalAmount * exchangeRate is the base-currency total that lines[].functionalAmount sums to. Reported whether you supplied it on create or the platform resolved it, which is what lets you compute the difference against the rate your own settlement later used. 1 on an entry posted in the base currency, since that is the conversion that was applied and stored. Null only on historical entries that stored no rate at all.

Example: 7.45
exchangeRateDate
​string | null

Date the exchangeRate was captured for. Null whenever exchangeRate is.

Example: 2026-01-15
description
​string

Description of the journal entry

Example: Office supplies purchase
reference
​string

Reference number

Example: REF-2026-001
externalSystemId
​string

Your own system's id for this entry, when set. Not unique — several entries may share one id.

Example: erp-7f3a2c91
contraAccountId
​string

The other half of the accountId pair, when the entry has a second non-VAT line. Same caveat: it is one line, not a summary of every line other than accountId.

Example: 550e8400-e29b-41d4-a716-446655440001
​JournalEntryLine[]

Every line of the entry, including VAT lines the platform derived. This is the complete picture: accountId, contraAccountId, amount, currency and vatCodeId above all describe one line, or two, and nothing about the rest. Debits and credits balance across the array on functionalAmount. The order is stable for a given entry — normally the order the lines were posted in — but match lines by account rather than by position, and use vatSourceLineIndex to link a VAT line to its source.

customerId
​string

Customer ID if applicable

Example: 550e8400-e29b-41d4-a716-446655440002
supplierId
​string

Supplier ID if applicable

Example: 550e8400-e29b-41d4-a716-446655440003
vatCodeId
​string

VAT/Tax code on the line accountId names, if it has one. Lines can carry different codes — read lines[].vatCodeId for the per-line codes.

Example: 550e8400-e29b-41d4-a716-446655440000
tagIds
​string[]

Tag IDs attached to the entry as a whole. Per-line dimensions are on lines[].tagIds.

documentRefs
​string[]

Document IDs attached to the entry

vendorId
​string · deprecated

Deprecated — use supplierId. Legacy alias, emitted with the same value.

Example: 550e8400-e29b-41d4-a716-446655440003
POST/v2/journal-entries
curl https://api.ledgerbee.com/api/v2/journal-entries \ --request POST \ --header 'Content-Type: application/json' \ --header 'x-api-key: <api-key>' \ --data '{ "entryType": "journal", "date": "string", "originalAmount": 0, "customerId": "string", "supplierId": "string", "vendorId": "string", "description": "string", "reference": "string", "externalSystemId": "erp-7f3a2c91", "currency": "DKK", "exchangeRate": 7.4612, "lines": [ { "accountId": "550e8400-e29b-41d4-a716-446655440000", "type": "debit", "amount": 500, "vatCodeId": "550e8400-e29b-41d4-a716-446655440000", "description": "Consulting hours — March", "tagIds": [ "550e8400-e29b-41d4-a716-446655440003" ] } ], "tagIds": [ "string" ], "journalCategoryId": "string", "attachments": [ { "filename": "invoice.pdf", "content": "JVBERi0xLjQKJeLjz9MKMyAwIG9iago8PC...", "mimeType": "application/pdf" } ] }'
Example Request Body
{ "entryType": "journal", "date": "string", "originalAmount": 0, "customerId": "string", "supplierId": "string", "vendorId": "string", "description": "string", "reference": "string", "externalSystemId": "erp-7f3a2c91", "currency": "DKK", "exchangeRate": 7.4612, "lines": [ { "accountId": "550e8400-e29b-41d4-a716-446655440000", "type": "debit", "amount": 500, "vatCodeId": "550e8400-e29b-41d4-a716-446655440000", "description": "Consulting hours — March", "tagIds": [ "550e8400-e29b-41d4-a716-446655440003" ] } ], "tagIds": [ "string" ], "journalCategoryId": "string", "attachments": [ { "filename": "invoice.pdf", "content": "JVBERi0xLjQKJeLjz9MKMyAwIG9iago8PC...", "mimeType": "application/pdf" } ] }
json
application/json
Example Responses
{ "id": "550e8400-e29b-41d4-a716-446655440000", "entryNumber": "JE-00001", "date": "2026-01-15", "documentDate": "2026-01-15", "amount": 1000, "currency": "DKK", "originalAmount": 200, "originalCurrency": "EUR", "exchangeRate": 7.45, "exchangeRateDate": "2026-01-15", "description": "Office supplies purchase", "reference": "REF-2026-001", "externalSystemId": "erp-7f3a2c91", "journalType": "JOURNAL_ENTRY", "type": "debit", "status": "POSTED", "accountId": "550e8400-e29b-41d4-a716-446655440000", "contraAccountId": "550e8400-e29b-41d4-a716-446655440001", "lines": [ { "accountId": "550e8400-e29b-41d4-a716-446655440000", "type": "debit", "accountAmount": 500, "accountCurrency": "DKK", "functionalAmount": 500, "originalAmount": 200, "isVatLine": false, "vatSourceLineIndex": 0, "vatCodeId": "550e8400-e29b-41d4-a716-446655440000", "description": "Consulting hours — March", "tagIds": [ "string" ] } ], "customerId": "550e8400-e29b-41d4-a716-446655440002", "supplierId": "550e8400-e29b-41d4-a716-446655440003", "vendorId": "550e8400-e29b-41d4-a716-446655440003", "vatCodeId": "550e8400-e29b-41d4-a716-446655440000", "tagIds": [ "string" ], "documentRefs": [ "string" ], "createdAt": "2026-01-15T10:30:00.000Z" }
json
application/json

Create journal entries in batch (v2)

POST
https://api.ledgerbee.com/api
/v2/journal-entries/batch
x-api-key (header)
or
OAuth 2.0

Atomically creates 1–100 journal entries in a single transaction. Each entry follows the same restrictions as POST /api/v2/journal-entries: for CUSTOMER_/SUPPLIER_ types submit only the counter-side lines and the server auto-appends the AR/AP leg on the partner group default account.

If any entry fails validation or persistence the entire batch is rolled back. journalCategoryId is validated per entry against the API key's app company — cross-tenant or unknown IDs reject the whole batch with 400 JOURNAL_CATEGORY_NOT_FOUND.

Attachments: each entry may include up to 10 base64-encoded attachments[]. A failure on any entry rolls back the whole batch and deletes every already-uploaded blob — no orphan documents survive.

Required Scope

  • journal-entries-write

Create journal entries in batch (v2) › Headers

x-api-idempotency-key
​string · maxLength: 255

Optional idempotency key for safely retrying mutating requests.

Create journal entries in batch (v2) › Request Body

CreateJournalEntryV2BatchRequest
​CreateJournalEntryV2Dto[] · minItems: 1 · maxItems: 100 · required

Array of 1–100 journal entries, carrying at most 10000 lines in total across the batch. Wrapped in a single transaction; one bad entry rolls back the whole batch.

Create journal entries in batch (v2) › Responses

Batch created successfully

CreateJournalEntryV2BatchResponse
totalCreated
​number · required

Number of journal entries created (= entries.length on success).

​JournalEntryResponse[] · required

Created journal entries, ordered to match the request entries[].

POST/v2/journal-entries/batch
curl https://api.ledgerbee.com/api/v2/journal-entries/batch \ --request POST \ --header 'Content-Type: application/json' \ --header 'x-api-key: <api-key>' \ --data '{ "entries": [ { "entryType": "journal", "date": "string", "originalAmount": 0, "customerId": "string", "supplierId": "string", "vendorId": "string", "description": "string", "reference": "string", "externalSystemId": "erp-7f3a2c91", "currency": "DKK", "exchangeRate": 7.4612, "lines": [], "tagIds": [ "string" ], "journalCategoryId": "string", "attachments": [] } ] }'
Example Request Body
{ "entries": [ { "entryType": "journal", "date": "string", "originalAmount": 0, "customerId": "string", "supplierId": "string", "vendorId": "string", "description": "string", "reference": "string", "externalSystemId": "erp-7f3a2c91", "currency": "DKK", "exchangeRate": 7.4612, "lines": [], "tagIds": [ "string" ], "journalCategoryId": "string", "attachments": [] } ] }
json
application/json
Example Responses
{ "totalCreated": 0, "entries": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "entryNumber": "JE-00001", "date": "2026-01-15", "documentDate": "2026-01-15", "amount": 1000, "currency": "DKK", "originalAmount": 200, "originalCurrency": "EUR", "exchangeRate": 7.45, "exchangeRateDate": "2026-01-15", "description": "Office supplies purchase", "reference": "REF-2026-001", "externalSystemId": "erp-7f3a2c91", "journalType": "JOURNAL_ENTRY", "type": "debit", "status": "POSTED", "accountId": "550e8400-e29b-41d4-a716-446655440000", "contraAccountId": "550e8400-e29b-41d4-a716-446655440001", "lines": [ { "accountId": "550e8400-e29b-41d4-a716-446655440000", "type": "debit", "accountAmount": 500, "accountCurrency": "DKK", "functionalAmount": 500, "originalAmount": 200, "isVatLine": false, "vatSourceLineIndex": 0, "vatCodeId": "550e8400-e29b-41d4-a716-446655440000", "description": "Consulting hours — March", "tagIds": [ "string" ] } ], "customerId": "550e8400-e29b-41d4-a716-446655440002", "supplierId": "550e8400-e29b-41d4-a716-446655440003", "vendorId": "550e8400-e29b-41d4-a716-446655440003", "vatCodeId": "550e8400-e29b-41d4-a716-446655440000", "tagIds": [ "string" ], "documentRefs": [ "string" ], "createdAt": "2026-01-15T10:30:00.000Z" } ] }
json
application/json

Journal EntriesMCP