Migrating from API V2 to V3
What changes with API V3 and how to move your integrations and automations. API V2 remains available until the end of 2028.
Preview: this documents PQFORCE 4.26.6, which has not been released yet.
Audience — developers who consume the PQFORCE API today and want to move to generation V3:
- Client developers building a user interface or a desktop/mobile app on the REST API.
- JavaScript developers writing server-side automations (
Pqf.*inside a PQFORCE JavaScript source). - API / integration developers connecting a third-party system through the public API and a bearer token.
Scope — this guide covers only endpoints that are publicly available: the REST API (client and public API) and the JavaScript API. Endpoints reserved for the PQFORCE browser client are out of scope and are not listed. V2 endpoints that were already maintenance-only are included, because tooling built on them needs a successor too; their tables say so, and they need maintenance authentication rather than a bearer token.
Status — API V3 is complete. As of PQFORCE 4.26.6, every publicly available V2 endpoint either has a V3 successor or is retired; none is waiting for migration. This guide describes that state.
Reference documentation — this guide tells you what to change. The exact syntax, parameters, permissions and data contracts of every V3 endpoint are in the API V3 reference documentation and in the machine-readable definitions described in section 3.
1. Why migrate, and how much time you have
API V3 is the generation that all new PQFORCE functionality targets. It is not a re-packaging of V2: it introduces sorting, bulk reads, object identifications, version timelines, a waste bin, and a consistent naming and permission model. Capabilities added from now on appear in V3 only.
API V2 remains available and supported. Every deprecated V2 endpoint carries a note naming its successor and the sentence “will be discontinued at end of 2028”. Treat that as the planning horizon: V2 is switched off at the end of 2028, and everything that only works because a V2 compatibility rule exists stops working with it.
At 4.26.6, 100 % of the relevant V2 surface has a V3 successor — every endpoint that is not retired. A full migration is therefore possible for every module; section 2.5 has the per-module picture. You do not have to move everything at once: V2 and V3 can be called side by side, in the same integration and even in the same JavaScript automation, so migrating module by module is expected and fully supported.
2. How a V2 endpoint reaches V3
Every publicly available V2 endpoint is in exactly one of three states: redirected, reimplemented or retired. The fourth state, not yet in V3, is empty.
2.1 Redirected — 205 endpoints
The V2 endpoint has a V3 successor with an identical signature: same parameters, same request body, same response
body. Calling the V2 URL answers 307 Temporary Redirect with the V3 URL in the Location header.
- REST: your HTTP client must follow redirects. Note that
307(unlike301/302) preserves the method and the body, so a redirectedPUTorPOSTis re-sent unchanged — but only if your client library is configured to follow redirects for those methods. Many are not by default. - Once redirected, you are talking to V3. The response you get is a genuine V3 response. Where V2 and V3 disagree on a value — most notably the work-item object type, see section 6 — you receive the V3 spelling.
- JavaScript: there is no HTTP layer, so there is no redirect. The V2 function calls the V3 implementation directly and is marked deprecated. Behaviour is already V3 behaviour.
- What to do: switch the URL (or the function name) at your convenience. Nothing else changes. Do it before the end of 2028.
2.2 Reimplemented — 521 endpoints
The V2 endpoint has a V3 successor, but the call differs: a renamed endpoint, a different parameter list, a different request or response body, or a combination. There is no redirect — the V2 URL keeps serving the V2 behaviour until V2 is switched off.
What to do: rewrite the call. Section 10 names the successor and says what differs; the reference documentation has the details.
2.3 Retired — 51 endpoints
No V3 successor, by design: the functionality moved elsewhere, was replaced by a general mechanism, or is
discontinued. These endpoints disappear when V2 does. Section 8 lists the whole-module cases; section 10 lists
them per module with the advice from their deprecation note. One of them, PM getProjectScenarioChangesTimeline,
is retired only for now: its V3 successor follows with the Allocation 2.0 feature.
2.4 Not yet in V3 — none
No V2 endpoint is waiting for migration any more. The migration is complete.
2.5 Per-module readiness
| Module | Scope | Redirected | Reimplemented | Retired | Not yet in V3 |
|---|---|---|---|---|---|
| ACM | Access control, users, tokens, single sign-on | 17 | 41 | 2 | 0 |
| ACT | Actual times and presences | 8 | 19 | 7 | 0 |
| ALC | Allocations and capacity planning | 3 | 30 | 1 | 0 |
| ATM | Automation (JavaScript sources and triggers) | 15 | 5 | 0 | 0 |
| CHT | Charts | 0 | 2 | 0 | 0 |
| CLF | Client framework (cockpit widgets, stores, translations) | 18 | 6 | 1 | 0 |
| CLS | Classification schemes | 1 | 4 | 0 | 0 |
| DOC | Legacy document exports | 0 | 0 | 8 | 0 |
| DPO | Disposition views | 1 | 0 | 8 | 0 |
| EXP | Exports | 3 | 4 | 0 | 0 |
| FCO | Financial controlling (costs, budgets, currencies) | 14 | 63 | 0 | 0 |
| LCY | Lifecycles | 7 | 27 | 0 | 0 |
| LIC | Licensing | 0 | 5 | 0 | 0 |
| MAIN | Server information and session start | 3 | 3 | 0 | 0 |
| MSG | Messages, forwarding rules and mail | 7 | 9 | 0 | 0 |
| MTG | Meetings | 8 | 9 | 1 | 0 |
| NAV | Navigation and search | 0 | 2 | 8 | 0 |
| PF | Platform (relations, attachments, properties, enums, icons) | 29 | 53 | 8 | 0 |
| PI | Project items | 3 | 7 | 0 | 0 |
| PM | Project management (projects, portfolios, reports, scenarios, work items) | 43 | 133 | 3 | 0 |
| RES | Resources, resource links, holidays and availabilities | 11 | 46 | 4 | 0 |
| RSK | Risks | 1 | 14 | 0 | 0 |
| STG | Strategy | 12 | 30 | 0 | 0 |
| TDP | External (third-party) object references | 1 | 9 | 0 | 0 |
| Total | 205 | 521 | 51 | 0 |
Fully migrated: ACM, ACT, ALC, ATM, CHT, CLF, CLS, EXP, FCO, LCY, LIC, MAIN, MSG, MTG, PF, PI, PM, RES, RSK, STG, TDP. Retired outright: DOC, DPO, NAV.
3. New machine-readable definitions
Do not port a generated client by hand. Regenerate it from the V3 definitions.
3.1 OpenAPI
| V2 | V3 | |
|---|---|---|
| Standard | OpenAPI 3.0.3 | OpenAPI 3.2.0 |
| JSON | GET /API/ |
GET /API/ |
| YAML | GET /API/ |
GET /API/ |
Note that the V3 URL carries no standard-version segment — there is no /320/ in it.
Both accept a modules filter to keep the file small enough for tooling that struggles with the full
description: ?modules=pm, or ?modules="pm","fco" for several. Replace the host with your own instance's host.
Only endpoints reachable from the public API appear in the OpenAPI description. Endpoints available exclusively inside the JavaScript sandbox are documented in the TypeScript definition instead.
3.2 TypeScript definitions — new in V3
GET /API/V3/MAIN/ApiDescription/TypeScript
There is no V2 counterpart: this is new. It declares the whole JavaScript surface — Pqf, PqfV2 and PqfV3
namespaces, one function per endpoint (with one overload per omitted trailing optional parameter), and every data
contract as an interface. Contract inheritance is preserved as extends, enum contracts become string enums, and
every nullable member is typed T | null.
Point your editor at it and you get completion and type checking while writing a PQFORCE automation. It requires the JavaScript licence feature, like the automations themselves.
3.3 Assertions are not in the schema
Many V3 parameters and body members carry an assertion — a length, a range, a regular expression, an array
bound. Assertions are documentation: they are deliberately not expressed as constraints in the OpenAPI schema or
in the generated TypeScript types, because they would not survive most code generators intact. Validate against
them yourself; a violation is answered with 422 before the request is processed.
4. What does not change
Do not spend migration effort on these — they are identical in V3.
- The four access kinds and their authentication: session cookie (plus
Csrf-TokenforPUT/POST/DELETE) for the client API,Authorization: Bearerfor the public API, certificate and challenge headers for the maintenance API, and the in-process JavaScript API. - Tokens. An API token created and authorized for V2 works for V3. There is no separate V3 token.
- The tenant alias and the way it enters the URL.
Accept-Languagefor language andX-Timezonefor time zone.pf.Reference— still{ type, id }, with the same meaning.- Array parameter encoding — a JSON array without the enclosing brackets. One value may be written bare
(
sort=name), several must be quoted and comma-separated (sort="name:desc","code"). V3 additionally accepts the fully bracketed form (sort=["name:desc","code"]). - HTML sanitizing. Any string containing
<,>or&is treated as HTML and must be HTML-encoded on the way in and decoded on the way out, unless the member is explicitly marked as not sanitized. - The error-code concept. Responses carry coded references, not messages; the four-character code identifies the log entry.
5. Concepts that changed
5.1 Endpoint naming and URL shape
V3 applies one naming scheme across all modules, so an endpoint you have never seen is usually guessable.
| Purpose | Name | URL |
|---|---|---|
| Read one object | get<Object> |
GET /API/ |
| Read several objects | get<Objects> |
GET /API/ |
| Read all objects (as references) | getAll<Objects> |
GET /API/ |
| Read a filtered set | get<Objects>By<Discriminator> |
GET /API/V3/<MOD>/… |
| Create or update one object | put<Object> |
PUT /API/ |
| Create with a new ID | add<Object> |
POST /API/V3/<MOD>/…/Add |
| Delete | del<Object> |
DELETE /API/ |
| Display data only | get<Object>Identification(s) |
GET /API/ |
| Version history | get<Object>Timeline, get<Object>Version |
…/:id/Timeline, …/:id/Version/:versionId |
| Waste bin | getRecentlyDeleted<Objects>, undel<Object> |
…/, …/:id/Undelete |
Two consequences for readers of V2 code:
- The plural URL segment means "several by ID", not "all". V2's
GET /API/V2/PM/Projectsreturned every project; V3'sGET /API/returns the ones you name, andV3/ PM/ Projects/ :projectIds GET /API/V3/PM/Projectsreturns references to all of them (section 5.2). - A sub-collection is named after the relationship, with
/Addappended for the adder — for exampleGET …/SubWorkItemsandPOST …/SubWorkItems/Add.
The same name can mean something different. Because V3 reserves the plural for "several by ID", a number of V2 names survive into V3 with a different meaning:
pm.getProjects,acm.getUsers,mtg.getMeetings,stg.getStrategies,pi.getProjectItemTypesand others returned everything in V2 and now return the ones you name. A call that compiles and returns200may therefore return the wrong thing. Check every plural getter against section 10 rather than assuming the name carried its meaning across.
Where a module's V2 vocabulary was inconsistent, V3 renamed it. The largest case is the external-reference module (TDP), where four V2 concepts collapse into two; see section 10.
5.2 References first, details second — and how you page
This is the single most important change for anything that shows a list.
V2 offered unbounded "give me everything, in full" endpoints. GET /API/V2/PM/Projects returned a complete
Project object for every project the user may see. That response grows with the tenant, cannot be ordered, and
cannot be split.
V3 has no such endpoint. The pattern is two steps:
getAll<Objects>returns a cheap, orderable list of references. Of the 45getAll…endpoints, 20 return a plainpf.Reference(type+id), 14 return a reference plus its parent (pf.ReferenceWithParent) or its parent chain (pf.ReferenceWithParents), and the remainder return a small module-specific reference type. The list is filtered by permission — you only see what you are allowed to see.get<Objects>/:idsreads the details for a slice of that list, up topqforce.performance.bulk.maxIDs per call — a configured limit whose default is 100. Read the value your instance uses rather than hard-coding it (section 5.13).
That is the paging mechanism. There is no offset/limit on the detail read: you own the reference list, so you
decide which slice to fetch, in which order, and how far to scroll.
GET /API/V3/PM/Projects?sort="name"
-> [ {type:"Project", id:"…A"}, {type:"Project", id:"…B"}, … ] (all, ordered, cheap)
GET /API/V3/PM/Projects/"…A","…B"
-> [ {…full project A…}, {…full project B…} ] (page 1, max 100 IDs)
If all you need is a label, an icon or a code — a picker, a breadcrumb, a tooltip — do not read the full object. Use the identification endpoints of section 5.5 instead; they are a fraction of the payload.
5.3 Bulk endpoints and partial success
Every get<Objects>/:ids endpoint, and every other endpoint taking an array of IDs, is a bulk endpoint. Two rules
matter:
- Permission is evaluated per element. Elements the user may not touch are dropped, and the call still
succeeds for the rest. A bulk read with one forbidden ID returns
200and a shorter array — not403. - Per-element outcomes are reported in the
X-Detail-Codesresponse header where the endpoint provides them, as comma-separated integers using the same values as HTTP status codes. Read it when you need to know which element failed and why. The overall status code follows the "partial success is success" rule: if any element succeeded, the call succeeded.
Because elements can be dropped, never assume the result array is the same length as the ID array, or in the
same order. Match results back to your input by the id in each element, not by position.
X-Detail-Codes is not restricted to reads or to ID arrays, either: a write whose request body has parts that
are written independently reports one status per part, in the order the body lists them.
alc.updateResourceShiftPlan is the case to know — it answers one code per slot of the planning matrix, 400
for every slot its update modes refused to write (section 10, ALC).
The bulk maximum (pqforce.performance.bulk.max, default 100) is enforced as an assertion, so exceeding it is
rejected with 422 rather than truncated. It is configured per instance — read it at runtime (section 5.13).
5.4 Sorting — new in V3
V2 had no sort parameter anywhere. In V3, 128 endpoints — the getAll…, get…Of… and get…By… lists and most other lists of references — take an
optional sort array.
- One element per criterion, applied in order:
name,name:ascorname:desc(ascending is the default). - Up to
pqforce.performance.sort.maxcriteria per request — a configured limit whose default is 8, readable at runtime (section 5.13). - The properties allowed on a given endpoint are enumerated in that endpoint's
sortdescription, as “Possible properties: …”. The common set istype,id,name,code,description,color,createdAt,modifiedAt, and individual endpoints add their own (sortIndex,validityStart, …). - Dynamic (tenant-configured) properties can be sorted on too, by their key, when their semantics are sortable: string, UUID, integer, long, double, boolean, duration, point in time, day, currency amount, URI and colour.
- An unknown or malformed criterion is rejected with
422.
GET /API/V3/PM/Projects?sort="code","name:desc"
If you sorted lists client-side in V2 because there was no alternative, this is the first thing to delete.
5.5 Identifications — display data without the object
Object families that V3 models as a full CRUD family expose …/:id/Identification (one object) and
…/:ids/Identification on the plural route (several) — 40 such endpoints today. The payload is
pf.Identification: type, id, name, code, description, color, iconRef. Nothing else — no dynamic
properties, no timing information, no relations.
The bulk variant takes an optional deleted flag and answers with pf.IdentificationExtended, which adds a
deleted member — so a stale reference in your own data can be labelled rather than silently dropped.
Use it for anything that renders a reference: pickers, link labels, breadcrumbs, and — importantly — resolving
the createdBy / modifiedBy references described in section 5.10.
5.6 Version history — Timeline and Version
For versioned object types, V3 exposes history uniformly:
GET …/— the list of versions in a period, at a chosen calendar granularity.:id/ Timeline?limit=&from=&until=&granularity= GET …/:id/Version/:versionId— one historic version, in the same contract as the current one.
V2 exposed history through per-module get…History endpoints with per-module response shapes. Those either
redirect or are reimplemented as the two endpoints above; section 10 says which.
5.7 Waste bin — Deleted/Recently and Undelete
Where an object type supports it, V3 offers GET …/ and
POST …/<Object>/:id/Undelete. Both require the undelete licence feature and the corresponding permission, and
both are limited to the tenant's undelete window — an object deleted longer ago than the window is neither listed
nor restorable (404).
The window is part of the tenant's licence, not a fixed number of days. Read it with
GET /API/V3/PF/UndeleteLimit -> PF.UndeleteLimit { days }
which needs the same undelete licence feature and answers 402 without it. Do not assume a default: use the
value to decide whether offering "restore" to your user makes sense at all.
5.8 Creating objects — Add with basic field initializers
In V2, creating an object was usually two calls: POST …/Add returned a reference to a default-named object, and
you then issued a PUT to give it a name, a code, a description, a colour and an icon.
In V3, 31 of the 41 add… endpoints accept those basics as optional query parameters, in a consistent order:
POST /API/V3/PM/Project/:projectId/Scenarios/Add?name=Baseline&code=BL&color=%23336699
POST /API/V3/MTG/MeetingGroups/Add?name=Steering%20board&iconRef=mdi:account-group
POST /API/V3/RES/Resource/:parentResourceId/AddChild?linkTypeId=…&name=New%20team
| Parameter | Meaning |
|---|---|
name |
The name of the new object. Omit it and the object gets a localized default name. |
code |
Short code, at most 32 characters. |
description |
Descriptive text, may contain HTML. |
color |
A colour value. |
iconRef |
The icon: /images/…png on the server, /API/V3/PF/Icon/<id> for an uploaded icon, a data:image/…;base64,… inline image, or mdi:<name> for a Material Design icon. |
Individual endpoints add their own initializers next to these — start / end, sortIndex, periodStart /
periodEnd, currency, and the copy… flags that control what is carried over when creating from a template.
The return value is unchanged from V2: a pf.Reference to the new object, with 201 Created. So the migration is
a simplification — fold your follow-up PUT into the POST, and keep the PUT only for the fields the Add
endpoint does not offer.
One naming note: the icon member is iconRef throughout V3. If your V2 code still writes an imageUrl member on
one of the few contracts that had one, rename it.
5.9 PUT does not always create
In V3, PUT /…/<Object>/:id updates an existing object, and only creates one where the endpoint documents that
it may. Where it may not, a PUT to an unknown ID answers 404, and the object has to be created through the
module's POST …/Add endpoint. The permission checked is UPDATE when the object exists and CREATE when it
does not.
If your V2 integration invents its own IDs and creates objects by PUT, check each endpoint before relying on it.
5.10 Data contracts — a cleaner hierarchy
The generic base contracts were rebuilt. The change is small in size and easy to miss in effect.
| V2 | V3 | Members |
|---|---|---|
pf.Reference |
pf.Reference |
type, id — unchanged |
pf.Item |
pf.Identification |
name, code, description, color, iconRef |
pf.VersionedReference |
pf.VersionReference / pf.VersionedReference |
version; plus historic, createdAt, createdBy, modifiedAt, modifiedBy |
pf.VersionedItem |
pf.BasicObject |
versioned reference + the five identification members |
pf.VersionedItemWithProperties |
pf.CustomizedObject |
pf.BasicObject + properties |
Three differences bite in practice:
createdByandmodifiedByare now bare references. In V2 they were full items, somodifiedBy.namewas there for the taking. In V3 they arepf.Reference—typeandidonly. Resolve the name through the user's identification endpoint, and cache it: in a list of 100 rows, one bulk identification call replaces 100 lookups.- Validity left the generic contract. V2's
pf.ItemcarriedvalidityStartandvalidityUntilfor every object, whether or not it had a validity period. In V3 validity is declared only on the objects that actually have one, under the same namesvalidityStartandvalidityUntil. - Translated variants are explicit. Where a contract exists in a translated form, its
name,descriptionandiconRefare arrays of per-language values rather than a single resolved string. The untranslated contract still resolves to the request'sAccept-Language.
5.11 Assertions and 422
Assertions (section 3.3) are pervasive in V3 — roughly five times as many declared constraints as in V2. The practical effect is that malformed input is rejected earlier and more consistently:
- A value that violates its assertion — a code longer than 32 characters, a sort criterion that is not a known
property, a bulk array over the maximum, a malformed icon reference — is answered with
422, before any business logic runs. - A missing mandatory parameter, or one that cannot be parsed into its declared type at all, is answered with
400. - A body that is not valid JSON, or does not match the declared structure, is answered with
422.
Read the Assertion column in the reference documentation for each parameter you send, and validate on your side. It is cheaper than a round trip, and the server deliberately does not tell you which rule you broke.
5.12 Return codes and response headers
The codes V3 uses:
| Code | When |
|---|---|
200 |
Request succeeded |
201 |
A new object was created (all add… endpoints, and a creating PUT) |
202 |
Accepted, processing not yet complete |
304 |
Cached copy still valid (static requests with If-None-Match) |
307 |
A deprecated or alias URL; the effective URL is in Location. This is what a redirected V2 endpoint answers. |
308 |
As 307, permanently |
400 |
Missing or unparsable parameter or header |
401 |
Authentication failed |
402 |
A licensing restriction: the endpoint, an optional parameter, or an expired licence |
403 |
No permission for the endpoint or the object (also returned when the object does not exist) |
404 |
Unknown endpoint, or an object that does not exist or was deleted |
415 |
Missing or wrong request body type |
422 |
Assertion violation, malformed body, or a sanitizer violation |
429 |
Too many requests in parallel |
500 |
Server-side failure |
503 |
Server is in maintenance mode |
Three headers to handle that you may have ignored in V2:
Location— on307/308. Following it is mandatory for redirected V2 endpoints (section 2.1).X-Detail-Codes— per-element results of a bulk call (section 5.3).Deprecation— present on every response from a deprecated endpoint, or from a call that used a deprecated parameter. Log it. It is the cheapest early warning you will get, and it is how you find the V2 calls still hiding in your code. In the JavaScript API the equivalent is a warning in the JavaScript console.
Note 429: parallel requests are limited per token (and per user, per session, per address), and the limits are
configured per instance. An integration that fans out bulk reads should read its own ceiling and respect it
rather than rely on retries:
GET /API/V3/PF/Limits/MaxParallelRequests -> PF.ParallelRequestsLimit { maxParallel }
The endpoint reports the limit that applies to the caller as it is calling — the per-token limit when you
authenticate with a bearer token, the per-user limit otherwise — so a public-API integration and a browser
session get different answers from the same URL. Two things changed here from V2, and there is no redirect:
the URL segment is Limits, not Limitations, and the response member is maxParallel, not limit.
5.13 Read the limits, do not hard-code them
Every numeric limit quoted in this guide is a configured default. It can differ on a dedicated or on-premises instance, and it can change with a release — the defaults below are the base configuration layer, which every instance may override. Read the values at start-up and cache them for the lifetime of your process; do not compile them in.
There are three endpoints, because the limits come from three different places.
| What you need | Endpoint | Answers |
|---|---|---|
| A shared server setting | GET /API/ |
text/plain, the raw value; 404 for a key that is not published |
| Your own parallel-request ceiling | GET /API/ |
PF.ParallelRequestsLimit { maxParallel } |
| The tenant's undelete window | GET /API/V3/PF/UndeleteLimit |
PF.UndeleteLimit { days }; needs the undelete licence |
ServerConfig publishes a fixed set of keys — anything else answers 404, so it is not a way to read
arbitrary server configuration. The defaults below come from the base configuration layer; an instance may
override any of them, and a key it does not configure at all is not published — so a 404 on a key from this
list means "not configured on this instance", not "wrong key". The keys:
| Key | Default | What it limits |
|---|---|---|
pqforce.performance.bulk.max |
100 |
Elements in one bulk parameter array (sections 5.2, 5.3) |
pqforce.performance.sort.max |
8 |
Sort criteria per request (section 5.4) |
pqforce. |
20971520 |
Attachment upload size, in bytes |
pqforce. |
500 |
Projects in one Gantt chart |
pqforce.planningrange.from / .to |
-2 / 2 |
Years, relative to the current one, in which allocations may be planned |
pqforce.dayrange.from / .to |
-10 / 10 |
Years, relative to the current one, in which day-based planning is available |
pqforce.dayrange.max |
731 |
Days one request may be answered a slot per day for; a wider range is refused with 400 |
pqforce. |
— | The password rule, as a regular expression |
pqforce. |
— | The password rule in words, for display; one key per available language |
pqforce. / …Blacklist |
— | Accepted / rejected upload file extensions |
pqforce. / …Blacklist |
— | Accepted / rejected upload MIME types |
pqforce. |
— | Whether text bodies are content-checked |
pqforce. |
— | Whether JSON bodies are content-checked |
pqforce.website, pqforce.login, pqforce.support |
— | The instance's public web address, login service URL and support address |
Validate an upload against the extension, MIME and size keys before you send it, and the password rule before you submit a password — all three are rejections you can avoid entirely.
The two other limits are not ServerConfig keys, and that is deliberate: the parallel-request ceiling
depends on how you authenticate and the undelete window comes from the licence, so neither has one shared value
to publish. Use their own endpoints, above.
Do not confuse ServerConfig with Config. GET /API/ reads a setting the
whole instance shares and is read-only. GET /API/V3/PF/Config/:configId reads a tenant setting, addressed by
a known configuration ID rather than a dotted key, and has PUT and DELETE counterparts. Neither accepts an
arbitrary key: both answer 404 for an identifier they do not publish.
Inside a JavaScript automation the runtime limits are reachable without a request at all:
sandbox.remainingRuntimeMs() reports the time left in the current execution, against the configured
per-execution and hourly quotas.
Finally, check compatibility once at start-up with GET /API/V3/MAIN/Versions, which reports the server release
and the API version. All four of these calls belong in the same start-up step.
5.14 Change notifications over WebSocket
V2 had a single WebSocket, handed out by getNewWebSocketConnection (POST /API/V2/PF/WebSocket/Create) and
shared by the PQFORCE browser client and the public API. V3 splits it in two. The browser client gets a WebSocket of
its own, which is out of scope here. Integrations get a change-notification WebSocket, which is reserved for
public-API access, that is, for agents and interface components.
POST /API/V3/PF/ChangeNotification/CreateNew -> PF.WebSocketInfo { url, validUntil }
Call it, then open the returned URL — note the limited validity, so open it promptly and re-request when it
expires. The socket is effectively one-directional: the server does not accept messages (an empty {} is
tolerated), and sends JSON messages of two kinds:
| Message | Meaning |
|---|---|
{"sessionInfo": … } |
Sent once, describing the session |
{"dataChange": … } |
An object was created or changed: action, the object's own reference in data, and its parents in parent |
The V2 call redirects here. getNewWebSocketConnection answers 307 with ChangeNotification/CreateNew, so
the URL it returns now opens the change-notification WebSocket. This has two consequences for code that stays on
the V2 call:
- Bearer token only. With a session cookie, the redirect target answers
404. - Change notifications only. The socket sends
sessionInfoanddataChangeand nothing else. The concurrency messages of the V2 socket (featureConcurrency,accessConcurrency) are no longer sent, and thefeatureandaccessmessages a client used to send are no longer accepted.
If your integration currently polls a list endpoint on a timer, this is the change that removes the timer. Note that a notification tells you that an object changed; you still read the new state through the ordinary endpoints.
5.15 Dynamic properties — definition, presentation, and the order you read them in
Dynamic (tenant-configured) properties are the one area where V3 did not rename an endpoint but split a concept. Every V2 property call maps onto the new shape, so read this before you rewrite them; the endpoint-by-endpoint mapping is in the PF part of section 10.
One contract became two. V2's PropertyDefinition described in a single object both what a property is and
how a client shows it. V3 separates the two, because the first is a fact about the tenant's data model and the
second is one client's opinion about it:
V2 PropertyDefinition member |
V3 home | Why |
|---|---|---|
id, objectType, semantics |
PF.PropertyDefinition |
The property itself — shared by every client |
sortIndex, label, identifier, hint, constraint |
PF.PropertyPresentation |
How one client presents it |
PropertyPresentation extends PropertyDefinition and adds clientId, so a presentation still carries the
definition's members — you rarely need both calls to display something.
The client is part of the URL. Every V2 property endpoint has a presentation endpoint as its successor, and
the client is a path segment. Pass Client4, the PQFORCE browser client, to get what V2 returned: V2 read
the Client4 presentation internally and never told you.
V2 GET /API/V2/PF/ObjectType/Project/PropertyDefinitions
V3 GET /API/V3/PF/PropertyPresentations/OfClient/Client4/OfObjectType/Project
Writing is two calls, in order. putAllPropertyDefinitions replaces the definitions of an object type — a
definition missing from the list is deleted, and that fails as long as any client still presents it.
putAllPropertyPresentationsTranslated replaces what one client presents — every definition must already exist,
nothing is ever deleted, and a property missing from the list only loses this client's presentation. So create
definition first, presentation second; when removing, drop the presentation first and the definition after.
Both need the config-properties licence feature and the configuration permission, where V2 had one call.
Values became typed. V2's Property was two strings: a key and a value that you parsed yourself. In V3
value is PF.PropertyValue, a choice contract with one member per semantics — string, uuid, int, long,
double, bool, uuidArray, duration, datetime, date, currencyAmount, uri, color, json — and the
definition's semantics tells you which member is filled. key is the property definition's ID, now typed
uuid; it still carries the readable keys you know from V2. A property the object has no value for is present
with no value.
The default sorting of a live object's properties is by definition ID — not by sortIndex. This is the part
that silently breaks a port. On a live object — a project, a resource, a work item — the properties array is
ordered by property definition ID, ascending and stable. It cannot be ordered by sortIndex, because
sortIndex belongs to a client and an object body is the same for every client.
- This is a change, and it lands on V2 as well. Until the split,
sortIndexwas a member of the definition itself, and the shared definition list — the template from which every object'spropertiesarray is built — was ordered by it. Since the split that list is ordered by definition ID, and so is thepropertiesarray of every object, in V2 responses just as much as in V3: both read the same list. A V2 client that walks the array positionally againstgetPropertyDefinitionsis already reading the wrong property. Match by key. getPropertyDefinitionsitself still answers insortIndexorder — V2 serves it from theClient4presentation. What changed is the relationship between the two lists, not that endpoint.- In V3 the definition list and the object agree again.
getAllPropertyDefinitions(objectType)answers in definition-ID order — the same order as every object of that type, one entry per definition, element for element. - The display order is a separate call.
getAllPropertyPresentations(clientId, objectType)answers in that client'ssortIndexorder (ties broken by ID). Use it to lay out a form or a column set, and join it to the object'spropertiesby key — do not re-order the object's array to match, and do not assume the n-th property of an object is the n-th presentation. - Reading a single property never depends on either order:
getPropertyDefinition(definitionId)andgetPropertyPresentation(definitionId, clientId)address it directly.
Sorting objects by a property works on the same key (section 5.4). Pass a property definition ID in sort
and the comparison follows that property's declared semantics. Two rules are easy to miss: a dynamic property is
only sortable when the request concerns a single object type — with several types, only the fixed properties
are — and a value the caller may not READ is treated as empty, so those objects group at the start of an
ascending sort and at the end of a :desc one.
6. The work-item type: Phase becomes ProjectWorkItem
A node of the project work breakdown structure — what users call a task — is identified by an object type ID.
That ID used to be Phase, which collided with project-management methodology phases and matched nothing users
say. As of 4.26.6 the type is called ProjectWorkItem.
Which spelling you get depends on the endpoint's generation, not on your code:
| You call | You send and receive |
|---|---|
| An API V2 endpoint | Phase — unchanged, indefinitely, until V2 is switched off |
| An API V3 endpoint | ProjectWorkItem |
| A redirected V2 endpoint (section 2.1) | you may send Phase; the response is a V3 response and says ProjectWorkItem |
The server translates the old spelling inbound at the V2 boundary, which is what makes the change a low-impact upgrade. It is also why the change surfaces at the end of 2028: everything still relying on the translation breaks when V2 goes.
What to check in your own code:
- Type comparisons. Anywhere you compare an object type against the literal
"Phase", decide which generation the value came from. A V2 response legitimately saysPhase; a V3 response saysProjectWorkItem. Code that handles both should accept either. - Mixed-generation code paths. If one part of your integration reads through V2 and another writes through V3, do not pass a type value from one to the other unchanged.
- Stored type values. Configuration, filters, mappings or downstream tables that recorded
Phaseas text still sayPhase. They keep working while V2 lives. Plan to update them. - Deep links. Links that embed the object type and were created before 4.26.6 still carry
Phaseand still work, because the server accepts the old spelling. They stop working when V2 is retired — worth regenerating if you store PQFORCE deep links in another system. - Endpoint names. In the PM module several V3 endpoints were renamed to spell the object out in full:
moveWorkItem→moveProjectWorkItem,splitWorkItem→splitProjectWorkItem,copyWorkItemTree→copyProjectWorkItemTree,addWorkItemSubWorkItem→addProjectWorkItemSubWorkItem,getWorkItemSubWorkItems→getSubWorkItemsOfProjectWorkItem. The URLs are unchanged except for the sub-work-item pair, which is now…/SubWorkItemsand…/SubWorkItems/Add. The V2 names are untouched.
Note that this affects the type ID, not your data: permissions, lifecycle states, relations, documents, dynamic properties and backups are migrated by the upgrade itself.
7. The JavaScript API
7.1 Choosing a generation
Every JavaScript source has an API generation attribute. It decides what the root object Pqf points at:
- In a V2 source,
Pqf.*is the V2 API. - In a V3 source,
Pqf.*is the V3 API. PqfV2andPqfV3are always both available, in either kind of source.
That gives you two migration strategies:
- Gradual, inside a V2 source: leave the source on V2 and rewrite call sites one at a time to
PqfV3.…. The rest of the script keeps working. This is the low-risk route for a long script. - All at once: switch the source to V3 and change every
Pqf.…call that has moved. UsePqfV2.…explicitly for the few endpoints that are not migrated yet.
Either way, be explicit about the generation of any type value you move between the two — see section 6.
7.2 What changes in a call
- Renames are hard breaks. There is no redirect for a function name. Calling a V3 function by its old name fails with “not a function”. Section 10's tables are the rename list.
- Optional parameters are overloads. A V3 function is declared once per omitted trailing optional parameter.
You can omit trailing arguments, but to skip a middle one you pass
null. - Deprecated calls warn. Calling a deprecated endpoint writes a warning into the JavaScript console. Run your automations once and read the console — it is a free inventory of what still needs migrating.
- Errors are unchanged in shape. A failed request throws; the message starts with
#and a three-digit code matching the HTTP status codes of section 5.12.try … catchas before, and switch on the code. - Bulk calls behave as over HTTP. Elements you may not read are dropped from the result array. Match results
by
id, not by index.
7.3 Small but easy to miss
- UUID generation. V2's
clf.newUuidsendpoint is not available to public-API or JavaScript callers in V3. In a script useUuid.generate(), which needs no request at all. - HTML sanitizing. V2's
clf.sanitizeHtmlendpoint is retired; useHtml.sanitize(…), alongsideHtml.encode(…)/Html.decode(…). - Everything else in the sandbox is unchanged —
console,store,sandbox,Uuid,Html,JSON,Date,Math, and the optionalmomentlibrary. Storage keys stay per script. - Typed authoring. Pull the TypeScript definition of section 3.2 into your editor before you start rewriting; it catches renamed functions and changed parameter lists as you type.
8. End-of-life modules and functionality
Three whole modules and three groups of endpoints are retired rather than migrated. All of them keep working until the end of 2028.
8.1 DOC — legacy document exports (whole module retired)
All eight DOC endpoints — export configurations, export templates, available exports and the export request handler — are discontinued. Use the EXP module with JavaScript exports instead:
PUT /API/V3/EXP/JavaScriptExportDefinition/:id/WithTranslations putExportDefinitionTranslated
GET /API/V3/EXP/JavaScriptExportDefinitions getAllExportDefinitions
GET /API/V3/EXP/ObjectType/:objectType/JavaScriptExportDefinitions
getExportDefinitionsForObjectType
POST /API/V3/EXP/JavaScriptExport/:id/:objectType/:objectId handleJavaScriptExportRequest
POST /API/V3/EXP/JavaScriptExport/:id/:objectType/:objectId/WithSettings
handleJavaScriptExportRequestWithSettings
The EXP model is more capable: the export logic is a JavaScript automation you control, rather than a template
the server interprets. Note that the V3 export definitions are named JavaScriptExportDefinition in the URL and
are written through the translated variant, so a definition always carries its language versions.
8.2 DPO — disposition views (whole module retired)
The eight disposition-view endpoints — reading, creating, moving, deleting and reassigning dispatch items by
resource, and the absence-block view — have no V3 successor. The one exception is delWorkItem, which is
redirected to pm.delProjectWorkItem. Build the equivalent view from the PM work-item endpoints and the
allocation endpoints once ALC is migrated.
8.3 NAV — navigation and search (retired except the full text search)
Eight of the ten NAV endpoints are discontinued. getRootContext, getContext and getObject modelled the
tree navigation of the old browser client and go with it; getTypeInfos described the types behind that
navigation. The structured and member searches (findObjects, getMemberTextSearch, getMemberRangeSearch,
getMemberRegexSearch) are retired with them.
The exception is the full text search: getContextSearch and getSearch are replaced by nav.search
(POST /API/V3/NAV/Search?query=...). It searches all objects of all types known to the navigation, takes the
plain text query only (HTML in it is decoded), and returns PF.ReferenceWithParent — the object found and its
parent (none where that is a navigation-only entry), one entry per object — sorted with the usual sort parameter. There is no start object, no
type restriction and no regular expression; filter the result by type where you need one type only. Only
objects the caller may identify are returned, and navigation-only entries of the old client (modules, lists)
are not, since they are no objects of V3.
8.4 ACT — single-time-per-day endpoints (retired)
Seven endpoints that read, wrote or deleted the project time or the project-and-task time of a resource for a day are discontinued, because a resource may book more than one time entry per project, task and day — so these endpoints could never represent the data faithfully.
Move to the time-actual family, which models the real cardinality. It is in V3 now, as a full object family
under the resource that booked the time: getResourceProjectTimeActual, putResourceProjectTimeActual,
delResourceProjectTimeActual and addResourceProjectTimeActual for the single record; getResourceProjectTimeActuals
(bulk by ID), getAllResourceProjectTimeActuals (a day range) and getAllResourceProjectTimeActualsByPeriod (one
actuals period) for the lists; getProjectResourcesProjectTimeActuals for the view from the project; and
getResourceProjectTimeActualTimeline / getResourceProjectTimeActualVersion for the history. Section 10 names the
V2 predecessor of each.
8.5 Endpoint-level retirements
The rest are individual endpoints whose functionality is covered by a general mechanism — object relations instead of a bespoke link endpoint, the sanitizer helper instead of an endpoint call, a translated variant instead of an untranslated one, the object endpoints instead of a "details" projection. Section 10 lists each of them with its own advice, per module.
9. A worked example
Reading the projects of a tenant and showing them in a sortable, paged table.
In V2 — one call, everything, unordered:
GET /API/V2/PM/Projects
-> PM.Project[] (every project the user may read, in full)
Sorting and paging happen in your code, and the payload grows with the tenant.
In V3 — references, then pages, ordered by the server:
GET /API/V3/PM/Projects?sort="name"
-> PF.ReferenceWithParents[] (every project the user may identify, ordered)
GET /API/V3/PM/Projects/"<id1>","<id2>",…"<id100>"
-> PM.Project[] (the first page, at most 100)
In V3, if the table only shows name, code and icon — skip the full read entirely:
GET /API/V3/PM/Projects/"<id1>",…,"<id100>"/Identification
-> PF.Identification[] (name, code, description, color, iconRef)
Creating a project inside a portfolio — V2 needed two calls, V3 needs one:
V2: POST /API/V2/PM/ProjectPortfolio/:portfolioId/Projects/Add
PUT /API/V2/PM/Project/:newProjectId (to set name, code, …)
V3: POST /API/V3/PM/ProjectPortfolio/:projectPortfolioId/Projects/Add?name=Apollo&code=APO
-> 201, PF.Reference
The same reads in a JavaScript automation:
var refs = PqfV3.pm.getAllProjects(['name']); // references, ordered
var ids = refs.slice(0, 100).map(function (r) { return r.id; });
var page = PqfV3.pm.getProjects(ids); // one page of details
var idns = PqfV3.pm.getProjectIdentifications(ids); // or just the labels
Optional parameters become trailing overloads, so a null is only needed to skip a parameter that is followed by
one you do want to pass:
var group = PqfV3.mtg.addMeetingGroup(null, null, 'Steering board', 'SB'); // copy, copyRels skipped
10. Per-module endpoint guide
How to read the tables:
- Paths omit the common prefix. A V2 path is relative to
/API/V2/<MODULE>/, a V3 path to/API/V3/<MODULE>/. When the V3 endpoint lives in a different module (writtenmod.name), its path starts with that module instead (ALC/Resource/…). JS onlymeans the endpoint has no HTTP route and exists only in the JavaScript API.- A V3 endpoint written as
mod.namelives in a different module than the V2 endpoint. - Redirected tables: the V2 URL answers
307; nothing else changes. Move at your convenience. - Reimplemented tables: there is no redirect. What differs is the shortest accurate summary — check the reference documentation for the endpoint before rewriting.
- Retired tables carry the endpoint's own deprecation note.
- New in V3: capability that had no V2 equivalent, listed so you can find it.
ACM — Access control, users, tokens, single sign-on
Almost every ACM response contract was rebuilt around pf.Reference and pf.Identification, so expect to touch
your response parsing even where the URL is unchanged.
- The SAML 2 URLs are spelled
Saml2/IdP(capitalP) and the path parameter is:authorityId. Both are covered by the redirect, so nothing breaks until you move. - The e-mail notification flag no longer has its own endpoint:
getCurrentUserReceiveNotificationsandputCurrentUserReceiveNotificationsfold intoget/putCurrentUserPreferences, where it is one member of the preferences object. getUsersandgetSaml2IdentityProvidersno longer return everything. UsegetAllUsers/getAllSaml2IdentityProvidersfor the reference list, then the plural getter with the IDs you want.getPermissionCubeForTypeandgetPermissionCubeForIdboth fold intogetPermissionCubeForObject.- User relations move to the general relation mechanism in PF — see
pf.getAllRelations. getUserCertificateis nowgetCurrentUserCertificate, matching theCurrentUserURL it always had.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
addSaml2IdentityProvider |
POST Saml2/Idps/Add |
addSaml2IdentityProvider |
POST Saml2/IdPs/Add |
apiTokenUnauthorize |
POST ApiToken/:tokenid/Unauthorize |
apiTokenUnauthorize |
POST ApiToken/:tokenId/Unauthorize |
createNewApiToken |
POST ApiToken/Create |
createNewApiToken |
POST ApiToken/Create |
delSaml2IdentityProvider |
DELETE Saml2/Idp/:authid |
delSaml2IdentityProvider |
DELETE Saml2/IdP/:authorityId |
delUser |
DELETE User/:userId |
delUser |
DELETE User/:userId |
delUserRoleAuthorizations |
DELETE UserRole/ |
delUserRoleAuthorizations |
DELETE UserRole/ |
delUserRoleTranslated |
DELETE UserRole/ |
delUserRoleTranslated |
DELETE UserRole/ |
getApiTokenInfo |
GET ApiToken/Info |
getApiTokenInfo |
GET ApiToken/Info |
getAuthorizedApiToken |
GET AuthorizedApiToken/:tokenId |
getAuthorizedApiToken |
GET AuthorizedApiToken/:tokenId |
getAuthorizedApiTokens |
GET AuthorizedApiTokens |
getAuthorizedApiTokens |
GET AuthorizedApiTokens |
getPermission |
GET Permission/:permissionId |
getPermission |
GET Permission/:permissionId |
getPermissions |
GET Permissions |
getPermissions |
GET Permissions |
getSaml2IdentityProviderRequestSignCertificate |
GET Saml2/ |
getSaml2IdentityProviderRequestSignCertificate |
GET Saml2/ |
getUserCertificateBinary |
GET CurrentUser/Certificate/Binary |
getCurrentUserCertificateBinary |
GET CurrentUser/Certificate/Binary |
getWelcomeMessage |
GET Welcome |
getWelcomeMessage |
GET Welcome |
putApiTokenInfo |
PUT ApiToken/Info |
putApiTokenInfo |
PUT ApiToken/Info |
renewSaml2IdentityProviderRequestSignCertificate |
POST Saml2/ |
renewSaml2IdentityProviderRequestSignCertificate |
POST Saml2/ |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
addUser |
POST Users/Add/:firstAuthority |
addUser |
POST Users/Add/:firstAuthorityId |
Returns a reference to the new user instead of the full user |
getAuthorizationByObj |
GET CurrentUser/ |
getAuthorizationByObj |
GET CurrentUser/ |
Names the transition transitionId |
getAuthorizationByPerm |
GET CurrentUser/ |
getAuthorizationByPerm |
GET CurrentUser/ |
The permission description is not included, read it with getPermission |
getAuthorizationsByObj |
GET CurrentUser/ |
getAuthorizationsByObj |
GET CurrentUser/ |
Names the transition transitionId |
getConfidentiality |
GET Confidentiality/ |
getConfidentiality |
GET Confidentiality/ |
Expects the V3 object type (ProjectWorkItem instead of Phase) |
getCreateAuthorizationByObj |
GET CurrentUser/ |
getCreateAuthorizationByObj |
GET CurrentUser/ |
Names the transition transitionId |
getCurrentUser |
GET CurrentUser |
getCurrentUser |
GET CurrentUser |
Reports the user name as login |
getCurrentUserAuthorizations |
GET CurrentUser/Authorizations |
getCurrentUserAuthorizations |
GET CurrentUser/Authorizations |
The permission descriptions are not included, read them with getPermissions |
getCurrentUserPreferences |
GET CurrentUser/Preferences |
getCurrentUserPreferences |
GET CurrentUser/Preferences |
Response body changed |
getCurrentUserReceiveNotifications |
GET CurrentUser/ |
getCurrentUserPreferences |
GET CurrentUser/Preferences |
Parameter list changed |
getFirstFactorAuthorities |
GET FirstFactorAuthorities |
getFirstFactorAuthorities |
GET FirstFactorAuthorities |
Response body changed |
getFirstFactorAuthority |
GET FirstFactorAuthority/ |
getFirstFactorAuthority |
GET FirstFactorAuthority/ |
Response body changed |
getPermissionCubeForId |
JS only |
getPermissionCubeForObject |
GET PermissionCube/ |
Response body changed |
getPermissionCubeForObject |
GET PermissionCube/ |
getPermissionCubeForObject |
GET PermissionCube/ |
Expects the V3 object type (ProjectWorkItem instead of Phase) and returns user references and lifecycle state IDs instead of full objects |
getPermissionCubeForType |
GET PermissionCube/:objectType |
getPermissionCubeForObject |
GET PermissionCube/ |
Parameter list changed |
getPermissionCubeMappingsForType |
GET PermissionCubeMappings/ |
getPermissionCubeMappingsForType |
GET PermissionCubeMappings/ |
Expects the V3 object type (ProjectWorkItem instead of Phase) and returns relation type, state and transition IDs instead of full objects |
getPermissionsGraph |
GET PermissionGraph |
getPermissionGraph |
GET PermissionGraph |
Names the parent permissions parentIds |
getSaml2IdentityProvider |
GET Saml2/Idp/:authid |
getSaml2IdentityProvider |
GET Saml2/IdP/:authorityId |
Names the e-mail field emailField |
getSaml2IdentityProviders |
GET Saml2/Idps |
getAllSaml2IdentityProviders |
GET Saml2/IdPs |
Returns references; read them with getSaml2IdentityProviders |
getSecondFactorAuthorities |
GET SecondFactorAuthorities |
getSecondFactorAuthorities |
GET SecondFactorAuthorities |
Response body changed |
getSecondFactorAuthority |
GET SecondFactorAuthority/ |
getSecondFactorAuthority |
GET SecondFactorAuthority/ |
Response body changed |
getUser |
GET User/:userId |
getUser |
GET User/:userId |
Reports the user name as login |
getUserAuthorizations |
GET User/:userId/Authorizations |
getUserAuthorizations |
GET User/:userId/Authorizations |
The permission descriptions are not included, read them with getPermissions |
getUserCertificate |
GET CurrentUser/Certificate |
getCurrentUserCertificate |
GET CurrentUser/Certificate |
Response body changed |
getUserIdentification |
GET User/:userId/Identification |
getUserIdentification |
GET User/:userId/Identification |
Parameter list changed |
getUserRole |
GET UserRole/:userRoleId |
getUserRole |
GET UserRole/:userRoleId |
Response body changed |
getUserRoleAssignments |
GET User/:userId/Roles |
getUserRoleAssignments |
GET User/:userId/Roles |
Returns references to the assigned user roles |
getUserRoleAuthorizations |
GET UserRole/ |
getUserRoleAuthorizations |
GET UserRole/ |
Names the permission permissionId |
getUserRoles |
GET UserRoles |
getUserRoles |
GET UserRoles |
Response body changed |
getUserRolesTranslated |
GET UserRoles/WithTranslations |
getUserRolesTranslated |
GET UserRoles/WithTranslations |
Response body changed |
getUserRoleTranslated |
GET UserRole/ |
getUserRoleTranslated |
GET UserRole/ |
Response body changed |
getUsers |
GET Users |
getAllUsers |
GET Users |
Returns references; read them with getUsers; the name, resourceId, firstAuthorityId, email and active filters are gone |
getUserSecondFactorStatus |
GET User/ |
getUserSecondFactorStatus |
GET User/ |
Response body changed |
putConfidentiality |
PUT Confidentiality/ |
putConfidentiality |
PUT Confidentiality/ |
Expects the V3 object type (ProjectWorkItem instead of Phase) |
putCurrentUserPreferences |
PUT CurrentUser/Preferences |
putCurrentUserPreferences |
PUT CurrentUser/Preferences |
Request body changed |
putCurrentUserReceiveNotifications |
PUT CurrentUser/ |
putCurrentUserPreferences |
PUT CurrentUser/Preferences |
Request body changed |
putSaml2IdentityProvider |
PUT Saml2/Idp/:authid |
putSaml2IdentityProvider |
PUT Saml2/IdP/:authorityId |
Names the e-mail field emailField |
putUser |
PUT User/:userId |
putUser |
PUT User/:userId |
Takes the user name as login |
putUserRoleAssignments |
PUT User/:userId/Roles |
putUserRoleAssignments |
PUT User/:userId/Roles |
Takes references to the user roles and requires the role management license (API V2 accepted an assignment of all roles without it) |
putUserRoleAuthorizations |
PUT UserRole/ |
putUserRoleAuthorizations |
PUT UserRole/ |
Body names the permission permissionId |
putUserRoleTranslated |
PUT UserRole/ |
putUserRoleTranslated |
PUT UserRole/ |
Request body changed |
Retired — no V3 successor; the endpoint disappears with API V2.
| V2 endpoint | V2 path | Note |
|---|---|---|
getCurrentUserRelations |
GET CurrentUser/Relations |
Use endpoints in PF module, will be discontinued at end of 2028 |
getUserRelations |
GET User/:userId/Relations |
Use PF endpoints, will be discontinued at end of 2028 |
New in V3 — no V2 equivalent.
getFirstFactorAuthorityUsers, getUserIdentifications, getUserPreferences, putUserPreferences
ACT — Actual times and presences
- Version history follows the general pattern: the
…Historyendpoints become…Timelineplus…Version/:versionId. getActualsPeriods(all periods) becomesgetAllActualsPeriods; the plural-with-IDs routes are new.- The seven single-time-per-day endpoints are retired — see section 8.4 for the replacement family.
- The efforts endpoints are in V3, reshaped:
ProjectEfforts.idbecomesprojectIdand the contract gained aresourceId, so oneResourceProjectEffortsserves both directions.getProjectResourcesEffortsis the new mirror image — the efforts of several resources in one project. All three take an optionalbeg/endday range (endexclusive); omit both and the answer spans the whole allocation, as V2 always did. Giving only one of the two is refused, and both days must lie within the configured planning range. - The phase-detailed efforts are the same answer plus a breakdown.
getResourceProjectWithWorkItemEffortsandgetResourceProjectsWithWorkItemEffortshang off the plain efforts URL asEfforts/WithWorkItemsand answer aResourceProjectWithWorkItemEfforts, which extendsResourceProjectEfforts. Itsplanned/actual/remainingare therefore the same totals the plain endpoints answer, and itsworkItemsarray adds one entry per work item — including the entry naming noworkItemId, which carries what was allocated on the project itself. V2 split that differently:ProjectWithPhasesEffortsput only the project-level amounts in its own three members and left the caller to add the phases back on. In V3 the entries sum to the totals, so both readings are available and they agree. - Presence writes carry their time zone. V3 stores a presence as a real UTC instant plus the day it
counts on and the zone that day was read in, so a presence no longer means something different to a
reader in another zone.
addResourcePresencetherefore asks fordayand, optionally,timezonerather than inferring both from whoever is calling, andclockResourcePresencederives the day from the stamp and that same optional zone. Both default to the calling user's zone, so a client that only ever calls in one zone can keep ignoring the parameter. - Presences are a V3 object family now. A presence is addressed under its resource
(
Resource/) and has the usual read, modify, delete,:resourceId/ Presence/ :presenceId TimelineandVersion/:versionIdendpoints. The V2 "give me the whole period" read splits the way the rest of V3 does:getAllResourcePresencesByPeriodanswers references,getResourcePresencesreads them by ID in bulk with one status per element, and the newgetAllResourcePresenceslists a resource's presences over an optional day range. The two list reads leave out what the caller may not read rather than failing; naming a presence is what gets it reported as forbidden. - The summaries read whole periods.
getResourcePresenceDailySummaryanswers one entry per day of the range,getResourcePresenceRangeSummarythe same range totalled into one. Both take the same requiredbeg/endrange with an exclusive end, and both are refused whole when the caller may not read one of the actuals periods the range touches: a summary over the days that were left would answer a target and a presence total that are wrong for the range that was asked for. - The two balances are one endpoint.
getResourcePresenceBalanceanswers the time balance and the per absence type balances together, where V2 neededgetTimeBalanceandgetAbsencesBalanceseparately. Neither figure covers the year you ask for on its own: both are cumulated from 2000 up to and including it, which V2 said out loud for the time balance and left the caller to know for the absences. The year moves from the path into a required parameter and is named in the answer; the time balance sits intime; and each entry ofabsencesnames itsabsenceTypeIdand holds what the time corrections booked on that type credited minus the absences taken on it, so it is negative until an entitlement is booked. Every absence type is reported, including the ones the resource has neither been credited nor been absent on. - Project time actuals are a V3 object family now. A booking is addressed under the resource that made it
(
Resource/) and has the usual read, modify, delete,:resourceId/ ProjectTimeActual/ :resourceProjectTimeActualId TimelineandVersion/:versionIdendpoints, plusaddResourceProjectTimeActual, which mints the ID rather than letting the caller choose it. The list reads split the way the rest of V3 does:getAllResourceProjectTimeActualsByPeriodanswers references for one actuals period,getAllResourceProjectTimeActualsa resource's bookings over an optional day range,getProjectResourcesProjectTimeActualsthe same records seen from a project, andgetResourceProjectTimeActualsreads them by ID in bulk with one status per element. The references carry the whole identity tuple —day,resourceId,projectIdandworkItemId— so the entries of a list can be told apart without a second call. As with the presences, the list reads leave out what the caller may not read rather than failing; naming a booking is what gets it reported as forbidden. - A booking's day, resource and project are fixed when it is added.
putResourceProjectTimeActualmodifiesworkItemId,durationandcommentand refuses a body that disagrees with the stored day, resource or project, rather than writing part of it. It does not create either: a body under an unknown ID is a404, andaddResourceProjectTimeActualis the way in. V2'sputResourceProjectTimeActualcreated under a caller-chosen ID and let the day and the project be restated on every write. - The presence and the actuals of the V2 allocation slots are ACT time slots.
getResourcePresenceSlotsandgetResourceTimeActualSlotsByProjectanswer what V2'salc.getMacroAllocationSlotsreported aspresenceand as the forecasts'actual, in time slots, with bulk siblings and single-slot lookups. Like the presence summaries they needREADon every actuals period the span touches. The family is described in the ALC section.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
getActualsPeriod |
GET ActualsPeriod/:periodId |
getActualsPeriod |
GET ActualsPeriod/:periodId |
getActualsPeriodByDay |
GET ActualsPeriod |
getActualsPeriodByDay |
GET ActualsPeriod |
getActualsPeriods |
GET ActualsPeriods |
getAllActualsPeriods |
GET ActualsPeriods |
getResourceActualsPeriod |
GET Resource/ |
getResourceActualsPeriod |
GET Resource/ |
getResourceActualsPeriodByDay |
GET Resource/ |
getResourceActualsPeriodByDay |
GET Resource/ |
delResourcePresence |
DELETE Resource/ |
delResourcePresence |
DELETE Resource/ |
getResourceActualsPeriods |
GET Resource/ |
getAllResourceActualsPeriods |
GET Resource/ |
delResourceProjectTimeActual |
DELETE Resource/ |
delResourceProjectTimeActual |
DELETE Resource/ |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
addResourcePresence |
POST Resource/ |
addResourcePresence |
POST Resource/ |
The body is gone: the values are parameters, and the presence's day and its timezone are now stated explicitly instead of being read out of the caller's own time zone |
clockResourcePresence |
POST Resource/ |
clockResourcePresence |
POST Resource/ |
time moves from the path into an optional parameter and defaults to now; an optional timezone decides the day the stamp counts on; the answer is a reference to the affected presence, 201 when the stamp opened one and 200 otherwise |
delResourceTimeCorrection |
DELETE Resource/ |
delResourceTimeCorrection |
DELETE Resource/ |
Addresses the correction by its ID instead of type and date; find it with getAllResourceTimeCorrections, whose references carry date and correction type |
getDaySummary |
GET Resource/ |
getResourcePresenceDailySummary |
GET Resource/ |
Both days of the range are required now, and every entry names the day it stands for instead of leaving the caller to count them out; the whole range has to be readable, so a day in an actuals period closed to the caller is a 403 rather than a gap |
getMidMonthSummary |
GET Resource/ |
getResourcePresenceRangeSummary |
GET Resource/ |
Totals any day range rather than the month up to a day: pass the first day of the month as beg and the day after the target one as end. The answer repeats the range it stands for, and its absences are merged per type - V2 listed the same type once per day it was booked on |
getTimeBalance |
GET Resource/ |
getResourcePresenceBalance |
GET Resource/ |
Merged with getAbsencesBalance into one call: the answer carries the time balance in time and the per absence type balances in absences. year moves from the path into a required parameter, and the resource must exist and be readable - V2 answered a zero balance for any ID |
getAbsencesBalance |
GET Resource/ |
getResourcePresenceBalance |
GET Resource/ |
Merged with getTimeBalance into one call: the per absence type balances sit in absences, each naming its absenceTypeId, and the answer states the year they are cumulated up to - V2 left the caller to remember it |
getResourcePresences |
GET Resource/ |
getAllResourcePresencesByPeriod |
GET Resource/ |
Answers references rather than whole presences; read them with the new bulk getResourcePresences (GET Resource/), which reports one status per element |
putResourcePresence |
PUT Resource/ |
putResourcePresence |
PUT Resource/ |
Request body changed; the day a presence counts on and the timezone it was recorded in are fixed when it is added and a change to either is refused |
getProjectEfforts |
GET Resource/ |
getResourceProjectEfforts |
GET Resource/ |
id renamed to projectId, resourceId added; optional beg/end day range added |
getProjectsEfforts |
GET Resource/ |
getResourceProjectsEfforts |
GET Resource/ |
Same body change and the same optional day range; projects the caller may not read are no longer dropped silently but reported per element |
getProjectWithPhasesEfforts |
GET Resource/ |
getResourceProjectWithWorkItemEfforts |
GET Resource/ |
phases becomes workItems and names a workItemId; the three top-level amounts are the totals over the whole project now, not the project-level part alone, and what was allocated on the project itself appears as the entry with no workItemId; optional beg/end day range added |
getProjectsWithPhasesEfforts |
GET Resource/ |
getResourceProjectsWithWorkItemEfforts |
GET Resource/ |
Same body change and the same optional day range; projects the caller may not read are no longer dropped silently but reported per element |
getProjectTimeActuals |
GET Project/ |
getProjectResourcesProjectTimeActuals |
GET Project/ |
The resources are named rather than derived from the project, from/to become beg/end, and the answer is references rather than whole records — read them with getResourceProjectTimeActuals |
getResourceProjectTimeActual |
GET Resource/ |
getResourceProjectTimeActual |
GET Resource/ |
Response body changed: the V3 contract carries the version and audit information of VersionedReference, and createdBy/modifiedBy are references rather than items |
getResourceProjectTimeActuals |
GET Resource/ |
getAllResourceProjectTimeActualsByPeriod |
GET Resource/ |
Answers references rather than whole records; read them with the new bulk getResourceProjectTimeActuals (GET Resource/), which reports one status per element |
putResourceProjectTimeActual |
PUT Resource/ |
putResourceProjectTimeActual |
PUT Resource/ |
Request body changed, and the endpoint no longer creates: day, resourceId and projectId are fixed when the booking is added and a change to any of them is refused — use addResourceProjectTimeActual to create |
getResourceTimeCorrections |
GET Resource/ |
getAllResourceTimeCorrections |
GET Resource/ |
Returns references; read them with getResourceTimeCorrections |
putResourceTimeCorrection |
PUT Resource/ |
putResourceTimeCorrection |
PUT Resource/ |
Addresses the correction by its ID instead of type and date; find it with getAllResourceTimeCorrections, whose references carry date and correction type. Takes the V3 ResourceTimeCorrection as its body |
Retired — no V3 successor; the endpoint disappears with API V2.
| V2 endpoint | V2 path | Note |
|---|---|---|
delResourceProjectPhaseTime |
DELETE Resource/ |
This API call is deprecated as it does not support more than one project time per project, task and day, will be discontinued at end of 2028 |
delResourceProjectTime |
DELETE Resource/ |
This API call is deprecated as it does not support more than one project time per project and day, will be discontinued at end of 2028 |
getResourceProjectPhaseTime |
GET Resource/ |
This API call is deprecated as it does not support more than one project time per project, task and day, will be discontinued at end of 2028 |
getResourceProjectTime |
GET Resource/ |
This API call is deprecated as it does not support more than one project time per project and day, will be discontinued at end of 2028 |
getResourceProjectTimes |
GET Resource/ |
This API call is deprecated as it does not support more than one project time per project and day, will be discontinued at end of 2028 |
putResourceProjectPhaseTime |
PUT Resource/ |
This API call is deprecated as it does not support more than one project time per project, task and day, will be discontinued at end of 2028 |
putResourceProjectTime |
PUT Resource/ |
This API call is deprecated as it does not support more than one project time per project and day, will be discontinued at end of 2028 |
New in V3 — no V2 equivalent.
addResourceProjectTimeActual, getActualsPeriods, getAllResourcePresences, getAllResourceProjectTimeActuals, getProjectResourcesEfforts, getResourceActualsPeriods, getResourcePresence, getResourcePresenceTimeline, getResourcePresenceVersion, getResourceProjectTimeActualTimeline, getResourceProjectTimeActualVersion, getResourceTimeCorrection, getResourceTimeCorrectionTimeline, getResourceTimeCorrectionVersion, getResourcesPresenceSlot, getResourcesTimeActualSlotByProject
ALC — Allocations and capacity planning
Allocation and capacity planning is fully in V3. Six families make it up: the absence types, the involvement endpoints, which answer which projects a resource works on and which resources work on a project, the day-by-day planning matrix, which V3 unifies into the resource shift plan, the macro allocations, which V3 calls resource allocations, the allocation slots, which V3 splits into the time slot family across RES, ALC and ACT, and the allocation workflow.
- Absence types are a V3 object family, addressed in their translated form only.
getAbsenceTypessplits the V2 "give me everything" call intogetAllAbsenceTypes(references, sortable) andgetAbsenceTypes(bulk read by ID);getAbsenceTypesTranslatedis new. The untranslated writes are gone:putAbsenceTypeis retired, anddelAbsenceTyperedirects todelAbsenceTypeTranslated— there is only one delete. AbsenceSlots,MicroAllocationSlotsandPlanningSlotsbecome one matrix. All three V2 families described the same grid of days and resource shifts, and differed only in how much of it they filled in. V3 has one read,getResourceShiftPlan, which always reports the whole grid — the absences and the reservations (the new name for micro allocations) — and one write,updateResourceShiftPlan. The body of either is the matrix itself, one row per resource shift:{ begin, rows: [ { shiftId, slots: [ { absence: { ref, remark }, reservation: { ref, remark } } ] } ] }. A row names its shift by ID only, so read the shift itself withres.getResourceShifts; every row holds one slot per day, the first one forbegin. The statistics over the matrix are a read of their own,getResourceShiftPlanStatistics(see below).- The write takes one update mode per dimension.
absencesandreservationsboth default toUPDATE_OR_DELETE, which makes that dimension match the body exactly.UPDATE_ONLYwrites creations and changes but keeps an entry the body leaves empty, andKEEPdoes not touch the dimension at all. The two V2 writes are thereforeupdateResourceShiftPlan(…, absences=UPDATE_OR_DELETE, reservations=KEEP)and its mirror image — and writing both dimensions in one call, which V2 could not do, is the default. - Every slot reports its own status.
X-Detail-Codesholds one code per slot of the request, row by row and within a row day by day, and400marks every slot an update mode refused to write: underKEEPeach slot the request would have changed, underUPDATE_ONLYeach slot it would have emptied. The call still answers200as long as one slot was written — see section 5.3. - Permissions follow the dimension that is really written. Reading the matrix needs the permission to read
the actuals of the resource. Writing the absences needs
PLANon the resource andUPDATEon every actuals period the matrix spans; writing the reservations needsRESERVE. A mode set toKEEPdemands neither, so a caller who may only reserve can still send the whole matrix withabsences=KEEP. - Absence and reservation share one shape. Both are a
ResourceShiftPlanEntry, aPF.Referenceplus a remark: therefof an absence names its absence type (V2absenceType), therefof a reservation its project work item (V2phaseId, section 6); any other type is answered with422. A slot may hold both, since an absence need not keep the resource from working. The remark of a reservation is new; a V2 write, which knows none, keeps the stored remark of every reservation whose work item it leaves unchanged. The matrix names nothing but these references: V2'sphaseName,projectId,projectName,scenarioId,scenarioName,absenceNameandabsenceColorhave no V3 counterpart, since the names disclosed objects the caller need not be allowed to see - read them from the objects themselves, e.g.alc.getAbsenceTypes. Nor does a slot report V2'spresence,model(the worktime model with its holiday) anddescriptionany longer;getResourceShiftPlanStatisticscounts the available and the bank holiday slots. - What changed in a slot is a list of its own.
getResourceShiftPlanAbsenceChangesandgetResourceShiftPlanReservationChanges(GET Resource/and:resourceId/ ShiftPlan/ Absences/ Changes …/Reservations/Changes) answer the changes to one dimension of the shift plan on the given days, newest first: the slot (day,shiftId), the entry before and after the change (previous,current, each absent for an empty slot), andmodifiedAtandmodifiedBy;from,untilandlimitnarrow them down. They replace theabsencesTimelineandreservationsTimelineof V2'sgetMacroAllocationHistory, from the same records: slots are not versioned, so a slot changed in place shows only its latest state, as in V2. - The statistics count slots, grouped by reference.
getPlanningSlotStatsis deprecated in favour ofgetResourceShiftPlanStatistics,GET Resource/. Instead of the V2 arrays:resourceId/ ShiftPlan/ Statistics absencesandprojectsof{ id, hint, slotcount }it reports one arrayslotCountsof{ ref, count }, whererefis aPF.Referenceto an absence type or a project — by type and ID, the V2hint(the name) is gone.availableandunavailablebecome the plain countsavailableSlotsandunavailableSlots, andholidaySlotscounts the slots on a bank holiday, which V2 did not report. A slot now counts as available exactly when the shift plan reports it as present, so the resource's own shift plan is honoured. Unlike the matrix, the statistics are not bounded bypqforce.dayrange.max. - Clearing the reservations of one work item is an ALC call now.
pm.delMicroAllocationsredirects tounassignResourceShiftPlanByProjectWorkItem,POST Resource/, which deletes every reservation that work item holds in the plan of that resource, over the whole time the plan spans, and touches no absence. It needs:resourceId/ ShiftPlan/ ByProjectWorkItem/ :projectWorkItemId/ Delete RESERVEon the resource, like every other write of reservations, andUPDATEon the work item; the V2 call asked for that sameUPDATE, but forPLANon the resource. - So is writing them.
pm.assignWorkItemShiftPlanredirects toassignResourceShiftPlanByProjectWorkItem,POST Resource/, the exact counterpart of the delete above - same path,:resourceId/ ShiftPlan/ ByProjectWorkItem/ :projectWorkItemId/ Assign Assigninstead ofDelete, same two permissions, and the same move fromPLANtoRESERVEon the resource. It takes the pattern of days and shifts from the shift plan of the work item (pm.getProjectWorkItemShiftPlan) and lays it out from the work item's start onwards, one reservation per planned slot. Only the URL really differs: the mandatoryresbecame the path segment:resourceId, beside the:projectWorkItemIdthat V2 carried in the path as:workItemId.forcekeeps its name and its meaning - without it a slot another reservation already holds is left alone - and a work item without a start is still answered400. - Macro allocations are resource allocations, an ALC object family. The seven V2 endpoints were part of PM;
V3 addresses a
ResourceAllocationby its own ID alone -getResourceAllocation(s),putResourceAllocation,delResourceAllocationandgetResourceAllocationIdentificationsatALC/ResourceAllocation/ :resourceAllocationId - because allocations are going to belong to the project rather than to one of its work items. The object
therefore names what it belongs to in a read-only
parentreference (today always a project work item, V2workItemId) instead of V2'sprojectId,scenarioIdandworkItemId;resourceTypeis gone as well. Itstypeis stillMacroAllocation.addResourceAllocation,POST ALC/, creates one withProjectWorkItem/ :projectWorkItemId/ ResourceAllocations/ Add resourceId,amount,amountUnitandamountType; a resource can be allocated to a work item only once, so a second one is answered400, where V2 silently overwrote the existing allocation.putResourceAllocationonly updates, and the work item and the resource it ignores. The lists are references with the work item as parent, by work item, by scenario and - new - by project (getAllResourceAllocationsOfProject, its active scenario or the single inactive one). The enumerations are spelled the V3 way:AllocationWorkflowStateisNew,Changed,Requested,Rejected,Approved, andResourceAllocationAmountTypeisAbsolute,OfCapacity,OfAvailability,OfFteandOfProjectWorkItem(V2OF_PHASE). The history follows the general pattern (section 5.6):getResourceAllocationTimelineandgetResourceAllocationVersion. A version reads the allocation as it was then, but withouteffectiveDuration, which only today's planning yields. What changed across all allocations of one resource isgetResourceAllocationChangesOfResource(GET Resource/), newest first: each change names the allocation with its work item as:resourceId/ ResourceAllocations/ Changes?beg&end parent, theversionit wrote, thepreviousVersionand whether itdeletedthe allocation - read either version withgetResourceAllocationVersion. It replaces theallocationTimelineof V2'sgetMacroAllocationHistory. A project counts with its current scenario, and only while the resource is still involved in it. The V2 endpoints are listed in the PM section.
- because allocations are going to belong to the project rather than to one of its work items. The object
therefore names what it belongs to in a read-only
- The allocation workflow moves an allocation like a lifecycle.
requestResourceAllocation,approveResourceAllocationandrejectResourceAllocation(POST ResourceAllocation/,:resourceAllocationId/ Request …/Approve,…/Reject) answer200without a body. A remark is not a URL parameter any more: each has a…WithRemarksibling (…/Request/WithRemarkand so on) taking alcy.LifecycleUpgradeRemarkas body, aslcy.upgradeObjectdoes. A remark without a move isaddResourceAllocationRemark(…/Remark/Add, V2commentResourceAllocation), which answers201. A move the workflow does not allow from the current state is answered400, and so is every write while the allocation workflow is not enabled; the history and the newgetResourceAllocationWorkflowTransitions- the states the caller may move the allocation to now - answer404then. Requesting needsALLOCATEon the work item, approving and rejectingALLOCATEon the resource, a remark either of the two;autoApprove(V2autoapprove) still approves a request at once if the caller may. - The allocation slots become a family of time slots, one time value per endpoint. A V2
Workloadanswered availability, presence and the forecasts of every group in one array of slots. V3 answers each value on its own, in the module it belongs to:res.,getResourceAvailabilitySlots getResourcePlannedTimeSlotsByProject,getResourceScenarioPlannedTimeSlots,act.getResourcePresenceSlotsandact.. Each has a bulk sibling for several resources atgetResourceTimeActualSlotsByProject Resources/:resourceIds/…(V2getMacroAllocationSlotsByResource), and a single-slot lookup that answers one slot over exactly the requested span —…Slotinstead of…Slots, the successor ofgetMacroAllocationSlot. All of them cut a span into the very same slots, so their answers can be laid over one another, and a bulk request answers every resource in the same slots. TheWorkloadenvelope itself is gone: an answer is the array of slots. - The planned time by work item is a single slot too, for one project with its current scenario,
getResourceProjectPlannedTimeSlotByProjectWorkItem(V2getProjectPhaseAllocationsByResource), and for one scenario, active or not,getResourceScenarioPlannedTimeSlotByProjectWorkItem(V2getScenarioPhaseAllocationsByResource). Their bulk siblings take the resources from you — find them withgetInvolvedResources(V2getProjectPhaseAllocations,getScenarioPhaseAllocations). The time on a work item the caller may notIDENTIFYis answered under the reference of the project or the scenario itself. - A slot names its own time span. A V2 slot was a position in an array the client had to map back to
begandzoom. A V3PF.TimeSlotcarriesbeg,end(exclusive),unit(aPF.CalendarGranularity) andcomplete— false where the requested span cuts the slot — pluscapacity, the scale of the slot as the resource's worktime model defines it; a time may exceed it.zoomis optional: given, every slot has that unit; omitted, the server chooses the slots, and they may differ in width — readbegandendinstead of assuming one width. A single slot reports the smallest calendar unit one instance of which contains the whole span, e.g.Weekfor Tuesday to Friday. Withzoom=Daythe days of all requested resources together are bounded bypqforce.dayrange.max(section 5.13), and the span has to lie in the planning range, as in V2. - Grouped times are references, and always by project.
groupByis gone, and with it the grouping by lifecycle state; so is theprojectIdfilter. APF.GroupedDurationSlotholds atimesarray ofPF.ReferenceDuration, a project reference with its time; a project without time in a slot is left out, so there is nogroupingarray to index into any more. Every project counts, whatever its state, with its active scenario or, if it has none, its single inactive one — in the planned time and in the actuals alike. V2 left out the planned time of projects that were neither active nor in planning; in V3 you pick the projects of interest from the answer yourself. Time on a project the caller may notIDENTIFYgoes to an entry of the typeBaseLoad, whose ID is derived from the resource's ID and stays the same from one call to the next; in the planned time it also holds the base load of the resource's worktime model, in the actuals it never does. - What else changed. The availability is the working time without absences before the base load is taken
off; V2's
availabilitywas after it. The planned time of one scenario, active or not, is a call of its own (V2scenarioId,getScenarioAllocationSlots, andgetProjectAllocationSlots, for which you pass the project's active scenario). The presence is the reported presence only.expectedPresence, the forecast valuesactual,expectedActualandremaining,deviationFromOptimumwith itsfewerWorkWeight,fte,ftePercent,maxFtePercent,maxCapacityand theactualsReportedUntil/presenceReportedUntildays have no V3 counterpart. The presence and the actuals slots total whole spans, like the presence summaries, and so needREADon every actuals period the span touches.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
delAbsenceType |
DELETE AbsenceType/:absenceTypeId |
delAbsenceTypeTranslated |
DELETE AbsenceType/ |
delAbsenceTypeTranslated |
DELETE AbsenceType/ |
delAbsenceTypeTranslated |
DELETE AbsenceType/ |
getUnoptimizedResourcesByParent |
GET UnoptimizedResources/ |
getUnoptimizedResourcesByParent |
GET UnoptimizedResources/ |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
approveResourceAllocation |
POST ResourceAllocation/ |
approveResourceAllocation |
POST ResourceAllocation/ |
Without a remark; the remark is no longer a URL parameter but the body of approveResourceAllocationWithRemark (…/WithRemark), a lcy.LifecycleUpgradeRemark; a move the workflow does not allow is answered 400; 400 while the allocation workflow is not enabled |
commentResourceAllocation |
POST ResourceAllocation/ |
addResourceAllocationRemark |
POST ResourceAllocation/ |
The remark is the body, a lcy.LifecycleUpgradeRemark, and required (422); answers 201; 400 while the allocation workflow is not enabled |
getAbsenceSlots |
GET AbsenceSlots/ |
getResourceShiftPlan |
GET Resource/:resourceId/ShiftPlan |
Reports the whole matrix, not only its absences; body restructured and members renamed |
getAbsenceType |
GET AbsenceType/:absenceTypeId |
getAbsenceType |
GET AbsenceType/:absenceTypeId |
Response body changed |
getAbsenceTypes |
GET AbsenceTypes |
getAllAbsenceTypes |
GET AbsenceTypes |
Reports references and takes a sort; read the objects with getAbsenceTypes(:absenceTypeIds) |
getAbsenceTypeTranslated |
GET AbsenceType/ |
getAbsenceTypeTranslated |
GET AbsenceType/ |
Response body changed |
getAvailabilitySlot |
GET AvailabilitySlot/ |
res. |
GET RES/ |
The availability is before the base load is taken off; fte and ftePercent are not answered; the span has to lie in the planning range |
getInvolvedProjects |
GET Resource/ |
getInvolvedProjects |
GET Resource/ |
Reports PF.Reference instead of PF.Item, accepts an optional sort, and the array only contains what the caller may IDENTIFY |
getInvolvedResources |
GET Project/ |
getInvolvedResources |
GET Project/ |
Reports PF.Reference instead of PF.Item, accepts an optional sort, and the array only contains what the caller may IDENTIFY |
getMacroAllocationHistory |
GET MacroAllocationHistory/ |
getResourceAllocationChangesOfResource |
GET Resource/ |
One change list per timeline: the allocations here, the absences and reservations in getResourceShiftPlanAbsenceChanges and getResourceShiftPlanReservationChanges, the active scenario and the work items in pm. and pm.getProjectWorkItemTimeline; objects are references, an allocation's states are read with getResourceAllocationVersion |
getMacroAllocationSlot |
GET MacroAllocationSlot/ |
getResourcePlannedTimeSlotByProject |
GET Resource/ |
One time value per endpoint: availability, presence and actuals are res., act.getResourcePresenceSlot and act.; the slot names its span and unit; always by project, groupBy, projectId, scenarioId and fewerWorkWeight are gone |
getMacroAllocationSlots |
GET MacroAllocationSlots/ |
getResourcePlannedTimeSlotsByProject |
GET Resource/ |
One time value per endpoint: availability, presence and actuals are res., act.getResourcePresenceSlots and act.; answers the array of slots, each naming its span and unit; zoom is optional; always by project, groupBy, projectId, scenarioId and fewerWorkWeight are gone |
getMacroAllocationSlotsByResource |
GET MacroAllocationSlots/ |
getResourcesPlannedTimeSlotsByProject |
GET Resources/ |
As getMacroAllocationSlots, one row of slots per requested resource; the bulk siblings res., act.getResourcesPresenceSlots and act. answer the other values |
getMicroAllocationSlots |
GET MicroAllocationSlots/ |
getResourceShiftPlan |
GET Resource/:resourceId/ShiftPlan |
Reports the whole matrix, not only its reservations; body restructured and members renamed |
getPlanningSlots |
GET PlanningSlots/ |
getResourceShiftPlan |
GET Resource/:resourceId/ShiftPlan |
Body restructured and members renamed; the shift is named by ID, not embedded |
getPlanningSlotStats |
GET PlanningSlotStats/ |
getResourceShiftPlanStatistics |
GET Resource/ |
One array of references and counts instead of two arrays with names; adds the bank holiday slots |
getProjectAllocationsByResource |
GET ProjectAllocations/ |
getResourcePlannedTimeSlotByProject |
GET Resource/ |
One single slot of time slot references per endpoint: the actuals are act. and the availability res., the latter before the base load is taken off; expectedPending and remaining are not answered, includeInactive is gone (every project counts), a project is a reference without name and state |
getProjectAndPhaseAllocationsByResource |
GET ProjectAndPhaseAllocations/ |
getResourcePlannedTimeSlotByProject |
GET Resource/ |
No ready-made structure: the projects come as references with their planned time, the work items of one project from getResourceProjectPlannedTimeSlotByProjectWorkItem, their names and dates from pm.getProjectWorkItems; only what has time planned within the span is answered, and every project counts, whatever its state |
getProjectAllocationSlots |
GET MacroAllocationSlots/ |
getResourceScenarioPlannedTimeSlots |
GET Resource/ |
Addressed by the project's active scenario instead of the project; answers the planned time only, availability and presence are res. and act.getResourcePresenceSlots |
getProjectPhaseAllocations |
GET Project/ |
getResourcesProjectPlannedTimeSlotByProjectWorkItem |
GET Resources/ |
Name the resources yourself, e.g. from getInvolvedResources; one single slot of the planned time per work item reference per resource; actuals and availability are act. and res.; actuals, expectedPending and remaining per work item are not answered |
getProjectPhaseAllocationsByResource |
GET Project/ |
getResourceProjectPlannedTimeSlotByProjectWorkItem |
GET Resource/ |
One single slot of the planned time per work item reference; the project's actuals are act.; actuals, expectedPending and remaining per work item are not answered |
getScenarioPhaseAllocations |
GET ProjectScenario/ |
getResourcesScenarioPlannedTimeSlotByProjectWorkItem |
GET Resources/ |
Name the resources yourself, e.g. from getInvolvedResources; one single slot of the scenario's planned time per work item reference per resource; actuals, expectedPending and remaining per work item are not answered |
getScenarioPhaseAllocationsByResource |
GET ProjectScenario/ |
getResourceScenarioPlannedTimeSlotByProjectWorkItem |
GET Resource/ |
One single slot of the scenario's planned time per work item reference; the project's actuals are act.; actuals, expectedPending and remaining per work item are not answered |
getResourceAllocationWorkflowHistory |
GET ResourceAllocation/ |
getResourceAllocationWorkflowHistory |
GET ResourceAllocation/ |
Entries name their user by reference only (initiatedBy) and carry their version; 404 while the allocation workflow is not enabled |
getScenarioAllocationSlots |
GET MacroAllocationSlots/ |
getResourceScenarioPlannedTimeSlots |
GET Resource/ |
Answers the planned time of the scenario only, ungrouped; availability and presence are res. and act.getResourcePresenceSlots; fewerWorkWeight is gone |
putAbsenceTypeTranslated |
PUT AbsenceType/ |
putAbsenceTypeTranslated |
PUT AbsenceType/ |
Request body changed |
rejectResourceAllocation |
POST ResourceAllocation/ |
rejectResourceAllocation |
POST ResourceAllocation/ |
Without a remark; the remark is no longer a URL parameter but the body of rejectResourceAllocationWithRemark (…/WithRemark), a lcy.LifecycleUpgradeRemark; a move the workflow does not allow is answered 400; 400 while the allocation workflow is not enabled |
requestResourceAllocation |
POST ResourceAllocation/ |
requestResourceAllocation |
POST ResourceAllocation/ |
Without a remark; the remark is no longer a URL parameter but the body of requestResourceAllocationWithRemark (…/WithRemark), a lcy.LifecycleUpgradeRemark; autoapprove is spelled autoApprove; a move the workflow does not allow is answered 400; 400 while the allocation workflow is not enabled |
updateAbsenceSlots |
POST AbsenceSlots/ |
updateResourceShiftPlan |
POST Resource/ |
One write for both dimensions; pass reservations=KEEP to keep the V2 scope |
updateMicroAllocationSlots |
POST MicroAllocationSlots/ |
updateResourceShiftPlan |
POST Resource/ |
One write for both dimensions; pass absences=KEEP to keep the V2 scope |
Retired — no V3 successor; the endpoint disappears with API V2.
| V2 endpoint | V2 path | Note |
|---|---|---|
putAbsenceType |
PUT AbsenceType/:absenceTypeId |
Use version with translations instead, will be discontinued at end of 2028 |
New in V3 — no V2 equivalent.
approveResourceAllocationWithRemark, getAbsenceTypesTranslated, getAllResourceAllocationsOfProject, getResourceAllocationIdentifications, getResourceAllocationChangesOfResource, getResourceAllocationTimeline, getResourceAllocationVersion, getResourceAllocationWorkflowTransitions, getResourceShiftPlanAbsenceChanges, getResourceShiftPlanReservationChanges, getResourceScenarioPlannedTimeSlot, getResourcesPlannedTimeSlotByProject, getResourcesProjectPlannedTimeSlotByProjectWorkItem, getResourcesScenarioPlannedTimeSlot, getResourcesScenarioPlannedTimeSlotByProjectWorkItem, rejectResourceAllocationWithRemark, requestResourceAllocationWithRemark
ATM — Automation (JavaScript sources and triggers)
Fully migrated, and almost entirely by redirect — the cheapest module in this guide. The only rename is
triggerJavaScriptSource → triggerJavaScriptSandbox (JavaScript only on both sides), and the source
endpoints gained a reference list and historic versions.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
addJavaScriptChangeTrigger |
POST JavaScript/ |
addJavaScriptChangeTrigger |
POST JavaScript/ |
clearJavaScriptConsole |
POST JavaScript/Console/Clear |
clearJavaScriptConsole |
POST JavaScript/Console/Clear |
clearJavaScriptConsoleOfSandbox |
POST JavaScript/ |
clearJavaScriptConsoleOfSandbox |
POST JavaScript/ |
clearJavaScriptSandboxPerformance |
POST JavaScript/ |
clearJavaScriptSandboxPerformance |
POST JavaScript/ |
delJavaScriptChangeTrigger |
DELETE JavaScript/ |
delJavaScriptChangeTrigger |
DELETE JavaScript/ |
delJavaScriptSource |
DELETE JavaScript/Source/:sourceId |
delJavaScriptSource |
DELETE JavaScript/ |
getJavaScriptChangeTrigger |
GET JavaScript/ |
getJavaScriptChangeTrigger |
GET JavaScript/ |
getJavaScriptChangeTriggers |
GET JavaScript/ |
getJavaScriptChangeTriggers |
GET JavaScript/ |
getJavaScriptConsole |
GET JavaScript/Console |
getJavaScriptConsole |
GET JavaScript/Console |
getJavaScriptConsoleOfSandbox |
GET JavaScript/Console/:sandboxId |
getJavaScriptConsoleOfSandbox |
GET JavaScript/Console/:sandboxId |
getJavaScriptLibraries |
GET JavaScript/Libraries |
getJavaScriptLibraries |
GET JavaScript/Libraries |
getJavaScriptQuota |
GET JavaScript/Quota |
getJavaScriptQuota |
GET JavaScript/Quota |
getJavaScriptSandboxPerformance |
GET JavaScript/ |
getJavaScriptSandboxPerformance |
GET JavaScript/ |
runJavaScriptSource |
POST JavaScript/ |
runJavaScriptSandbox |
POST JavaScript/ |
triggerJavaScriptSource |
JS only |
triggerJavaScriptSandbox |
JS only |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
getJavaScriptSource |
GET JavaScript/Source/:sourceId |
getJavaScriptSource |
GET JavaScript/ |
The version parameter is not available, read a historic version with getJavaScriptSourceVersion using a version ID from getJavaScriptSourceTimeline |
getJavaScriptSourceCompileErrors |
GET JavaScript/ |
getJavaScriptSandboxCompileErrors |
GET JavaScript/ |
Names the source sourceId |
getJavaScriptSources |
GET JavaScript/Sources |
getAllJavaScriptSources |
GET JavaScript/Sources |
Returns references; read them with getJavaScriptSources |
getJavaScriptSourceTimeline |
GET JavaScript/ |
getJavaScriptSourceTimeline |
GET JavaScript/ |
Takes from, until and limit instead of beg and end |
putJavaScriptSource |
PUT JavaScript/Source/:sourceId |
putJavaScriptSource |
PUT JavaScript/ |
Request body changed |
New in V3 — no V2 equivalent.
getJavaScriptSourceVersion
CHT — Charts
Two endpoints, both reimplemented: the chart and its meta model return new bodies. There is no redirect, so rewrite both calls.
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
getChart |
GET Chart/ |
getChart |
GET Chart/ |
Response body changed |
getChartMetaModel |
GET MetaModel |
getChartMetaModel |
GET MetaModel |
Response body changed |
CLF — Client framework (cockpit widgets, stores, translations)
Mostly redirected. Three things to note:
- The stores gained reference lists —
getGlobalStores,getUserStoresandgetAllCockpitWidgets— so you can enumerate before reading. sanitizeHtmlis retired. In a JavaScript automation useHtml.sanitize(…); over HTTP, sanitizing happens on the server for you (section 4).newUuidsis restricted to the browser client in V3. In a JavaScript automation useUuid.generate(); in an integration, generate UUIDs locally — there is no reason to spend a round trip on it.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
calculateScriptedCockpitWidget |
POST CockpitWidget/ |
calculateScriptedCockpitWidget |
POST CockpitWidget/ |
delCockpitWidgetTranslated |
DELETE CockpitWidget/ |
delCockpitWidgetTranslated |
DELETE CockpitWidget/ |
delGlobalStore |
DELETE GlobalStore/:storeId |
delGlobalStore |
DELETE GlobalStore/:storeId |
delObjectStore |
DELETE ObjectStore/ |
delObjectStore |
DELETE ObjectStore/ |
delUserStore |
DELETE UserStore/:storeId |
delUserStore |
DELETE UserStore/:storeId |
getGlobalStore |
GET GlobalStore/:storeId |
getGlobalStore |
GET GlobalStore/:storeId |
getGlobalStoreIds |
GET GlobalStores/Ids |
getGlobalStoreIds |
GET GlobalStores |
getObjectStore |
GET ObjectStore/ |
getObjectStore |
GET ObjectStore/ |
getObjectStoreIds |
GET ObjectStores/Ids |
getObjectStoreIds |
GET ObjectStores/Ids |
getSharedData |
GET SharedData/:dataId |
getSharedData |
GET SharedData/:dataId |
getTranslationOverrides |
GET TranslationOverrides/:lang |
getTranslationOverrides |
GET TranslationOverrides/:lang |
getUserStore |
GET UserStore/:storeId |
getUserStore |
GET UserStore/:storeId |
getUserStoreIds |
GET UserStores/Ids |
getUserStoreIds |
GET UserStores |
putGlobalStore |
PUT GlobalStore/:storeId |
putGlobalStore |
PUT GlobalStore/:storeId |
putObjectStore |
PUT ObjectStore/ |
putObjectStore |
PUT ObjectStore/ |
putUserStore |
PUT UserStore/:storeId |
putUserStore |
PUT UserStore/:storeId |
reportThirdPartyError |
POST ThirdPartyError/Report |
reportError |
POST Error/Report |
shareData |
POST ShareData |
shareData |
POST ShareData |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
getCockpitWidget |
GET CockpitWidget/:widgetId |
getCockpitWidget |
GET CockpitWidget/:widgetId |
Response body changed |
getCockpitWidgets |
GET CockpitWidgets |
getAllCockpitWidgets |
GET CockpitWidgets |
Returns references; read them with getCockpitWidgets |
getCockpitWidgetsTranslated |
GET CockpitWidgets/ |
getAllCockpitWidgets |
GET CockpitWidgets |
Returns references; read them with getCockpitWidgetsTranslated |
getCockpitWidgetTranslated |
GET CockpitWidget/ |
getCockpitWidgetTranslated |
GET CockpitWidget/ |
Response body changed |
newUuids |
GET Uuid/New/:count |
newUuids |
GET Uuid/New/:count |
Interactive clients only; in JavaScript use Uuid.generate(). Response body changed: the array is uuids (V2: newUuids) |
putCockpitWidgetTranslated |
PUT CockpitWidget/ |
putCockpitWidgetTranslated |
PUT CockpitWidget/ |
Request body changed |
Retired — no V3 successor; the endpoint disappears with API V2.
| V2 endpoint | V2 path | Note |
|---|---|---|
sanitizeHtml |
JS only |
Use Html.sanitize(...) instead, will be discontinued at end of 2028 |
New in V3 — no V2 equivalent.
getGlobalStores, getUserStores
CLS — Classification schemes
Five endpoints. The schema getters and the translated variants return new bodies; only putSchemaTranslated
redirects.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
delSchemaTranslated |
DELETE ClassificationSchema/ |
delSchemaTranslated |
DELETE ClassificationSchema/ |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
getSchema |
GET ClassificationSchema/:schemaId |
getSchema |
GET ClassificationSchema/:schemaId |
Response body changed |
getSchemasForType |
GET ObjectType/ |
getSchemasForType |
GET ObjectType/ |
Expects the V3 object type (ProjectWorkItem instead of Phase) |
getSchemaTranslated |
GET ClassificationSchema/ |
getSchemaTranslated |
GET ClassificationSchema/ |
Response body changed |
putSchemaTranslated |
PUT ClassificationSchema/ |
putSchemaTranslated |
PUT ClassificationSchema/ |
Request body changed |
DOC — Legacy document exports
The whole module is retired. See section 8.1 for the EXP replacement.
Retired — no V3 successor; the endpoint disappears with API V2.
| V2 endpoint | V2 path | Note |
|---|---|---|
delExportConfiguration |
DELETE ExportViewConfiguration/ |
DOC module is deprecated. Use EXP module with JS exports instead. Will be discontinued at end of 2028 |
delExportTemplate |
DELETE Templates/:id |
DOC module is deprecated. Use EXP module with JS exports instead. Will be discontinued at end of 2028 |
getAvailableExports |
GET AvailableExports/:view |
DOC module is deprecated. Use EXP module with JS exports instead. Will be discontinued at end of 2028 |
getExportConfiguration |
GET ExportViewConfiguration/:view |
DOC module is deprecated. Use EXP module with JS exports instead. Will be discontinued at end of 2028 |
getTemplates |
GET Templates/:exportType |
DOC module is deprecated. Use EXP module with JS exports instead. Will be discontinued at end of 2028 |
handleExportRequest |
POST Export |
DOC module is deprecated. Use EXP module with JS exports instead. Will be discontinued at end of 2028 |
putExportConfiguration |
PUT ExportViewConfiguration/:id |
DOC module is deprecated. Use EXP module with JS exports instead. Will be discontinued at end of 2028 |
putExportTemplate |
PUT Templates/:id |
DOC module is deprecated. Use EXP module with JS exports instead. Will be discontinued at end of 2028 |
DPO — Disposition views
The whole module is retired, except delWorkItem, which redirects into PM. See section 8.2.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
delWorkItem |
DELETE DispoView/ |
pm.delProjectWorkItem |
DELETE PM/ |
Retired — no V3 successor; the endpoint disappears with API V2.
| V2 endpoint | V2 path | Note |
|---|---|---|
assignToOtherResource |
POST DispoView/ |
This endpoint will not be available in API V3 and will be discontinued at end of 2028 |
delDispoByResource |
POST DispoView/ |
This endpoint will not be available in API V3 and will be discontinued at end of 2028 |
getAbsenceBlocksByResource |
GET DispoView/ |
This endpoint will not be available in API V3 and will be discontinued at end of 2028 |
getDispoByResource |
GET DispoView/ |
This endpoint will not be available in API V3 and will be discontinued at end of 2028 |
getWorkItem |
GET DispoView/ |
This endpoint will not be available in API V3 and will be discontinued at end of 2028 |
moveDispoByResource |
POST DispoView/ |
This endpoint will not be available in API V3 and will be discontinued at end of 2028 |
newDispoByResource |
POST DispoView/ |
This endpoint will not be available in API V3 and will be discontinued at end of 2028 |
putWorkItem |
PUT DispoView/ |
This endpoint will not be available in API V3 and will be discontinued at end of 2028 |
EXP — Exports
Export definitions are addressed as JavaScriptExportDefinition and are written through the translated
variant, so a definition always carries its language versions: putExportDefinition →
putExportDefinitionTranslated, delExportDefinition → delExportDefinitionTranslated.
getExportDefinitionsForObjectType moved the object type to the front of the URL
(ObjectType/).
Both export request endpoints redirect unchanged, so running an export is a URL change only.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
delExportDefinition |
DELETE JavaScriptExportDefinition/ |
delExportDefinitionTranslated |
DELETE JavaScriptExportDefinition/ |
handleJavaScriptExportRequest |
POST JavaScriptExport/ |
handleJavaScriptExportRequest |
POST JavaScriptExport/ |
handleJavaScriptExportRequestWithSettings |
POST JavaScriptExport/ |
handleJavaScriptExportRequestWithSettings |
POST JavaScriptExport/ |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
getAllExportDefinitions |
GET JavaScriptExportDefinitions |
getAllExportDefinitions |
GET JavaScriptExportDefinitions |
Returns references to all JavaScript export definitions; read them with getExportDefinitions |
getExportDefinition |
GET JavaScriptExportDefinition/ |
getExportDefinition |
GET JavaScriptExportDefinition/ |
Response body changed |
getExportDefinitionsForObjectType |
GET JavaScriptExportDefinitions/ |
getExportDefinitionsForObjectType |
GET ObjectType/ |
Expects the V3 type name (ProjectWorkItem instead of Phase) and returns references; read them with getExportDefinitions |
putExportDefinition |
PUT JavaScriptExportDefinition/ |
putExportDefinitionTranslated |
PUT JavaScriptExportDefinition/ |
Request body changed |
New in V3 — no V2 equivalent.
getExportDefinitionTranslated, getExportDefinitions, getExportDefinitionsTranslated
FCO — Financial controlling (costs, budgets, currencies)
Financial controlling is fully in V3: the master data — currencies and their exchange rates, the currency calculator, costs types and costs type groups —, the project costs — costs positions and their actuals, the costs overviews and the costs timelines —, the budgets — budget positions, budget assignments, budget lines and the external, foreign and sub-object budgets — and the planned costs of work items and resource allocations.
- Lists become references plus a bulk read.
getCurrencies,getCostsTypesandgetCostsTypeGroups(and their translated variants) split intogetAllCurrencies/getAllCostsTypes/getAllCostsTypeGroups(references, sortable) and a bulk read by ID. Careful: the V3getCostsTypes,getCostsTypesTranslated,getCostsTypeGroups,getCostsTypeGroupsTranslatedandgetCurrencieskeep their V2 names but read by ID — they no longer return everything. - A costs type carries
groupId, not the group. V2 nested the whole costs type group; V3 returns its ID (andgetAllCostsTypesreturns it as the parent of each reference). Read the group withgetCostsTypeGroup. - Writes are translated and one at a time.
putCurrencybecomesputCurrencyTranslated, and the bulk writesputCostsTypesTranslated/putCostsTypeGroupsTranslatedhave no V3 successor beyond the singleput…Translated.delCurrencyredirects todelCurrencyTranslated— there is only one delete. - Costs centers and pay plans are enum values. They are values of fixed PF enum types, so V3 has no FCO
endpoint for them.
getCostsCenterEnumTypeandgetPayPlanEnumTypereturn the reference of the enum type; pass its ID to PFgetAllEnumValues,getEnumValuesorgetEnumValue. - Exchange rates check the currency. The exchange-rate endpoints answer
404for an unknown currency — through the redirect, V2 callers ofgetTodaysCurrencyExchangeRateand the…ExchangeRateAtfamily see it too. - Costs positions and actuals are addressed by their own ID. The project (and, for an actual, the costs position) no longer appears in the path of a read, write or delete. Adding an actual needs only its costs position.
- A costs position carries IDs and stored amounts.
getCostsPosition(s)returncostsTypeId,costsCenterIdandpayPlanIdinstead of references, and the planned, supplementary and remaining amounts as they were entered — in their own currency, not converted. The converted amounts and the calculated provisional, actual and available amounts come fromgetCostsPosition(s)Converted, which takes a mandatorytargetCurrencyId. The same split applies to actuals:getCostsActual(s)andgetCostsActual(s)Converted. - Costs overviews and timelines rename their parameters.
refid→referencePortfolioId,beg→start,currency→targetCurrencyId, and the timeline filtersfilterFlow,filterType,filterTypeGroup,filterContainer,filterProject,filterPositionandfilterMgmtPhasebecomeflowFilter,costsTypeFilter,costsTypeGroupFilter,costsContainerFilter,projectFilter,costsPositionFilterandmanagementPhaseFilter. The filters take IDs, and anullelement matches costs without that dimension. Thegroupingvalues are spelled in PascalCase (Container,Flow, …). The response bodies are restructured. - Budget positions and budget assignments are kept apart. V2 called both a "budget position": the one a
portfolio owns, and the share of one that was inherited by — assigned to — a sub-portfolio or a project. V3
has separate endpoints for each:
…BudgetPosition…for an owned position,…PortfolioBudgetAssignment…and…ProjectBudgetAssignment…for an assigned share. Each accepts only its own ID, given alone without the portfolio or project. Creating an inherited budget (V2inheritFrom) isaddPortfolioBudgetAssignment. - A project's budgets are budget lines.
getProjectBudgetLines/getProjectsBudgetLinesreturn the calculated amounts per line and name the assignment behind each one; read the assignments themselves withgetProjectBudgetAssignments. Inherited positions of a portfolio are read the same way withgetPortfolioBudgetLines/getPortfoliosBudgetLines. - External, foreign and sub-object budgets rename their parameters like the costs overviews (
refid→referencePortfolioId,beg→start,currency→targetCurrencyId), andendis now exclusive. Every entry carries the referencesbudgetPositionandprojectPortfolio.SubObjis spelledSubObject. For a project, the foreign and sub-object budgets report the amount the costs timeline carries over the requested period instead of the whole assigned amount, so that they add up to the external budgets.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
addProjectCostsPosition |
POST ProjectCosts/ |
addCostsPosition |
POST ProjectCosts/ |
addProjectCostsPositionActual |
POST ProjectCosts/ |
addCostsActual |
POST CostsPosition/ |
delCostsTypeGroupTranslated |
DELETE CostsTypeGroup/ |
delCostsTypeGroupTranslated |
DELETE CostsTypeGroup/ |
delCostsTypeTranslated |
DELETE CostsType/ |
delCostsTypeTranslated |
DELETE CostsType/ |
delCurrency |
DELETE Currency/:currencyId |
delCurrencyTranslated |
DELETE Currency/ |
delCurrencyExchangeRateAt |
DELETE Currency/ |
delCurrencyExchangeRateAt |
DELETE Currency/ |
delProjectCostsPosition |
DELETE ProjectCosts/ |
delCostsPosition |
DELETE CostsPosition/:costsPositionId |
delProjectCostsPositionActual |
DELETE ProjectCosts/ |
delCostsActual |
DELETE CostsActual/:costsActualId |
getCurrencyExchangeRateAt |
GET Currency/ |
getCurrencyExchangeRateAt |
GET Currency/ |
getPortfolioBudgetAssignmentParents |
GET PortfolioBudgetAssignment/ |
getPortfolioBudgetAssignmentParents |
GET PortfolioBudgetAssignment/ |
getPortfolioBudgetPositionParent |
GET PortfolioBudgetPosition/ |
getBudgetPositionParent |
GET BudgetPosition/ |
getProjectBudgetAssignmentParents |
GET ProjectBudgetAssignment/ |
getProjectBudgetAssignmentParents |
GET ProjectBudgetAssignment/ |
getTodaysCurrencyExchangeRate |
GET Currency/ |
getCurrencyExchangeRateToday |
GET Currency/ |
putCurrencyExchangeRateAt |
PUT Currency/ |
putCurrencyExchangeRateAt |
PUT Currency/ |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
addPortfolioBudgetPosition |
POST PortfolioCosts/ |
addBudgetPosition |
POST ProjectPortfolio/ |
Names the sort index sortIndex and the currency currencyId, and also takes name, code, description, color, iconRef, periodStart and periodEnd; inheriting via inheritFrom is addPortfolioBudgetAssignment (POST ProjectPortfolio/), which takes budgetPositionId and currencyId and no sort index |
addProjectBudgetPosition |
POST ProjectCosts/ |
addProjectBudgetAssignment |
POST Project/ |
Names the granting portfolio sourcePortfolioId, the budget position budgetPositionId and the currency currencyId; takes the root budget position only, not the ID of a budget assignment |
calculateSum |
POST Calculator/Sum |
calculateSum |
POST Calculator/Sum |
Names the currency currencyId |
convertCurrency |
GET CurrencyExchange/ |
convertCurrency |
GET CurrencyExchange/ |
Names the currency currencyId |
delPortfolioBudgetPosition |
DELETE PortfolioCosts/ |
delBudgetPosition |
DELETE BudgetPosition/ |
Addressed by the position's ID alone; a share assigned to the portfolio is deleted with delPortfolioBudgetAssignment (DELETE PortfolioBudgetAssignment/) |
delProjectBudgetPosition |
DELETE ProjectCosts/ |
delProjectBudgetAssignment |
DELETE ProjectBudgetAssignment/ |
Addressed by the assignment's ID alone, without the project |
getCostsCenter |
GET CostsCenter/:costsCenterId |
getCostsCenterEnumType |
GET CostsCenterEnumType |
Costs centers are values of a fixed PF enum type; this returns the type's reference, read the value with PF getEnumValue |
getCostsCenters |
GET CostsCenters |
getCostsCenterEnumType |
GET CostsCenterEnumType |
Costs centers are values of a fixed PF enum type; this returns the type's reference, PF getAllEnumValues returns references to the values, read them with PF getEnumValues |
getCostsType |
GET CostsType/:costsTypeId |
getCostsType |
GET CostsType/:costsTypeId |
Returns the group's ID in groupId instead of the nested group; read the group with getCostsTypeGroup |
getCostsTypeGroup |
GET CostsTypeGroup/ |
getCostsTypeGroup |
GET CostsTypeGroup/ |
Response body changed |
getCostsTypeGroups |
GET CostsTypeGroups |
getAllCostsTypeGroups |
GET CostsTypeGroups |
Returns references; read them with getCostsTypeGroups, which reads by ID |
getCostsTypeGroupsTranslated |
GET CostsTypeGroups/ |
getAllCostsTypeGroups |
GET CostsTypeGroups |
Returns references; read them with getCostsTypeGroupsTranslated, which reads by ID |
getCostsTypeGroupTranslated |
GET CostsTypeGroup/ |
getCostsTypeGroupTranslated |
GET CostsTypeGroup/ |
Response body changed |
getCostsTypes |
GET CostsTypes |
getAllCostsTypes |
GET CostsTypes |
Returns references with the parent group; read them with getCostsTypes, which reads by ID |
getCostsTypesTranslated |
GET CostsTypes/WithTranslations |
getAllCostsTypes |
GET CostsTypes |
Returns references with the parent group; read them with getCostsTypesTranslated, which reads by ID |
getCostsTypeTranslated |
GET CostsType/ |
getCostsTypeTranslated |
GET CostsType/ |
Returns the group's ID in groupId instead of the nested group |
getCurrencies |
GET Currencies |
getAllCurrencies |
GET Currencies |
Returns references; read them with getCurrencies, which reads by ID |
getCurrency |
GET Currency/:currencyId |
getCurrency |
GET Currency/:currencyId |
Response body changed |
getCurrencyExchangeRates |
GET Currency/ |
getCurrencyExchangeRates |
GET Currency/ |
Answers 404 for an unknown currency instead of an empty rate set |
getHomeCurrency |
GET HomeCurrency |
getHomeCurrency |
GET HomeCurrency |
Response body changed |
getMacroAllocationPlannedCosts |
GET MacroAllocationCosts/ |
getResourceAllocationPlannedCosts |
GET ResourceAllocationCosts/ |
The macro allocation is called a resource allocation |
getPayPlan |
GET PayPlan/:payPlanId |
getPayPlanEnumType |
GET PayPlanEnumType |
Pay plans are values of a fixed PF enum type; this returns the type's reference, read the value with PF getEnumValue |
getPayPlans |
GET PayPlans |
getPayPlanEnumType |
GET PayPlanEnumType |
Pay plans are values of a fixed PF enum type; this returns the type's reference, PF getAllEnumValues returns references to the values, read them with PF getEnumValues |
getPortfolioBudgetPosition |
GET PortfolioCosts/ |
getBudgetPosition |
GET BudgetPosition/ |
Addressed by the position's ID alone; a share assigned to the portfolio is read with getPortfolioBudgetAssignment (GET PortfolioBudgetAssignment/) |
getPortfolioBudgetPositions |
GET PortfolioCosts/ |
getAllBudgetPositionsOfProjectPortfolio |
GET ProjectPortfolio/ |
Returns references to the positions the portfolio owns, with the portfolio as parent; read them with getBudgetPositions, which reads by ID. Inherited positions are not listed — read them with getPortfolioBudgetLines |
getPortfolioBudgetPositionTimeline |
GET PortfolioCosts/ |
getBudgetPositionTimeline |
GET BudgetPosition/ |
Addressed by the position's ID alone; names the range from / until, adds limit, drops currency and returns a pf.VersionTimeline with the latest version per slot; the timeline of an assignment is getPortfolioBudgetAssignmentTimeline |
getPortfolioCostsOverview |
GET PortfolioCosts/:ppfId/Overview |
getPortfolioCostsOverview |
GET PortfolioCosts/ |
Names the reference portfolio referencePortfolioId, the range start / end and the currency targetCurrencyId; the costs overview has a different structure |
getPortfolioCostsTimeline |
GET PortfolioCosts/ |
getPortfolioCostsTimeline |
GET PortfolioCosts/ |
Renamed parameters and filters (see above); the costs matrix has a different structure |
getPortfolioExternalBudgets |
GET PortfolioCosts/ |
getPortfolioExternalBudgets |
GET PortfolioCosts/ |
Names the reference portfolio referencePortfolioId, the range start / end (end now exclusive) and the currency targetCurrencyId; every entry carries the references budgetPosition and projectPortfolio |
getPortfolioForeignBudgets |
GET PortfolioCosts/ |
getPortfolioForeignBudgets |
GET PortfolioCosts/ |
Parameters and entries as getPortfolioExternalBudgets |
getPortfoliosBudgetPositions |
GET PortfoliosCosts/ |
getAllBudgetPositions |
GET BudgetPositions |
No portfolioid filter: returns references to the positions owned by all portfolios, each with its portfolio as parent; read them with getBudgetPositions, which reads by ID. Inherited positions are not listed — read them with getPortfoliosBudgetLines |
getPortfoliosCostsOverviews |
GET PortfoliosCosts/Overviews |
getPortfoliosCostsOverviews |
GET PortfoliosCosts/ |
Takes the portfolio IDs in the path instead of portfolioid; parameters and response as getPortfolioCostsOverview |
getPortfolioSubObjBudgets |
GET PortfolioCosts/ |
getPortfolioSubObjectBudgets |
GET PortfolioCosts/ |
Spelled SubObject; parameters and entries as getPortfolioExternalBudgets |
getProjectBudgetPosition |
GET ProjectCosts/ |
getProjectBudgetAssignment |
GET ProjectBudgetAssignment/ |
Addressed by the assignment's ID alone, without the project |
getProjectBudgetPositions |
GET ProjectCosts/ |
getProjectBudgetLines |
GET Project/:projectId/BudgetLines |
Returns the project's budget lines with the calculated amounts, each naming the assignment behind it; read the assignments with getProjectBudgetAssignments |
getProjectCostsActuals |
GET ProjectCosts/ |
getCostsActualsOfProject |
GET ProjectCosts/ |
Returns references, no longer grouped by costs position — sort by costsPositionId or call getCostsActualsOfCostsPosition per position to rebuild the groups; read the actuals with getCostsActuals |
getProjectCostsOverview |
GET ProjectCosts/:prjId/Overview |
getProjectCostsOverview |
GET ProjectCosts/ |
Names the reference portfolio referencePortfolioId, the range start / end and the currency targetCurrencyId; the costs overview has a different structure |
getProjectCostsPosition |
GET ProjectCosts/ |
getCostsPosition |
GET CostsPosition/:costsPositionId |
Addressed by the costs position's ID alone; returns costsTypeId / costsCenterId / payPlanId and the amounts as entered — read the converted and calculated amounts with getCostsPositionConverted |
getProjectCostsPositionActual |
GET ProjectCosts/ |
getCostsActual |
GET CostsActual/:costsActualId |
Addressed by the costs actual's ID alone; returns the amount as entered — read the converted amount with getCostsActualConverted |
getProjectCostsPositionActualParents |
GET ProjectCostsPositionActual/ |
getCostsActual |
GET CostsActual/:costsActualId |
Obsolete: an actual reports its one parent in costsPositionId |
getProjectCostsPositionActuals |
GET ProjectCosts/ |
getCostsActualsOfCostsPosition |
GET CostsPosition/ |
Returns references with the costs position as parent; read the actuals with getCostsActuals, which reads by ID |
getProjectCostsPositionCostsTimeline |
GET ProjectCosts/ |
getCostsPositionCostsTimeline |
GET CostsPosition/ |
Addressed by the costs position's ID alone; renamed parameters and filters (see above); the costs matrix has a different structure |
getProjectCostsPositionParents |
GET ProjectCostsPosition/ |
getAllCostsPositions |
GET CostsPositions |
Obsolete: a costs position has exactly one parent, its project, reported in projectId and as the parent of each reference |
getProjectCostsPositions |
GET ProjectCosts/ |
getCostsPositionsOfProject |
GET ProjectCosts/ |
Returns references with the project as parent; read the positions with getCostsPositions, which reads by ID |
getProjectCostsTimeline |
GET ProjectCosts/ |
getProjectCostsTimeline |
GET ProjectCosts/ |
Renamed parameters and filters (see above); the costs matrix has a different structure |
getProjectExternalBudgets |
GET ProjectCosts/ |
getProjectExternalBudgets |
GET ProjectCosts/ |
Names the reference portfolio referencePortfolioId, the range start / end (end now exclusive) and the currency targetCurrencyId; every entry carries the references budgetPosition and projectPortfolio |
getProjectForeignBudgets |
GET ProjectCosts/ |
getProjectForeignBudgets |
GET ProjectCosts/ |
Parameters and entries as getProjectExternalBudgets; reports the amount the costs timeline carries over the requested period instead of the whole assigned amount |
getProjectPhasePlannedCosts |
GET ProjectPhaseCosts/ |
getProjectWorkItemPlannedCosts |
GET ProjectWorkItemCosts/ |
The phase is called a project work item (section 6) |
getProjectsBudgetPositions |
GET ProjectsCosts/BudgetPositions |
getProjectsBudgetLines |
GET Projects/ |
Takes the project IDs in the path instead of projectid; returns budget lines as getProjectBudgetLines |
getProjectScenarioCostsOverview |
GET ScenarioCosts/ |
getProjectScenarioCostsOverview |
GET ScenarioCosts/ |
Names the reference portfolio referencePortfolioId, the range start / end and the currency targetCurrencyId; the costs overview has a different structure |
getProjectScenarioCostsTimeline |
GET ScenarioCosts/ |
getProjectScenarioCostsTimeline |
GET ScenarioCosts/ |
Renamed parameters and filters (see above); the costs matrix has a different structure |
getProjectsCostsOverviews |
GET ProjectsCosts/Overviews |
getProjectsCostsOverviews |
GET ProjectsCosts/ |
Takes the project IDs in the path instead of projectid; parameters and response as getProjectCostsOverview |
getProjectSubObjBudgets |
GET ProjectCosts/ |
getProjectSubObjectBudgets |
GET ProjectCosts/ |
Spelled SubObject; parameters, entries and amounts as getProjectForeignBudgets |
moveCostsPositionActual |
POST ProjectCosts/ |
moveCostsPositionActual |
POST CostsPosition/ |
No project in the path; the target costs position is a mandatory path segment instead of the optional targetId; checks the update permission on both positions |
putCostsTypeGroupsTranslated |
PUT CostsTypeGroups/ |
putCostsTypeGroupTranslated |
PUT CostsTypeGroup/ |
No bulk write; write the groups one at a time |
putCostsTypeGroupTranslated |
PUT CostsTypeGroup/ |
putCostsTypeGroupTranslated |
PUT CostsTypeGroup/ |
Takes the V3 CostsTypeGroupTranslated as its body |
putCostsTypesTranslated |
PUT CostsTypes/WithTranslations |
putCostsTypeTranslated |
PUT CostsType/ |
No bulk write; write the costs types one at a time |
putCostsTypeTranslated |
PUT CostsType/ |
putCostsTypeTranslated |
PUT CostsType/ |
Takes the V3 CostsTypeTranslated as its body, with groupId instead of the nested group |
putCurrency |
PUT Currency/:currencyId |
putCurrencyTranslated |
PUT Currency/ |
Takes the V3 CurrencyTranslated as its body, with all translations |
putPortfolioBudgetPosition |
PUT PortfolioCosts/ |
putBudgetPosition |
PUT BudgetPosition/ |
Addressed by the position's ID alone; a share assigned to the portfolio is written with putPortfolioBudgetAssignment (PUT PortfolioBudgetAssignment/) |
putProjectBudgetPosition |
PUT ProjectCosts/ |
putProjectBudgetAssignment |
PUT ProjectBudgetAssignment/ |
Addressed by the assignment's ID alone, without the project; writes only the amount |
putProjectCostsPosition |
PUT ProjectCosts/ |
putCostsPosition |
PUT CostsPosition/:costsPositionId |
Addressed by the costs position's ID alone; the body takes costsTypeId / costsCenterId / payPlanId instead of references, and its projectId must not differ from the stored one |
putProjectCostsPositionActual |
PUT ProjectCosts/ |
putCostsActual |
PUT CostsActual/:costsActualId |
Addressed by the costs actual's ID alone; moving it to another costs position is moveCostsPositionActual |
New in V3 — no V2 equivalent.
getAllBudgetAssignmentsOfProject, getAllBudgetAssignmentsOfProjectPortfolio, getAllPortfoliosBudgetAssignments, getAllProjectsBudgetAssignments, getCostsActualIdentification, getCostsActualIdentifications, getCostsActualsConverted, getCostsPositionIdentification, getCostsPositionIdentifications, getCostsPositionsConverted, getCurrenciesTranslated, getCurrencyTranslated, getPortfolioBudgetAssignments
LCY — Lifecycles
Fully migrated, but 27 of 34 endpoints are reimplemented rather than redirected: the lifecycle contracts were rebuilt around references and explicit sub-states. Budget time for this module even though nothing is retired.
New capability worth adopting: getAllStates and getAllTransitions for the reference lists,
getObjectsByStates to query several states at once, and getStateSubStates / getStateAllSubStates for the
sub-state hierarchy.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
delStateTranslated |
DELETE State/ |
delStateTranslated |
DELETE State/ |
delSubStateTranslated |
DELETE State/ |
delSubStateTranslated |
DELETE State/ |
delTransitionTranslated |
DELETE Transition/ |
delTransitionTranslated |
DELETE Transition/ |
delTypeInitialState |
DELETE Type/:objtype/InitialState |
delTypeInitialState |
DELETE Type/:objectType/InitialState |
getObjectsByState |
GET State/ |
getObjectsByState |
GET State/ |
getStuckObjects |
GET Objects/:objtype/Stuck |
getStuckObjects |
GET Objects/:objectType/Stuck |
putTypeInitialState |
PUT Type/:objtype/InitialState |
putTypeInitialState |
PUT Type/:objectType/InitialState |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
getInitialStates |
GET InitialStates |
getInitialStates |
GET InitialStates |
Returns references to the states and sub-states together with the object type, and getStates to read the states by ID |
getObjectHistory |
GET Object/:objtype/:objid/History |
getObjectHistory |
GET Object/ |
Returns the entries newest first with references to the state, the transition and the initiating user |
getObjectReachableStates |
GET Object/ |
getObjectReachableStates |
GET Object/ |
Returns references to the states; read them with getStates |
getObjectsHistories |
GET Objects/ |
getObjectsHistories |
GET Objects/ |
Returns the entries newest first with references to the state, the transition and the initiating user |
getObjectsReachableStates |
GET Objects/ |
getObjectsReachableStates |
GET Objects/ |
Returns references to the states; read them with getStates |
getObjectsStates |
GET Objects/ |
getObjectsStates |
GET Objects/ |
Returns references to the states and sub-states, and getStates to read the states by ID |
getObjectState |
GET Object/:objtype/:objid/State |
getObjectState |
GET Object/ |
Returns references to the state and sub-state, and getState to read the state |
getObjectsTransitions |
GET Objects/ |
getObjectsTransitions |
GET Objects/ |
Returns references to the transitions; read them with getTransitions |
getObjectTransitions |
GET Object/ |
getObjectTransitions |
GET Object/ |
Returns references to the transitions; read them with getTransitions |
getState |
GET State/:stateId |
getState |
GET State/:stateId |
Response body changed |
getStateReachableStates |
GET State/:stateId/ReachableStates |
getStateReachableStates |
GET State/:stateId/ReachableStates |
Returns references to the states; read them with getStates |
getStates |
GET States |
getAllStates |
GET States |
Returns references; read them with getStates |
getStatesTranslated |
GET States/WithTranslations |
getAllStates |
GET States |
Returns references; read them with getStatesTranslated |
getStateTransitions |
GET State/:stateId/Transitions |
getStateTransitions |
GET State/:stateId/Transitions |
Returns references to the transitions; read them with getTransitions |
getStateTranslated |
GET State/ |
getStateTranslated |
GET State/ |
Response body changed |
getSubStatesTranslated |
GET State/ |
getStateAllSubStates |
GET State/:stateId/SubStates |
Returns references; read them with getSubStatesTranslated |
getSubStateTranslated |
GET State/ |
getSubStateTranslated |
GET State/ |
Response body changed |
getTransition |
GET Transition/:transitionId |
getTransition |
GET Transition/:transitionId |
from and to are references to the state and sub-state; read the states with getStates |
getTransitions |
GET Transitions |
getAllTransitions |
GET Transitions |
Returns references; read them with getTransitions |
getTransitionTranslated |
GET Transition/ |
getTransitionTranslated |
GET Transition/ |
Response body changed |
getTypeInitialState |
GET Type/:objtype/InitialState |
getTypeInitialState |
GET Type/:objectType/InitialState |
Returns references to the state and sub-state, and getState to read the state |
getTypeReachableStates |
GET Type/:objtype/ReachableStates |
getTypeReachableStates |
GET Type/ |
Returns references to the states; read them with getStates |
migrateObjects |
POST Objects/ |
migrateObjects |
POST Objects/ |
Takes the remark in its body as the V3 LifecycleUpgradeRemark |
putStateTranslated |
PUT State/ |
putStateTranslated |
PUT State/ |
Takes the V3 LifecycleStateTranslated as its body |
putSubStateTranslated |
PUT State/ |
putSubStateTranslated |
PUT State/ |
Takes the V3 LifecycleSubStateTranslated as its body |
putTransitionTranslated |
PUT Transition/ |
putTransitionTranslated |
PUT Transition/ |
Takes the V3 LifecycleTransitionTranslated as its body |
upgradeObject |
POST Object/ |
upgradeObject |
POST Object/ |
Takes the remark in its body as the V3 LifecycleUpgradeRemark and returns references to the reached state and sub-state |
New in V3 — no V2 equivalent.
getObjectsByStates, getStateSubStates, getTransitionsTranslated
LIC — Licensing
getLicenseStatus is the only LIC endpoint that stays available to public-API and JavaScript callers, and it is
the one an integration normally wants: it reports what the tenant is licensed for.
The licence administration endpoints — getLicenses, putLicenses, getUsages, initTenants — moved to the
maintenance interface in V3 and cannot be called with a bearer token. If your tooling uses them, it needs the
maintenance access kind, which is a different authentication mechanism entirely.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
getLicenses |
GET Licenses |
getLicenses |
GET Licenses |
V3 successor is reachable only from the browser client or the maintenance interface |
getLicenseStatus |
GET License/Status |
getLicenseStatus |
GET License/Status |
Names the members validUntil and admin expiry and adminEmail |
getUsages |
GET Licenses/Usage |
getUsages |
GET Licenses/Usage |
V3 successor is reachable only from the browser client or the maintenance interface |
initTenants |
POST Tenants/Init |
initTenants |
POST Tenants/Init |
V3 successor is reachable only from the browser client or the maintenance interface |
putLicenses |
PUT Licenses |
putLicenses |
PUT Licenses |
V3 successor is reachable only from the browser client or the maintenance interface |
MAIN — Server information and session start
getStartUrl→getHomeUrl(JavaScript only).- The OpenAPI description endpoints lose the standard-version segment from their URL and now emit OpenAPI 3.2.0;
getTypeScriptDefinitionis new. See section 3. getVersion(GET /API/V3/MAIN/Versions) is unchanged in spirit and is still the recommended compatibility check at start-up.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
getObjectUrl |
JS only |
getObjectUrl |
JS only |
getServerStatus |
GET ServerStatus |
dgn.getServerStatus |
GET DGN/ServerStatus |
getStartUrl |
JS only |
getHomeUrl |
JS only |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
getOpenApi3Json |
GET ApiDescription/ |
getOpenApi3Json |
GET ApiDescription/OpenApi/Json |
Describes API V3 in OpenAPI 3.2.0; an OpenAPI 3.0.3 rendition is not available |
getOpenApi3Yaml |
GET ApiDescription/ |
getOpenApi3Yaml |
GET ApiDescription/OpenApi/Yaml |
Describes API V3 in OpenAPI 3.2.0; an OpenAPI 3.0.3 rendition is not available |
getVersion |
GET Versions |
getVersion |
GET Versions |
Reports the version and fingerprint of API V3 |
New in V3 — no V2 equivalent.
getTypeScriptDefinition
MSG — Messages, forwarding rules and mail
The inbox and the forwarding rules of the calling user now live under CurrentUser/; an administrator manages
another resource's rules under Resource/:resourceId/.
- Inbox:
getAllCurrentUserMessagesreturns references (most recent first, sortable,includeReadnow really filters),getCurrentUserMessage/getCurrentUserMessagesreturn the messages. In a message,source,trigger,createdByand every shown addressee are references; the trigger's text moved totriggerReason. Reading and deleting act on the caller's own copy only — the other recipients keep theirs. Both were not implemented in V2 and work now, on the V2 URL as well. - Forwarding rules:
getAll…MessageForwardRulesreturns references in the order the rules are applied; reading and deleting are bulk operations, and a rule of another resource is simply not found.subjectRegExwas never stored in V2 and is now. A regular expression that does not compile answers422, and a rule ID must be a well-formed UUID. - Posting:
postCurrentUserMessageanswers201. Theurgency/privacyvalues are spelledBreakingNews,Public, … instead ofBREAKING_NEWS,PUBLIC, and an addressee without a user answers422. forwardedAtis now filled when a message was forwarded by email.
If you maintain forwarding rules that filter on an object type pattern, read section 6: a pattern written to match the old work-item type name no longer matches work items.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
delMessage |
DELETE Message/:messageId |
delCurrentUserMessage |
DELETE CurrentUser/Message/:messageId |
getMessageTriggers |
GET MessageTriggers |
getAllMessageTriggers |
GET MessageTriggers |
putMessageForwardRule |
PUT ForwardRule/:forwardRuleId |
putCurrentUserMessageForwardRule |
PUT CurrentUser/ |
putMessageForwardRuleOfResource |
PUT Resource/ |
putResourceMessageForwardRule |
PUT Resource/ |
readMessage |
POST Message/:messageId/Read |
readCurrentUserMessage |
POST CurrentUser/ |
sendMail |
JS only |
sendMail |
JS only |
sendMailByTemplate |
JS only |
sendMailByTemplate |
JS only |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
delMessageForwardRule |
DELETE ForwardRule/:forwardRuleId |
delCurrentUserMessageForwardRules |
DELETE CurrentUser/ |
Bulk operation |
delMessageForwardRuleOfResource |
DELETE Resource/ |
delResourceMessageForwardRules |
DELETE Resource/ |
Bulk operation |
getMessage |
GET Message/:messageId |
getCurrentUserMessage |
GET CurrentUser/Message/:messageId |
Response body changed |
getMessageForwardRule |
GET ForwardRule/:forwardRuleId |
getCurrentUserMessageForwardRules |
GET CurrentUser/ |
Bulk operation |
getMessageForwardRuleOfResource |
GET Resource/ |
getResourceMessageForwardRules |
GET Resource/ |
Bulk operation |
getMessageForwardRules |
GET ForwardRules |
getAllCurrentUserMessageForwardRules + getCurrentUserMessageForwardRules |
GET CurrentUser/ |
References, then bulk read |
getMessageForwardRulesOfResource |
GET Resource/ |
getAllResourceMessageForwardRules + getResourceMessageForwardRules |
GET Resource/ |
References, then bulk read |
getMessages |
GET Messages |
getAllCurrentUserMessages + getCurrentUserMessages |
GET CurrentUser/Messages |
References, then bulk read |
postMessage |
POST Message/Post |
postCurrentUserMessage |
POST CurrentUser/Message/Post |
Request body changed |
MTG — Meetings
Meetings and meeting groups are full V3 object families now: identifications, version timelines, historic
versions, and getAllMeetings / getAllMeetingGroups reference lists, plus getRootMeetingGroups.
copyMeetingis retired: calladdMeetingwith thecopyparameter (andcopyRelationsto carry relations over). This is the general V3 pattern — copying is an option of creating, not an endpoint of its own.getMeetingsByRefis replaced by the general relation mechanism,pf.getAllRelations. Read the object's relations, then read the meetings you found among them.addMeetingGroupmoved fromPOST MeetingGroupstoPOST MeetingGroups/Add, in line with the house form.getSubGroupsOfMeetingGroupbecomesgetSubGroupsOfMeetingGroup.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
addMeeting |
POST MeetingGroup/ |
addMeeting |
POST MeetingGroup/ |
addMeetingGroup |
POST MeetingGroups |
addMeetingGroup |
POST MeetingGroups/Add |
addMeetingGroupSubGroup |
POST MeetingGroup/ |
addMeetingGroupSubGroup |
POST MeetingGroup/ |
delMeeting |
DELETE Meeting/:meetingId |
delMeeting |
DELETE Meeting/:meetingId |
delMeetingGroup |
DELETE MeetingGroup/:groupId |
delMeetingGroup |
DELETE MeetingGroup/:meetingGroupId |
moveGroup |
POST MeetingGroup/ |
moveGroup |
POST MeetingGroup/:groupId/Move |
moveGroupToTop |
POST MeetingGroup/ |
moveGroupToTop |
POST MeetingGroup/ |
moveMeeting |
POST Meeting/:meetingId/Move |
moveMeeting |
POST Meeting/:meetingId/Move |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
getMeeting |
GET Meeting/:meetingId |
getMeeting |
GET Meeting/:meetingId |
Response body changed |
getMeetingGroup |
GET MeetingGroup/:groupId |
getMeetingGroup |
GET MeetingGroup/:meetingGroupId |
Response body changed |
getMeetingGroups |
GET MeetingGroups |
getAllMeetingGroups |
GET MeetingGroups |
Returns references; read them with getMeetingGroups |
getMeetings |
GET Meetings |
getAllMeetings |
GET Meetings |
Returns references; read them with getMeetings; the state filter is gone |
getMeetingsByRef |
GET Meetings/ |
pf.getAllRelations |
GET PF/ |
Parameter list changed |
getMeetingsOfGroup |
GET MeetingGroup/:groupId/Meetings |
getMeetingsOfGroup |
GET MeetingGroup/:groupId/Meetings |
Returns references to the meetings of the group; read them with getMeetings; the state filter is not available |
getSubGroups |
GET MeetingGroup/ |
getSubGroupsOfMeetingGroup |
GET MeetingGroup/ |
Returns references to the sub groups; read them with getMeetingGroups |
putMeeting |
PUT Meeting/:meetingId |
putMeeting |
PUT Meeting/:meetingId |
Takes the V3 Meeting as its body |
putMeetingGroup |
PUT MeetingGroup/:groupId |
putMeetingGroup |
PUT MeetingGroup/:meetingGroupId |
Takes the V3 MeetingGroup as its body and only updates an existing group; create one with addMeetingGroup or addMeetingGroupSubGroup |
Retired — no V3 successor; the endpoint disappears with API V2.
| V2 endpoint | V2 path | Note |
|---|---|---|
copyMeeting |
POST Meeting/:meetingId/Copy |
Use addMeeting with copy parameter, will be discontinued at end of 2028 |
New in V3 — no V2 equivalent.
getMeetingGroupIdentification, getMeetingGroupIdentifications, getMeetingGroupTimeline, getMeetingGroupVersion, getMeetingIdentification, getMeetingIdentifications, getMeetingTimeline, getMeetingVersion, getRootMeetingGroups
NAV — Navigation and search
The module is retired except for the full text search. See section 8.3.
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
getContextSearch |
GET Context/:type/:id/Search |
search |
POST Search |
Searches all object types, full text only (no start object, regex, recursive, ranking or followrelations); response is PF.ReferenceWithParent[] |
getSearch |
GET Type/:type |
search |
POST Search |
Searches all object types, full text only (no type, regex or ranking); response is PF.ReferenceWithParent[] |
Retired — no V3 successor; the endpoint disappears with API V2.
| V2 endpoint | V2 path | Note |
|---|---|---|
findObjects |
POST Find |
This endpoint will not be available in API V3 and will be discontinued at end of 2028 |
getContext |
GET Context/:type/:id |
Navigation will not be available in new client and will be discontinued at end of 2028 |
getMemberRangeSearch |
GET Type/:type/MemberRangeSearch |
This endpoint will not be available in API V3 and will be discontinued at end of 2028 |
getMemberRegexSearch |
GET Type/:type/MemberRegexSearch |
This endpoint will not be available in API V3 and will be discontinued at end of 2028 |
getMemberTextSearch |
GET Type/:type/MemberTextSearch |
This endpoint will not be available in API V3 and will be discontinued at end of 2028 |
getObject |
GET Object/:type/:id |
Navigation will not be available in new client and will be discontinued at end of 2028 |
getRootContext |
GET RootContext |
Navigation will not be available in new client and will be discontinued at end of 2028 |
getTypeInfos |
GET TypeInfos |
This endpoint will not be available in API V3 and will be discontinued at end of 2028 |
PF — Platform (relations, attachments, properties, enums, icons)
The platform module is where the general mechanisms live, so several other modules' endpoints resolve here.
- Relations are the general mechanism.
getAllRelationsreplaces module-specific "by reference" endpoints (mtg.getMeetingsByRef) and relation listings (acm.getUserRelations).delExplicitRelationis retired: delete a relation by naming its two ends, not by a relation ID. - Documents became proper families: document folders and document links have reference lists, parent lookups, sub-folder creation, and folder-scoped attachment adders.
- Moving a document folder or link takes two endpoints. V2 had one
Movecall whosefolderparameter meant "the top" when omitted; V3 splits that intoMoveTo(destination mandatory) andMoveToTop, so that each call can name the permission it needs. That is also why aputcannot move anything:putDocumentFolderandputDocumentLinkanswer400if the request body changes the parent folder. The move endpoints ask more than V2 did —UPDATEon the folder or link being moved andCREATEbelow the destination, where V2 only askedUPDATEon the owning object and never checked the destination at all. Moving a folder below itself or below one of its own sub-folders answers400. getExplicitRelationneeds both ends. Reading one requiresIDENTIFYon the relation's source object and on its target object — the same rule V2 applied, now documented. It is not redirected because V3'sRelationis both slimmer and differently keyed:typenow carries the relation type, where V2 put a fixedRelationthere and named the relation type inrelationType.- A relation's
typeis its relation type, everywhere. The reading endpoints —getExplicitRelation,getForwardRelations,getBackwardRelations,getAllRelationsand thegetCurrentUser…Relationstrio — reporttype= the relation type, and so does thepf.Referenceanswered byaddExplicitRelation. So the reference you get from Add is the(relationType, relationId)pair that addresses the relation, and you can feed it straight into the Get URL. This differs from V2, where the same Add call answered the fixedRelationtype — if you readtypeoff that response, it changes value when you move. The fixedRelationtype lives on only as a second identity on the change notification websocket: a relation is announced under both, so a listener is reached whichever one it subscribed to. - Enum values: the bulk
putEnumValues,putEnumValuesTranslatedanddelEnumValuesTranslatedare retired in favour of the single-value endpoints.getAllEnumTypesandgetAllEnumValuesare new. - Dynamic properties split in two —
PropertyDefinition…is the property,PropertyPresentation…is one client's presentation of it and carries the client in the URL. Every V2 property endpoint therefore maps to a presentation endpoint withclientIdClient4, except the type list, which is nowgetAllPropertyObjectTypesand redirects. Section 5.15 has the whole picture, including the order a live object'spropertiesarray comes in — read it before rewriting these calls. - Icons:
getIconis new, and it is what aniconRefof the form/API/V3/PF/Icon/<id>points at. - Attachments keep their binary / JSON / text variants (JavaScript only, as in V2). The
…AndLinkvariants gained the basic field initializers of section 5.8. - Retired without a successor:
getQrCode,getDataMatrix,getUserAgent,inspectConnection. Generate barcodes and parse user agents on your side. - Limits:
getMaxParallelRequestsmoved fromLimitations/toMaxParallelRequests Limits/MaxParallelRequestsand renamed its response member fromlimittomaxParallel. It is not redirected, so this one needs a rewrite.getServerConfig,getConfigandgetUndeleteLimitare unchanged and redirect — see section 5.13 for what each of them is for. - WebSocket:
getNewWebSocketConnectionredirects to the change-notification WebSocket. That makes it bearer-token only and limits it to change notifications (section 5.14).
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
addAttachment |
POST Attachment/Add |
addAttachment |
POST Attachment/Add |
addAttachmentBinary |
JS only |
addAttachmentBinary |
JS only |
addAttachmentJson |
JS only |
addAttachmentJson |
JS only |
addAttachmentText |
JS only |
addAttachmentText |
JS only |
addExplicitRelation |
POST ExplicitRelations/ |
addExplicitRelation |
POST ExplicitRelations/ |
delConfig |
DELETE Config/:configId |
delConfig |
DELETE Config/:configId |
delDocumentFolder |
DELETE DocFolders/ |
delDocumentFolder |
DELETE DocFolder/ |
delDocumentLink |
DELETE DocLinks/ |
delDocumentLink |
DELETE DocLink/ |
delEnumTypeTranslated |
DELETE Enum/ |
delEnumTypeTranslated |
DELETE EnumType/ |
delEnumValueTranslated |
DELETE Enum/ |
delEnumValueTranslated |
DELETE Enum/ |
delExplicitRelationTypeTranslated |
DELETE ExplicitRelationType/ |
delExplicitRelationTypeTranslated |
DELETE ExplicitRelationType/ |
delUniqueReadableCodeDef |
DELETE UniqueReadableCodeDef/:typeId |
delUniqueReadableCodeDef |
DELETE UniqueReadableCodeDef/:typeId |
getAttachment |
GET Attachment/:attachmentId |
getAttachment |
GET Attachment/:attachmentId |
getAttachmentBinary |
JS only |
getAttachmentBinary |
JS only |
getAttachmentDetails |
GET Attachment/ |
getAttachmentDetails |
GET Attachment/ |
getAttachmentJson |
JS only |
getAttachmentJson |
JS only |
getAttachmentText |
JS only |
getAttachmentText |
JS only |
getConfig |
GET Config/:configId |
getConfig |
GET Config/:configId |
getCurrentTenant |
GET Tenant/Current |
getCurrentTenant |
GET Tenant/Current |
getCurrentTenantLicenseFeatures |
GET Tenant/ |
getCurrentTenantLicenseFeatures |
GET Tenant/ |
getDefaultIcon |
GET DefaultIcon/:objType |
getDefaultIcon |
GET DefaultIcon/:objectType |
getNewWebSocketConnection |
POST WebSocket/Create |
createNewChangeNotificationWebSocket |
POST ChangeNotification/CreateNew |
getPropertyDefinitionTypes |
GET ObjectTypes/ |
getAllPropertyObjectTypes |
GET PropertyObjectTypes |
getRelationType |
GET RelationType/:relationType |
getRelationType |
GET RelationType/:relationType |
getServerConfig |
GET ServerConfig/:configKey |
getServerConfig |
GET ServerConfig/:configKey |
getUndeleteLimit |
GET UndeleteLimit |
getUndeleteLimit |
GET UndeleteLimit |
getUniqueReadableCodeDef |
GET UniqueReadableCodeDef/:typeId |
getUniqueReadableCodeDef |
GET UniqueReadableCodeDef/:typeId |
putConfig |
PUT Config/:configId |
putConfig |
PUT Config/:configId |
putUniqueReadableCodeDef |
PUT UniqueReadableCodeDef/:typeId |
putUniqueReadableCodeDef |
PUT UniqueReadableCodeDef/:typeId |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
addAttachmentAndLink |
POST Attachment/:objType/:objId/Add |
addAttachmentAndLink |
POST DocLinks/ |
Parameter list changed |
addAttachmentBinaryAndLink |
JS only |
addAttachmentBinaryAndLink |
JS only |
Parameter list changed |
addAttachmentJsonAndLink |
JS only |
addAttachmentJsonAndLink |
JS only |
Parameter list changed |
addAttachmentTextAndLink |
JS only |
addAttachmentTextAndLink |
JS only |
Parameter list changed |
addDocumentFolder |
POST DocFolders/:objType/:objId/Add |
addDocumentFolder |
POST DocFolders/ |
A folder inside another folder is added with addDocumentFolderSubFolder |
convertUnit |
GET UnitSystem/:systemId/Convert |
convertUnit |
GET UnitSystem/:systemId/Convert |
Returns the ID of the unit (unitId) instead of the unit itself; read the unit with getUnit |
delExplicitRelationByRef |
DELETE ExplicitRelations/ |
removeExplicitRelation |
POST ExplicitRelations/ |
HTTP method changed |
getAllRelations |
GET Relations/ |
getAllRelations |
GET Relations/ |
Reports the relation type as the type of each relation; read it with getRelationTypes for its name and whether it is explicit |
getAllRelationTypesForType |
GET RelationTypes/ |
getAllRelationTypesForType |
GET RelationTypes/ |
Returns references to the relation types; read them with getRelationTypes |
getBackwardRelations |
GET Relations/ |
getBackwardRelations |
GET Relations/ |
Reports the relation type as the type of each relation; read it with getRelationTypes for its name and whether it is explicit |
getBackwardRelationTypesForType |
GET RelationTypes/ |
getBackwardRelationTypesForType |
GET RelationTypes/ |
Returns references to the relation types; read them with getRelationTypes |
getCurrentTenantWithAdditionalData |
GET Tenant/ |
getCurrentTenantWithAdditionalData |
GET Tenant/ |
Response body changed |
getCurrentUserAllRelations |
GET Relations/OfCurrentUser/All |
getCurrentUserAllRelations |
GET Relations/OfCurrentUser/All |
Reports the relation type as the type of each relation; read it with getRelationTypes for its name and whether it is explicit |
getCurrentUserBackwardRelations |
GET Relations/ |
getCurrentUserBackwardRelations |
GET Relations/ |
Reports the relation type as the type of each relation; read it with getRelationTypes for its name and whether it is explicit |
getCurrentUserForwardRelations |
GET Relations/ |
getCurrentUserForwardRelations |
GET Relations/ |
Reports the relation type as the type of each relation; read it with getRelationTypes for its name and whether it is explicit |
getDocumentFolder |
GET DocFolders/ |
getDocumentFolder |
GET DocFolder/ |
Response body changed |
getDocumentFolderParent |
GET DocFolder/:folderId/Parent |
getDocumentFolderParent |
GET DocFolderParent/:folderId |
Response body changed |
getDocumentFolders |
GET DocFolders/:objType/:objId |
getAllDocumentFolders |
GET DocFolders/ |
Parameter list changed |
getDocumentLink |
GET DocLinks/ |
getDocumentLink |
GET DocLink/ |
Response body changed |
getDocumentLinkParent |
GET DocLink/:linkId/Parent |
getDocumentLinkParent |
GET DocLinkParent/:linkId |
Response body changed |
getDocumentLinks |
GET DocLinks/:objType/:objId |
getAllDocumentLinks |
GET DocLinks/:objectType/:objectId |
Parameter list changed |
getEnumType |
GET Enum/:typeId/Type |
getEnumType |
GET EnumType/:typeId |
Response body changed |
getEnumTypes |
GET Enum/Types |
getAllEnumTypes |
GET EnumTypes |
Returns references; read them with getEnumTypes |
getEnumTypeTranslated |
GET Enum/ |
getEnumTypeTranslated |
GET EnumType/ |
Response body changed |
getEnumValue |
GET Enum/:typeId/Value/:valueId |
getEnumValue |
GET Enum/:typeId/Value/:valueId |
Response body changed |
getEnumValues |
GET Enum/:typeId/Values |
getAllEnumValues |
GET Enum/:typeId/Values |
Returns references; read them with getEnumValues; deleted is gone |
getEnumValuesTranslated |
GET Enum/ |
getAllEnumValues |
GET Enum/:typeId/Values |
Returns references; read them with getEnumValuesTranslated |
getEnumValueTranslated |
GET Enum/ |
getEnumValueTranslated |
GET Enum/ |
Response body changed |
getExplicitRelation |
GET ExplicitRelation/ |
getExplicitRelation |
GET ExplicitRelation/ |
Response body changed — V3 Relation carries only type, id, source and target. explicit and name are gone, and relationType has no successor because type now holds the relation type itself, where V2 put a fixed Relation there |
getExplicitRelationTypesTranslated |
GET ExplicitRelationTypes/ |
getAllRelationTypes |
GET RelationTypes |
Returns references; pass implicit=false, then read them with getExplicitRelationTypesTranslated |
getExplicitRelationTypeTranslated |
GET ExplicitRelationType/ |
getExplicitRelationTypeTranslated |
GET ExplicitRelationType/ |
Response body changed |
getForwardRelations |
GET Relations/ |
getForwardRelations |
GET Relations/ |
Reports the relation type as the type of each relation; read it with getRelationTypes for its name and whether it is explicit |
getForwardRelationTypesForType |
GET RelationTypes/ |
getForwardRelationTypesForType |
GET RelationTypes/ |
Returns references to the relation types; read them with getRelationTypes |
getMaxParallelRequests |
GET Limitations/ |
getMaxParallelRequests |
GET Limits/MaxParallelRequests |
Reports the limit as maxParallel |
getPropertyDefinition |
GET PropertyDefinition/ |
getPropertyPresentation |
GET PropertyPresentation/ |
The client is part of the URL — pass Client4 |
getPropertyDefinitions |
GET ObjectType/ |
getAllPropertyPresentations |
GET PropertyPresentations/ |
The client is part of the URL — pass Client4 |
getPropertyDefinitionsTranslated |
GET ObjectType/ |
getAllPropertyPresentationsTranslated |
GET PropertyPresentations/ |
The client is part of the URL — pass Client4 |
getRelationTypes |
GET RelationTypes |
getAllRelationTypes |
GET RelationTypes |
Returns references; read them with getRelationTypes |
getUniqueReadableCodeDefs |
GET UniqueReadableCodeDefs |
getAllUniqueReadableCodeDefs |
GET UniqueReadableCodeDefs |
Response body changed |
getUnit |
GET UnitSystem/ |
getUnit |
GET UnitSystem/ |
Names the member abbr abbreviation |
getUnits |
GET UnitSystem/:systemId/Units |
getUnits |
GET UnitSystem/:systemId/Units |
Names the member abbr abbreviation |
getUnitsFactors |
GET UnitSystem/:systemId/Factors |
getUnitFactors |
GET UnitSystem/:systemId/Factors |
Names the unit unitId |
getUnitsPreference |
GET UnitSystem/ |
getUnitPreference |
GET UnitSystem/ |
Names the preferred units preferredUnitIds |
moveDocumentFolder |
POST DocFolders/ |
moveDocumentFolder + moveDocumentFolderToTop |
POST DocFolder/, POST DocFolder/ |
Two endpoints now: the destination folder is mandatory on MoveTo, and moving to the top has its own call instead of an omitted folder |
moveDocumentLink |
POST DocLinks/ |
moveDocumentLink + moveDocumentLinkToTop |
POST DocLink/, POST DocLink/ |
Two endpoints now: the destination folder is mandatory on MoveTo, and moving to the top has its own call instead of an omitted folder |
putDocumentFolder |
PUT DocFolders/ |
putDocumentFolder |
PUT DocFolder/ |
Request body changed |
putDocumentLink |
PUT DocLinks/ |
putDocumentLink |
PUT DocLink/ |
Request body changed |
putEnumTypeTranslated |
PUT Enum/ |
putEnumTypeTranslated |
PUT EnumType/ |
Takes the V3 IdentificationTranslated as its body |
putEnumValueTranslated |
PUT Enum/ |
putEnumValueTranslated |
PUT Enum/ |
Takes the V3 IdentificationTranslated as its body |
putExplicitRelationTypeTranslated |
PUT ExplicitRelationType/ |
putExplicitRelationTypeTranslated |
PUT ExplicitRelationType/ |
Takes the V3 ExplicitRelationTypeTranslated as its body |
putPropertyDefinitionsTranslated |
PUT ObjectType/ |
putAllPropertyPresentationsTranslated + putAllPropertyDefinitions |
PUT PropertyPresentations/, PUT PropertyDefinitions/ |
Two calls now: the definitions and the client's presentations of them are written separately |
putUnitsFactors |
PUT UnitSystem/:systemId/Factors |
putUnitFactors |
PUT UnitSystem/:systemId/Factors |
Body names the unit unitId |
putUnitsPreference |
PUT UnitSystem/ |
putUnitPreference |
PUT UnitSystem/ |
Body names the preferred units preferredUnitIds |
Retired — no V3 successor; the endpoint disappears with API V2.
| V2 endpoint | V2 path | Note |
|---|---|---|
delEnumValuesTranslated |
DELETE Enum/ |
Use single delete function, will be discontinued at end of 2028 |
delExplicitRelation |
DELETE ExplicitRelation/ |
delete relations by reference, will be discontinued at end of 2028 |
getDataMatrix |
GET Barcode/DataMatrix |
Will not be transferred to V3 and will be discontinued at end of 2028 |
getQrCode |
GET Barcode/QR |
Will not be transferred to V3 and will be discontinued at end of 2028 |
getUserAgent |
GET UserAgent |
Will not be transferred to V3 and will be discontinued at end of 2028 |
inspectConnection |
POST Connection/Inspect |
Will not be transferred to V3 and will be discontinued at end of 2028 |
putEnumValues |
PUT Enum/:typeId/Values |
This endpoint is deprecated since 4.06.0 and will be discontinued at end of 2028. Use PUT /API/ |
putEnumValuesTranslated |
PUT Enum/ |
Use single put function, will be discontinued at end of 2028 |
New in V3 — no V2 equivalent.
addDocumentFolderAttachmentAndLink, addDocumentFolderAttachmentBinaryAndLink, addDocumentFolderAttachmentJsonAndLink, addDocumentFolderAttachmentTextAndLink, addDocumentFolderDocumentLink, addDocumentFolderSubFolder, addDocumentLink, delPropertyDefinition, delPropertyPresentationTranslated, getAllDocumentFoldersOfFolder, getAllDocumentLinksOfFolder, getAllPropertyDefinitions, getDocumentFolders, getDocumentFoldersParents, getDocumentLinks, getDocumentLinksParents, getEnumTypesTranslated, getIcon, getPropertyDefinition, getPropertyPresentationTranslated, putPropertyDefinition, putPropertyPresentationTranslated
PI — Project items
addProjectItemByReffolds intoaddProjectItem, which now takesrelType/refType/refId(andforward) as optional parameters. The redirect handles it, so this is a URL change only.getProjectItemSummariesByReffolds intogetProjectItemsByRef— one endpoint, one shape.- Watch the plural type getter. V2's
getProjectItemTypesreturned all item types; in V3 that isgetAllProjectItemTypes, and the namegetProjectItemTypesnow means "the types with these IDs". Same name, different meaning. addProjectItemtakescolorId(a reference into a colour enum) where most modules takecolor.- New: item identifications, a version timeline and historic versions.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
addProjectItem |
POST ItemType/:type/Add |
addProjectItem |
POST ItemType/:type/Items/Add |
addProjectItemByRef |
POST ItemType/ |
addProjectItem |
POST ItemType/:type/Items/Add |
delProjectItem |
DELETE ItemType/:type/Item/:itemId |
delProjectItem |
DELETE ItemType/ |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
getProjectItem |
GET ItemType/:type/Item/:itemId |
getProjectItem |
GET ItemType/ |
No longer includes the lifecycle state; read it with lcy.getObjectState |
getProjectItems |
GET ItemType/:type/Items |
getAllProjectItems |
GET ItemType/:type/Items |
Returns references; state becomes states, lateststatechange becomes reachedAtOrAfter and requires states. Read the items with getProjectItems |
getProjectItemsByRef |
GET ItemType/ |
getProjectItemsByRef |
GET ItemType/ |
Parameter list changed |
getProjectItemSummariesByRef |
GET ItemType/ |
getProjectItemsByRef |
GET ItemType/ |
Parameter list changed |
getProjectItemType |
GET ItemType/:type |
getProjectItemType |
GET ItemType/:type |
Response body changed |
getProjectItemTypes |
GET ItemTypes |
getAllProjectItemTypes |
GET ItemTypes |
Response body changed |
putProjectItem |
PUT ItemType/:type/Item/:itemId |
putProjectItem |
PUT ItemType/ |
Takes the V3 ProjectItem as its body |
New in V3 — no V2 equivalent.
getProjectItemIdentification, getProjectItemIdentifications, getProjectItemTimeline, getProjectItemTypes, getProjectItemVersion
PM — Project management (projects, portfolios, reports, scenarios, work items)
The largest module, and fully migrated — every endpoint has a V3 successor or is retired.
- Read section 6 first. The work-item object type is now
ProjectWorkItem, and five V3 endpoint names were changed to spell the object out in full. getProjectschanged meaning. V2'sgetProjectsreturned every project in full. UsegetAllProjectsfor the reference list andgetProjects/:projectIdsfor a page of details (section 5.2). The same applies togetProjectIdentifications, and to portfolios, reports and scenarios.getProjectDetails/putProjectDetailsare retired: the object endpoints carry the same data.- Report indicators are a three-layer model in V3, addressable layer by layer. The tenant-wide definition,
the selection with a target on a project and the target/actual comparison on a report each have their own endpoints,
and each is split into a dimension and a detail - see
docs/pm-indicator-model.md. Two consequences for a V2 caller: a selection is now addressed by its own ID, not by the ID of the indicator definition it realises, and the whole-collectionputIndicatorSelectionsis replaced by one call per object. The twodelIndicatorIntl*endpoints redirect, and in doing so lose the:projectReportTypeIdsegment V2 used to check the definition against - a call naming the wrong report type used to do nothing and now deletes. - A definition is written in every language at once.
IndicatorDetail,IndicatorDimension,IndicatorClassificationandIndicatorClassificationValueare read in the user's language but written only through.../WithTranslations, withname,descriptionandiconRefas translation arrays - the same shapeputIndicatorIntlDetailDefandputIndicatorIntlDimensionDefuse in V2, so a write can no longer drop the translations it did not send. All four translated bodies arepf.BasicObjectTranslateds, so they also reportversionand the create/modify audit data; those members are server-managed and ignored on write. There is no single-language PUT on any of the four, and for the same reason noIdentificationendpoint on them. A classification scheme is flat in V3: its body no longer carries the steps, and a step is an addressable object of its own -IndicatorClassificationValue, read one by one or as references under the scheme it belongs to. V2'sputIndicatorIntlClassificationanddelIndicatorIntlClassificationare gone: neither ever had a server-side implementation, every call answered500, so no integration can have depended on them. Write a scheme throughpm.and each of its steps throughputIndicatorClassificationTranslated pm..putIndicatorClassificationValueTranslated - The latest report is a reference now, and one per parent.
getLatestProjectReportandgetLatestProjectPortfolioReportbecomegetLatestProjectReportOfProjectandgetLatestProjectPortfolioReportOfProjectPortfolio, each with a bulk sibling taking several parent IDs. They answer apf.ReferenceWithParentinstead of the full report - read it withgetProjectReport/getProjectPortfolioReport. The report type leaves the path and becomes the optionalreportTypeFilter; with several types the answer is the latest report of any of them, not one per type.statebecomesstateFilter,skipstays. The two...WithLatestReportsendpoints have no single successor: list the parents withgetAllProjects/getAllProjectPortfolios, call the bulk once per report type of interest, and read the reports withgetProjectReports/getProjectPortfolioReports. Their misspelled twingetAllProjectPortfoliosWithLatestReportsDeprecatedfollows the same recipe. - Reports of a project or portfolio are references too.
getProjectReportsandgetProjectReportsByTypebecomegetProjectReportsOfProject,getProjectPortfolioReportsandgetProjectPortfolioReportsByTypebecomegetProjectPortfolioReportsOfProjectPortfolio; the report type is always the optionalreportTypeFilter. The V3 endpoints of the old names,getProjectReports/getProjectPortfolioReports, are the bulk reads by report ID that turn those references into full reports. - The sub-work-item pair moved and changed shape.
addWorkItemSubWorkItembecomesaddProjectWorkItemSubWorkItemonProjectWorkItem/, and it no longer takes a request body: pass:workItemId/ SubWorkItems/ Add name,code,description,color,iconRef,start,endandsortIndexas query parameters instead (section 5.8).getWorkItemSubWorkItemsbecomesgetSubWorkItemsOfProjectWorkItemonProjectWorkItem/, takes:workItemId/ SubWorkItems depthandsortinstead ofversion, and returns references rather than full work items — read the ones you need withgetProjectWorkItems. - Portfolio scenarios are
PortfolioSimulationin V3, and the two names are not interchangeable. The object type was renamed fromPM-PFSCENARIOtoPortfolioSimulation; V2 keeps reporting the old value, V3 reports the new one, and a reference read from one API must never be compared with one read from the other. For the same reason the four endpoints that carry a body —getPortfolioScenarios,getPortfolioScenario,putPortfolioScenarioandaddPortfolioScenario— are not redirected to V3: a<redirectV3>is a real 307, so the client would receive the V3 body with the V3 type and bypass the V2 translation entirely. They stay V2-implemented until V2 reaches end of life.delPortfolioScenariois redirected: it has no body in either direction, so there is no type for the caller to read off it. - Portfolio milestones are a V3 object family now, addressed by their own ID. V2 reached a milestone
through its portfolio (
ProjectPortfolio/); V3 addresses it as:portfolioId/ Milestone/ :milestoneId ProjectPortfolioMilestone/, with the usual bulk, identification and delete endpoints beside it.:projectPortfolioMilestoneId addProjectPortfolioMilestoneanddelProjectPortfolioMilestoneare redirected — the delete now ignores the portfolio the V2 URL carried and deletes by milestone ID, so a call that named the wrong portfolio used to fail with400and now succeeds.addtakes the milestone position aspositioninstead ofat, and it is mandatory: a milestone has to sit somewhere on the time axis. It also accepts the basic object properties, and names the new milestone after its type whennameis omitted.getProjectPortfolioMilestoneandputProjectPortfolioMilestoneare not redirected: the V3 body is aCustomizedObjectand no longer carriesvalidityStart/validityUntil. V2'sgetProjectPortfolioMilestoneslisted one portfolio's milestones in full; in V3 that name is the bulk getter, and the list isgetProjectPortfolioMilestonesOfProjectPortfolio(references,includeParentPortfoliosinstead ofincludeparent) orgetAllProjectPortfolioMilestonestenant-wide. - Dependencies are addressed by their own ID now, and the ends are plain references. V2 reached a
dependency under
Dependency/:dependencyIdand answered a body that spelled out each end - its name, position, color, milestone kind and the chain of parents above it - plus aconstraintTypethat was alwaysMANUAL. V3 keepspredecessorandsuccessoras type-and-ID references and drops the rest: read the ends withgetProjectMilestone(s)resp.getProjectPortfolioMilestone(s), and go fromProjectMilestone.workItemIdtogetProjectWorkItemfor the task, its scenario and its project.addProjectDependencyanddelProjectDependencyare redirected;addtakes the two ends in camel case (predecessorType,predecessorId,successorType,successorId), all four mandatory and restricted toProjectMilestoneandProjectPortfolioMilestone, refuses an end that does not exist with404, and now also acceptsminDistanceandmaxDistance. All four lists - tenant-wide, per project, per portfolio and per scenario - aregetAll*and answer references, each one naming the scenarios and portfolios the dependency sits in, and all four take asort; read the dependencies themselves withgetProjectDependencies/:ids. Theversionparameter is gone from all of them - V3 has no historic read for a dependency. - Constraints between the milestones of one scenario are addressed by their own ID, and the scenario keeps
the create. V2 reached a constraint under
ProjectScenario/; V3 calls the object a:scenarioId/ Constraint/ :constraintId ProjectMilestoneConstraintand addresses it by its ID alone, reading the permission off the project scenario behind it -READto read,UPDATEto write - exactly as V2 did off the scenario in the URL.PUTno longer creates:addProjectScenarioMilestoneConstraintdoes, under the scenario, with a server-generated ID, and it answers a reference.putProjectMilestoneConstraintchanges the distances of a constraint that exists; its two ends and itsconstraintTypeare fixed, and a body that names other milestones is refused with422. Themovetarget/movesourceparameters are gone from the write and became an action of their own,fixProjectMilestoneConstraint, which takesmove=PREDECESSOR|SUCCESSOR(and theresourceIdfor workdays). The four mutually exclusive filters ofgetProjectConstraintsbecame three lists - per scenario, per work item and per milestone, the last with an optionaldirection- which answer references naming the two milestones each constraint connects; read the constraints themselves withgetProjectMilestoneConstraints/. The:ids advancedtaskdependencieslicense is enforced by the API now: onaddit is the presence ofminDistanceormaxDistancethat needs it, so passingminDistance=0without the license fails where V2 allowed it. - The two position proposals keep their URL and their behaviour, but are not redirected.
proposeWorkItemEndandproposeWorkItemStartbecomeproposeProjectWorkItemEndandproposeProjectWorkItemStart- the work item is spelled in full, as everywhere else on this resource - andmaxmoveis spelledmaxMove. The path, the bounds (720 >= maxMove > 0), theoptimizetasklicense and the body are unchanged, except that V3 names the milestonemilestoneIdwhere V2 saysobjectId. One answer is not: where V2 replied200with a JSONnull- a work item that is not a phase, that has no such end, or that no resource is allocated to, so that there is no workload to optimize - V3 replies404, the same corner case the move-pattern endpoints have. - The move-pattern endpoints are not redirected.
getMovePatternByWorkItem,getMovePatternByWorkItemStartandgetMovePatternByWorkItemEndbecomegetProjectWorkItemMovePattern,getProjectWorkItemStartMovePatternandgetProjectWorkItemEndMovePattern; URL and parameters are unchanged, the payload names the milestonemilestoneIdwhere V2 saysobjectId. One answer differs as well: where V2 replied200with a JSONnull— a work item without milestones of its own, or one that cannot move at all — V3 replies404. delMicroAllocationsmoved to ALC and is redirected there. Clearing the reservations a work item holds in the plan of one resource is a write on that resource's shift plan, so V3 spells italc.,unassignResourceShiftPlanByProjectWorkItem POST ALC/, where V2 saidResource/ :resourceId/ ShiftPlan/ ByProjectWorkItem/ :projectWorkItemId/ Delete POST ProjectWorkItem/. It deletes the same thing - every reservation of that work item on that resource, over the whole time the plan spans - and leaves the absences alone, and it still demands:workItemId/ DelMicroAllocations?res=. . . UPDATEon the work item. Two things differ: the second permission isRESERVEon the resource where V2 asked forPLAN, which is what every other write of reservations in V3 asks for; and a call that omits the mandatoryresruns into404at the V3 URL the redirect points at, where V2 answered400.- The shift plan of a work item keeps its URL, but the call that assigns it moved to ALC. The three calls on
the plan itself become
getProjectWorkItemShiftPlan,putProjectWorkItemShiftPlananddelProjectWorkItemShiftPlan- the work item is spelled in full, as everywhere else on this resource - and their paths stay as they were. What the plan means is unchanged: one pattern per resource shift of the tenant, as long as the work item is, counted from its start, and writing it reserves nothing. The delete is redirected; the read and the write are not, because a pattern names its shift by ID now:shift, a whole embeddedres.ResourceShift, becameshiftId, matchingalc.ResourceShiftPlanRow. Read the shifts themselves withres.getResourceShiftsif the names, colors or times are needed.assignWorkItemShiftPlanis the odd one out: laying the pattern onto a resource is a write on that resource's shift plan, so it joined its inverseunassignResourceShiftPlanByProjectWorkItemin ALC asassignResourceShiftPlanByProjectWorkItem- see the ALC section above for what changed with it. - Macro allocations moved to ALC as resource allocations. The seven V2 endpoints on
MacroAllocationare reimplemented in ALC - see the ALC section for the new object and what changed with it. - New capability worth adopting: identifications, timelines and historic versions for projects, portfolios,
reports, scenarios and work items; the report-type lists; the milestone endpoints; the scenario lookups
(
getScenariosOfProject,getActiveScenarioOfProjects); andgetProjectReportRecalculated.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
addProjectDependency |
POST Dependency/Add |
addProjectDependency |
POST ProjectDependencies/Add |
addProjectPortfolio |
POST ProjectPortfolios/Add |
addProjectPortfolio |
POST ProjectPortfolios/Add |
addProjectPortfolioMilestone |
POST ProjectPortfolio/ |
addProjectPortfolioMilestone |
POST ProjectPortfolio/ |
addProjectPortfolioProject |
POST ProjectPortfolio/ |
addProjectPortfolioProject |
POST ProjectPortfolio/ |
addProjectPortfolioReport |
POST ProjectPortfolio/ |
addProjectPortfolioReport |
POST ProjectPortfolio/ |
addProjectPortfolioSubPortfolio |
POST ProjectPortfolio/ |
addProjectPortfolioSubPortfolio |
POST ProjectPortfolio/ |
addProjectReport |
POST Project/ |
addProjectReport |
POST Project/ |
addProjectScenario |
POST Project/:projectId/AddScenario |
addProjectScenario |
POST Project/ |
assignWorkItemShiftPlan |
POST ProjectWorkItem/ |
alc. |
POST ALC/ |
delIndicatorIntlDetailDef |
DELETE Indicators/ |
delIndicatorDetailTranslated |
DELETE IndicatorDetail/ |
delIndicatorIntlDimensionDef |
DELETE Indicators/ |
delIndicatorDimensionTranslated |
DELETE IndicatorDimension/ |
delMacroAllocation |
DELETE MacroAllocation/ |
alc.delResourceAllocation |
DELETE ALC/ |
delMicroAllocations |
POST ProjectWorkItem/ |
alc. |
POST ALC/ |
delPmMethodPhaseTranslated |
DELETE Method/ |
delProjectManagementMethodologyPhaseTranslated |
DELETE Methodology/ |
delPmMethodTranslated |
DELETE Method/ |
delProjectManagementMethodologyTranslated |
DELETE Methodology/ |
delPortfolioScenario |
DELETE PortfolioScenario/ |
delPortfolioSimulation |
DELETE PortfolioSimulation/ |
delProject |
DELETE Project/:projectId |
delProject |
DELETE Project/:projectId |
delProjectConstraint |
DELETE ProjectScenario/ |
delProjectMilestoneConstraint |
DELETE ProjectMilestoneConstraint/ |
delProjectDependency |
DELETE Dependency/:dependencyId |
delProjectDependency |
DELETE ProjectDependency/ |
delProjectPortfolio |
DELETE ProjectPortfolio/:portfolioId |
delProjectPortfolio |
DELETE ProjectPortfolio/ |
delProjectPortfolioMilestone |
DELETE ProjectPortfolio/ |
delProjectPortfolioMilestone |
DELETE ProjectPortfolioMilestone/ |
delProjectPortfolioReport |
DELETE ProjectPortfolioReport/ |
delProjectPortfolioReport |
DELETE ProjectPortfolioReport/ |
delProjectPortfolioReportTypeTranslated |
DELETE ProjectPortfolioReportType/ |
delProjectPortfolioReportTypeTranslated |
DELETE ProjectPortfolioReportType/ |
delProjectReport |
DELETE ProjectReport/ |
delProjectReport |
DELETE ProjectReport/ |
delProjectReportTypeTranslated |
DELETE ProjectReportType/ |
delProjectReportTypeTranslated |
DELETE ProjectReportType/ |
delProjectScenario |
DELETE ProjectScenario/:scenarioId |
delProjectScenario |
DELETE ProjectScenario/ |
delWorkItem |
DELETE ProjectWorkItem/:workItemId |
delProjectWorkItem |
DELETE ProjectWorkItem/ |
delWorkItemLog |
DELETE ProjectWorkItem/ |
delProjectWorkItemLog |
DELETE ProjectWorkItemLog/ |
delWorkItemShiftPlan |
DELETE ProjectWorkItem/ |
delProjectWorkItemShiftPlan |
DELETE ProjectWorkItem/ |
downloadProjectScenario |
GET ProjectScenario/ |
exportProjectScenario |
GET ProjectScenario/ |
getPmMethodPhaseLifecycleAssignment |
GET Method/ |
getProjectManagementMethodologyPhaseLifecycleAssignments |
GET Methodology/ |
getPmMethodsPhaseLifecycleAssignment |
GET Methods/ |
getAllProjectManagementMethodologyPhaseLifecycleAssignments |
GET MethodologyPhaseLifecycleAssignments |
linkProject |
POST Project/:projectId/LinkTo |
linkProject |
POST Project/:projectId/Link |
moveProject |
POST Project/:projectId/MoveTo |
moveProject |
POST Project/:projectId/MoveTo |
moveProjectPortfolio |
POST ProjectPortfolio/ |
moveProjectPortfolio |
POST ProjectPortfolio/ |
moveProjectPortfolioToTop |
POST ProjectPortfolio/ |
moveProjectPortfolioToTop |
POST ProjectPortfolio/ |
moveWorkItem |
POST ProjectWorkItem/ |
moveProjectWorkItem |
POST ProjectWorkItem/ |
moveWorkItemEnd |
POST ProjectWorkItem/ |
moveProjectWorkItemEnd |
POST ProjectWorkItem/ |
moveWorkItemStart |
POST ProjectWorkItem/ |
moveProjectWorkItemStart |
POST ProjectWorkItem/ |
putPmMethodsPhaseLifecycleAssignment |
PUT Methods/ |
putProjectManagementMethodologyPhaseLifecycleAssignments |
PUT MethodologyPhaseLifecycleAssignments |
unlinkProject |
DELETE Project/:projectId/LinkTo |
unlinkProject |
DELETE Project/:projectId/Link |
uploadProjectPortfolioProject |
POST ProjectPortfolio/ |
importProjectPortfolioProject |
POST ProjectPortfolio/ |
uploadProjectScenario |
POST Project/ |
importProjectScenario |
POST Project/ |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
addPortfolioScenario |
POST PortfolioScenarios/Add |
addPortfolioSimulation |
POST PortfolioSimulations/Add |
Optional name, code, description, color and iconRef added |
addWorkItemMacroAllocation |
POST ProjectWorkItem/ |
alc.addResourceAllocation |
POST ALC/ |
argid becomes resourceId and amountType takes the V3 values; a resource already allocated to the work item is answered with 400 instead of being overwritten |
addWorkItemSubWorkItem |
POST ProjectWorkItem/ |
addProjectWorkItemSubWorkItem |
POST ProjectWorkItem/ |
Parameter list changed |
copyWorkItemTree |
POST ProjectWorkItem/ |
copyProjectWorkItemTree |
POST ProjectWorkItem/ |
2nd parameter changed |
delProjectWorkItemProgressCorrection |
DELETE ProjectWorkItem/ |
delProjectWorkItemProgressCorrection |
DELETE ProjectWorkItem/ |
The day is a mandatory path segment instead of the optional at (which defaulted to today, UTC); deleteoverride is spelled deleteOverride |
delWorkItemMacroAllocation |
DELETE ProjectWorkItem/ |
alc.delResourceAllocation |
DELETE ALC/ |
Addressed by the allocation's ID instead of work item and resource; find it with alc. |
getAllProjectDependencies |
GET Dependencies |
getAllProjectDependencies |
GET ProjectDependencies |
Returns references with the objects each dependency sits in; the V3 name getProjectDependencies is the bulk getter |
getAllProjectPortfolioReports |
GET ProjectPortfolioReports/ |
getAllProjectPortfolioReports |
GET ProjectPortfolioReports |
Returns references to all project portfolio reports; read them with getProjectPortfolioReports; the state filter is not available |
getAllProjectPortfoliosWithLatestReports |
GET ProjectPortfolios/ |
getLatestProjectPortfolioReportOfProjectPortfolios |
GET ProjectPortfolios/ |
Takes the portfolio IDs (list them with getAllProjectPortfolios) and answers one reference per portfolio; call it once per report type and read the reports with getProjectPortfolioReports |
getAllProjectPortfoliosWithLatestReportsDeprecated |
GET ProjectPortfolioss/ |
getLatestProjectPortfolioReportOfProjectPortfolios |
GET ProjectPortfolios/ |
Misspelled twin of getAllProjectPortfoliosWithLatestReports, same successor: takes the portfolio IDs (list them with getAllProjectPortfolios) and answers one reference per portfolio; call it once per report type and read the reports with getProjectPortfolioReports |
getAllProjectReports |
GET ProjectReports/:reportType |
getAllProjectReports |
GET ProjectReports |
Returns references to all project reports; read them with getProjectReports; the state filter and the project risks of a report are not available |
getAllProjectsWithLatestReports |
GET Projects/WithLatestReports |
getLatestProjectReportOfProjects |
GET Projects/ |
Takes the project IDs (list them with getAllProjects) and answers one reference per project; call it once per report type and read the reports with getProjectReports |
getIndicatorClassification |
GET Indicators/ |
getIndicatorClassification |
GET IndicatorClassification/ |
Response gains type and id and no longer carries values - read the steps of a scheme with getAllIndicatorClassificationValuesByClassification |
getIndicatorClassificationValue |
GET Indicators/ |
getIndicatorClassificationValue |
GET IndicatorClassificationValue/ |
Response gains type, id and indicatorClassificationId |
getIndicatorClassifications |
GET Indicators/Classifications |
getAllIndicatorClassifications |
GET IndicatorClassifications |
Returns references, not whole schemes; read one with getIndicatorClassification |
getIndicatorDetailDef |
GET Indicators/ |
getIndicatorDetail |
GET IndicatorDetail/ |
Addressed without the report type. Response renames dimension to indicatorDimensionId, adds source, and drops valueType, inputActual, inputRemaining, inputForecast, accumulation and projectManagementMethodPhase |
getIndicatorDetailDefs |
GET Indicators/ |
getAllProjectReportTypeIndicatorDetails |
GET ProjectReportType/ |
Returns references, not whole definitions |
getIndicatorDimensionDef |
GET Indicators/ |
getIndicatorDimension |
GET IndicatorDimension/ |
Addressed without the report type; response gains type and id |
getIndicatorDimensionDefs |
GET Indicators/ |
getAllProjectReportTypeIndicatorDimensions |
GET ProjectReportType/ |
Returns references, not whole definitions |
getIndicatorIntlClassification |
GET Indicators/ |
getIndicatorClassificationTranslated |
GET IndicatorClassification/ |
The translation arrays are unchanged; the body gains version and the create/modify audit data and no longer carries values - the steps are read with getIndicatorClassificationValueTranslated |
getIndicatorIntlDetailDef |
GET Indicators/ |
getIndicatorDetailTranslated |
GET IndicatorDetail/ |
Addressed without the report type. Response renames dimension to indicatorDimensionId and aggregationRule to source, and adds semantics, version and the create/modify audit data; the translation arrays are unchanged |
getIndicatorIntlDimensionDef |
GET Indicators/ |
getIndicatorDimensionTranslated |
GET IndicatorDimension/ |
Addressed without the report type; the body gains version and the create/modify audit data |
getIndicatorSelectionDetail |
GET Project/ |
getProjectIndicatorDetail |
GET Project/ |
Addressed by the selection's own ID instead of the indicator definition's; typeId becomes indicatorDetailId |
getIndicatorSelectionDetailHistory |
GET Project/ |
getProjectIndicatorDetailVersion |
GET Project/ |
One version per call, addressed by version ID, instead of a granularity-sampled range |
getIndicatorSelectionDetailTimeline |
GET Project/ |
getProjectIndicatorDetailTimeline |
GET Project/ |
Addressed by the selection's own ID; returns a VersionTimeline |
getIndicatorSelections |
GET Project/ |
getProjectIndicatorDetailsOfProject |
GET Project/ |
Split per axis - getProjectIndicatorDimensionsOfProject returns the dimensions - and returns references instead of the nested aggregate |
getLatestProjectPortfolioReport |
GET ProjectPortfolio/ |
getLatestProjectPortfolioReportOfProjectPortfolio |
GET ProjectPortfolio/ |
Answers a reference - read the report with getProjectPortfolioReport; the type becomes the optional reportTypeFilter (several types: latest of any), state becomes stateFilter |
getLatestProjectReport |
GET Project/ |
getLatestProjectReportOfProject |
GET Project/ |
Answers a reference - read the report with getProjectReport; the type becomes the optional reportTypeFilter (several types: latest of any), state becomes stateFilter |
getMacroAllocation |
GET MacroAllocation/ |
alc.getResourceAllocation |
GET ALC/ |
Response body changed; currency and version are gone |
getMovePatternByWorkItem |
GET ProjectWorkItem/ |
getProjectWorkItemMovePattern |
GET ProjectWorkItem/ |
Names the milestone milestoneId |
getMovePatternByWorkItemEnd |
GET ProjectWorkItem/ |
getProjectWorkItemEndMovePattern |
GET ProjectWorkItem/ |
Names the milestone milestoneId |
getMovePatternByWorkItemStart |
GET ProjectWorkItem/ |
getProjectWorkItemStartMovePattern |
GET ProjectWorkItem/ |
Names the milestone milestoneId |
getPmMethod |
GET Method/:methodId |
getProjectManagementMethodology |
GET Methodology/:methodId |
Response body changed |
getPmMethodPhase |
GET Method/ |
getProjectManagementMethodologyPhase |
GET Methodology/ |
Response body changed |
getPmMethodPhases |
GET Method/:methodId/Phases |
getAllProjectManagementMethodologyPhases |
GET Methodology/:methodId/Phases |
Parameter list changed |
getPmMethodPhaseTranslated |
GET Method/ |
getProjectManagementMethodologyPhaseTranslated |
GET Methodology/ |
Response body changed |
getPmMethods |
GET Methods |
getAllProjectManagementMethodologies |
GET Methodologies |
Parameter list changed |
getPmMethodTranslated |
GET Method/ |
getProjectManagementMethodologyTranslated |
GET Methodology/ |
Response body changed |
getPortfolioScenario |
GET PortfolioScenario/ |
getPortfolioSimulation |
GET PortfolioSimulation/ |
Response body changed, and the object type it reports differs — see the note above |
getPortfolioScenarios |
GET PortfolioScenarios |
getAllPortfolioSimulations |
GET PortfolioSimulations |
Returns references only; read the ones you need with getPortfolioSimulations/:ids |
getProject |
GET Project/:projectId |
getProject |
GET Project/:projectId |
Historic versions are read with getProjectTimeline and getProjectVersion, the lifecycle state with lcy.getObjectState, the classification with getProjectClassification and the portfolios with getAllProjects |
getProjectAccumulatedValues |
GET Project/ |
getAccumulatedStructureOfProjectWorkItems, getAccumulatedProgressOfProjectWorkItems, getAccumulatedTimesOfProjectWorkItems, getAccumulatedCostsOfProjectWorkItems |
GET ProjectWorkItems/ |
Split into four groups, each answering only the work items asked for: find the active scenario with getActiveScenarioOfProject and its work items with getProjectWorkItemsOfProjectScenario. For the project as a whole, getAccumulated…OfProject answers one object. The currency parameter is targetCurrencyId (Costs only); the costs forecasts are grouped like a costs overview |
getProjectActiveScenario |
GET Project/ |
getActiveScenarioOfProject |
GET Project/ |
Response body changed |
getProjectActiveScenarioHistory |
GET Project/ |
getActiveScenarioTimelineOfProject |
GET Project/ |
Reports a reference timeline: slots of until / latestReference / changeCount instead of a flat list of items, and it takes limit, from and granularity like the other V3 timelines |
getProjectClassification |
GET Project/ |
getProjectClassification |
GET Project/ |
Names the member description of the classification data remark |
getProjectConstraint |
GET ProjectScenario/ |
getProjectMilestoneConstraint |
GET ProjectMilestoneConstraint/ |
Addressed by its own ID; createdBy / modifiedBy are type-and-ID references now |
getProjectConstraints |
GET ProjectScenario/ |
getAllProjectMilestoneConstraintsOfProjectScenario |
GET ProjectScenario/ |
Returns references; the workItemId and milestoneId filters became getAllProjectMilestoneConstraintsOfProjectWorkItem resp. …OfProjectMilestone (with direction in place of predecessorId / successorId), read them with getProjectMilestoneConstraints/ |
getProjectDependencies |
GET Project/ |
getAllProjectDependenciesOfProject |
GET Project/ |
Renamed, returns references, no historic version |
getProjectDependency |
GET Dependency/:dependencyId |
getProjectDependency |
GET ProjectDependency/ |
Response body changed, no historic version |
getProjectIdentification |
GET Project/ |
getProjectIdentification |
GET Project/ |
No longer includes the lifecycle state; read it with lcy.getObjectState |
getProjectIdentifications |
GET Projects/Identification |
getAllProjects |
GET Projects |
Returns references; read them with getProjectIdentifications |
getProjectManagementMethod |
GET Project/ |
getProjectManagementMethodologyOfProject |
GET Project/:projectId/Methodology |
Response body changed |
getProjectManagementMethodPhase |
GET Project/ |
getProjectManagementMethodologyPhaseOfProject |
GET Project/ |
Response body changed |
getProjectManagementMethodTimeline |
GET Project/ |
getProjectManagementMethodologyTimelineOfProject |
GET Project/ |
Response body changed |
getProjectPortfolio |
GET ProjectPortfolio/:portfolioId |
getProjectPortfolio |
GET ProjectPortfolio/ |
The parent portfolio is read with getProjectPortfolioParentPortfolio |
getProjectPortfolioDependencies |
GET ProjectPortfolio/ |
getAllProjectDependenciesOfProjectPortfolio |
GET ProjectPortfolio/ |
Renamed, returns references |
getProjectPortfolioProjects |
GET ProjectPortfolio/ |
getProjectsOfProjectPortfolio |
GET ProjectPortfolio/ |
Returns references to the projects of the portfolio; read them with getProjects |
getProjectPortfolioReport |
GET ProjectPortfolioReport/ |
getProjectPortfolioReport |
GET ProjectPortfolioReport/ |
Reports the validity as periodStart and periodEnd |
getProjectPortfolioReports |
GET ProjectPortfolio/ |
getProjectPortfolioReportsOfProjectPortfolio |
GET ProjectPortfolio/ |
Returns references; reporttype becomes reportTypeFilter. Read the reports with getProjectPortfolioReports |
getProjectPortfolioReportsByType |
GET ProjectPortfolio/ |
getProjectPortfolioReportsOfProjectPortfolio |
GET ProjectPortfolio/ |
Returns references; the type leaves the path and becomes reportTypeFilter. Read the reports with getProjectPortfolioReports |
getProjectPortfolioReportType |
GET ProjectPortfolioReportType/ |
getProjectPortfolioReportType |
GET ProjectPortfolioReportType/ |
Response body changed |
getProjectPortfolioReportTypes |
GET ProjectPortfolioReportTypes |
getAllProjectPortfolioReportTypes |
GET ProjectPortfolioReportTypes |
Returns references; read them with getProjectPortfolioReportTypes |
getProjectPortfolioReportTypeTranslated |
GET ProjectPortfolioReportType/ |
getProjectPortfolioReportTypeTranslated |
GET ProjectPortfolioReportType/ |
Response body changed |
getProjectPortfolios |
GET ProjectPortfolios |
getAllProjectPortfolios |
GET ProjectPortfolios |
Returns references; read them with getProjectPortfolios |
getProjectPortfolioSubPortfolios |
GET ProjectPortfolio/ |
getSubPortfoliosOfProjectPortfolio |
GET ProjectPortfolio/ |
Returns references to the sub-portfolios; read them with getProjectPortfolios |
getProjectReport |
GET ProjectReport/ |
getProjectReport |
GET ProjectReport/ |
The JavaScript twin of getProjectReportHttp (Pqf.pm.getProjectReport), not redirected: with a JavaScript data collector on the report type, V2 refuses recalculate=1 with 400; the successor is the same |
getProjectReportHttp |
GET ProjectReport/ |
getProjectReport |
GET ProjectReport/ |
recalculate is gone: the V3 read never recalculates, and recalculate=1 becomes a separate call to getProjectReportRecalculated (GET ProjectReport/), where currency is spelled currencyId |
getProjectReports |
GET Project/:projectId/Reports |
getProjectReportsOfProject |
GET Project/:projectId/Reports |
Returns references; reporttype becomes reportTypeFilter. Read the reports with getProjectReports |
getProjectReportsByType |
GET Project/ |
getProjectReportsOfProject |
GET Project/:projectId/Reports |
Returns references; the type leaves the path and becomes reportTypeFilter. Read the reports with getProjectReports |
getProjectReportType |
GET ProjectReportType/ |
getProjectReportType |
GET ProjectReportType/ |
jsDataSourceId is only returned by getProjectReportTypeTranslated |
getProjectReportTypes |
GET ProjectReportTypes |
getAllProjectReportTypes |
GET ProjectReportTypes |
Returns references; read them with getProjectReportTypes |
getProjectReportTypeTranslated |
GET ProjectReportType/ |
getProjectReportTypeTranslated |
GET ProjectReportType/ |
Response body changed |
getProjects |
GET Projects |
getAllProjects |
GET Projects |
Returns references; read them with getProjects |
getProjectScenarioMacroAllocations |
GET ProjectScenario/ |
alc. |
GET ALC/ |
Reports references with the work item as parent and takes a sort; read the objects with alc.getResourceAllocations; version is gone |
getProjectsWithActiveScenario |
GET Projects/WithActiveScenario |
getAllProjectsWithActiveScenario |
GET ProjectsWithActiveScenario |
Returns references rather than whole projects; read them with getProjects. singleinactive is spelled allowSingleInactive, and a sort parameter was added |
getProjectsWithMissingReport |
GET Projects/WithMissingReport |
getAllProjectsWithMissingReport |
GET ProjectsWithMissingReport |
Returns references rather than whole projects; read them with getProjects. projectstate, reportstate and reporttype are spelled projectStateIds, reportStateIds and reportTypeIds, and a sort parameter was added |
getProjectScenario |
GET ProjectScenario/:scenarioId |
getProjectScenario |
GET ProjectScenario/ |
Historic versions are read with getProjectScenarioTimeline and getProjectScenarioVersion, the lifecycle state with lcy.getObjectState; the owner is not available |
getProjectScenarioDependencies |
GET ProjectScenario/ |
getAllProjectDependenciesOfProjectScenario |
GET ProjectScenario/ |
Renamed, returns references, no historic version |
getProjectScenarioManagementMethodTimeline |
GET ProjectScenario/ |
getProjectManagementMethodologyTimelineOfProjectScenario |
GET ProjectScenario/ |
Response body changed |
getProjectScenarioProgressCorrections |
GET ProjectScenario/ |
getProjectScenarioProgressCorrections |
GET ProjectScenario/ |
Response body changed: ref references the work item (type ProjectWorkItem), a day's element names its day in day and the corrections it overrode in overridden, modifiedBy is a type-and-ID reference |
getProjectWorkItemProgressCorrection |
GET ProjectWorkItem/ |
getProjectWorkItemProgressCorrection |
GET ProjectWorkItem/ |
The day is a mandatory path segment instead of the optional at; answers the correction of that day itself (pm.ProgressCorrection), or 404 if there is none, instead of a history filtered to that day |
getProjectWorkItemProgressCorrections |
GET ProjectWorkItem/ |
getProjectWorkItemProgressCorrections |
GET ProjectWorkItem/ |
Response body changed the same way as getProjectScenarioProgressCorrections |
getProjectPortfolioMilestone |
GET ProjectPortfolio/ |
getProjectPortfolioMilestone |
GET ProjectPortfolioMilestone/ |
Parameter list changed, response body no longer carries the validity |
getProjectPortfolioMilestones |
GET ProjectPortfolio/ |
getProjectPortfolioMilestonesOfProjectPortfolio |
GET ProjectPortfolio/ |
Returns references; the V3 name getProjectPortfolioMilestones is the bulk getter |
getWorkItemMacroAllocations |
GET ProjectWorkItem/ |
alc. |
GET ALC/ |
Reports references with the work item as parent and takes a sort; read the objects with alc.getResourceAllocations; version is gone |
proposeWorkItemEnd |
GET ProjectWorkItem/ |
proposeProjectWorkItemEnd |
GET ProjectWorkItem/ |
Names the milestone milestoneId |
proposeWorkItemStart |
GET ProjectWorkItem/ |
proposeProjectWorkItemStart |
GET ProjectWorkItem/ |
Names the milestone milestoneId |
putIndicatorIntlDetailDef |
PUT Indicators/ |
putIndicatorDetailTranslated |
PUT IndicatorDetail/ |
Addressed without the report type. Request renames dimension to indicatorDimensionId and aggregationRule to source; version and the audit members are server-managed and ignored on write; still creates the definition when the ID is unknown |
putIndicatorIntlDimensionDef |
PUT Indicators/ |
putIndicatorDimensionTranslated |
PUT IndicatorDimension/ |
Addressed without the report type; version and the audit members are added to the body but are server-managed and ignored on write |
putIndicatorSelections |
PUT Project/ |
putProjectIndicatorDetail |
PUT Project/ |
One object per call instead of every dimension and detail of the project in one nested payload; putProjectIndicatorDimension writes a dimension |
putMacroAllocation |
PUT MacroAllocation/ |
alc.putResourceAllocation |
PUT ALC/ |
Request body changed; it only updates an existing allocation, whose work item and resource cannot be changed |
putProjectClassification |
PUT Project/ |
putProjectClassification |
PUT Project/ |
Body names the member description of the classification data remark |
putProjectPortfolioMilestone |
PUT ProjectPortfolio/ |
putProjectPortfolioMilestone |
PUT ProjectPortfolioMilestone/ |
Parameter list changed, request body no longer carries the validity |
getProjectScenarios |
GET Project/:projectId/Scenarios |
getScenariosOfProject |
GET Project/:projectId/Scenarios |
Returns references; read them with getProjectScenarios |
getProjectSubObj |
GET Project/ |
getProjectSubObject |
GET Project/ |
Historic versions are read with getProjectSubObjectTimeline and getProjectSubObjectVersion |
getProjectSubObjs |
GET Project/:projectId/SubObjects |
getProjectSubObjects |
GET Project/:projectId/SubObjects |
Response body changed |
getProjectSubObjTimeline |
GET Project/ |
getProjectSubObjectTimeline |
GET Project/ |
Parameter list changed |
getProjectSubObjTypes |
GET SubObjectTypes |
getAllProjectSubObjectTypes |
GET SubObjectTypes |
Returns references; read them with getProjectSubObjectTypes |
getProjectSummaries |
GET Projects/Summaries |
per category, see getProjectSummary |
— | Several projects at once: the project, active scenario, accumulated values, costs, management method, latest reports and lifecycle history successors take project IDs in bulk; relations, confidentiality, third-party references and sub objects are read per project (getProjectsSubObject reads one sub object type for several), the main phase per scenario |
getProjectSummary |
GET Project/:projectId/Summary |
getProjects, getProjectSubObjects, getActiveScenarioOfProjects, getProjectWorkItemsOfProjectScenario, getAccumulated{Structure,Progress,Times,Costs}OfProjects, fco.getProjectsCostsOverviews, pf.getAllRelations, getProjectManagementMethodologyOfProjects, getProjectManagementMethodologyPhaseOfProjects, tdp., getLatestProjectReportOfProjects, acm.getConfidentiality, lcy.getObjectsHistories |
— | No combined answer: each category of the summary is read on its own. Relations: includeImplicit=false. Latest reports: one call per report type with reportTypeFilter (and stateFilter). Main phase: the single top-most work item. Accumulated values: the project's top-most work items merged, which is the main phase's values when there is one. Costs: the overview's planned, actual, expected pending, remaining, forecast and budget totals; the currency parameter is targetCurrencyId |
getProjectTimeline |
GET Project/:projectId/Timeline |
getProjectTimeline |
GET Project/:projectId/Timeline |
Takes from and until instead of beg and end |
getRecentlyDeletedProjects |
GET Projects/RecentlyDeleted |
getRecentlyDeletedProjects |
GET Projects/Deleted/Recently |
Reports deletedAt and deletedBy |
getRecentlyDeletedProjectScenarios |
GET ProjectScenarios/ |
getRecentlyDeletedProjectScenarios |
GET ProjectScenarios/ |
Reports deletedAt and deletedBy and the project as parent |
getRootProjectPortfolios |
GET RootProjectPortfolios |
getRootProjectPortfolios |
GET RootProjectPortfolios |
Returns references to the root portfolios; read them with getProjectPortfolios |
getScenarioAccumulatedValues |
GET ProjectScenario/ |
getAccumulatedStructureOfProjectWorkItems, getAccumulatedProgressOfProjectWorkItems, getAccumulatedTimesOfProjectWorkItems, getAccumulatedCostsOfProjectWorkItems |
GET ProjectWorkItems/ |
Split into four groups, each answering only the work items asked for (list them with getProjectWorkItemsOfProjectScenario). For the scenario as a whole, getAccumulated…OfProjectScenario answers one object. The currency parameter is targetCurrencyId (Costs only) |
getScenarioWorkItems |
GET ProjectScenario/ |
getProjectWorkItemsOfProjectScenario |
GET ProjectScenario/ |
2nd parameter changed |
getWorkItem |
GET ProjectWorkItem/:workItemId |
getProjectWorkItems |
GET ProjectWorkItems/ |
Parameter list changed |
getWorkItemAccumulatedValues |
GET ProjectWorkItem/ |
getAccumulatedStructureOfProjectWorkItem, getAccumulatedProgressOfProjectWorkItem, getAccumulatedTimesOfProjectWorkItem, getAccumulatedCostsOfProjectWorkItem |
GET ProjectWorkItem/ |
Split into four groups; the currency parameter is targetCurrencyId (Costs only) |
getWorkItemLog |
GET ProjectWorkItem/ |
getProjectWorkItemLogs |
GET ProjectWorkItemLogs/ |
Addressed by log ID alone, reads several at once, response is pm.ProjectWorkItemLog |
getWorkItemLogParent |
GET ProjectWorkItemLog/ |
getProjectWorkItemLogs |
GET ProjectWorkItemLogs/ |
Obsolete: a log reports its work item in projectWorkItemId |
getWorkItemLogs |
GET ProjectWorkItem/ |
getAllProjectWorkItemLogsOfProjectWorkItem |
GET ProjectWorkItem/ |
Returns pf.ReferenceWithParent[]; read the logs themselves with getProjectWorkItemLogs |
getWorkItemProject |
GET ProjectWorkItem/ |
getProjectWorkItems |
GET ProjectWorkItems/ |
1st parameter changed |
getWorkItemShiftPlan |
GET ProjectWorkItem/ |
getProjectWorkItemShiftPlan |
GET ProjectWorkItem/ |
Response body changed: a pattern names its shift by ID in shiftId rather than embedding a whole res.ResourceShift; read the shifts with res.getResourceShifts |
getWorkItemSubWorkItems |
GET ProjectWorkItem/ |
getSubWorkItemsOfProjectWorkItem |
GET ProjectWorkItem/ |
Parameter list changed |
putPmMethodPhaseTranslated |
PUT Method/ |
putProjectManagementMethodologyPhaseTranslated |
PUT Methodology/ |
Request body changed |
putPmMethodTranslated |
PUT Method/ |
putProjectManagementMethodologyTranslated |
PUT Methodology/ |
Request body changed |
putPortfolioScenario |
PUT PortfolioScenario/ |
putPortfolioSimulation |
PUT PortfolioSimulation/ |
Request body changed; validityStart / validityEnd are gone and are preserved as they were |
putProject |
PUT Project/:projectId |
putProject |
PUT Project/:projectId |
Only updates an existing project; create one with addProjectPortfolioProject |
putProjectConstraint |
PUT ProjectScenario/ |
putProjectMilestoneConstraint |
PUT ProjectMilestoneConstraint/ |
Updates only - create with addProjectScenarioMilestoneConstraint; movetarget / movesource became fixProjectMilestoneConstraint |
putProjectDependency |
PUT Dependency/:dependencyId |
putProjectDependency |
PUT ProjectDependency/ |
Request body changed |
putProjectPortfolio |
PUT ProjectPortfolio/:portfolioId |
putProjectPortfolio |
PUT ProjectPortfolio/ |
Only updates an existing portfolio; create one with addProjectPortfolio or addProjectPortfolioSubPortfolio |
putProjectPortfolioReport |
PUT ProjectPortfolioReport/ |
putProjectPortfolioReport |
PUT ProjectPortfolioReport/ |
Only updates an existing report and takes the validity as periodStart and periodEnd; create one with addProjectPortfolioReport |
putProjectPortfolioReportTypeTranslated |
PUT ProjectPortfolioReportType/ |
putProjectPortfolioReportTypeTranslated |
PUT ProjectPortfolioReportType/ |
Request body changed |
putProjectReport |
PUT ProjectReport/ |
putProjectReport |
PUT ProjectReport/ |
The JavaScript twin of putProjectReportHttp (Pqf.pm.putProjectReport), not redirected: with a JavaScript data collector on the report type, V2 answers 202 before the collector has run; the successor is the same |
putProjectReportHttp |
PUT ProjectReport/ |
putProjectReport |
PUT ProjectReport/ |
Only updates an existing report, takes the currency and the period in its body and leaves the indicators to putProjectReportIndicatorDimension and putProjectReportIndicatorDetail; create one with addProjectReport |
putProjectReportTypeTranslated |
PUT ProjectReportType/ |
putProjectReportTypeTranslated |
PUT ProjectReportType/ |
Request body changed |
putProjectScenario |
PUT ProjectScenario/:scenarioId |
putProjectScenario |
PUT ProjectScenario/ |
Only updates an existing scenario and keeps its owner, which cannot be set; create one with addProjectScenario |
putProjectSubObj |
PUT Project/ |
putProjectSubObject |
PUT Project/ |
Request body changed |
putWorkItem |
PUT ProjectWorkItem/:workItemId |
putProjectWorkItem |
PUT ProjectWorkItem/ |
Parameter list changed |
putWorkItemLog |
PUT ProjectWorkItem/ |
putProjectWorkItemLog |
PUT ProjectWorkItemLog/ |
Work item moves into the body as projectWorkItemId; addProjectWorkItemLog creates one with a server-side ID |
putWorkItemShiftPlan |
PUT ProjectWorkItem/ |
putProjectWorkItemShiftPlan |
PUT ProjectWorkItem/ |
Request body changed the same way; all patterns must be of the same length, and an empty shifts is refused with 400 - the delete is what drops a plan |
splitWorkItem |
POST ProjectWorkItem/ |
splitProjectWorkItem |
POST ProjectWorkItem/ |
2nd parameter changed |
updateProjectWorkItemProgressCorrection |
POST ProjectWorkItem/ |
putProjectWorkItemProgressCorrection |
PUT ProjectWorkItem/ |
A PUT whose day is a mandatory path segment; remainingEffort or progress and remark move into the body (pm.ProgressCorrectionChange), includestimebased / deleteoverride are spelled includesTimeBased / deleteOverride |
Retired — no V3 successor; the endpoint disappears with API V2.
| V2 endpoint | V2 path | Note |
|---|---|---|
getProjectDetails |
GET Project/:projectId/Details |
Use getProject() / GET API/V2/PM/Project/:id instead, will be discontinued at end of 2028 |
getProjectScenarioChangesTimeline |
GET ProjectScenario/ |
Will be replaced by an API V3 endpoint that also covers the changes of the Allocation 2.0 feature as soon as that feature is released. API V2 will be discontinued at end of 2028 |
putProjectDetails |
PUT Project/:projectId/Details |
Use putProject() / PUT API/V2/PM/Project/:id instead, will be discontinued at end of 2028 |
getProjectScenarioChangesTimeline is the one retirement that is only deferred: keep using it on V2 until its V3
successor is released; this guide will then name it.
New in V3 — no V2 equivalent.
addProjectWorkItemLog, delIndicatorClassificationTranslated, delIndicatorClassificationValueTranslated, delProjectIndicatorDetail, delProjectIndicatorDimension, delProjectReportIndicatorDetail, delProjectReportIndicatorDimension, delProjectSubObjectTypeTranslated, getActiveScenarioOfProjects, getAllIndicatorClassificationValues, getAllIndicatorClassificationValuesByClassification, getAllIndicatorDetails, getAllIndicatorDimensionDetails, getAllIndicatorDimensions, getAllProjectDependenciesOfProject, getAllProjectDependenciesOfProjectPortfolio, getAllProjectDependenciesOfProjectScenario, getAllProjectPortfolioMilestones, getAllProjectScenarios, getAllProjectWorkItemLogsOfProjectScenario, getIndicatorClassificationValueTranslated, getIndicatorClassificationValues, getIndicatorClassificationValuesTranslated, getIndicatorClassificationsTranslated, getIndicatorDetails, getIndicatorDetailsTranslated, getIndicatorDimensions, getIndicatorDimensionsTranslated, getPortfolioSimulationIdentification, getPortfolioSimulationIdentifications, getPortfolioSimulations, getProjectIndicatorDetailIdentification, getProjectIndicatorDetailIdentifications, getProjectIndicatorDetails, getProjectIndicatorDimension, getProjectIndicatorDimensionIdentification, getProjectIndicatorDimensionIdentifications, getProjectIndicatorDimensionTimeline, getProjectIndicatorDimensionVersion, getProjectIndicatorDimensions, getProjectManagementMethodologies, getProjectManagementMethodologiesTranslated, getProjectManagementMethodologyOfProjects, getProjectManagementMethodologyPhaseOfProjects, getProjectManagementMethodologyPhases, getProjectManagementMethodologyPhasesTranslated, getProjectManagementMethodologyTimelineOfProjectScenarios, getProjectManagementMethodologyTimelineOfProjects, getProjectMilestone, getProjectMilestones, getProjectPortfolioIdentification, getProjectPortfolioIdentifications, getProjectPortfolioMilestoneIdentification, getProjectPortfolioMilestoneIdentifications, getProjectPortfolioMilestonesOfProjectPortfolio, getProjectPortfolioParentPortfolio, getProjectPortfolioReportIdentification, getProjectPortfolioReportIdentifications, getProjectPortfolioReportTypesTranslated, getProjectPortfolioReportsOfType, getProjectPortfolioTimeline, getProjectPortfolioVersion, getProjectReportIdentification, getProjectReportIdentifications, getProjectReportIndicatorDetail, getProjectReportIndicatorDetailIdentification, getProjectReportIndicatorDetailIdentifications, getProjectReportIndicatorDetails, getProjectReportIndicatorDimension, getProjectReportIndicatorDimensionIdentification, getProjectReportIndicatorDimensionIdentifications, getProjectReportIndicatorDimensions, getProjectReportRecalculated, getProjectReportTypesTranslated, getProjectReportsOfType, getProjectScenarioIdentification, getProjectScenarioIdentifications, getProjectScenarioTimeline, getProjectScenarioVersion, getProjectSubObjectType, getProjectSubObjectTypeTranslated, getProjectSubObjectTypesTranslated, getProjectSubObjectVersion, getProjectVersion, getProjectWorkItem, getProjectWorkItemIdentification, getProjectWorkItemIdentifications, getProjectWorkItemLog, getProjectWorkItemLogIdentification, getProjectWorkItemLogIdentifications, getProjectWorkItemLogTimeline, getProjectWorkItemLogVersion, getProjectWorkItemTimeline, getProjectWorkItemVersion, getProjectsSubObject, getScenariosOfProjects, putIndicatorClassificationTranslated, putIndicatorClassificationValueTranslated, putProjectMilestone, putProjectReportIndicatorDetail, putProjectReportIndicatorDimension, putProjectSubObjectTypeTranslated
RES — Resources, resource links, holidays and availabilities
- Holidays are addressed globally. In V2 a holiday lived under its locale
(
HolidayLocale/); in V3 it has its own ID (:locid/ Holiday/ :holid Holiday/:holidayId), and several at once areHolidays/:holidayIds. The separate…Bulkendpoints disappear — for reading and deleting, the plural endpoint is the bulk endpoint. - The bulk write is the exception, and it is worth using.
putHolidaysBulkbecomesupdateHolidays(POST HolidayLocale/), the one holiday endpoint that keeps the locale in the URL: a holiday that does not exist yet has no locale to look up. Each element of the request body carries its own:holidayLocaleId/ Holidays/ Update idandlocaleId, so the parallel ID array of the V2 URL is gone. Prefer it over aputHolidayper holiday — a single write of a holiday recalculates the availability, presence and work plan of every resource that works by its locale, and oneupdateHolidaysrequest pays that price once instead of once per holiday. - Availabilities collapse into one endpoint.
getAvailabilitiesandgetAvailabilitiesByResourceboth becomegetResourceAvailabilities. - The holiday-locale "details" and "obj" endpoints are retired: use
getHolidayLocale/putHolidayLocale. - Resources, resource links and holiday locales are V3 object families now, with identifications and reference
lists (
getAllResourceTypes,getAllResourceGroups,getAllResourceLinkTypes,getResourceLinks). - The hierarchy endpoints are gone; the hierarchy is assembled from parts.
getResourceHierarchyandgetResourceHierarchyByTypereturned a ready-made tree. In V3 you read the resources (getAllResourcesByTypes/getResourceIdentifications) and their parent links (getResourcesParentsLinks) and build the tree yourself — which is also what makes the per-link-type variants (getResourceParentsByLinkType,getResourcesChildrenLinks, …) possible. Note that a resource's own validity dates are not part of the V3 answer. addResourceChildis the oneadd…endpoint whose URL is not…/Add— it staysResource/— and it now takes:parentResourceId/ AddChild linkTypeIdplus the basic field initializers.- New: work-time units and factors, standard work time per group, children by link type, and the holiday list of a locale.
- The availability of the V2 allocation slots is a RES time slot.
getResourceAvailabilitySlotsanswers the working time without absences in time slots, before the base load of the worktime model is taken off — V2'salc.getMacroAllocationSlotsreported it after. It has a bulk sibling and a single-slot lookup; the family is described in the ALC section.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
addHolidayLocale |
POST HolidayLocales/Add |
addHolidayLocale |
POST HolidayLocales/Add |
addResourceChild |
POST Resource/ |
addResourceChild |
POST Resource/ |
addResourceLink |
POST Resource/:fromId/AddLink |
addResourceLink |
POST Resource/:fromId/AddLink |
delAvailability |
DELETE Resource/ |
delAvailability |
DELETE Resource/ |
delHolidayLocale |
DELETE HolidayLocale/:locid |
delHolidayLocale |
DELETE HolidayLocale/:holidayLocaleId |
delResourceLink |
DELETE ResourceLink/:linkType/:linkId |
delResourceLink |
DELETE ResourceLink/ |
getResourceKind |
GET ResourceKind/:kindId |
getResourceKind |
GET ResourceKind/:kind |
getResourceKinds |
GET ResourceKinds |
getResourceKinds |
GET ResourceKinds |
getWeekDaysToWorkDaysMapping |
GET Resource/ |
getWeekDaysToWorkDaysMapping |
GET Resource/ |
getWorkDaysToWeekDaysMapping |
GET Resource/ |
getWorkDaysToWeekDaysMapping |
GET Resource/ |
importHolidays |
POST HolidayLocale/ |
importHolidays |
POST HolidayLocale/ |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
delHoliday |
DELETE HolidayLocale/ |
delHoliday |
DELETE Holiday/:holidayId |
Addresses the holiday by its ID alone |
delHolidaysBulk |
DELETE HolidayLocale/ |
delHolidays |
DELETE Holidays/:holidayIds |
Parameter list changed |
delResource |
DELETE Resource/:resourceId |
delResource |
DELETE Resource/:resourceId |
Recursive deletion is not available, hard-linked children have to be moved or deleted first |
getAvailabilities |
GET Resource/ |
getResourceAvailabilities |
GET Resource/ |
Parameter list changed |
getAvailabilitiesByResource |
GET Availabilities/ |
getResourceAvailabilities |
GET Resource/ |
Parameter list changed |
getAvailability |
GET Resource/ |
getAvailability |
GET Resource/ |
Response body changed |
getHoliday |
GET HolidayLocale/ |
getHoliday |
GET Holiday/:holidayId |
Addresses the holiday by its ID alone |
getHolidayLocale |
GET HolidayLocale/:locid |
getHolidayLocale |
GET HolidayLocale/:holidayLocaleId |
Requires READ permission; getHolidayLocaleIdentification requires IDENTIFY only |
getHolidayLocales |
GET HolidayLocales |
getAllHolidayLocales |
GET HolidayLocales |
Returns references; read the locales with getHolidayLocales |
getHolidays |
GET HolidayLocale/:locid/Holidays |
getHolidayLocaleHolidays |
GET HolidayLocale/ |
Returns references; read them with getHolidays |
getHolidaysBulk |
GET HolidayLocale/ |
getHolidays |
GET Holidays/:holidayIds |
Parameter list changed |
getRecentlyDeletedResources |
GET Resources/RecentlyDeleted |
getRecentlyDeletedResources |
GET Resources/Deleted/Recently |
Requires the administration permission and returns identifications with deletedAt and deletedBy; the resource administration permission alone is not sufficient |
getResource |
GET Resource/:resourceId |
getResource |
GET Resource/:resourceId |
Historic versions are read with getResourceTimeline and getResourceVersion instead of version |
getResourceAncestors |
GET Resource/:resourceId/Ancestors |
getResourceAncestors |
GET Resource/:resourceId/Ancestors |
Returns references to the ancestors; read them with getResources |
getResourceChildren |
GET Resource/:resourceId/Children |
getResourceChildren |
GET Resource/:resourceId/Children |
Returns references to the children; read them with getResources |
getResourceChildrenIdentification |
GET Resource/ |
getResourceChildren |
GET Resource/:resourceId/Children |
Parameter list changed |
getResourceGroup |
GET ResourceGroup/:groupId |
getResourceGroup |
GET ResourceGroup/:groupId |
Response body changed |
getResourceGroups |
GET ResourceGroups |
getAllResourceGroups |
GET ResourceGroups |
Returns references; read them with getResourceGroups |
getResourceGroupStandardWorktimes |
GET ResourceGroups/ |
getResourceGroupsStandardWorktime |
GET ResourceGroups/ |
Parameter list changed |
getResourceGroupWorktimeUnitFactors |
GET ResourceGroup/ |
getResourceGroupWorktimeUnitFactors |
GET ResourceGroup/ |
Names the unit unitId |
getResourceGroupWorktimeUnits |
GET ResourceGroup/ |
getResourceGroupWorktimeUnits |
GET ResourceGroup/ |
Names the member abbr of a unit abbreviation |
getResourceIdentification |
GET Resource/ |
getResourceIdentification |
GET Resource/ |
The links to the parents are read with getResourceParentsLinks |
getResourceLink |
GET ResourceLink/:linkType/:linkId |
getResourceLink |
GET ResourceLink/ |
Returns the V3 ResourceLink including the linked resources |
getResourceLinkType |
GET ResourceLinkType/:linkTypeId |
getResourceLinkType |
GET ResourceLinkType/:linkTypeId |
Names the implicit relation type implicitRelationTypeId |
getResourceLinkTypes |
GET ResourceLinkTypes |
getAllResourceLinkTypes |
GET ResourceLinkTypes |
Returns references; read them with getResourceLinkTypes |
getResources |
GET Resources |
getAllResourcesByTypes |
GET ResourceTypes/:= length > 0;non-null">typeIds/ |
Returns references per resource type (list the types with getAllResourceTypes); read the resources with getResources |
getResourcesByGroup |
GET ResourceGroup/ |
getAllResourcesByGroup |
GET ResourceGroup/ |
Returns references to the resources; read them with getResourceIdentifications |
getResourcesByKind |
GET ResourceKind/:kindId/Resources |
getAllResourcesByKind |
GET ResourceKind/:kind/Resources |
Returns references to the resources; read them with getResourceIdentifications |
getResourcesByKinds |
GET ResourceKinds/ |
getAllResourcesByKind |
GET ResourceKind/:kind/Resources |
Parameter list changed |
getResourcesByType |
GET ResourceType/:typeId/Resources |
getAllResourcesByType |
GET ResourceType/:typeId/Resources |
Returns references to the resources; read them with getResources; reading them requires READ permission |
getResourcesByTypes |
GET ResourceTypes/ |
getAllResourcesByTypes |
GET ResourceTypes/ |
Returns references to the resources; read them with getResources; reading them requires READ permission |
getResourceShift |
GET ResourceShift/:shiftid |
getResourceShift |
GET ResourceShift/:shiftId |
Response body changed |
getResourceShifts |
GET ResourceShifts |
getResourceShifts |
GET ResourceShifts |
Response body changed |
getResourceHierarchy |
GET Resources/ResourceHierarchy |
getAllResourceTypes + getAllResourcesByTypes + getResourceIdentifications + getResourcesParentsLinks |
see section prose | The ready-made tree is gone; assemble it from resources and parent links. The resource's own validity dates are not available in V3 |
getResourceHierarchyByType |
GET ResourceType/ |
getAllResourcesByType + getResourceIdentifications + getResourcesParentsLinks |
see section prose | The ready-made tree is gone; assemble it from resources and parent links. The resource's own validity dates are not available in V3 |
getResourceTimeline |
GET Resource/:resourceId/Timeline |
getResourceTimeline |
GET Resource/:resourceId/Timeline |
Returns the version timeline and takes from and until instead of beg and end; it requires READ permission instead of IDENTIFY |
getResourceType |
GET ResourceType/:typeId |
getResourceType |
GET ResourceType/:typeId |
Response body changed |
getResourceTypes |
GET ResourceTypes |
getAllResourceTypes |
GET ResourceTypes |
Returns references; read them with getResourceTypes |
previewHolidays |
POST Holidays/Import/Preview |
previewHolidays |
POST Holidays/Import/Preview |
The format value ical becomes Ical |
putAvailability |
PUT Resource/ |
putAvailability |
PUT Resource/ |
Request body changed |
putHoliday |
PUT HolidayLocale/ |
putHoliday |
PUT Holiday/:holidayId |
Addresses the holiday by its ID and takes the V3 Holiday, including its localeId, as its body |
putHolidaysBulk |
PUT HolidayLocale/ |
updateHolidays |
POST HolidayLocale/ |
Request body changed |
putHolidayLocale |
PUT HolidayLocale/:locid |
putHolidayLocale |
PUT HolidayLocale/:holidayLocaleId |
Takes the V3 HolidayLocale as its body and only updates an existing locale, which requires the multiholidaylocale license; create one with addHolidayLocale |
putResource |
PUT Resource/:resourceId |
putResource |
PUT Resource/:resourceId |
Takes the V3 Resource as its body and only updates an existing resource; create one under a parent with addResourceChild |
putResourceGroupStandardWorktime |
PUT ResourceGroup/ |
putResourceGroupStandardWorktime |
PUT ResourceGroup/ |
Body names the resource group resourceGroupId |
putResourceLink |
PUT ResourceLink/:linkType/:linkId |
putResourceLink |
PUT ResourceLink/ |
Takes the V3 ResourceLink as its body |
Retired — no V3 successor; the endpoint disappears with API V2.
| V2 endpoint | V2 path | Note |
|---|---|---|
getHolidayLocaleDetails |
GET HolidayLocale/:locid/Details |
Use getHolidayLocale(...) instead, will be discontinued at end of 2028 |
getHolidayLocaleObj |
JS only |
Use getHolidayLocale(...) instead, will be discontinued at end of 2028 |
putHolidayLocaleDetails |
PUT HolidayLocale/:locid/Details |
Use putHolidayLocale(...) instead, will be discontinued at end of 2028 |
putHolidayLocaleObj |
JS only |
Use getHolidayLocale(...) instead, will be discontinued at end of 2028 |
New in V3 — no V2 equivalent.
getAvailabilities, getHolidayLocaleIdentification, getHolidayLocaleIdentifications, getResourceChildrenByLinkType, getResourceChildrenLinks, getResourceChildrenLinksByLinkType, getResourceGroupStandardWorktime, getResourceGroupsWorktimeUnitFactors, getResourceGroupsWorktimeUnits, getResourceIdentifications, getResourceLinkIdentification, getResourceLinkIdentifications, getResourceLinks, getResourceParents, getResourceParentsByLinkType, getResourceParentsLinks, getResourceParentsLinksByLinkType, getResourceVersion, getResourcesAvailabilitySlot, getResourcesChildren, getResourcesChildrenByLinkType, getResourcesChildrenLinks, getResourcesChildrenLinksByLinkType, getResourcesParents, getResourcesParentsByLinkType, getResourcesParentsLinksByLinkType
RSK — Risks
Risks are a V3 object family: identifications, version timeline, historic versions. getAllProjectRisks and
getProjectRisksOfProjectPortfolio let you read risks across projects instead of one project at a time. Most
endpoints are reimplemented with new bodies, so plan on rewriting rather than re-pointing.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
addProjectRisk |
POST Project/:prjid/Risks/Add |
addProjectRisk |
POST Project/:projectId/Risks/Add |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
calculateRisk |
POST RiskMatrix/Calculate |
calculateRisk |
POST RiskMatrix/Calculate |
Names the classifications …ClassificationId |
delProjectRisk |
DELETE Project/:prjid/Risk/:riskId |
delProjectRisk |
DELETE ProjectRisk/:projectRiskId |
Addresses the risk by its ID alone |
getAllProjectRisks |
GET ProjectRisks |
getAllProjectRisks |
GET ProjectRisks |
Returns references; read them with getProjectRisks; currency is gone |
getProjectPortfolioRisks |
GET ProjectPortfolio/:ppfid/Risks |
getProjectRisksOfProjectPortfolio |
GET ProjectPortfolio/ |
Parameter list changed |
getProjectPortfolioRisksWithHistory |
GET ProjectPortfolio/ |
getProjectRisksOfProjectPortfolio |
GET ProjectPortfolio/ |
Parameter list changed |
getProjectRisk |
GET Project/:prjid/Risk/:riskId |
getProjectRisk |
GET ProjectRisk/:projectRiskId |
Addresses the risk by its ID alone; historic versions are read with getProjectRiskTimeline and getProjectRiskVersion |
getProjectRiskById |
GET ProjectRisk/:riskId |
getProjectRisks |
GET ProjectRisks/:projectRiskIds |
Parameter list changed |
getProjectRisks |
GET Project/:prjid/Risks |
getProjectRisksOfProject |
GET Project/:projectId/Risks |
Returns references; read them with getProjectRisks; version and currency are gone |
getProjectRisksWithHistory |
GET Project/ |
getProjectRisksOfProject |
GET Project/:projectId/Risks |
Returns references; read them with getProjectRisksWithHistory; version and currency are gone, simplify stays |
getProjectRiskWithHistory |
GET Project/ |
getProjectRiskWithHistory |
GET ProjectRisk/ |
Addresses the risk by its ID alone and takes simplify as a calendar granularity; the history up to a historic version and simplification by decade are not available |
getRiskMatrixDefinition |
GET RiskMatrix/Definition |
getRiskMatrixDefinition |
GET RiskMatrix/Definition |
Response body changed |
getRiskMatrixDefinitionTranslated |
GET RiskMatrix/ |
getRiskMatrixDefinitionTranslated |
GET RiskMatrix/ |
Requires the administration permission |
putProjectRisk |
PUT Project/:prjid/Risk/:riskId |
putProjectRisk |
PUT ProjectRisk/:projectRiskId |
Addresses the risk by its ID alone, takes the V3 ProjectRisk as its body and only updates an existing risk; create one with addProjectRisk |
putRiskMatrixDefinitionTranslated |
PUT RiskMatrix/ |
putRiskMatrixDefinitionTranslated |
PUT RiskMatrix/ |
Takes the V3 RiskMatrixDefinitionTranslated as its body |
New in V3 — no V2 equivalent.
getProjectRiskIdentification, getProjectRiskIdentifications, getProjectRiskTimeline, getProjectRiskVersion
STG — Strategy
Fully migrated, mostly reimplemented — every put… body changed, so budget for a rewrite of all write paths.
Renames to know:
| V2 | V3 |
|---|---|
getStrategies |
getAllStrategies |
getVisions |
getVisionsOfStrategy |
getProjectContributions |
getProjectContributionsOfObjective |
getProjectContribution |
getProjectContributions (bulk by ID) |
get…History |
get…Timeline |
Note that getStrategies, getVisions, getObjectives, getObjectiveIndicators and getFieldOfActions all
exist in V3 as bulk getters by ID — which is not what the identically spelled V2 names meant. Check every
one of them.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
addFieldOfAction |
POST Vision/ |
addFieldOfAction |
POST Vision/ |
addObjective |
POST FieldOfAction/ |
addObjective |
POST FieldOfAction/ |
addObjectiveIndicator |
POST Objective/ |
addObjectiveIndicator |
POST Objective/ |
addProjectContribution |
POST Objective/ |
addProjectContribution |
POST Objective/ |
addStrategy |
POST Strategies/Add |
addStrategy |
POST Strategies/Add |
addVision |
POST Strategy/ |
addVision |
POST Strategy/ |
delFieldOfAction |
DELETE FieldOfAction/:foaId |
delFieldOfAction |
DELETE FieldOfAction/:fieldOfActionId |
delObjective |
DELETE Objective/:objectiveId |
delObjective |
DELETE Objective/:objectiveId |
delObjectiveIndicator |
DELETE ObjectiveIndicator/ |
delObjectiveIndicator |
DELETE ObjectiveIndicator/ |
delProjectContribution |
DELETE ProjectContribution/ |
delProjectContribution |
DELETE ProjectContribution/ |
delStrategy |
DELETE Strategy/:strategyId |
delStrategy |
DELETE Strategy/:strategyId |
delVision |
DELETE Vision/:visionId |
delVision |
DELETE Vision/:visionId |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
getAllFieldsOfAction |
GET FieldsOfAction |
getAllFieldsOfAction |
GET FieldsOfAction |
Parameter list changed |
getAllObjectiveIndicators |
GET ObjectiveIndicators |
getAllObjectiveIndicators |
GET ObjectiveIndicators |
Parameter list changed |
getAllObjectives |
GET Objectives |
getAllObjectives |
GET Objectives |
Parameter list changed |
getAllProjectContributions |
GET ProjectContributions |
getAllProjectContributions |
GET ProjectContributions |
Parameter list changed |
getAllVisions |
GET Visions |
getAllVisions |
GET Visions |
Parameter list changed |
getContributionsByProject |
GET Project/ |
getProjectContributionsOfProject |
GET Project/ |
Parameter list changed |
getFieldOfAction |
GET FieldOfAction/:foaId |
getFieldOfAction |
GET FieldOfAction/:fieldOfActionId |
Response body changed |
getFieldOfActionHistory |
GET FieldOfAction/:foaId/History |
getFieldOfActionTimeline |
GET FieldOfAction/ |
Parameter list changed |
getFieldsOfAction |
GET Vision/ |
getFieldsOfActionOfVision |
GET Vision/ |
Parameter list changed |
getObjective |
GET Objective/:objectiveId |
getObjective |
GET Objective/:objectiveId |
Response body changed |
getObjectiveHistory |
GET Objective/:objectiveId/History |
getObjectiveTimeline |
GET Objective/ |
Parameter list changed |
getObjectiveIndicator |
GET ObjectiveIndicator/ |
getObjectiveIndicator |
GET ObjectiveIndicator/ |
Response body changed |
getObjectiveIndicatorHistory |
GET ObjectiveIndicator/ |
getObjectiveIndicatorTimeline |
GET ObjectiveIndicator/ |
Parameter list changed |
getObjectiveIndicators |
GET Objective/ |
getObjectiveIndicatorsOfObjective |
GET Objective/ |
Parameter list changed |
getObjectives |
GET FieldOfAction/ |
getObjectivesOfFieldOfAction |
GET FieldOfAction/ |
Parameter list changed |
getProjectContribution |
GET ProjectContribution/ |
getProjectContributions |
GET ProjectContributions/ |
1st parameter changed |
getProjectContributionHistory |
GET ProjectContribution/ |
getProjectContributionTimeline |
GET ProjectContribution/ |
Parameter list changed |
getProjectContributions |
GET Objective/ |
getProjectContributionsOfObjective |
GET Objective/ |
Parameter list changed |
getStrategies |
GET Strategies |
getAllStrategies |
GET Strategies |
Parameter list changed |
getStrategy |
GET Strategy/:strategyId |
getStrategy |
GET Strategy/:strategyId |
Response body changed |
getStrategyHistory |
GET Strategy/:strategyId/History |
getStrategyTimeline |
GET Strategy/:strategyId/Timeline |
Parameter list changed |
getVision |
GET Vision/:visionId |
getVision |
GET Vision/:visionId |
Response body changed |
getVisionHistory |
GET Vision/:visionId/History |
getVisionTimeline |
GET Vision/:visionId/Timeline |
Parameter list changed |
getVisions |
GET Strategy/:strategyId/Visions |
getVisionsOfStrategy |
GET Strategy/:strategyId/Visions |
Parameter list changed |
putFieldOfAction |
PUT FieldOfAction/:foaId |
putFieldOfAction |
PUT FieldOfAction/:fieldOfActionId |
Request body changed |
putObjective |
PUT Objective/:objectiveId |
putObjective |
PUT Objective/:objectiveId |
Request body changed |
putObjectiveIndicator |
PUT ObjectiveIndicator/ |
putObjectiveIndicator |
PUT ObjectiveIndicator/ |
Request body changed |
putProjectContribution |
PUT ProjectContribution/ |
putProjectContribution |
PUT ProjectContribution/ |
Request body changed |
putStrategy |
PUT Strategy/:strategyId |
putStrategy |
PUT Strategy/:strategyId |
Request body changed |
putVision |
PUT Vision/:visionId |
putVision |
PUT Vision/:visionId |
Request body changed |
New in V3 — no V2 equivalent.
getFieldOfActionIdentification, getFieldOfActionIdentifications, getFieldOfActionVersion, getFieldOfActions, getObjectiveIdentification, getObjectiveIdentifications, getObjectiveIndicatorIdentification, getObjectiveIndicatorIdentifications, getObjectiveIndicatorVersion, getObjectiveIndicators, getObjectiveVersion, getObjectives, getProjectContributionVersion, getStrategies, getStrategyIdentification, getStrategyIdentifications, getStrategyVersion, getVisionIdentification, getVisionIdentifications, getVisionVersion, getVisions
TDP — External (third-party) object references
This module was renamed wholesale. The V2 endpoints were named after four different things — Reference,
ForeignItem, ForeignKeyReference, ForeignKeyAssignments — for what is really one mirrored external object
plus one piece of configuration. All ten V2 endpoints are deprecated, and only the delete-by-key endpoint
could be redirected — every other body contract changed. Plan a rewrite of the whole integration surface.
The new vocabulary:
| Concept | V3 name |
|---|---|
| A PQFORCE object type that may carry external objects, with its maximum count | AssignableObjectType |
| An external object mirrored in PQFORCE | ExternalObject |
| The external system's own key for it | externalKey |
| The PQFORCE object it is assigned to | assignedTo |
| URL parameters | objectType / objectId / externalObjectId |
Member renames inside the payload:
| V2 | V3 |
|---|---|
foreignName / foreignCode / foreignDescription |
name / code / description |
foreignImageUrl |
iconUrl |
foreignKey |
externalKey |
pqforceId |
assignedTo — a pf.Reference, so the type is explicit |
pqforceName / pqforceCode / pqforceDescription / pqforceImageUrl |
not in the payload; read them with the identification endpoint of the assigned object's module |
typeId (on the type contract) |
objectType |
additionalData |
unchanged |
Two contracts disappear: the "with own data" variant (the PQFORCE object's name, code, description and
image) has no successor, and the assignment contract is replaced by a plain pf.Reference array.
Behaviour worth knowing:
getForeignItemandgetForeignItemsare dropped, not renamed. They returned the same rows as the reference endpoints in a different shape, and put the external key where the ID belonged. UsegetExternalObjectByKey(orgetExternalObjectIdentification) andgetAllExternalObjects.- A single assignment can now be changed atomically:
assignExternalObjectandunassignExternalObjecttake anobjectIdand change one assignment, instead of reading the whole set and writing it back. Prefer them overputExternalObjectAssignmentswhenever you change one link, so a concurrent change cannot be lost. putExternalObjectrejects a changedexternalKeywith400, because the key is part of the object's identity.assignedandunassignedongetAllExternalObjectsare still two independent booleans, both defaulting to true — including the quirk that setting both to false yields an empty list.getAllExternalObjectsanswers references, not whole objects, each one carrying theexternalKeyand, for an assigned object, the PQFORCE object it is assigned to as itsparent. Read the objects themselves withgetExternalObjects/. It also takes a:objectType/ :externalObjectIds sortnow, overtype,id,externalKey,name,code,descriptionandassignedTo.ExternalObject.typeis still3rdPartyRef/<objectType>and itsidis still derived from(objectType, externalKey), exactly as in V2. Existing IDs stay valid.- New in V3: the full object family — bulk read,
put,del, identifications, version timeline, historic versions, recently deleted and undelete — none of which V2 offered.
Redirected — the V2 URL answers 307 with the V3 location; request and response are identical.
| V2 endpoint | V2 path | V3 endpoint | V3 path |
|---|---|---|---|
delForeignKeyReference |
DELETE :type/ |
delExternalObjectByKey |
DELETE ExternalObjectByKey/ |
Reimplemented — no redirect; the call has to be rewritten.
| V2 endpoint | V2 path | V3 endpoint | V3 path | What differs |
|---|---|---|---|---|
getForeignItem |
GET :type/ForeignItem/:foreignKey |
getExternalObjectByKey |
GET ExternalObjectByKey/ |
Response body changed |
getForeignItems |
GET :type/ForeignItems |
getAllExternalObjects |
GET ExternalObjects/:objectType |
Parameter list changed, returns references; read the objects with getExternalObjects/:ids |
getForeignKeyAssignments |
GET :type/ |
getExternalObjectAssignments |
GET Object/ |
Response body changed |
getForeignKeyReference |
GET :type/ |
getExternalObjectByKey |
GET ExternalObjectByKey/ |
Response body changed |
getReference |
GET :type/Reference/:internalId |
getExternalObject |
GET ExternalObject/ |
Response body changed |
getReferences |
GET :type/References |
getAllExternalObjects |
GET ExternalObjects/:objectType |
Returns references; read the objects with getExternalObjects/:ids |
getReferenceTypes |
GET ReferenceTypes |
getAllAssignableObjectTypes |
GET AssignableObjectTypes |
Response body changed |
putForeignKeyAssignments |
PUT :type/ |
putExternalObjectAssignments |
PUT Object/ |
Request body changed |
putForeignKeyReference |
PUT :type/ |
putExternalObjectByKey |
PUT ExternalObjectByKey/ |
Request body changed; an absent assignedTo keeps the assignment, where V2's absent pqforceId cleared it |
New in V3 — no V2 equivalent.
assignExternalObject, delExternalObject, getAssignableObjectType, getExternalObjectIdentification, getExternalObjectIdentifications, getExternalObjectTimeline, getExternalObjectVersion, getExternalObjects, getRecentlyDeletedExternalObjects, putExternalObject, unassignExternalObject, undelExternalObject
11. A practical migration order
If you are planning the work rather than reading it endpoint by endpoint:
- Inventory what you actually call. Run your integration or automation once and collect every response that
carries a
Deprecationheader (or, in a JavaScript automation, every deprecation warning in the console). That list, not this document, is your scope. - Regenerate your client from the V3 OpenAPI description (section 3) into a separate namespace, so V2 and V3 calls can coexist while you move.
- Take the redirects first. They are URL or function-name changes with no behavioural risk, and they clear a
large part of the list cheaply. Check that your HTTP client follows
307forPUTandPOSTbefore you start. - Then the reads. Convert list screens to the reference-plus-page pattern (section 5.2) and switch label-only views to identifications (section 5.5). This is where V3 pays off, and it is low-risk: reads are idempotent.
- Then the writes. Request bodies changed on many
put…endpoints. Do these module by module, with the reference documentation open, and delete the follow-upPUTafter eachAddyou convert (section 5.8). - Handle the retirements. Section 8 and the Retired tables in section 10. These need a decision, not a rewrite — a replacement mechanism, or dropping the feature.
- Finish before the end of 2028. Every call you make has a V3 successor or a retirement decision, so a
complete migration is possible today. Check the
Deprecationheaders once more at the end: when none is left, you are done.
Two things worth doing while you are in the code anyway: switch anything that polls to the change-notification
WebSocket (section 5.14), and delete client-side sorting in favour of the sort parameter (section 5.4).
12. How this document is maintained
The migration from V2 to V3 is complete, so this document no longer grows release by release. It is revised only when something a migrating developer needs to know changes:
- Sections 1–9 describe concepts and change rarely.
- Section 10 changes when a deferred endpoint gets its V3 successor — currently only PM
getProjectScenarioChangesTimeline— or when a change to an existing V3 endpoint becomes unavoidable. Such a change is announced through the usual deprecation channel — aDeprecationheader and a note in the reference documentation — not silently. - Counts in this document — the totals in section 2, the per-module table in section 2.5 — describe the release named at the top. Compare them against the release you are running.
| Release | What changed in this guide |
|---|---|
| 4.26.6 | First edition. Covers the complete V2 → V3 migration (100 %): ACM, ACT, ALC, ATM, CHT, CLF, CLS, EXP, FCO, LCY, LIC, MAIN, MSG, MTG, PF, PI, PM, RES, RSK, STG and TDP fully migrated; DOC, DPO and NAV retired. The work-item object type became ProjectWorkItem (section 6). |