Model Registry
Register, manage, version, and deploy machine learning models. The model registry provides a centralized catalog for tracking models across your organization, regardless of their source or framework.
All endpoints require authentication via X-API-Key header and the appropriate scope.
RegisteredModel Object
{
"id": "model_abc123",
"name": "Churn Prediction XGBoost",
"description": "XGBoost model for customer churn prediction trained on Q4 2024 data",
"owner": "user_456",
"organizationId": "org_xyz",
"workspaceId": "ws_001",
"framework": "xgboost",
"source": "automl",
"latestVersion": 3,
"versions": [
{
"version": 1,
"description": "Initial training",
"metrics": { "accuracy": 0.89, "f1Score": 0.87 },
"artifactUri": "s3://models/churn-xgb/v1",
"createdAt": "2025-01-15T10:30:00Z"
},
{
"version": 2,
"description": "Retrained with feature engineering",
"metrics": { "accuracy": 0.92, "f1Score": 0.91 },
"artifactUri": "s3://models/churn-xgb/v2",
"createdAt": "2025-01-22T14:00:00Z"
},
{
"version": 3,
"description": "Hyperparameter tuning",
"metrics": { "accuracy": 0.94, "f1Score": 0.93 },
"artifactUri": "s3://models/churn-xgb/v3",
"createdAt": "2025-02-01T09:00:00Z"
}
],
"tags": ["production", "churn", "xgboost"],
"status": "deployed",
"deployment": {
"endpointUrl": "https://models.strongly.ai/v1/predict/model_abc123",
"replicas": 2,
"hardware": "gpu-a100-40gb",
"deployedAt": "2025-02-01T10:00:00Z"
},
"deleted": false,
"createdAt": "2025-01-15T10:30:00Z",
"updatedAt": "2025-02-01T10:00:00Z"
}
GET /api/v1/model-registry/models
List all registered models accessible to the authenticated user.
Scope: model-registry:read
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
search | string | No | Search by model name or description |
framework | string | No | Filter by framework: pytorch, tensorflow, xgboost, sklearn, onnx, custom |
source | string | No | Filter by source: automl, fine-tuning, experiment, manual |
status | string | No | Filter by status: registered, deployed, archived |
tag | string | No | Filter by tag |
workspaceId | string | No | Filter by workspace ID |
limit | integer | No | Number of results to return (default: 20) |
offset | integer | No | Number of results to skip (default: 0) |
sort | string | No | Sort field and direction, e.g. createdAt:desc |
Response 200 OK
{
"count": 34,
"limit": 20,
"offset": 0,
"models": [
{
"id": "model_abc123",
"name": "Churn Prediction XGBoost",
"description": "XGBoost model for customer churn prediction trained on Q4 2024 data",
"owner": "user_456",
"organizationId": "org_xyz",
"workspaceId": "ws_001",
"framework": "xgboost",
"source": "automl",
"latestVersion": 3,
"tags": ["production", "churn", "xgboost"],
"status": "deployed",
"deleted": false,
"createdAt": "2025-01-15T10:30:00Z",
"updatedAt": "2025-02-01T10:00:00Z"
}
]
}
POST /api/v1/model-registry/upload
Upload a model artifact bundle to S3 and parse its manifest. Routes through the same upload path the UI uses, so manifest extraction, validation, and S3 upload behave identically. The returned s3Key + manifest are what POST /model-registry/models (register) expects.
Scope: model-registry:write
Request (multipart/form-data)
| Field | Type | Required | Description |
|---|---|---|---|
file | file | Yes | Bundle binary — either a .zip containing strongly.manifest.yaml at root (or one level nested), or a single .pkl / .joblib / .pt / .onnx artifact. Streamed up to 500 MB. |
Response 201 Created
{
"s3Key": "model-artifacts/org_xyz/upload_abc123.zip",
"bucket": "strongly-models",
"sizeMb": 12.5,
"manifest": {
"name": "Churn Prediction XGBoost",
"framework": "xgboost",
"version": "1.0.0",
"entrypoint": "predict.py"
},
"manifestRaw": "name: Churn Prediction XGBoost\nframework: xgboost\n..."
}
The manifest / manifestRaw fields are only populated when the bundle is a .zip containing a valid strongly.manifest.yaml.
POST /api/v1/model-registry/models
Register a new model in the registry.
Scope: model-registry:write
Request Body
{
"name": "Churn Prediction XGBoost",
"framework": "xgboost",
"description": "XGBoost model for customer churn prediction trained on Q4 2024 data",
"source": "automl",
"tags": ["churn", "xgboost"],
"workspaceId": "ws_001",
"problemType": "classification",
"features": { "featureNames": ["tenure", "monthly_spend", "support_tickets", "plan_type"] }
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Human-readable model name |
framework | string | Yes | Model framework: pytorch, tensorflow, xgboost, sklearn, onnx, custom |
description | string | No | Model description |
source | string | No | Where the model originated: automl, fine-tuning, experiment, manual |
tags | string[] | No | Array of tag strings for categorization |
workspaceId | string | No | Workspace to register the model in |
problemType | string | No | classification or regression. Stored at training.problemType; required for drift monitoring |
features | object | Conditional | { "featureNames": [...] } — the training feature columns in input order. Required for tabular frameworks (sklearn, xgboost, lightgbm, strongly-automl) so predictions are labelled for drift analysis |
Response 201 Created
{
"id": "model_abc123",
"name": "Churn Prediction XGBoost",
"framework": "xgboost",
"status": "registered",
"latestVersion": 0,
"createdAt": "2025-01-15T10:30:00Z"
}
GET /api/v1/model-registry/models/:id
Get a single registered model by ID, including all versions.
Scope: model-registry:read
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Model ID |
Response 200 OK
Returns the full RegisteredModel object.
PUT /api/v1/model-registry/models/:id
Update a registered model's metadata.
Scope: model-registry:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Model ID |
Request Body
{
"name": "Churn Prediction XGBoost v2",
"description": "Updated model description with latest findings",
"tags": ["production", "churn", "xgboost", "v2"]
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Model name |
description | string | No | Model description |
tags | string[] | No | Array of tag strings |
Response 200 OK
Returns the updated RegisteredModel object.
DELETE /api/v1/model-registry/models/:id
Delete a registered model. Deployed models must be undeployed before deletion. This action is irreversible.
Scope: model-registry:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Model ID |
Response 204 No Content
POST /api/v1/model-registry/models/:id/deploy
Deploy a registered model for inference. Provisions the required infrastructure and creates a prediction endpoint.
Scope: model-registry:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Model ID |
Request Body
{
"version": 3,
"hardware": "gpu-a100-40gb",
"replicas": 2,
"autoscaling": {
"enabled": true,
"minReplicas": 1,
"maxReplicas": 5,
"targetCpuUtilization": 70
}
}
| Field | Type | Required | Description |
|---|---|---|---|
version | integer | No | Model version to deploy (default: latest) |
hardware | string | No | Hardware configuration ID |
replicas | integer | No | Number of replicas (default: 1) |
autoscaling | object | No | Autoscaling configuration |
Response 200 OK
{
"id": "model_abc123",
"status": "deployed",
"deployment": {
"endpointUrl": "https://models.strongly.ai/v1/predict/model_abc123",
"replicas": 2,
"hardware": "gpu-a100-40gb",
"deployedAt": "2025-02-01T10:00:00Z"
},
"message": "Model deployed successfully"
}
POST /api/v1/model-registry/models/:id/predict
Run inference on a deployed model (deployment status running). The request
is proxied to the model's pod through the AI Gateway, since model pods are
internal to the cluster. By default the prediction is logged for drift
detection.
Scope: model-registry:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Model ID |
Request Body
{
"input_data": [[3.1, 4.2], [8.0, 9.1]],
"entityId": "order-1042",
"logPrediction": true
}
input_data is the feature payload forwarded verbatim to the model's serving
endpoint. For the built-in tabular server pass the feature rows directly (a list
of rows as above), a single { "feature": value, ... } row object, or
{ "instances": [ ...rows ] }. Do not wrap the rows in { "features": ... }
— the built-in server does not recognize that shape.
| Field | Type | Required | Description |
|---|---|---|---|
input_data | array | object | Yes | Feature rows forwarded to the model's serving endpoint (rows array, single row object, or {"instances": rows}) |
entityId | string | No | Id used to match this prediction with a later ground-truth record for drift detection (defaults to a generated id) |
logPrediction | boolean | No | Log this prediction for drift detection (default true) |
Response 200 OK
{
"predictions": [1, 0],
"probabilities": [[0.18, 0.82], [0.74, 0.26]],
"latency_ms": 12,
"predictionId": "pZ8kQ2",
"entityId": "order-1042"
}
predictions holds one entry per input row. probabilities is present for
classifiers that expose predict_proba (one probability vector per row); it is
omitted for regressors. A single-row request also returns single-element arrays.
Keep predictionId / entityId to attach ground truth later via
POST /api/v1/drift/ground-truth for drift analysis. Returns 409 if the model
is not deployed.
Versions
A registered model accumulates immutable versions. Version 1 is created at registration; add a new version from a freshly uploaded artifact, then choose which one is served.
GET /api/v1/model-registry/models/:id/versions
List the model's version history and which one is active.
{
"versions": [
{ "version": 1, "description": "Initial version", "artifact": { "s3Key": "..." }, "createdAt": "..." },
{ "version": 2, "description": "retrained on more data", "artifact": { "s3Key": "..." }, "createdAt": "..." }
],
"activeVersion": 2
}
POST /api/v1/model-registry/models/:id/versions
Add a new version. Upload the artifact first via POST /model-registry/upload,
then pass its returned reference.
Body:
{
"artifact": { "s3Key": "uploads/model-v2.joblib", "s3Bucket": "...", "sizeMb": 4.2 },
"description": "retrained on more data"
}
Returns { "version": 2, "modelId": "..." }. artifact.s3Key is required.
POST /api/v1/model-registry/models/:id/versions/:version/activate
Point the model's served artifact/metrics at :version without deploying.
Returns { "success": true, "activeVersion": <n> }.
POST /api/v1/model-registry/models/:id/versions/:version/deploy
Set :version active and (re)deploy the serving pod with that version's
artifact. Rolling back is just deploying an earlier version again.