Metadata discovery
The information on the BI Endpoints page in Business Central is also available as API endpoints. Use them to build documentation, generate pipelines, or create relationships in a BI model without hard-coding endpoint and field names.
| Endpoint | Returns |
|---|---|
biEndpoints | Every endpoint, standard and custom, with category, type, business key, URLs, tier and source table |
properties | The fields of each endpoint |
relationships | Foreign keys from an endpoint to others |
referencedBy | Foreign keys in other endpoints pointing at an endpoint |
applicationInfo | The installed app version and the subscription |
They are read like any other endpoint, under
.../api/datawareness/endpoints/v1.0/companies({companyId})/, and take
$filter and $select. In the Postman collection they are in the System
folder.
biEndpoints
GET .../biEndpoints?$filter=category eq 'Sales'
| Field | Meaning |
|---|---|
entitySetName | The endpoint name used in the URL, for example customers |
category | Finance, Sales, Purchasing, Inventory, Jobs, Resources, Manufacturing, Assembly, Approvals, System or Custom |
type | Master Data or Transactional Data |
businessKeyFields | The field or fields that identify a record, joined with &&, for example documentNo&&lineNo |
url | The full URL of the endpoint in this environment and company |
genericUrl | The same URL with {{tenantId}}, {{environment}} and {{companyId}} placeholders |
deletedRecordsUrl, genericDeletedRecordsUrl | The URL of the endpoint's deleted entries. See Deleted entries. |
tier | Free or Premium |
description | What the endpoint provides |
sourceTable | The Business Central source table |
Category and type are rendered in the API output language.
properties
The fields of one endpoint:
GET .../properties?$filter=entitySetName eq 'purchaseInvoiceHeaders'
| Field | Meaning |
|---|---|
entitySetName | The endpoint |
propertyName | The field name in the response, for example buyFromVendorNo |
propertyCaption | The field's caption, for example Buy-from Vendor No. |
dataType | The type, for example Code, Text, Decimal, Date |
maxLength | The maximum length of text and code fields |
isPrimaryKey | Whether the field is part of the business key |
For a custom endpoint, propertyName is the column
slot (col1, col2, …) and propertyCaption is the business field it
holds.
relationships
How an endpoint's foreign keys join to other endpoints:
GET .../relationships?$filter=fromEndpoint eq 'purchaseInvoiceHeaders'
{
"value": [
{ "fromEndpoint": "purchaseInvoiceHeaders", "foreignKey": "buyFromVendorNo", "toEndpoint": "vendors", "primaryKeyField": "no", "condition": "" },
{ "fromEndpoint": "purchaseInvoiceHeaders", "foreignKey": "buyFromContactNo", "toEndpoint": "contacts", "primaryKeyField": "no", "condition": "" }
]
}
condition qualifies a relationship that only holds under a condition. For
example, a global dimension column joins to dimensionValues only for the
dimension code set up in General Ledger Setup:
dimensionCode=glSetup.globalDimension1Code.
referencedBy
The inverse: which endpoints point at this one.
GET .../referencedBy?$filter=toEndpoint eq 'purchaseInvoiceHeaders'
{
"value": [
{ "fromEndpoint": "purchaseInvoiceLines", "foreignKey": "documentNo", "toEndpoint": "purchaseInvoiceHeaders", "primaryKeyField": "no" }
]
}
applicationInfo
GET .../applicationInfo
| Field | Meaning |
|---|---|
appId, name, publisher, version | The installed BI Endpoints app |
subscriptionId, tier, subscriptionStatus, expirationDate | The subscription |
adminName, adminEmail | The subscription admin from BI Endpoints Setup |
Use it to check which version a pipeline is talking to, and whether the subscription is active.
Example: build a model from metadata
# Every transactional endpoint, its fields, and its joins
endpoints = get_all(f"{base}/biEndpoints?$filter=type eq 'Transactional Data'")
for ep in endpoints:
name = ep["entitySetName"]
fields = get_all(f"{base}/properties?$filter=entitySetName eq '{name}'")
joins = get_all(f"{base}/relationships?$filter=fromEndpoint eq '{name}'")
...
Add a custom endpoint and the same code picks it up on its next run.