Upload and Deploy an AI Model
Overview
Authenticate each request with a WEDA bearer token that grants access to the target organization and devices. Obtain one through the standard SSO flow or as an M2M Client Credential.
The workflow has two parts:
- Upload — create the model, register an edition, upload the binary, and wait for hash verification
- Deploy — push the verified edition to target devices and confirm the result
Upload Flow
| Step | Call | Result |
|---|---|---|
| 1. Create model | POST /api/v1/orgs/{orgId}/ai-models — body { modelName } | 201 → modelId. If the name already exists, 409 — list existing models and reuse the modelId |
| 2. Register edition | POST /api/v1/orgs/{orgId}/ai-models/{modelId}/editions — body { edition, fileName, fileSize, fileHash } | 201 → uploadId, tusEndpoint |
| 3. Create upload session (tus) | POST /api/v1/orgs/{orgId}/ai-models/{modelId}/editions/{edition}/uploads — headers Tus-Resumable: 1.0.0, Upload-Length: {fileSize}, Upload-Metadata: uploadId {base64(uploadId)} | 201 + Location header containing the upload resource URL |
| 4. Upload binary (tus PATCH) | Send PATCH to the complete URL returned in the Location header — headers Tus-Resumable: 1.0.0, Upload-Offset: 0, Content-Type: application/offset+octet-stream, body = file bytes | 204; object stored, Upload-Offset equals fileSize |
| 5. Check verification status | GET /api/v1/orgs/{orgId}/ai-models/{modelId}/editions/{edition}/uploads/{uploadId}/status | Pending → Uploading → Verifying → Uploaded. WEDA Core re-hashes the file server-side; a mismatch sets VerifyFailed and deletes the object |
Upload-Metadata in step 3 carries the registered uploadId returned from step 2,
base64-encoded. For subsequent HEAD and PATCH requests, use the complete upload resource URL
from the Location header without parsing or reconstructing it. Continue to use the registered
uploadId when polling the upload status. The edition is identified throughout by the edition
string you chose in step 2 (e.g. 1-0-3), not by a numeric ID.
Poll step 5 until the status reaches Uploaded before deploying.
Resuming or Abandoning an Upload
If the upload connection drops mid-transfer, query the current offset before resuming:
| Call | Result |
|---|---|
| Get current upload offset | HEAD to the same upload resource URL from the Location header — returns Upload-Offset and Upload-Length |
| Terminate the upload | DELETE to the same upload resource URL — cancels and removes the in-progress upload. Returns 204, or 404 if the upload resource no longer exists |
Resume by sending the remaining bytes in a subsequent PATCH with Upload-Offset set to the value returned by HEAD.
Terminate instead when you want to start the transfer over. The uploadId stays valid — repeat
step 3 with the same uploadId to create a fresh upload session. There is no need to register the
edition again.
Upload Requirements
- Complete the upload within 12 hours after registering the edition.
- The maximum file size is 50 GiB.
- Provide
fileHashas a 64-character lowercase SHA-256 hexadecimal string. - Supply
fileName,fileSize, andfileHashtogether. Omitting all three creates an empty edition inPendingstatus without starting an upload.
Deploy Flow
| Step | Call | Result |
|---|---|---|
| 6. Deploy | POST /api/v1/orgs/{orgId}/ai-models/{modelId}/editions/{edition}:deploy — body { targets[] } | 202 → { modelDeploymentId, status: "IN_PROGRESS" }, each target at state: "SENT". The deployment is queued and delivered once the device is reachable |
The deploy verb lives under /ai-models/ — there is no separate /models/ route.
The Deploy Body — Apply Pipeline
Each target device carries a tasks[] entry describing a four-phase action pipeline:
preCmd → validateCmd → applyCmd → postCmd. Every hook is an { action, params } pair
drawn from a closed enum — WEDA Core never sends arbitrary shell commands to the device.
The tasks array is optional. If you omit it, WEDA still downloads the verified file to the
device's Secured Volume, but it does not run additional lifecycle actions against a container or
service. Omitting an individual hook (e.g. no preCmd key) has the same effect as setting it to
NOOP for that stage — the stage is skipped without failing.
Common configuration — check disk space, verify the file's checksum, then atomically swap it in and restart the container:
{
"targets": [
{
"deviceIdList": ["000c29e353e9"],
"tasks": [
{
"preCmd": { "action": "CHECK_DISK_USAGE", "params": { "maxUsagePercent": "95" } },
"validateCmd": { "action": "CHECKSUM_VERIFY", "params": { "expectedChecksum": "...", "algorithm": "sha256" } },
"applyCmd": { "action": "ATOMIC_SWAP_AND_RESTART_CONTAINER", "params": { "containerName": "container1" } }
}
]
}
]
}
postCmd is omitted here — there is currently no tested postCmd action to recommend (see the
actions table below). Omitting a hook has the same effect as setting it to NOOP for that stage —
the stage is skipped without failing.
| Hook | Recommended action | Why |
|---|---|---|
validateCmd | CHECKSUM_VERIFY | Confirms the downloaded file matches the expected hash before it's swapped in |
applyCmd | ATOMIC_SWAP_AND_RESTART_CONTAINER | Swaps the file into place and restarts the target container so it picks up the new version |
When you use an action that operates on a container, such as
ATOMIC_SWAP_AND_RESTART_CONTAINER, applyCmd.params.containerName must match a container that
is already running on the device. The action does not create or mount the container. The
container must already have the Secured Volume mounted; see
Make Your Container Read the Model.
An action value outside the documented enum is rejected as a schema validation error (400).
All available actions and parameters
Each hook operates at a different point in the file's lifecycle — validateCmd runs against the
working path (downloaded, not yet moved into place); applyCmd runs against the final path
(after the atomic move). Using an action at the wrong stage fails because the path it expects
doesn't exist yet.
| Action | Stage | Params (✅ required) | Behavior |
|---|---|---|---|
CHECK_DISK_USAGE | preCmd | maxUsagePercent ✅ (0 < x ≤ 100) | Fails if root filesystem usage exceeds the threshold |
CHECKSUM_VERIFY | validateCmd | expectedChecksum ✅ (hex), algorithm (sha256 default or sha512) | Streaming hash comparison |
ATOMIC_SWAP_AND_RESTART_CONTAINER | applyCmd | containerName ✅ | Confirms the swap, then docker restart. A restart failure is non-fatal — the file is already deployed; a warning is logged and nothing is rolled back |
NOOP | preCmd | — | Skip the pre-command step; proceed directly to download |
NOOP | validateCmd | — | Skip validation; trust the downloaded file as-is |
NOOP | applyCmd | — | Skip activation; the file remains in the staging directory and is never moved to its final path |
NOOP | postCmd | — | Skip the post-deployment health check; assume activation succeeded |
Omitting a hook has the same effect as setting it to NOOP for that stage.
postCmd accepts only NOOPNOOP is the only action defined for postCmd, which skips the post-deployment health check.
Omitting the postCmd key has the same effect.
Check Deployment Result
Two read endpoints confirm a deployment — query by device, or by model edition. Both return a paged envelope.
| Operation | Call | Description |
|---|---|---|
| By device | GET /api/v1/devices/{deviceId}/ai-models?maxResultCount=10&skipCount=0 | Per-device deployment records; each walks to the terminal state: DEPLOYED |
| By model edition | GET /api/v1/orgs/{orgId}/ai-models/{modelId}/editions/{edition}/deployments?maxResultCount=10&skipCount=0 | One item per target device, with deviceId, state, edgeFilePath, deploymentStartTime, lastTransitionTime |
{
"items": [
{
"modelDeploymentId": "d642d71e-0cbd-40db-a649-99cdb68def2d",
"modelName": "defect-detector",
"edition": "1-0-3",
"deviceId": "000c29e353e9",
"edgeFilePath": "/ai-models/defect-detector/1-0-3/model.bin",
"state": "DEPLOYED"
}
],
"skipCount": 0,
"maxResultCount": 10,
"totalCount": 1,
"totalPages": 1
}
What Happens on the Device
Once the deployment instruction reaches the device, the on-device agent (dmagent) takes over
automatically:
- Signal received —
dmagentpicks up the pending deployment - Download — retrieves the model file into the device's secured volume
- Apply pipeline — runs the
preCmd → validateCmd → applyCmd → postCmdsequence against the target container
CHECKSUM_VERIFY to verify the file on the deviceWEDA Core re-hashes every upload server-side against the fileHash you registered — a mismatch
sets VerifyFailed and deletes the object, so a corrupted upload never becomes deployable.
On the device, hash verification is opt-in: set validateCmd to CHECKSUM_VERIFY to have the
device check the file before it is activated. With validateCmd omitted or set to NOOP, the
deployment still reaches VALIDATED, but nothing is actually checked at that stage.
A deployment reports these edge-side stages on its way to DEPLOYED:
SENT → SERVERFILEPATH_OBTAINED → EDGERECEIVED → MODEL_STORAGE_CHECKED
→ CAPACITY_CHECKED → DOWNLOADED → VALIDATED → DEPLOYED
A REJECTED status carries a rejection reason identifying which stage failed.
Deployment Statuses
The deployment-level status summarizes the result across all target devices:
| Status | Meaning |
|---|---|
IN_PROGRESS | At least one target device is still processing the deployment. |
COMPLETED | Every target device reached DEPLOYED. |
PARTIAL_FAILED | Some target devices reached DEPLOYED, while others were rejected. |
FAILED | All target devices were rejected. |
Each target device reports its own state:
| State | Meaning |
|---|---|
SENT | WEDA Core accepted and dispatched the deployment request. |
SERVERFILEPATH_OBTAINED | The device resolved the source file location. |
EDGERECEIVED | The device received the deployment instruction. |
MODEL_STORAGE_CHECKED | The device verified that model storage is available. |
CAPACITY_CHECKED | The device confirmed that sufficient storage capacity is available. |
DOWNLOADED | The device downloaded the model file. |
VALIDATED | The downloaded file passed the configured validation. |
DEPLOYED | The model file was placed in its active location successfully. |
REJECTED | The device rejected the deployment. Inspect the rejection reason for details. |
DELETED | The deployed file was removed from the device. |
Device Offline Behavior
Issuing a deployment never checks whether the target device is online — a request to an offline
device is accepted the same as any other. The deployment is queued and will apply automatically
when the device reconnects. While the device is unreachable, its state remains SENT.
Deployments do not time out while a device is offline — they remain pending indefinitely until the device reconnects.
Deploying the Same Model More Than Once
A deployment is identified by its deployment path — the combination of model name, edition, and file name. What happens when you deploy again depends on how the new deployment compares with what is already on the device:
| New deployment vs. existing | Result |
|---|---|
| Any of model name, edition, or file name differs | Both deployments coexist on the device |
| Deployment path and file hash both match | The request is rejected |
| Deployment path matches but the file hash differs | The existing file is replaced |
A rejected deploy fails at the API call, not later in the device state: the request returns 409
with error code AiModelMgmt:ConflictingModelDeployment, and the response's extension.devices
lists the devices that already hold that file.
Recreating a model with the same name and edition but a different file name therefore produces a second, coexisting deployment. Recreating it with the same file name but different content replaces what is already on the device.
Managing Models and Editions
Beyond the upload and deploy flow, these operations let you inspect and maintain models and their editions.
| Operation | API | Description |
|---|---|---|
| List Editions of a Model | GET /api/v1/orgs/{orgId}/ai-models/{modelId}/editions | Returns a paginated list of editions for the specified model |
| Get Model Edition Detail | GET /api/v1/orgs/{orgId}/ai-models/{modelId}/editions/{edition} | Returns the full metadata for a single model edition |
| Update Edition Metadata | PATCH /api/v1/orgs/{orgId}/ai-models/{modelId}/editions/{edition} | Updates the editable metadata of an existing edition |
| Update Model Basic Info | PATCH /api/v1/orgs/{orgId}/ai-models/{modelId} | Updates the basic, model-level metadata. Editions are unaffected |
Constraints
- After an edition's file passes upload verification, its file content cannot be replaced.
Descriptive metadata can still be updated. Re-registering an edition that is still
Pendingreuses it, so an interrupted upload can be retried; re-registering an edition that already has a verified file returns409 EditionAlreadyExists. - An edition with
VerifyFailedstatus cannot be deployed - You can deploy only to devices that belong to an organization you are authorized to manage.
The deployment ACL fields
allowedContainersandallowedSubnetsseparately control access to the deployed file on the device. - A deployment reaches
DEPLOYEDonce the device is reachable and applies it; while offline, it remains queued indefinitely — see Device Offline Behavior
Teardown
| Step | Call | Result |
|---|---|---|
| Remove from device | DELETE /api/v1/devices/{deviceId}/ai-models/{modelId}/editions/{edition} | 202 — the removal is queued and applied once the device is reachable |
| Remove from all deployed devices | DELETE /api/v1/orgs/{orgId}/ai-models/{modelId}/editions/{edition}/deployments | 202 — requests removal from every device that received the edition |
| Delete a Single Edition | DELETE /api/v1/orgs/{orgId}/ai-models/{modelId}/editions/{edition} | Permanently deletes the specified model edition, leaving the model and its other editions in place |
| Delete the model | DELETE /api/v1/orgs/{orgId}/ai-models/{modelId} | Hard delete — permanently removes the model, all its editions, uploads, and stored files from WEDA Core |
Removing an edition from devices and deleting the cloud model are independent operations — neither requires the other, and there is no ordering constraint between them:
- You do not need to remove an edition from its devices before deleting the model from WEDA Core
- A device's online/offline status has no effect on whether the cloud model can be deleted
- Deleting the cloud model does not touch files already deployed to a device's Secured Volume — those remain in place until separately removed via Remove from device
- Because deletion is a hard delete, a
(modelName, edition)pair can be reused immediately after the original model is deleted — the name is not reserved by a soft-deleted record
Related
- Understand the tus protocol behind steps 3–4: Resumable Uploads with tus
- Mount the deployed file into your inference container: Make Your Container Read the Model
- Obtain a bearer token for these calls: Authentication
- Track the target device's status: Device Management