Simple Object Designer Documentation
Index

Expose Codeunits

This page explains how to select and expose codeunit methods as business logic APIs.

Accessing the Exposure Interface

  1. Open Expose Data > Expose business logic as APIs
  2. The Business Logic API page shows available methods
  3. Browse and select methods to expose

Finding Methods

Tables never appear here. This list contains codeunits and their methods only. If you are looking for a table — table 27 Item, for example — to expose its fields, you will not find it, and that is by design. Use Expose Data > Expose data as web service APIs instead. See Create API Endpoints.

Browse by Codeunit

  1. View the list of codeunits with exposable methods
  2. Expand or filter to specific codeunits
  3. See methods within each codeunit

The list is a curated allow-list

Not every valid public codeunit method appears here. The set of exposable methods is maintained by Hougaard, and a method being public with supported parameter types does not guarantee it is currently listed. Whse.-Activity-Register — the Register warehouse pick functionality — is an example of a method that had to be added on request.

If the method you need is missing, ask Hougaard to add it. Once added, it ships through an AppSource update to SOD, sometimes within hours. You must then update the SOD app in your environment before the new method appears — see Updating SOD.

Two hard limits on what can ever be added:

  • Only Microsoft / base application codeunits can be exposed. SOD has to prepare a codeunit behind the scenes for it to work as an API, and that is only possible for standard Business Central code. Codeunits and methods delivered by third-party apps cannot be exposed — even when the functionality is triggered from a standard page.
  • Page actions are not exposable. A button you see on a page is not itself a method. To judge whether an action can be exposed, identify the underlying codeunit and method behind it and confirm it is Microsoft-provided. Business Central's Page Inspection tool helps identify the page object, which usually reveals whether the action is standard or app-provided.

Search by Name

Filter by:

  • Codeunit name
  • Method name
  • Codeunit number

Filter by Status

  • Show all methods
  • Show only exposed methods
  • Show only unexposed methods

Exposing a Method

Step 1: Select Method

  1. Find the codeunit and method
  2. Click on the method row

Step 2: Review Parameters

Check the method parameters:

  • Parameter names
  • Parameter types
  • Required vs optional

Step 3: Enable Exposure

  1. Click Exposed or use the action
  2. The configuration opens
  3. Review/modify settings

Step 4: Configure Settings

Setting Description
EntityName JSON property / singular name (camelCase, used in URL)
EntitySetName Collection name (used in URL after companies({id})/)
EntityCaption Human-readable singular caption
EntitySetCaption Human-readable collection caption
Group API URL group segment (the {group} in /api/hougaard/{group}/v2.0/)
ObjectName Generated AL object name (auto-derived from codeunit + method)
RequestRetentionTime Optional retention duration for processed requests

Step 5: Publish

Publish your extension to activate the endpoint.

Method Configuration

The Business Logic API Setting Card

Field Description
Codeunit No. Source codeunit
Method Procedure name
EntityName Singular API name (used in JSON property and URL)
EntitySetName Collection name in the URL
EntityCaption / EntitySetCaption User-facing labels
Group URL group segment in /api/hougaard/{group}/v2.0/
ObjectName Generated AL object name
RequestRetentionTime Optional duration to retain processed requests

There is no separate "API Name" or free-form "Description" field on this card — the identifiers above drive both the endpoint URL and metadata.

Parameter Mapping

Method parameters become JSON request properties named after the AL parameter. There is no separate per-parameter configuration page — SOD validates that each parameter type is API-compatible at the moment you enable exposure.

Validation

Automatic Checks

When you try to expose a method, SOD validates:

  • Parameter types are supported
  • Return type is supported
  • Method is accessible

Validation Errors

Error Cause Solution
"Unsupported parameter type" Parameter not API-compatible Cannot expose this method
"Temporary record not supported" Uses temp tables Cannot expose
"Variant parameter" Dynamic type Cannot expose

Calling Exposed Methods

Methods are invoked as OData v4 bound actions

This is the single biggest source of confusion: inserting a record into the entity set does not run the method. A business logic API generated by SOD is an OData v4 bound action, and you trigger it by POSTing to the bound-action segment.

POST {entityUrl}/Microsoft.NAV.{procedureName}

For a method whose generated procedure name is OnRun, the segment is Microsoft.NAV.OnRun.

Do not POST to {url}/OnRun without the Microsoft.NAV. prefix — that returns "No HTTP resource was found that matches the request URI".

The procedure name can be confirmed by inspecting the AL page object SOD generates for the codeunit and method.

Microsoft's reference: https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-creating-and-interacting-with-odatav4-bound-action

This is not Power Automate-specific. Bound actions are plain HTTP, callable from any client — Postman, curl, a custom C# application — with the same POST to the same segment.

Endpoint URL

The base entity URL:

https://api.businesscentral.dynamics.com/v2.0/{tenant}/{environment}/api/hougaard/{group}/v2.0/companies({companyId})/{entitySetName}
  • {group} is the Group value on the Business Logic API Setting card (used as the API URL segment).
  • {entitySetName} is the Entity Set Name value on the setting card.
  • There is no ?Company= query string on codeunit APIs (the company is part of the path).

To execute the method, append the bound-action segment:

POST https://api.businesscentral.dynamics.com/v2.0/{tenant}/{environment}/api/hougaard/{group}/v2.0/companies({companyId})/{entitySetName}/Microsoft.NAV.OnRun

Request Format

{
  "parameter1": "value1",
  "parameter2": 123
}

JSON property names are generated from the AL parameter and field identifiers. For a method taking a record's primary key fields, the body looks like this:

{
  "Warehouse_Activity_Line_Activity_Type": "Pick",
  "Warehouse_Activity_Line_No_": "PICK0000000",
  "Warehouse_Activity_Line_Line_No_": 10000
}

A BadRequest (HTTP 400) means the body or its property names do not match what the generated API page expects — inspect the generated page code to confirm the exact names.

A walkthrough video is available at https://youtu.be/xFVu0bOovYg.

Option and Enum parameter values

When a parameter is an option or enum type, pass the underlying integer value, not the caption. Power Automate in particular requires the number.

Service Document Type, for example:

Value Meaning
0 Quote
1 Order
2 Invoice
3 Credit Memo

A "service order" is therefore document type 1. Sales, Purchase and Service documents each have their own document type enum values — use the right one for your table.

Symptom of a wrong value: the action reports that the record "does not exist", because the document type does not match any record.

Codeunits with an "OnRun" parameter table

Some codeunits operate on a parameter record and expose a corresponding OnRun table. You must insert the parameter record before invoking the codeunit.

To post an Item Journal Line with the Item Jnl.-Post Line codeunit:

  1. Add a record to the ItemJnlPostLineOnRun table — this holds the Item Journal Line the codeunit will read
  2. Run/post the codeunit through its bound action

Running the codeunit without inserting the record first produces an error. The general principle: populate the OnRun table first, then invoke the codeunit.

Posting routines that show a dialog

A posting routine that asks the user a question in the UI cannot be answered through the API. Calling purch_postonrun-onRun without preparing the record returns HTTP 400 with:

Application_DialogException: Please enter "Yes" in Receive and/or Invoice and/or Ship.

Resolution: set the relevant selection fields — Receive, Invoice, Ship — on the document header as a separate API call first, then invoke the posting action.

The general rule: for any posting routine that relies on an interactive dialog, populate the corresponding fields on the document header record before calling the posting API.

Response

Success:

{
  "value": "result if any"
}

Error:

{
  "error": {
    "code": "Error_Code",
    "message": "Error description"
  }
}

Managing Exposed Methods

Viewing Exposed Methods

Filter Business Logic API list to Exposed = Yes

Modifying Configuration

  1. Select exposed method
  2. Open configuration
  3. Make changes
  4. Republish

Removing Exposure

  1. Select exposed method
  2. Uncheck Exposed or remove
  3. Republish
  4. Note: Breaks existing consumers

Best Practices

Method Selection

Choose methods that:

  • Have clear business purpose
  • Have stable signatures
  • Validate inputs properly
  • Handle errors gracefully

Naming

  • Use descriptive API names
  • Follow naming conventions
  • Document clearly

Security

  • Consider who needs access
  • Review method permissions
  • Log significant operations

Testing

  • Test with various inputs
  • Test error scenarios
  • Verify BC behavior matches expectations

Troubleshooting

Method Not Appearing

Check:

  • Codeunit is in downloaded symbols
  • Method is public
  • Method has supported parameters
  • Is it a table? Tables never appear here — use Expose data as web service APIs
  • Is it a page action? Page actions are not exposable; find the codeunit method behind it
  • Does it come from a third-party app? Only Microsoft codeunits can be exposed
  • Is it simply not on the allow-list yet? Request it from Hougaard, then update SOD once it ships

Exposure Fails

Check:

  • Parameter types supported
  • No temporary tables
  • No variant parameters

Call Fails

Check:

  • Authentication valid
  • Parameters correct
  • Permissions sufficient
  • The bound-action segment is present and spelled correctly

"No HTTP resource was found that matches the request URI"

Cause: the bound-action URL is missing the Microsoft.NAV. prefix, or the wrong HTTP verb is used.

Solution: POST to {entityUrl}/Microsoft.NAV.{procedureName} (for example Microsoft.NAV.OnRun). Confirm the procedure name from the generated AL page object.

The call fails for a service-to-service caller while other APIs work

An Entra (Azure AD) application can authenticate, GET and POST against custom table APIs, and still fail on a business logic call.

Cause: the Entra application lacks Business Central permissions to the tables the method touches. A method such as "Release Sales Document" runs BC logic across many tables.

Fix: assign the Entra application the permission set included with your SOD-published app. Azure AD API permissions (API.ReadWrite.All) operate at the API layer only — they do not grant table access. See Consuming APIs.

Internal_RecordNotFound although the operation succeeded

Symptom: the POST executes the business logic correctly — the pick is registered, for example — but the response contains:

{
  "error": {
    "code": "Internal_RecordNotFound",
    "message": "The Warehouse Activity Line does not exist. Identification fields and values: Activity Type='Pick',No.='...',Line No.='...'"
  }
}

Cause: the record that keyed the call no longer exists when the framework reads it back, because the method itself deleted or registered it.

Fix: update SOD to 12.0.0.560 or later from AppSource and republish the app. Do not work around it by swallowing API errors unconditionally — that would mask genuine failures too.