Aller au contenu
Pages de documentation

API reference

Base URL: https://api.cadae.ai. Interactive documentation lives at /v1/docs, generated from the published OpenAPI description.

Authentication

Send a bearer token in the Authorization header. Three kinds:

PrefixKindActs as
cad_osk_…Portfolio tokenThe Portfolio (created by an Owner)
cad_pat_…Personal tokenYou, scopes capped by your role
cad_at_…OAuth access tokenA consenting user

Create a Portfolio or personal token in Settings → Developer. An OAuth client gets its access token through the flow in OAuth & scopes.

A request is refused with 401 only when the credential itself fails: it is missing, malformed, unknown, revoked or expired, or it names an account that no longer exists, such as a cad_osk_ token whose creator's account was deleted. A credential that is valid but not allowed is refused with 403: the person behind it has no active membership in the Portfolio (suspended, removed or never a member), a cad_osk_ token's creator is not an Owner, or the token belongs to a Cadae Super Admin (who cannot hold API tokens). REST and MCP answer the same way, and a REST 403 on a scope check also names the requiredScope.

Errors

Every non-2xx answer is { error, code, reason?, requiredScope? }. error is a sentence, code is the machine-readable reason — branch on that, not on the words. reason narrows a code when the refusal is one you may want to tell apart from its neighbours; today the only value is MODULE_DISABLED:

StatuscodeWhen
400BAD_REQUESTthe input failed validation
401UNAUTHORIZEDthe credential itself is not one
403FORBIDDENthe credential is valid and its holder or its scope does not cover this; a scope refusal also carries requiredScope, and a hotel whose module is switched off carries reason: "MODULE_DISABLED"
404NOT_FOUNDno such row
409CONFLICTthe world moved while your command was in flight, or the name is taken
412PRECONDITION_FAILEDa condition you can satisfy is unmet
429TOO_MANY_REQUESTStoo many requests

reason: "MODULE_DISABLED" means the Hotel does not have that module enabled — it is not an empty result and must never be rendered as a zero. Read GET /v1/hotels/{hotelId}/modules for the Hotel's own flags. A 403 with no reason is an access refusal, and says nothing about the Hotel's modules.

List filters

A repeated query parameter is an array: ?type=role_changed&type=member_invited (style: form, explode: true, as the OpenAPI document declares). A comma is never a separator — ?name=Grand,Central is one value.

Scopes and endpoints

Scopes are capped by the holder's role in the Portfolio, from the permission matrix: organisation.write is Owner only; hotel.read|write, members.read|write, invites.write and activities.read need an Owner or an Administrator. A personal token can never carry a scope its holder could not use.

Scopes

viewer.read · organisation.read · organisation.write · hotel.read · hotel.write · members.read · members.write · invites.write · activities.read · notifications.read · phi.read · phi.write · projects.read · projects.write · projects.approve · budgets.write · tasks.read · tasks.write · documents.read · documents.write · events.read · events.write · risks.read · risks.write

…plus the aliases apis.all and apis.read. More scope names are reserved for capabilities not yet released; a token can only carry one an endpoint below needs.

Endpoints

EndpointScopeWhat
GET /v1/access-eventsactivities.readAccess and membership audit events
GET /v1/activitiesactivities.readPortfolio audit feed
GET /v1/asset-typesprojects.readAsset types this Portfolio can use, with their active configurable fields
GET /v1/contextviewer.readResolve and re-authorise a route context
GET /v1/context/landingviewer.readWhere the signed-in user lands
GET /v1/context/treeviewer.readAuthorised Portfolios and hotels for the switcher
GET /v1/documentsdocuments.readDocuments attached to a record, or held at a scope
GET /v1/documents/{documentId}documents.readOne document, with its versions and links
POST /v1/documents/{documentId}/linksdocuments.writeAttach a document to a record
DELETE /v1/documents/{documentId}/linksdocuments.writeDetach a document from a record
POST /v1/documents/{documentId}/versionsdocuments.writeReplace a document with a new version
POST /v1/documents/referencesdocuments.writeRecord reference-only evidence and link it to the record it supports
POST /v1/documents/upload-urldocuments.writeReserve a document and mint a signed upload URL
GET /v1/documents/versions/{versionId}/downloaddocuments.readDownload a document version (REST streams the file)
GET /v1/documents/versions/{versionId}/download-urldocuments.readMint a signed download URL for a document version
POST /v1/documents/versions/{versionId}/finalisedocuments.writeFinalise an uploaded document version
POST /v1/documents/versions/{versionId}/markdocuments.writeMark a version superseded or added in error
GET /v1/hotel-names/checkhotel.writeWould this hotel name be refused as a duplicate?
GET /v1/hotelshotel.readHotels I can access
POST /v1/hotelshotel.writeCreate hotel
GET /v1/hotels-comparephi.readUp to five hotels side by side
GET /v1/hotels-league-tablephi.readThe Portfolio's hotels league table
GET /v1/hotels-league-table/exportphi.readThe Portfolio's hotels league table as CSV (REST streams the file)
GET /v1/hotels/{hotelId}hotel.readOne hotel
PATCH /v1/hotels/{hotelId}hotel.writeUpdate hotel
GET /v1/hotels/{hotelId}/activityactivities.readA hotel's activity
GET /v1/hotels/{hotelId}/annual-confirmationsphi.readThe hotel's annual property-model confirmations
POST /v1/hotels/{hotelId}/annual-confirmations/{confirmationId}/confirmphi.writeAnswer an annual property-model confirmation
GET /v1/hotels/{hotelId}/applicability-overridesphi.readThe hotel's applicability overrides
GET /v1/hotels/{hotelId}/assumptionsphi.readThe hotel's assumption needs and values
POST /v1/hotels/{hotelId}/assumptionsphi.writePropose that an assumption is needed
GET /v1/hotels/{hotelId}/assumptions/approvedphi.readThe hotel's approved assumptions for a period
GET /v1/hotels/{hotelId}/bill-inbox-addressphi.readThe hotel's bill forwarding address
POST /v1/hotels/{hotelId}/bill-inbox-addressphi.writeMint the hotel's bill forwarding address
POST /v1/hotels/{hotelId}/bill-suggestions/{suggestionId}/confirmphi.writeConfirm a suggested match
POST /v1/hotels/{hotelId}/bill-suggestions/{suggestionId}/declinephi.writeDecline a suggested match
GET /v1/hotels/{hotelId}/billsphi.readThe hotel's bill inbox
POST /v1/hotels/{hotelId}/billsphi.writeAdd a finalised document to the bill inbox
GET /v1/hotels/{hotelId}/bills/{billDocumentId}phi.readOne inbound bill and its suggested matches
POST /v1/hotels/{hotelId}/bills/{billDocumentId}/archivephi.writeArchive an inbound bill
POST /v1/hotels/{hotelId}/bills/{billDocumentId}/attachphi.writeAttach a bill to a source and a draft month by hand
POST /v1/hotels/{hotelId}/bills/{billDocumentId}/retry-extractionphi.writeRead an inbound bill again
GET /v1/hotels/{hotelId}/bills/{billDocumentId}/suggestionsphi.readThe suggested matches for one bill
GET /v1/hotels/{hotelId}/boundary-rulesphi.readThe hotel's calculation-boundary rules
POST /v1/hotels/{hotelId}/boundary-rulesphi.writePropose a calculation-boundary rule
GET /v1/hotels/{hotelId}/boundary-rules/approvedphi.readThe hotel's boundary rules in force on a date (approved, or superseded after it)
GET /v1/hotels/{hotelId}/budgets/{budgetYear}projects.readThe delegated budget position for one hotel and budget year
PUT /v1/hotels/{hotelId}/budgets/{budgetYear}budgets.writeSet a hotel's delegated budget for one budget year
GET /v1/hotels/{hotelId}/budgets/{budgetYear}/ledgerprojects.readThe append-only budget ledger for one hotel and budget year
GET /v1/hotels/{hotelId}/correction-requestsphi.readThe hotel's correction requests and Cadae's answers
GET /v1/hotels/{hotelId}/data-gapsphi.readThe hotel's open data gaps
POST /v1/hotels/{hotelId}/data-gaps/{gapId}/acknowledgephi.writeAcknowledge a data gap
GET /v1/hotels/{hotelId}/data-sourcesphi.readThe hotel's data-source register
POST /v1/hotels/{hotelId}/data-sourcesphi.writeRegister a data source for the hotel
PATCH /v1/hotels/{hotelId}/data-sources/{dataSourceId}phi.writeChange an active data source of the hotel
POST /v1/hotels/{hotelId}/data-sources/{dataSourceId}/closephi.writeClose a data source of the hotel
POST /v1/hotels/{hotelId}/data-sources/{dataSourceId}/replacephi.writeReplace a meter of the hotel, with its closing and opening readings
GET /v1/hotels/{hotelId}/data-sources/activephi.readThe hotel's data sources active on a date
POST /v1/hotels/{hotelId}/lifecyclehotel.writeSet hotel lifecycle status
GET /v1/hotels/{hotelId}/membersmembers.readHotel members
POST /v1/hotels/{hotelId}/membersmembers.writeGrant hotel access
DELETE /v1/hotels/{hotelId}/members/{userId}members.writeRevoke hotel access
GET /v1/hotels/{hotelId}/moduleshotel.readModules enabled for a hotel
POST /v1/hotels/{hotelId}/period-findings/{findingId}/explainphi.writeExplain a validation finding
GET /v1/hotels/{hotelId}/periodsphi.readThe hotel's reporting months
GET /v1/hotels/{hotelId}/periods/{month}phi.readOne reporting month
PATCH /v1/hotels/{hotelId}/periods/{month}phi.writeSave a month's draft data
POST /v1/hotels/{hotelId}/periods/{month}/correction-requestsphi.writeAsk Cadae to correct a locked or published month
GET /v1/hotels/{hotelId}/periods/{month}/historyphi.readThe input versions of one reporting month
GET /v1/hotels/{hotelId}/periods/{month}/readinessphi.readThe month's ready-to-submit checklist
POST /v1/hotels/{hotelId}/periods/{month}/submitphi.writeSubmit a month to Cadae
GET /v1/hotels/{hotelId}/periods/{month}/submitted-versionphi.readThe submitted input version of a month
POST /v1/hotels/{hotelId}/periods/{month}/validatephi.writeRe-run the validation catalogue over a month
POST /v1/hotels/{hotelId}/periods/baselinephi.writeCreate the hotel's baseline reporting months
GET /v1/hotels/{hotelId}/phi-contactsphi.readThe hotel's PHI data contacts
PUT /v1/hotels/{hotelId}/phi-contactsphi.writeSet the hotel's PHI data contacts
GET /v1/hotels/{hotelId}/phi-summary/actionsphi.readA hotel's action progress: Savings Task buckets, Projects by stage and what completed in the period
GET /v1/hotels/{hotelId}/phi-summary/moneyphi.readA hotel's money story: savings realised in the period, the remaining opportunity and the investment return — three figures, never added
GET /v1/hotels/{hotelId}/phi-summary/risksphi.readA hotel's risk summary: open findings by severity, the oldest unresolved and the top types
GET /v1/hotels/{hotelId}/phi/dashboard/category-driversphi.readThe hotel's largest PHI category drivers
GET /v1/hotels/{hotelId}/phi/dashboard/coveragephi.readThe hotel's PHI data coverage
GET /v1/hotels/{hotelId}/phi/dashboard/intensityphi.readThe hotel's operational intensity measures
GET /v1/hotels/{hotelId}/phi/dashboard/resource-trendphi.readOne resource's monthly trend
GET /v1/hotels/{hotelId}/phi/dashboard/seriesphi.readThe hotel's PHI over time
GET /v1/hotels/{hotelId}/phi/dashboard/summaryphi.readThe hotel dashboard's headline cards and notices
GET /v1/hotels/{hotelId}/phi/dashboard/yearly-totalsphi.readOne resource's published calendar-year totals
GET /v1/hotels/{hotelId}/phi/import-mappingsphi.readA hotel's saved import source mappings
POST /v1/hotels/{hotelId}/phi/importsphi.writeOpen a staged import over an uploaded workbook
GET /v1/hotels/{hotelId}/phi/importsphi.readA hotel's staged imports
GET /v1/hotels/{hotelId}/phi/resultsphi.readThe hotel's published PHI results
GET /v1/hotels/{hotelId}/phi/results/for-projectsphi.readPublished PHI quantities with their publication ids
GET /v1/hotels/{hotelId}/phi/results/latestphi.readThe hotel's latest published PHI result
GET /v1/hotels/{hotelId}/phi/source-selectionsphi.readThe source selections recorded for a hotel
GET /v1/hotels/{hotelId}/phi/templatephi.readThe hotel's PHI data template (REST streams the .xlsx workbook)
POST /v1/hotels/{hotelId}/primary-contactmembers.writeSet a hotel's primary contact
GET /v1/hotels/{hotelId}/project-assetsprojects.readA hotel's asset records, with their configured field answers
POST /v1/hotels/{hotelId}/project-assetsprojects.writeCreate an asset record, with its first configured answers
GET /v1/hotels/{hotelId}/projects-setupprojects.readA hotel's Projects setup: baselines, price forecasts, delegated budget and readiness
PATCH /v1/hotels/{hotelId}/projects-setupprojects.writeSave a hotel's Projects baselines and price forecasts
GET /v1/hotels/{hotelId}/projects-setup/baselinesprojects.readA hotel's annual Energy and Water baselines, with what PHI proposes
PUT /v1/hotels/{hotelId}/projects-setup/baselines/{resource}projects.writeAccept PHI's baseline, or override it with a reason
GET /v1/hotels/{hotelId}/projects-setup/pricesprojects.readA hotel's utility prices for this budget year and the next three, VAT-exclusive
PUT /v1/hotels/{hotelId}/projects-setup/pricesprojects.writeSet utility prices, or a yearly % increase, for the current budget year and the next three
GET /v1/hotels/{hotelId}/projects-setup/readinessprojects.readWhether a hotel's Projects setup is ready, and what is missing
GET /v1/hotels/{hotelId}/projects-summary/pipelineprojects.readOne hotel's remaining opportunity: gross, adjusted for overlaps, on hold and awaiting verification
GET /v1/hotels/{hotelId}/property-modelphi.readThe hotel's property model, with every record
GET /v1/hotels/{hotelId}/property-model/approvedphi.readThe approved property model on a date or across a period
POST /v1/hotels/{hotelId}/property-model/building-sectionsphi.writeCreate or change a building section of the hotel's draft property model
DELETE /v1/hotels/{hotelId}/property-model/building-sections/{logicalId}phi.writeRemove a building section from the hotel's draft property model
PATCH /v1/hotels/{hotelId}/property-model/draftphi.writeSave one section of the hotel's draft property model
POST /v1/hotels/{hotelId}/property-model/facility-closuresphi.writeRecord or change a closure in the hotel's draft property model
DELETE /v1/hotels/{hotelId}/property-model/facility-closures/{logicalId}phi.writeRemove a closure from the hotel's draft property model
PUT /v1/hotels/{hotelId}/property-model/facility-presence/{kind}phi.writeAnswer whether the hotel has a facility
POST /v1/hotels/{hotelId}/property-model/facility-systemsphi.writeRecord or change a facility system in the hotel's draft property model
PUT /v1/hotels/{hotelId}/property-model/facility-systems/{logicalId}/areasphi.writeSet the usage areas a facility system serves
POST /v1/hotels/{hotelId}/property-model/facility-systems/{logicalId}/closephi.writeClose a facility system of the hotel's draft property model
GET /v1/hotels/{hotelId}/property-model/field-historyphi.readEvery value one property-model field has held
GET /v1/hotels/{hotelId}/property-model/reviewphi.readThe property model's review: section states, totals and submission blockers
GET /v1/hotels/{hotelId}/property-model/sectionsphi.readThe property model's sections, fields and answers
GET /v1/hotels/{hotelId}/property-model/setup-overviewphi.readThe hotel's PHI setup overview: workstreams, readiness and blockers
POST /v1/hotels/{hotelId}/property-model/submitphi.writeSubmit the hotel's property model for Cadae review
POST /v1/hotels/{hotelId}/property-model/usage-areasphi.writeCreate or change a usage area of the hotel's draft property model
DELETE /v1/hotels/{hotelId}/property-model/usage-areas/{logicalId}phi.writeRemove a usage area from the hotel's draft property model
GET /v1/hotels/{hotelId}/property-model/versionsphi.readThe hotel's property-model versions
GET /v1/hotels/{hotelId}/source-record-chargesphi.readThe charge lines of a set of records
POST /v1/hotels/{hotelId}/source-records/{recordId}/mark-duplicatephi.writeMark a record as a duplicate of another
POST /v1/hotels/{hotelId}/source-records/{recordId}/resolve-duplicatephi.writeClear a record's duplicate flag
POST /v1/hotels/{hotelId}/source-records/{recordId}/voidphi.writeVoid a utility source record
GET /v1/hotels/{hotelId}/taskstasks.readA hotel's Savings Tasks across its Projects, with overdue derived in the hotel's time zone
GET /v1/invitesmembers.readList invitations
POST /v1/invitesinvites.writeInvite a member
PATCH /v1/invites/{invitationId}invites.writeEdit and resend an invitation
POST /v1/invites/{invitationId}/cancelinvites.writeCancel an invitation
POST /v1/invites/{invitationId}/resendinvites.writeResend an invitation
POST /v1/invites/{invitationId}/retry-deliveryinvites.writeRetry a failed invitation delivery
POST /v1/invites/batchinvites.writeInvite several people
GET /v1/membersmembers.readPortfolio members
PATCH /v1/members/{userId}members.writeChange a member's role, department or hotels
DELETE /v1/members/{userId}members.writeRemove a member from the Portfolio
POST /v1/members/{userId}/access-instructionsmembers.writeEmail a member their sign-in instructions
GET /v1/members/{userId}/removal-previewmembers.readOpen work and assignments a removal would affect
POST /v1/members/{userId}/restoremembers.writeRestore a suspended Portfolio membership
POST /v1/members/{userId}/suspendmembers.writeSuspend a Portfolio membership
GET /v1/notificationsnotifications.readMy notifications
GET /v1/organisationsorganisation.readPortfolios I can open
GET /v1/organisations/{organisationId}organisation.readPortfolio detail
PATCH /v1/organisations/{organisationId}organisation.writeUpdate a Portfolio
GET /v1/peoplemembers.readPeople and access
GET /v1/people-summarymembers.readPeople and access summary counts
GET /v1/people/{userId}members.readOne person's access
POST /v1/people/check-contactsmembers.readCheck contacts before inviting
GET /v1/phi-eventsevents.readPHI events I can see, filtered
POST /v1/phi-eventsevents.writeCreate a PHI event as a draft
GET /v1/phi-events-timelineevents.readThe PHI event markers for a chart
GET /v1/phi-events/{id}events.readOne PHI event
PATCH /v1/phi-events/{id}events.writeEdit a PHI event
POST /v1/phi-events/{id}/archiveevents.writeArchive a PHI event
POST /v1/phi-events/{id}/dateevents.writeMove a PHI event's date
POST /v1/phi-events/{id}/publishevents.writePublish a PHI event
GET /v1/phi-summary/actionsphi.readThe Portfolio's action progress: Savings Task buckets, Projects by stage and what completed in the period
GET /v1/phi-summary/moneyphi.readThe Portfolio's money story: savings realised in the period, the remaining opportunity and the investment return — three figures, never added
GET /v1/phi-summary/risksphi.readThe Portfolio's risk summary: open findings by severity, the oldest unresolved, the top types and the hotels affected
GET /v1/phi/categoriesphi.readThe Portfolio's PHI category breakdown
GET /v1/phi/comparison-groupsphi.readThe Portfolio dashboard's four hotel comparison groups
GET /v1/phi/confidencephi.readEach hotel's PHI confidence, behind the Portfolio counts
GET /v1/phi/context-markersphi.readThe Portfolio's cohort context markers
GET /v1/phi/coveragephi.readThe Portfolio's PHI data coverage
GET /v1/phi/dashboard/points/{resultId}phi.readOne point of the PHI series, in detail
GET /v1/phi/imports/{batchId}phi.readOne staged import
POST /v1/phi/imports/{batchId}/confirmphi.writeApply a validated import to the hotel's drafts
POST /v1/phi/imports/{batchId}/discardphi.writeDiscard a staged import
POST /v1/phi/imports/{batchId}/remapphi.writeMap several source labels to registered meters
GET /v1/phi/imports/{batchId}/rowsphi.readThe staged rows of one import
POST /v1/phi/imports/{batchId}/rows/{rowId}/resolvephi.writeDecide what to do with one staged row
POST /v1/phi/imports/{batchId}/validatephi.writeParse and classify a staged import
GET /v1/phi/intensityphi.readThe Portfolio's intensity measures, as ratios of totals
GET /v1/phi/publications/{publicationId}phi.readOne PHI publication and the windows it published
GET /v1/phi/publications/{publicationId}/historyphi.readThe correction history of a published window
GET /v1/phi/resource-trendphi.readOne resource's monthly totals across the Portfolio
GET /v1/phi/results/{resultId}/breakdownphi.readOne result's category totals and intensity measures
GET /v1/phi/results/{resultId}/co2phi.readOne published month's CO₂ outputs
GET /v1/phi/results/{resultId}/confidencephi.readOne result's confidence level and reason
GET /v1/phi/results/{resultId}/costphi.readOne published month's eligible cost and theoretical cost gap
GET /v1/phi/summaryphi.readThe Portfolio's PHI headline cards
GET /v1/phi/trendphi.readPHI over time, one line per hotel
GET /v1/programmesprojects.readThe Portfolio's programme labels
POST /v1/programmesprojects.writeCreate a programme label
PATCH /v1/programmes/{programmeId}projects.writeRename a programme or change its description
POST /v1/programmes/{programmeId}/archiveprojects.writeArchive a programme label
GET /v1/project-assets/{assetId}projects.readOne asset record, with its answers and (optionally) their history
PATCH /v1/project-assets/{assetId}projects.writeChange an asset record's name, location, quantity or details
POST /v1/project-assets/{assetId}/archiveprojects.writeArchive an asset record (kept, read-only)
PUT /v1/project-assets/{assetId}/field-valuesprojects.writeAnswer an asset record's configured fields
GET /v1/project-templatesprojects.readProject templates this Portfolio can create a Project from
GET /v1/project-templates/{templateVersionId}projects.readOne Project template version and everything it gives a Project
GET /v1/projectsprojects.readProjects I can see, filtered
POST /v1/projectsprojects.writeCreate a Project in Draft
GET /v1/projects-dashboard/analyticsprojects.readThe Projects Analytics panels — status, type, hotel, return, budget, confidence and exceptions, over the filtered set
GET /v1/projects-dashboard/boardprojects.readThe Projects Pipeline board — six lifecycle columns, their totals and the exception lane
POST /v1/projects-dashboard/board/reorderprojects.writeMove a Project within its column of the Pipeline board's manual order
GET /v1/projects-dashboard/filter-optionsprojects.readThe Projects dashboard's filter options, from the Projects the caller can read
GET /v1/projects-dashboard/listprojects.readOne page of the Projects List — filtered, sorted and paged on the server
GET /v1/projects-dashboard/summaryprojects.readThe Projects dashboard's five headline cards, with the Projects behind each figure
GET /v1/projects-dashboard/timelineprojects.readThe Projects Timeline — planned bars, milestone markers and the Projects whose dates are required
POST /v1/projects-from-templateprojects.writeCreate a Project in Draft from a Project template
GET /v1/projects-open-workprojects.readThe open work one person still holds: the Projects they own and the Savings Tasks they own or contribute to
POST /v1/projects-open-work/reassignprojects.writeReassign one person's open work — the Projects and Savings Tasks they own, their open task contributions and the milestones they own
GET /v1/projects-summary/pipelineprojects.readThe Portfolio's remaining opportunity: gross, adjusted for overlaps, on hold and awaiting verification
GET /v1/projects/{projectId}projects.readOne Project, with its governance answer, its action bar and its owner
PATCH /v1/projects/{projectId}projects.writeUpdate a Project's details (never its status)
POST /v1/projects/{projectId}/approve-under-delegationprojects.approveApprove (or re-approve) a Project within the hotel's delegated authority
PUT /v1/projects/{projectId}/assets/{assetId}projects.writeFile one of the hotel's asset records under this Project
DELETE /v1/projects/{projectId}/assets/{assetId}projects.writeTake an asset record out of this Project (it stays with the hotel)
PUT /v1/projects/{projectId}/budget-yearprojects.writeMove a Project to another budget year
GET /v1/projects/{projectId}/business-caseprojects.readA Project's business case: Cadae's calculated summary and the hotel team's sections
POST /v1/projects/{projectId}/business-case/exportprojects.writeGenerate a Project's business case as a PDF, filed in its Documents as Generated by Cadae — answers the export request and its state (stored, pending or failed)
GET /v1/projects/{projectId}/business-case/exports/{requestId}projects.readThe state of a business-case PDF export you requested: stored (with a download URL), pending or failed
GET /v1/projects/{projectId}/business-case/printprojects.readA Project's business case as a printable HTML document, in the hotel's language — about 350 KB, most of it the inlined typeface
POST /v1/projects/{projectId}/business-case/reviewprojects.writeMark a Project's business-case sections reviewed against its current figures
PUT /v1/projects/{projectId}/business-case/sections/{sectionKey}projects.writeWrite one section of a Project's business case
GET /v1/projects/{projectId}/collaboratorsprojects.readWho is on this Project, and which of the hotel's people may be added
PUT /v1/projects/{projectId}/collaborators/{userId}projects.writePut somebody on this Project, or change the role they hold
DELETE /v1/projects/{projectId}/collaborators/{userId}projects.writeTake somebody off this Project
GET /v1/projects/{projectId}/commentsprojects.readA Project's comments, newest first
POST /v1/projects/{projectId}/commentsprojects.writePost a comment, mentioning colleagues with @name
POST /v1/projects/{projectId}/completionprojects.writeComplete a Project — refused 412 until every item of the completion checklist is met
POST /v1/projects/{projectId}/completion/readinessprojects.readThe Complete checklist, over the stored answers or a draft of them — nothing is saved
GET /v1/projects/{projectId}/confidenceprojects.readThe confidence judgements recorded on this Project
POST /v1/projects/{projectId}/confidenceprojects.writeRecord a confidence judgement, with its reason
GET /v1/projects/{projectId}/copy-to-draftprojects.writePreview restarting a cancelled Project as a new Draft in its own hotel
POST /v1/projects/{projectId}/copy-to-draftprojects.writeRestart a cancelled Project as a new Draft in its own hotel
GET /v1/projects/{projectId}/copy-to-hotelprojects.writePreview a copy of this Project into another hotel of the Portfolio: what travels and what stays
POST /v1/projects/{projectId}/copy-to-hotelprojects.writeCopy this Project into another hotel of the Portfolio as a new Draft (an Owner's)
GET /v1/projects/{projectId}/costsprojects.readA Project's actual costs, the cost to date, the forecast and the variances against the approved amount and the preferred quote
POST /v1/projects/{projectId}/costsprojects.writeRecord an actual cost (VAT-exclusive) — posted to the hotel's budget ledger as actual spend
PUT /v1/projects/{projectId}/costs/{costId}projects.writeCorrect an actual cost — a changed amount posts its difference to the ledger
POST /v1/projects/{projectId}/costs/proposals/{proposalId}/confirmprojects.writeConfirm a supplier invoice the bill inbox proposed — recorded as an actual cost and posted to the ledger, as the person confirming; the document's figures may be corrected
POST /v1/projects/{projectId}/costs/proposals/{proposalId}/dismissprojects.writeDismiss a supplier invoice the bill inbox proposed, with the reason — nothing is recorded or posted
POST /v1/projects/{projectId}/decisionsprojects.approveRecord an approval decision on a submitted Project, or re-approve an outgrown one
GET /v1/projects/{projectId}/delivery/readinessprojects.readThe Start delivery checklist: every item with whether it is satisfied and why not
POST /v1/projects/{projectId}/delivery/startprojects.writeStart delivery — refused 412 until every item of the delivery checklist is met
GET /v1/projects/{projectId}/document-requirementsdocuments.readThe document categories one of a Project's gates requires, each with whether a live document satisfies it
GET /v1/projects/{projectId}/financialsprojects.readA Project's financial position, computed now, with its stored version
POST /v1/projects/{projectId}/financials/accept-recalculationprojects.writeAccept a Project's recalculation: re-pin a stale PHI baseline and recompute its figures
GET /v1/projects/{projectId}/financials/versionsprojects.readThe immutable financial versions, newest first
POST /v1/projects/{projectId}/financials/versionsprojects.writeSave this Project's figures as a new immutable version
PUT /v1/projects/{projectId}/forecastprojects.writeRecord a Project's revised final cost
GET /v1/projects/{projectId}/fundingprojects.readA Project's external funding, confirmed and potential
PUT /v1/projects/{projectId}/funding/{fundingId}projects.writeCreate or replace one external funding row
DELETE /v1/projects/{projectId}/funding/{fundingId}projects.writeRemove one external funding row from the live set
GET /v1/projects/{projectId}/governanceprojects.readApproval requirement, approval state and budget position
GET /v1/projects/{projectId}/historyprojects.readA Project's lifecycle events and approval decisions
GET /v1/projects/{projectId}/inbox-proposalsprojects.readThe supplier invoices and quotes the bill inbox proposed to a Project, pending first — none is a recorded cost or quote until confirmed
GET /v1/projects/{projectId}/investment-linesprojects.readA Project's investment lines
PUT /v1/projects/{projectId}/investment-lines/{lineId}projects.writeCreate or replace one investment line (VAT-exclusive)
DELETE /v1/projects/{projectId}/investment-lines/{lineId}projects.writeRemove one investment line from the live set
GET /v1/projects/{projectId}/milestonesprojects.readA Project's milestones, with overdue derived in the hotel's time zone and owner access shown
POST /v1/projects/{projectId}/milestonesprojects.writeAdd a milestone to a Project's plan
PUT /v1/projects/{projectId}/milestones/{milestoneId}projects.writeReplace a milestone's fields (a date change keeps the previous date in history)
DELETE /v1/projects/{projectId}/milestones/{milestoneId}projects.writeTake a milestone out of the plan (a completed one stays)
POST /v1/projects/{projectId}/milestones/{milestoneId}/completeprojects.writeComplete a milestone on a date (the go-live milestone raises project.went_live)
POST /v1/projects/{projectId}/milestones/{milestoneId}/go-liveprojects.writeMake this milestone the Project's one operational go-live
PUT /v1/projects/{projectId}/milestones/{milestoneId}/ownerprojects.writeAssign or clear a milestone's owner (an active person with access to the hotel)
GET /v1/projects/{projectId}/overviewprojects.readA Project's identity, scope and dates
PATCH /v1/projects/{projectId}/overviewprojects.writeEdit a Project's scope, dates and narrative
PUT /v1/projects/{projectId}/ownerprojects.writeAssign or clear a Project's owner
PUT /v1/projects/{projectId}/owner-approvalprojects.approveRequire (or stop requiring) Owner approval for this Project
PUT /v1/projects/{projectId}/quote-requiredprojects.writeSay whether Start delivery needs a preferred quote; “no quote required” carries its reason
GET /v1/projects/{projectId}/quotesprojects.readA Project's quotes, each with its displayed status (Expired derived in the hotel's time zone)
POST /v1/projects/{projectId}/quotesprojects.writeRecord a supplier's quote (received; nothing about the Project moves)
PUT /v1/projects/{projectId}/quotes/{quoteId}projects.writeReplace a quote's typed fields (a confirmed quote's total and recurring cost are fixed)
POST /v1/projects/{projectId}/quotes/{quoteId}/confirm-financialsprojects.writeConfirm the preferred quote into a new financial version (investment lines, recurring cost, ROI)
PUT /v1/projects/{projectId}/quotes/{quoteId}/investment-linesprojects.writeSet the investment lines a quote supports (replaces the set)
POST /v1/projects/{projectId}/quotes/{quoteId}/preferprojects.writePrefer a quote, with a reason — answers the proposed financial changes and writes none of them
POST /v1/projects/{projectId}/quotes/{quoteId}/withdrawprojects.writeWithdraw a quote from the running; its figures and file stay
GET /v1/projects/{projectId}/quotes/comparisonprojects.readThe live quotes side by side, with missing-document, expired and scope-mismatch warnings
POST /v1/projects/{projectId}/quotes/proposals/{proposalId}/confirmprojects.writeConfirm a supplier's quote the bill inbox proposed — recorded as a received quote, as the person confirming; nothing is preferred or confirmed into the figures
POST /v1/projects/{projectId}/quotes/proposals/{proposalId}/dismissprojects.writeDismiss a supplier's quote the bill inbox proposed, with the reason — no quote is recorded
GET /v1/projects/{projectId}/relationshipsprojects.readProjects this one depends on, overlaps or is an alternative to
PUT /v1/projects/{projectId}/relationshipsprojects.writeState how this Project relates to another
DELETE /v1/projects/{projectId}/relationshipsprojects.writeMake two Projects independent again
PUT /v1/projects/{projectId}/relationships/adjusted-pipelineprojects.writeChoose which Projects of an overlap group count in the adjusted pipeline
GET /v1/projects/{projectId}/relationships/overlap-groupsprojects.readThe overlap groups this Project sits in, and which options count in the adjusted pipeline
GET /v1/projects/{projectId}/saving-linesprojects.readA Project's saving lines
PUT /v1/projects/{projectId}/saving-lines/{lineId}projects.writeCreate or replace one saving line
DELETE /v1/projects/{projectId}/saving-lines/{lineId}projects.writeRemove one saving line from the live set
POST /v1/projects/{projectId}/saving-lines/previewprojects.readPrice one saving line against this Project's assumptions, without saving it
GET /v1/projects/{projectId}/task-proposalstasks.readWhat completed tasks propose to change on a Project — current beside proposed, pending until confirmed
GET /v1/projects/{projectId}/taskstasks.readA Project's Savings Tasks — fields, answers, readiness to complete and what each waits on
POST /v1/projects/{projectId}/taskstasks.writeAdd a Savings Task to a Project, with its owner, contributors and completion fields
POST /v1/projects/{projectId}/transitionsprojects.writeTake a lifecycle action on a Project
GET /v1/projects/{projectId}/utility-assumptionsprojects.readThe prices this Project is costed at, per resource and budget year, with their basis
PUT /v1/projects/{projectId}/utility-overridesprojects.writeSet a Project-only unit price for one resource and year
DELETE /v1/projects/{projectId}/utility-overridesprojects.writeDrop a Project price override, so the hotel's forecast answers again
GET /v1/projects/{projectId}/verificationprojects.readA Project's savings verification, its variance against the estimate, and what a reopen kept
PUT /v1/projects/{projectId}/verificationprojects.writeRecord the verified annual saving per resource, with its method, period and evidence
POST /v1/projects/{projectId}/verification/acceptprojects.writeAccept the verification: the verified saving becomes the realised saving, derived once
POST /v1/projects/{projectId}/verification/unableprojects.writeRecord that the saving could not be verified, with the reason — it contributes no verified saving
GET /v1/projects/{projectId}/versionsprojects.readA Project's scope and narrative snapshots, newest first
GET /v1/risk-findingsrisks.readRisk findings I can see, filtered
POST /v1/risk-findingsrisks.writeOpen a risk finding
GET /v1/risk-findings/{id}risks.readOne risk finding
PATCH /v1/risk-findings/{id}risks.writeEdit a risk finding
POST /v1/risk-findings/{id}/phi-eventrisks.writePut a risk finding on the PHI timeline
POST /v1/risk-findings/{id}/transitionrisks.writeMove a risk finding to another status
POST /v1/risk-findings/from-gaprisks.writePromote a data gap into a risk finding
POST /v1/task-proposals/{proposedUpdateId}/acceptprojects.writeConfirm a task's proposal — the target's own command applies it (a quote is created, a milestone completed, an asset answer saved, a document filed)
POST /v1/task-proposals/{proposedUpdateId}/rejectprojects.writeReject a task's proposal — kept as history; nothing about the Project changes
GET /v1/taskstasks.readSavings Tasks across the Portfolio's hotels where Savings Tasks is on (an Owner's view)
GET /v1/tasks/{taskId}tasks.readOne Savings Task, with its fields, answers and readiness to complete
PUT /v1/tasks/{taskId}tasks.writeReplace an open task's details (a changed dependency drops an earlier override)
POST /v1/tasks/{taskId}/blocktasks.writeBlock a task — the reason, what is needed, and who is responsible where known
POST /v1/tasks/{taskId}/canceltasks.writeCancel a task with a reason (a required task is a documented exception only with an exception note)
POST /v1/tasks/{taskId}/completetasks.writeComplete a task — refused until every required answer and document is there and its dependency is complete or overridden; what it proposes waits for confirmation
POST /v1/tasks/{taskId}/dependency-overridetasks.writeLet a task complete past an open dependency — an Owner's or an Administrator's, with a reason kept in history
PUT /v1/tasks/{taskId}/fieldstasks.writeReplace a task's completion fields (eight types, no conditions; an answered field keeps its type)
PUT /v1/tasks/{taskId}/ownertasks.writeAssign or clear a task's owner and, when given, replace its contributors (active people with access to the hotel)
PUT /v1/tasks/{taskId}/responsestasks.writeAnswer one completion field of an open task — a document for a photograph or a file; a blank answer clears it
POST /v1/tasks/{taskId}/starttasks.writeStart a task (Not started → In progress)
POST /v1/tasks/{taskId}/unblocktasks.writeUnblock a task — it returns to the status it had
GET /v1/viewerviewer.readCurrent user profile

Rate limits

600 requests/minute per bearer+IP on /v1, 120/minute on /mcp.