Data Message Types

This document describes the Data message types available in the Cloud Events API for retrieving and manipulating record data.

Parent Document: API_Reference.md

Implementation Folder: app/src/Message Type/Implementations/Data/


Overview

Data message types provide operations for retrieving and manipulating record data in Business Central tables following the data shipping standard format. All data operations support field filtering, date/time range filtering, and pagination for optimal performance with large datasets.

Available Message Types:

Message TypeDescriptionDirection
Data.Records.GetRetrieves full record data as JSON for records in a specified tableOutbound
Data.Records.SetInserts or updates full record data as JSON for records in a specified tableInbound
Data.RecordIds.GetRetrieves record IDs and modification timestamps for records in a specified tableOutbound
CSV.Records.GetExports all matching records from a specified table as a CSV file in Open Mirroring formatOutbound
Data.Totals.GetAggregates Decimal SumIndexFields across all matching records, returning field totalsOutbound
Data.Notes.GetRetrieves notes from the Record Link table for a specified recordOutbound
Data.Notes.SetAdds new notes or edits existing notes on the Record Link table for a specified recordInbound
Deleted.Records.GetRetrieves full field-level snapshots of deleted records from the Cloud Events Delete LogOutbound
Deleted.RecordIds.GetRetrieves SystemId and deletion timestamp for deleted recordsOutbound
CSV.DeletedRecords.GetExports deleted record audit log entries as CSVOutbound
Data.Entries.FindFinds all related entries for a document using BC standard NavigateOutbound

1. Data.Records.Get

Purpose: Retrieve full record data as JSON for records in a specified table, following the data shipping standard format.

Description: Retrieves full record data as JSON for records in a specified table, following the data shipping standard format. Supports optional field filtering, FlowField retrieval, table view filtering, date/time range filtering, and pagination.

Message Direction: Outbound

Table Identification:

The target table can be specified using the following options (evaluated in this order):

  1. tableName in the JSON data payload
  2. tableNumber in the JSON data payload
  3. tableNo in the JSON data payload (alias for tableNumber)
  4. tableId in the JSON data payload (alias for tableNumber)
  5. subject field in the CloudEvents envelope — accepts either a table name (e.g., "Customer") or a table number (e.g., "18")

Input Parameters:

{
  "tableName": "Customer",  // Table name OR
  "tableNumber": 18,         // Table number OR
  "tableNo": 18,             // Table number (alias for tableNumber) OR
  "tableId": 18,             // Table ID (alias for tableNumber)
  "fieldNumbers": [1, 2, 3, 5, 7],  // Optional - specific field numbers to include; also enables FlowField retrieval
  "startDateTime": "2026-01-01T00:00:00Z",  // Optional - filter by SystemModifiedAt
  "endDateTime": "2026-02-19T23:59:59Z",    // Optional - filter by SystemModifiedAt
  "tableView": "WHERE(Blocked = CONST( ))",  // Optional - additional SETVIEW filter
  "skip": 0,                 // Optional - number of records to skip (default: 0)
  "take": 100                // Optional - number of records to return (default: 100)
}

Response Format:

{
  "status": "Success",
  "noOfRecords": 245,  // Total number of records matching the filters
  "result": [
    {
      "id": "{guid}",
      "primaryKey": {
        "No": "10000"
      },
      "fields": {
        "Name": "Contoso Ltd.",
        "Address": "123 Main St",
        "City": "Atlanta",
        "Balance": 1250.50
      }
    }
  ]
}

Data Shipping Standard Format:

Each record in the result array contains:

Field names are normalized to contain only alphanumeric characters (spaces and special characters removed).

Supported Field Types:

Option/Enum fields: Values are returned as their display captions (not internal names). Use Help.Fields.Get to discover valid values and their captions for a specific field.

Notes:

Example Usage Scenarios:

  1. Get all fields for all customers:

``json {"tableName": "Customer"} ``

  1. Get specific fields for customers modified in date range:

``json { "tableName": "Customer", "fieldNumbers": [2, 5, 7, 21], "startDateTime": "2026-02-01T00:00:00Z", "endDateTime": "2026-02-28T23:59:59Z" } ``

  1. Get customers with table view filter:

``json { "tableName": "Customer", "tableView": "WHERE(Blocked = CONST( ))", "fieldNumbers": [1, 2, 3, 5] } ``

  1. Get customers with pagination (first 100 records):

``json { "tableName": "Customer", "skip": 0, "take": 100 } ``

  1. Get customers with pagination (records 101-200):

``json { "tableName": "Customer", "skip": 100, "take": 100 } ``


2. Data.Records.Set

Purpose: Insert or update full record data as JSON for records in a specified table, following the data shipping standard format.

Description: Inserts or updates full record data as JSON for records in a specified table, following the data shipping standard format. Supports both insert (new records) and update (existing records) operations based on SystemId or primary key.

Message Direction: Inbound

Table Identification:

The target table can be specified using the following options (evaluated in this order):

  1. tableName in the JSON data payload
  2. tableNumber in the JSON data payload
  3. tableNo in the JSON data payload (alias for tableNumber)
  4. tableId in the JSON data payload (alias for tableNumber)
  5. subject field in the CloudEvents envelope — accepts either a table name (e.g., "Customer") or a table number (e.g., "18")

Input Parameters:

{
  "data": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",  // Optional - SystemId for update
      "identityInsert": true,                         // Optional - allow insert with specific SystemId
      "primaryKey": {                                 // Optional - for lookup or verification
        "No_": "10000"
      },
      "fields": {                                     // Fields to set/update
        "Name": "Contoso Ltd.",
        "Address": "123 Main St",
        "City": "Atlanta",
        "Balance": 1250.50
      }
    }
  ]
}

Response Format:

{
  "status": "Success",
  "insertedCount": 5,   // Number of new records inserted
  "modifiedCount": 3,   // Number of existing records updated
  "result": [           // Complete record data for all processed records
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "primaryKey": {
        "No_": "10000"
      },
      "fields": {
        "Name": "Contoso Ltd.",
        "Address": "123 Main St",
        "City": "Atlanta",
        "Balance": 1250.50
      }
    }
  ]
}

Data Shipping Standard Format:

Each record in the data array contains:

Field names are normalized to contain only alphanumeric characters (spaces and special characters replaced with underscores).

Record Lookup Logic:

For each record in the data array, the system determines whether to insert or update based on:

  1. If "id" is provided:
  1. If "primaryKey" is provided (without "id"):
  1. If neither "id" nor "primaryKey" is provided:

Field Handling:

Supported Field Types:

Special Field Handling:

Notes:

Example Usage Scenarios:

  1. Insert new customer record:

``json { "data": [ { "primaryKey": { "No_": "CUST-001" }, "fields": { "Name": "New Customer Inc.", "Address": "456 Oak Ave", "City": "Seattle" } } ] } `` Subject: "Customer" or "18"

  1. Update existing customer by SystemId:

``json { "data": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "fields": { "Address": "789 New Street", "City": "Portland" } } ] } `` Subject: "Customer"

  1. Batch insert/update multiple records:

``json { "data": [ { "id": "existing-customer-guid", "fields": { "City": "Boston" } }, { "primaryKey": { "No_": "CUST-NEW" }, "fields": { "Name": "Fresh Customer", "City": "Miami" } } ] } `` Subject: "Customer"

Error Messages:


3. Data.RecordIds.Get

Purpose: Retrieve record IDs and modification timestamps for records in a specified table within a date/time range.

Description: Retrieves record IDs (SystemId) and modification timestamps (SystemModifiedAt) for records in a specified table within a specified date/time range. This message type is optimized for synchronization scenarios where you need to identify which records have changed without retrieving full record data.

Message Direction: Outbound

Input Parameters:

{
  "tableName": "Customer",  // Table name OR
  "tableNumber": 18,         // Table number OR
  "tableNo": 18,             // Table number (alias for tableNumber) OR
  "tableId": 18,             // Table ID (alias for tableNumber), all optional if subject is set
  "startDateTime": "2026-01-01T00:00:00Z",  // Optional - filter by SystemModifiedAt
  "endDateTime": "2026-02-19T23:59:59Z",    // Optional - filter by SystemModifiedAt
  "tableView": "WHERE(Blocked = CONST( ))",  // Optional - additional filtering
  "skip": 0,                 // Optional - number of records to skip (default: 0)
  "take": 100                // Optional - number of records to return (default: 100)
}

Response Format:

{
  "status": "Success",
  "noOfRecords": 245,  // Total number of records matching the filters
  "result": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "modifiedAt": "2026-02-15T14:30:00Z"
    },
    {
      "id": "b2c3d4e5-f6g7-8901-bcde-fg2345678901",
      "modifiedAt": "2026-02-16T09:15:30Z"
    }
  ]
}

Response Fields:

Notes:

Example Usage Scenarios:

  1. Get all customer record IDs (no date filter):

``json { "tableName": "Customer" } ``

  1. Get customer record IDs modified in date range:

``json { "tableName": "Customer", "startDateTime": "2026-02-01T00:00:00Z", "endDateTime": "2026-02-28T23:59:59Z" } ``

  1. Get customer IDs with pagination (first 100 records):

``json { "tableName": "Customer", "startDateTime": "2026-02-01T00:00:00Z", "endDateTime": "2026-02-28T23:59:59Z", "skip": 0, "take": 100 } ``

  1. Get customer IDs with table view filter:

``json { "tableName": "Customer", "startDateTime": "2026-02-01T00:00:00Z", "endDateTime": "2026-02-28T23:59:59Z", "tableView": "WHERE(Blocked = CONST( ))" } ``

Integration Pattern:

Step 1: Identify changed records

{
  "type": "Data.RecordIds.Get",
  "data": {
    "tableName": "Customer",
    "startDateTime": "2026-02-01T00:00:00Z",
    "endDateTime": "2026-02-28T23:59:59Z"
  }
}

Step 2: Retrieve full data for changed records Use the returned IDs with Data.Records.Get and tableView filter:

{
  "type": "Data.Records.Get",
  "data": {
    "tableName": "Customer",
    "tableView": "WHERE(SystemId=FILTER(a1b2c3d4-e5f6-7890-abcd-ef1234567890|b2c3d4e5-f6g7-8901-bcde-fg2345678901))"
  }
}

4. CSV.Records.Get

Purpose: Export all matching records from a specified Business Central table as a CSV file in Open Mirroring format.

Description: Exports all matching records from a specified table as a UTF-8 encoded CSV file following the bc2adls Open Mirroring column-naming convention. Unlike the JSON-based data message types, this message type returns text/csv content directly in the response blob. For large result sets that approach the 2 GB OutStream limit, a continuation pattern is supported via continueFromRecordId.

Message Direction: Outbound Content-Type: text/csv

Table Identification:

The target table can be specified using the following options (evaluated in this order):

  1. tableName in the JSON data payload
  2. tableNumber in the JSON data payload
  3. tableNo in the JSON data payload (alias for tableNumber)
  4. tableId in the JSON data payload (alias for tableNumber)
  5. subject field in the CloudEvents envelope — accepts either a table name (e.g., "Customer") or a table number (e.g., "18")

Input Parameters:

{
  "tableName": "Customer",              // Table name OR
  "tableNumber": 18,                     // Table number (also: tableNo, tableId)
  "fieldNumbers": [1, 2, 5, 7],         // Optional - specific field numbers to include
  "startDateTime": "2026-01-01T00:00:00Z",  // Optional - filter by SystemModifiedAt >=
  "endDateTime": "2026-12-31T23:59:59Z",    // Optional - filter by SystemModifiedAt <=
  "tableView": "WHERE(Blocked = CONST( ))"  // Optional - additional filter/sort view
}

Note: skip and take are NOT supported. The entire result set is always returned.

Response Format:

When records match, a UTF-8 encoded CSV text is returned with content type text/csv. The first row is the header row; subsequent rows are data rows, one per record.

If no records match the filters, no CSV is written. Both data and datacontenttype in the Cloud Event response will be empty string. The task still completes successfully — always check whether data is empty before attempting to download.

Example (Customer table, fields 1 and 2 only):

No,Name,timestamp,SystemId,SystemCreatedAt,SystemCreatedBy,SystemModifiedAt,SystemModifiedBy,$Company,__rowMarker__
"10000","Contoso Ltd.",0,a1b2c3d4-e5f6-7890-abcd-ef1234567890,2026-01-10T08:00:00.000Z,user-guid-here,2026-03-01T12:30:00.000Z,user-guid-here,"CRONUS International Ltd.",4

Column Naming Convention:

Each column header is formed by stripping non-alphanumeric characters (except %) from the BC field name.

Only the characters abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890% are kept from the BC field name; all other characters (spaces, dots, hyphens, slashes, parentheses, etc.) are removed.

FieldColumn Header
No.No
NameName
Sell-to Customer No.SelltoCustomerNo
SystemIdSystemId

System Fields (always included):

The following system fields are always appended at the end of every row, regardless of fieldNumbers:

ColumnField No.Description
timestamp0Internal timestamp (BigInteger)
SystemId2000000000Record GUID
SystemCreatedAt2000000001Creation timestamp (UTC)
SystemCreatedBy2000000002Created by user GUID
SystemModifiedAt2000000003Last modified timestamp (UTC)
SystemModifiedBy2000000004Last modified by user GUID

$Company Column:

For per-company tables (most Business Central tables), a $Company column is appended after the system fields. The value is double-quoted and escaped. The exact value is controlled by the Export Company Name Type setup field (Cloud Events Setup):

Setup value$Company value
Company Name (default)CompanyName() — the technical Company.Name
Company Display NameCompany."Display Name", falling back to CompanyName() when blank

The value is resolved once per request and reused for every row. The enum is extensible via the Cloud Event Company Name Type enum (65601) and the Cloud Event Company Name interface — see Setup_Reference.md section 8.

rowMarker Column (Open Mirroring):

The __rowMarker__ column is always the last column in every row. For CSV.Records.Get, the value is always 4, indicating an upsert/active record. When combined with CSV.DeletedRecords.Get exports (rowMarker = 2), downstream systems can merge both exports to maintain a complete record lifecycle view. This follows the Open Mirroring convention used by bc2adls and Azure Data Lake sync pipelines.

Supported Field Types:

Value Formatting:

TypeFormatQuoted
BigInteger, Integer, Decimal, DurationCulture-invariant (Format(x, 0, 9))No
Booleantrue or falseNo
DateYYYY-MM-DD (blank date → empty string)No
TimeHH:MM:SSYes
DateTimeISO 8601 UTC with 3-digit ms: YYYY-MM-DDTHH:MM:SS.mmmZ (zero DateTime → empty string)No
OptionEnum value name (not caption)Yes
Code, Text, GuidRaw valueYes

String quoting: values are wrapped in double quotes; inner double quotes are escaped as \", backslashes as \\, and CR/LF replaced with a space.

Notes:

Example Usage Scenarios:

  1. Export all Customer fields as CSV:

``json {"tableName": "Customer"} ``

  1. Export specific Customer fields, modified in a date range:

``json { "tableName": "Customer", "fieldNumbers": [1, 2, 5, 7, 21], "startDateTime": "2026-03-01T00:00:00Z", "endDateTime": "2026-03-31T23:59:59Z" } ``

  1. Export non-blocked customers only:

``json { "tableName": "Customer", "tableView": "WHERE(Blocked = CONST( ))" } ``

  1. Export Item Ledger Entries modified since a checkpoint:

``json { "tableName": "Item Ledger Entry", "startDateTime": "2026-03-15T00:00:00Z" } ``

Error Messages:

Continuation Pattern (Large Exports)

When the CSV response approaches the 2 GB OutStream limit, the export stops after the current 4 MB chunk and returns the SystemId of the next unprocessed record in the continueFromRecordId response field.

How It Works:

  1. Send a normal CSV.Records.Get request (no continueFromRecordId).
  2. Check the continueFromRecordId field in the response.
  3. If it contains a GUID, send another request with continueFromRecordId set to that value.
  4. Repeat until the response continueFromRecordId is empty (all records exported).

**continueFromRecordId is a top-level CloudEvents attribute** (like subject), not part of the JSON data payload.

ParameterTypeRequiredDescription
continueFromRecordIdGUIDNoSystemId of the record to resume from. Omit or leave empty for the first request.

Continuation Example:

First request (no continuation):

{
  "specversion": "1.0",
  "type": "CSV.Records.Get",
  "source": "my-integration",
  "subject": "Item Ledger Entry",
  "datacontenttype": "application/json",
  "data": {}
}

Response indicates more data available:

Next request (with continuation):

{
  "specversion": "1.0",
  "type": "CSV.Records.Get",
  "source": "my-integration",
  "subject": "Item Ledger Entry",
  "continueFromRecordId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "datacontenttype": "application/json",
  "data": {}
}

Final response (all records exported):

Important Notes:


5. Data.Totals.Get

Purpose: Aggregate Decimal SumIndexFields across all matching records in a specified Business Central table, optionally grouped by a field.

Description: Uses Business Central's native CalcSums function to sum one or more Decimal fields without iterating over individual records. Returns a JSON array where each element contains a group key and one key/value pair per requested field. Without groupBy, a single element is returned with an empty group value. With groupBy, one element is returned per distinct value. Supports optional tableView filtering. Does not support pagination — skip, take, startDateTime, and endDateTime are not applicable.

Message Direction: Outbound Content-Type: text/json

Table Identification: Same options as other Data message types (tableName, tableNumber, tableNo, tableId, or subject).

Input Parameters:

{
  "tableName": "Item Ledger Entry",
  "fieldNumbers": [12, 14],
  "tableView": "WHERE(Entry Type=CONST(Purchase))",
  "groupBy": 3
}
ParameterTypeRequiredDescription
tableName / tableNumberstring / integerYes (one of)Target table
fieldNumbersarray of integersRequiredField numbers to aggregate. Must all be Decimal SumIndexFields.
tableViewstringNoBC AL SetView filter to restrict which records are included
groupByinteger or stringNoField number or field name to group by. When provided, returns one result element per distinct value.

**Requirements for fieldNumbers:**

**groupBy behavior:**

Response Format (without groupBy):

{
  "status": "Success",
  "result": [
    {
      "group": "",
      "Quantity": 12500.00,
      "InvoicedQuantity": 11200.50
    }
  ]
}

Response Format (with groupBy):

{
  "status": "Success",
  "result": [
    {
      "group": "Purchase",
      "Quantity": 8500.00,
      "InvoicedQuantity": 7200.00
    },
    {
      "group": "Sale",
      "Quantity": -3200.00,
      "InvoicedQuantity": -2800.50
    }
  ]
}

Field Key Naming Convention:

JSON keys in each result element follow the same stripping rule as Data.Records.Get:

  1. Characters %, ., ", \, /, ' → replaced with _
  2. All other non-[a-zA-Z0-9_] characters (e.g. spaces) → removed
BC Field NameJSON Key
QuantityQuantity
Invoiced QuantityInvoicedQuantity
Cost Amount (Actual)CostAmountActual
Sales (LCY)SalesLCY

CalcSums Requirement:

Data.Totals.Get uses BC's CalcSums, which requires all fields to be declared as SumIndexFields on one of the table's SIFT keys. Use Help.Fields.Get to check field metadata before calling this message type.

If no records match the tableView, CalcSums returns 0 for each field — this is not an error.

Error Handling:

ConditionResponse
fieldNumbers missing or empty{"status":"Error","error":"fieldNumbers is required and must contain at least one field number."}
Table not foundError propagated from table evaluation
Read permission denied{"status":"Error","error":"Read permission denied for table {n}."}
Field not found in table{"status":"Error","error":"Field {n} does not exist in table {t}."}
Field not Decimal type{"status":"Error","error":"Field {n} ({name}) in table {t} is not of type Decimal."}
Field read-restricted{"status":"Error","error":"Read access to field {n} ({name}) in table {t} is restricted."}
Field not a SumIndexFieldBC runtime error propagates as task failure
No records match tableViewReturns 0 for each field — not an error

Usage Examples:

Example 1 — Ungrouped totals:

Request:

{
  "specversion": "1.0",
  "type": "Data.Totals.Get",
  "source": "my-integration",
  "datacontenttype": "application/json",
  "data": {
    "tableName": "Item Ledger Entry",
    "fieldNumbers": [12, 14],
    "tableView": "WHERE(Entry Type=CONST(Purchase))"
  }
}

Response:

{
  "status": "Success",
  "result": [
    {
      "group": "",
      "Quantity": 8500.00,
      "InvoicedQuantity": 7200.00
    }
  ]
}

Example 2 — Grouped by Entry Type (field 3):

Request:

{
  "specversion": "1.0",
  "type": "Data.Totals.Get",
  "source": "my-integration",
  "datacontenttype": "application/json",
  "data": {
    "tableName": "Item Ledger Entry",
    "fieldNumbers": [12, 14],
    "groupBy": 3
  }
}

Response:

{
  "status": "Success",
  "result": [
    {
      "group": "Purchase",
      "Quantity": 8500.00,
      "InvoicedQuantity": 7200.00
    },
    {
      "group": "Sale",
      "Quantity": -3200.00,
      "InvoicedQuantity": -2800.50
    }
  ]
}

Example 3 — Grouped by field name:

Request:

{
  "specversion": "1.0",
  "type": "Data.Totals.Get",
  "source": "my-integration",
  "datacontenttype": "application/json",
  "data": {
    "tableName": "Item Ledger Entry",
    "fieldNumbers": [12],
    "groupBy": "Entry Type"
  }
}

Related Message Types:


6. Data.Notes.Get

Purpose: Retrieve notes attached to records from the Record Link table.

Description: Follows the same record-loop pattern as Data.Records.Get — iterates through matching records and returns notes per record instead of field data. Notes are user-entered text annotations linked to individual records in any table (e.g., Customer, Sales Header, Item). Only entries of type Note are returned — links are excluded.

Message Direction: Outbound

Table Identification:

The target table can be specified using the following options (evaluated in this order):

  1. tableName in the JSON data payload
  2. tableNumber in the JSON data payload
  3. tableNo in the JSON data payload (alias for tableNumber)
  4. tableId in the JSON data payload (alias for tableNumber)
  5. subject field in the CloudEvents envelope

Input Parameters:

{
  "tableName": "Customer",
  "tableView": "WHERE(No. = FILTER(10000..20000))",
  "startDateTime": "2025-01-01T00:00:00Z",
  "endDateTime": "2025-12-31T23:59:59Z",
  "skip": 0,
  "take": 100
}
ParameterTypeRequiredDefaultDescription
tableNameTextYes*Name of the target table
tableNumber / tableNo / tableIdIntegerYes*ID of the target table (alternative to tableName)
tableViewTextNoBC table view filter string to limit which records are included
startDateTimeDateTimeNoFilter records by SystemModifiedAt >= value (ISO 8601 UTC)
endDateTimeDateTimeNoFilter records by SystemModifiedAt <= value (ISO 8601 UTC)
skipIntegerNo0Number of records to skip (pagination)
takeIntegerNo100Maximum records to return (pagination)

\* One table identifier is required.

Response Format:

{
  "status": "Success",
  "noOfRecords": 2,
  "result": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "notes": [
        {
          "lineNo": 12345,
          "description": "Call follow-up",
          "note": "Called customer about delayed payment.",
          "created": "2025-06-15T10:30:00Z",
          "userId": "USER001"
        },
        {
          "lineNo": 12346,
          "description": "Meeting scheduled",
          "note": "Follow-up meeting scheduled.",
          "created": "2025-06-16T14:00:00Z",
          "userId": "USER002"
        }
      ]
    },
    {
      "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "notes": []
    }
  ]
}

Response Fields:

FieldTypeDescription
statusText"Success" or "Error"
noOfRecordsIntegerTotal number of matching records (before skip/take)
resultArrayArray of record objects, each with its notes
result[].idTextSystemId GUID of the record
result[].notesArrayArray of note objects for this record
result[].notes[].lineNoIntegerRecord Link ID (unique identifier)
result[].notes[].descriptionText[250]Short description / subject line of the note
result[].notes[].noteTextThe note text content
result[].notes[].createdDateTimeWhen the note was created (ISO 8601 UTC)
result[].notes[].userIdCode[50]User who created the note

Error Responses:

ErrorCause
Table not foundInvalid table name or number
Permission deniedUser lacks read permission on the table

Example — Get notes for all customers:

{
  "tableName": "Customer"
}

Example — Get notes for a specific customer using tableView:

{
  "tableName": "Customer",
  "tableView": "WHERE(No. = CONST(10000))"
}

Example — Get notes with pagination:

{
  "tableName": "Sales Header",
  "skip": 10,
  "take": 5
}

Example — Get notes modified in a date range:

{
  "tableName": "Customer",
  "startDateTime": "2025-01-01T00:00:00Z",
  "endDateTime": "2025-06-30T23:59:59Z"
}

Performance Considerations:

Related Message Types:


7. Data.Notes.Set

Purpose: Add new notes or edit existing notes on the Record Link table for a specified record.

Description: Writes notes to any BC record via the Record Link table (Type = Note). Each note in the request array is either added (no lineNo) or edited (lineNo provided). Editing a note with empty text deletes it. Returns a summary of added/modified counts and the resulting note details.

Message Direction: Inbound

Table Identification:

The target table can be specified using the following options (evaluated in this order):

  1. tableName in the JSON data payload
  2. tableNumber in the JSON data payload
  3. tableNo in the JSON data payload (alias for tableNumber)
  4. tableId in the JSON data payload (alias for tableNumber)
  5. subject field in the CloudEvents envelope

Record Identification:

The target record must be identified using one of:

At least one must be provided. If both are present, recordId takes precedence.

Input Parameters:

{
  "tableName": "Customer",
  "recordId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "notes": [
    { "description": "Payment follow-up", "note": "New note text" },
    { "description": "Updated subject", "note": "Updated text", "lineNo": 12345 }
  ]
}
ParameterTypeRequiredDefaultDescription
tableNameTextYes*Name of the target table
tableNumber / tableNo / tableIdIntegerYes*ID of the target table (alternative to tableName)
recordIdGUIDYes**SystemId of the target record
tableViewTextYes**BC table view filter to locate exactly one record
notesArrayYesArray of note objects to add or edit
notes[].descriptionText[250]NoShort description / subject line for the note. On edit, only updated when non-empty.
notes[].noteTextYes (add) / No (edit)The note text content. On edit, empty text deletes the note.
notes[].lineNoIntegerNoRecord Link ID of existing note to edit. Omit to add new.

\ One table identifier is required. \\* At least one record identifier is required. If both provided, recordId takes precedence.

Response Format:

{
  "status": "Success",
  "addedCount": 1,
  "modifiedCount": 1,
  "notes": [
    {
      "lineNo": 67890,
      "note": "New note text",
      "action": "added"
    },
    {
      "lineNo": 12345,
      "note": "Updated text",
      "action": "modified"
    }
  ]
}

Response Fields:

FieldTypeDescription
statusText"Success" or "Error"
addedCountIntegerNumber of new notes created
modifiedCountIntegerNumber of existing notes updated
notesArrayArray of processed note objects
notes[].lineNoIntegerRecord Link ID (assigned on add, echoed on edit)
notes[].noteTextThe note text that was written
notes[].actionText"added" or "modified"

Error Responses:

ErrorCause
Table not foundInvalid table name or number
Table restrictedTable is internal and cannot be written via this message type
Record not foundrecordId or tableView did not match any record
Missing record identifierNeither recordId nor tableView was provided
Missing notes arrayThe notes array is required in the request
Note not foundlineNo does not match an existing Note-type record link for the record

Example — Add a single note by SystemId:

{
  "tableName": "Customer",
  "recordId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "notes": [
    { "note": "Called customer about delayed payment." }
  ]
}

Example — Edit an existing note by tableView:

{
  "tableName": "Customer",
  "tableView": "WHERE(No. = CONST(10000))",
  "notes": [
    { "note": "Updated: Payment received.", "lineNo": 12345 }
  ]
}

Example — Mixed add and edit:

{
  "tableName": "Sales Header",
  "recordId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "notes": [
    { "note": "Shipping confirmed." },
    { "note": "Correction: address updated.", "lineNo": 54321 }
  ]
}

Example — Delete a note:

{
  "tableName": "Customer",
  "recordId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "notes": [
    { "note": "", "lineNo": 12345 }
  ]
}

Implementation Details:

Related Message Types:


8. Deleted.Records.Get

Purpose: Retrieve full field-level snapshots of deleted records from the Cloud Events Delete Log.

Description: Retrieves full field-level snapshots of deleted records from the Cloud Events Delete Log, following the same data-shipping format as Data.Records.Get. Prerequisite: "Store Record" must be enabled in Cloud Events Delete Setup for the source table — otherwise an error is returned.

Message Direction: Outbound

Input Parameters:

{
  "tableName": "Customer",
  "startDateTime": "2026-01-01T00:00:00Z",
  "endDateTime": "2026-03-21T23:59:59Z",
  "fieldNumbers": [1, 2, 5],
  "skip": 0,
  "take": 100
}
ParameterTypeDefaultDescription
tableName / tableNumberstring / integerSource table (required)
fieldNumbersint[]all stored fieldsSpecific field numbers to return
startDateTimeISO 8601 datetimeFilter by "Deleted At" ≥
endDateTimeISO 8601 datetimenowFilter by "Deleted At" ≤
skipinteger0Pagination offset
takeinteger100Page size

Response Format:

{
  "status": "Success",
  "noOfRecords": 25,
  "result": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "primaryKey": { "No_": "10000" },
      "fields": { "Name": "Deleted Customer", "City": "Reykjavik" }
    }
  ]
}

Error Scenarios:

Related Message Types:


9. Deleted.RecordIds.Get

Purpose: Retrieve SystemId and deletion timestamp for deleted records — lightweight sync-oriented type.

Description: Returns only SystemId and deletion timestamp for deleted records. Works regardless of "Store Record" configuration in Cloud Events Delete Setup. Ideal for sync workflows that only need to know which records were deleted and when.

Message Direction: Outbound

Input Parameters:

{
  "tableName": "Customer",
  "startDateTime": "2026-03-01T00:00:00Z",
  "endDateTime": "2026-03-21T23:59:59Z",
  "skip": 0,
  "take": 100
}
ParameterTypeDefaultDescription
tableName / tableNumberstring / integerSource table (required)
startDateTimeISO 8601 datetimeFilter by "Deleted At" ≥
endDateTimeISO 8601 datetimenowFilter by "Deleted At" ≤
skipinteger0Pagination offset
takeinteger100Page size

Note: fieldNumbers and tableView are not supported.

Response Format:

{
  "status": "Success",
  "noOfRecords": 42,
  "result": [
    { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "deletedAt": "2026-03-15T14:30:00Z" }
  ]
}

Note: the timestamp field is deletedAt (not modifiedAt as in Data.RecordIds.Get).

Related Message Types:


10. CSV.DeletedRecords.Get

Purpose: Export deleted record audit log entries as CSV.

Description: Returns a plain UTF-8 CSV of Cloud Events Delete Log entries. Returns fixed audit columns plus a $Company column for per-company tables (controlled by the Export Company Name Type setup field — see Setup_Reference.md section 8) — not the field-level record data (use Deleted.Records.Get for full field data). tableName is optional; omit to get entries for all tables.

Message Direction: Outbound

Input Parameters:

{
  "tableName": "Customer",
  "startDateTime": "2026-01-01T00:00:00Z",
  "endDateTime": "2026-03-21T23:59:59Z"
}
ParameterTypeDescription
tableName / tableNumberstring / integerSource table filter (optional — omit for all tables)
startDateTimeISO 8601 datetimeFilter by "Deleted At" ≥
endDateTimeISO 8601 datetimeFilter by "Deleted At" ≤ (defaults to now)

Fixed CSV Columns (always the same):

ColumnDescription
systemIdGUID of the deleted record
tableIdBC table number
tableNameBC table name
deletedAtISO 8601 deletion timestamp
userIdUser ID who deleted the record
$CompanyCompany name (only for per-company tables)
__rowMarker__Open Mirroring row marker — always 2 (deleted record)

rowMarker Column (Open Mirroring):

The __rowMarker__ column is always the last column in every row. For CSV.DeletedRecords.Get, the value is always 2, indicating a deleted record. When combined with CSV.Records.Get exports (rowMarker = 4), downstream systems can merge both exports for a complete record lifecycle view.

Response: When records match, the data field in the response contains a download URL. GET that URL to retrieve the CSV file. The first row is the column header; subsequent rows are data rows.

If no records match the filters, no CSV is written. Both data and datacontenttype in the Cloud Event response will be empty string. The task still completes successfully — check whether data is empty before attempting to download. Pagination (skip/take) is not supported.

Related Message Types:


11. Data.Entries.Find

Purpose: Find all related entries for a document number using BC's standard Navigate (Find Entries) mechanism.

Description: Returns a list of tables that contain entries matching the given document number, along with the record count in each table. This is the programmatic equivalent of the "Find Entries..." action (Ctrl+F7 → Navigate) available throughout Business Central. It searches all standard entry tables (G/L Entries, Customer Ledger Entries, Vendor Ledger Entries, Item Ledger Entries, VAT Entries, Bank Account Ledger Entries, etc.) plus any tables registered by installed extensions.

Message Direction: Outbound

Input Parameters:

{
  "documentNo": "PSI-103047",
  "postingDate": "2025-03-15"
}
ParameterTypeRequiredDescription
documentNostringYesThe document number to search for (e.g. invoice number, order number, shipment number)
postingDatedate (ISO 8601)NoOptional posting date filter. When provided, only entries with this posting date are included. Format: YYYY-MM-DD

Minimal Request (document number only):

{
  "documentNo": "PSI-103047"
}

Response Format:

{
  "status": "Success",
  "documentNo": "PSI-103047",
  "postingDate": "2025-03-15",
  "totalTables": 4,
  "totalRecords": 12,
  "entries": [
    {
      "tableId": 21,
      "tableName": "Cust. Ledger Entry",
      "noOfRecords": 1
    },
    {
      "tableId": 17,
      "tableName": "G/L Entry",
      "noOfRecords": 5
    },
    {
      "tableId": 254,
      "tableName": "VAT Entry",
      "noOfRecords": 2
    },
    {
      "tableId": 379,
      "tableName": "Detailed Cust. Ledg. Entry",
      "noOfRecords": 4
    }
  ]
}

Response Fields:

FieldTypeDescription
statusstring"Success" or "Error"
documentNostringThe document number that was searched
postingDatestringThe posting date filter (only present if provided in request)
totalTablesintegerNumber of distinct tables with matching entries
totalRecordsintegerTotal number of matching records across all tables
entriesarrayArray of table results
entries[].tableIdintegerThe BC table ID
entries[].tableNamestringThe table caption/name
entries[].noOfRecordsintegerNumber of matching records in this table

Usage Notes:

Common Tables in Results:

Table IDTable NameTypical Content
17G/L EntryGeneral ledger postings
21Cust. Ledger EntryCustomer receivables
25Vendor Ledger EntryVendor payables
32Item Ledger EntryInventory movements
254VAT EntryVAT postings
271Bank Account Ledger EntryBank transactions
379Detailed Cust. Ledg. EntryDetailed customer entries
380Detailed Vendor Ledg. EntryDetailed vendor entries
5802Value EntryItem valuation entries

Error Handling:

ErrorCause
documentNo is required.The documentNo parameter was not provided or is empty

Related Message Types:


Related Documentation


© Origo – Cloud Events Base Extension