REST API
The Principal Toolbox REST API allows administrators and developers to integrate external systems with the Principal Toolbox programmatically. This article covers authentication, request formatting, all available endpoints, and error handling.
Getting Started
This section covers the foundational requirements for making API calls: the base URL structure, authentication flow, required headers, error responses, and data formatting rules.
Base URL structure
All API endpoints follow this URL pattern:
{baseurl}/service/fortesipm/{objecttype}/{crud}/{context}
| Segment | Description |
|---|---|
{baseurl} | The root URL of your Principal Toolbox instance (e.g. https://client.principaltoolbox.com) |
{objecttype} | The type of object being targeted (e.g. node, entry, user) |
{crud} | The operation type: read, create, update, or delete |
{context} | The specific action or scope (e.g. instance, list, descendants) |
Example:
https://client.principaltoolbox.com/service/fortesipm/node/read/descendants
Authentication
Authentication uses a token-based flow. First obtain a token via login, then include it in all subsequent requests.
Step 1: Obtain a token
Send a POST request to:
POST {baseurl}/service/fortesipm/login
Request body:
{
"username": "someUsername",
"password": "somePassword"
}
A successful login returns HTTP 200 with the following response body:
{
"status": { "code": 101, "text": "SUCCESSFUL" },
"message": "Successful lease",
"details": {
"loginMessage": "Logged in",
"authToken": "NmZmNDM1YTEt...",
"username": "someUsername",
"userDisplayName": "Display Name",
"userID": 1234,
"administrator": false
}
}
A failed login returns HTTP 403.
Step 2: Use the token
Include the authToken value in every subsequent request using the following header:
PTB-Rest-Authorization: Basic {TOKEN}
Note: The Principal Toolbox requires a minimum JVM version of 1.7 for 4096-bit SSL connections.
Required headers
| Header | Value | When required |
|---|---|---|
Content-Type | Application/JSON;charset=UTF-8 | All JSON request bodies |
PTB-Rest-Authorization | Basic {TOKEN} | All calls except login |
For multipart requests (document upload), omit Content-Type and let the HTTP client set it automatically.
Error handling
When a request fails, the API returns HTTP 400 with a RestStatus object in the response body:
{
"status": { "code": 102, "text": "FAILURE" },
"message": "This is an error message"
}
Status codes:
| Code | Text | Description |
|---|---|---|
101 | SUCCESSFUL | The request completed successfully |
102 | FAILURE | A general error occurred |
501 | LEASE SUCCESSFUL | Object was leased (locked) successfully |
502 | LEASE FAILURE | Object is already locked by another user |
When a 502 Lease Failure occurs, the response includes additional details:
{
"status": { "code": 502, "text": "LEASE FAILURE" },
"message": "Object is locked",
"details": {
"lockedOn": "2024-01-15T10:30:00",
"lockedBy": "someUsername",
"leaseTime": 300
}
}
Data formats
| Type | Format | Examples |
|---|---|---|
| Encoding | UTF-8 | — |
| Dates | YYYY-MM-DD | 2015-08-04 |
| Numbers | [-]#[.##] | 450, 2031.40, -12.3 |
| JSON | RFC7159 compliant | — |
| CSV (import/export) | Header row required; no spaces in column names; string and memo values in quotes | — |
When passing XML inside a JSON parameter, strip all tabs, newlines, and comments from the XML before encoding it as a JSON string value.
Instances
Instance endpoints read and write individual nodes or collections of nodes within the Principal Toolbox object tree.
Read instance
Available: 6.0+
Returns the data for a single node by its ID.
GET {baseurl}/service/fortesipm/node/read/instance/{id}
| Parameter | Type | Description |
|---|---|---|
id | URL | The node ID to retrieve |
The response includes the node's nodeTypeName, nodeTypeID, id, and all field values.
Example:
GET {baseurl}/service/fortesipm/node/read/instance/48826857
Read list
Available: 6.0+
Returns all nodes of a given type, system-wide. This endpoint is not scope-limited to a specific location, making it suitable for retrieving financial categories, skills, and other global node types.
POST {baseurl}/service/fortesipm/node/read/list/{nodeTypeName}
| Parameter | Type | Description |
|---|---|---|
nodeTypeName | URL | The node type to list (e.g. P2Project, PlanItem) |
POST body parameters (all optional):
| Parameter | Description |
|---|---|
viewXml | A view definition XML for filtering and layout. If omitted, all fields are returned with no filter. |
fieldNames | Comma-separated list of field names to return (e.g. "Name,Description,FolderID") |
sortFields | Comma-separated field names to sort by |
sortDirections | Sort direction per sort field: ASC or DESC |
Example with viewXml filter (XML must be on a single line with no tabs or newlines):
{
"viewXml": "<listing id='0'><filter><Name operator='equals' filterValues='Test issue' /></filter><layout><header /><row><cell name='Name' /><cell name='Description' /><cell name='FolderID' /></row></layout></listing>"
}
Example with fieldNames only:
{
"fieldNames": "Name,Description,FolderID"
}
Read descendants
Available: 7.0+
Returns all nodes of a given type within the scope of a parent location. Results are returned as a flat (non-hierarchical) list.
POST {baseurl}/service/fortesipm/node/read/descendants/{id}/{type}
| Parameter | Type | Description |
|---|---|---|
id | URL | The parent node ID (defines the scope) |
type | URL | The node type name to return |
POST body parameters are the same as Read list: viewXml, fieldNames, sortFields, sortDirections. All optional.
Read recursive
Available: 7.0+
Returns a hierarchical (nested) JSON structure of nodes. Similar to Read descendants, but preserves the tree structure. The root node is always included in the result.
POST {baseurl}/service/fortesipm/node/read/recursive/{id}/{type}/{relation}
| Parameter | Type | Description |
|---|---|---|
id | URL | The root node ID |
type | URL | The node type name |
relation | URL | The relation type: normal, planning, or breakdown |
POST body parameters:
| Parameter | Description |
|---|---|
fieldNames | Comma-separated list of field names to return (optional) |
Example:
POST {baseurl}/service/fortesipm/node/read/recursive/1455/PlanItem/planning
Update instance
Available: 8.5+
Updates one or more fields on an existing node.
POST {baseurl}/service/fortesipm/node/update/instance/{nodeTypeName}/{id}
| Parameter | Type | Description |
|---|---|---|
nodeTypeName | URL | The node type name |
id | URL | The node ID to update |
Note: The older endpoint
/node/update/instance/{id}(withoutnodeTypeName) is deprecated since version 8.5.0. Use the form above.
Include only the fields you want to change in the request body:
{
"Remarks": "Remarks on this instance",
"Custom2": "123456"
}
Create instance
Available: 6.0+
Creates a new node at the specified location. Not every node type can be created at every location.
POST {baseurl}/service/fortesipm/node/create/instance/{parentId}/{type}
| Parameter | Type | Description |
|---|---|---|
parentId | URL | The ID of the parent node where the new instance is placed |
type | URL | The node type name to create |
Provide the field values for the new node in the request body:
{
"Description": "REST call does not respond when connection is lost",
"Remarks": "Remarks on this issue",
"Custom2": "123456"
}
Create instances (system-wide)
Available: 8.5.3+
Creates a system-wide node, not attached to a specific location. Use this only for node types explicitly designed for system-wide creation, such as CurrencyRate.
POST {baseurl}/service/fortesipm/node/create/instances/{type}
| Parameter | Type | Description |
|---|---|---|
type | URL | The node type name (e.g. CurrencyRate) |
Example:
{
"Startdate": "2018-01-01",
"Currency": 5678980,
"Rate": 123.456
}
Note: Only use this endpoint when specifically advised to do so. For most node types, use Create instance with a parent location.
Metadata
Metadata endpoints return field definitions and available values for node types.
Read metadata
Available: 6.0+
Returns the metadata for a node type: field names, display names, types, editability, and select values for static select fields. Responses are cached.
POST {baseurl}/service/fortesipm/node/read/metadata/{nodeTypeName}
| Parameter | Type | Description |
|---|---|---|
nodeTypeName | URL | The node type to retrieve metadata for |
No POST body parameters are required.
Example response:
{
"id": 6001,
"name": "Issue",
"displayName": "Issue",
"pluralDisplayName": "Issues",
"fields": {
"Name": {
"displayName": "Name",
"type": "string",
"isEditable": true
},
"Custom2": {
"displayName": "Custom 02",
"type": "int",
"isCustom": true,
"displayWidth": 60,
"isEditable": true
},
"Custom7": {
"displayName": "Custom 07",
"type": "string",
"inputType": "select",
"isCustom": true,
"displayWidth": 100,
"isEditable": true,
"selectvalues": [
{ "value": "1", "displayName": "one" },
{ "value": "2", "displayName": "two" }
]
}
}
}
Read available select values
Available: 6.0+
Returns the values for a dynamic select field. Dynamic select values are not included in the standard metadata response, so this endpoint is required to retrieve them.
POST {baseurl}/service/fortesipm/node/read/metadata/selectvalues/{id}/{fieldName}/{nodeTypeName}
| Parameter | Type | Description |
|---|---|---|
id | URL | The ID of the top-level node (e.g. a project) that provides context for the select values |
fieldName | URL | The name of the select field |
nodeTypeName | URL | The node type the field belongs to |
Entries
Entry endpoints return time and cost entries associated with a location.
Read entry list
Available: 6.0+
Returns individual entries (hours, costs) for a given location.
POST {baseurl}/service/fortesipm/entry/read/list/{id}
| Parameter | Type | Description |
|---|---|---|
id | URL | The location node ID |
POST body parameters:
| Parameter | Required | Description |
|---|---|---|
viewXml | Yes | View definition XML with filter and layout |
The viewXml supports filter operators, sorting via sortfield and sortdirection attributes on the <filter> element, and a completelist flag.
Example:
{
"viewXml": "<listing id='0'><filter sortfield='Resource,Type,PeriodStartdate' sortdirection='ASC,ASC,ASC' completelist='true'><ValueType operator='in' filterValues='Available,Allocation' /><PeriodStartdate operator='bigger' filterValues='today' /></filter><layout><header /><row><cell name='Resource' /><cell name='Type' /><cell name='PeriodStartdate' /><cell name='Hours' /></row></layout></listing>"
}
Read entry timeline
Available: 6.0+
Groups entries into time periods. Extend the viewXml with a <timeline> section to define the period structure.
POST {baseurl}/service/fortesipm/entry/read/timeline/{id}
| Parameter | Type | Description |
|---|---|---|
id | URL | The location node ID |
Add a <timeline> section to the viewXml:
<timeline>
<startdate>today</startdate>
<intervals>5</intervals>
<scale>weeks</scale>
</timeline>
scale value | Description |
|---|---|
days | One column per day |
weeks | One column per week |
months | One column per month |
To return pivoted output, add doPivoting='true' to the <layout> element. Pivot columns are returned dynamically as PVT{date} fields in the response.
Documents
Document endpoints manage file attachments and links associated with nodes.
Add document
Available: 8.0.3+
Attaches a document, link, or file to a node. The request must use multipart content type. Standard JSON content type is not used for this endpoint.
POST {baseurl}/service/fortesipm/node/create/instance/{id}/Document
| Parameter | Type | Description |
|---|---|---|
id | URL | The ID of the node to attach the document to |
The multipart request body contains two parts:
| Part | Type | Content |
|---|---|---|
| Parameters | text | JSON object with FileType, Name, and type-specific fields |
| File | file | UU-encoded file content (only for actual file uploads) |
FileType options:
| FileType | Purpose | Additional required fields |
|---|---|---|
internaldocument | Link to an existing document in the toolbox | InternalLinkID |
externaldocumentlink | Link to an external REST service | ExternalDocumentLink |
hyperlink | Generic URL link | Url |
MIME type (e.g. application/msword) | Upload a file | ActualFileName |
Supported MIME types for file upload:
| MIME type | Extension |
|---|---|
application/msword | .doc |
application/vnd.openxmlformats-officedocument.wordprocessingml.document | .docx |
application/vnd.ms-excel | .xls |
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet | .xlsx |
application/vnd.ms-powerpoint | .ppt |
application/vnd.openxmlformats-officedocument.presentationml.presentation | .pptx |
application/octet-stream | Other file types |
Example: Add a hyperlink:
{
"FileType": "hyperlink",
"Name": "Example Link",
"Url": "http://www.example.com/link?par1=test"
}
Update document
Available: 8.0.3+
Updates an existing document attachment. Uses the same multipart structure as Add document.
POST {baseurl}/service/fortesipm/node/update/instance/{id}
| Parameter | Type | Description |
|---|---|---|
id | URL | The ID of the document node (not the parent location) |
Messages
Send notification message
Available: 7.0+
Sends a message at the specified location. The authenticated user is automatically added as a mention.
POST {baseurl}/service/fortesipm/message/send/{id}
| Parameter | Type | Description |
|---|---|---|
id | URL | The location node ID where the message is posted |
POST body parameters:
| Parameter | Required | Description |
|---|---|---|
message | Yes | The message text. HTML is supported, including <a href> links. |
mentions | No | Array of user or resource IDs. The message appears on their homepage. |
hashtags | No | Array of folder or node IDs. The message appears at those locations. |
Example:
{
"message": "<p>Test message that may contain HTML</p>",
"mentions": ["8129701", "221345"],
"hashtags": ["563655"]
}
Import and export
Import and export endpoints execute tasks that have been pre-configured in the Principal Toolbox. Administrator rights are required for both endpoints. See Imports & Exports for guidance on configuring tasks.
Execute import task
Available: 8.0.1+
Executes a configured import task with the provided data. Only CSV format is supported via this endpoint.
POST {baseurl}/service/fortesipm/integration/import/execute/{id}
| Parameter | Type | Description |
|---|---|---|
id | URL | The ID of the import task to execute |
The request body is raw CSV data, not JSON:
"column1";"column2"
"value1a";"value1b"
"value2a";"value2b"
A successful response includes a details.log field with the import result, and errors and warnings boolean flags.
Execute export task
Available: 8.0.1+
Executes a configured export task and returns the export data directly (typically CSV).
GET {baseurl}/service/fortesipm/integration/export/execute/{id}
| Parameter | Type | Description |
|---|---|---|
id | URL | The ID of the export task to execute |
No POST body parameters are required.
User administration
User administration endpoints require administrator rights. Passwords cannot be set or changed via the REST API.
Create user
Available: 8.0.1+
Creates a new user account.
POST {baseurl}/service/fortesipm/user/create/instance
POST body parameters:
| Parameter | Required | Description |
|---|---|---|
UserName | Yes | Login username |
Lastname | Yes | Last name |
Email | Yes | Email address |
IsGroup | No | Set to true to create a user group |
Initials | No | User initials |
Firstname | No | First name |
ResourceFolderID | No | Creates the user from an existing resource |
SendEmail | No | Set to true to send an invitation email |
EmailRemarks | No | Custom text to include in the invitation email |
Note: The
Passwdfield is not accepted. To allow a user to log in, useSendEmail: trueto trigger an invitation email.
Update user
Available: 8.0.1+
Updates an existing user account. Include only the fields to change.
Update by user ID:
POST {baseurl}/service/fortesipm/user/update/instance/{id}
Update by field value:
POST {baseurl}/service/fortesipm/user/update/instance/{fieldname}/{fieldvalue}
| Parameter | Type | Description |
|---|---|---|
id | URL | The user node ID |
fieldname | URL | The field to match on (e.g. Custom1) |
fieldvalue | URL | The value to match |
Example: update by custom field:
POST {baseurl}/service/fortesipm/user/update/instance/Custom1/jsmith98
Request body:
{
"Initials": "J.",
"Firstname": "Jeremiah"
}
Note: Ensure the field value used for matching is unique across all users.
Delete user (inactivate)
Available: 8.0.1+
Inactivates a user account. The user's data is preserved.
Delete by user ID:
GET {baseurl}/service/fortesipm/user/delete/instance/{id}
Delete by field value:
GET {baseurl}/service/fortesipm/user/delete/instance/{fieldname}/{fieldvalue}
| Parameter | Type | Description |
|---|---|---|
id | URL | The user node ID |
fieldname | URL | The field to match on |
fieldvalue | URL | The value to match |
Event triggers
Event triggers invoke external systems automatically when certain actions occur in the Principal Toolbox. Configuration requires a system setting to be added by a system administrator.
Project creation webhook
Available: 8.0.1+
Triggers an HTTP POST to a configured URL when a project is created successfully.
Add the following system setting to enable this webhook:
<Setting>
<SettingName>CreateProjectWebhookUrl</SettingName>
<SettingValue>http://mywebhook:8080/something/somethingelse</SettingValue>
</Setting>
When a project is created, the Principal Toolbox sends the following body to the configured URL:
{
"id": 123456
}
Where id is the ID of the newly created project. Use Read instance to retrieve full project details.
The webhook response is ignored but logged on failure. Logs are accessible to system administrators.
Note: HTTPS is only supported for certificates trusted by the JVM/Tomcat. For HTTP basic authentication, include credentials in the URL:
http://username:password@host.
External document generation
Available: 8.0.3+
Triggers an HTTP POST when a user generates an external document from the automated reports section.
Add the following system setting to enable this trigger:
<Setting>
<SettingName>EnableExternalDocumentLinks</SettingName>
<SettingValue>true</SettingValue>
</Setting>
The Principal Toolbox sends the following body to the external service:
{
"id": 123456,
"personID": 123344
}
Where id is the location of the report and personID is the ID of the user who triggered the action.
Node types reference
The table below lists all available node types with their internal IDs, general display names, and version availability.
| Name | ID | Display name | Available from | Removed in |
|---|---|---|---|---|
| Benefit | 720 | Benefit | 7.0+ | |
| BudgetType | 8215 | Financial category | ||
| CurrencyRate | 77 | Currency rates | ||
| DependencyRelation | 5700 | Dependency | ||
| DiscussionLog | 29 | Discussion item | ||
| Entry | 100 | Generic entry | 6.0+ | 9.5 |
| ExportTask | 21 | Export task | ||
| History | 10 | History log | ||
| Idea | 4901 | Idea | 7.0+ | |
| ImportTask | 23 | Import task | ||
| KnowledgeRepository | 4 | Documents & knowledge folder | ||
| Message | 8003 | Message | 7.0+ | |
| NonProjectActivity | 5502 | Non project activity | ||
| NonProjectActivitySet | 5500 | Non project activity set | ||
| NonProjectCategory | 5501 | Non project category | ||
| Order | 6061 | Order | 7.5+ | |
| OrganizationalUnit | 500 | Organisational unit | 8.0+ | |
| P2Action | 6041 | Action | ||
| P2Change | 6031 | Change | ||
| P2Issue | 6001 | Issue | ||
| P2Lessonlearned | 6051 | Lessons learned | ||
| P2Product | 5302 | Classic project product | 9.0 | |
| P2Program | 5100 | Classic MSP programme folder | 9.0 | |
| P2ProgramProject | 5110 | Classic MSP programme project | 9.0 | |
| P2ProgramTemplate | 5111 | Classic MSP programme model | 9.0 | |
| P2Project | 5000 | Project | ||
| P2ProjectTemplate | 5002 | Project model | ||
| P2Quality | 6021 | Quality review | ||
| P2Risk | 6011 | Risk | ||
| P2Stage | 5301 | Classic project stage | 9.0 | |
| Person | 3 | User account | ||
| PlanItem | 5602 | Plan item | ||
| Portfolio | 701 | Portfolio | ||
| PortfolioDashboard | 711 | Custom dashboard | ||
| PortfolioModel | 703 | Portfolio model | ||
| ProgramProject | 4910 | Programme | 8.0+ | |
| ProgramProjectModel | 4911 | Programme model | 8.0+ | |
| ProjectReport | 5003 | Portfolio item | ||
| ProjectResource | 8017 | Project resource | ||
| SavedProjectReport | 5006 | Saved portfolio item | ||
| Scenario | 730 | Saved portfolio scenario | ||
| Skill | 16 | Skill | ||
| TimeRegistrationConfiguration | 5520 | Time entry configuration | ||
| Timesheet | 81 | Time sheet | ||
| TimesheetRow | 84 | Time sheet row | ||
| URLFolder | 400 | Link (url) | ||
| UserGroup | 30 | User group | 7.5+ | |
| Workpackage | 5303 | Classic project work package | 9.0 |
Node relations
Relations define how nodes are connected in the object tree. The relation type is used in endpoints such as Read recursive.
Normal relation: used for structural containment:
P2Project → P2Issue, P2Risk, P2Quality, P2Change, P2Action, P2Lessonlearned, Order, KnowledgeRepository → Document, Entry
Planning relation: used for Gantt/plan hierarchy:
P2Project → PlanItem (hierarchical)
Breakdown relation: used for product breakdown structure:
P2Project → PlanItem (hierarchical)
Best practices
- Store the
authTokensecurely and reuse it across requests. If the session expires, log in again to obtain a new token. - Always set the
Content-Type: Application/JSON;charset=UTF-8header on all JSON requests. - Strip XML of tabs, newlines, and comments before embedding it as a value in a JSON parameter.
- Use
fieldNameswhen you only need specific fields. This reduces response payload size and improves performance. - Use the
/node/read/metadata/{nodeTypeName}endpoint to discover field names and types before building integrations. - When matching users via a custom field, ensure the field value is unique across all users.
- Test all calls with a tool such as Postman before integrating them into your application.
- Import and export tasks must be configured manually in the Principal Toolbox before they can be executed via the API. See Imports & Exports.
- Passwords cannot be set via the REST API. Use
SendEmail: truewhen creating or updating users to trigger an invitation email. - Use the newer
node/update/instance/{nodeTypeName}/{id}endpoint (available from 8.5) rather than the deprecated form withoutnodeTypeName.
FAQ
How do I log in via the REST API?
Send a POST to {baseurl}/service/fortesipm/login with {"username": "...", "password": "..."}. A successful response includes an authToken. Pass this token in the PTB-Rest-Authorization: Basic {TOKEN} header on all subsequent calls.
Which HTTP method does each endpoint use?
Most endpoints use POST. Read instance and all delete calls use GET. Check the method listed for each endpoint in this article.
What does a 400 response mean?
The response body contains a RestStatus object with status.code and message. Code 102 indicates a general failure. Code 502 indicates a lease failure: the object is locked by another user.
How do I filter results in a list call?
Use the viewXml POST parameter with a <listing> XML structure containing a <filter> element. Strip all tabs and newlines from the XML before encoding it as a JSON string.
Can I set a password via the REST API?
No. The Passwd field is always ignored. Use SendEmail: true when creating or updating a user to send an invitation email.
How do I find the correct field names for a node type?
Call /node/read/metadata/{nodeTypeName} to retrieve all field names, types, and display names for a given node type.
Why am I receiving a Lease Failure (502)?
Another user has locked the object. The response details object includes lockedBy, lockedOn, and leaseTime to identify who holds the lock.
Which version does my endpoint require?
Each endpoint in this article lists its minimum version under "Available". Most endpoints are available from version 6.0 onwards. The node/update/instance/{nodeTypeName}/{id} form requires version 8.5+.
Can I create a node anywhere in the tree? No. Not every node type can be created at every location. Refer to the Node relations section and the node type table to understand valid parent-child relationships.
Need more support?
Contact your Fortes Change Cloud administrator or reach out to Fortes Support for assistance with API configuration and integration.