Projekt-Id in zwei Formen
Data Management braucht die Id mit b.-Präfix, alle Modul-APIs ohne.
Besprechungen bestehen auf einer reinen UUID. container() und
with_prefix() entscheiden das an einer Stelle.
Ein MCP-Server, der Autodesk Forma über natürliche Sprache bedienbar macht. Aufgaben anlegen, Bautagebücher rückdatieren, Nachträge ändern, Objekte pflegen, Nutzer einladen. Alles im Chat, ohne Klickweg durch die Oberfläche.
An MCP server that makes Autodesk Forma operable through natural language. Create issues, backdate daily logs, change change orders, maintain assets, invite users. All from a chat, without clicking through the interface.
Eine Common Data Environment beantwortet normalerweise nur, was man anklickt. Forma-MCP macht sie ansprechbar: Wer im Chat schreibt „leg einen Mangel Brandschottung im 2. Obergeschoss an und weise ihn dem Polier zu“, bekommt keinen Vorschlag, wie er das in der Oberfläche macht. Der Mangel ist danach in Forma.
MCP steht für Model Context Protocol. Es ist die vereinbarte Sprache, in der ein Chat-Modell erfährt, welche Werkzeuge es hat und wie es sie aufruft. Ein MCP-Server meldet beim Start eine Liste von Tools an, jedes mit Namen, Parametern und einer Beschreibung in Prosa. Das Modell liest diese Liste, entscheidet selbst, welches Tool zur Anfrage passt, füllt die Parameter und ruft auf. Der Server macht die eigentliche Arbeit gegen die API und gibt Text zurück.
Der praktische Unterschied zu einem Skript: Ein Skript muss man kennen, finden und mit den richtigen Argumenten starten. Ein Tool beschreibt sich selbst, und das Modell wählt es aus. Genau daran hängt die Qualität der Tool-Beschreibungen. Sie sind kein Kommentar für Entwickler, sie sind die Bedienungsanleitung für das Modell.
Zwei Zwecke, beide aus der Pre-Sales-Arbeit heraus. Erstens: eine Demo-Umgebung aufbauen und lebendig halten. Ein leeres Forma-Projekt überzeugt niemanden, ein Projekt mit Firmen, Nutzern, 150 Objekten, 21 rückdatierten Bautagebüchern, Verträgen und Nachträgen schon. Zweitens: einem Kunden im Gespräch zeigen, was die API hergibt, ohne Folien. Die Frage „geht das auch automatisiert?“ lässt sich mit einem Satz im Chat beantworten statt mit einer Roadmap.
Dasselbe Produkt, umbenannt. Die Endpunkte liegen technisch weiter unter
construction/ und bim360/, weil Autodesk die
API-Pfade nicht mit umbenannt hat. In Texten steht Forma, im Code stehen die
alten Pfade. Das ist kein Fehler.
A common data environment usually only answers what you click on. Forma-MCP makes it conversational: type “create a defect for incomplete fire stopping on level 2 and assign it to the foreman” into the chat and you do not get a suggestion for how to do it in the interface. The defect is in Forma afterwards.
MCP stands for Model Context Protocol. It is the agreed language in which a chat model learns which tools it has and how to call them. An MCP server announces a list of tools at startup, each with a name, parameters and a description in prose. The model reads that list, decides for itself which tool fits the request, fills in the parameters and calls it. The server does the actual work against the API and returns text.
The practical difference from a script: a script has to be known, found and started with the right arguments. A tool describes itself, and the model picks it. That is exactly what the quality of the tool descriptions hangs on. They are not comments for developers, they are the manual for the model.
Two purposes, both grounded in pre-sales work. First, building a demo environment and keeping it alive. An empty Forma project convinces nobody; a project with companies, users, 150 assets, 21 backdated daily logs, contracts and change orders does. Second, showing a customer in conversation what the API is capable of, without slides. The question “can that be automated too?” can be answered with one sentence in a chat rather than with a roadmap.
The same product, renamed. Technically the endpoints still live under
construction/ and bim360/, because Autodesk did not
rename the API paths along with the product. Prose says Forma, the code carries
the old paths. That is not a mistake.
Der Server läuft als lokaler Prozess auf demselben Rechner wie der Chat-Client. Die Verbindung ist STDIO: Anfragen und Antworten laufen als JSON-RPC über die Standardein- und -ausgabe. Nichts davon geht über das Netz, außer den API-Aufrufen selbst.
The server runs as a local process on the same machine as the chat client. The connection is STDIO: requests and answers travel as JSON-RPC over standard input and output. None of that goes over the network, except the API calls themselves.
core.py den Token der gewünschten
Identität und ruft den passenden APS-Endpunkt. Zurück geht immer Text, nie ein
Objekt. Deshalb liest sich jede Antwort auch ohne Nachbearbeitung.
core.py and calls the matching APS endpoint. What comes back is
always text, never an object. That is why every answer reads well without
post-processing.
core.py abnimmtVier Dinge, die vorher in jedem einzelnen Tool standen und dort jedes Mal neu falsch werden konnten.
Data Management braucht die Id mit b.-Präfix, alle Modul-APIs ohne.
Besprechungen bestehen auf einer reinen UUID. container() und
with_prefix() entscheiden das an einer Stelle.
APS legt den Grund je nach Modul unter detail, message,
errorCode oder in einer errors-Liste ab.
_error_text() sammelt alle vier Stellen ein, statt nur den
Statuscode zu zeigen.
Objekte per Cursor, Data Management über links.next, Kosten und
Aufgaben über offset. api_all() deckt alle drei ab
und bricht ab, sobald eine Seite nichts Neues bringt.
Jeder Aufruf nimmt einen persona-Parameter entgegen und holt
darüber den passenden Token. Ohne das trügen alle Einträge denselben Namen.
core.py takes off your handsFour things that used to sit in every single tool and could go wrong afresh in each one.
Data Management needs the id with the b. prefix, every module API
without it. Meetings insist on a bare UUID. container() and
with_prefix() decide that in one place.
Depending on the module, APS puts the reason under detail,
message, errorCode or in an errors list.
_error_text() collects all four instead of showing the status code
alone.
Assets by cursor, Data Management via links.next, cost and issues
via offset. api_all() covers all three and stops as
soon as a page brings nothing new.
Every call accepts a persona parameter and fetches the matching
token through it. Without that every entry would carry the same name.
54 Tools, davon 26 lesend und 28 schreibend. Vollständige Parameterlisten stehen in der Tool-Referenz, hier steht, wofür die Bereiche gut sind.
Hubs und Projekte auflisten, den Ordnerbaum eines Projekts durchlaufen,
Ordnerberechtigungen lesen und setzen. Die Berechtigungen werden dabei in die sechs
Stufen der deutschen Oberfläche übersetzt, von „Anzeigen“ bis „Verwalten“, statt
roher Aktionslisten wie VIEW, DOWNLOAD, COLLABORATE. Wer eine Rolle
auf Stufe 4 setzt, muss nicht wissen, dass dahinter fünf Einzelaktionen stehen.
Anlegen, ändern, löschen, filtern, dazu die Typen und Untertypen des Projekts
auflisten. Ein Untertyp ist beim Anlegen Pflicht, und im Demoprojekt sind die
meisten Typen inaktiv, weshalb create_issue inaktive automatisch
überspringt und einen Namen wie „Brandschutz“ oder „Mangel“ selbst auflöst.
Zuweisen geht an Personen über Namen oder Mailadresse.
Eine per API angelegte Aufgabe wäre ohne Zutun ein Entwurf, und Entwürfe sieht
außer dem Ersteller niemand, auch kein Projektadministrator.
create_issue setzt published deshalb standardmäßig.
Ein unsichtbarer Mangel nützt in einer Vorführung nichts.
Vorlagen listen, Formulare anlegen, Kopf- und Inhaltsfelder füllen. Der wichtigste
Punkt steckt in create_form: Über das Feld userCreatedAt
lässt sich das Anlegedatum in die Vergangenheit setzen. Das ist der einzige Weg zu
glaubwürdiger Historie in Forma. Bei Aufgaben ist Rückdatierung gesperrt, bei
Formularen nicht. Zwanzig Bautagebücher, die über sechs Wochen verteilt entstanden
zu sein scheinen, machen ein Demoprojekt erst glaubhaft.
Der einzige Bereich, in dem sich auch die Konfiguration anfassen lässt: Kategorien,
Statusgruppen und benutzerdefinierte Felder lassen sich über
list_asset_config lesen und über eigene Tools auch anlegen, samt
Auswahloptionen und automatischer Farbverteilung bei Statusgruppen. Beim Anlegen
eines Objekts genügen Kennung und Kategorie, den Pflicht-Status leitet
create_asset selbst ab. Felder lassen sich über ihren Anzeigenamen
setzen, also Hersteller:Hilti statt ca3:Hilti.
Der Block, der ein leeres Projekt überhaupt erst bevölkert. Nutzer listen und
einladen, Produktzugriffe ändern, Firmen anlegen und ins Projekt holen. Die
unangenehmste Falle steckt eingebaut: Die API ersetzt bei jedem Aufruf die komplette
Produktliste, statt zu ergänzen. update_user liest deshalb den
Ist-Stand, rechnet die Änderung darauf und schickt immer die vollständige Liste.
Der größte Bereich. Hauptvertrag mit Wertgliederung, Nachunternehmerverträge,
Budgetzeilen nach DIN 276, alle fünf Nachtragstypen und Abschlagsrechnungen.
Zwei Tools bündeln jeweils mehrere API-Aufrufe: create_cost_item
sucht die Budgetzeile, verknüpft Budget und Vertrag und legt dann erst die Position
an. create_payment legt Abrechnungszeitraum, Zahlung und Positionen in
einem Rutsch an und trägt den Fortschritt ein.
Planungsanfragen sind der einzige Vorgang mit zwei sichtbar Beteiligten: Gefragt
wird von der einen Seite, geantwortet von der anderen. Antworten darf ausschließlich
die zugewiesene Person, weshalb hier der persona-Parameter wirklich
gebraucht wird und nicht nur die Optik verbessert. Besprechungen kommen mit
Teilnehmern und Tagesordnung, beides trägt create_meeting gleich mit
ein. Ohne Teilnehmer wäre die Besprechung für alle außer dem Ersteller unsichtbar.
Eine API verbindet Objekte über Modulgrenzen hinweg: eine Aufgabe mit einem Foto,
ein Objekt mit einem Dokument, einen Nachtrag mit einer Planungsanfrage. In Forma
erscheinen diese Verknüpfungen als „Referenzen“ am jeweiligen Eintrag. Suchen,
anlegen, löschen, dazu die Matrix der erlaubten Paare und ein Sync-Mechanismus für
externe Ablagen. Adressiert wird mit Kurznamen wie issue oder
photo; die sperrigen Domain-Namen der API bleiben unter der Haube.
Die Standortgliederung als Baum mit Barcodes. Mengenpakete samt Import von DIN 276
und Geschossgliederung. Und forma_request, ein bewusst grobes
Werkzeug: Es fragt jeden beliebigen APS-Endpunkt lesend ab, mit Kürzeln für die
Modulwurzeln und einer Tiefenbegrenzung, damit eine Antwort mit 200 Einträgen den
Kontext nicht flutet. Damit lassen sich neue Endpunkte im Gespräch erkunden, ohne
vorher ein Skript zu schreiben. Dazu list_personas: die
eingerichteten Identitäten samt Standard-Persona.
54 tools, 26 of them reading and 28 writing. Full parameter lists live in the tool reference; this section says what the areas are good for.
List hubs and projects, walk a project’s folder tree, read and set folder
permissions. Permissions are translated into the six levels of the interface, from
“view” to “manage”, instead of raw action lists such as
VIEW, DOWNLOAD, COLLABORATE. Setting a role to level 4 does not
require knowing that five individual actions sit behind it.
Create, update, delete, filter, plus listing the project’s types and subtypes. A
subtype is mandatory when creating, and in the demo project most types are inactive,
which is why create_issue skips inactive ones automatically and
resolves a name such as “Brandschutz” or “Mangel” by itself. Assignment to people
works by name or email address.
An issue created through the API would be a draft by default, and nobody sees a
draft except its creator, not even a project administrator.
create_issue therefore sets published as standard. An
invisible defect is of no use in a demo.
List templates, create forms, fill header and content fields. The crucial point
sits inside create_form: the field userCreatedAt lets you
push the creation date into the past. That is the only route to believable history
in Forma. For issues backdating is blocked, for forms it is not. Twenty daily logs
that appear to have been written across six weeks are what makes a demo project
credible in the first place.
The only area where the configuration can be touched as well: categories, status
sets and custom fields can be read through list_asset_config and
created through tools of their own, pick-list options and automatic colour spread
included. To create an asset, an identifier and a category suffice;
create_asset derives the mandatory status itself. Fields can be set
by display name, so Hersteller:Hilti rather than
ca3:Hilti.
The block that populates an empty project in the first place. List and invite
users, change product access, create companies and add them to the project. The
nastiest pitfall is built in: the API replaces the entire product list on every
call instead of merging. update_user therefore reads the current
state, applies the change to it and always sends the complete list.
The largest area. Main contract with schedule of values, subcontracts, budget lines
by DIN 276, all five change order types and payment applications. Two tools bundle
several API calls each: create_cost_item finds the budget line, links
budget and contract and only then creates the item. create_payment
creates the billing period, the payment and the items in one go and records
progress.
RFIs are the only process with two visibly involved parties: one side asks, the
other answers. Only the assigned person may answer, which is why the
persona parameter is genuinely needed here rather than merely
cosmetic. Meetings come with participants and an agenda, both of which
create_meeting adds straight away. Without participants the meeting
would be invisible to everyone but its creator.
One API connects objects across module boundaries: an issue with a photo, an asset
with a document, a change order with an RFI. In Forma these links appear as
“references” on the entry. Search, create, delete, plus the matrix of allowed
pairs and a sync mechanism for external stores. Addressing works through short
names such as issue or photo; the unwieldy domain names
of the API stay under the hood.
The location breakdown as a tree with barcodes. Takeoff packages including an
import of DIN 276 and a storey breakdown. And forma_request, a
deliberately coarse instrument: it queries any APS endpoint read-only, with
shorthands for the module roots and a depth limit so that an answer holding 200
entries does not flood the context. It makes exploring new endpoints possible mid
conversation, without writing a script first. Plus list_personas: the configured
identities with the default persona.
In einem Demoprojekt steht an jedem Eintrag ein Name. Legt ein einziger Zugang alles an, tragen zwanzig Bautagebücher, alle Mängel und sämtliche Planungsanfragen denselben Namen. Das fällt in einer Vorführung sofort auf und zerstört die Glaubwürdigkeit der Umgebung.
Deshalb gibt es sechs 3-legged-Identitäten, jede mit eigener Token-Datei. Alle
schreibenden Tools nehmen einen persona-Parameter entgegen, Vorgabe ist
default. Wer ein Bautagebuch als Bauleitung anlegen will, übergibt
deren Kurznamen als persona, und in Forma steht danach dieser Name.
| Persona | Token-Datei | Rolle in der Demo-Umgebung |
|---|---|---|
default | refresh_token.txt | Standard-Identität, erweiterte Scopes |
<kurzname> | refresh_token_<kurzname>.txt | je eine Identität pro Rolle, z. B. Architektur, Bauleitung, Polier |
Die Identität steuert nicht nur die Optik. Bei Planungsanfragen darf ausschließlich die zugewiesene Person antworten, sonst kommt HTTP 403, auch als Projektadministrator. Entwürfe von Aufgaben und Planungsanfragen sind ebenfalls nur für ihren Ersteller sichtbar. Wer einen gerade angelegten Entwurf sucht und nicht findet, hat meist nur die falsche Identität benutzt.
In a demo project every entry carries a name. If a single account creates everything, twenty daily logs, all defects and every RFI carry the same name. That is noticed immediately in a demo and destroys the credibility of the environment.
Hence six three-legged identities, each with its own token file. All writing tools
accept a persona parameter, defaulting to default. To
create a daily log as site management you pass that persona’s short name, and
their name is what appears in Forma.
| Persona | Token file | Role in the demo environment |
|---|---|---|
default | refresh_token.txt | Default identity, extended scopes |
<shortname> | refresh_token_<shortname>.txt | one identity per role, e.g. architecture, site management, foreman |
The identity governs more than appearances. On an RFI only the assigned person may answer, otherwise HTTP 403 comes back, even for a project administrator. Drafts of issues and RFIs are likewise visible only to their creator. If you look for a draft you just created and cannot find it, you usually just used the wrong identity.
Aus 89 dokumentierten Punkten die, die beim Benutzen des Servers wirklich beißen.
b.-Präfix
Data Management verlangt die Projekt-Id mit Präfix, alle Modul-APIs ohne, und
Besprechungen bestehen auf einer reinen UUID. Der falsche Zuschnitt gibt einen 404
mit dem Text „The requested resource does not exist“, was exakt aussieht wie ein
fehlendes Recht oder eine falsche Id. Der Server nimmt das ab, aber wer
forma_request mit freiem Pfad benutzt, muss es wissen.
Manche APS-Wurzeln enden vor /projects, andere schließen es ein.
Historisch gewachsen und die teuerste Falle beim Verschieben von Code, weil ein
doppeltes /projects/projects/ denselben nichtssagenden 404 gibt. Die
Gruppen stehen in forma/core.py kommentiert.
Aufgaben und Planungsanfragen entstehen ohne Zutun als Entwurf, und ein Entwurf
taucht bei jedem anderen weder in der Liste auf noch beim Einzelabruf. Der
Einzelabruf gibt HTTP 403. Bei Aufgaben umgeht create_issue das durch
sofortiges Veröffentlichen, bei Planungsanfragen ist es nicht umgehbar, siehe
Abschnitt 9.
Ein rückdatiertes Formular trägt das gewünschte Datum in userCreatedAt.
Das technische createdAt bleibt der echte Zeitstempel und ist nicht
rücksetzbar. Wer nach dem Anlegen createdAt prüft, hält die
Rückdatierung fälschlicherweise für gescheitert.
Jede Identität sieht unterschiedlich viele Formularvorlagen, und eine Vorlage in der Liste zu sehen bedeutet nicht, darin anlegen zu dürfen. Vor dem Anlegen also nachsehen, wer die bestehenden Einträge derselben Vorlage geschrieben hat, und dieselbe Identität nehmen.
| Objekt | Verhalten |
|---|---|
| Aufgabe | Soft-Delete. Verschwindet aus Liste und Oberfläche, bleibt über die Id mit deleted: true abrufbar. Zweites Löschen gibt 404 |
| Objekt | Hard-Delete, danach 404. Braucht Administratorrechte, der Ersteller allein darf nicht |
| Planungsanfrage | Nicht löschbar, DELETE gibt 401. Bereinigen über Status void |
| Formular | Nicht löschbar. Skripte deshalb idempotent bauen, also vorhandenes Datum vorher abfragen |
| Mengenpaket | Nicht löschbar, DELETE gibt 404 |
| Firma | Löschbar auf beiden Ebenen. Achtung: Firmen entstehen im gesamten Konto, nicht im Projekt |
invite_user löst eine Einladungsmail aus, die sich nicht zurückholen
lässt. Der Nutzer lässt sich danach zwar wieder aus dem Projekt entfernen, die Mail
ist trotzdem draußen. Vor dem Einsatz in einer Live-Umgebung die Adresse zweimal
lesen.
Out of 89 documented points, the ones that actually bite while using the server.
b. prefix
Data Management requires the project id with the prefix, every module API without
it, and meetings insist on a bare UUID. The wrong shape returns a 404 reading “The
requested resource does not exist”, which looks exactly like a missing permission or
a wrong id. The server handles this, but anyone using forma_request
with a free-form path needs to know.
Some APS roots end before /projects, others include it. Historically
grown, and the most expensive trap when moving code, because a doubled
/projects/projects/ yields that same uninformative 404. The groups are
commented in forma/core.py.
Issues and RFIs are created as drafts by default, and for everyone else a draft
appears neither in the list nor on a direct fetch. The direct fetch returns HTTP 403.
For issues create_issue works around this by publishing immediately;
for RFIs there is no way around it, see section 9.
A backdated form carries the intended date in userCreatedAt. The
technical createdAt remains the real timestamp and cannot be reset.
Checking createdAt after creating makes the backdate look like it
failed.
Each identity sees a different number of form templates, and seeing a template in the list does not mean being allowed to create in it. So before creating, check who wrote the existing entries of that template and use the same identity.
| Object | Behaviour |
|---|---|
| Issue | Soft delete. Disappears from list and interface, stays retrievable by id with deleted: true. A second delete returns 404 |
| Asset | Hard delete, 404 afterwards. Needs administrator rights; the creator alone is not allowed |
| RFI | Cannot be deleted, DELETE returns 401. Clean up via status void |
| Form | Cannot be deleted. Build scripts idempotently, that is, query the existing date first |
| Takeoff package | Cannot be deleted, DELETE returns 404 |
| Company | Deletable at both levels. Careful: companies are created account-wide, not in the project |
invite_user triggers an invitation email that cannot be recalled. The
user can be removed from the project afterwards, but the email is out regardless.
Before using this against a live environment, read the address twice.
Eine Anfrage entsteht immer als Entwurf. Der Wechsel auf open gibt
HTTP 403 mit INVALID_TRANSITION. Pflichtattribute mitzuschicken hilft
nicht, das gibt HTTP 400 „redundant parameters“. Vermutlich darf nur der
zugewiesene Manager den Übergang auslösen, und wie der gesetzt wird, ist offen.
Anfragen lassen sich also anlegen und beantworten, aber nicht regulär stellen.
Die Suche nach Verknüpfungen antwortet mit HTTP 200 und null Treffern,
vermutlich fehlen undokumentierte Pflichtparameter. Dateiversionen ließen sich
mangels Dateien in den oberen Ordnerebenen nicht gegen echte Daten prüfen. Bewusst
kein Tool gebaut. Zum Erkunden forma_request nutzen.
createdAt, openedAt und closedAt sind
gesperrte Migrationsfelder, jeder Versuch gibt 403. Zeitlichkeit nur über
startDate und dueDate. Bei Formularen geht
Rückdatierung, bei Aufgaben nicht.
Die Photos-API ist endgültig als lesend bestätigt. Am Issue steht in den
erlaubten Aktionen ein add_attachment, der Endpunkt dahinter ist
unbekannt. Das bleibt der aussichtsreichste Weg zu Mängeln mit Bild.
Arbeitszeit, Material und Gerät im Bautagebuch lassen sich lesen, aber nicht schreiben. Lese- und Schreibschema unterscheiden sich, jedes naheliegende Feld gibt „Unknown field“. Nach mehreren Versuchen aufgegeben. Eigene benutzerdefinierte Felder funktionieren dagegen zuverlässig.
Der Wechsel von Entwurf über eingereicht zu genehmigt ist nicht per API setzbar, auch nicht mit Administratorrechten. Die Zeitstempel lassen sich setzen, ändern aber den Status nicht. Muss in der Oberfläche passieren.
Kommt aus einem Wetterdienst und ist nicht überschreibbar. Es wird zudem für den echten Anlegezeitpunkt gefüllt, nicht für das rückdatierte Datum. Ein rückdatiertes Bautagebuch zeigt also das Wetter von heute. Wetterangaben gehören deshalb in den Notiztext.
Der Endpunkt existiert, jeder Schreibversuch scheitert mit demselben Fehler, auch mit gültigen Ids. Vermutlich braucht das Feature eine Konfiguration in der Oberfläche, die per API nicht setzbar ist. Behelf: als Nachtrag mit reinem Budget-Bezug abbilden.
Eine Linie, die sich quer durch alle Module zieht: Daten sind schreibbar, Konfiguration meist nicht. Budgets, Verträge, Positionen, Nachträge und Ausgaben lassen sich per API anlegen. Der Budget-Code-Aufbau, Begriffe, Steuer, Währung, Einbehalt, Vertragstypen und die Firmeneinrichtung dagegen nicht. Die einzige Ausnahme sind Objekte: Kategorien, Status, Statusgruppen und benutzerdefinierte Felder lassen sich dort tatsächlich per API bauen. Für das Aufsetzen einer Demo-Umgebung aus dem Nichts ist das der wertvollste Block überhaupt.
Vier Module sind laut Dokumentation machbar und trotzdem nicht gebaut, weil keines davon heute einen Anlass in einer Demo hat. Geholt wird erst, wenn ein Kundengespräch danach fragt.
| Modul | Warum draußen |
|---|---|
| Submittals | Elf Endpunkte, für Generalunternehmer ein starkes Thema. Bisher blinder Fleck, der erste Kandidat für einen Ausbau |
| Data Connector | Massenexport von Projektdaten. Interessant für Auswertungen, nicht für eine Vorführung |
| Webhooks | Ereignisse statt Abfragen. Erst relevant bei einer echten Integration, nicht bei einem Demo-Werkzeug |
| Model Coordination | Ohne Bezug zu den aktuellen Demo-Themen |
An RFI is always created as a draft. Moving it to open returns
HTTP 403 with INVALID_TRANSITION. Sending the mandatory attributes
along does not help, that returns HTTP 400 “redundant parameters”. Presumably only
the assigned manager may trigger the transition, and how that manager is set is
unresolved. RFIs can therefore be created and answered, but not formally raised.
The relationship search answers with HTTP 200 and zero hits, presumably missing
undocumented mandatory parameters. File versions could not be tested against real
data because the upper folder levels hold no files. Deliberately no tool built. Use
forma_request to explore.
createdAt, openedAt and closedAt are
locked migration fields; every attempt returns 403. Timing only through
startDate and dueDate. Forms allow backdating, issues do
not.
The photos API is confirmed read-only for good. The issue’s permitted actions
list an add_attachment, but the endpoint behind it is unknown. That
remains the most promising route to defects with images.
Labour, materials and equipment in the daily log can be read but not written. Read and write schemas differ, and every obvious field returns “Unknown field”. Abandoned after several attempts. Custom fields of your own, by contrast, work reliably.
The move from draft through submitted to approved cannot be set through the API, not even with administrator rights. The timestamps can be set but do not change the status. It has to happen in the interface.
Comes from a weather service and cannot be overwritten. It is also filled for the real creation time, not for the backdated date. A backdated daily log therefore shows today’s weather. Weather information belongs in the notes text.
The endpoint exists, every write attempt fails with the same error, even with valid ids. Presumably the feature needs a setting in the interface that cannot be set through the API. Workaround: model it as a change order with budget-only scope.
One line runs through every module: data is writable, configuration mostly is not. Budgets, contracts, items, change orders and expenses can be created through the API. The budget code scheme, terminology, tax, currency, retention, contract types and company setup cannot. The single exception is assets: categories, statuses, status sets and custom fields really can be built through the API there. For setting up a demo environment from nothing, that is the most valuable block of all.
Four modules are feasible according to the documentation and still not built, because none of them has an occasion in a demo today. They get picked up when a customer conversation asks for them.
| Module | Why it is out |
|---|---|
| Submittals | Eleven endpoints, a strong topic for main contractors. A blind spot so far, and the first candidate for an expansion |
| Data Connector | Bulk export of project data. Interesting for analysis, not for a demo |
| Webhooks | Events instead of polling. Only relevant for a real integration, not for a demo instrument |
| Model Coordination | No bearing on the current demo topics |
Alle 54 Tools mit Parametern, Fallen und einem Beispielsatz, der sie auslöst.
project_id nimmt jedes Tool mit oder ohne b.-Präfix
entgegen, der Server setzt die richtige Form selbst. Alle schreibenden Tools
nehmen zusätzlich persona, Vorgabe default; die
übrigen Kurznamen zeigt list_personas. Einige lesende Tools haben ihn ebenfalls, etwa weil Entwürfe nur ihr
Ersteller sieht.
All 54 tools, with parameters, pitfalls and a sample sentence that triggers each
one. Every tool accepts project_id with or without the
b. prefix; the server normalises it. All writing tools also take
persona, defaulting to default; the
remaining short names come from list_personas. A few reading tools have it as well, for example because drafts are visible
only to their creator.