Thyme App • Website • BC API Docs
Custom Business Central API endpoints for the Thyme time tracking app.
The standard BC API v2.0 /projects endpoint only returns 4 fields:
id,number,displayName,lastModifiedDateTime
This extension exposes additional fields needed by Thyme:
- Customer name and number
- Person responsible
- Project status and dates
- Job tasks
- Time sheets with approval status (Open, Submitted, Approved, Rejected)
- Resources with capacity information
- Posted time entries from Job Ledger
Once deployed, the APIs are available at:
.../api/knowall/thyme/v1.0/companies({companyId})/projects
.../api/knowall/thyme/v1.0/companies({companyId})/jobTasks
.../api/knowall/thyme/v1.0/companies({companyId})/timeSheets
.../api/knowall/thyme/v1.0/companies({companyId})/timeSheetLines
.../api/knowall/thyme/v1.0/companies({companyId})/timeSheetDetails
.../api/knowall/thyme/v1.0/companies({companyId})/resources
.../api/knowall/thyme/v1.0/companies({companyId})/timeEntries
For user information, use BC's standard Automation API:
.../api/microsoft/automation/v2.0/companies({companyId})/users
Base URL: https://api.businesscentral.dynamics.com/v2.0/{tenant}/{environment}
| Field | Description |
|---|---|
id |
System GUID |
number |
Job No. |
description |
Project description |
billToCustomerNo |
Customer number |
billToCustomerName |
Customer name |
personResponsible |
Project manager |
status |
Planning, Quote, Open, Completed |
startingDate |
Project start date |
endingDate |
Project end date |
lastModifiedDateTime |
Last modified timestamp |
| Field | Description |
|---|---|
id |
System GUID |
jobNo |
Parent job number |
jobTaskNo |
Task number |
description |
Task description |
jobTaskType |
Posting, Heading, Total, Begin-Total, End-Total |
lastModifiedDateTime |
Last modified timestamp |
| Field | Description |
|---|---|
id |
System GUID |
number |
Time sheet number |
startingDate |
Week starting date |
endingDate |
Week ending date |
resourceNo |
Resource number |
ownerUserId |
Owner user ID |
approverUserId |
Approver user ID |
openExists |
True if any line is Open |
submittedExists |
True if any line is Submitted |
rejectedExists |
True if any line is Rejected |
approvedExists |
True if any line is Approved |
lastModifiedDateTime |
Last modified timestamp |
Bound Actions:
POST /timeSheets({id})/Microsoft.NAV.submit- Submit for approvalPOST /timeSheets({id})/Microsoft.NAV.approve- Approve time sheetPOST /timeSheets({id})/Microsoft.NAV.reject- Reject time sheetPOST /timeSheets({id})/Microsoft.NAV.reopen- Reopen for editing
| Field | Description |
|---|---|
id |
System GUID |
timeSheetNo |
Parent time sheet number |
lineNo |
Line number |
timeSheetStartingDate |
Time sheet starting date |
type |
Resource, Job, Absence, Assembly Order, Service |
jobNo |
Job number (if type=Job) |
jobTaskNo |
Job task number (if type=Job) |
description |
Line description |
totalQuantity |
Total hours (sum of details) |
status |
Open, Submitted, Rejected, Approved |
approvedBy |
User who approved |
approvalDate |
Date approved |
posted |
Whether posted to ledger |
lastModifiedDateTime |
Last modified timestamp |
Bound Actions:
POST /timeSheetLines({id})/Microsoft.NAV.approve- Approve linePOST /timeSheetLines({id})/Microsoft.NAV.reject- Reject linePOST /timeSheetLines({id})/Microsoft.NAV.reopen- Reopen for editing
Daily hour entries for each time sheet line. One record per day with hours.
| Field | Description |
|---|---|
id |
System GUID |
timeSheetNo |
Parent time sheet number |
timeSheetLineNo |
Parent line number |
date |
Date for this entry |
type |
Resource, Job, Absence, etc. |
resourceNo |
Resource number |
jobNo |
Job number |
jobTaskNo |
Job task number |
quantity |
Hours worked |
postedQuantity |
Hours already posted |
status |
Open, Submitted, Rejected, Approved |
posted |
Whether posted to ledger |
lastModifiedDateTime |
Last modified timestamp |
Usage: To log 4 hours on Jan 8 for a job:
POST /timeSheetDetails
{ "timeSheetNo": "TS00001", "timeSheetLineNo": 10000, "date": "2026-01-08", "quantity": 4 }
| Field | Description |
|---|---|
id |
System GUID |
number |
Resource No. |
name |
Resource name |
searchName |
Search name for lookup |
type |
Person or Machine |
capacity |
Weekly hours capacity (FlowField) |
unitCost |
Cost per unit |
unitPrice |
Price per unit |
baseUnitOfMeasure |
Hour/Day units |
resourceGroupNo |
Resource group code |
blocked |
Whether resource is blocked |
privacyBlocked |
Privacy blocked flag |
useTimeSheet |
Time sheet enabled |
timeSheetOwnerUserId |
Time sheet owner user ID |
timeSheetApproverUserId |
Time sheet approver user ID |
lastDateModified |
Last date modified |
lastModifiedDateTime |
Last modified timestamp |
| Field | Description |
|---|---|
id |
System GUID |
entryNo |
Ledger entry number |
jobNo |
Parent job number |
jobTaskNo |
Task number |
postingDate |
Entry posting date |
type |
Entry type (Resource) |
number |
Resource/item number |
description |
Entry description |
quantity |
Hours/units |
unitCost |
Cost per unit (LCY) |
totalCost |
Total cost (LCY) |
unitPrice |
Price per unit (LCY) |
totalPrice |
Total price (LCY) |
workTypeCode |
Work type classification |
entryType |
Usage or Sale |
documentNo |
Source document number |
lastModifiedDateTime |
Last modified timestamp |
Note: Time Entries are filtered to Resource-type entries only (employee time tracking).
For user information, use BC's built-in Automation API:
GET /api/microsoft/automation/v2.0/companies({companyId})/users
Returns userSecurityId, userName, displayName, state, expiryDate, contactEmail.
Usage: Match the user's userName to a Resource's timeSheetOwnerUserId field.
- VS Code
- AL Language extension
- Access to a Business Central sandbox environment
- Open the project in VS Code
- Press
Ctrl+Shift+P→ "AL: Download Symbols" - Enter your BC sandbox credentials
Press Ctrl+Shift+B to build the .app file.
The repo includes CI/CD workflows for both environments:
| Workflow | Trigger | Target |
|---|---|---|
deploy-sandbox.yml |
Push to main |
Sandbox (Contoso Ltd) |
deploy-production.yml |
Release published | Production (KnowAll Ltd) |
GitHub Environments Required:
Create two environments in Settings → Environments:
- Sandbox - No protection rules
- Production - Add required reviewers for safety
Secrets (per environment):
| Secret | Description |
|---|---|
BC_TENANT_ID |
Your Azure AD tenant ID |
BC_CLIENT_ID |
Azure AD app registration client ID |
BC_CLIENT_SECRET |
Azure AD app registration client secret |
Azure AD App Setup:
- Register an app in Azure AD
- Grant API permissions:
Dynamics 365 Business Central→API.ReadWrite.AllandAutomation.ReadWrite.All - Add redirect URI:
https://businesscentral.dynamics.com/OAuthLanding.htm - Create a client secret
- In BC Admin Center → Microsoft Entra Apps → Authorize the app
- Critical: In Business Central → search "Microsoft Entra applications" → add the app with permission sets
D365 AUTOMATIONandEXTEN. MGT. - ADMIN
See docs/INSTALLATION.adoc for detailed setup instructions.
- Configure
launch.jsonwith your sandbox environment name - Press
F5to publish directly to sandbox
- Build the
.appfile - Go to BC Admin Center → Extensions → Upload Extension
- Or use PowerShell:
Publish-NAVApp
thyme-bc-extension/
├── app.json # Extension manifest
├── src/
│ ├── api/
│ │ ├── ThymeProjectsAPI.Page.al # Projects endpoint (page 50100)
│ │ ├── ThymeJobTasksAPI.Page.al # Job Tasks endpoint (page 50101)
│ │ ├── ThymeTimeSheetAPI.Page.al # Time Sheets (page 50102)
│ │ ├── ThymeTimeSheetLineAPI.Page.al # Time Sheet Lines (page 50103)
│ │ ├── ThymeResourcesAPI.Page.al # Resources endpoint (page 50104)
│ │ └── ThymeTimeEntriesAPI.Page.al # Time Entries endpoint (page 50105)
│ └── codeunit/
│ └── ThymeTimeSheetActions.Codeunit.al # Approval workflow actions (codeunit 50100)
└── .vscode/
├── launch.json # Debug configuration
└── settings.json # Editor settings
- Installation Guide - Complete setup instructions
- Solution Design - Architecture and API design
- Troubleshooting - Common issues and solutions
- Testing - How to test the API