Using the EMDESK API to retrieve expenses data
The Workspace API allows read access to your expense records using a secure endpoint. You can connect to the API from reporting tools such as Microsoft Excel, Google Sheets, or your own dashboards.
In this article:
- Generate and copy your API key
- Retrieve data in Microsoft Excel (Power Query)
- Retrieve data in Google Sheets (EMDESK API)
Generate and copy your API key
- Go to Settings → General → Workspace API
- Click Add new API key
- Copy the generated token (starts with eyJ...) to your clipboard
This token is your Bearer Token for authentication
Choose an endpoint
For expenses, use:
https://renaissance.api.emdesk.com/api/resource/actual-cost-entry
This endpoint returns a list of all recorded actual cost entries including fields like:
|
Field
|
Type
|
Description
|
|---|---|---|
|
id
|
integer
|
Internal unique identifier of the cost entry. Every entry has a stable ID.
|
|
project_numbering
|
integer
|
Sequential numbering used for ordering cost entries within a project. Often matches reporting order.
|
|
amount
|
number (float)
|
Direct cost amount assigned to this entry (e.g., personnel cost, subcontracting cost). Before overhead/indirects.
|
|
date
|
string (ISO date, YYYY-MM-DD )
|
Start date of the cost or event. If end_date is NULL, this is treated as a single-date expense.
|
|
end_date
|
string or null (ISO date)
|
End date of the cost period. If not null, the cost is time-distributed across this date range (important for burn-rates, monthly breakdowns).
|
|
exclude_funding
|
boolean
|
If true: funding is not applied to this entry (e.g., ineligible cost). Funding = 0.
|
|
exclude_indirect
|
boolean
|
If true: indirect/overhead cost is not applied to this entry.
|
|
amount_indirect
|
number (float)
|
Calculated indirect/overhead amount for this entry. Often based on indirect funding rate × eligible amount.
|
|
participant
|
string
|
Name of the organisation/partner who generated the cost (beneficiary, subcontractor, etc.).
|
|
activity
|
string
|
Work Package / Task / Activity this cost contributes to.
|
|
project
|
string
|
Project short name. Useful only for multi-project contexts in reporting.
|
|
funding_rate
|
number (float 0.0–1.0)
|
Direct funding rate applicable to this cost category. Example: 0.7 = 70 % reimbursement.
|
|
funding_rate_indirect
|
number (float 0.0–1.0)
|
Funding rate applied to the indirect cost amount. Often same as funding_rate unless excluded.
|
|
funding
|
number (float)
|
Eligible direct funding amount (amount × funding_rate).
|
|
funding_indirect
|
number (float)
|
Eligible indirect funding amount (amount_indirect × funding_rate_indirect).
|
|
funding_total
|
number (float)
|
Total funding = funding + funding_indirect.
|
|
amount_total
|
number (float)
|
Total cost including indirects = amount + amount_indirect.
|
|
cost_category
|
string (enum)
|
Financial category of the cost. Common values: "Personnel" , "Subcontracting" , "Travel" , "Other" , "Equip Rate" .
|
|
person
|
number (float)
|
Person-months (PM) or similar effort units. Depends on resource_unit.
|
|
person_pd
|
number (float)
|
Person-days (PD) equivalent. Conversion depends on your project’s settings.
|
|
person_ph
|
number (float)
|
Person-hours (PH) equivalent. Useful for granular analyses.
|
|
personnel_rate_name
|
string or null
|
Name of applied personnel rate (e.g., staff member or blended rate). Only set for Personnel categories.
|
|
personnel_rate
|
number (float)
|
Applied personnel cost rate per PM
|
|
description
|
string or null
|
User-provided description of the cost entry (invoice description, scope of work, notes).
|
|
resource_unit
|
string or null
|
Examples: "PM" (person-month), "PD" (person-day), "PH" (person-hour). null for non-personnel costs.
|
Authentication is always done via:
Authorization: Bearer eyJ...(your API token)
Retrieve data in Microsoft Excel (Power Query)
You can connect Excel directly to the EMDESK API and import live expense records. This works in Excel 365, 2019, or 2016 using Power Query (also called Get & Transform Data).
Start a new Web query
In Excel:
| Menu path |
|---|
| Data → Get Data → From Other Sources → From Web |
A dialog opens. Click Advanced.
Enter the API endpoint and authentication header
In the URL parts section:
https://renaissance.api.emdesk.com/api/resource/actual-cost-entry
In the HTTP request header parameters section:
| Header | Value |
|---|---|
| Authorization | Bearer eyJ…(paste your full API token) |
Click OK.
Excel will now:
- Connect to the endpoint
- Use your token to authenticate
- Retrieve the JSON data
- Open the Power Query Editor
If authentication is successful, you will see either a Record, List, or data column.
Convert JSON into a readable table
In the Power Query Editor:
- If the content appears as a Record, click Into Table (Home tab)
- You will likely see columns like data, timestamp, or status
- Click the expand icon ↔ on the data column
In the expand dialog:
□ Uncheck Use original column name as prefix
- Click OK
You should now see expense fields such as:
| id | project_numbering | amount | date | end_date | participant | exclude_funding | exclude_indirect | currency |
|---|
Format your data (optional but recommended)
In Power Query, assign the correct data types:
| Column | Recommended data type |
|---|---|
| amount | Decimal number |
| date / end_date | Date |
| id | Text |
| participant | Text |
Use: Home → Data Type
Load the data into Excel
Click Close & Load
Your API data now appears in a new worksheet as a formatted Excel table.
You can now:
✔ Filter and sort
✔ Use formulas or PivotTables
✔ Build dashboards or charts
✔ Combine with your budget or cost sheet
Refresh your data anytime
To get updated values from EMDESK:
| Option | Action |
|---|---|
| Refresh manually | Right click table → Refresh |
| Or via ribbon | Data → Refresh All |
Excel will reconnect to the API and update all rows automatically.
🔍 Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| 401 Unauthorized | Token incorrect or expired | Generate a new token in Settings → Workspace API |
| Data loads but some columns are blank | Nested data not expanded | Re-expand the data column |
| “We couldn’t authenticate” | Header not properly formatted | Must start with: Bearer eyJ... |
| Wrong date or amount format | Not assigned as date or number | Apply Data Type in Power Query |
Retrieve data in Google Sheets (EMDESK API)
You can import live expense records from your EMDESK workspace directly into Google Sheets using Apps Script. The setup takes only a few minutes and can be reused or refreshed at any time.
Open Apps Script
In your Google Sheet:
| Menu path |
|---|
| Extensions → Apps Script |
A code editor will open in a new tab.
Paste the script
Delete anything in the editor and replace it with the full script below:
const API_TOKEN = "eyJ0...Q"; // paste your API key from EMDESK
const API_ENDPOINT = "https://renaissance.api.emdesk.com/api/resource/actual-cost-entry";
const TARGET_SHEET = "ActualCostEntries";
function importEmdeskData() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
let sheet = ss.getSheetByName(TARGET_SHEET);
if (!sheet) {
sheet = ss.insertSheet(TARGET_SHEET);
}
sheet.clearContents();
const options = {
method: "get",
headers: {
"Authorization": "Bearer " + API_TOKEN,
"Accept": "application/json"
},
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(API_ENDPOINT, options);
const status = response.getResponseCode();
if (status < 200 || status >= 300) {
sheet.getRange(1, 1).setValue("Error: " + status);
sheet.getRange(2, 1).setValue(response.getContentText());
return;
}
const json = JSON.parse(response.getContentText());
if (!json.data || json.data.length === 0) {
sheet.getRange(1, 1).setValue("No data returned");
return;
}
const headers = Object.keys(json.data[0]);
const rows = json.data.map(obj =>
headers.map(field => obj[field])
);
rows.unshift(headers);
sheet.getRange(1, 1, rows.length, headers.length).setValues(rows);
}
function onOpen() {
SpreadsheetApp.getUi()
.createMenu("EMDESK API")
.addItem("Import Actual Cost Entries", "importEmdeskData")
.addToUi();
}
Configure and save
At the top of the script, replace:
const API_TOKEN = "eyJ0...";
with your full API key from EMDESK (keep the quotes).
Click Save and give your script a name, e.g. EmdeskImport.
Authorize and run
In the toolbar, click:
▶ importEmdeskData
The first time you run it, Google will ask for permissions:
Approve access for UrlFetchApp so Sheets can connect to the API.
Use the custom menu
After saving and reloading the sheet, you will see a new menu:
EMDESK API → Import Actual Cost Entries
Click it — the script will:
✔ Fetch expense data from EMDESK
✔ Create or update the ActualCostEntries sheet
✔ Fill it with all expense fields as rows and columns
Refreshing the data
You can refresh the data anytime:
| Menu path |
|---|
| EMDESK API → Import Actual Cost Entries |
This runs the script again and updates values from the API.
Optional — Enable automatic scheduled refresh
You can automate refresh daily, weekly or hourly:
In Apps Script, go to Triggers → Add Trigger and choose:
| Setting | Value |
|---|---|
| Function | importEmdeskData |
| Event source | Time-driven |
| Type | Daily / Hourly / Custom |
Now the data will refresh automatically.
Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| Error 401 | Token invalid or expired | Generate new API key in EMDESK |
| No data returned | No expense records yet | Enter expenses first |
| Script runs but sheet is empty | Missing data property | Check endpoint and token |
| “Service invoked too many times” | Too frequent refresh | Change trigger to daily/hourly |