Finance Message Types

This document describes the Finance-related message types in the Cloud Events Base extension.

Overview

Finance message types provide functionality for working with general journals, including validation and posting.

Message Type List

Message TypeDirectionPurpose
Finance.GeneralJournal.CheckOutboundValidates a general journal batch and returns readiness status
Finance.GeneralJournal.PostInboundPosts a general journal batch and returns posting statistics
Finance.GeneralJournal.PreviewPostInboundSimulates posting a general journal batch and returns the resulting ledger entries without committing changes
Finance.GeneralJournal.ReverseRegisterInboundReverses all entries in a G/L Register
Finance.GeneralJournal.ReverseTransactionInboundReverses all entries in a G/L transaction
Finance.GeneralJournal.SetupNewLineInboundCreates a new journal line with defaults — the default way to prepare a journal line
Finance.FAJournal.SetupNewLineInboundCreates a new fixed asset journal line with defaults
Finance.FAJournal.CheckOutboundValidates a fixed asset journal batch and returns readiness status
Finance.FAJournal.PostInboundPosts a fixed asset journal batch and returns posting statistics
Finance.FAJournal.PreviewPostInboundSimulates posting a fixed asset journal batch and returns predicted ledger entries (rolled back)
Finance.BankReconciliation.CreateInboundCreates or reuses a bank reconciliation and imports statement lines
Finance.BankReconciliation.MatchInboundResolves match mode and applies auto/strict matching rules
Finance.BankReconciliation.ResetInboundRemoves all matches from a bank reconciliation
Finance.BankReconciliation.PostInboundPosts a bank reconciliation
Finance.VAT.CalcAndPostSettlementInboundPreviews or posts a VAT settlement via report 20 and returns the resulting G/L Register and VAT entry range
Finance.VATStatement.PreviewInboundReproduces page 474 "VAT Statement Preview" and returns the calculated Column Amount per VAT Statement Line
Finance.Currency.AdjustExchangeRatesInboundPreviews or posts a foreign-currency revaluation via codeunit 699 and returns either the simulated entries or the new G/L Register, entry range, and per-currency breakdown

Finance.GeneralJournal.Check

Direction: Outbound (validation only, no data modification)

Purpose: Validates a general journal batch without posting. Returns comprehensive readiness status and detailed validation results.

Create Request Format

Cloud Events parameters:

{
  "specversion": "1.0",
  "type": "Finance.GeneralJournal.Check",
  "source": "dynamics365/businesscentral",
  "subject": "GENERAL|DEFAULT",
  "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "time": "2024-01-15T10:30:00Z",
  "datacontenttype": "application/json",
  "data": {}
}

Journal Batch Identification

The journal batch can be identified in three ways:

  1. Pipe-separated in subject: "subject": "TEMPLATE|BATCH"
  2. SystemId in subject: "subject": "guid-without-braces"
  3. JSON data parameters:
{
  "data": {
    "templateName": "GENERAL",
    "batchName": "DEFAULT"
  }
}

JSON data parameters take precedence over the subject field.

Response Format

Ready (no errors, no warnings)

{
  "status": "Success",
  "validationResult": "Ready",
  "templateName": "GENERAL",
  "batchName": "DEFAULT",
  "batchDescription": "Default Journal Batch",
  "lineCount": 4,
  "isBalanced": true,
  "requiresBalance": true,
  "totalAmount": 0.0,
  "totalAmountLCY": 0.0,
  "errorCount": 0,
  "warningCount": 0,
  "errors": [],
  "warnings": []
}

ReadyWithWarnings

{
  "status": "Success",
  "validationResult": "ReadyWithWarnings",
  "templateName": "GENERAL",
  "batchName": "DEFAULT",
  "lineCount": 2,
  "isBalanced": true,
  "requiresBalance": true,
  "totalAmountLCY": 0.0,
  "errorCount": 0,
  "warningCount": 2,
  "errors": [],
  "warnings": [
    "Line 10000: Posting Date is in the future (2025-12-31).",
    "Line 20000: Customer C00010 is blocked (Payment)."
  ]
}

NotReady (validation errors)

{
  "status": "Success",
  "validationResult": "NotReady",
  "templateName": "GENERAL",
  "batchName": "INVALID",
  "lineCount": 2,
  "isBalanced": false,
  "requiresBalance": true,
  "totalAmountLCY": 1500.0,
  "errorCount": 3,
  "warningCount": 0,
  "errors": [
    "Journal is not balanced: Total LCY = 1500.00 (should be 0.00).",
    "Line 10000: Document No. is required.",
    "Line 20000: G/L Account 44000 does not allow direct posting."
  ],
  "warnings": []
}

Response Fields

FieldTypeDescription
statusstringAlways "Success" for validation (even if journal not ready)
validationResultstring"Ready", "ReadyWithWarnings", or "NotReady"
templateNamestringJournal template name
batchNamestringJournal batch name
batchDescriptionstringJournal batch description
lineCountintegerNumber of journal lines in batch
isBalancedbooleanTrue if total LCY = 0
requiresBalancebooleanTrue if template requires balance
totalAmountdecimalSum of Amount on all lines
totalAmountLCYdecimalSum of Amount (LCY) on all lines
errorCountintegerNumber of blocking errors
warningCountintegerNumber of non-blocking warnings
errorsarrayList of error messages (prevent posting)
warningsarrayList of warning messages (posting allowed)

Validation Rules

Validation Method: Uses BC Error Message Management framework with codeunit 11 "Gen. Jnl.-Check Line" to collect ALL validation errors in a single pass.

Rules Applied:

  1. Balance (batch-level): General journal templates require total LCY = 0
  2. Lines (batch-level): Batch must contain at least one line
  3. Per-Line Validation (via Gen. Jnl.-Check Line):
  1. Additional Warnings (non-blocking):

Error Handling

ErrorCause
Missing identificationNo subject or data parameters provided
Batch not foundTemplate/batch combination does not exist
No linesBatch exists but contains no journal lines

Notes

Related Message Types


Finance.BankReconciliation.Create

Direction: Inbound

Purpose: Creates a new bank reconciliation for a bank account or reuses an existing empty one, then imports statement lines.

Bank Reconciliation Workflow

This message type is the first step in the bank reconciliation cycle:

  1. Finance.BankReconciliation.Create -- create or reuse the reconciliation header (Bank Acc. Reconciliation with Statement Type = Bank Reconciliation) and import statement lines into Bank Acc. Reconciliation Line.
  2. Finance.BankReconciliation.Match -- pair statement lines with Bank Account Ledger Entry (BLE) rows. Match stamps the BLE with Statement No., Statement Line No., and Statement Status = Bank Acc. Entry Applied via standard BC helper Bank Acc. Entry Set Recon.-No.. Many-to-one matches also write rows to Bank Acc. Rec. Match Buffer.
  3. Finance.BankReconciliation.Reset (optional) -- clear all match stamps to redo the match plan.
  4. Finance.BankReconciliation.Post -- run codeunit Bank Acc. Reconciliation Post, close matched BLEs (Open=false, Statement Status=Closed), and delete the reconciliation header.

This flow does not create Applied Payment Entry rows. That table is only populated for Statement Type = Payment Application, which is not exposed by this extension.

Request Format

{
  "specversion": "1.0",
  "type": "Finance.BankReconciliation.Create",
  "source": "MyIntegrationApp v1.0",
  "subject": "BANK-MAIN",
  "data": {
    "statementDate": "2026-05-30"
  }
}

Identifier resolution order:

  1. subject as GUID -> Bank Account SystemId
  2. subject as text -> Bank Account No.
  3. JSON keys: bankAccountNo, bankAccountId, id, systemId, recordSystemId

Create Response Format

{
  "status": "Success",
  "reused": true,
  "bankAccountNo": "BANK-MAIN",
  "statementNo": "STMT-000123",
  "statementDate": "2026-05-30",
  "systemId": "<guid>",
  "lineCount": 3,
  "warning": "<optional import warning>"
}

Create Error Handling

If no bank account identifier can be resolved, the endpoint returns:

{
  "status": "Error",
  "error": "Bank account identifier must be specified..."
}

Create Notes


Finance.BankReconciliation.Match

Direction: Inbound

Purpose: Resolves matching mode (Auto, 0-N, 1-1, 1-N, N-1, N-N-Strict, Custom) and applies strict validation for N-N mode.

Match Data Effects

For every BLE matched to a statement line, the standard BC helpers Match Bank Rec. Lines and Bank Acc. Entry Set Recon.-No. write:

On each matched Bank Acc. Reconciliation Line: Applied Amount, Applied Entries, and Difference are updated.

Auto mode runs Match Bank Rec. Lines.BankAccReconciliationAutoMatch(BankAccReconciliation, 0). No Applied Payment Entry rows are written by any mode.

Match Request Format

{
  "specversion": "1.0",
  "type": "Finance.BankReconciliation.Match",
  "source": "MyIntegrationApp v1.0",
  "subject": "<reconciliation-systemid>",
  "data": {
    "statementLines": [10000, 20000],
    "ledgerEntries": [30000, 40000],
    "strict": true
  }
}

Match Response Format

{
  "status": "Success",
  "mode": "N-N-Strict",
  "strict": true,
  "statementLinesCount": 2,
  "ledgerEntriesCount": 2,
  "bankAccountNo": "BANK-MAIN",
  "statementNo": "STMT-000123",
  "reconciliationSystemId": "<guid>"
}

Match Error Handling


Finance.BankReconciliation.Reset

Direction: Inbound

Purpose: Removes all match stamps from every line in a bank reconciliation by invoking the standard BC helper Match Bank Rec. Lines.RemoveMatchesFromRecLines.

Reset Data Effects

For every BLE previously stamped by Match:

For each affected Bank Acc. Reconciliation Line:

Reset Request Format

{
  "specversion": "1.0",
  "type": "Finance.BankReconciliation.Reset",
  "source": "MyIntegrationApp v1.0",
  "subject": "<reconciliation-systemid>",
  "data": {}
}

Reset Response Format

{
  "status": "Success",
  "mode": "ResetAll",
  "resetLineCount": 0,
  "bankAccountNo": "BANK-MAIN",
  "statementNo": "STMT-000123",
  "reconciliationSystemId": "<guid>"
}

Reset Error Handling

Raises error if reconciliation cannot be resolved.


Finance.BankReconciliation.Post

Direction: Inbound

Purpose: Posts a bank reconciliation using standard Business Central posting logic (codeunit Bank Acc. Reconciliation Post).

Post Data Effects

Post Request Format

{
  "specversion": "1.0",
  "type": "Finance.BankReconciliation.Post",
  "source": "MyIntegrationApp v1.0",
  "subject": "<reconciliation-systemid>",
  "data": {}
}

Post Response Format

{
  "status": "Success",
  "bankAccountNo": "BANK-MAIN",
  "statementNo": "STMT-000123",
  "reconciliationSystemId": "<guid>"
}

Post Error Handling


Finance.GeneralJournal.Post

Direction: Inbound (modifies data — posts journal and clears lines)

Purpose: Posts a fully validated general journal batch to create ledger entries.

Request Format

Cloud Events parameters:

{
  "specversion": "1.0",
  "type": "Finance.GeneralJournal.Post",
  "source": "MyIntegrationApp v1.0",
  "subject": "GENERAL|BATCH001",
  "id": "b2c3d4e5-6789-01bc-def2-234567890abc",
  "time": "2024-01-15T14:20:00Z",
  "datacontenttype": "application/json",
  "data": {}
}

Journal Batch Identification

The journal batch can be identified in three ways:

  1. Pipe-separated in subject: "subject": "TEMPLATE|BATCH"
  2. SystemId in subject: "subject": "guid-without-braces"
  3. JSON data parameters:
{
  "data": {
    "templateName": "GENERAL",
    "batchName": "BATCH001"
  }
}

JSON data parameters take precedence over the subject field.

Response Format

Success

{
  "status": "Success",
  "templateName": "GENERAL",
  "batchName": "BATCH001",
  "batchDescription": "Default Journal Batch",
  "linesPosted": 6,
  "postingDate": "2024-01-15",
  "totalAmount": 0.0,
  "totalAmountLCY": 0.0,
  "glRegisterNo": 42,
  "glRegisterId": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "fromEntryNo": 1001,
  "toEntryNo": 1006,
  "fromVATEntryNo": 501,
  "toVATEntryNo": 502
}

Error Response

{
  "status": "Error",
  "error": "Error message text",
  "callstack": "Full error callstack from posting"
}

Response Fields

FieldTypeDescription
statusstring"Success" or "Error"
templateNamestringJournal template name
batchNamestringJournal batch name
batchDescriptionstringJournal batch description
linesPostedintegerNumber of journal lines posted
postingDatestringPosting date (ISO format)
totalAmountdecimalTotal Amount posted
totalAmountLCYdecimalTotal Amount (LCY) posted
glRegisterNointegerG/L Register number created by posting
glRegisterIdstringG/L Register SystemId (GUID without braces)
fromEntryNointegerFirst G/L Entry No. in register
toEntryNointegerLast G/L Entry No. in register
fromVATEntryNointegerFirst VAT Entry No. in register (0 if none)
toVATEntryNointegerLast VAT Entry No. in register (0 if none)
errorstringError message (only on Error status)
callstackstringError callstack (only on Error status)

Error Handling

Common errors:

Notes

Workflow

  1. Validate journal batch existence
  2. Validate that lines exist in the batch
  3. Call "Gen. Jnl.-Post Batch" (codeunit 80) to post all lines
  4. Verify G/L Register was created
  5. On success: return G/L Register statistics
  6. On error: return error message with callstack

Recommended approach: Validate with Finance.GeneralJournal.Check first, then post with Finance.GeneralJournal.Post.

Security Considerations

Related Message Types


Finance.GeneralJournal.PreviewPost

Direction: Inbound (simulates posting; no data modification)

Purpose: Simulates posting a general journal batch and returns the resulting ledger entries (G/L Entry, VAT Entry, Customer/Vendor/Bank/Employee Ledger Entry, FA Ledger Entry, Job Ledger Entry, and any other ledger table populated by the BC posting routine) without committing changes. The full Gen. Jnl.-Post routine runs inside a transaction that is rolled back at the end after the captured entries are read into temporary records.

Use this message type to:

Input Parameters

Journal batch identification (at least one method required). First matched wins:

MethodSubject fieldData field
Pipe-separated names`TEMPLATE\BATCH`
SystemId GUID<guid> (no braces)
Template + batch namestemplateName + batchName

Response Format

{
  "status": "Success",
  "rollback": true,
  "summary": "Preview-posting general journal batch GENERAL|DEFAULT (3 lines) would create 6 ledger entries across 2 tables. Transaction is balanced.",
  "templateName": "GENERAL",
  "batchName": "DEFAULT",
  "batchDescription": "Default Journal Batch",
  "linesToPost": 3,
  "postingDate": "2024-01-15",
  "lcyCode": "USD",
  "predictedDocumentNos": ["DOC-001", "DOC-002"],
  "totals": {
    "balanced": true,
    "totalDebitLCY": 1500.00,
    "totalCreditLCY": 1500.00
  },
  "preview": [
    {
      "tableId": 17,
      "tableName": "G/L Entry",
      "tableCaption": "G/L Entry",
      "description": "General ledger entries posted as a result of this document",
      "entryCount": 6,
      "entries": [ /* one JSON object per captured G/L Entry */ ]
    }
  ]
}

Response Fields

FieldTypeDescription
statusstringAlways "Success" on a completed preview, "Error" otherwise.
rollbackbooleanAlways true — confirms no data was persisted.
summarystringOne-line natural-language description of the simulated posting.
templateNamestringJournal template name.
batchNamestringJournal batch name.
batchDescriptionstringJournal batch description.
linesToPostintegerNumber of journal lines that would be posted.
postingDatestringPosting date from the first line (ISO format).
lcyCodestringLocal Currency code from General Ledger Setup.
predictedDocumentNosstring[]Distinct Document Nos found in captured G/L Entry rows (informational only — No. Series state may change between preview and actual post).
totals.balancedbooleantrue when totalDebitLCY = totalCreditLCY (rounded to 0.01).
totals.totalDebitLCY / totalCreditLCYdecimalSum of G/L Entry Debit/Credit amounts in LCY.
previewarrayOne element per ledger table populated by the BC posting routine.
preview[].tableIdintegerBC table number.
preview[].tableNamestringBC table name.
preview[].entryCountintegerNumber of entries captured.
preview[].entriesarrayOne JSON object per captured entry; field names follow the same mechanical PascalCase rules as Data.Records.Get. Restricted fields are omitted per Cloud Events Field Access.

Currency Handling

A general journal batch can contain lines in multiple currencies. The top-level totals object therefore reports only LCY totals. Per-entry currency context (CurrencyCode, Amount, AmountLCY) remains available inside the preview array on each individual ledger entry.

Error Handling

Errors are reported as { "status": "Error", "error": "..." } instead of throwing. Common errors:

Related Message Types


Finance.GeneralJournal.ReverseRegister

Direction: Inbound (reverses posted entries)

Purpose: Reverses all G/L entries in a specified G/L Register. This creates new correcting entries that offset the original entries in the register.

Request Format

Cloud Events parameters:

{
  "specversion": "1.0",
  "type": "Finance.GeneralJournal.ReverseRegister",
  "source": "dynamics365/businesscentral",
  "subject": "42",
  "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "time": "2024-01-15T10:30:00Z",
  "datacontenttype": "application/json",
  "data": {}
}

Register Identification

The subject identifies the G/L Register to reverse:

  1. Register No. (integer): "subject": "42" — the G/L Register "No." field value
  2. SystemId (GUID): "subject": "a1b2c3d4-5678-90ab-cdef-1234567890ab" — the SystemId of the G/L Register record

Response Format

Success:

{
  "status": "Success",
  "reversedRegisterNo": 42,
  "fromEntryNo": 100,
  "toEntryNo": 105
}

Error:

{
  "status": "Error",
  "error": "The register has already been reversed.",
  "callstack": "..."
}

Response Fields

FieldTypeDescription
statusTextSuccess or Error
reversedRegisterNoIntegerThe G/L Register No. that was reversed
fromEntryNoIntegerFirst entry number in the register
toEntryNoIntegerLast entry number in the register
errorTextError message (only on failure)
callstackTextAL callstack (only on failure)

Validations

Workflow

  1. Identify G/L Register (by No. or SystemId lookup)
  2. Validate register exists and is not already reversed
  3. Execute reversal using isolated write codeunit (Codeunit.Run pattern)
  4. On success: return register statistics
  5. On error: return error message with callstack

Related Message Types


Finance.GeneralJournal.ReverseTransaction

Direction: Inbound (reverses posted entries)

Purpose: Reverses all G/L entries sharing a specified transaction number. This creates new correcting entries that offset the original transaction entries.

Request Format

Cloud Events parameters:

{
  "specversion": "1.0",
  "type": "Finance.GeneralJournal.ReverseTransaction",
  "source": "dynamics365/businesscentral",
  "subject": "1234",
  "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "time": "2024-01-15T10:30:00Z",
  "datacontenttype": "application/json",
  "data": {}
}

Transaction Identification

The subject identifies the transaction to reverse:

  1. Transaction No. (integer): "subject": "1234" — the transaction number
  2. SystemId (GUID): "subject": "a1b2c3d4-5678-90ab-cdef-1234567890ab" — the SystemId of any G/L Entry in the transaction; the Transaction No. is extracted from the entry

Response Format

Success:

{
  "status": "Success",
  "reversedTransactionNo": 1234,
  "entriesReversed": 4
}

Error:

{
  "status": "Error",
  "error": "The transaction has already been reversed.",
  "callstack": "..."
}

Response Fields

FieldTypeDescription
statusTextSuccess or Error
reversedTransactionNoIntegerThe transaction number that was reversed
entriesReversedIntegerNumber of G/L entries reversed
errorTextError message (only on failure)
callstackTextAL callstack (only on failure)

Validations

Workflow

  1. Identify transaction (by Transaction No. or by looking up the G/L Entry via SystemId)
  2. Validate entries exist and are not already reversed
  3. Execute reversal using isolated write codeunit (Codeunit.Run pattern)
  4. On success: return transaction statistics
  5. On error: return error message with callstack

Related Message Types


Finance.GeneralJournal.SetupNewLine

Direction: Inbound (creates a new journal line)

Purpose: Creates and inserts a new general journal line in the specified batch, pre-populated with defaults from BC's SetUpNewLine procedure. This is the default way to prepare a general journal line before populating business fields via Data.Records.Set.

Default values inherited from the template and batch include Bal. Account Type, Bal. Account No., Document Type, and Posting Date. If a No. Series is configured on the journal batch, the Document No. is automatically populated from the next number in the series.

The line is assigned the next available Line No. (last line + 10000, or 10000 if the batch is empty).

Request Format

Cloud Events parameters:

{
  "specversion": "1.0",
  "type": "Finance.GeneralJournal.SetupNewLine",
  "source": "MyIntegrationApp v1.0",
  "subject": "GENERAL|DEFAULT",
  "id": "c3d4e5f6-7890-12cd-ef34-567890abcdef",
  "time": "2026-04-15T10:00:00Z",
  "datacontenttype": "application/json",
  "data": {}
}

Journal Batch Identification

The journal batch can be identified in three ways:

  1. Pipe-separated in subject: "subject": "TEMPLATE|BATCH"
  2. SystemId in subject: "subject": "guid-without-braces"
  3. JSON data parameters:
{
  "data": {
    "templateName": "GENERAL",
    "batchName": "DEFAULT"
  }
}

JSON data parameters take precedence over the subject field.

Optional Parameters

ParameterTypeDefaultDescription
fieldNumbersint[]all fieldsField numbers to include in response. When omitted, all fields are returned.
{
  "data": {
    "templateName": "GENERAL",
    "batchName": "DEFAULT",
    "fieldNumbers": [1, 2, 3, 5, 8]
  }
}

Response Format

The response uses the same format as Data.Records.Get: a single record in the result array with id, primaryKey, and fields.

{
  "status": "Success",
  "noOfRecords": 1,
  "result": [
    {
      "id": "A1B2C3D4-E5F6-7890-ABCD-EF1234567890",
      "primaryKey": {
        "JournalTemplateName": "GENERAL",
        "JournalBatchName": "DEFAULT",
        "LineNo_": 10000
      },
      "fields": {
        "PostingDate": "2026-04-15",
        "DocumentNo_": "GJ-00001",
        "DocumentType": " ",
        "AccountType": "G/L Account",
        "BalAccountType": "G/L Account",
        "BalAccountNo_": "29900",
        "..."
      }
    }
  ]
}

Response Fields

FieldTypeDescription
statusstring"Success" or "Error"
noOfRecordsintegerAlways 1 on success
resultarraySingle-element array containing the new journal line
result[].idstringSystemId of the newly inserted journal line (GUID)
result[].primaryKeyobjectPrimary key fields: JournalTemplateName, JournalBatchName, LineNo_
result[].fieldsobjectAll non-PK fields (or only those in fieldNumbers if specified)

Behaviour

  1. The batch is identified using one of the three methods above.
  2. The last existing line in the batch is found (if any).
  3. A new line is initialised with Template Name, Batch Name, and next Line No.
  4. BC's SetUpNewLine is called, passing the last line as reference (or an empty line if the batch has no lines). This applies default values from the template and batch: Bal. Account Type, Bal. Account No., Document Type, Posting Date, etc. If a No. Series is configured on the batch, the Document No. is populated from the next number in the series.
  5. The line is inserted with triggers.
  6. The response returns the record in Data.Records.Get format.

Typical Workflow

  1. Call Finance.GeneralJournal.SetupNewLine to create a line with defaults.
  2. Use the returned id (SystemId) with Data.Records.Set to populate Account No., Amount, etc.
  3. Repeat steps 1–2 for each journal line.
  4. Call Finance.GeneralJournal.Check to validate the batch.
  5. Call Finance.GeneralJournal.Post to post.

Error Handling

ErrorCause
Missing identificationNo template/batch, SystemId, or pipe-separated subject provided
Batch not foundThe specified batch does not exist

Related Message Types


Finance.FAJournal.SetupNewLine

Direction: Inbound (creates a new journal line)

Purpose: Creates and inserts a new fixed asset journal line in the specified batch, pre-populated with defaults from BC's SetUpNewLine procedure. This is the default way to prepare a fixed asset journal line before populating business fields via Data.Records.Set.

Default values inherited from the template and batch include FA Posting Type, Posting Date, Depreciation Book Code, and Document No. (when a No. Series is configured). The line is assigned the next available Line No. (last line + 10000, or 10000 if the batch is empty).

Request Format

{
  "specversion": "1.0",
  "type": "Finance.FAJournal.SetupNewLine",
  "source": "MyIntegrationApp v1.0",
  "subject": "ASSETS|DEFAULT",
  "data": {}
}

Journal Batch Identification

  1. Pipe-separated in subject: "subject": "TEMPLATE|BATCH"
  2. SystemId in subject: "subject": "guid-without-braces"
  3. JSON data parameters:
{
  "data": {
    "templateName": "ASSETS",
    "batchName": "DEFAULT"
  }
}

JSON data parameters take precedence over the subject field.

Optional Parameters

ParameterTypeDefaultDescription
fieldNumbersint[]all fieldsField numbers to include in response
noOfLinesinteger1Number of lines to create (1–100)
clearExistingLinesbooleanfalseWhen true, deletes all existing lines in the batch first

Response Format

Uses the Data.Records.Get response shape.

{
  "status": "Success",
  "noOfRecords": 1,
  "result": [
    {
      "id": "A1B2C3D4-E5F6-7890-ABCD-EF1234567890",
      "primaryKey": {
        "JournalTemplateName": "ASSETS",
        "JournalBatchName": "DEFAULT",
        "LineNo_": 10000
      },
      "fields": {
        "PostingDate": "2026-04-15",
        "DocumentNo_": "FA-00001",
        "FAPostingType": "Acquisition Cost",
        "DepreciationBookCode": "COMPANY",
        "..."
      }
    }
  ]
}

Response Fields

FieldTypeDescription
statusstring"Success" or "Error"
noOfRecordsintegerNumber of lines created
result[].idstringSystemId of the new journal line
result[].primaryKeyobjectJournalTemplateName, JournalBatchName, LineNo_
result[].fieldsobjectAll non-PK fields (or only those in fieldNumbers)

Typical Workflow

  1. Call Finance.FAJournal.SetupNewLine to create lines with defaults.
  2. Use the returned id with Data.Records.Set to populate FA No., Amount, etc.
  3. Call Finance.FAJournal.Check to validate.
  4. Call Finance.FAJournal.Post to post.

Error Handling

ErrorCause
Missing identificationNo template/batch, SystemId, or pipe-separated subject provided
Batch not foundThe specified batch does not exist

Related Message Types


Finance.FAJournal.Check

Direction: Outbound (validation only, no data modification)

Purpose: Validates a fixed asset journal batch without posting. Returns readiness status with detailed validation results.

Request Format

{
  "specversion": "1.0",
  "type": "Finance.FAJournal.Check",
  "source": "dynamics365/businesscentral",
  "subject": "ASSETS|DEFAULT",
  "data": {}
}

Identification follows the same three-method pattern.

Response Format

Ready

{
  "status": "Success",
  "validationResult": "Ready",
  "templateName": "ASSETS",
  "batchName": "DEFAULT",
  "batchDescription": "Default FA Batch",
  "lineCount": 2,
  "totalAmount": 25000.0,
  "errorCount": 0,
  "warningCount": 0,
  "errors": [],
  "warnings": []
}

ReadyWithWarnings / NotReady

Same shape with validationResult set accordingly and populated errors / warnings arrays.

Response Fields

FieldTypeDescription
statusstringAlways "Success" for validation
validationResultstring"Ready", "ReadyWithWarnings", or "NotReady"
templateNamestringJournal template name
batchNamestringJournal batch name
batchDescriptionstringJournal batch description
lineCountintegerNumber of journal lines in batch
totalAmountdecimalSum of Amount on all lines
errorCountintegerNumber of blocking errors
warningCountintegerNumber of non-blocking warnings
errorsarrayError messages (prevent posting)
warningsarrayWarning messages (posting allowed)

Validation Rules

Uses BC's "FA Jnl.-Check Line" codeunit via the Error Message Management framework to collect all errors in a single pass.

Per-Line Validation includes:

Additional Warnings (non-blocking):

Error Handling

ErrorCause
Missing identificationNo subject or data parameters provided
Batch not foundTemplate/batch combination does not exist

Notes

Related Message Types


Finance.FAJournal.Post

Direction: Inbound (modifies data — posts journal and clears lines)

Purpose: Posts a validated fixed asset journal batch to create FA Ledger Entries.

Request Format

{
  "specversion": "1.0",
  "type": "Finance.FAJournal.Post",
  "source": "MyIntegrationApp v1.0",
  "subject": "ASSETS|BATCH001",
  "data": {}
}

Identification follows the same three-method pattern.

Response Format

Success

{
  "status": "Success",
  "templateName": "ASSETS",
  "batchName": "BATCH001",
  "batchDescription": "Default FA Batch",
  "linesPosted": 2,
  "postingDate": "2026-04-15",
  "totalQuantity": 0.0,
  "totalAmount": 25000.0,
  "faRegisterNo": 11,
  "faRegisterId": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "fromEntryNo": 401,
  "toEntryNo": 402
}

Error

{
  "status": "Error",
  "error": "Error message text",
  "callstack": "Full error callstack from posting"
}

Response Fields

FieldTypeDescription
statusstring"Success" or "Error"
templateNamestringJournal template name
batchNamestringJournal batch name
batchDescriptionstringJournal batch description
linesPostedintegerNumber of journal lines posted
postingDatestringPosting date (ISO format)
totalQuantitydecimalTotal Quantity posted (typically 0 for FA journals)
totalAmountdecimalTotal Amount posted
faRegisterNointegerFA Register number created (when register was produced)
faRegisterIdstringFA Register SystemId (GUID without braces)
fromEntryNointegerFirst FA Ledger Entry No. in register
toEntryNointegerLast FA Ledger Entry No. in register
errorstringError message (only on Error status)
callstackstringError callstack (only on Error status)

Error Handling

Common errors:

Notes

Recommended approach: Validate with Finance.FAJournal.Check first, then post with Finance.FAJournal.Post.

Related Message Types


Finance.FAJournal.PreviewPost

Direction: Inbound (simulates posting; no data modification)

Purpose: Simulates posting a Fixed Asset Journal batch and returns the ledger entries that would be produced — without writing anything to the database. Drives the BC Gen. Jnl.-Post Preview.SetContext + Run() headless flow against the FA Jnl.-Post subscriber. Captured tables typically include Maintenance Ledger Entry and (for posting types that integrate to G/L) FA Ledger Entry, G/L Entry, VAT Entry, and ledger entries on the offset account.

Input Parameters

FA Journal batch identification (first matched wins):

MethodSubject fieldData field
Pipe-separated names`TEMPLATE\BATCH`
SystemId GUID<guid> (no braces)
Template + batch namestemplateName + batchName

Response Format

{
  "status": "Success",
  "rollback": true,
  "summary": "Preview-posting FA journal batch ASSETS|BATCH001 (1 line, type Maintenance) would create 1 ledger entry across 1 table. No G/L impact.",
  "templateName": "ASSETS",
  "batchName": "BATCH001",
  "batchDescription": "Default FA Batch",
  "linesToPost": 1,
  "postingDate": "2026-04-15",
  "lcyCode": "ISK",
  "predictedDocumentNos": [],
  "totals": { "balanced": true, "totalDebitLCY": 0.0, "totalCreditLCY": 0.0 },
  "preview": [
    {
      "tableId": 5625,
      "tableName": "Maintenance Ledger Entry",
      "tableCaption": "Maintenance Ledger Entry",
      "entryCount": 1,
      "entries": [
        {
          "id": "00000000-0000-0000-0000-000000000000",
          "primaryKey": { "EntryNo_": "1" },
          "fields": { "FANo_": "FA000010", "FAPostingType": "Maintenance", "Amount": "-2500", "DocumentNo_": "MNT-0001" }
        }
      ]
    }
  ]
}

For G/L-integrated postings (Acquisition Cost, Depreciation, Disposal, etc.) the preview[] array additionally contains FA Ledger Entry (5601), G/L Entry (17), and offset-account ledger entries, and totals.totalDebitLCY/totalCreditLCY reflect the G/L impact.

Response Fields

Same envelope as Inventory.ItemJournal.PreviewPost (rollback, summary, totals, preview[] with tableCaption + per-entry id/primaryKey/fields). FA-specific notes:

FieldDescription
predictedDocumentNosEmpty for Maintenance-only posting (no G/L Entries produced). Populated for G/L-integrated posting types.
totalsAlways balanced=true with zero amounts for Maintenance-only posting.

Operational Notes

Errors

BC validation errors propagate verbatim. Common errors:

Related Message Types


Implementation Details

Object IDs

Object TypeObject IDObject Name
Enum Value65350Finance.GeneralJournal.Check
Implementation Codeunit65385Gen. Journal Check Impl
Help Codeunit65389Gen. Journal Check Help
Enum Value65351Finance.GeneralJournal.Post
Implementation Codeunit65386Gen. Journal Post Impl
Help Codeunit65390Gen. Journal Post Help
Enum Value65352Finance.GeneralJournal.SetupNewLine
Implementation Codeunit65399Gen. Jnl. SetupLine Impl
Help Codeunit65400Gen. Jnl. SetupLine Help
Enum Value65353Finance.GeneralJournal.ReverseRegister
Implementation Codeunit65486Gen. Journal Reverse Register Impl
Help Codeunit65489Gen. Jnl. Reverse Register Help
Enum Value65354Finance.GeneralJournal.ReverseTransaction
Implementation Codeunit65487Gen. Journal Reverse Trans Impl
Help Codeunit65490Gen. Jnl. Reverse Trans Help
Helper Codeunit65488Gen. Journal Reverse Process
Enum Value65503Finance.FAJournal.SetupNewLine
Implementation Codeunit65503FA Jnl. SetupLine Impl
Help Codeunit65515FA Jnl. SetupLine Help
Enum Value65504Finance.FAJournal.Check
Implementation Codeunit65504FA Journal Check Impl
Help Codeunit65516FA Journal Check Help
Enum Value65505Finance.FAJournal.Post
Implementation Codeunit65505FA Journal Post Impl
Help Codeunit65517FA Journal Post Help
Enum Value65539Finance.FAJournal.PreviewPost
Implementation Codeunit65620FA Jnl. Preview Post Impl
Help Codeunit65621FA Jnl. Preview Post Help

File Locations

app/src/Message Type/
  Implementations/Finance/
    GenJournalCheckImpl.Codeunit.al
    GenJournalPostImpl.Codeunit.al
    GenJnlSetupLineImpl.Codeunit.al
    GenJournalReverseRegisterImpl.Codeunit.al
    GenJournalReverseTransImpl.Codeunit.al
    GenJournalReverseProcess.Codeunit.al
  Help/Finance/
    GenJournalCheckHelp.Codeunit.al
    GenJournalPostHelp.Codeunit.al
    GenJnlSetupLineHelp.Codeunit.al
    GenJnlReverseRegisterHelp.Codeunit.al
    GenJnlReverseTransHelp.Codeunit.al
    FAJnlSetupLineHelp.Codeunit.al
    FAJournalCheckHelp.Codeunit.al
    FAJournalPostHelp.Codeunit.al

FA implementations:

app/src/Message Type/
  Implementations/Finance/
    FAJnlSetupLineImpl.Codeunit.al
    FAJournalCheckImpl.Codeunit.al
    FAJournalPostImpl.Codeunit.al
    FAJnlPreviewPostImpl.Codeunit.al
  Help/Finance/
    FAJnlPreviewPostHelp.Codeunit.al

Testing

Test codeunits:

Test coverage includes:


See Also


Finance.VAT.CalcAndPostSettlement

Direction: Inbound

Purpose: Calculates and optionally posts a VAT settlement by invoking report 20 Calc. and Post VAT Settlement. Preview (post=false) returns the aggregated VAT entries that would be settled. Post (post=true) performs the posting through the standard report and returns the new G/L Register number plus the resulting VAT entry range.

Settlement Workflow

  1. Caller sends a preview request (post=false, the default) to inspect the totals and per-posting-group breakdown for a given period and account.
  2. Caller reviews the aggregated totals and byPostingGroup arrays; no posting has occurred.
  3. Caller sends the same request with post=true to actually post. The implementation:
  1. The settlement transfers the open VAT entries onto the settlementAccountNo G/L account and closes them. Individual VAT entries are intentionally excluded from the response � use Data.Records.Get against VAT Entry filtered by the returned entry-no. range when line-level detail is needed.

Request Format

{
  "specversion": "1.0",
  "type": "Finance.VAT.CalcAndPostSettlement",
  "source": "MyIntegrationApp v1.0",
  "data": {
    "startingDate": "2026-01-01",
    "endingDate": "2026-01-31",
    "postingDate": "2026-02-01",
    "documentNo": "VAT-2026-01",
    "settlementAccountNo": "2150",
    "post": true,
    "showAmountsInAddCurrency": false,
    "vatBusPostingGroup": "DOMESTIC|EU",
    "vatProdPostingGroup": "VAT24",
    "vatRegistrationNo": "",
    "type": "Sale"
  }
}

Request Fields

FieldTypeRequiredDescription
startingDatedate (ISO 8601)YesFirst posting date included in the settlement range.
endingDatedate (ISO 8601)YesLast posting date included. Must be on or after startingDate.
postingDatedate (ISO 8601)YesPosting date for the settlement G/L entry.
documentNoCode[20]YesDocument number for the settlement G/L entry.
settlementAccountNoCode[20]YesTarget G/L account. Must exist, be Posting type, and not blocked.
postbooleanNo (default false)true runs the report and posts; false returns aggregation only.
showAmountsInAddCurrencybooleanNo (default false)Passes the corresponding option to the report.
vatBusPostingGrouptextNoOptional VAT Entry filter expression.
vatProdPostingGrouptextNoOptional VAT Entry filter expression.
vatRegistrationNotextNoOptional VAT Entry filter expression.
typetextNoOptional VAT Entry filter on Type (Purchase, Sale, or `PurchaseSale`). Defaults to both.

Response Format

**Success � preview (post=false)**

{
  "status": "Success",
  "posted": false,
  "documentNo": "VAT-2026-01",
  "postingDate": "2026-02-01",
  "settlementAccountNo": "2150",
  "startingDate": "2026-01-01",
  "endingDate": "2026-01-31",
  "showAmountsInAddCurrency": false,
  "lcyCode": "ISK",
  "totals": {
    "vatBase": 1000000.00,
    "vatAmount": 240000.00,
    "vatBaseACY": 0.00,
    "vatAmountACY": 0.00,
    "entryCount": 42
  },
  "byPostingGroup": [
    {
      "type": "Sale",
      "vatBusPostingGroup": "DOMESTIC",
      "vatProdPostingGroup": "VAT24",
      "entryCount": 15,
      "vatBase": 600000.00,
      "vatAmount": 144000.00,
      "vatBaseACY": 0.00,
      "vatAmountACY": 0.00
    }
  ]
}

**Success � posted (post=true)**

Adds the four posting fields below the preview shape:

{
  "status": "Success",
  "posted": true,
  "glRegisterNo": 1234,
  "fromVATEntryNo": 5678,
  "toVATEntryNo": 5720,
  "settlementVATEntryCount": 43
}

Error

{
  "status": "Error",
  "error": "Settlement G/L Account 2150 must have Account Type = Posting.",
  "callstack": "..."
}

callstack is present only when the failure originated inside the isolated report run.

Response Fields

FieldTypeDescription
statusstringSuccess or Error.
postedbooleantrue only when post=true was requested and the report run succeeded.
documentNo, postingDate, settlementAccountNoEcho of the input used for the settlement.
startingDate, endingDatedateEcho of the settled posting-date range.
showAmountsInAddCurrencybooleanEcho of input.
lcyCodeCode[10]LCY code from General Ledger Setup.
totals.vatBase / vatAmountdecimalSums across the entire filtered range, in LCY.
totals.vatBaseACY / vatAmountACYdecimalSums in the additional reporting currency.
totals.entryCountintegerNumber of open VAT entries that match the filters.
byPostingGroup[]arrayOne entry per Type + VAT Bus. Posting Group + VAT Prod. Posting Group combination.
byPostingGroup[].typestringPurchase or Sale.
byPostingGroup[].vatBusPostingGroup / vatProdPostingGroupCode[20]Group keys.
byPostingGroup[].entryCountintegerNumber of VAT entries in that group.
byPostingGroup[].vatBase / vatAmount / vatBaseACY / vatAmountACYdecimalGroup sums.
glRegisterNointegerPosted only. G/L Register."No." created by the report.
fromVATEntryNo / toVATEntryNointegerPosted only. Inclusive range of VAT Entry."Entry No." written by the settlement.
settlementVATEntryCountintegerPosted only. toVATEntryNo - fromVATEntryNo + 1.

Validation Rules

CheckError Message
startingDate presentstartingDate is required.
endingDate presentendingDate is required.
postingDate presentpostingDate is required.
documentNo presentdocumentNo is required.
settlementAccountNo presentsettlementAccountNo is required.
endingDate >= startingDateendingDate (X) must be on or after startingDate (Y).
Settlement account existsSettlement G/L Account X does not exist.
Account "Account Type" = PostingSettlement G/L Account X must have Account Type = Posting.
Account not blockedSettlement G/L Account X is blocked.
At least one open VAT entry matches the filtersNo open VAT entries match the supplied filters.

Error Handling

Validation errors return status=Error with an error field. Errors raised during the actual report run additionally include a callstack field for diagnostics. The isolated posting codeunit ensures a failed report run does not roll back the message-processing transaction.

Notes

Related Message Types


Finance.VATStatement.Preview

Direction: Inbound (read-only)

Purpose: Reproduces the standard BC page 474 VAT Statement Preview for a given VAT Statement Template/Name. Iterates the VAT Statement Line rows and returns the calculated Column Amount per line via report 12 "VAT Statement".CalcLineTotal — the exact same API page 474 uses, so values match. No posting and no database writes.

To enumerate templates and names, call Data.Records.Get against VAT Statement Template (table 256) or VAT Statement Name (table 257).

Request Format

{
  "specversion": "1.0",
  "type": "Finance.VATStatement.Preview",
  "source": "MyIntegrationApp v1.0",
  "data": {
    "templateName": "DEFAULT",
    "name": "DEFAULT",
    "selection": "Open and Closed",
    "periodSelection": "Within Period",
    "dateFilter": "01/01/25..31/01/25",
    "countryRegionFilter": "",
    "rowNoFilter": "",
    "showAmountsInAddCurrency": false
  }
}

Request Fields

FieldTypeRequiredDescription
templateNameCode[10]YesVAT Statement Template name. Must exist.
nameCode[10]YesVAT Statement Name within the template. Must exist.
selectiontextNo (default Open and Closed)Open, Closed, or Open and Closed. Maps to the page 474 Selection field.
periodSelectiontextNo (default Within Period)Within Period or Before and Within Period. Maps to the page 474 Period Selection field.
dateFiltertextNoFilter expression applied to the VAT Statement Name Date Filter FlowFilter (e.g. 01/01/25..31/01/25).
countryRegionFiltertextNoFilter expression for the report Country/Region Filter parameter.
rowNoFiltertextNoOptional filter on Row No. to return a subset of lines (e.g. 100..199).
showAmountsInAddCurrencybooleanNo (default false)When true, amounts are calculated in the additional reporting currency.

Response Format

Success

{
  "status": "Success",
  "templateName": "DEFAULT",
  "name": "DEFAULT",
  "description": "Default VAT Statement",
  "selection": "Open and Closed",
  "periodSelection": "Within Period",
  "dateFilter": "01/01/25..31/01/25",
  "countryRegionFilter": "",
  "showAmountsInAddCurrency": false,
  "lineCount": 12,
  "lines": [
    {
      "lineNo": 10000,
      "rowNo": "100",
      "description": "VAT Sales 24%",
      "type": "VAT Entry Totaling",
      "amountType": "Amount",
      "genPostingType": "Sale",
      "vatBusPostingGroup": "DOMESTIC",
      "vatProdPostingGroup": "VAT24",
      "accountTotaling": "",
      "rowTotaling": "",
      "print": true,
      "printWith": "Sign",
      "newPage": false,
      "boxNo": "",
      "columnAmount": 240000.00
    }
  ]
}

Error

{
  "status": "Error",
  "error": "VAT Statement Name DEFAULT does not exist in template DEFAULT."
}

Response Fields

FieldTypeDescription
statusstringSuccess or Error.
templateName / nameCode[10]Echo of the request.
descriptionText[100]Description of the VAT Statement Name.
selection / periodSelectionstringEcho of the resolved enum values.
dateFilter / countryRegionFiltertextEcho of the request filters.
showAmountsInAddCurrencybooleanEcho of the request.
lineCountintegerNumber of VAT Statement Line rows returned.
lines[]arrayOne entry per VAT Statement Line.
lines[].lineNointegerVAT Statement Line Line No..
lines[].rowNoCode[10]VAT Statement Line Row No..
lines[].descriptionText[100]Row description.
lines[].typestringAccount Totaling, VAT Entry Totaling, Row Totaling, or Description.
lines[].amountTypestringAmount, Base, Unrealized Amount, Unrealized Base, Full Amount, Full Base, or empty.
lines[].genPostingTypestringPurchase, Sale, (blank), or Settlement.
lines[].vatBusPostingGroup / vatProdPostingGroupCode[20]VAT posting groups.
lines[].accountTotalingText[30]G/L account filter expression for Account Totaling rows.
lines[].rowTotalingText[50]Row number filter expression for Row Totaling rows.
lines[].printbooleanWhether the row is printed.
lines[].printWithstringSign or Opposite Sign. When Opposite Sign, columnAmount is already inverted.
lines[].newPagebooleanWhether a new page is started before the row.
lines[].boxNoText[30]Box number used by external VAT reports.
lines[].columnAmountdecimal \falseCalculated Column Amount. false for Description rows or when CalcLineTotal returns no amount.

Validation Rules

CheckError Message
templateName presenttemplateName is required.
name presentname is required.
selection is one of Open, Closed, Open and Closedselection must be one of: Open, Closed, Open and Closed.
periodSelection is one of Within Period, Before and Within PeriodperiodSelection must be one of: Before and Within Period, Within Period.
VAT Statement Template existsVAT Statement Template X does not exist.
VAT Statement Name exists within the templateVAT Statement Name X does not exist in template Y.

Notes

Related Message Types


VAT Settlement Process

End-to-end workflow that ties Finance.VATStatement.Preview and Finance.VAT.CalcAndPostSettlement together. Both message types read the same VAT Entry table; they differ in how they aggregate it and what they do with the result.

Concepts

Standard BC Workflow

  1. Post the period's transactions — sales invoices, purchase invoices, etc. Each posts one or more VAT Entry rows with Closed = false.
  2. Preview the VAT return via the VAT Statement. *Cloud Event equivalent: Finance.VATStatement.Preview.*
  3. Preview the settlement aggregates. *Cloud Event equivalent: Finance.VAT.CalcAndPostSettlement with post=false.*
  4. Resolve discrepancies: if step 2 and step 3 disagree, the Statement Template is wrong — fix it and repeat from step 2.
  5. Post the settlement. *Cloud Event equivalent: Finance.VAT.CalcAndPostSettlement with post=true.*
  6. Submit the VAT return using the Column Amounts from step 2.
  7. Pay or reclaim the net amount on the settlement G/L account.

Two Different Aggregations of the Same Data

AspectFinance.VATStatement.PreviewFinance.VAT.CalcAndPostSettlement
GroupingPer VAT Statement Line (Row No.)Per VAT Bus. + VAT Prod. Posting Group
Filter sourceVAT Statement Line row definitionRequest JSON filters on VAT Entry
SelectionOpen / Closed / Open and ClosedOpen entries only (Closed = false)
Date scopeDate Filter FlowFilter on the VAT Statement NamePosting Date range
Side effectNone (read-only)None if post=false; closes entries + posts G/L if post=true
Underlying reportReport 12 CalcLineTotal per lineReport 20 Execute for the whole settlement

Reconciliation Rule

For a correctly-defined VAT Statement, the sum of the VAT-amount rows of Finance.VATStatement.Preview for a given period equals totals.vatAmount returned by Finance.VAT.CalcAndPostSettlement for the same period and posting-group filters. When they disagree:

What the Settlement Posts

Report 20 produces exactly one G/L Register containing:

The Finance.VAT.CalcAndPostSettlement post response returns the bounding G/L Register No., fromVATEntryNo, and toVATEntryNo so the caller can retrieve the rows via Data.Records.Get.

Idempotency

Re-running a successful posted settlement for the same period (without new postings in between) fails with No open VAT entries match the supplied filters. This is the intended guard: a settlement is allowed once per period per filter combination.


Finance.Currency.AdjustExchangeRates

Direction: Inbound

Purpose: Runs BC Exch. Rate Adjmt. Process (codeunit 699) for foreign-currency revaluation. Two modes:

Request Format

Cloud Events parameters:

{
  "specversion": "1.0",
  "type": "Finance.Currency.AdjustExchangeRates",
  "source": "dynamics365/businesscentral",
  "id": "<event-guid>",
  "time": "2025-12-31T00:00:00Z",
  "datacontenttype": "application/json",
  "data": {
    "endingDate": "2025-12-31",
    "postingDate": "2025-12-31",
    "documentNo": "FX-2025-12",
    "currencyCode": "USD|EUR",
    "adjustCustomers": true,
    "adjustVendors": true,
    "adjustEmployees": false,
    "adjustBankAccounts": true,
    "adjustGLAccounts": true,
    "post": true
  }
}

Request Parameters

FieldTypeRequiredDescription
endingDateDateYesLast posting date considered for adjustment. All open ledger entries with posting date on or before this date are evaluated.
postingDateDateYesPosting date for the adjustment G/L entries.
documentNoCode[20]YesDocument number on the adjustment G/L entries.
postBooleanNo (default false)true to run and commit; false for preview only.
currencyCodeTextNoBC-style filter expression (e.g. USD or `USD\EUR`). Defaults to all foreign currencies set up in BC.
adjustCustomersBooleanNo (default true)Adjust Detailed Customer Ledger Entries.
adjustVendorsBooleanNo (default true)Adjust Detailed Vendor Ledger Entries.
adjustEmployeesBooleanNo (default true)Adjust Detailed Employee Ledger Entries.
adjustBankAccountsBooleanNo (default true)Adjust Bank Account Ledger Entries.
adjustGLAccountsBooleanNo (default true)Adjust G/L Account currency balances.
postingDescriptionText[100]NoDescription on the adjustment G/L lines. Default: Exchange rate adjustment <currencyCode-filter-or-blank> <endingDate>.

At least one adjust* toggle must be true; otherwise the request fails validation.

Posting Gate

Calling this message type requires the CE G/L Posting permission set in addition to CE API ACCESS. Both preview and post enforce the Cloud Events Posting Gate for posting type G/L; the gate is checked before parameters are populated, so a denial never reaches the BC adjustment engine. Without the permission set the request returns status=Error with Posting denied: missing 'CE G/L Posting' permission set. — no preview entries are produced and no G/L Register is created.

Currency Master Setup

BC codeunit 699 requires several account fields on every currency that takes part in a run, **including any currency the filter excludes when adjustGLAccounts=true** (the G/L-balance validation iterates all currencies, not just the filtered ones). Populate the Currency Card before the first run:

Currency fieldUsed byWhen validated
Unrealized Gains Acc. / Unrealized Losses Acc.All adjust phasesEvery run that revalues entries in this currency
Realized Gains Acc. / Realized Losses Acc.Detailed ledger entry revaluationCustomer / vendor / employee / bank phases
Realized G/L Gains Account / Realized G/L Losses Account (fields 40/41)G/L Account balance revaluationOnly when adjustGLAccounts=true — but validated on all currencies regardless of the currencyCode filter

Missing Unrealized Gains Acc. errors with Unrealized Gains Acc. must have a value in Currency: Code=<XYZ>. Missing Realized G/L Gains Account errors the same way and is the most common surprise — set adjustGLAccounts=false for ledger-only revaluation, or populate fields 40/41 on every active currency.

Response Format — Post (post=true)

{
  "status": "Success",
  "posted": true,
  "postingDate": "2025-12-31",
  "endingDate": "2025-12-31",
  "documentNo": "FX-2025-12",
  "postingDescription": "Exchange rate adjustment USD|EUR 2025-12-31",
  "currencyFilter": "USD|EUR",
  "adjustCustomers": true,
  "adjustVendors": true,
  "adjustEmployees": false,
  "adjustBankAccounts": true,
  "adjustGLAccounts": true,
  "lcyCode": "ISK",
  "totals": {
    "totalDebitLCY": 152034.55,
    "totalCreditLCY": 152034.55,
    "netLCY": 0.00,
    "newGLEntryCount": 18
  },
  "byCurrency": [
    {
      "currencyCode": "USD",
      "adjustedBaseLCY": 84020.10,
      "adjustedAmtLCY": 1024.55,
      "registerCount": 3
    },
    {
      "currencyCode": "EUR",
      "adjustedBaseLCY": 68014.45,
      "adjustedAmtLCY": -510.30,
      "registerCount": 2
    }
  ],
  "glRegisterNo": 4321,
  "fromGLEntryNo": 98765,
  "toGLEntryNo": 98782,
  "newGLEntryCount": 18,
  "durationMs": 412
}

Response Format — Preview (post=false)

{
  "status": "Success",
  "posted": false,
  "rollback": true,
  "postingDate": "2025-12-31",
  "endingDate": "2025-12-31",
  "documentNo": "FX-2025-12-PREVIEW",
  "postingDescription": "Exchange rate adjustment  2025-12-31",
  "currencyFilter": "",
  "adjustCustomers": true,
  "adjustVendors": true,
  "adjustEmployees": true,
  "adjustBankAccounts": true,
  "adjustGLAccounts": true,
  "lcyCode": "ISK",
  "totals": {
    "balanced": true,
    "totalDebitLCY": 152034.55,
    "totalCreditLCY": 152034.55
  },
  "preview": [
    {
      "tableId": 17,
      "tableCaption": "G/L Entry",
      "entryCount": 18,
      "entries": [ /* curated field projection per row */ ]
    },
    {
      "tableId": 379,
      "tableCaption": "Detailed Cust. Ledg. Entry",
      "entryCount": 6,
      "entries": [ /* ... */ ]
    }
  ],
  "durationMs": 287
}

Response Fields

FieldTypeDescription
statusTextSuccess or Error.
postedBooleantrue when the adjustment actually ran and committed.
rollbackBooleanPreview only; always true. Indicates no database changes remain visible after the call.
postingDate / endingDateDateEchoes the input.
documentNoCode[20]Document number on the adjustment lines.
postingDescriptionText[100]Description on the adjustment lines (input or default).
currencyFilterTextFilter applied to currency selection (input or empty for "all").
adjustCustomers / adjustVendors / adjustEmployees / adjustBankAccounts / adjustGLAccountsBooleanEchoes the input toggles.
lcyCodeCode[10]LCY code from General Ledger Setup, for context.
totalsObjectLCY totals across all entries written by the run. Preview adds balanced; post adds netLCY and newGLEntryCount.
byCurrencyArrayPost only. Per-currency breakdown of adjusted LCY amounts and register counts.
previewArrayPreview only. One element per ledger table touched, each with the simulated entries projected to a curated field set.
glRegisterNoIntegerPost only. G/L Register number created by the run.
fromGLEntryNo / toGLEntryNoIntegerPost only. Range of G/L entries written by the adjustment.
newGLEntryCountIntegerPost only. Number of G/L entries in the new register. 0 when no adjustment was needed.
durationMsBigIntegerWall-clock time spent inside the BC engine (excludes parsing and response build).

Notes

Error Handling

Validation errors return status=Error and an error field describing the failure. Errors raised by the underlying adjustment engine during posting include a callstack field for diagnostics. Validated conditions:

Common engine-time errors (post and preview branches both surface these as status=Error):

Error messageRoot causeFix
Unrealized Gains Acc. must have a value in Currency: Code=XYZ.Currency master missing fields 6/7/8/9Populate the four Unrealized/Realized Gains/Losses Acc. fields on the Currency Card
Realized G/L Gains Account must have a value in Currency: Code=XYZ.adjustGLAccounts=true against a currency lacking fields 40/41Populate fields 40/41 on every active currency, or set adjustGLAccounts=false
You must specify a Posting Date.postingDate missing or invalidSend ISO-8601 date (YYYY-MM-DD)
Posting denied: missing 'CE G/L Posting' permission set.Caller lacks CE G/L PostingAssign the permission set; the gate runs before the engine

Observed Behavior

End-to-end validation with USD + EUR on a BC 27 on-prem container (LCY = ISK, ARC = EUR), seeded with two open journal lines (USD 50.00 / EUR 25.00, both balanced through a clearing account), produced consistent and reversible results:

**Preview (post=false)** — 4 simulated G/L entries, balanced, no database changes:

{
  "status": "Success", "posted": false, "rollback": true,
  "currencyFilter": "USD|EUR", "lcyCode": "ISK",
  "totals": { "balanced": true, "totalDebitLCY": 9765.11, "totalCreditLCY": 9765.11 },
  "preview": [ { "tableId": 17, "tableCaption": "G/L Entry", "entryCount": 4, "entries": [ /* ... */ ] } ],
  "durationMs": 437
}
G/L AccountDebit (LCY)Credit (LCY)Description
2320 (USD Unrealized Gains)6,520.41USD ledger revaluation
6700 (USD Unrealized Losses)6,520.41USD offset
5420 (EUR Unrealized Gains)3,244.70EUR ledger revaluation
7250 (EUR Unrealized Losses)3,244.70EUR offset

**Post (post=true)** — same shape, materialised as G/L Register 1119, entries 4369–4372:

{
  "status": "Success", "posted": true,
  "glRegisterNo": 1119, "fromGLEntryNo": 4369, "toGLEntryNo": 4372,
  "newGLEntryCount": 4,
  "totals": { "totalDebitLCY": 9765.11, "totalCreditLCY": 9765.11, "netLCY": 0.00, "newGLEntryCount": 4 },
  "byCurrency": [
    { "currencyCode": "USD", "adjustedBaseLCY": 0.00, "adjustedAmtLCY":  6520.41, "registerCount": 1 },
    { "currencyCode": "EUR", "adjustedBaseLCY": 0.00, "adjustedAmtLCY": -3244.70, "registerCount": 1 }
  ],
  "durationMs": 328
}

Notable: adjustedBaseLCY is 0.00 when the underlying open entries already net to zero LCY in the source currency (typical for newly-posted clearing transactions); only adjustedAmtLCY reflects the FX delta. byCurrency totals reconcile to totals.totalDebitLCY - totals.totalCreditLCY = 0 because each per-currency adjustment posts a balanced unrealized gain/loss pair.

Known Gotchas

AI Caller Guidance

Related Message Types


© Origo – Cloud Events Base Extension