Component Edit API — Programmatic Property Updates
This guide explains how to read and modify component properties via the HiStruct REST API, simulating the same operations the Aurelia frontend performs.
Overview
There are two approaches to modifying component state:
- Direct PVC manipulation — set the raw JSON parameter values (quick, but bypasses triggers and validation)
- Property transaction — load the property ViewModel, modify it, and POST it back with a trigger (proper, runs the full constraint pipeline)
The property transaction approach is the correct way to simulate user interaction.
API Endpoints
All endpoints are relative to the HiStruct instance (e.g., https://deve.histruct.com).
Component discovery
GET /api/spaces/{spaceKey}/components/{componentId}?privateKey={pk}
Returns a JSON object with URLs to all component resources:
| Field | Description |
|---|---|
component_pvc_json_url |
Current PVC as JSON |
component_edit_url |
Edit page (HTML) |
component_details_url |
Component metadata |
component_pvc_hash_url |
Content-addressed PVC hash |
Read PVC (direct)
GET /api/spaces/{spaceKey}/components/{componentId}/pvc-json?privateKey={pk}
Returns the current PVC as a JSON object. Example:
{
"inMapImageUrl": "https://example.com/image.png",
"reconResponse": {"SOK": true, "timestamp": "2026..."}
}
Evaluate expressions
POST /api/spaces/{spaceKey}/components/{componentId}/expression?privateKey={pk}
Content-Type: application/json
{"Expression": "hasMask"}
Returns: {"Result": true}
Useful for checking computed values without loading the full property UI.
Property Transaction Flow
This is the proper way to simulate a user editing a parameter and clicking an action button.
Step 1: Load properties
POST /api/spaces/{spaceKey}/components/{componentId}/load-properties?privateKey={pk}
Content-Type: application/json
{"contextPath": "inMapImageUrl"}
The contextPath is the FCS variable identifier (e.g., "inMapImageUrl"). Returns a ContextParamValueViewModel:
{
"ComponentId": "479418",
"ComponentSubRevision": null,
"ComponentPrivateKey": null,
"ComponentPrototypeName": "https://github.com/HiStructClient*fcs-lab-01*...",
"ContextPath": "inMapImageUrl",
"ContextPathHash": "32186",
"RevisionPublished": false,
"ContextTitle": "Satellite Image URL",
"ParamValueDto": {
"Resources": {"ListOptionsEntries": []},
"Value": {
"TypeName": "ParamValueStringVM",
"Value": "https://example.com/image.png",
"Identifier": "inMapImageUrl",
"HumanName": "Satellite Image URL",
"IsEditable": true,
"FromUser": true
}
},
"StagingEditedPvcB64": null,
"OriginalPvcB64": "fcc698a8...",
"DialogOriginalPvcB64": "fcc698a8..."
}
Step 2: Modify the ViewModel (optional)
To change a parameter value, modify ParamValueDto.Value.Value in the returned VM:
{
"ParamValueDto": {
"Value": {
"Value": "https://new-image-url.com/image.png"
}
}
}
Step 3: POST update-properties (with trigger)
POST /api/spaces/{spaceKey}/components/{componentId}/update-properties?privateKey={pk}
Content-Type: application/json
{
"vm": <the ContextParamValueViewModel from step 1>,
"vms": null,
"validationTrigger": "detectBuildingsTrigger",
"observedContexts": null,
"navigationContexts": null,
"jobResultKey": null
}
The validationTrigger is the name of the FCS trigger variable to execute (same as ValidationTrigger on Fcs.Parameter.ItemAction).
Response format
The response is chunked JSON with EditResult objects:
["chunk:000000000513", {
"validationresult": {
"Exception": null,
"NotesList": ["Running building detection...", "Downloading mask..."],
"UpdatedValuesList": [],
"Ok": false
},
"originalPvcB64": "d8dea119...",
"timeline": {
"CurrentAction": {"CheckoutToken": "..."},
"Undo": {"CheckoutToken": null},
"Redo": {"CheckoutToken": null}
},
"ResultType": "ResultUpdateTransaction"
}]
| Field | Meaning |
|---|---|
Exception |
null on success, error string on failure |
NotesList |
Collected Explanation strings from constraints that fired |
Ok |
Whether the edit was fully committed |
originalPvcB64 |
PVC hash before the transaction |
timeline |
Undo/redo tokens for the edit history |
Direct PVC Manipulation
For quick updates without triggers (e.g., pre-filling values at creation time):
Create component with PVC
POST /{spaceKey}/{language}/inquiry/new-configuration
Content-Type: application/json
{
"FccRef": "SkyNetRecognizer2.fcc",
"PvcJsonString": "{\"inMapImageUrl\": \"https://example.com/image.png\"}"
}
PVC Store (content-addressed)
The PVC store is a content-addressed key-value store. The Aurelia frontend uses it for the admin palette editor:
POST /api/pvc-store/json
Content-Type: application/json
Body: "{\"key\": \"value\"}"
→ Returns: "hash-string"
GET /api/pvc-store/{hash}/json
→ Returns: the PVC object
Note: PVC store endpoints require Admin role.
Edit PVC directly (MVC form POST)
POST /edit/ComponentPvc
Content-Type: application/x-www-form-urlencoded
ComponentRevision=479418&PvcJsonString={"inMapImageUrl":"..."}
This bypasses triggers entirely and writes the PVC directly.
Complete Example: Programmatic Detection Pipeline
# 1. Create component with pre-filled image URL
$pvc = @{ inMapImageUrl = $imageUrl } | ConvertTo-Json -Compress
$body = @{ FccRef = "SkyNetRecognizer2.fcc"; PvcJsonString = $pvc } | ConvertTo-Json
$r = Invoke-WebRequest -Uri "$base/sky/en/inquiry/new-configuration" `
-WebSession $session -Method Post -ContentType "application/json" -Body $body
$result = $r.Content | ConvertFrom-Json
$cid = $result.componentId; $pk = $result.privateKey
# 2. Load properties VM
$loadBody = @{ contextPath = "inMapImageUrl" } | ConvertTo-Json
$r = Invoke-WebRequest -Uri "$base/api/spaces/sky/components/$cid/load-properties?privateKey=$pk" `
-WebSession $session -Method Post -ContentType "application/json" -Body $loadBody
$vm = $r.Content | ConvertFrom-Json
# 3. Trigger detection (runs all constraints in the trigger)
$updateBody = @{
vm = $vm
vms = $null
validationTrigger = "detectBuildingsTrigger"
observedContexts = $null
navigationContexts = $null
jobResultKey = $null
} | ConvertTo-Json -Depth 10
$r = Invoke-WebRequest -Uri "$base/api/spaces/sky/components/$cid/update-properties?privateKey=$pk" `
-WebSession $session -Method Post -ContentType "application/json" -Body $updateBody
# 4. Verify results
$pvcR = Invoke-WebRequest -Uri "$base/api/spaces/sky/components/$cid/pvc-json?privateKey=$pk" `
-WebSession $session
$pvc = $pvcR.Content | ConvertFrom-Json
# $pvc.reconResponse.SOK → true
# $pvc.maskBase64 → base64 PNG string
ContextEditContextRequestDto Reference
The update-properties endpoint accepts this DTO:
public record ContextEditContextRequestDto(
ContextParamValueViewModel vm, // the loaded property VM
ContextParamValueViewModel[] vms, // null for single-property edits
string validationTrigger, // trigger name (e.g., "detectBuildingsTrigger")
string observedContexts, // null for simple cases
string[] navigationContexts, // null for simple cases
string jobResultKey // null unless committing a background job result
);
Source: ContextParamValueViewModel.cs:31-38
Gotchas
-
Variables must be InputItems — A trigger constraint can only write to variables declared in
InputPageGallery_ParameterItemClasses. Hidden variables useVisibilityCondition = "False". -
Absolute vs relative URLs — If the FCS code prepends a base URL to an API response field, make sure the response field contains a relative path (e.g.,
/api/GetMask?ts=...), not an absolute URL. -
ContextPath must be a variable identifier — The
contextPathinload-propertiesis the FCS variable name (e.g.,"inMapImageUrl"), not a UI page name. -
PVC store requires Admin — The
GET/POST /api/pvc-store/...endpoints checkIsUserAdmin(). Theload-properties/update-propertiesendpoints work for any authorized user. -
Chunked response — The
update-propertiesresponse is a JSON array of["chunk:NNNNNN", {...}]pairs. Parse accordingly.
Template Upgrade — Updating a component to a newer commit
When the prototype branch has new commits, you can upgrade a component to use the latest code.
Check upgrade availability
GET /api/spaces/{spaceKey}/components/{componentId}/template-upgrade?privateKey={pk}
Returns:
| Field | Type | Description |
|---|---|---|
upgradeAvailable |
bool | Whether a newer commit exists |
currentlyUsedPrototypeCommit |
object | Current commit reference with .Version (SHA) |
latestCommitForPrototypeUpgrade |
object | Latest commit reference |
componentTemplateUpgradePostUrl |
string | Full URL to POST for upgrade (null if not available) |
Execute the upgrade
POST /api/spaces/{spaceKey}/components/{componentId}/template-upgrade?componentPrototype={protoString}&privateKey={pk}
Body: {}
The componentPrototype format: https://github.com/{org}*{repo}*{fccFolder}*{commitSha}
Example:
https://github.com/HiStructClient*fcs-lab-01*SkyNetRecognizer2.fcc*b790f7f5da06ad41dee8cc5483fcd7e20f2eafbe
Important: Use the full SHA (40 chars). Short SHAs may not be cached in gitlocal yet, causing SnapshotPath errors.
Returns: {"success": true, "newPrototype": "..."}
List prototype commits
GET /api/spaces/{spaceKey}/components/{componentId}/template-commits?take=N
Returns recent commits for the component's prototype, useful for browsing version history.
Cache considerations
- The gitlocal proxy caches prototype data. After pushing new commits, the upgrade may show
upgradeAvailable: falseuntil the cache refreshes. - Cache bust: Call
GET /api/spaces/{spaceKey}/prototype-branch-info/{urlEncodedPrototype}to trigger a fetch from GitHub. - The URL-encoded prototype format for branch info:
https:%2F%2Fgithub.com%2F{org}*{repo}*{fccFolder}*{branchName}
Source: ComponentTemplateController.cs:84-145 (GET/POST upgrade), ComponentTemplateController.cs:151 (commits)