Inventory Elf GraphQL API
Use POST /api/v2/graphql for new integrations. POST /api/v1/graphql remains
supported with its saved-record inventory contract. Both versions share bearer-token
authentication, scopes, limits, catalog operations, settings, availability publishing and
stock writers. Requests/responses use JSON over HTTPS. Site creation, webhooks and
subscriptions are not exposed. Binary image uploads continue at /api/v1/images.
Published schemas: v2 schema and v1 schema. Authenticated introspection follows normal query limits. Prices are decimal strings, IDs are UUIDs, timestamps are ISO 8601 UTC. Stored stock is signed; mutation quantities are nonnegative 32-bit integers, subject to direction and reason validation.
V2 inventory and migration from v1
Every material, component and product variant exists in inventory at every organization
site. Products group variants. Missing saved balances return quantity: 0, version: 0,
inventoryItemId: null and location: null. Reading inventory, creating catalog items,
creating sites or connecting Shopify products creates no stock rows/events. Existing
positive, zero and negative stock, labels, settings and immutable history are preserved.
query Inventory($siteId: ID!, $after: String) {
inventory(siteId: $siteId, first: 50, after: $after) {
nodes { siteId targetType targetId inventoryItemId quantity location version }
pageInfo { endCursor hasNextPage }
}
}
Use { siteId, targetType, targetId } as inventory identity, including after saving.
Target types are MATERIAL, COMPONENT, PRODUCT_VARIANT. Single-item reads use
inventoryItem(siteId:, targetType:, targetId:). An inaccessible/missing site or catalog
target returns null. Inventory at an inaccessible site is an empty connection.
V2 inventory is ordered by target type then target UUID, including default zeros. Use opaque cursors only with the same API version, organization, site and collection. Page size defaults to 50 and is capped at 100. Pagination is a live view; inserts before a cursor may require another full scan. V1 inventory still lists saved rows by UUID.
mutation Receive($input: AdjustInventoryInput!) {
adjustInventory(input: $input) { siteId targetType targetId inventoryItemId version }
}
{
"input": {
"siteId": "REPLACE_WITH_SITE_UUID",
"targetType": "MATERIAL",
"targetId": "REPLACE_WITH_MATERIAL_UUID",
"direction": "INCREASE",
"reason": "STOCK_RECEIVED",
"quantity": 10,
"expectedVersion": 0,
"idempotencyKey": "v2-receipt-1042-line-1"
}
}
Every adjustment and location edit requires expectedVersion. Read it first; use zero
only when no balance exists. The writer checks the version under the site/target lock.
Concurrent first writes with distinct keys yield one success and one VERSION_CONFLICT.
The first adjustment creates the balance and records only that adjustment atomically;
failed changes leave no row/event. Mutation results contain target identity, nullable
saved UUID and resulting version. Re-read inventory for quantity and location.
INCREASE/DECREASE require positive quantities. RECOUNT sets a nonnegative total,
including zero, and leaves the item visible. DECREASE with reason REMOVE requires a
nonblank note and may create a negative balance; other manual decreases cannot do so.
Receipts preserve and reduce existing debt. Integer overflow is rejected.
mutation Shelf($site: ID!, $target: ID!, $version: Int!, $key: String!) {
updateInventoryLocation(siteId: $site, targetType: MATERIAL, targetId: $target,
location: "Shelf A", expectedVersion: $version, idempotencyKey: $key) {
siteId targetType targetId inventoryItemId version
}
}
A first shelf/bin edit can save a zero balance without a quantity event or alert.
location: null clears the label. Options/settings remain independent of balance rows.
inventoryHistory(siteId:, targetType:, targetId:) uses immutable target snapshots,
including history whose saved inventory row was deleted. History uses the same target-type
enum as inventory entries. Supply both target fields or
neither to read all site history. History pagination remains UUID-ordered.
Migration steps:
- Change the GraphQL endpoint and use the v2 schema. Catalog operations remain compatible.
- Replace inventory-row keys with site/type/target keys; retain
inventoryItemIdonly as optional saved-record metadata. Expect many zero-balance entries in lists. - Replace first-row
addInventoryItemwith a normal adjustment at version zero. Replace stock-row deletion with a recount to zero when that is the intended change. - Move single-item, shelf and history inputs to target identity and supply read versions.
- Start fresh pagination cursors and mutation keys when switching API versions.
V2 has no stock assignment or deletion mutations. V1 UUID queries and mutations continue to behave as before; a v1 deletion cannot hide a catalog item from app/v2 inventory. Replay keys share the token namespace across versions, but validation includes API version: a key cannot replay a v1 response through v2 or vice versa. Retry an uncertain request with the same version, key and input. Rollout requires no balance backfill or schema migration.
The remaining inventory examples explicitly labeled v1 document compatibility behavior; authentication, catalog, limits and other shared operations apply to both versions.
Create a token
In the app, open Organization → Settings → API tokens as an organization admin. Enter an integration name, select permissions and choose expiry (default 90 days, maximum 365). Copy the token immediately: it is only shown once. Store it in your integration's secret manager, not source code or URLs.
Only admins of that organization can issue/list/revoke tokens. Tokens are bound to one organization; GraphQL accepts no organization override. A token stops working when expired, revoked, or while its creator is no longer an admin there. Admins may revoke another admin's token. If admin access is restored, an unrevoked, unexpired token becomes valid again; revoke tokens when permanently offboarding an integration. Maximum 20 active tokens and 10 creations per rolling hour per organization. The list shows up to 100 tokens, with active tokens first, then recent expired/revoked tokens. For rotation, create a replacement, deploy it, then revoke the old token. Automatic overlap scheduling is not implemented.
| Scope | Operations |
|---|---|
catalog:read | Catalog records and image URLs, direct composition items, options, categories, units |
catalog:write | Create/update materials, components, component models, products and variants; manage component model connections; upload replacement images |
catalog:delete | Delete catalog records |
inventory:read | Sites, inventory and immutable history; v2 includes default-zero catalog targets |
inventory:write | Adjust counts and update locations; v1 also adds saved rows |
inventory:delete | V1 saved-row removal and stock-linked catalog deletion |
inventory-options:read | Read per-site minimum levels and alert thresholds |
inventory-options:write | Save per-site minimum levels and alert thresholds |
availability:read | Discover connected variants and read Availability Sync previews/status |
availability:write | Check live eligible locations, enable/disable per-location sync, retry publishing |
Write/delete scopes automatically include the corresponding read scope. Availability and inventory-options permissions also include inventory:read for site, stock and target discovery. Existing tokens gain no new permissions; create a replacement token with the desired scopes.
Deleting a catalog record with linked stock additionally requires
inventory:delete, including product-to-variant cascades. Tokens never grant
member management, credential access, token management or browser login.
First request
Set INVENTORY_ELF_URL to your Inventory Elf service URL (for example, https://invelf.com) and INVENTORY_ELF_API_TOKEN from secure
configuration. Do not enable shell tracing with credentials present.
curl "$INVENTORY_ELF_URL/api/v1/graphql" \
-H "Authorization: Bearer $INVENTORY_ELF_API_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"query":"{ sites(first: 50) { nodes { id name } pageInfo { endCursor hasNextPage } } }"}'
All requests support query, optional variables, and optional operationName.
Only one operation is executed. HTTP operation arrays/batching and subscriptions
are rejected. Cookies cannot authenticate this endpoint. Browsers do not receive
cross-origin CORS permission; use a server-side integration.
Find catalog IDs and v1 inventory
query Inventory($siteId: ID!, $after: String) {
inventory(siteId: $siteId, first: 50, after: $after) {
nodes {
id siteId materialId componentId productVariantId
quantity location version
}
pageInfo { endCursor hasNextPage }
}
}
Each stock row has exactly one target: material, component, or product variant.
Use materials, components, products, variants(productId:) and single-record
queries to discover catalog IDs. categories and units return existing IDs.
productOptions(productId:) and optionValues(optionId:) expose variant option
IDs. componentItems(componentId:) and variantItems(variantId:) return direct
composition rows; variant items do not include inherited product/option items.
Use effectiveVariantItems(variantId:) for the combined recipe shown in the app.
All collections use opaque cursors, default first: 50, maximum 100.
Pass pageInfo.endCursor as after while hasNextPage is true. Ordering is UUID
ascending, including history (effective variant items sort by source, then UUID).
Use createdAt to interpret event time. Cursors
are specific to the organization, collection and filters. Pagination is a live
view, not a snapshot: concurrent inserts may require a subsequent full scan.
No search/sort/filter language or total count is exposed in v1 beyond the
explicit schema arguments. Inaccessible single records return null; collections
contain only accessible rows.
Effective variant children
effectiveVariantItems(variantId:, first:, after:) requires catalog:read and
returns product defaults, children from the variant's selected option values,
and children assigned directly to the variant. This also works for variants whose
variantItems list is empty because all children are inherited. Unselected option
values are excluded. Missing or inaccessible variants return an empty connection.
query VariantChildren($variantId: ID!, $after: String) {
effectiveVariantItems(variantId: $variantId, first: 100, after: $after) {
nodes {
id variantId materialId componentId quantity
source sourceOptionId sourceOptionValueId sourceLabel
}
pageInfo { hasNextPage endCursor }
}
}
source is PRODUCT, OPTION_VALUE, or VARIANT. Option-source rows identify
the option and selected value, with a label such as Color: Red. Material quantities
can be fractional. Separate rows that reference the same child remain separate;
quantities are not combined or recursively expanded. Use componentItems for a
component's own children, and material/component to resolve names and SKUs.
Pages sort by source (OPTION_VALUE, PRODUCT, VARIANT), then row UUID. Use
(source, id) as a row identity because direct and inherited tables may contain
the same UUID. Cursors are specific to the organization, variant and collection;
do not reuse a variantItems cursor. The existing direct-only query is unchanged.
Catalog mutations
Every catalog mutation needs a unique idempotencyKey. Every catalog update and delete needs the
record's current expectedVersion. Successful catalog mutations return { id, version };
deletions return a null version. Read the record separately for its full data.
mutation CreateMaterial($input: MaterialInput!, $key: String!) {
createMaterial(input: $input, idempotencyKey: $key) { id version }
}
{
"input": { "name": "Aluminum bracket", "sku": "BRACKET-001", "price": "3.50" },
"key": "erp-material-BRACKET-001-create"
}
| Resource | Create | Update | Delete |
|---|---|---|---|
| Material | createMaterial | updateMaterial | deleteMaterial |
| Component | createComponent | updateComponent | deleteComponent |
| Product | createProduct | updateProduct | deleteProduct |
| Variant | createVariant | updateVariant | deleteVariant |
Material updates require name; optional omitted fields remain unchanged.
Use empty strings to clear material description/SKU, and null to clear optional
price/unit/category fields. Component updates supply a complete replacement
items list (empty means remove all direct items) and follow the app's existing
field replacement rules. Each component item specifies either materialId or
childComponentId and a positive integer quantity. Nested loops are rejected.
Product creation may supply options and values with client-generated UUIDs. The app generates all option combinations, or a single default variant for a product without options. The API caps generated variants at 100 per create. Product updates change name, description and base price; option-definition editing and inherited-item editing are not exposed in this release.
createVariant(productId:, input:) adds one missing combination of the product's
existing option values; it does not modify options or generate duplicate
combinations. selectedOptionValueIds must select one value per option. Variant
creation/update supply a complete direct items list, and each item references
one material or component. Component quantities are integers; material quantities
may be fractional. Existing SKU, pricing, reference and organization constraints
apply. At most 100 elements per input list and eight input nesting levels.
Deletion requires confirm: true. A component referenced by another component
must first be removed from that composition. The last variant of a product
cannot be deleted individually; delete the product instead. Product deletion
removes its variants. Inspect dependencies and stock before deleting catalog rows.
Catalog GraphQL mutations preserve existing images. Use the image upload endpoint below to assign or replace an image after creating an item.
Item images
Materials, components, products and variants expose an optional image field in
both single-record and collection queries. image is null when no image is
available. Variants use their own image when set, otherwise their product's image.
query MaterialImage($id: ID!) {
material(id: $id) {
id name version
image { url thumbnailUrl largeUrl }
}
}
The URLs are ready to display or download. They do not require a bearer token; anyone with an image URL can view it. Treat catalog images as public assets. Image URLs may serve optimized formats depending on the requesting client.
Upload or replace an image
Send raw file bytes to POST /api/v1/images with the same bearer token used for
GraphQL. The token must include catalog:write. Supply these query parameters:
| Parameter | Value |
|---|---|
targetType | MATERIAL, COMPONENT, COMPONENT_TEMPLATE, PRODUCT, or VARIANT |
targetId | UUID of an existing item in the token's organization |
expectedVersion | Current item version from a GraphQL read |
Set Content-Type to image/jpeg, image/png, or image/webp, and send a unique
Idempotency-Key header. Do not send JSON, base64, multipart form data, an image
URL, or a storage identifier. Uploads accept a single-frame image up to 4 MiB
(4,194,304 bytes) and 25 megapixels. SVG, GIF and animated images are not
supported. Images are optimized, stripped of metadata, and resized to fit within
4096 × 4096 pixels while preserving their aspect ratio.
curl "$INVENTORY_ELF_URL/api/v1/images?targetType=MATERIAL&targetId=$MATERIAL_ID&expectedVersion=3" \
-H "Authorization: Bearer $INVENTORY_ELF_API_TOKEN" \
-H 'Content-Type: image/png' \
-H 'Idempotency-Key: material-photo-2026-09-12' \
--data-binary @material.png
Success returns HTTP 200 with { "data": { "id": "…", "version": 4, "image": { "url": "…", "thumbnailUrl": "…", "largeUrl": "…" } } }. Save the returned version
for subsequent edits. The upload replaces only the item's image, preserving its
other fields. A product upload changes its featured image; a variant upload sets
an override. Replacing a product image also changes what variants without their
own images display; re-read those variants to see the new URLs. Removing an image
or clearing a variant override is not exposed in this version.
Retries must use the same target, expected version, content type, file bytes and
idempotency key. Successful retries return the original result without another
replacement. Different content with the same key returns IDEMPOTENCY_CONFLICT.
A stale version returns VERSION_CONFLICT before the image is replaced. A failed
upload leaves the current image unchanged. Uploads use the same token-wide
idempotency namespace as GraphQL mutations.
Each upload consumes one request, one write and 100 query-cost points from the
ordinary API allowances, including retries. Additional upload limits replenish at
6/minute per token (burst 2) and 30/minute per organization (burst 5). Rejected
uploads also consume these allowances once authorized. Honor Retry-After on
HTTP 429. Image upload errors use the same errors envelope and request IDs as
GraphQL, with HTTP status codes: 400 invalid image or parameters, 401 invalid
token, 403 missing permission, 404 inaccessible item, 408 upload timeout, 409
version/idempotency conflict, 413 file too large, 415 unsupported content type,
429 rate limit, or 503 temporary unavailability. A server error may return 500.
Check HTTP status and the response body before treating an upload as successful.
V1 add stock and adjust counts
Use addInventoryItem(input:) for the first row at a site, with siteId,
targetType (MATERIAL, COMPONENT, PRODUCT_VARIANT), targetId, quantity,
optional location/note and idempotencyKey. Initial quantity creates an
inventory recount event. A duplicate site/target row is a conflict.
mutation AdjustStock($input: AdjustInventoryInput!) {
adjustInventory(input: $input) { id version }
}
{
"input": {
"inventoryItemId": "REPLACE_WITH_INVENTORY_UUID",
"direction": "INCREASE",
"quantity": 10,
"reason": "STOCK_RECEIVED",
"note": "Receipt PO-1042",
"expectedVersion": 3,
"idempotencyKey": "warehouse-PO-1042-line-1"
}
}
INCREASE and DECREASE require a positive quantity; RECOUNT sets the absolute
count and permits zero. Negative resulting stock and integer overflow are
rejected. Every adjustment atomically updates stock and appends an immutable
history event. Concurrent browser and API changes increment version.
Use updateInventoryLocation with a version/key to set a location (null clears
it). Use deleteInventoryItem with confirm: true, a nonblank note, a version
and key to remove a row. Removal records its count going to zero and retains
history. inventoryHistory(siteId:, inventoryItemId:) can be filtered by a live
inventory ID. After removal, query site history; deleted entries no longer have
an inventory ID. History includes target snapshots and event type.
Retries and concurrency
Keys are 1–128 characters: letters, digits, _, ., :, -. Scope is per token
across all mutations. The same key, operation and input replay the original result
without another write, even if the old expected version is now stale. Different
input with the same key returns IDEMPOTENCY_CONFLICT. Failed mutations make no changes
and do not reserve a key. Successful replay records are retained for
the token lifetime (at least 24 hours unless the token/organization is removed).
Changing tokens also changes the idempotency namespace: do not blindly repeat
an uncertain mutation after rotating credentials.
On VERSION_CONFLICT, read fresh state, reconcile your desired change, and send
a new key with the current version. Avoid blindly recalculating/retrying recounts.
A successful mutation saves its result and history together, so retrying the
same request does not apply the change twice.
Rate limits and bounded query cost
Limits apply per token and per organization. Request allowances replenish continuously at the rates below. Short bursts are allowed up to the stated capacity. All tokens belonging to an organization share its allowance.
| Limit | Sustained rate | Burst capacity |
|---|---|---|
| Requests per token | 120/min | 20 |
| Requests per organization | 600/min | 100 |
| Writes per token | 30/min | 5 |
| Writes per organization | 120/min | 20 |
| Query cost per token | 10,000 points/min | 10,000 |
| Query cost per organization | 50,000 points/min | 50,000 |
Requests must fit within all applicable limits. Invalid GraphQL requests with a valid token still consume request quota; valid operations also consume cost and write budgets before execution, including replays and failed mutations. Service-wide traffic protection may also temporarily limit requests.
Maximum operation cost: 1,000 points; field depth: 8; aliases: 20; parsed tokens:
10,000; request body: 256 KB. Only one root mutation is allowed per request,
including aliases and fragment expansion. Cost starts at one per selected field,
multiplies descendants of paginated collections by first, and charges root
mutations 100 points. Fragments are expanded and directives are counted
conservatively even if skipped. Oversized operations are rejected before execution.
Responses include X-Query-Cost after successful analysis and X-Request-Id.
429 includes Retry-After in seconds. Honor it and use exponential backoff with
jitter. There is no remaining-quota header in v1. Temporary service unavailability
returns 503; use the same idempotency key when retrying uncertain writes.
Errors
Authentication/transport/validation failures use appropriate HTTP status codes
(401, 405, 413, 415, 400, 429, 503). Resolver errors follow GraphQL semantics:
HTTP 200 with an errors array; always inspect it, even after an HTTP success.
Queries can return partial data. Mutation execution is atomic.
{
"data": null,
"errors": [{
"message": "Resource changed. Read its current version before retrying.",
"path": ["adjustInventory"],
"extensions": { "code": "VERSION_CONFLICT", "requestId": "..." }
}]
}
Stable codes include UNAUTHENTICATED, FORBIDDEN, NOT_FOUND,
VALIDATION_FAILED, GRAPHQL_PARSE_FAILED, GRAPHQL_VALIDATION_FAILED,
CONFLICT, VERSION_CONFLICT, IDEMPOTENCY_CONFLICT, QUERY_TOO_COMPLEX,
RATE_LIMITED, PAYLOAD_TOO_LARGE, UNSUPPORTED_MEDIA_TYPE,
METHOD_NOT_ALLOWED, SERVICE_UNAVAILABLE, and INTERNAL_SERVER_ERROR.
Use the response request ID when reporting an error to support.
API versioning
This reference describes API v1. Breaking changes require a new API version. New fields and operations may be added compatibly.
Minimum levels and alerts
inventoryOptions and saveInventoryOptions share the app's per-site settings for
MATERIAL, COMPONENT, and PRODUCT_VARIANT targets, including untracked targets.
Unconfigured targets return empty alerts, minimum 0, enforcement false, version 0.
Alert thresholds must be unique nonnegative 32-bit integers (maximum 50); saved
levels are sorted descending. Saving replaces all settings. Use an empty alerts
array to clear alerts and stopSellingAtMinimum: false to disable the reserve.
Use the returned version on the next save; stale versions return CONFLICT.
Settings changes do not send alerts immediately. Future stock decreases crossing
thresholds use the existing notification flow. Enabled minimums affect Shopify
publishing without rejecting physical stock changes or already-placed purchases.
query Options($site: ID!, $target: ID!) {
inventoryOptions(siteId: $site, targetType: MATERIAL, targetId: $target) {
alertLevels minimumLevel stopSellingAtMinimum version
}
}
mutation SaveOptions($input: InventoryOptionsInput!) {
saveInventoryOptions(input: $input) {
alertLevels minimumLevel stopSellingAtMinimum version
}
}
Example variables for the mutation:
{"input":{"siteId":"SITE_UUID","targetType":"MATERIAL","targetId":"MATERIAL_UUID","alertLevels":[20,10],"minimumLevel":5,"stopSellingAtMinimum":true,"expectedVersion":0,"idempotencyKey":"material-options-1"}}
Availability Sync to Shopify
Use availabilitySyncVariants to discover connected Shopify variant UUIDs and
corresponding Inventory Elf variant UUIDs. availabilitySync(shopifyVariantId:)
returns calculated quantities, blockers, per-location enablement, queue/error
state and an ISO timestamp version. An inaccessible/unlinked variant returns
linked: false. Shopify location IDs are Shopify GIDs, not Inventory Elf UUIDs.
availabilitySyncEligibleLocations performs live validation and requires
availability:write; ordinary status reads require only availability:read.
Connection setup and location mapping remain in the app. Credentials, internal
publication payloads and notification delivery records are never public fields.
query Sync($variant: ID!) {
availabilitySync(shopifyVariantId: $variant) {
linked runtimeReady enabled version pending error attempts attemptLimit
locations { locationId siteId enabled finished buildable minimum quantity blockers }
}
}
mutation SetSync($input: AvailabilitySyncInput!) {
setAvailabilitySync(input: $input) {
enabled
confirmation { token refreshed changes { locationId siteName currentQuantity quantity } }
}
}
mutation RetrySync($variant: ID!, $key: String!) {
retryAvailabilitySync(shopifyVariantId: $variant, idempotencyKey: $key) { queued }
}
To enable a location, send its Shopify variant UUID, location GID, enabled: true,
the preview's timestamp as expectedVersion, and a unique idempotencyKey.
If live quantities differ, the result contains a confirmation and makes no
configuration change. Review every quantity, then submit the same request with
confirmationToken and a new idempotency key. Live/local quantities are checked
again; changed quantities return a refreshed confirmation requiring another
review and new key. Reusing a key with changed input returns IDEMPOTENCY_CONFLICT;
replaying identical input returns its saved result. A confirmation token does not
reserve stock. A stale link version returns CONFLICT; unmet Shopify prerequisites
return PRECONDITION_FAILED.
Disable with enabled: false, the current version and a new key. Disabling needs
no Shopify read and leaves the last published quantity in Shopify. Retry queues
fresh work for an enabled variant; publishing runs asynchronously through the
existing worker/cron. Minimum edits also enqueue recalculation.
Availability publication retries retain the existing read/write scope requirements. Retry no longer rejects a stock mismatch: InvElf publishes absolute availability. Uncertain writes keep their original key and block newer revisions. Expired or disabled-target uncertainty returns a precondition error requiring operational resolution. Inbox/recovery administration is available only through admin tRPC, not through availability API tokens. See the processing contract.
Component models (v1 and v2)
The UI calls these Component models. Existing API names (ComponentTemplate,
componentTemplate, componentTemplates, templateId/templateName) and the
COMPONENT_TEMPLATE image target remain unchanged for compatibility.
Component models group concrete components within the token organization. They expose name, description, independent image, version and componentCount. They cannot hold stock or be recipe targets. Use componentTemplates(first,after,search) and componentTemplate(id) for reads; components(templateId,search,first,after) lists their concrete members. Passing null templateId selects unassigned components; omission leaves the collection unfiltered. Component records expose templateId/templateName. Filtered cursors are bound to the filter.
createComponentTemplate(input,idempotencyKey) accepts required name, optional description and up to 100 components[{id,expectedVersion}]. updateComponentTemplate requires the expected component model version. setComponentTemplate(input:{templateId,components,idempotencyKey}) atomically assigns/moves selected components; null clears. Component create/update inputs also accept optional templateId; omitted updates preserve it and null clears it. Concurrent component changes return VERSION_CONFLICT without partially applying a batch.
deleteComponentTemplate(id,expectedVersion,confirm:true,idempotencyKey) retains components and clears connections. It requires catalog:delete and, if assigned, catalog:write. No inventory scope is needed. Empty component models only require catalog:delete. Members with catalog:read can browse; every write still requires the token owner's admin membership.
Use the image endpoint with targetType=COMPONENT_TEMPLATE and the current component model version to upload/replace. updateComponentTemplate(input:{name,clearImage:true},...) clears explicitly; otherwise image identity is preserved. Component images never inherit the component model image. All usual API bounds and idempotency rules apply; see generated SDL for complete typed inputs and results.