Resource Registry — API Management (Instances & Admin)

Instance Management — base path /instances

💡 Architectural Note: Nested JSON vs Flat URIs
Throughout this chapter, you will see deep conceptual structures (like Facet instances or ConsistsOf instances attached to a Resource instance) represented as heavily nested JSON objects. This nesting is used for readability, payload efficiency, and representing the structural graph topology in a single response.
However, the REST URIs remain strictly flat. You do not update a Facet instance by constructing a nested path like /instances/{resource-type}/{resource-uuid}/{consists-of-type}/{consists-of-uuid}/{facet-type}/{facet-uuid}. Because every instance (Resource instance, Facet instance, ConsistsOf instance, or IsRelatedTo instance) is a topologically independent graph instance with a globally unique UUID, the API addresses every single instance individually via /instances/{type}/{instance-uuid}. For the design rationale behind this separation, see Flat Addressability vs Nested ROA Paths.

Authorization & Token Selection

| Action | HTTP | Path | Query Parameters | IS-M / Infra-M | IS-Admin / Ctx-M | IS-Editor | IS-Contrib | IS-Member | |——–|——|——|——————|:————–:|:—————-:|:———:|:———-:|:———:| | List | GET | /instances/{type} | limit, offset, polymorphic, hierarchical, metadataPolicy, includeContexts | ✅ | ✅ | ✅ | ✅ | ✅ | | Execute JSON Query | QUERY | /instances (POST /instances/query fallback) | limit, offset, polymorphic, hierarchical, metadataPolicy, includeContexts | ✅ | ✅ | ✅ | ✅ | ✅ | | Exists | HEAD | /instances/{type}/{instance-uuid} | hierarchical, metadataPolicy, includeContexts | ✅ | ✅ | ✅ | ✅ | ✅ | | Read | GET | /instances/{type}/{instance-uuid} | hierarchical, metadataPolicy, includeContexts | ✅ | ✅ | ✅ | ✅ | ✅ | | Create | POST | /instances/{type} | hierarchical, metadataPolicy, includeContexts | ✅ | ✅ | ⚠️ | ⚠️ | ❌ | | Create / Update | PUT | /instances/{type}/{instance-uuid} | hierarchical, syncExistingHierarchy, metadataPolicy, includeContexts | ✅ | ✅ | ⚠️ | ⚠️ | ❌ | | Merge Update | PATCH | /instances/{type}/{instance-uuid} | metadataPolicy, includeContexts | ✅ | ✅ | ⚠️ | ⚠️ | ❌ | | Remove from Current Context | DELETE | /instances/{type}/{instance-uuid} | propagationMode, dryRun, metadataPolicy, includeContexts | ✅ | ✅ | ⚠️ | ⚠️ | ❌ | | Add to Context | PUT | /instances/{type}/{instance-uuid}/contexts/{new-context-uuid} | propagationMode, dryRun, metadataPolicy, includeContexts | ✅ | ⚠️ | ⚠️ | ❌ | ❌ | | List Instance Contexts | GET | /instances/{type}/{instance-uuid}/contexts | None | ✅ | ✅ | ✅ | ✅ | ✅ |

Token Scope Rule:

| Operation Group | Token must be issued for | |—————-|—————————| | List, Execute JSON Query, Exists, Read | The operational Context from which visibility is evaluated | | Create, Create / Update, Merge Update, Remove from Current Context | The operational Context where the instance is managed | | Add to Context | The operational Context from which the membership operations are orchestrated; for IS-Admin / Ctx-M / IS-Editor, the newly specified Contexts must stay inside the managed subtree | | List Instance Contexts | The operational Context from which membership visibility is evaluated |

HTTP Contract

| Action | Additional Request Headers | Response Headers | Success HTTP Code | Error HTTP Code | |——–|—————————-|——————|——————-|—————–| | List | Accept | Content-Type, Link, X-Warning, X-Result-Scope | 200 OK | 400 Bad Request, 403 Forbidden, 404 Not Found | | Execute JSON Query | Content-Type, Accept | Content-Type, Link, X-Warning, X-Result-Scope | 200 OK | 400 Bad Request, 403 Forbidden | | Exists | Accept | Content-Length, Content-Type, Link, X-Warning, X-Result-Scope | 200 OK | 400 Bad Request, 403 Forbidden, 404 Not Found | | Read | Accept | Content-Type, Link, X-Warning, X-Result-Scope | 200 OK | 400 Bad Request, 403 Forbidden, 404 Not Found | | Create | Content-Type, Accept | Content-Type, X-Warning | 201 Created | 400 Bad Request, 403 Forbidden, 404 Not Found, 409 Conflict | | Create / Update | Content-Type, Accept | Content-Type, X-Warning | 201 Created / 200 OK | 400 Bad Request, 403 Forbidden, 404 Not Found, 409 Conflict | | Merge Update | Content-Type: application/merge-patch+json, Accept | Content-Type, X-Warning | 200 OK | 400 Bad Request, 403 Forbidden, 404 Not Found, 409 Conflict | | Remove from Current Context | Accept, Prefer (return) | Content-Type, X-Warning, Preference-Applied | 200 OK | 400 Bad Request, 403 Forbidden, 404 Not Found, 409 Conflict | | Add to Context | Accept, Prefer (return) | Content-Type, X-Warning, Preference-Applied | 200 OK | 400 Bad Request, 403 Forbidden, 404 Not Found, 409 Conflict | | List Instance Contexts | Accept | Content-Type, Link, X-Warning, X-Result-Scope | 200 OK | 403 Forbidden, 404 Not Found |

Operational Notes

  • HEAD Is the Bodyless Read: HEAD /instances/{type}/{instance-uuid} is the automatic bodyless view of the corresponding GET, not an independent operation with reduced semantics. It accepts the same hierarchical, metadataPolicy, and includeContexts parameters and returns the same status and representation headers (plus the computed Content-Length), while omitting only the response body.

  • List Endpoint 403 Absence: The List endpoint never returns 403 Forbidden for data visibility boundaries. Results are strictly filtered according to the token’s operational Context. If no instances exist within the token’s scope, it simply returns an empty list [], even if those instances exist in other Contexts. (Note: The only scenario where a List operation returns a 403 Forbidden is if the token Context itself is in a non-ACTIVE state, which acts as a global administrative block for standard roles, as detailed in the Context Management chapter).

  • Path vs Body Consistency (Double-Check): When creating or updating an instance via PUT or PATCH on /instances/{type}/{instance-uuid}, the type and id parameters in the URL path must exactly match the type and id fields provided inside the JSON payload. Even though PATCH acts as a partial merge, the type and id fields are strictly mandatory in the JSON body. If they are missing or do not match, the server strictly rejects the request with a 400 Bad Request to prevent accidental data corruption or schema-mismatch errors.

  • Type-in-Path Semantics (Exact Type Enforcement): For all endpoints targeting a specific instance using the path variable {type} (e.g., /{type}/{instance-uuid}), the client MUST specify the exact concrete Type of the instance. Specifying an abstract supertype (e.g., calling /instances/Resource/{uuid} when the instance is actually an EService) is strictly invalid for any operation (GET, PUT, PATCH, DELETE, HEAD) and will be rejected with a 404 Not Found (as the requested composite key (type, instance-uuid) effectively does not exist, which safely prevents any existence leakage of the UUID). The system enforces strict 1:1 parity between the concrete instance schema and the {type} path parameter. (Note: This exact-match restriction applies strictly to single-instance targeting endpoints. The collection endpoint GET /instances/{type} fully supports querying by abstract supertypes when combined with the polymorphic=true parameter).

  • Instance Creation Scope: While flat URIs address every graph instance individually for reads and updates, standalone creation via POST /instances/{type} or PUT /instances/{type}/{instance-uuid} is structurally valid only for Resource, IsRelatedTo, and ConsistsOf instances. As dictated by the core IS-Model topology, a Facet instance cannot exist independently and must be created exclusively as a nested element (either within a parent Resource mutation payload, or within a standalone ConsistsOf mutation payload acting as its target).

  • Create (POST) — Optional Client-Supplied UUIDs: Unlike PUT, POST /instances/{type} does not require an id on the root instance or on any nested Facet/ConsistsOf/IsRelatedTo. Any id present in the payload — root or nested — is honored as-is and validated against the same uniqueness domain as PUT (see “UUID Reuse Across Types” below): an id already bound to an element of the same type is 409 Conflict; of a different type, 400 Bad Request. Because the whole payload tree is created inside a single database transaction, a conflict anywhere in the tree — root or nested — rolls back the entire request atomically; nothing is partially persisted.

  • Create (POST) Is Intentionally Not Idempotent: Two identical POST requests that omit every id always produce two distinct instances (Resource, Facet, ConsistsOf, or IsRelatedTo alike, depending on what is being created) — this is deliberate POST semantics per RFC 9110 §9.3.3, not a limitation. Clients that need retry-safety for a specific element should supply that element’s own id; see the point above for what happens on a resubmit in that case.

  • Lookup (403 vs 404): For instance lookup endpoints (HEAD/GET on /instances/{type}/{instance-uuid}), the API intentionally distinguishes 404 Not Found (no instance exists for the requested lookup key) from 403 Forbidden (an instance matching the lookup key exists, but is outside the caller’s authorization scope). This distinction is preserved by design for operational diagnosability. Given the D4Science exposure model (write surfaces internal; /access facade internet-facing but read-scoped), this is an explicit and accepted security/operational trade-off. An attacker could theoretically deduce existence by attempting a PUT with a specific UUID and receiving a 409 Conflict, so returning 403 Forbidden on GET does not significantly alter the threat model.

  • Point Read Scope Contract (hierarchical): Point lookups (HEAD / GET /instances/{type}/{instance-uuid}) intentionally support hierarchical for scope alignment with collection discovery. Without hierarchical=true, lookup is restricted to the token Context; with hierarchical=true, lookup is evaluated against the authorized descendant subtree.

  • Discovery -> Fetch Symmetry Rule: If a client discovers an instance through a hierarchical collection operation (GET /instances/{type}?hierarchical=true or QUERY /instances?hierarchical=true), it should keep the same hierarchical=true scope on the subsequent point read. Dropping the flag narrows the scope and can legitimately turn a previous discovery into 403 Forbidden on point fetch.

  • Lookup vs Create Domain: Lookup operations evaluate the composite key (type, instance-uuid) against visibility/existence semantics. Create/Update uniqueness validation (PUT) evaluates the identifier against an implementation-defined uniqueness domain (which may be equal to or broader than (type, instance-uuid)), returning 409 Conflict when identifier occupancy violates backend uniqueness constraints. This contract avoids false assumptions by clients: lookup and creation/update are related but not guaranteed to share identical internal uniqueness scopes.

  • UUID Reuse Across Types: A UUID is a graph-wide identifier, never scoped to a single type. Supplying an id (top-level or nested, e.g. a consistsOf entry) that already identifies an existing element of the same type is a 409 Conflict (ordinary already-exists semantics). Supplying an id that already identifies an existing element of a different type — whether via a direct PUT/PATCH that changes an instance’s declared type, or a nested element reusing another element’s id under a different type — is rejected with 400 Bad Request: a malformed request, not a context-visibility concern.

  • List Instance Contexts returns: Returns a map of Context UUID → Context path. For all roles, the returned Contexts are strictly filtered to the competence subtree defined by the authorization token. The response emits Link: rel="up" pointing back to the owning instance URI (/instances/{type}/{instance-uuid}). (Note: If an IS-M / Infra-M uses a token issued for a specific VO, they will only see Contexts within that VO. To obtain full global visibility, they must explicitly use a token issued for the Root Context /). The response includes X-Result-Scope: role-filtered only when this subtree restriction actually removes a membership; state-filtered is additionally reported when a non-administrative caller actually loses a non-ACTIVE descendant membership.

Contextual Mutations & Update Intent (PUT vs PATCH)

(Note on Response Shape: All PUT and PATCH operations on the base instance path /instances/{type}/{instance-uuid} always return a representation with the same structural shape as a standard Read operation for the targeted instance. Even if query parameters like syncExistingHierarchy=true or hierarchical=true are used to distribute the state across multiple Contexts, the API response remains strictly bounded to the requested target instance. These operations do not trigger broad topological traversal (unlike membership operations) and therefore do not return an Operation Envelope).

Because Resource instances act as structural hubs for their nested Facet instances (via ConsistsOf instances), and because all these graph nodes are shared across Contexts by reference rather than being duplicated, updating a Resource instance’s topology in one Context can have broader repercussions. To effectively manage these shared topologies, the API explicitly distinguishes between PATCH (Merge) and PUT (Full Replace) operations, providing an escalating mechanism of topological impact.

Important (Global Property Mutations): Because property fields are intrinsically bound to the single underlying instance, modifying a property field via PATCH or PUT applies globally across all Contexts where that instance is shared. Therefore, the concept of a hierarchical Context sync applies exclusively to topological structural changes (i.e., modifying the graph structure, such as attaching or detaching Facet instances), never to property field mutations.

PATCH (Merge Semantic)

PATCH applies a Merge semantic (application/merge-patch+json), modifying only the provided fields and leaving the rest of the instance intact. In accordance with RFC 7396, arrays containing standard data fields (e.g., a list of strings) are treated as atomic values; providing such an array in a PATCH payload will completely replace the existing array.

  • Mandatory Identity Fields: Even though a Merge Patch normally allows clients to send only the fields they wish to change, the Resource Registry strictly requires the top-level type and id fields to be present in the JSON body. These fields must exactly match the type and id provided in the URL path. If they are omitted or mismatched, the request is instantly rejected with a 400 Bad Request.

  • Null and Omission Semantics: An omitted property is left unchanged, whereas an explicitly submitted null is an update instruction that removes the property in accordance with RFC 7396. Optional properties may therefore be removed through PATCH; mandatory properties cannot be removed, and attempting to do so results in 409 Conflict during schema validation. The model does not expose notnull as an independent constraint.

  • Pragmatic Deviation on Graph Arrays: The Resource Registry API intentionally diverges from the RFC rule for structural graph arrays like consistsOf when the PATCH is performed on a Resource instance. If a PATCH payload on a Resource instance includes a consistsOf array, the backend performs a surgical merge: it patches only the explicitly referenced ConsistsOf and Facet instances (requiring both the id of the ConsistsOf instance and the id of its target Facet instance to safely match the instances) without dropping the omitted ones. If a client attempts to execute a PATCH omitting these nested IDs (e.g., intending to create a new nested structure on the fly), the request is strictly rejected with a 400 Bad Request. To create new topological structures like adding a new Facet instance, clients must use a PUT operation. PATCH does not support hierarchical parameters.

PUT on Resource Instances (Topological Impact)

When the target of a PUT operation is a Resource instance, the API enforces a Full Replace semantic for the target Context. Any ConsistsOf instance or nested Facet instance omitted from the payload will be systematically removed from the Context. This enables atomic, transaction-level replacements of mandatory Facet instances without breaking schema validation (e.g., solving the “Cardinality Chicken-and-Egg” problem). The topological impact of a PUT operation on a Resource instance is governed by its query parameters:

1. Single Context Update (Local Copy-on-Write)

Without hierarchy parameters, the topological effect (adding, removing, or replacing Facet instances) is confined strictly to the current token Context. This operation handles any combination of structural changes: adding new Facet instances (by including new ConsistsOf JSON objects with a freshly client-generated id that does not yet exist in the system), removing existing ones (by omitting them from the payload), or both simultaneously.

This simultaneous action is what enables the Local Copy-on-Write (Forking) pattern: to create a local variation of a shared Facet instance without affecting other Contexts, the client can perform a PUT on the parent Resource instance, assigning a freshly client-generated id to both the new ConsistsOf instance and its nested Facet instance, instead of the id of the shared instances.

The system will create a new isolated clone for the current Context and seamlessly drop the old association locally. (Note: It is crucial to generate fresh ids for both. If the client reused the existing ConsistsOf instance’s id while only generating a new id for the Facet instance, it would attempt to retarget an existing shared ConsistsOf instance to a different Facet across different Contexts, which strictly violates the topological rule that a ConsistsOf instance points to exactly one immutable Facet target).

While a fork could theoretically be achieved using two distinct operations (a Remove from Current Context on the existing ConsistsOf instance, followed by a standalone creation of a new ConsistsOf instance along with its new target Facet instance), performing it in two steps is restricted by min/max constraints on the Resource:

  • If max: 1 but no min, you could remove then create.

  • If min: 1 but no max, you could create then remove.

  • If both min: 1 and max: 1 are set, any sequential order violates the schema.

More importantly, even without schema constraints, using a single PUT on the parent Resource is the only way to guarantee that both the addition and the removal are executed atomically within a single transaction.

For example, consider a Resource instance R currently composed of Facet instances [F1, F2, F3, F4] in the current Context, where F1 satisfies a strict min: 1, max: 1 schema constraint. If a PUT request provides a new configuration [F1b, F2, F3, F5]: the old F1 and F4 are removed, while the new F1b and F5 are added, all simultaneously. Because it executes as a single atomic transaction, the min: 1, max: 1 constraint (transitioning from F1 to F1b) is never violated.

(Note: Schema validation is strictly evaluated at the very end of the transaction. If the resulting topological state of the Resource instance violates its schema, the entire operation is safely rolled back and returns a 409 Conflict).

2. Subtree Synchronization (?syncExistingHierarchy=true)

Safely pushes topological changes (like attaching or detaching Facet instances) only to descendant Contexts where the Resource instance is already explicitly shared. This effectively acts as a combined Create/Update + Add to Context + Remove from Current Context avalanche of nested elements across the applicable descendant Contexts.

Similar to the Single Context Update scenario, attempting to manually replicate these topological shifts across the hierarchy via sequential Remove from Current Context and Add to Context operations on the nested instances in each child Context is heavily restricted by min/max constraints on the parent Resource:

  • If max: 1 but no min, you could remove then add.

  • If min: 1 but no max, you could add then remove.

  • If both min: 1 and max: 1 are set (e.g., swapping F1 for F1b), any manual sequential propagation in the descendant Contexts strictly violates the schema.

By executing the [F1, F2, F3, F4] -> [F1b, F2, F3, F5] mutation described above with ?syncExistingHierarchy=true, the identical simultaneous atomic replacement occurs not just in the current Context, but simultaneously across all applicable descendant Contexts, safely bypassing the schema deadlock.

Important (Strict Uniformization): Because the PUT operation enforces a Full Replace, any local topological deviations (e.g., an extra Facet instance previously added only in a child Context) are systematically wiped out to perfectly align the target Context with the submitted payload. Because the resulting topology becomes completely uniform across all synced Contexts, the schema validation result is globally deterministic: it is mathematically impossible to adhere to the schema in one Context while violating it in another.

Crucially, a client can also achieve this in two separate phases: they might first update the local Context without the flag, and later issue the identical PUT [F1b, F2, F3, F5] ?syncExistingHierarchy=true payload. In this second phase, the operation behaves as a “pure sync”: it makes no local topological changes (since the state already matches) but atomically forces the alignment down the hierarchy. This “pure sync” pattern is extremely valuable for reconciling descendant Contexts that have become topologically misaligned (e.g., due to operational drift or mistakes). Reconciling them in a single shot via PUT ?syncExistingHierarchy=true is infinitely safer than the manual alternative (i.e., removing the entire Resource instance from the descendant Context and re-adding it with the corrected facets). Removing a Resource instance from a Context normally triggers the avalanche destruction of its associated IsRelatedTo instances. Even if a client attempted to bypass the standard avalanche using a surgical removal of the Resource instance, the problem persists: a relation cannot logically exist in a Context if its source and target Resource instances are missing. Therefore, removing the Resource instance inherently drops all its incoming and outgoing IsRelatedTo instances from that Context. The client would then be forced to meticulously track down and perform surgical Add to Context operations to restore all those N relations (and potentially recreate from scratch any relations that existed only in that local Context). The atomic “pure sync” completely avoids this operational nightmare and collateral damage, perfectly restoring the intended schema and structure. (The orphaned F1 and F4 continue to exist in any external Contexts; if no longer referenced anywhere, they are destroyed by the Garbage Collector).

(Note: On a creation, this flag is logically ignored as the instance does not yet exist anywhere, and the system safely emits an X-Warning header).

3. Hierarchical Distribution (?hierarchical=true)

Operates identically to the Subtree Synchronization mode, but with one fundamental expansion in blast radius: instead of pushing changes only to descendant Contexts where the Resource instance is already explicitly shared, it forcefully propagates the Resource instance itself (acting as an Add to Context avalanche) and all its topological changes to every descendant Context within the authorized subtree, systematically overriding local absences.

This mode enforces the exact same strict uniformization, shares the exact same atomic transaction guarantees, and completely bypasses the manual schema violation limitations described above.

(Note: Unlike syncExistingHierarchy, which is logically ignored on creation (emitting an X-Warning header), hierarchical is fully supported and actively used during the initial creation of a Resource instance to establish a baseline configuration across the entire subtree from day one).

PUT on Other Instances (Full Replace Semantic)

When the target of a PUT operation is not a Resource instance, it simply replaces its property fields entirely:

  • Facet instances: The operation replaces its property fields entirely.

  • ConsistsOf instances: The operation replaces its property fields entirely. (System Constraint: A PUT or PATCH operation cannot be used to change the source or target of an existing relation. A relation is intrinsically bound to its original endpoints upon creation. To change them, the existing relation must be deleted and a new one created).

  • IsRelatedTo instances: The operation replaces its property fields entirely. (System Constraint: Identical to ConsistsOf, a PUT or PATCH operation cannot alter the source or target fields of the relation).

Note on Hierarchical Parameters: Because syncExistingHierarchy and hierarchical exclusively govern the topological distribution of a Resource instance, they have no structural meaning when targeting a Facet, ConsistsOf, or IsRelatedTo instance directly. If a client mistakenly passes these query parameters when mutating these specific types, the system safely ignores them and emits an X-Warning header (e.g., 199 resource-registry "ignored-query-parameters=hierarchical; ignored-count=1; reason=Not applicable for this instance type").

For detailed operational patterns (including Facet instance Forking, Copy-on-Write, and resolving cardinality constraints), refer to the API Operational Cookbook & Advanced Use Cases.

Membership Operations (Remove from Current Context / Add to Context)

Conceptual Note (Sharing & Unsharing): Because Contexts act as logical environments over a global graph, the act of “Adding to Context” can be conceptually viewed as “sharing” an instance into another Context, making it visible and usable there. Conversely, “Remove from Current Context” acts as “unsharing”. This documentation and the broader ecosystem may occasionally use the terms share and unshare informally to describe these membership operations.

The API provides two ways to manage an instance’s Context membership:

  1. Single Remove (DELETE): The Remove from Current Context operation (DELETE /instances/{type}/{instance-uuid}) removes it from the token’s Context.

  2. Single Add (PUT): The Add to Context operation (PUT /instances/{type}/{instance-uuid}/contexts/{new-context-uuid}) adds an instance from a source Context (determined by the authorization token) to a destination Context (specified in the URL).

Implementation Detail (Implicit Pull on Relations): If the direct target of the Add to Context operation is a Relation instance, the database enforces strict topological integrity. A Relation cannot exist in a Context if its source and target are missing. Therefore, the system ALWAYS implicitly pulls the target Entity instance into the Context (if it isn’t already there), actively bypassing the unpropagate propagation constraint defined by the Relation. This guarantees that the graph is always structurally sound within any given Context boundary.

Authorization Rules:

  • IS-Admin / Ctx-M and IS-Editor can only add/remove instances across Contexts from a parent Context to one of its child/descendant Contexts (all target UUIDs must belong to their competence subtree).

  • IS-M and Infra-M can add/remove instances across Contexts from any Context to any other Context.

Adding or removing from a Context triggers an avalanche effect. Before successfully returning, the system always strictly validates the resulting state in the target Contexts to prevent logical inconsistencies (e.g., ensuring mandatory Facet instances are present, or ensuring that a Relation instance is not added to a Context where its source Resource instance is missing). If this final validation fails, the operation is aborted and returns a 409 Conflict (topological/schema violation). If successful, both operations (Add to Context, Remove from Current Context) return the full list of instances affected by the avalanche effect.

Even though the Add to Context operation triggers a complex avalanche process, it is exposed via PUT because it is strictly idempotent. Calling the endpoint 1 time or 100 times results in the same final graph state (the instance and required dependencies are present in the target Context). The URI explicitly identifies the membership association. Note that propagationMode=surgical is strictly rejected on this standard endpoint (400 Bad Request); surgical injection is reserved exclusively for the Admin API (PUT /admin/instances/...).

Operation Envelope and Parameter Matrix

Because these operations can trigger avalanche effects, their canonical response is an Operation Envelope. The HTTP status code is always 200 OK (if successful), but the density of the response body and the effect of query parameters (metadataPolicy, includeContexts) depend strictly on the Prefer: return header. The default behavior is to return the full representation.

Successful operation-envelope responses always emit Preference-Applied with the applied payload shape (return=representation or return=minimal). When the request omits Prefer, the response still emits Preference-Applied: return=representation to make the default explicit.

| dryRun | Prefer: return header | Success HTTP Code | Action | Body Density | metadataPolicy, includeContexts | |:—:|—|—|—|—|—| | false | Missing or representation | 200 OK | Real Execution | Full Operation Envelope | Applied (enrich the returned envelope elements) | | false | minimal | 200 OK | Real Execution | Minimal Operation Envelope | Ignored (no structural payload to enrich) | | true | Missing or representation | 200 OK | Simulation Only | Simulated Full Operation Envelope | Applied (enrich the simulated envelope elements) | | true | minimal | 200 OK | Simulation Only | Simulated Minimal Operation Envelope | Ignored (no structural payload to enrich) |

Content Negotiation (Prefer header) and Payload Shape: Returning the full array of complex objects can be bandwidth-intensive for large avalanche operations. Clients can use the standard HTTP Prefer header to explicitly request different shapes of the response payload.

  • Prefer: return=minimal: Returns a highly optimized flat array payload containing only the core topological fields (type, id, and for Relation instances: source, target). Custom fields, supertypes, metadata, contexts, and propagationConstraint are strictly omitted. If a client explicitly passes inclusion query parameters (e.g., metadataPolicy=root), the system ignores them to honor the minimal structural contract, and emits a X-Warning header (e.g., 199 resource-registry "ignored-query-parameters=metadataPolicy; ignored-count=1; reason=Overridden by Prefer: return=minimal").

  • Prefer: return=representation (Default): Returns the instances in full detail. The system fields metadata and contexts are included only if explicitly requested via their respective query parameters (metadataPolicy, includeContexts), whereas propagationConstraint is inherently included as a standard structural field for all Relation instances. The structural rules are as follows:

    • The envelope payload is typically a flat array at the Infrastructure Topology level containing only the Resource instances and IsRelatedTo instances (with ConsistsOf and Facet instances properly nested inside their parent Resource). (Note: If an operation directly targets a Facet or ConsistsOf instance, such as deleting a specific Facet, those specific instances will be returned directly in the array, as the avalanche was not triggered by a source Resource instance).

    • Resource instances are returned in full, meaning their attached ConsistsOf instances and Facet instances are nested inside the Resource instance.

    • IsRelatedTo instances are returned in full, but their source and target fields are serialized as minimal references containing inherently only "type" and "id". (Note: As per standard enrichment rules, these reference pointers will be explicitly populated with "metadata" and "contexts" blocks if the client explicitly requests them via metadataPolicy=all and includeContexts=true, allowing clients to perform deep synchronization checks if required).

Try-Check-Confirm Pattern (dryRun=true)

Because these operations can trigger powerful and unpredictable avalanches, it is highly recommended to adopt a “Try-Check-Confirm” pattern using dryRun=true, and using Prefer: return=representation to simulate the operation without persisting changes.

DELETE vs /admin/ DELETE Paradigm (Reference Counting)

The Delete operation on the base instance endpoint (DELETE /instances/{type}/{instance-uuid}) functions as a removal from the current Context (triggering local REMOVE propagation constraints). The instance is physically destroyed (Garbage Collected) only when removed from its very last Context.

The Admin Remove from Context operation (available exclusively to global admins) uses the admin path DELETE /admin/instances/{type}/{instance-uuid}. When executed with a token representing the Root Context and ?hierarchical=true, it completely annihilates the instance across all Contexts. However, if executed with a token representing a specific Virtual Organization (VO), it performs a surgical hierarchical wipe, removing the instance from that specific subtree while allowing it to survive in parallel Contexts. Because of its destructive nature, this explicit path is strictly reserved for global administrators (IS-Manager, Infrastructure-Manager).

Because both operations trigger avalanche effects (via propagation constraints), they support the dryRun=true query parameter and the Prefer: return=representation header. Following the same “Try-Check-Confirm” pattern, clients can simulate deletion to receive a 200 OK with the flat Normalized Graph of all affected instances before committing.

Additional Constraints

  • hierarchical is available to IS-M / Infra-M, IS-Admin / Ctx-M and IS-Editor on read/query operations. It is also available to IS-Contrib and IS-Member but only for read operations (see hierarchical parameter).

  • List Instance Contexts: Returns a map of Context UUID → Context path. For all roles, the returned Contexts are strictly filtered to the competence subtree defined by the authorization token. Emits Link: rel="up" pointing back to the owning instance URI. (Note: If an IS-M / Infra-M uses a token issued for a specific VO, they will only see Contexts within that VO. To obtain full global visibility, they must explicitly use a token issued for the Root Context /). The response includes X-Result-Scope: role-filtered only when this subtree restriction actually removes a membership; state-filtered is additionally reported when a non-administrative caller actually loses a non-ACTIVE descendant membership.

  • Non-ACTIVE Context behavior: See the detailed behavior documented in Context Management.

Admin API — base path /admin

This section groups all the Global Privileged Operations. These APIs are intentionally segregated under the /admin path to allow strict API Gateway and WAF filtering. They are designed for administrative interventions and are restricted to global administrators (IS-Manager / Infrastructure-Manager).

Authorization & Token Selection

| Action | HTTP | Path | Query Parameters | IS-M / Infra-M | IS-Admin / Ctx-M | IS-Editor | IS-Contrib | IS-Member | |——–|——|——|——————|:————–:|:—————-:|:———:|:———-:|:———:| | Admin Remove from Context | DELETE | /admin/instances/{type}/{instance-uuid} | hierarchical, propagationMode, dryRun, metadataPolicy, includeContexts | ✅ | ❌ | ❌ | ❌ | ❌ | | Admin Add to Context | PUT | /admin/instances/{type}/{instance-uuid}/contexts/{new-context-uuid} | hierarchical, propagationMode, dryRun, metadataPolicy, includeContexts, bypassHierarchyCheck | ✅ | ❌ | ❌ | ❌ | ❌ | | Execute Raw Query | QUERY | /admin/raw-query (POST /admin/raw-query fallback) | hierarchical, metadataPolicy, includeContexts, rawResult | ✅ | ❌ | ❌ | ❌ | ❌ | | System Dump | GET | /admin/system/dump | — | ✅ | ❌ | ❌ | ❌ | ❌ | | System Restore | POST | /admin/system/restore | — | ✅ | ❌ | ❌ | ❌ | ❌ |

Token Scope Rule:

| Operation Group | Token must be issued for | |—————-|—————————| | All /admin/* operations | Administrative role (IS-M / Infra-M) is required. For Admin Remove from Context and Admin Add to Context, the operational token Context dictates the starting root of the subtree the operation applies to (use a root-Context token for true global scope). System Dump and System Restore are whole-system operations: the token’s Context is irrelevant, any IS-M / Infra-M token works regardless of which Context it was issued for. |

HTTP Contract

| Action | Additional Request Headers | Response Headers | Success HTTP Code | Error HTTP Code | |——–|—————————-|——————|——————-|—————–| | Admin Remove from Context | Accept, Prefer (return) | Content-Type, X-Warning, Preference-Applied | 200 OK | 400 Bad Request, 403 Forbidden, 404 Not Found, 409 Conflict | | Admin Add to Context | Accept, Prefer (return) | Content-Type, X-Warning, Preference-Applied | 200 OK | 400 Bad Request, 403 Forbidden, 404 Not Found, 409 Conflict | | Execute Raw Query | Content-Type, Accept | Content-Type, X-Warning | 200 OK | 400 Bad Request, 403 Forbidden | | System Dump | Accept (application/zip) | Content-Type (application/zip), Content-Disposition (attachment) | 200 OK | 403 Forbidden | | System Restore | Content-Type (application/zip) | — | 200 OK | 400 Bad Request, 403 Forbidden, 409 Conflict |

Operational Notes

  • Admin Remove from Context: A standard user DELETE /instances/ removes an instance from a single Context. The admin DELETE /admin/instances/ acts hierarchically. If the admin provides a token for /VO1 and uses ?hierarchical=true, the instance is cleanly wiped from /VO1 and all its VREs, but survives in /VO2. If they provide a Root token, the instance is completely annihilated globally.

  • Admin Add to Context: Exactly like the standard Add to Context, this operation fundamentally acts as a transfer from a source Context to a destination Context. The destination Context is explicitly provided in the URL ({new-context-uuid}) and must resolve to a live Context; an unknown or cemetery target returns 404 Not Found before target-scope evaluation. The source Context—which determines the exact topological blueprint (the specific set of outgoing Relation instances to evaluate for propagation)—is always exclusively and non-hierarchically determined by the Context bound to the administrator’s authorization token. An instance available only in a descendant or parallel Context is therefore rejected with 403 Forbidden. Even if the administrator holds a globally-scoped role (e.g., IS-M), their token is still bound to a specific Context (e.g., the Root Context or a specific VO). This explicitly anchors the operation to a deterministic source topology, preventing any ambiguity about which topological branch is being copied. bypassHierarchyCheck=true waives only destination containment and never source lookup. Combining this with hierarchical=true atomically applies the source blueprint to the destination Context and its entire descendant subtree.

  • Execute Raw Query: Body: JSON payload {"query": "..."}. ⚠️ NOT for production (OrientDB SQL, backend may change). Should not be used programmatically or implemented in a client library — intended for manual administrative diagnostics only. Only read-only statements are accepted. Any valid read-only OrientDB SQL statement is supported (e.g., SELECT, TRAVERSE, MATCH, EXPLAIN). Because the endpoint executes under a read-only database user, metadata/system-class reads and vendor-specific read functions are permitted, whereas destructive operations are inherently rejected at the engine level. The database session is scoped to the token Context; hierarchical=true extends its visibility to descendants. With rawResult=false (default), element rows are formatted through the Information System model and honour metadataPolicy/includeContexts, while scalar and projection rows have no Information System representation and are therefore preserved in backend-native JSON without being dropped; explicitly requested enrichment parameters are ignored for those rows with X-Warning. With rawResult=true, every row retains the backend-native JSON shape and field names unmodified. Serialization is all-or-nothing: a row-formatting failure never produces a partial successful result.

  • System Dump: Produces a complete logical dump of the entire Resource Registry state as a closed seven-entry ZIP archive (Content-Disposition: attachment; filename="resource-registry-dump.zip"), independently of the caller’s token Context: manifest.json, RegistryMetadata, every registered Type schema, every Context (live and cemetery alike), every Query Template, and every Resource and IsRelatedTo relation instance, each with full metadata and embedded Context membership. Facet entities and ConsistsOf relations are not dumped separately — they are embedded within their owning Resource’s own representation, exactly as when reading a Resource “as-a-whole”. Serialization is all-or-nothing: any collection or row serialization failure aborts the download instead of producing a successful incomplete archive. Every entry can be read with information-system-model alone: manifest.json (a DumpManifest) describes the archive — formatVersion and createdAt — while registry-metadata.json (a RegistryMetadata) describes the registry the information comes from — models, every model by name (information-system-model, the domain model, and the runtime model holding the types created through REST, marked runtime: true), each with its version from the classpath, its types ({ typeName: version }) and its revisionCount, next to the global revisionCount.

  • System Restore: Ingests the exact seven-entry ZIP archive produced by System Dump and recreates the entire Resource Registry state in strict topological order: Types, Contexts, Query Templates, Resources, then IsRelatedTo relations, and finally RegistryMetadata, kept as dumped except its global revisionCount, which stays the target’s. Missing, duplicate, unexpected, malformed, incompatible, or referentially invalid archive content is rejected with 400 Bad Request before any write — incompatible meaning an unsupported formatVersion, or an information-system-model version in registry-metadata.json newer than the target’s; every Resource and IsRelatedTo relation must declare at least one valid Context membership. Every original UUID and every original metadata object (creator, creation/last-update timestamps) is preserved verbatim. Requires the target system to be empty (no Context, Query Template, Resource, or IsRelatedTo relation may already exist, and no Type may extend Resource, Facet, IsRelatedTo, ConsistsOf, or Property) — the state immediately after a service startup against an empty database. This is a hard precondition with no override: restoring into an already-populated system is rejected outright (409 Conflict), never attempted as a merge. Archive preflight completes before the first write, but the subsequent restore is not one global transaction: an unexpected persistence failure can leave a partially populated target, which must be recreated before retrying.

High-Impact Topological Operations Summary

To consolidate the reader’s mental model before proceeding to Query Templates, the API provides several powerful mechanisms that can drastically alter the graph structure across multiple boundaries. Because of their significant high-impact nature and potential for massive avalanche consequences, it is vital to fully understand their blast radius. To ensure operational comprehension and safety, the following table summarizes these high-impact structural operations and their typical safe use cases:

| Operation Name | Method, Path & Parameters | Blast Radius | Dry-run? | Typical Safe Use | |—|—|—|:—:|—| | Single Context Update | PUT /instances/{type}/{instance-uuid} | Current Context. Replaces local topology and overwrites properties globally. | ❌ | Forking a shared element (Local Copy-on-Write) or updating a field globally. | | Subtree Synchronization | PUT /instances/{type}/{instance-uuid}?syncExistingHierarchy=true | Shared Subtree. Descendant Contexts where the instance is already explicitly shared. | ❌ | Safe topological alignment across the hierarchy without forcing inclusion in new Contexts. | | Hierarchical Distribution | PUT /instances/{type}/{instance-uuid}?hierarchical=true | Current Context + Entire descendant subtree. | ❌ | Forced blanket replication of a mandatory baseline configuration for all child tenants. | | Shallow Add to Context | PUT /instances/{type}/{instance-uuid}/contexts/{new-context-uuid}?propagationMode=shallow | Target Context + Avalanche (stops at existing instances). | ✅ | Safe, standard sharing of an instance and its strictly missing dependencies. | | Deep Add to Context | PUT /instances/{type}/{instance-uuid}/contexts/{new-context-uuid}?propagationMode=deep | Target Context + Full Transitive Closure Avalanche. | ✅ | Forced re-evaluation and importation of a deeply interconnected graph. | | Surgical Add to Context | PUT /admin/instances/{type}/{instance-uuid}/contexts/{new-context-uuid}?propagationMode=surgical | Target Context (Targeted instance only). Stops Add-Propagation. | ✅ | Manual topology repair or targeted injection of a single node. (Restricted to IS-M / Infra-M). | | Cross-Boundary Add | PUT /admin/instances/{type}/{instance-uuid}/contexts/{new-context-uuid}?bypassHierarchyCheck=true | Cross-subtree (breaks logical tree boundaries). | ✅ | Injecting harvested infrastructure data or migrating cross-tenant instances. (Restricted to IS-M / Infra-M). | | Admin Hierarchical Add | PUT /admin/instances/{type}/{instance-uuid}/contexts/{new-context-uuid}?hierarchical=true | Target Context + Entire descendant subtree. | ✅ | Forced blanket propagation of an external instance into a specific target subtree. (Restricted to IS-M / Infra-M). | | Standard Removal | DELETE /instances/{type}/{instance-uuid}?propagationMode=shallow | Current Context + Garbage Collector Avalanche (for orphans). | ✅ | Standard removal. The instance dies physically only if removed from its final Context. | | Surgical Removal | DELETE /instances/{type}/{instance-uuid}?propagationMode=surgical | Current Context (Targeted instance only). Stops Remove-Propagation. | ✅ | Emergency “undo” facility to eliminate a relation without collateral resource damage. | | Admin Hierarchical Wipe | DELETE /admin/instances/{type}/{instance-uuid}?hierarchical=true | Entire descendant subtree (Or global ecosystem if invoked from Root). | ✅ | Brutal global decommissioning of a corrupted or obsolete instance everywhere it exists. (Restricted to IS-M / Infra-M). |

(Note: The operations restricted to global administrators are exclusively available via the /admin/ API subset).