Consumes Microsoft standard Business Central APIs (v2.0) for customers, vendors, items, salesOrders, and other built-in entities. No AL coding required. Use when integrating external systems with BC data, building Power Automate flows, or querying BC from Postman/scripts.
70
85%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Standard APIs are maintained by Microsoft and expose common BC entities. No AL coding required - just authenticate and call the endpoints.
For custom data or business logic, use al-custom-api skill instead.
| Entity | Endpoint | Operations |
|---|---|---|
| Companies | /companies | GET |
| Customers | /customers | GET, POST, PATCH, DELETE |
| Vendors | /vendors | GET, POST, PATCH, DELETE |
| Items | /items | GET, POST, PATCH, DELETE |
| Sales Orders | /salesOrders | GET, POST, PATCH, DELETE |
| Sales Invoices | /salesInvoices | GET, POST, PATCH, DELETE |
| Purchase Orders | /purchaseOrders | GET, POST, PATCH, DELETE |
| Purchase Invoices | /purchaseInvoices | GET, POST, PATCH, DELETE |
| General Ledger Entries | /generalLedgerEntries | GET |
| Accounts | /accounts | GET |
| Dimensions | /dimensions | GET |
| Employees | /employees | GET, POST, PATCH, DELETE |
| Journal Lines | /journalLines | GET, POST, PATCH, DELETE |
Full list: Microsoft API v2.0 Reference
Prerequisite: Azure AD App Registration with Dynamics 365 Business Central API permissions.
See al-oauth-integration skill for token acquisition patterns.
Token endpoint:
POST https://login.microsoftonline.com/<TenantID>/oauth2/v2.0/token
grant_type=client_credentials
client_id=<ClientID>
client_secret=<ClientSecret>
scope=https://api.businesscentral.dynamics.com/.defaultBase URL pattern:
https://api.businesscentral.dynamics.com/v2.0/<TenantID>/<Environment>/api/v2.0With company:
https://api.businesscentral.dynamics.com/v2.0/<TenantID>/<Environment>/api/v2.0/companies(<CompanyID>)/<Entity>| Placeholder | Description | Example |
|---|---|---|
<TenantID> | Azure AD tenant ID (GUID) | 12345678-1234-1234-1234-123456789abc |
<Environment> | BC environment name | Production, Sandbox |
<CompanyID> | Company SystemId (GUID) | 87654321-4321-4321-4321-cba987654321 |
<Entity> | API entity name (camelCase plural) | customers, salesOrders |
<EntityID> | Record SystemId (GUID) | 11111111-2222-3333-4444-555555555555 |
GET all companies:
GET /api/v2.0/companies
Authorization: Bearer <token>GET all customers (with $select):
GET /api/v2.0/companies(<CompanyID>)/customers?$select=id,number,displayName,email
Authorization: Bearer <token>GET single customer:
GET /api/v2.0/companies(<CompanyID>)/customers(<EntityID>)
Authorization: Bearer <token>POST new customer:
POST /api/v2.0/companies(<CompanyID>)/customers
Authorization: Bearer <token>
Content-Type: application/json
{
"displayName": "New Customer",
"email": "customer@example.com",
"currencyCode": "EUR"
}PATCH update customer:
PATCH /api/v2.0/companies(<CompanyID>)/customers(<EntityID>)
Authorization: Bearer <token>
Content-Type: application/json
If-Match: *
{
"email": "updated@example.com"
}DELETE customer:
DELETE /api/v2.0/companies(<CompanyID>)/customers(<EntityID>)
Authorization: Bearer <token>
If-Match: *$select - Limit returned fields (ALWAYS use for performance):
?$select=id,number,displayName$filter - Filter results:
?$filter=displayName eq 'Contoso'
?$filter=lastModifiedDateTime gt 2024-01-01T00:00:00Z
?$filter=contains(displayName,'Smith')$filter with IN operator (BC24+):
Requires $schemaversion=2.1 in URL:
?$schemaversion=2.1&$filter=number in ('10000', '20000', '30000')Without $schemaversion=2.1, returns error BadRequest_MethodNotImplemented.
$expand - Include related entities:
?$expand=salesOrderLines
?$expand=customer($select=displayName,email)Filter inside $expand:
?$expand=salesOrderLines($filter=lineType eq 'Item')Note: Use parentheses () around the nested query options.
Multi-level expand:
?$expand=salesOrderLines($expand=item($expand=itemCategory))$orderby - Sort results:
?$orderby=displayName
?$orderby=lastModifiedDateTime desc$count - Get total count:
/salesOrders/$countReturns integer count of matching records.
BC uses server-driven paging with @odata.nextLink:
{
"@odata.context": "...",
"value": [...],
"@odata.nextLink": "https://api.../customers?$skiptoken=..."
}Pattern:
value array@odata.nextLink exists, request that URL@odata.nextLinkDo NOT use $top + $skip for paging - poor performance.
| Environment | Limit |
|---|---|
| BC Online | 600 requests/minute |
| BC On-Premises | Configurable |
HTTP 429 = Too Many Requests → implement exponential backoff.
| Error | Cause | Fix |
|---|---|---|
| 401 | Invalid/expired token | Refresh OAuth token |
| 403 | Missing permissions | Check Azure AD API permissions |
| 404 | Entity not found | Verify CompanyID and EntityID |
| 400 | Invalid request | Check JSON body, field names (camelCase) |
| 429 | Rate limited | Implement backoff, reduce request frequency |
displayName not Display Name* or actual ETagSee references/ folder for:
http-examples.md - Complete HTTP request examples for all standard entities (customers, vendors, items, sales orders, etc.)52f8705
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.