- Inline training data. Pass
training_datain the body. No Files API, notraining_file. - Fully managed. No hyperparameters. Train from scratch, or warm-start from any custom or default reflex.
Quick Start
Four steps: get a key, create a job, wait for it, classify text.training_data is a Morph extension. The OpenAI Python SDK rejects unknown arguments, so pass it through extra_body=.1
Get an API key
Grab one from the dashboard.
2
Create a training job
Send labeled examples. No data? Use
generate or label_data instead.3
Wait for training
Poll until
status is succeeded. A small Reflex takes about 30 seconds.4
Classify text
Predict against
fine_tuned_model (your suffix, or the job id if you gave none).Create a Job
training_data, generate, or label_data (see Input modes).
Input modes
Pick one. The training set, however it is produced, must have 2+ labels and 5+ examples per label, else the job fails.generate and label_data synthesize or label data through the OpenAI Batch API, so the job spends a few minutes on data before training. status reads validating_files during this phase, then moves to running. Poll as usual.training_data: labeled rows you supply.
2.
generate: no data; synthesize it from a description.
3.
label_data: your unlabeled text, sorted into your classes.
Continual training
Setmodel to an existing classifier’s name to start a job from its weights instead of from scratch. The new model inherits what the checkpoint already learned, so it converges on fewer examples. Use it to grow a Reflex as you collect data, retrain a drifting classifier on fresh labels, or specialize one of Morph’s default Reflexes to your domain. Omit model for a cold start.
For a warm start, model accepts two kinds of name, resolved owned-first:
- A model you trained. Its
suffix(thefine_tuned_modelname) or job id. The latestsucceededversion is pinned when the job is created, so retraining the source afterward never moves an in-flight job. - A default Reflex.
guardrail,jailbreak,difficulty,domain,ambiguity,stuck-in-a-loop,leaked-thinking,incomplete-thought,user-frustrated,user-joy, orhealth-emergency. Starts from Morph’s pre-trained classifier for that task (see the overview). An owned model of the same name shadows the default.
model reflects what it trained from — the warm-start reflex, or the from-scratch base when you omit model. Everything else (poll, predict, manage) is unchanged.
The starting checkpoint must be on the current training stack. A model trained before the aLoRA migration returns
model_incompatible; retrain it once from scratch and it becomes a valid base. A model that has not finished training yet returns model_not_ready.Retrieve a Job
status is succeeded, failed, or cancelled.
List Jobs
Cancel a Job
status becomes cancelled.
Training Events
running, succeeded, failed) interleaved with the loss curve, oldest first. type is metrics for a loss point and message for a lifecycle line. Add ?stream=true for a live Server-Sent Events stream.
Webhooks
Passwebhook_url when you create a job to get a signed POST the moment it finishes, instead of polling. Morph delivers a webhook for each terminal state:
The body is a thin event envelope — it carries only the job id, mirroring OpenAI. Fetch the job to read the result:
Verifying signatures
Deliveries are signed with the Standard Webhooks scheme — the same one OpenAI and Stripe use — so off-the-shelf verifiers work. Three headers travel with each request:2xx quickly and do work asynchronously; failed deliveries are retried with backoff, and duplicates are possible, so make your handler idempotent on webhook-id.
Predict
POST. The model must be ready, else 409 (model_not_ready).
single_label vs multi_label scoring decides the winning class. One billing note specific to this endpoint: prefill_tokens is the tokenized input length, charged once per request regardless of how many models run.
The SDK flattens this for you: predict returns the winning label/confidence and selected class alongside the full classes array (allScores), plus mode, completionId, and inferenceTimeMs. Pass completionId to tag the call (sent as the X-Completion-Id header) so the prediction is correlatable in your logs.
Classify against multiple models
Run several classifiers over the sametext in one request — morph.reflex.predictMany({ models, text }) in the SDK, or a models array on the raw endpoint. They share a single prefill, so the input is tokenized once: cheaper and faster than a call per model. You get back { predictions, inferenceTimeMs, prefillTokens }, one entry per model. An entry that fails at inference carries an error instead of a classification; an unknown model name still fails the whole request with model_not_found.
Delete a Job
Delete a Model
fine_tuned_model value or job id). Same effect as deleting the job; OpenAI Models-API parity.
Reference
Job object
Job object
Event object
Event object
Errors
Errors
OpenAI-shaped:
{ "error": { "message", "type", "param", "code" } }.Reflexes overview
What a Reflex is, the default classifiers, and realtime
/predict.Batch classification
Classify up to 300 rows inline, or 10,000 offline. Sync and async batch APIs.