Skip to main content

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

ParameterTypeRequiredDescription
searchstringNoSearch by model name or description
frameworkstringNoFilter by framework: pytorch, tensorflow, xgboost, sklearn, onnx, custom
sourcestringNoFilter by source: automl, fine-tuning, experiment, manual
statusstringNoFilter by status: registered, deployed, archived
tagstringNoFilter by tag
workspaceIdstringNoFilter by workspace ID
limitintegerNoNumber of results to return (default: 20)
offsetintegerNoNumber of results to skip (default: 0)
sortstringNoSort 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)

FieldTypeRequiredDescription
filefileYesBundle 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"] }
}
FieldTypeRequiredDescription
namestringYesHuman-readable model name
frameworkstringYesModel framework: pytorch, tensorflow, xgboost, sklearn, onnx, custom
descriptionstringNoModel description
sourcestringNoWhere the model originated: automl, fine-tuning, experiment, manual
tagsstring[]NoArray of tag strings for categorization
workspaceIdstringNoWorkspace to register the model in
problemTypestringNoclassification or regression. Stored at training.problemType; required for drift monitoring
featuresobjectConditional{ "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

ParameterTypeRequiredDescription
idstringYesModel 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

ParameterTypeRequiredDescription
idstringYesModel ID

Request Body

{
"name": "Churn Prediction XGBoost v2",
"description": "Updated model description with latest findings",
"tags": ["production", "churn", "xgboost", "v2"]
}
FieldTypeRequiredDescription
namestringNoModel name
descriptionstringNoModel description
tagsstring[]NoArray 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

ParameterTypeRequiredDescription
idstringYesModel 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

ParameterTypeRequiredDescription
idstringYesModel ID

Request Body

{
"version": 3,
"hardware": "gpu-a100-40gb",
"replicas": 2,
"autoscaling": {
"enabled": true,
"minReplicas": 1,
"maxReplicas": 5,
"targetCpuUtilization": 70
}
}
FieldTypeRequiredDescription
versionintegerNoModel version to deploy (default: latest)
hardwarestringNoHardware configuration ID
replicasintegerNoNumber of replicas (default: 1)
autoscalingobjectNoAutoscaling 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

ParameterTypeRequiredDescription
idstringYesModel 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.

FieldTypeRequiredDescription
input_dataarray | objectYesFeature rows forwarded to the model's serving endpoint (rows array, single row object, or {"instances": rows})
entityIdstringNoId used to match this prediction with a later ground-truth record for drift detection (defaults to a generated id)
logPredictionbooleanNoLog 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.