API reference

Model uploads

Create an upload reservation, transfer the bundle to the presigned URL, complete validation, and inspect upload status.

Resource shape

FieldTypeDescription
idstringUpload reservation ID.
statusstringOne of pending_upload, uploaded, validating, validated, failed, expired.
filenamestringOriginal .tar.gz filename sent during reservation.
namestringBase model name derived from filename.
model_keystringVersioned object storage key.
modalitystringDeclared model modality.
taskstringDeclared task for the modality.
versionnumberReserved model version.
size_bytesnumberClient-provided expected size, or 0 if omitted.
actual_size_bytesnumber | nullSize measured from object storage after upload.
s3_etagstring | nullObject storage ETag captured during completion.
errorstring | nullValidation or completion error for failed uploads.
expires_attimestampWhen the presigned upload URL expires.
uploaded_attimestamp | nullSet when completion confirms the object exists.
completed_attimestamp | nullSet when completion finishes with validated or failed.
model_idstring | nullCreated model ID after validation succeeds.

Status lifecycle

StatusMeaning
pending_uploadThe upload reservation exists and the presigned upload_url is active until expires_at.
uploadedReserved for an uploaded object before validation. The current public completion flow usually moves directly to validating.
validatingThe object exists in storage and FlashML is checking bundle contents, preprocessing config, labels, tokenizer files, and model shape.
validatedValidation succeeded and a model record was created. The upload response includes model_id and model.
failedValidation or size checks failed. Inspect upload.error, fix the bundle, and create a new upload reservation.
expiredThe presigned upload URL expired before completion could find the object. Create a new upload reservation.
POST/v1/models/uploads

Create a model upload

Reserves the next model version, creates an upload record, and returns a short-lived presigned S3 PUT URL. size_bytes is optional but recommended for early size checks.

Request

curl https://api.flashml.dev/v1/models/uploads \
  -H "Authorization: Bearer $FLASHML_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filename": "sentiment-classifier.tar.gz",
    "modality": "text",
    "task": "classification",
    "size_bytes": 44040192
  }'

Response

{
  "upload_id": "upl_ZdvJxLqgP6QeVnkn8SLcWg",
  "status": "pending_upload",
  "model_key": "user-id/sentiment-classifier-v1.tar.gz",
  "version": 1,
  "upload_url": "https://...",
  "expires_in": 300,
  "expires_at": "2026-05-21T16:48:03.120000+00:00",
  "method": "PUT"
}
PUTpresigned upload_url

Upload the bundle

Upload the tarball directly to object storage. This request does not use your FlashML API key.

Request

curl -X PUT "$UPLOAD_URL" \
  --upload-file ./sentiment-classifier.tar.gz

Response

HTTP/1.1 200 OK
POST/v1/models/uploads/{upload_id}/complete

Complete and validate upload

Checks that the object exists, validates the bundle, creates the model record, and marks the upload as validated.

Request

curl -X POST https://api.flashml.dev/v1/models/uploads/upl_ZdvJxLqgP6QeVnkn8SLcWg/complete \
  -H "Authorization: Bearer $FLASHML_API_KEY"

Response

{
  "status": "validated",
  "upload": {
    "id": "upl_ZdvJxLqgP6QeVnkn8SLcWg",
    "status": "validated",
    "filename": "sentiment-classifier.tar.gz",
    "name": "sentiment-classifier",
    "model_key": "user-id/sentiment-classifier-v1.tar.gz",
    "modality": "text",
    "task": "classification",
    "version": 1,
    "size_bytes": 44040192,
    "actual_size_bytes": 44040192,
    "s3_etag": "\"7d793037a0760186574b0282f2f435e7\"",
    "error": null,
    "expires_at": "2026-05-21T16:48:03.120000+00:00",
    "uploaded_at": "2026-05-21T16:45:26.900000+00:00",
    "completed_at": "2026-05-21T16:45:31.700000+00:00",
    "model_id": "6f2c8d9a-2e8d-4ed3-b9f2-9f3d2d2d7e8f"
  },
  "model": {
    "id": "6f2c8d9a-2e8d-4ed3-b9f2-9f3d2d2d7e8f",
    "name": "sentiment-classifier",
    "modality": "text",
    "task": "classification",
    "size_mb": 42,
    "s3_key": "user-id/sentiment-classifier-v1.tar.gz",
    "version": 1,
    "status": "validated",
    "user_id": "user-id"
  }
}
GET/v1/models/uploads/{upload_id}

Inspect upload status

Returns the current upload record, including status, object size, validation error, timestamps, and linked model ID.

Request

curl https://api.flashml.dev/v1/models/uploads/upl_ZdvJxLqgP6QeVnkn8SLcWg \
  -H "Authorization: Bearer $FLASHML_API_KEY"

Response

{
  "upload": {
    "id": "upl_ZdvJxLqgP6QeVnkn8SLcWg",
    "status": "validating",
    "filename": "sentiment-classifier.tar.gz",
    "name": "sentiment-classifier",
    "model_key": "user-id/sentiment-classifier-v1.tar.gz",
    "modality": "text",
    "task": "classification",
    "version": 1,
    "size_bytes": 44040192,
    "actual_size_bytes": 44040192,
    "error": null,
    "expires_at": "2026-05-21T16:48:03.120000+00:00",
    "uploaded_at": "2026-05-21T16:45:26.900000+00:00",
    "completed_at": null,
    "model_id": null
  }
}

Upload URL behavior

The presigned S3 URL expires after 300 seconds. Do not include your FlashML API key in the PUT request to object storage.