---
title: "Sync Training Job Status"
method: POST
path: "/v1/training/jobs/{job_id}/sync"
tags: ["training-jobs"]
---

# Sync Training Job Status

`POST /v1/training/jobs/{job_id}/sync`

## Request

- Base URL: `https://api.fastino.ai`
- URL: `https://api.fastino.ai/v1/training/jobs/{job_id}/sync`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Sync training job status from the provider to the database.

## Path parameters

- `job_id` string, required

## Response `200`

Successful Response

- TrainingJobResponse: Training job response model
  - `artifact_ready` boolean, nullable: Whether an artifact location is recorded, so there is something to serve.
  - `base_model` string, required: The catalog base model the adapter was trained on (for an `interactive_checkpoint` model, the base of the interactive job it came from).
  - `batch_size` integer, nullable, required: Training batch size. Null for an `interactive_checkpoint` model.
  - `completed_at` string, nullable
  - `created_at` string, required
  - `current_epoch` integer, nullable: Epoch currently in progress (1-indexed). Updated live during training.
  - `datasets` DatasetReference[], required
    - `name` string, required: Dataset name
    - `version` string, nullable: Version (latest if omitted)
  - `deployability_reason` string, nullable: Why the job is not deployable (e.g. 'job_incomplete', 'missing_artifact', 'provider_incompatible', 'adapter_inference_unavailable'). Null when deployable.
  - `deployment_status` string, nullable, required: Deprecated. Always returns None -- deployment_status no longer exists. Kept for backward compat with clients that read this field.
  - `error_message` string, nullable
  - `example` string, nullable: Sample text to pre-load into inference input
  - `experiment_id` string, nullable: Experiment associated with this training job, when available. Null means no associated experiment was recorded.
  - `hub_model_id` string, nullable: HuggingFace repo id (e.g. 'username/model-name') set only after a successful push_training_job_to_hub call. This is the sole source of truth for whether a checkpoint has been pushed to the Hub -- it does not mean the repo is reachable by anyone other than the pusher: see hub_model_private for that. trained_model_path is an internal storage key and must never be parsed to infer a Hub repo id.
  - `hub_model_private` boolean, nullable: Whether the pushed Hub repository is private, as recorded at push time. Null means the job was not pushed or its repository visibility was not recorded.
  - `id` string, required
  - `instance_type` string, nullable
  - `is_deployable` boolean, nullable: Whether this job passes server-side deployability validation for its own project. Authoritative -- the same check the deployment endpoints enforce.
  - `is_terminal_status` boolean, nullable: Whether this status is terminal for polling loops
  - `job_reference` string, nullable
  - `labels` string[], nullable: Merged labels from training datasets (entity types for NER, class labels for classification)
  - `learning_rate` number, nullable, required: Learning rate. Null for an `interactive_checkpoint` model.
  - `metrics` object, nullable: Training and evaluation metrics dictionary. Contains final_training_loss, final_validation_loss, best_validation_loss from training logs, and optional evaluation metrics (f1_score, precision_score, recall_score, accuracy) if an evaluation has been run.
  - `model_auto_selected` boolean, nullable
  - `model_kind` 'lora' | 'full', nullable: Normalized fine-tune kind: 'lora' for adapters (lora/qlora) or 'full' for merged weights. Null when the persisted training type is unrecognised -- clients must not claim a kind in that case.
  - `model_name` string, nullable
  - `model_selection_reason` string, nullable
  - `normalized_status` string, nullable: Canonical status alias for compatibility handling (requested, running, complete, deployed, failed, cancelled)
  - `notices` TrainingNotice[]: Advisories to show alongside this job, such as the dedicated-endpoint serving terms for full fine-tunes.
    - `code` string, required: Stable machine-readable notice code.
    - `message` string, required: Customer-facing notice text.
  - `nr_epochs` integer, nullable, required: Training epochs. Null for an `interactive_checkpoint` model.
  - `progress_percent` integer, nullable: Overall training completion percentage (0-100). Updated live during training.
  - `project_id` string, nullable: Project ID this training job is associated with
  - `provider_deployments` object, nullable: Provider-specific deployment metadata written by the training monitor, keyed by provider: {"modal": {...}}.
  - `provider_name` string, nullable: Training provider that handled this job (e.g. 'modal'). Jobs predating a provider removal carry an 'archived_<provider>' label.
  - `provider_ready` boolean, nullable: Whether a provider is already serving this artifact. False is not a deployment blocker: promotion provisions or re-warms a provider.
  - `resolved_recipe` object, nullable: Immutable snapshot of what this job actually trained with, taken at dispatch: LoRA rank/alpha/dropout, learning rate, warmup ratio, gradient accumulation, packing, precision, attention backend, reasoning parser, container image, runtime profile, max sequence length, and seed, for every seed-capable provider/model. Null for jobs dispatched before the snapshot existed, and for providers that resolve no catalog recipe -- except Modal encoder and Modal RL strategies, which have no dense-LoRA catalog recipe but still return a non-null (seed) snapshot, since seed has no other persisted column. Read this rather than re-deriving from the catalog: the catalog reports what a job dispatched *today* would get, which is a different question.
  - `root_job_id` string, nullable: ID of the original/root training job this version derives from
  - `seed` integer, nullable: Effective reproducibility seed for Modal decoder or GLiNER2 (encoder) training. Null for Fireworks, unknown, and other providers/architectures that cannot honor this contract, and also null for a legacy Modal decoder/encoder job created before seed provenance was recorded, because its seed is unknown, and for an `interactive_checkpoint` model, which this job did not train. A non-null value is always a genuinely recorded seed. Decoder contract: A pinned seed governs LoRA initialisation and the trainer's own RNG (dataloader shuffle order and dropout). It does not select the train/validation split: that partition uses a dedicated split seed so two runs that differ only in `seed` are scored on the same held-out rows. It does not make runs bit-identical: GPU reduction order stays non-deterministic, so metrics can differ between otherwise identical runs. Across six observed same-config decoder pairs, final validation loss agreed to within 6.8% relative and two pairs agreed exactly. Treat that as an observed envelope from production history, not a guaranteed bound. Encoder contract: A pinned seed governs dataset shuffle and auto-sizing downsample order, and the trainer's own weight-initialisation and dropout RNG. It does not select the train/validation split on a Brain-dispatched run: that partition is a fixed left-to-right split derived from validation_data_percentage (validation is the tail), independent of seed, so two runs that differ only in `seed` are scored on the same held-out rows. Runs are seeded but not bit-identical: GPU reduction order stays non-deterministic (cuBLAS GEMM split-k, and the embedding-backward scatter_add/index_add path, which is not forced deterministic), so metrics can still differ between identically-configured runs. Before encoder seed control existed, three identically-configured launches measured classification macro-F1 ranging 0.38–0.63 — treat pinning a seed as removing one real, measured source of that noise, not as a guaranteed bound on the rest. Every GLiNER2 job unconditionally pins cuDNN's own algorithm selection (the same flags GLiNER2's bundled Trainer sets) -- this is a fixed container default, not a per-request knob. The cuDNN pin currently costs nothing and changes nothing on this backbone: cuDNN governs convolution/pooling/RNN kernels, and this encoder's DeBERTa-v2 backbone has none, so pinning it has nothing to pin there; the throughput trade-off only materializes if a future backbone adds conv/pooling/RNN layers. torch deterministic algorithms are not enabled: they would roughly halve training throughput without making runs bit-identical.
  - `source` 'config_training' | 'interactive_checkpoint': How the model came to exist: `config_training` for a job Fastino trained from data and a config, `interactive_checkpoint` for a sampler checkpoint of an interactive job served as a model (`POST /v1/training/jobs/{job_id}/checkpoints/sampler_weights/{name}/deploy`). An `interactive_checkpoint` model ran no training of its own, so it lists no datasets and its training settings are null.
  - `started_at` string, nullable
  - `status` string, required
  - `task_type` string, nullable: Task type derived from training datasets: 'ner', 'classification', 'custom', or 'decoder'
  - `trained_model_path` string, nullable
  - `training_type` string, nullable: Raw training method as persisted: 'lora', 'qlora', or 'full'.
  - `type` 'config': A config training job (you give data and a config, Fastino runs the loop). ``/v1/trained-models`` also lists interactive jobs (``type: interactive``).
  - `updated_at` string, required
  - `user_id` string, required
  - `validation_data_percentage` number, nullable, required: Share of the data held out for validation (0-1). Null for an `interactive_checkpoint` model.
  - `version_number` string, nullable: Version number for this training job (e.g., '1', '2', '3')

## Other responses

- `422`: Validation Error

## Changes

- **2026-10-15** `5efbc8b70225`: 4 breaking, 1 info
  - response property `batch_size` list-of-types was widened by adding types `null` to media type `application/json` of response `200`
  - response property `learning_rate` list-of-types was widened by adding types `null` to media type `application/json` of response `200`
  - response property `nr_epochs` list-of-types was widened by adding types `null` to media type `application/json` of response `200`
  - response property `validation_data_percentage` list-of-types was widened by adding types `null` to media type `application/json` of response `200`
  - …1 more
- **2026-10-13** `5ebfd9fe8f46`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/fastino-ai/apis/pioneer-inference-api/changes/v1/training/jobs/:job_id/sync/post.md)

---

[API](https://skmtc.dev/fastino-ai/apis/pioneer-inference-api.md) - [All operations](https://skmtc.dev/fastino-ai/apis/pioneer-inference-api/llms.txt) - [OpenAPI document](https://skmtc.dev/fastino-ai/apis/pioneer-inference-api/revisions/81465e18c1d2?raw)
