The routes follow OpenAI's Files and Fine-tuning APIs where a shape exists, so an OpenAI SDK can upload files and create, list, retrieve and cancel jobs unchanged; endpoints, hardware and the estimate are the platform's own. Every route takes your API key (Authorization: Bearer $YELNO_API_KEY) and answers in the gateway's error envelope. Every route except the overview checks the allow_fine_tuning policy. Amounts are integer nanos as JSON numbers (1 USD = 1,000,000,000), and every price is a final price.
MethodPathWhat it does
GET/v1/fine_tuningOverview: enabled, available, where the data goes, retention, settings in force.
GET/v1/fine_tuning/base_modelsSupported base models, their methods and final training prices.
GET/v1/fine_tuning/hardware?model=Hardware a model can be served on, with the final price per replica-hour.
POST/v1/filesUpload a dataset (multipart: file, purpose=fine-tune, optional format). Validated on upload.
POST/v1/fine_tuning/endpoints/{endpoint_id}/startStart a stopped endpoint.
POST/v1/fine_tuning/endpoints/{endpoint_id}/stopStop it: bills up to now and releases the hold.
DELETE/v1/fine_tuning/endpoints/{endpoint_id}Stop if needed and delete.
In the console, the same operations live under /api/v1/fine-tuning/… with a session token, and lists use the console's cursor page. The examples below show the objects as the API returns them; ids and amounts are illustrative.
GET /v1/fine_tuning · 200
{"object": "fine_tuning.overview", "enabled": true, "available": true, "unavailable_reason": null,
"provider": {"name": "Together AI",
"data_destination": "Your training and validation files are uploaded to Together AI to run the job.",
"retention": "Datasets are deleted from Together AI after the job finishes unless you choose to keep them. The platform keeps its own copy under your file retention.",
"terms_url": "https://www.together.ai/terms-of-service"},
"settings": {"hold_buffer_bps": 2000, "min_prepaid_hours": 1, "billing_interval_seconds": 300,
"default_auto_stop_idle_minutes": 15, "approval_threshold_nanos": 0},
"counts": {"datasets": 0, "jobs_running": 0, "models": 0, "endpoints_running": 0},
"running_cost_per_hour_nanos": 0, "currency": "USD"}
available is false, with unavailable_reasonkill_switch, provider_unavailable or zdr_required, when nothing can be started.
POST /v1/files, multipart, with file, purpose=fine-tune and optionally format (chat, completion or preference; detected from the first valid line otherwise). Up to 100 MB and 200,000 lines. The response is OpenAI's file object with a yelno.fine_tuning block holding the validation report. An invalid file is stored with status: "error" so its report can be read again. GET /v1/files?purpose=fine-tune lists them, GET /v1/files/{file_id} returns one, and DELETE removes it here and at the provider.
POST /v1/fine_tuning/jobs and POST /v1/fine_tuning/estimate take the same body. model is a base model's slug, its provider model id or its ftb_… id. method.type is supervised (default) or dpo, method.training_typelora (default) or full; OpenAI's method object with nested hyperparameters is accepted too. suffix matches ^[a-z0-9-]{1,40}$. n_evals above 0 needs a validation_file.
Request body (every field but model and training_file is optional)
Create accepts an Idempotency-Key header and answers 200 with the job. The hold is placed first, then the files go to the provider and the job is created there; a provider refusal fails the job with error.code: "provider_rejected" and releases the hold.
status is OpenAI's word (validating_files, queued, running, succeeded, failed, cancelled); yelno.settlement is pending, charged, released or reconciliation (the provider's final figures are missing and the job is under review, never free). GET /v1/fine_tuning/jobs takes limit, after and status and returns {object: "list", data, has_more}.
POST /v1/fine_tuning/estimate computes what the job would cost without starting it or holding anything: billable tokens = training tokens × epochs + validation tokens × evaluations, at the final price per 1M tokens, never below the minimum charge. hold_nanos is what create would hold (the estimate plus hold_buffer_bps). It is labelled an estimate: the charge is the tokens the provider reports as trained.
POST /v1/fine_tuning/estimate · 200
{"object": "fine_tuning.estimate", "label": "estimate", "model": "…",
"method": {"type": "supervised", "training_type": "lora"},
"training_tokens_per_epoch": 53000, "validation_tokens": 0, "n_epochs": 3, "n_evals": 0,
"billable_tokens": 159000, "price_per_million_tokens_nanos": 480000000, "minimum_charge_nanos": 4000000000,
"estimate_nanos": 4000000000, "hold_nanos": 4800000000, "hold_buffer_bps": 2000,
"available_nanos": 25000000000, "sufficient_funds": true, "currency": "USD",
"hosting_note": "Training is a one-off charge. Hosting the result on a dedicated endpoint is billed per hour while it runs and is usually the larger cost.",
"data_destination": "Together AI"}
A succeeded job creates a model. GET /v1/models lists it as {id: "ft:…", object: "model", created, owned_by: "<org_id>"}, for your organization only. GET /v1/fine_tuning/models and GET /v1/fine_tuning/models/{model_id} (ftm_… or ft:…) return the full object. PATCH with {"name": "…"} renames it (409 name_taken); DELETE archives it, refused with 409 endpoint_running while its endpoint is starting or running.
POST /v1/fine_tuning/endpoints creates the endpoint and, unless start is false, starts it. One live endpoint per model (409 endpoint_exists). Starting needs at least one hour of the endpoint's price available (402 insufficient_funds). budget is in nanos.
price_per_hour_nanos is the final price per hour for the whole endpoint (the hardware's price × max_replicas), fixed when it starts. run_cost_nanos is this run so far, billed plus accrued; total_cost_nanos covers the endpoint's life. stop_reason is user, idle, max_hours, budget, wallet_empty, staff, provider or failed.
PATCH /v1/fine_tuning/endpoints/{endpoint_id} with any of auto_stop_idle_minutes, max_hours and budget changes auto-stop. POST …/start starts it (409 endpoint_running when it already runs); POST …/stop bills up to now and releases the hold; DELETE stops it if needed and leaves it deleted. GET /v1/fine_tuning/endpoints?state= lists them.
GET /v1/fine_tuning/hardware?model= takes an ft:… id, an ftm_… id or a base model and lists the hardware it can run on, each with its final price per replica-hour. Hardware without a published price is not listed. GET /v1/fine_tuning/base_models lists the supported base models: each method carries its final price per 1M training tokens and the minimum charge, and available: false when no price is published for it yet.
Errors use the standard envelope, {"error": {"type", "code", "message", "param"}}. The codes specific to fine-tuning:
HTTPCodeMeaning
400invalid_training_file · invalid_validation_file · invalid_file_formatThe file failed validation, or is not a fine-tune file in a usable format.
400file_too_largeOver 100 MB.
400method_not_supported · format_method_mismatchThe base model does not offer the method, or the file format does not fit it (DPO needs preference; SFT chat or completion).
400invalid_hyperparametersA value is out of range or does not apply to the method.
400approval_requiredAn approval policy covers the job or endpoint; approval_request_id names the request. Re-send with X-Yelno-Approval.
402insufficient_fundsThe job's hold, or one hour of the endpoint's price, cannot be placed.
403fine_tuning_disabledallow_fine_tuning is off for your organization.
403zdr_requiredYour organization requires zero data retention, which the training provider's terms do not meet.
404not_found · model_not_foundUnknown id, or another organization's: never a hint that it exists.
409model_not_deployedInference on an ft: model with no running endpoint.
409endpoint_exists · endpoint_runningThe model already has a live endpoint; the endpoint is already running; or archiving a model whose endpoint runs.
409job_not_cancellable · file_in_use · name_takenCancelling a finished job; deleting a file an open job uses; renaming to a name already in use.
409idempotency_key_reusedThe Idempotency-Key was used with a different body.
409price_unavailableNo final price is published for that model, method or hardware yet.
503fine_tuning_unavailable · provider_unavailableFine-tuning is paused platform-wide, or the training provider is not available.
Where the data goes. Training and validation files are sent to Together AI, and training runs on Together AI's infrastructure. They are deleted there after the job unless you set keep_provider_files. No accuracy, quality, availability or SLA is promised for fine-tuned models or their endpoints.