> ## Agent Instructions > Use https://docs.fastino.ai/llms.txt to discover and navigate pages. Use https://docs.fastino.ai/llms-full.txt when you need the complete documentation corpus. Use https://docs.fastino.ai/openapi.json as the source of truth for customer-facing routes. For GLiDE decision inference, call POST https://api.fastino.ai/v1/systemone with model fastino/GLiDE. Create managed config jobs with POST /v1/training/jobs using base_model. For custom training loops, native JSON clients use the public operations under /v1/training/jobs and /v1/training/usage. Existing Tinker clients use tinker==0.32.0 with TINKER_BASE_URL=https://api.fastino.ai/v1/training/compat/tinker and TINKER_CREDENTIAL_CMD. Compatibility child routes are private and absent from OpenAPI. Auto Train is private access and has no public route; direct interested users to sales@fastino.ai. Do not infer undocumented routes. Read API keys from FASTINO_API_KEY and never embed credentials in code, logs, or reports. # Delete a dataset Source: https://docs.fastino.ai/api-reference/datasets/delete DELETE /v1/datasets/{name} Soft-delete a dataset and all of its stored versions by name with DELETE /v1/datasets/{name}. `DELETE /v1/datasets/{name}` Soft-delete a dataset and all of its stored versions by name. This route does not delete one selected version. ## Authorization Requires the Owner, Admin, or Editor team role. Other roles receive `403 Forbidden`. # List datasets Source: https://docs.fastino.ai/api-reference/datasets/list GET /v1/datasets List datasets available to the authenticated Fastino account with GET /v1/datasets, and paginate results with the limit and offset query parameters. `GET /v1/datasets` List datasets available to the authenticated Fastino account. ## Result behavior By default, the response contains the latest version of each dataset name and excludes failed uploads. Set `include_all_versions=true` to return every version or `include_failed=true` to include your failed uploads. Results are newest first. `limit` defaults to 200 and cannot exceed 200; use `offset` to request subsequent pages. # Process an uploaded dataset Source: https://docs.fastino.ai/api-reference/datasets/process-upload POST /v1/datasets/upload/process Queue asynchronous processing after a dataset file upload completes by calling POST /v1/datasets/upload/process with its dataset_id. `POST /v1/datasets/upload/process` Queue processing after a dataset file upload completes. ## Asynchronous processing A successful request returns `202` and queues processing; it does not mean the dataset is ready. Poll [`GET /v1/datasets/{name}`](/api-reference/datasets/versions), select the exact `version_number` returned when the upload URL was created, and continue until its `status` is `ready` or `failed`. For a failure, read `processing_error` before correcting the file and uploading a new version. A `503` means storage verification or queueing failed before processing began and the same upload can be retried. ## Authorization Requires the Owner, Admin, or Editor team role. Other roles receive `403 Forbidden`. # Create a dataset upload URL Source: https://docs.fastino.ai/api-reference/datasets/upload-url POST /v1/datasets/upload/url Create a presigned upload URL with POST /v1/datasets/upload/url, upload the file as application/octet-stream, then process it with the returned dataset_id. `POST /v1/datasets/upload/url` Create a presigned upload URL for a new dataset file. ## Bind the URL to the file Optionally send `content_length` (the exact byte count, up to 5 GiB) and `sha256` (a 64-character hexadecimal digest). Storage then rejects a PUT whose size or digest differs, which catches truncated and corrupted uploads before processing. ```bash theme={null} CONTENT_LENGTH="$(wc -c < training.jsonl | tr -d ' ')" SHA256="$(shasum -a 256 training.jsonl | awk '{print $1}')" curl --fail-with-body -sS https://api.fastino.ai/v1/datasets/upload/url \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d "$(jq -n \ --argjson content_length "$CONTENT_LENGTH" \ --arg sha256 "$SHA256" \ '{ dataset_name: "docs-example-ner", filename: "training.jsonl", dataset_type: "ner", content_length: $content_length, sha256: $sha256 }')" > dataset-upload.json ``` ## Upload the file Upload the exact file bytes to `presigned_url` before it expires. Copy every entry in the response's `upload_headers` object exactly. The object always contains `Content-Type: application/octet-stream`; when you declared `content_length` and `sha256`, it also contains the signed `Content-Length` and `x-amz-checksum-sha256` values. A missing or changed signed header returns `403`. ```bash theme={null} PRESIGNED_URL="$(jq -r '.presigned_url' dataset-upload.json)" curl --fail-with-body -X PUT \ -H "Content-Type: $(jq -r '.upload_headers["Content-Type"]' dataset-upload.json)" \ -H "Content-Length: $(jq -r '.upload_headers["Content-Length"]' dataset-upload.json)" \ -H "x-amz-checksum-sha256: $(jq -r '.upload_headers["x-amz-checksum-sha256"]' dataset-upload.json)" \ --upload-file training.jsonl "$PRESIGNED_URL" ``` Most HTTP clients calculate `Content-Length` from the body, but it must still match the signed value. After the upload succeeds, pass the returned `dataset_id` to [`POST /v1/datasets/upload/process`](/api-reference/datasets/process-upload). ## Authorization Requires the Owner, Admin, or Editor team role. Other roles receive `403 Forbidden`. # List dataset versions Source: https://docs.fastino.ai/api-reference/datasets/versions GET /v1/datasets/{name} List all visible versions, processing states, and metadata for one dataset with GET /v1/datasets/{name}. `GET /v1/datasets/{name}` List all visible versions and metadata for one dataset. ## Processing status The response contains `success`, `versions`, and `count`. Match `version_number` exactly when polling a recent upload. A version is usable for training only when its `status` is `ready`; `failed` versions include `processing_error`. # Chat Completions Source: https://docs.fastino.ai/api-reference/inference/chat-completions POST /v1/chat/completions Run GLiNER extraction, classification, structured tasks, and supported decoder inference. `POST /v1/chat/completions` Run GLiNER extraction, classification, structured tasks, and supported decoder inference. > **[Follow the happy-path guide](/inference/chat-completions)** > > Run extraction, classification, record, and relation examples with GLiNER. # Native GLiNER-2 inference Source: https://docs.fastino.ai/api-reference/inference/gliner-2 POST /v1/gliner-2 Run synchronous native GLiNER-2 extraction and classification with the unified GLiNER schema, with entity extraction and classification examples. `POST /v1/gliner-2` Run synchronous native GLiNER-2 extraction and classification. The OpenAPI panel on this page is the source of truth for every request field and response field. Use `POST /v1/chat/completions` when you need a named hosted model, a fine-tuned model, inference persistence, or the OpenAI-compatible envelope. This native endpoint selects the Fastino GLiNER-2 base model for you. ## Request schema The request requires: * `text`: one string or an array of strings. * `schema`: the unified GLiNER schema dictionary. The legacy flat label array is deprecated. It also accepts `threshold`, `include_confidence`, `include_spans`, and `format_results`. Omit `task`; it is a deprecated legacy hint and the schema identifies the operation. ## Entity extraction example ```bash theme={null} curl -X POST "https://api.fastino.ai/v1/gliner-2" \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "text": "Apple CEO Tim Cook introduced the iPhone in Cupertino.", "schema": { "entities": [ {"name": "person", "description": "named individual"}, {"name": "organization", "description": "business or institution"}, {"name": "product", "description": "named commercial product"}, {"name": "location", "description": "city, region, or place"} ] }, "threshold": 0.5, "include_confidence": true, "include_spans": true }' ``` ## Classification example ```bash theme={null} curl -X POST "https://api.fastino.ai/v1/gliner-2" \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "text": "The replacement arrived quickly and works perfectly.", "schema": { "classifications": [ { "task": "sentiment", "labels": ["positive", "negative", "neutral"], "multi_label": false, "top_k": 1 } ] } }' ``` Each classic classification requires at least one label. For every supported entity, classification, structure, relation, record, attribute, and constrained-classification shape, use the complete [`POST /v1/chat/completions` GLiNER schema reference](/api-reference/inference/chat-completions). ## Response schema A successful response contains: * `result`: the schema-shaped extraction or classification result. * `token_usage`: the number of input tokens processed. ```json theme={null} { "result": { "entities": [ { "text": "Apple", "label": "organization", "score": 0.99, "start": 0, "end": 5 } ] }, "token_usage": 10 } ``` When `text` is an array, `result` is an array in the same input order. Do not send that batch shape through `POST /v1/chat/completions`; submit those conversations separately. # Submit an asynchronous GLiNER-2 job Source: https://docs.fastino.ai/api-reference/inference/gliner-2-async POST /v1/gliner-2/async Submit very large GLiNER-2 inputs for asynchronous processing when the input exceeds one million tokens or may outlast the synchronous request timeout. `POST /v1/gliner-2/async` Submit very large GLiNER-2 inputs for asynchronous processing. Use this endpoint when the input exceeds one million tokens or may outlast the synchronous request timeout. The OpenAPI panel on this page is the source of truth for every request field and `202` response field. The request uses the same native GLiNER schema as [`POST /v1/gliner-2`](/api-reference/inference/gliner-2). ## Request example ```bash theme={null} curl -X POST "https://api.fastino.ai/v1/gliner-2/async" \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "text": "A very large document to process asynchronously...", "schema": { "entities": [ {"name": "person", "description": "named individual"}, {"name": "organization", "description": "business or institution"} ] }, "threshold": 0.5, "include_confidence": true, "include_spans": true }' ``` `text` may also be an array of strings. Omit the deprecated `task` field; the unified schema identifies extraction, classification, structures, or relations. ## Accepted response The endpoint returns HTTP `202` immediately. This illustrative payload shortens `message`; the service supplies a concrete polling path containing the returned job ID. ```json theme={null} { "job_id": "3f08a17f-777a-4aa6-8ec5-879df37775a8", "status": "accepted", "estimated_tokens": 1284307, "message": "Job queued. ..." } ``` Store `job_id`, then poll [`GET /v1/gliner-2/jobs/{job_id}`](/api-reference/inference/gliner-2-job-status) with the same API key. Jobs are scoped to the authenticated user. # Get an asynchronous GLiNER-2 job Source: https://docs.fastino.ai/api-reference/inference/gliner-2-job-status GET /v1/gliner-2/jobs/{job_id} Poll a GLiNER-2 asynchronous job by its job_id until it completes or fails, with example processing, complete, and error responses. `GET /v1/gliner-2/jobs/{job_id}` Poll a GLiNER-2 asynchronous job until it completes or fails. Use the same API key that submitted the job; jobs are scoped to the authenticated user. The OpenAPI panel on this page is the source of truth for the `job_id` path parameter and every response field. ## Request example ```bash theme={null} curl "https://api.fastino.ai/v1/gliner-2/jobs/3f08a17f-777a-4aa6-8ec5-879df37775a8" \ -H "X-API-Key: $FASTINO_API_KEY" ``` ## Processing response Continue polling while `status` is `pending` or `processing`: ```json theme={null} { "job_id": "3f08a17f-777a-4aa6-8ec5-879df37775a8", "status": "pending", "result": null, "error": null, "token_usage": 1284307, "created_at": "2026-10-07T22:10:00+00:00", "completed_at": null } ``` ## Complete response Stop polling when `status` is `complete`. The `result` follows the schema from the submission request: ```json theme={null} { "job_id": "3f08a17f-777a-4aa6-8ec5-879df37775a8", "status": "complete", "result": { "entities": [ { "text": "Apple", "label": "organization", "score": 0.99, "start": 0, "end": 5 } ] }, "error": null, "token_usage": 1284307, "created_at": "2026-10-07T22:10:00+00:00", "completed_at": "2026-10-07T22:13:42+00:00" } ``` ## Zero Data Retention For a team with Zero Data Retention, a completed response sets `notice` to explain that the result is available once. Read and persist it in your own approved system during that poll: Fastino deletes the result after the first read, or 24 hours after completion if it is never read. ```json theme={null} { "status": "complete", "result": {"entities": []}, "notice": "" } ``` ## Error response A finished job can report `status: "error"` with a message in `error`: ```json theme={null} { "job_id": "3f08a17f-777a-4aa6-8ec5-879df37775a8", "status": "error", "result": null, "error": "The input could not be processed", "token_usage": 1284307, "created_at": "2026-10-07T22:10:00+00:00", "completed_at": "2026-10-07T22:10:08+00:00" } ``` An unknown job, or one belonging to another user, returns `404`. # Get an inference record Source: https://docs.fastino.ai/api-reference/inference/history/get GET /v1/inferences/{inference_id} Call GET /v1/inferences/{inference_id} to retrieve one stored inference record by its identifier. `GET /v1/inferences/{inference_id}` Retrieve one stored inference record by its identifier. # Get inference feedback Source: https://docs.fastino.ai/api-reference/inference/history/get-feedback GET /v1/inferences/{inference_id}/feedback Call GET /v1/inferences/{inference_id}/feedback to retrieve the feedback stored for one inference, identified by its inference_id. `GET /v1/inferences/{inference_id}/feedback` Retrieve the feedback stored for one inference. ## Identify the reviewer Read `human_feedback_by` to identify the member who submitted the feedback. It is a user ID, not a display name. The value is `null` for feedback recorded before authorship tracking was available. ```bash theme={null} curl --fail-with-body -sS \ "https://api.fastino.ai/v1/inferences/$INFERENCE_ID/feedback" \ -H "X-API-Key: $FASTINO_API_KEY" | jq '{human_verdict, human_feedback_by}' ``` The inference record returned by `GET /v1/inferences/{inference_id}` also includes `human_feedback_by` for its current feedback. # List inference history Source: https://docs.fastino.ai/api-reference/inference/history/list GET /v1/inferences Call GET /v1/inferences to list stored inference records with supported filters and pagination. `GET /v1/inferences` List stored inference records with supported filters and pagination. # Submit inference feedback Source: https://docs.fastino.ai/api-reference/inference/history/submit-feedback POST /v1/inferences/{inference_id}/feedback Submit a verdict and optional corrected output for one stored inference. `POST /v1/inferences/{inference_id}/feedback` Submit a verdict and optional corrected output for one stored inference. # Anthropic-compatible Messages Source: https://docs.fastino.ai/api-reference/inference/messages POST /v1/messages Run supported Fastino models through the Anthropic Messages wire contract. `POST /v1/messages` Run supported Fastino models through the Anthropic Messages wire contract. # List compatibility models Source: https://docs.fastino.ai/api-reference/inference/models GET /v1/models List model IDs exposed through the OpenAI- and Anthropic-compatible SDK surfaces. `GET /v1/models` List model IDs exposed through the OpenAI- and Anthropic-compatible SDK surfaces. > **[Related guide: Compatibility models](/concepts/models)** # Inference API reference Source: https://docs.fastino.ai/api-reference/inference/overview Exact request and response contracts for GLiDE, GLiNER, compatibility, history, and feedback inference endpoints. Use these contracts when you need exact fields, constraints, status codes, and response shapes. For executable workflows, start with the guides. > **[Call GLiDE](/inference/systemone)** > > Choose a decision primitive and run a complete System One request. > **[Call GLiNER](/inference/chat-completions)** > > Run extraction, classification, records, and relations through Chat Completions. > **[Cookbooks](/cookbooks/overview)** > > Tested requests and responses for the most common GLiDE and GLiNER tasks. # OpenAI-compatible Responses Source: https://docs.fastino.ai/api-reference/inference/responses POST /v1/responses Run supported Fastino models through the OpenAI Responses wire contract. `POST /v1/responses` Run supported Fastino models through the OpenAI Responses wire contract. # GLiDE decision inference Source: https://docs.fastino.ai/api-reference/inference/systemone POST /v1/systemone Call GLiDE with state and typed questions and receive calibrated decision answers. `POST /v1/systemone` Call GLiDE with state and typed questions and receive calibrated decision answers. > **[Follow the happy-path guide](/inference/systemone)** > > Choose a primitive, make a complete GLiDE call, and interpret its probability. # Get training-job billing Source: https://docs.fastino.ai/api-reference/training-jobs/billing GET /v1/training/jobs/{job_id}/billing Call GET /v1/training/jobs/{job_id}/billing to check whether a Fastino training job was billed, plus its charge in USD, GPU minutes, and timestamps. `GET /v1/training/jobs/{job_id}/billing` This operation is config-only; after normal feature and permission checks, an interactive job ID returns `400`, and interactive jobs have no equivalent aggregate compute-billing endpoint (`GET /v1/training/usage` reports checkpoint storage only). Returns whether a job was billed and, when available, the charge and GPU duration. ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Training-job UUID. ```bash cURL theme={null} curl https://api.fastino.ai/v1/training/jobs/YOUR_TRAINING_JOB_ID/billing \ -H "X-API-Key: $FASTINO_API_KEY" ``` ## Response **job\_id** `string` Training-job UUID. **status** `string` Current persisted job status. **started\_at** `string | null` Time the job was dispatched. **compute\_started\_at** `string | null` Time the training container began executing. **completed\_at** `string | null` Time the job completed. **billed** `boolean` Whether a billing record exists. **request\_id** `string | null` Associated billing-request ID. **charged\_usd** `string | null` USD amount charged, represented as a decimal string. **gpu\_minutes** `string | null` Billed GPU minutes, represented as a decimal string. **billed\_at** `string | null` Time the billing record was created. ```json Response theme={null} { "job_id": "YOUR_TRAINING_JOB_ID", "status": "complete", "started_at": "2026-09-22T20:00:00Z", "compute_started_at": "2026-09-22T20:01:00Z", "completed_at": "2026-09-22T20:31:00Z", "billed": true, "request_id": "REQUEST_ID", "charged_usd": "3.25", "gpu_minutes": "30.0", "billed_at": "2026-09-22T20:32:00Z" } ``` An unknown or inaccessible job returns `404`. # List training checkpoints Source: https://docs.fastino.ai/api-reference/training-jobs/checkpoints GET /v1/training/jobs/{job_id}/checkpoints List config or interactive training-job checkpoints and use the correct identifier for each job type. `GET /v1/training/jobs/{job_id}/checkpoints` Returns checkpoints visible for a training job. ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Config-job UUID, or the interactive `job_id` returned by `POST /v1/training/jobs/create-model`. ```bash cURL theme={null} curl https://api.fastino.ai/v1/training/jobs/YOUR_TRAINING_JOB_ID/checkpoints \ -H "X-API-Key: $FASTINO_API_KEY" ``` ## Response **success** `boolean` Whether the request succeeded. **checkpoints** `object[]` Saved checkpoints. The item shape depends on the job type. **count** `integer` Number of checkpoints returned. ### Config job Config checkpoints include `id`, `job_id`, epoch, step, loss, metric, deployment, and timestamp fields. Their `id` values are not accepted by the interactive checkpoint-download endpoint. ```json Response theme={null} { "success": true, "checkpoints": [ { "id": "CHECKPOINT_ID", "job_id": "YOUR_TRAINING_JOB_ID", "epoch": 5, "step": 500, "training_loss": 0.12, "validation_loss": 0.18, "is_deployable": true, "is_best": true, "is_final": true, "created_at": "2026-09-22T20:30:00Z", "updated_at": "2026-09-22T20:30:00Z" } ], "count": 1 } ``` ### Interactive job Interactive jobs also return `run_id`. Their checkpoints are live checkpoints, ordered newest first. Use `checkpoint_id`, such as `sampler_weights/checkpoint-1`, with the [interactive checkpoint-download endpoint](/api-reference/training-jobs/download-checkpoint). Do not pass the config checkpoint `id` or `tinker_path`. ```json Response theme={null} { "success": true, "run_id": "session-1:train:0", "checkpoints": [ { "checkpoint_id": "sampler_weights/checkpoint-1", "checkpoint_type": "sampler", "time": "2026-09-22T20:30:00Z", "tinker_path": "tinker://session-1:train:0/sampler_weights/checkpoint-1", "size_bytes": 12345, "public": false, "user_metadata": null, "expires_at": null } ], "count": 1 } ``` An unknown or inaccessible job returns `404`. # Create a config training job Source: https://docs.fastino.ai/api-reference/training-jobs/create POST /v1/training/jobs Call POST /v1/training/jobs to start an asynchronous Fastino-managed training job from a base model and datasets. `POST /v1/training/jobs` Creates an asynchronous `config` training job and returns its job record. In a config job, you provide a dataset and configuration and Fastino runs the training loop. To control the loop step by step, follow the [custom training loop path](/training/decoder-quickstart), which creates an `interactive` job through [`POST /v1/training/jobs/create-model`](/api-reference/training-jobs/interactive/create-model) or the supported Tinker SDK. This endpoint does not create interactive jobs. After creation, both job types use their canonical IDs with the documented `/v1/training/jobs/{job_id}` lifecycle operations. Config jobs train encoder models that are returned by `GET /v1/base-models?supports_training=true` and have a compatible config-job dispatch route. Decoder base models return `400`; train decoders step by step with an interactive job instead. This endpoint is limited to 20 requests per minute per user. ## Request **X-API-Key** `string` *required* Your Fastino API key. **Idempotency-Key** `string` Client-generated retry key, 1–255 characters; a UUID is recommended. Repeating the same key and body returns the original job. Reusing the key with a different body returns `422`. **model\_name** `string` *required* Display name for the trained model. Length: 1–100 characters. **base\_model** `string` *required* A trainable encoder ID returned by `GET /v1/base-models?supports_training=true`. The selected `training_type` must have a compatible dispatch route. Checkpoint UUIDs and decoder base models return `400`. **datasets** `object[]` *required* One or more [uploaded dataset](/concepts/datasets) references. Each item requires `name` and may include `version`; omitted versions resolve to the latest version. **training\_type** `string` (default: lora) `lora` or `full`. The selected base model must support the requested type. **validation\_data\_percentage** `number` (default: 0.2) Fraction held out for validation, from `0` to `0.9` in increments of `0.01`. **nr\_epochs** `integer` (default: 100) Maximum epoch count, from `1` to `10000`; early stopping can finish sooner. **learning\_rate** `number` Peak learning rate from `1e-8` to `1`. Omit it to use the selected model's training recipe. **batch\_size** `integer` (default: 4) Per-device batch size from `1` to `256`. Prefer omitting it so the training service can apply or safely clamp to the model-specific default. **seed** `integer` Optional reproducibility seed from `0` through `2147483647`. Set `provider_name` to `modal` when using it. A seed reduces one source of variation but does not guarantee bit-identical GPU runs. **project\_id** `string` Project UUID. When omitted, Fastino associates the job with the caller's default project. **Additional training parameters** **save\_steps** `integer` (default: 100) Save a checkpoint every N steps, from `1` to `2147483647`. **profile\_training** `boolean` (default: false) Persist a structured training profile artifact. **wandb\_api\_key** `string` Optional Weights & Biases API key. Treat it as a secret and never put it in source control, logs, or examples. **lora\_r** `integer` LoRA rank from `1` to `256`. Omit it to use the model recipe. **lora\_alpha** `integer` Positive LoRA alpha, up to `2147483647`. Omit it to use the model recipe. **lora\_dropout** `number` LoRA dropout from `0` (inclusive) to `1` (exclusive). Omit it to use the model recipe. **warmup\_ratio** `number` Warmup fraction from `0` to `1`. Use this field to configure warmup for GLiNER jobs. **warmup\_steps** `integer` Absolute warmup-step count, from `1` to `2147483647`. GLiNER jobs reject this field with `422 unsupported_encoder_scheduling`; use `warmup_ratio`. **lr\_scheduler\_type** `string` Learning-rate schedule: `constant`, `linear`, or `cosine`. GLiNER uses `linear` when this field is omitted; only an explicit value is forwarded. **weight\_decay** `number` Accepted for request compatibility but not forwarded to GLiNER training. GLiNER uses its container default of `0.01`. **early\_stopping\_patience** `integer` (default: 3) Validation epochs without improvement before stopping, from `0` to `10000`. Set `0` to disable. **early\_stopping\_min\_delta** `number` (default: 0.0001) Non-negative minimum validation-loss improvement that counts as progress. **provider\_name** `string` Pin a compatible training provider. Omit it for automatic selection. **encoder\_learning\_rate** `number` GLiNER encoder learning rate from `1e-8` to `1`. Falls back to `learning_rate`. **task\_learning\_rate** `number` GLiNER task-head learning rate from `1e-8` to `1`. Falls back to `learning_rate`. **gradient\_accumulation\_steps** `integer` Positive mini-batch accumulation count, up to `2147483647`. **auto\_data\_sizing** `boolean` Enable GLiNER dataset auto-sizing. **min\_samples\_per\_dataset** `integer` GLiNER auto-sizing lower bound, from `1` to `2147483647`. **max\_samples\_per\_dataset** `integer` GLiNER auto-sizing upper bound, from `1` to `2147483647`. **samples\_per\_label** `integer` GLiNER auto-sizing scale per label, from `1` to `2147483647`. **min\_training\_steps** `integer` Minimum GLiNER optimizer steps, from `0` to `2147483647`. **eval\_steps** `integer` GLiNER2 periodic validation interval, from `1` to `2147483647` optimizer steps. Omit it to validate only at epoch end. **max\_eval\_samples** `integer` GLiNER2 per-dataset cap for periodic validation, from `1` to `2147483647`. Omit it for no cap. **max\_length** `integer` GLiNER maximum input length, from `1` to `2147483647` tokens. Omit it to use the model context limit. **max\_gold\_per\_query** `integer` GLiNER2 maximum retained gold spans per query, from `1` to `1024`. Omit it to use `32`. **on\_capacity\_exceeded** `string` GLiNER2 behavior when gold spans exceed `max_gold_per_query`: `raise`, `truncate_with_warning`, or `skip_sample`. Omit it to use `raise`. **training\_algorithm** `string` (default: sft) Only `sft` is supported for config jobs. Omit it to use the default. ```bash cURL theme={null} curl -X POST https://api.fastino.ai/v1/training/jobs \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Idempotency-Key: YOUR_UNIQUE_RETRY_KEY" \ -H "Content-Type: application/json" \ -d '{ "model_name": "my-model-name", "base_model": "fastino/gliner2-base-v1", "datasets": [{"name": "my-ready-dataset"}], "training_type": "lora", "nr_epochs": 5, "learning_rate": 5e-5, "validation_data_percentage": 0.2 }' ``` ## Response Returns `200` with the full training-job record, including a UUID `id` and initial status. The example below is abbreviated; the actual response includes all fields defined by `TrainingJobResponse`. ```json Response theme={null} { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "type": "config", "model_name": "my-model-name", "base_model": "fastino/gliner2-base-v1", "status": "requested", "training_type": "lora", "nr_epochs": 5, "learning_rate": 5e-5, "validation_data_percentage": 0.2 } ``` Save the `id` from this response. You will use it to poll status, retrieve metrics and artifacts, and run inference against the trained model. A malformed body returns `422`. A valid but unavailable model, dataset, training type, or provider combination returns a request-specific `4xx` error. Creation can return these coded conflicts: | Status | Meaning | | - | - | | `402` | The account has never been funded or has exhausted its credits. | | `403` | A payment method, account requirement, or the caller's team role blocks creation. | | `409 duplicate_training_submission` | An identical active job was submitted in the previous 60 seconds. Poll the `job_id` from the error instead of resubmitting. | | `409 idempotency_key_job_deleted` | The job originally created with this idempotency key was deleted. Use a new key for a new job. | | `409` | A referenced dataset retired between validation and job insertion. Resolve the dataset and retry with a new key. | | `422 idempotency_key_reused` | The same `Idempotency-Key` was used with a different request body. Use the original body to replay, or a new key for a new job. | | `429` | The request rate or active config-job limit was exceeded. A user can have at most 25 active config jobs. | | `503` | Billing state could not be checked or all training providers are at capacity. Retry later with the same `Idempotency-Key`. | The same `Idempotency-Key` and identical body replay the original job instead of creating another. A changed body with the same key returns `422`. The 60-second identical-submission check is separate from idempotency-key replay. After that window, sending the same body without reusing the original key creates and bills another job. If the requested model name is already taken, the next job receives a suffix such as `_2`. A decoder base model returns `400`: ```json theme={null} { "error": { "message": "Decoder training on this route is retired: 'Qwen/Qwen3.6-35B-A3B' cannot be trained here. Train decoders step by step with the training job routes under /v1/training/jobs (see https://docs.fastino.ai/training/quickstart).", "type": "invalid_request_error", "param": null, "code": null } } ``` To train a decoder, create an interactive job with [`POST /v1/training/jobs/create-model`](/api-reference/training-jobs/interactive/create-model) and follow the [custom training loop](/training/decoder-quickstart). ## Authorization Requires the Owner, Admin, or Editor team role. Other roles receive `403 Forbidden`. # Delete a training job Source: https://docs.fastino.ai/api-reference/training-jobs/delete DELETE /v1/training/jobs/{job_id} Call DELETE /v1/training/jobs/{job_id} to permanently delete a training job with its checkpoints and stored artifacts, stopping the job first if active. `DELETE /v1/training/jobs/{job_id}` Deletes a config or interactive job and its stored artifacts. > [!WARNING] > > Deletion is irreversible. First download anything you need into storage you > control. For a config job, the service first requests cancellation when the job is active. Deletion completes in the same call only when cancellation is confirmed. It removes checkpoints and stored artifacts and releases active hosted deployments. For an interactive job, the service cancels queued non-sampling training calls, requests a stop, and marks the job and its checkpoints deleted in the same request. The job immediately becomes unavailable through list, get, checkpoint, and future routes. Queued sampling calls and calls already running still finish and are billed before background cleanup completes. Models already deployed from the job's sampler checkpoints remain separate model resources and continue serving until deleted separately. ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Config-job UUID or interactive job ID. ```bash cURL theme={null} curl -X DELETE https://api.fastino.ai/v1/training/jobs/YOUR_TRAINING_JOB_ID \ -H "X-API-Key: $FASTINO_API_KEY" ``` ## Response ```json Response theme={null} { "success": true, "message": "Training job deleted successfully" } ``` An unknown or inaccessible job returns `404`. | Status | Meaning | | - | - | | `409 training_job_already_finished` | For a config job, the job completed or failed before cancellation landed. Read the job state before deciding whether to retry. | | `409 cancellation_unconfirmed` | For a config job, the job is still stopping. Poll `GET /v1/training/jobs/{job_id}`, then retry this `DELETE` after the job is stopped. Deletion does not complete in the background. | ## Authorization Requires the Owner, Admin, or Editor team role. Other roles receive `403 Forbidden`. # Deploy a training checkpoint Source: https://docs.fastino.ai/api-reference/training-jobs/deploy-checkpoint POST /v1/training/jobs/{job_id}/checkpoints/{checkpoint_id}/deploy Deploy one deployable checkpoint from a Fastino training job to the hosted multi-model inference endpoint, using the checkpoint ID from the list endpoint. `POST /v1/training/jobs/{job_id}/checkpoints/{checkpoint_id}/deploy` Deploys one deployable checkpoint to the hosted multi-model inference endpoint. ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Training-job UUID. **checkpoint\_id** `string` *required* Checkpoint ID returned by the checkpoint-list endpoint. ```bash cURL theme={null} curl -X POST \ https://api.fastino.ai/v1/training/jobs/YOUR_TRAINING_JOB_ID/checkpoints/CHECKPOINT_ID/deploy \ -H "X-API-Key: $FASTINO_API_KEY" ``` ## Response ```json Response theme={null} { "success": true, "message": "Checkpoint deployed successfully", "job_id": "YOUR_TRAINING_JOB_ID", "checkpoint_id": "CHECKPOINT_ID", "deployment_path": "PROVIDER_MODEL_PATH", "mme_path": "PROVIDER_MODEL_PATH" } ``` `deployment_path` is the canonical deployed-object path. `mme_path` is a deprecated compatibility alias. An unknown job or checkpoint returns `404`. A checkpoint that is not deployable returns a request-specific `4xx` error. ## Authorization Requires the Owner or Admin team role because this operation changes a live deployment. Other roles receive `403 Forbidden`. # List training-job deployments Source: https://docs.fastino.ai/api-reference/training-jobs/deployments GET /v1/training/jobs/{job_id}/deployments List deployments created from or associated with a training job by calling GET /v1/training/jobs/{job_id}/deployments with the job ID. `GET /v1/training/jobs/{job_id}/deployments` This operation is config-only; after normal feature and permission checks, an interactive job ID returns `400`. A sampler-checkpoint deployment reports initial progress in its `status`; use the returned `model_id` with this endpoint to list that served model's deployment records. List deployments created from or associated with a training job. # Download trained weights Source: https://docs.fastino.ai/api-reference/training-jobs/download GET /v1/training/jobs/{job_id}/download Call GET /v1/training/jobs/{job_id}/download to get a temporary presigned URL for a trained artifact, with its expiry time and a suggested file name. `GET /v1/training/jobs/{job_id}/download` This operation is config-only; after normal feature and permission checks, an interactive job ID returns `400`, so download a named checkpoint with `GET /v1/training/jobs/{job_id}/checkpoints/{checkpoint_id}/download` instead. Returns a presigned URL for the trained artifact. Fetch the returned URL separately to download the file. ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Training-job UUID. ```bash cURL theme={null} curl https://api.fastino.ai/v1/training/jobs/YOUR_TRAINING_JOB_ID/download \ -H "X-API-Key: $FASTINO_API_KEY" ``` ## Response **success** `boolean` Whether the URL was generated. **job\_id** `string` Training-job UUID. **download\_url** `string` Temporary presigned artifact URL. **expires\_in\_seconds** `integer` URL lifetime. The default is 3600 seconds. **file\_name** `string` Suggested download file name in the form `gliner2-model-.tar.gz`. ```json Response theme={null} { "success": true, "job_id": "YOUR_TRAINING_JOB_ID", "download_url": "https://...", "expires_in_seconds": 3600, "file_name": "gliner2-model-a1b2c3d4.tar.gz", "message": "Download URL generated successfully" } ``` > [!WARNING] > > The presigned URL is a temporary bearer credential. Do not log, commit, persist, or share it. Download the artifact promptly and store it according to your data-handling policy. To request the URL and download the artifact in one workflow: ```bash theme={null} response=$(curl -fsS \ https://api.fastino.ai/v1/training/jobs/YOUR_TRAINING_JOB_ID/download \ -H "X-API-Key: $FASTINO_API_KEY") curl -fL \ -o "$(jq -r '.file_name' <<<"$response")" \ "$(jq -r '.download_url' <<<"$response")" ``` This example requires `jq`. Weight downloads are enabled by default. A team whose download access was explicitly disabled receives `403`. | Status | Meaning | | - | - | | `400` | For a config job, training is incomplete or its artifact is not ready; wait and retry. For an interactive job ID, use the named-checkpoint download route instead. | | `401` | A deferred billing check requires a payment method. Add one in billing settings. | | `403` | Weight downloads were explicitly disabled for the team. | | `404` | The job is unknown or inaccessible. | # Download an interactive checkpoint Source: https://docs.fastino.ai/api-reference/training-jobs/download-checkpoint GET /v1/training/jobs/{job_id}/checkpoints/{checkpoint_id}/download Get a short-lived download URL for an interactive training-job checkpoint. `GET /v1/training/jobs/{job_id}/checkpoints/{checkpoint_id}/download` Returns a short-lived presigned object-storage URL for one checkpoint from an `interactive` job. A sampler checkpoint's archive contains the decoder adapter files. Config jobs use [`GET /v1/training/jobs/{job_id}/download`](/api-reference/training-jobs/download) for their final model artifact. ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Interactive `job_id` returned by `POST /v1/training/jobs/create-model`. **checkpoint\_id** `string` *required* Checkpoint identifier returned by the checkpoint list, such as `weights/checkpoint-1` or `sampler_weights/checkpoint-1`. Keep the `/` in the path; do not URL-encode the entire identifier. ```bash cURL theme={null} CHECKPOINT_ID="sampler_weights/checkpoint-1" curl "https://api.fastino.ai/v1/training/jobs/JOB_ID/checkpoints/$CHECKPOINT_ID/download" \ -H "X-API-Key: $FASTINO_API_KEY" ``` ## Response The response contains a signed archive URL that expires after 15 minutes. Treat the URL as a credential: do not log, share, or persist it. **success** `boolean` Whether the request succeeded. **run\_id** `string` Interactive job that owns the checkpoint. **checkpoint\_id** `string` Downloadable interactive checkpoint identifier. **download\_url** `string` Presigned object-storage URL. No API key is required when fetching it. **expires\_in\_seconds** `integer` Remaining lifetime of the signed URL. New links expire after 900 seconds. **file\_name** `string` Suggested `.tar` file name for the archive. ```json Response theme={null} { "success": true, "run_id": "session-1:train:0", "checkpoint_id": "sampler_weights/checkpoint-1", "download_url": "SIGNED_ARCHIVE_URL", "expires_in_seconds": 900, "file_name": "session-1_train_0-sampler_weights-checkpoint-1.tar" } ``` Checkpoint downloads are enabled by default. A team whose download access was explicitly disabled receives `403`. ## Load a decoder adapter A decoder's sampler checkpoint downloads as a standard Hugging Face PEFT adapter for the public base model. The archive holds `adapter_config.json`, `adapter_model.safetensors` with every trained tensor, and a `README.md` with loading code: ```python theme={null} from peft import PeftModel from transformers import AutoModelForCausalLM base = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3.6-35B-A3B", dtype="auto") model = PeftModel.from_pretrained(base, "path/to/extracted/archive") ``` Fastino tests these adapters with transformers 5.19.0 and peft 0.21.2, not with vLLM. A Nemotron 3.5 Lightning adapter that trains Mamba `out_proj` needs a one-line opt-in before PEFT loads it; the archive's `README.md` shows it. Only sampler checkpoints are converted: a training-state checkpoint downloads in Fastino's internal layout. ## Errors | Status | Meaning | | - | - | | `400` | `checkpoint_id` is not `weights/` or `sampler_weights/`. | | `403` | Weight downloads were explicitly disabled for the team. | | `404` | The job or checkpoint is unavailable, or the checkpoint has no downloadable files. | Fetching `download_url` returns an `application/x-tar` attachment. The presigned URL is the credential and expires after the response's `expires_in_seconds`. # Get a training job Source: https://docs.fastino.ai/api-reference/training-jobs/get GET /v1/training/jobs/{job_id} Get a config or interactive training job by its canonical Fastino job ID. `GET /v1/training/jobs/{job_id}` Returns one config or interactive training job visible to the caller's team. For an interactive job, use the `job_id` returned by [`POST /v1/training/jobs/create-model`](/api-reference/training-jobs/interactive/create-model). ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Canonical Fastino training-job ID. ```bash cURL theme={null} curl https://api.fastino.ai/v1/training/jobs/YOUR_TRAINING_JOB_ID \ -H "X-API-Key: $FASTINO_API_KEY" ``` ## Response ### Config job **id** `string` Canonical Fastino job ID for a config job. **type** `string` `config` when Fastino runs the training loop or `interactive` when the caller controls the loop through the interactive-job routes. **status** `string` Persisted lifecycle status. **normalized\_status** `string | null` Stable status for client compatibility. **is\_terminal\_status** `boolean | null` Whether polling can stop. **progress\_percent** `integer | null` Current completion percentage from `0` through `100`. **current\_epoch** `integer | null` Current 1-indexed epoch. **error\_message** `string | null` Failure details when available. **metrics** `object | null` Available training metrics. Common keys are `final_training_loss`, `final_validation_loss`, and `best_validation_loss`. Evaluation metrics are separate and are not guaranteed. **artifact\_ready** `boolean | null` Whether an artifact location is available. **is\_deployable** `boolean | null` Authoritative deployment-readiness decision. **deployability\_reason** `string | null` Why the job is not deployable. Config-job records also return their submitted configuration, dataset references, progress, metrics, and artifact metadata. ### Interactive job **job\_id** `string` Canonical Fastino job ID for the interactive job. Use it in `/v1/training/jobs/{job_id}` paths. **training\_run\_id** `string` Legacy run ID for the interactive job. It has the same value as `job_id`. **status** `string` Interactive lifecycle status: `creating`, `active`, `stopping`, `stopped`, or `failed`. **stop\_reason** `string | null` Why the job stopped: `requested`, `idle_timeout`, `session_finished`, or `session_errored`. **error\_message** `string | null` Failure details when `status` is `failed`. **is\_terminal\_status** `boolean` `true` when `status` is `stopped` or `failed`. **base\_model** `string` Base model used by the interactive training job. **model\_owner** `string` Team that owns the interactive job. **is\_lora** `boolean` Whether the job trains a LoRA adapter. **corrupted** `boolean` Whether the training state is unusable for further steps. **lora\_rank** `integer | null` LoRA rank, when applicable. **last\_request\_time** `string` ISO 8601 time of the most recent request to the job. **last\_checkpoint** `object | null` Latest training-state checkpoint. **last\_sampler\_checkpoint** `object | null` Latest sampler-weights checkpoint. Checkpoint objects include `checkpoint_id`, `checkpoint_type`, `time`, `tinker_path`, `size_bytes`, `public`, `user_metadata`, and `expires_at`. **user\_metadata** `object | null` String key-value metadata attached when the interactive job was created. Do not assume config-only fields are populated on an interactive job. ```json Response theme={null} { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "type": "config", "status": "running", "normalized_status": "running", "is_terminal_status": false, "progress_percent": 40, "current_epoch": 2, "metrics": { "final_training_loss": 0.12, "final_validation_loss": 0.18, "best_validation_loss": 0.15 }, "artifact_ready": false, "is_deployable": false, "deployability_reason": "job_incomplete" } ``` ```json Interactive job theme={null} { "type": "interactive", "job_id": "YOUR_SESSION_ID:train:0", "training_run_id": "YOUR_SESSION_ID:train:0", "status": "active", "stop_reason": null, "error_message": null, "is_terminal_status": false, "base_model": "Qwen/Qwen3.6-35B-A3B", "model_owner": "YOUR_TEAM_ID", "is_lora": true, "corrupted": false, "lora_rank": 32, "last_request_time": "2026-10-09T18:42:10Z", "last_checkpoint": null, "last_sampler_checkpoint": { "checkpoint_id": "sampler_weights/step-100", "checkpoint_type": "sampler", "time": "2026-10-09T18:40:02Z", "tinker_path": "tinker://YOUR_SESSION_ID:train:0/sampler_weights/step-100", "size_bytes": 167772160, "public": false, "user_metadata": null, "expires_at": null }, "user_metadata": {"experiment": "baseline"} } ``` An unknown or inaccessible job returns `404`. Non-UUID values are treated as interactive job IDs and return `404` when unavailable. # Cancel an interactive future Source: https://docs.fastino.ai/api-reference/training-jobs/interactive/cancel-future POST /v1/training/jobs/{job_id}/futures/{future_id}/cancel Request best-effort cancellation of a queued or running sample future. Terminal futures and training futures return 204 as successful no-ops. `POST /v1/training/jobs/{job_id}/futures/{future_id}/cancel` Cancellation is best effort for a queued or running `sample` future. The route returns `204 No Content` when the request is accepted. Cancelling a terminal future or a training future also returns `204`; it is a successful no-op because training operations run in order and are not cancelled. ```bash cURL theme={null} curl -X POST "https://api.fastino.ai/v1/training/jobs/$TRAINING_JOB_ID/futures/$FUTURE_ID/cancel" \ -H "X-API-Key: $FASTINO_API_KEY" ``` ## Errors | Status | Meaning | | - | - | | `404` | The job or future doesn't exist, or belongs to another team. | # Create an interactive model Source: https://docs.fastino.ai/api-reference/training-jobs/interactive/create-model POST /v1/training/jobs/create-model Create an interactive LoRA job from a base_model, or restore one from_checkpoint with optional load_optimizer. The response returns the job_id and future_id. `POST /v1/training/jobs/create-model` Creates an `interactive` LoRA training job on a decoder base model, or a new job seeded from a saved training state. Your application then sends each forward-backward pass, optimizer step, checkpoint, and sample. Native JSON clients do not send `seq_id` values or heartbeats. For managed training from an uploaded dataset, use [`POST /v1/training/jobs`](/api-reference/training-jobs/create). The job is ready once its `create` future completes. Read it with [`GET /v1/training/jobs/{job_id}/futures/{future_id}`](/api-reference/training-jobs/interactive/get-future). Each team can have at most `16` live interactive jobs. Each job can have at most `512` operations queued at once. Exceeding either limit returns `429`. ## Request **X-API-Key** `string` *required* Your Fastino API key. Send exactly one of `base_model` and `from_checkpoint`. **base\_model** `string` `nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16`, `nvidia/NVIDIA-Nemotron-3.5-Super-VL-120B-A12B-NVFP4`, or `Qwen/Qwen3.6-35B-A3B`. **from\_checkpoint** `string` The `path` that [`save-weights`](/api-reference/training-jobs/interactive/save-weights) returned for one of your jobs, such as `tinker:///weights/`. The new job takes that checkpoint's base model and LoRA settings, so omit `lora_config`. Sampler checkpoints are rejected. **load\_optimizer** `boolean` (default: false) Set `load_optimizer` with `from_checkpoint` to restore the optimizer state. **lora\_config** `object` LoRA settings for a new job. **properties** **rank** `integer` (default: 32) LoRA rank, from 1 through 32. **seed** `integer` Adapter initialization seed. **train\_attn** `boolean` (default: true) Train attention layers. **train\_mlp** `boolean` (default: true) Train MLP layers. **train\_unembed** `boolean` (default: true) Train the unembedding layer. **optimizer\_config** `object` Optimizer family. Only `{"type": "adamw"}` is served, which is the default. **project\_id** `string` Project the job and its usage belong to. Defaults to your default project. **user\_metadata** `object` Your own JSON metadata for the job. ```bash cURL theme={null} curl -X POST "https://api.fastino.ai/v1/training/jobs/create-model" \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "base_model": "Qwen/Qwen3.6-35B-A3B", "lora_config": {"rank": 32} }' ``` ## Response **job\_id** `string` Interactive job ID. Use it with every `/v1/training/jobs/{job_id}` route. **type** `string` Always `interactive`. **base\_model** `string` Base model of the job. **future\_id** `string` The job's `create` future. **load\_future\_id** `string | null` With `from_checkpoint`, the future that loads the checkpoint. ```json Response theme={null} { "job_id": "SESSION_ID:train:0", "type": "interactive", "base_model": "Qwen/Qwen3.6-35B-A3B", "future_id": "FUTURE_ID", "load_future_id": null } ``` ## Errors | Status | Meaning | | - | - | | `400` | The model isn't served, the rank is out of range, `from_checkpoint` is a sampler checkpoint, or `lora_config` was sent with `from_checkpoint`. | | `402` | The team is out of credits or has no valid payment setup. | | `404` | Interactive training isn't available to the team, or the checkpoint doesn't exist. | | `429` | The team already has `16` live interactive jobs. Stop an idle job before retrying. | | `422` | Both or neither of `base_model` and `from_checkpoint` were sent, or the body has an unknown field. | # Queue a forward operation Source: https://docs.fastino.ai/api-reference/training-jobs/interactive/forward POST /v1/training/jobs/{job_id}/forward Queue a forward pass without gradients on an interactive training job, then poll the returned future_id until the status is completed, failed, or cancelled. `POST /v1/training/jobs/{job_id}/forward` Computes the loss and per-token log probabilities of a batch without accumulating gradients. Use it for evaluation or to score tokens before an update. The body, response, and result match [`POST /v1/training/jobs/{job_id}/forward-backward`](/api-reference/training-jobs/interactive/forward-backward). The future `type` is `forward`. The numeric token arrays below are illustrative placeholders. Tokenize your actual text with the tokenizer for the job's `base_model`. ```bash cURL theme={null} curl -X POST "https://api.fastino.ai/v1/training/jobs/$TRAINING_JOB_ID/forward" \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "datums": [ { "model_input": {"chunks": [{"type": "encoded_text", "tokens": [151644, 872, 198, 3838]}]}, "loss_fn_inputs": { "target_tokens": {"data": [872, 198, 3838, 30], "dtype": "int64"} } } ] }' ``` ```json Response theme={null} { "future_id": "FUTURE_ID", "job_id": "SESSION_ID:train:0", "type": "forward" } ``` # Queue a forward-backward operation Source: https://docs.fastino.ai/api-reference/training-jobs/interactive/forward-backward POST /v1/training/jobs/{job_id}/forward-backward Queue a forward-backward pass that accumulates gradients on an interactive training job, then poll the returned future_id until it reaches a terminal status. `POST /v1/training/jobs/{job_id}/forward-backward` Computes the loss of a batch of token-level datums and accumulates its gradients. The next [optimizer step](/api-reference/training-jobs/interactive/optim-step) applies them. The response is a future; read the loss and per-token log probabilities from [`GET /v1/training/jobs/{job_id}/futures/{future_id}`](/api-reference/training-jobs/interactive/get-future). [`POST /v1/training/jobs/{job_id}/forward`](/api-reference/training-jobs/interactive/forward) takes the same body and computes the loss without gradients. ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Interactive job ID. **datums** `object[]` *required* One or more training examples. Tokenize them yourself with the base model's tokenizer. **properties** **model\_input** `object` *required* `{"chunks": [{"type": "encoded_text", "tokens": [...]}]}`. The input token IDs, N tokens in total. **loss\_fn\_inputs** `object` *required* Per-position tensors, each `{"data": [...], "dtype": "int64" | "float32"}` with an optional `shape`. Every tensor has N values. * `target_tokens` (`int64`, required): the token expected at each position, usually the input shifted left by one. * `weights` (`float32`): per-position loss weight. Use `0` for prompt positions and `1` for completion positions. * `logprobs` and `advantages` (`float32`): required by every loss except `cross_entropy`. `logprobs` are the sampler's log probabilities of the targets. **loss\_fn** `string` (default: cross\_entropy) `cross_entropy`, `importance_sampling`, `ppo`, `cispo`, or `dro`. **loss\_fn\_config** `object` Loss settings. `ppo` and `cispo` take `clip_low_threshold` and `clip_high_threshold`; `dro` takes `beta`. Unknown keys are rejected. The numeric token arrays below are illustrative placeholders. Tokenize your actual text with the tokenizer for the job's `base_model`. ```bash cURL theme={null} curl -X POST "https://api.fastino.ai/v1/training/jobs/$TRAINING_JOB_ID/forward-backward" \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "loss_fn": "cross_entropy", "datums": [ { "model_input": {"chunks": [{"type": "encoded_text", "tokens": [151644, 872, 198, 3838]}]}, "loss_fn_inputs": { "target_tokens": {"data": [872, 198, 3838, 30], "dtype": "int64"}, "weights": {"data": [0, 0, 1, 1], "dtype": "float32"} } } ] }' ``` ## Response **future\_id** `string` The queued future. **job\_id** `string` The job. **type** `string` `forward_backward`. ```json Response theme={null} { "future_id": "FUTURE_ID", "job_id": "SESSION_ID:train:0", "type": "forward_backward" } ``` ```json Completed future theme={null} { "future_id": "FUTURE_ID", "job_id": "SESSION_ID:train:0", "type": "forward_backward", "status": "completed", "result": { "loss_fn_output_type": "ArrayRecord", "loss_fn_outputs": [ {"logprobs": {"data": [-3.1, -0.4, -1.2, -0.8], "dtype": "float32", "shape": [4]}} ], "metrics": {"loss:sum": 2.0} }, "error": null } ``` ## Errors | Status | Meaning | | - | - | | `400` | Unknown `loss_fn`, a non-integer `target_tokens` tensor, out-of-vocabulary token IDs, or the job was stopped. | | `402` | The team is out of credits or has no valid payment setup. | | `404` | The job doesn't exist or belongs to another team. | | `422` | `datums` is empty or the body has an unknown field. | Problems found while the batch runs, such as a missing loss input, mismatched tensor lengths, an unknown `loss_fn_config` key, or a datum longer than the model's limit, fail the future. Its `error.category` is `user`. # Get an interactive future Source: https://docs.fastino.ai/api-reference/training-jobs/interactive/get-future GET /v1/training/jobs/{job_id}/futures/{future_id} Poll an interactive future for its status and result. With wait=true, the request waits up to 25 seconds, and the service retains results for one hour. `GET /v1/training/jobs/{job_id}/futures/{future_id}` Every interactive-job call that does work returns a `future_id`. Poll the future until its `status` is `completed`, `failed`, or `cancelled`. Use `wait=true` to wait at most 25 seconds per request; a timeout can still return a nonterminal future. Results are retained for one hour. ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Interactive job ID. **future\_id** `string` *required* Future ID returned when the work was queued. **wait** `boolean` (default: false) Wait up to 25 seconds for an unfinished future before answering. Repeat the request until it finishes. ```bash cURL theme={null} curl "https://api.fastino.ai/v1/training/jobs/$TRAINING_JOB_ID/futures/$FUTURE_ID?wait=true" \ -H "X-API-Key: $FASTINO_API_KEY" ``` ## Response **future\_id** `string` The future. **job\_id** `string` The job. **type** `string` `create`, `load`, `forward`, `forward_backward`, `optim_step`, `save`, or `sample`. **status** `string` `pending`, `running`, `completed`, `failed`, or `cancelled`. **queue\_state** `string | null` While unfinished: `active`, or `paused_capacity` while GPU capacity warms up. **queue\_state\_reason** `string | null` A human-readable capacity explanation while `queue_state` is `paused_capacity`; otherwise `null`. **result** `any` Once `completed`: * `forward` and `forward_backward`: `loss_fn_outputs` (one entry of tensors per datum, such as `logprobs`) and `metrics`. * `sample`: `sequences`, each with `tokens`, `logprobs`, and `stop_reason`, plus `prompt_logprobs` when requested. * `save`: the checkpoint path. * Other types: an acknowledgement. **error** `object | null` When `failed` or `cancelled`: `message`, and `category` (`user` for a problem with the request, `server` for a Fastino problem). Token arrays in the sample result below are illustrative placeholders. Decode real results with the tokenizer for the job's `base_model`. ```json Pending theme={null} { "future_id": "FUTURE_ID", "job_id": "SESSION_ID:train:0", "type": "forward_backward", "status": "pending", "queue_state": "paused_capacity", "queue_state_reason": null, "result": null, "error": null } ``` ```json Completed sample theme={null} { "future_id": "FUTURE_ID", "job_id": "SESSION_ID:train:0", "type": "sample", "status": "completed", "queue_state": null, "queue_state_reason": null, "result": { "sequences": [ {"tokens": [59604, 13, 151645], "logprobs": [-0.21, -0.05, -0.01], "stop_reason": "stop", "topk_logprobs": null} ], "prompt_logprobs": null, "topk_prompt_logprobs": null, "prompt_cache_hit_tokens": 0 }, "error": null } ``` | Status | Meaning | | - | - | | `404` | The job or future doesn't exist, belongs to another team, is attached to a different job, or its request record was removed after about seven days. | | `410` | Inspect `error.message`. A lost operation can be resubmitted. If the result expired after its one-hour retention window, the operation may already have run; do not replay a mutating operation until you reconcile checkpoints and your durable loop record. See [Training loop](/training/training-loop) and [Checkpoints](/training/checkpoints). | # Look up a training operation Source: https://docs.fastino.ai/api-reference/training-jobs/interactive/get-operation GET /v1/training/operations/{idempotency_key} Recover the job and future belonging to an Idempotency-Key without submitting work again. `GET /v1/training/operations/{idempotency_key}` Send the original key used on a native interactive POST or an encoder job create. Keys are team-scoped. `not_found` means no receipt is visible, including while a native call is still admitting before its job is recorded; it does not prove the call never arrived. An `accepted` receipt means the job was recorded, not that execution succeeded. Use the original future to read its outcome when one is available. A stop has no future; encoder creates return their job only. To retry an uncertain native request, resend the same body, route and key. A different request under the same key returns 422; an in-progress first call returns 409. Use a new key for intentionally new work. Receipt retention/expiry is not a guarantee of this endpoint. **X-API-Key** `string` *required* Fastino API key. **idempotency\_key** `string` *required* Idempotency-Key. ```json theme={null} { "idempotency_key": "training-step-1", "status": "accepted", "operation": "forward-backward", "job_id": "SESSION_ID:train:0", "future_id": "FUTURE_ID", "future_status": "completed" } ``` # Load training weights Source: https://docs.fastino.ai/api-reference/training-jobs/interactive/load-weights POST /v1/training/jobs/{job_id}/load-weights Queue a load into an interactive job from a state name or this job's tinker:// path. Set optimizer to restore optimizer state, then poll the future_id. `POST /v1/training/jobs/{job_id}/load-weights` Restores one of this job's `weights/` checkpoints into the same job, for example to roll back a bad update. To continue from a checkpoint in a new job, pass its path as `from_checkpoint` to [`POST /v1/training/jobs/create-model`](/api-reference/training-jobs/interactive/create-model). ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Interactive job ID. **path** `string` *required* The state name saved by this job, or this job's own `tinker:///weights/` path. **optimizer** `boolean` (default: false) Also restore the optimizer state. ```bash cURL theme={null} curl -X POST "https://api.fastino.ai/v1/training/jobs/$TRAINING_JOB_ID/load-weights" \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"path": "step-000100", "optimizer": true}' ``` ```json Response theme={null} { "future_id": "FUTURE_ID", "job_id": "SESSION_ID:train:0", "type": "load" } ``` | Status | Meaning | | - | - | | `400` | `path` is another job's checkpoint or a sampler checkpoint, or the job was stopped. | | `404` | The job doesn't exist or belongs to another team. | # Queue an optimizer step Source: https://docs.fastino.ai/api-reference/training-jobs/interactive/optim-step POST /v1/training/jobs/{job_id}/optim-step Queue an optimizer step over accumulated gradients on an interactive training job. The request body is optional, and the response returns a future_id to poll. `POST /v1/training/jobs/{job_id}/optim-step` Applies the gradients accumulated by forward-backward passes since the last step, using AdamW. Operations run in the order the job receives them. Although you can pre-queue this call, wait until the forward-backward future is `completed` before queueing it: a pre-queued optimizer step can still run after the forward-backward future `failed` or was `cancelled`. See the [training loop](/training/training-loop). ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Interactive job ID. The JSON body is optional. **adam\_params** `object` AdamW parameters. Omitted fields use their defaults. **properties** **learning\_rate** `number` (default: 0.0001) Learning rate, `>= 0`. **beta1** `number` (default: 0.9) From `0` up to, but not including, `1`. **beta2** `number` (default: 0.95) From `0` up to, but not including, `1`. **eps** `number` (default: 1e-12) `> 0`. **weight\_decay** `number` (default: 0) `>= 0`. **grad\_clip\_norm** `number` (default: 0) Gradient-norm clip, `>= 0`. `0` disables clipping. ```bash cURL theme={null} curl -X POST "https://api.fastino.ai/v1/training/jobs/$TRAINING_JOB_ID/optim-step" \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"adam_params": {"learning_rate": 0.0001}}' ``` ## Response ```json Response theme={null} { "future_id": "FUTURE_ID", "job_id": "SESSION_ID:train:0", "type": "optim_step" } ``` The completed future's `result` holds the step's metrics. | Status | Meaning | | - | - | | `400` | An Adam parameter is out of range, or the job was stopped. | | `404` | The job doesn't exist or belongs to another team. | | `422` | The body has an unknown field. | # Save training weights Source: https://docs.fastino.ai/api-reference/training-jobs/interactive/save-weights POST /v1/training/jobs/{job_id}/save-weights Save an interactive job's LoRA weights and optimizer state under a name. The response includes a future_id, a weights checkpoint ID, and its tinker:// path. `POST /v1/training/jobs/{job_id}/save-weights` Saves the job's LoRA weights and optimizer state as `weights/`. You can [load](/api-reference/training-jobs/interactive/load-weights) it back into the same job, or [start a new job](/api-reference/training-jobs/interactive/create-model) from it. To sample or download weights, save them with [`POST /v1/training/jobs/{job_id}/save-weights-for-sampler`](/api-reference/training-jobs/interactive/save-weights-for-sampler) instead. The save runs in order with the job's other calls. ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Interactive job ID. **name** `string` *required* 1–128 characters from `A-Z`, `a-z`, `0-9`, `.`, `_`, and `-`. **ttl\_seconds** `integer | null` Delete the checkpoint automatically after this many seconds, from `3600` (1 hour) to `315360000` (10 years). Omit it or send `null` to keep the checkpoint until you delete it. Live checkpoints count toward [storage usage](/api-reference/training-jobs/interactive/storage-usage). **overwrite** `boolean` (default: false) Replace a state checkpoint with the same name. **user\_metadata** `object` String key-value metadata stored with the checkpoint. ```bash cURL theme={null} curl -X POST "https://api.fastino.ai/v1/training/jobs/$TRAINING_JOB_ID/save-weights" \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "step-000100"}' ``` ## Response **future\_id** `string` The `save` future. **checkpoint\_id** `string` `weights/`. **path** `string` Full checkpoint path. Pass it as `from_checkpoint` when you create a job. ```json Response theme={null} { "future_id": "FUTURE_ID", "job_id": "SESSION_ID:train:0", "type": "save", "checkpoint_id": "weights/step-000100", "path": "tinker://SESSION_ID:train:0/weights/step-000100" } ``` | Status | Meaning | | - | - | | `400` | The name has invalid characters or length, the TTL is out of range, or the job was stopped. | | `404` | The job doesn't exist or belongs to another team. | | `422` | The body is missing `name` or has an unknown field. | # Save sampler weights Source: https://docs.fastino.ai/api-reference/training-jobs/interactive/save-weights-for-sampler POST /v1/training/jobs/{job_id}/save-weights-for-sampler Save an interactive job's LoRA weights under a name for sampling and adapter download. The response includes a future_id, checkpoint ID, and tinker:// path. `POST /v1/training/jobs/{job_id}/save-weights-for-sampler` Saves the job's LoRA weights as `sampler_weights/`. You can [sample](/api-reference/training-jobs/interactive/sample) from it, also after the job is stopped, or [download](/api-reference/training-jobs/download-checkpoint) it as an adapter archive. A decoder's download is a standard Hugging Face PEFT adapter for the public base model. It has no optimizer state, so a job can't load it or start from it; use [`POST /v1/training/jobs/{job_id}/save-weights`](/api-reference/training-jobs/interactive/save-weights) for that. The save runs in order with the job's other calls. ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Interactive job ID. **name** `string` *required* 1–128 characters from `A-Z`, `a-z`, `0-9`, `.`, `_`, and `-`. **ttl\_seconds** `integer | null` Delete the checkpoint automatically after this many seconds, from `3600` (1 hour) to `315360000` (10 years). Omit it or send `null` to keep the checkpoint until you delete it. Live checkpoints count toward [storage usage](/api-reference/training-jobs/interactive/storage-usage). **user\_metadata** `object` String key-value metadata stored with the checkpoint. ```bash cURL theme={null} curl -X POST "https://api.fastino.ai/v1/training/jobs/$TRAINING_JOB_ID/save-weights-for-sampler" \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "step-000100", "ttl_seconds": 86400}' ``` ## Response **future\_id** `string` The `save` future. **checkpoint\_id** `string` `sampler_weights/`. **path** `string` Full checkpoint path. ```json Response theme={null} { "future_id": "FUTURE_ID", "job_id": "SESSION_ID:train:0", "type": "save", "checkpoint_id": "sampler_weights/step-000100", "path": "tinker://SESSION_ID:train:0/sampler_weights/step-000100" } ``` | Status | Meaning | | - | - | | `400` | The name has invalid characters or length, the TTL is out of range, or the job was stopped. | | `404` | The job doesn't exist or belongs to another team. | | `422` | The body is missing `name` or has an unknown field. | # List training jobs Source: https://docs.fastino.ai/api-reference/training-jobs/list GET /v1/training/jobs Call GET /v1/training/jobs to list config and interactive jobs visible to your account. `GET /v1/training/jobs` Returns config and interactive training jobs visible to the authenticated account. Without `type`, config and interactive jobs are interleaved by `created_at`, newest first. If two jobs have the same timestamp, the config job appears first. Pass `type=interactive` to list only interactive jobs. ## Request **X-API-Key** `string` *required* Your Fastino API key. **status** `string` Filter both job types by status. Interactive jobs support `creating`, `active`, `stopping`, `stopped`, and `failed`; `running` also matches `active`, while `errored` and `error` match `failed`. `running`, `errored`, `error`, `stopped`, and `failed` can match both types. `creating`, `active`, and `stopping` match only interactive jobs; other config statuses match only config jobs. For config jobs, `status=complete` returns jobs persisted as `complete`, `artifact_ready`, or `deployed`. **type** `string` Filter by `config` or `interactive`. **project\_id** `string` Filter by project ID. **limit** `integer` (default: 200) Page size from `1` through `200`. **offset** `integer` (default: 0) Number of matching jobs to skip. ```bash cURL theme={null} curl "https://api.fastino.ai/v1/training/jobs?type=config&status=complete&limit=50&offset=0" \ -H "X-API-Key: $FASTINO_API_KEY" ``` ## Response **success** `boolean` Whether the request succeeded. **training\_jobs** `object[]` Training-job records for this page. Every record includes `id` and `created_at`. Interactive records also repeat `id` in `job_id` and `training_run_id` for API and SDK compatibility, and include `status`, `stop_reason`, `error_message`, and `is_terminal_status`. Poll an interactive job by `id` until the terminal flag is true. A record with `type: "config"` and `source: "interactive_checkpoint"` is the served model created from an interactive sampler checkpoint. Its config-training fields, including epochs, batch size, learning rate, and validation percentage, are `null`. **count** `integer` Number of jobs in this page. **total** `integer` Total number of matching jobs before pagination. **has\_more** `boolean` Whether another page exists after this one. ```json Response theme={null} { "success": true, "training_jobs": [], "count": 0, "total": 0, "has_more": false } ``` Invalid pagination values return `422`. See the [config-job lifecycle](/training#config-job-lifecycle) for the complete set of persisted statuses. # Get training logs Source: https://docs.fastino.ai/api-reference/training-jobs/logs GET /v1/training/jobs/{job_id}/logs Retrieve a point-in-time snapshot of a Fastino training job's output logs. `GET /v1/training/jobs/{job_id}/logs` This operation is config-only; after normal feature and permission checks, an interactive job ID returns `400`, so inspect each interactive operation through its future instead. Returns structured `stdout`, `stderr`, and `system` entries. This endpoint does not stream; poll it to follow a running job. ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Training-job UUID. ```bash cURL theme={null} curl https://api.fastino.ai/v1/training/jobs/YOUR_TRAINING_JOB_ID/logs \ -H "X-API-Key: $FASTINO_API_KEY" ``` ## Response **job\_id** `string` Training-job UUID. **logs** `object[]` Log entries. Each entry contains `id`, `job_id`, `timestamp`, `level`, `message`, and `source`. Fastino emits `stdout`, `stderr`, or `system` as the source. The API schema represents this field as a string rather than a closed enum. **total\_logs** `integer` Number of entries returned. ```json Response theme={null} { "job_id": "YOUR_TRAINING_JOB_ID", "logs": [ { "id": "LOG_ID", "job_id": "YOUR_TRAINING_JOB_ID", "timestamp": "2026-09-22T20:00:00Z", "level": "INFO", "message": "Epoch 2 completed", "source": "stdout" } ], "total_logs": 1 } ``` An unknown or inaccessible job returns `404`. # Push a trained model to Hugging Face Hub Source: https://docs.fastino.ai/api-reference/training-jobs/push-to-hub POST /v1/training/jobs/{job_id}/push-to-hub Publish a completed training artifact to Hugging Face Hub with POST /v1/training/jobs/{job_id}/push-to-hub, giving the target repo_id and hf_token. `POST /v1/training/jobs/{job_id}/push-to-hub` This operation is config-only; after normal feature and permission checks, an interactive job ID returns `400`, and interactive jobs have no Push to Hub operation. Publish a completed training artifact to Hugging Face Hub. # Stop a training job Source: https://docs.fastino.ai/api-reference/training-jobs/stop POST /v1/training/jobs/{job_id}/stop Stop a running Fastino training job while preserving existing checkpoints. `POST /v1/training/jobs/{job_id}/stop` Stops a running job and preserves checkpoints created before the stop. For an interactive job, the request returns immediately and rejects new calls. Already queued operations may finish before resources are released, and usage may continue until that release. ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Config-job UUID or interactive job ID. ### Config job The JSON body is optional for a config job. **reason** `string` Why the job was stopped. **scores** `object` Numeric metrics used to make the stop decision. **checkpoint** `string` Checkpoint path or step associated with the stop. ### Interactive job Send no request body. The response includes the verified common fields `success`, `job_id`, and `status`. ### Config-job request example ```bash cURL theme={null} curl -X POST https://api.fastino.ai/v1/training/jobs/YOUR_TRAINING_JOB_ID/stop \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"reason": "Validation loss stopped improving"}' ``` ### Interactive-job request example ```bash cURL theme={null} curl -X POST https://api.fastino.ai/v1/training/jobs/YOUR_INTERACTIVE_JOB_ID/stop \ -H "X-API-Key: $FASTINO_API_KEY" ``` ## Config-job response ```json Response theme={null} { "success": true, "message": "Training job stopped successfully. Checkpoints preserved.", "job_id": "YOUR_TRAINING_JOB_ID", "status": "stopped" } ``` ```json 202 — cancellation pending theme={null} { "success": true, "message": "Cancellation in progress. The job moves to 'stopped' once the provider confirms; checkpoints are preserved.", "job_id": "YOUR_TRAINING_JOB_ID", "status": "stopping" } ``` The `message` field, `202` response, and polling rule apply only to config jobs. Poll `GET /v1/training/jobs/{job_id}` after a config-job `202`; do not repeat the stop request while cancellation is pending. ## Interactive-job response An interactive job uses the same operation without a body. It returns the common fields `success`, `job_id`, and `status`. Do not require the config-only `message` field from an interactive response. ```json Response theme={null} { "success": true, "job_id": "YOUR_INTERACTIVE_JOB_ID", "status": "stopped" } ``` ## Config-job statuses The following statuses and error details apply only to config jobs. | Status | Meaning | | - | - | | `200` | The job is stopped and existing checkpoints remain available. | | `202` | Cancellation is in progress while the provider confirms it. | | `400` | The config-job ID or request is invalid. | | `409 training_job_already_finished` | The job reached a terminal state before the stop. | | `409 cancellation_unconfirmed` | Provider cancellation was not confirmed. Read the job state, then retry when appropriate. | | `422` | The config-job JSON request body is invalid. | ## Config-job authorization For config jobs, this operation requires the Owner, Admin, or Editor team role. Other roles receive `403 Forbidden`. The native interactive handler uses the interactive runtime's caller authorization; do not infer config-job RBAC from this shared path. # Synchronize a training job Source: https://docs.fastino.ai/api-reference/training-jobs/sync POST /v1/training/jobs/{job_id}/sync Refresh the training-job status from its training provider by calling POST /v1/training/jobs/{job_id}/sync with the ID of the training job. `POST /v1/training/jobs/{job_id}/sync` This operation is config-only; after normal feature and permission checks, an interactive job ID returns `400`, while interactive jobs expose current state through `GET /v1/training/jobs/{job_id}` and futures. Refresh the training-job status from its training provider. # Terminate a training job Source: https://docs.fastino.ai/api-reference/training-jobs/terminate POST /v1/training/jobs/{job_id}/terminate Terminate a config training job, preserving checkpoints unless deletion is explicitly requested. `POST /v1/training/jobs/{job_id}/terminate` This operation is config-only; after normal feature and permission checks, an interactive job ID returns `400`, so stop an interactive job with `POST /v1/training/jobs/{job_id}/stop` instead. Stops an active `config` job and requests provider cancellation. Existing checkpoints and artifacts are preserved by default. > [!WARNING] > > Setting `delete_checkpoints` to `true` permanently deletes the job's > checkpoints and artifacts after cancellation is confirmed. This cannot be > undone. ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Training-job UUID. The JSON body is optional. **delete\_checkpoints** `boolean` (default: false) Permanently delete checkpoints and artifacts after cancellation is confirmed. ```bash cURL theme={null} curl -X POST https://api.fastino.ai/v1/training/jobs/YOUR_TRAINING_JOB_ID/terminate \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"delete_checkpoints": false}' ``` ## Response ```json 200 — terminated theme={null} { "success": true, "message": "Training job terminated. Checkpoints preserved (pass delete_checkpoints=true to remove them).", "job_id": "YOUR_TRAINING_JOB_ID", "deleted_checkpoints": 0, "status": "terminated" } ``` ```json 202 — cancellation pending theme={null} { "success": true, "message": "Termination in progress. The job moves to 'terminated' once the provider confirms; checkpoints are preserved.", "job_id": "YOUR_TRAINING_JOB_ID", "deleted_checkpoints": 0, "status": "stopping" } ``` Poll `GET /v1/training/jobs/{job_id}` after a `202`; do not repeat the termination request while cancellation is pending. | Status | Meaning | | - | - | | `200` | The job is terminated. | | `202` | Termination is in progress while the provider confirms cancellation. | | `400` | `job_id` is not a valid config-job UUID, or it identifies an interactive job; use the interactive stop route instead. | | `409 training_job_already_finished` | The job reached a terminal state before termination. | | `409 cancellation_unconfirmed` | Cancellation was not confirmed and may be retried. | | `422` | The JSON request body is invalid. | ## Authorization Requires the Owner, Admin, or Editor team role. Other roles receive `403 Forbidden`. # Rename a trained model Source: https://docs.fastino.ai/api-reference/training-jobs/update-model-name PATCH /v1/training/jobs/{job_id}/model-name Call PATCH /v1/training/jobs/{job_id}/model-name to rename a trained model. New names use 1-64 letters, numbers, hyphens, or underscores. `PATCH /v1/training/jobs/{job_id}/model-name` This operation is config-only; after normal feature and permission checks, an interactive job ID returns `400`, so set `model_name` when deploying an interactive sampler checkpoint instead. Updates the model name on a training job. ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Training-job UUID. **model\_name** `string` *required* New model name. Length: 1–64 characters. Use letters, numbers, hyphens, or underscores. ```bash cURL theme={null} curl -X PATCH https://api.fastino.ai/v1/training/jobs/YOUR_TRAINING_JOB_ID/model-name \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model_name": "my-model-name"}' ``` ## Response ```json Response theme={null} { "success": true, "message": "Model name updated successfully", "job_id": "YOUR_TRAINING_JOB_ID", "model_name": "my-model-name" } ``` Invalid names return `422`. An unknown or inaccessible job returns `404`. ## Authorization Requires the Owner, Admin, or Editor team role. Other roles receive `403 Forbidden`. # Update a training job's project Source: https://docs.fastino.ai/api-reference/training-jobs/update-project PATCH /v1/training/jobs/{job_id} Call PATCH /v1/training/jobs/{job_id} to assign a training job to a project, or send null to unassign it. Related deployments and inferences stay put. `PATCH /v1/training/jobs/{job_id}` This operation is config-only; after normal feature and permission checks, an interactive job ID returns `400`. Existing Tinker clients can reassign the owning session's project through the SDK, which updates the job's list project and later billing. Updates only the job's `project_id`. ## Request **X-API-Key** `string` *required* Your Fastino API key. **job\_id** `string` *required* Training-job UUID. **project\_id** `string | null` Project UUID to assign. Send `null` to unassign the job. ```bash cURL theme={null} curl -X PATCH https://api.fastino.ai/v1/training/jobs/YOUR_TRAINING_JOB_ID \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"project_id": "YOUR_PROJECT_ID"}' ``` ## Response Returns `200` with `success` and `message`. ```json Response theme={null} { "success": true, "message": "Training job updated" } ``` > [!NOTE] > > This changes the training job's project label only. It does not move related deployments, inferences, or evaluation runs. Unknown request fields, including other training-job fields, return `422`. An unavailable job or project returns a request-specific `4xx` error. ## Authorization Requires the Owner, Admin, or Editor team role. Other roles receive `403 Forbidden`. # List available and trainable models Source: https://docs.fastino.ai/api-reference/training/base-models GET /v1/base-models Query the live Fastino model catalog and filter it by inference, training, or architecture capability. `GET /v1/base-models` Query the live Fastino model catalog and filter it by inference, training, or architecture capability. # Training API reference Source: https://docs.fastino.ai/api-reference/training/overview Reference for the public Training REST surface: base-model discovery, datasets, managed config jobs, lifecycle operations, and native interactive operations. Use these contracts for field-level details. Start with the lifecycle guides when building an end-to-end training workflow. The public REST surface covers: * Base-model discovery and dataset management * Managed `config` job creation with `POST /v1/training/jobs` for GLiNER encoders * [Interactive jobs](/api-reference/training-jobs/interactive/create-model) for decoder training: `POST /v1/training/jobs/create-model`, then forward-backward passes, optimizer steps, checkpoints, and sampling under `/v1/training/jobs/{job_id}` * Canonical lifecycle operations under `/v1/training/jobs` for both `config` and `interactive` jobs Auto Train remains private access and has no public API contract. > **[Training lifecycle](/training)** > > Choose a model, create a job, poll it, and work with the resulting artifact. > **[Encoder Quickstart](/training/encoder-quickstart)** > > Fine-tune a GLiNER encoder with managed training. > **[Decoder Quickstart](/training/decoder-quickstart)** > > Train Nemotron or Qwen with an interactive job. > **[Upload Dataset](/concepts/datasets)** > > Prepare JSONL, upload it, process it, and confirm a ready version. # Fastino API authentication: generate and use API keys Source: https://docs.fastino.ai/authentication Authenticate Fastino API requests with the X-API-Key header or a Bearer token, then create, rotate, and revoke API keys in the Fastino dashboard settings. Most Fastino API operations require your API key. Explicitly public catalog routes such as `GET /v1/models` can be called without one. Authenticated operations use a simple header-based scheme-no OAuth flow or token exchange is required. Your key identifies you and determines which resources and rate limits apply to your requests. ## Getting an API key 1. Log in at [Fastino](https://agent.fastino.ai). 2. Go to **Settings** → **API Keys**. 3. Click **Create key**, give it a name, and copy the value shown. Store your key in an environment variable (for example `FASTINO_API_KEY`) rather than hard-coding it in source files. New Fastino keys start with `fast_sk_`. Legacy `pio_sk_` keys are retired; create a replacement in the dashboard before calling the Fastino API. ## Passing your API key Include your key in the `X-API-Key` header on native Fastino requests: ```bash cURL theme={null} curl https://api.fastino.ai/v1/models \ -H "X-API-Key: $FASTINO_API_KEY" ``` OpenAI- and Anthropic-compatible SDKs conventionally send the same key as a Bearer token. Set their `api_key` option to `$FASTINO_API_KEY`; the SDK adds `Authorization: Bearer ...` for you. ## Managing keys Create, rotate, and revoke keys from **Settings → API Keys** in the Fastino dashboard. The public API does not expose API-key management operations. ### Rotation checklist 1. Create the replacement key and copy it immediately. 2. Update each service through its secret manager or `FASTINO_API_KEY` environment variable. 3. Verify requests succeed with the replacement. 4. Revoke the old key in the dashboard. Revocation is immediate and irreversible. ## Error responses | Status | Meaning | | - | - | | `401 Unauthorized` | The key is missing, malformed, expired, or revoked. | | `402 Payment Required` | The account has insufficient credits. Visit **Settings → Billing**. | > [!WARNING] > > Treat API keys as secrets. Never place them in source code, client-side applications, URLs, logs, documentation examples, or support messages. # Prepare and upload training datasets Source: https://docs.fastino.ai/concepts/datasets Format, upload, validate, and inspect NER or classification datasets before starting a Fastino GLiNER training job. Training jobs reference ready datasets by name. Prepare a JSONL file, upload it through the two-step dataset API, and confirm the processed version exists before calling `POST /v1/training/jobs`. ## Choose a dataset format Each line in the file must be one JSON object. Use one consistent shape throughout a dataset. ### Named entity recognition Use `text` plus an `entities` list of `[span, label]` pairs. Every span must appear in the text, but matching is case-insensitive: `"ada lovelace"` is valid for `"Ada Lovelace"`. Include negative examples with an empty list. ```jsonl theme={null} {"text":"Ada Lovelace worked in London.","entities":[["Ada Lovelace","PERSON"],["London","LOCATION"]]} {"text":"No tagged entities here.","entities":[]} ``` ### Classification Use `label` for single-label data or `labels` for multi-label data. Use the same field in every row. ```jsonl theme={null} {"text":"The setup was straightforward.","label":"positive"} {"text":"The request needs technical help.","label":"technical"} ``` ### GLiNER2 library format NER and classification uploads also accept GLiNER2's canonical `input` and `output` shape. For NER, map each entity label to its matching spans: ```jsonl theme={null} {"input":"Ada Lovelace worked in London.","output":{"entities":{"PERSON":["Ada Lovelace"],"LOCATION":["London"]}}} {"input":"No tagged entities here.","output":{"entities":{"PERSON":[],"LOCATION":[]}}} ``` For classification, `classifications` can contain one or several tasks in each row: ```jsonl theme={null} {"input":"jump now","output":{"classifications":[{"task":"action","labels":["jump","wait"],"true_label":["jump"]},{"task":"urgency","labels":["now","later"],"true_label":["now"]}]}} ``` Use one shape per row. Do not mix `text`, `label`, `labels`, or `entities` with `input` and `output` fields in the same row. ### Joint NER and classification A row can contain both `entities` and `label` to train both heads. Keep that same joint shape in every row, and do not mix single-label `label` with multi-label `labels`. ```jsonl theme={null} {"text":"Ada Lovelace worked in London.","entities":[["Ada Lovelace","PERSON"],["London","LOCATION"]],"label":"biography"} {"text":"No tagged entities here.","entities":[],"label":"other"} ``` ### Decoder Set `dataset_type` to `decoder` and give every row a `messages` array with chat roles and content. ```jsonl theme={null} {"messages":[{"role":"user","content":"What is 2+2?"},{"role":"assistant","content":"4"}]} ``` > [!NOTE] > > The dataset service accepts decoder datasets for fine-tune-agent and storage > workflows. Config jobs reject decoder base models, so don't treat > `dataset_type: decoder` as a direct config-job decoder-training path. > Interactive jobs don't accept a dataset name; read and tokenize the examples > in your application, then send tokenized datums as shown in the > [Decoder Quickstart](/training/decoder-quickstart). ## Upload a dataset ### 1. Reserve an upload URL ```bash theme={null} curl --fail-with-body -sS https://api.fastino.ai/v1/datasets/upload/url \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "dataset_name": "docs-example-ner", "filename": "training.jsonl", "dataset_type": "ner" }' | tee dataset-upload.json export PRESIGNED_URL="$(jq -r '.presigned_url' dataset-upload.json)" export DATASET_ID="$(jq -r '.dataset_id' dataset-upload.json)" export DATASET_VERSION="$(jq -r '.version_number' dataset-upload.json)" ``` The response contains a short-lived `presigned_url`, a `dataset_id`, and a `version_number`. The commands above retain all three values. Upload the exact file bytes to the presigned URL: ```bash theme={null} curl --fail-with-body -X PUT \ -H "Content-Type: application/octet-stream" \ --upload-file training.jsonl "$PRESIGNED_URL" ``` ### 2. Process the uploaded file ```bash theme={null} curl --fail-with-body -sS https://api.fastino.ai/v1/datasets/upload/process \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d "$(jq -n --arg dataset_id "$DATASET_ID" '{dataset_id: $dataset_id}')" ``` Processing returns `202`. Poll the dataset by name and select the entry whose `version_number` exactly matches the upload response. Continue until that version's `status` is `ready` or `failed`. If it is `failed`, stop and surface its `processing_error`; do not submit that version to training. ```bash theme={null} curl --fail-with-body -sS https://api.fastino.ai/v1/datasets/docs-example-ner \ -H "X-API-Key: $FASTINO_API_KEY" ``` ## Start training Pass the exact dataset name to the [training-job create endpoint](/api-reference/training-jobs/create): ```json theme={null} { "model_name": "my-ner-model", "base_model": "fastino/gliner2-base-v1", "datasets": [ {"name": "docs-example-ner", "version": "VERSION_NUMBER_FROM_UPLOAD"} ], "training_type": "lora" } ``` Use `GET /v1/base-models?supports_training=true` immediately before submission to select a currently trainable base model. ## Common blockers | Status | Cause | Action | | - | - | - | | `401` | Missing or invalid API key | Send `X-API-Key: $FASTINO_API_KEY` | | `404` | Dataset name does not exist | Confirm the exact name and wait for processing | | `failed` | Asynchronous content validation failed | Read `processing_error`, correct the JSONL, and upload a new version | | `422` | The request shape was rejected before processing | Correct the request fields before retrying | ## Dataset API contracts > **[Upload URL](/api-reference/datasets/upload-url)** > **[Process upload](/api-reference/datasets/process-upload)** > **[List datasets](/api-reference/datasets/list)** > **[Dataset versions](/api-reference/datasets/versions)** > **[Delete dataset](/api-reference/datasets/delete)** # Decision models for classification, routing, and scoring Source: https://docs.fastino.ai/concepts/decision-models Understand decision models for classification, routing, scoring, and confidence, and explore Fastino's decision model families. A **decision model** evaluates text or structured application state against caller-defined outcomes and returns structured decisions—labels, probabilities, scores, and confidence—instead of generated prose. Use decision models when application code must classify an input, select a route, score against a rubric, moderate content, or decide whether an action should proceed. ## Decision models vs. generative models | | Decision model | Generative model | | - | - | - | | Best for | Classification, routing, scoring, moderation, and gates | Open-ended generation, conversation, summarization, and coding | | Output | Structured answers over caller-defined outcomes | Generated text or tool calls | | Uncertainty | Explicit probabilities and confidence | Usually requires additional calibration or validation | | Application pattern | Act, route, or escalate from a bounded result | Generate, explain, plan, or transform content | The two model types can work together. A decision model can classify a request, select an agent or model, or gate an action before a generative model produces an open-ended result. ## Why use a decision model * **Structured by construction** — downstream code receives a bounded answer instead of prose that must be parsed. * **Caller-defined outcomes** — your application controls the permitted labels, routes, or levels. * **Explicit uncertainty** — probabilities and confidence let you automate clear cases and send ambiguous cases to a fallback or review path. ## Explore Fastino decision models > **[GLiDE](/concepts/glide)** > > Ask typed Noul, Choice, and Score questions against text or structured application state. > **[GLiNER 2.5 Decide](/concepts/gliner-2-5-decide)** > > Run schema-defined, single-label or multi-label classification over English text. To pull entities, relations, or structured records out of text, use GLiNER 2.5 Multi. > **[GLiNER 2.5 Multi](/concepts/gliner)** > > Extract entities, relations, and records from text in any supported language. # GLiDE: a decision model for typed questions Source: https://docs.fastino.ai/concepts/glide Learn what GLiDE is, when to use it, and where to start with typed decision questions. GLiDE (Generalized Lightweight Decision Engine) is a [decision model](/concepts/decision-models). It evaluates the application state you provide against one or more typed questions and returns structured answers, probabilities, and confidence across outcomes you define. GLiDE costs **\$0.04 per 1 million input tokens**. Output tokens are **free (\$0)**. See [Pricing](/pricing) for the current inference rates. ## Why GLiDE The same interface works for both routine classification and decisions involving arithmetic, code tracing, temporal logic, policy interpretation, or several related facts. Unlike a generative model, GLiDE does not write an answer in free-form text. Your application defines the permitted outcomes and can act directly on the returned probability distribution and confidence. ## When to use GLiDE | Use case | Example decision | | - | - | | Agent and tool routing | Select the next action while considering permissions and previous results | | High-risk action control | Execute, sandbox, request approval, or block an operation | | Incident response | Monitor, restart, roll back, isolate, or escalate | | Contracts and policies | Apply cross-references, dates, thresholds, and exceptions | | Model-output verification | Accept, reject, or request revision | | Everyday classification | Route tickets, moderate content, or score urgency | Use a generative model instead for open-ended writing, conversation, summarization, or code generation. ## Start building > **[Call GLiDE](/inference/systemone)** > > Authenticate and send a complete `POST /v1/systemone` request. > **[Choose a primitive](/concepts/glide-noul)** > > Start with Noul, Choice, or Score based on the answer shape your code needs. > **[Capabilities and limits](/concepts/glide-capabilities)** > > Review decision behavior, confidence, context limits, and unsupported shapes. > **[GLiDE guides](/guides/glide-routing)** > > Apply GLiDE to classification, routing, scoring, policy gates, and reranking. # Fastino GLiDE Agent Skill Source: https://docs.fastino.ai/concepts/glide-agent-skill Install Fastino's hosted GLiDE skill for Cursor, Claude Code, and Codex. The [Fastino GLiDE agent skill](https://docs.fastino.ai/.well-known/agent-skills/fastino-glide/SKILL.md) helps Cursor, Claude Code, and Codex use Fastino's hosted GLiDE decision model to classify, route, and score structured decisions, and integrate GLiDE inference into a project. ## Install Run this command from your project: ```bash theme={null} npx skills add https://docs.fastino.ai --skill fastino-glide ``` The installer lets you choose which supported agents receive the skill. Before using the skill, expose your Fastino API key to the agent's environment: ```bash theme={null} export FASTINO_API_KEY="..." ``` Then invoke it explicitly with `/fastino-glide`, or ask your agent for a classification, routing, or scoring decision built on GLiDE. ## Non-interactive installation Use the command for your agent to install the skill into the current project without prompts: ```bash Cursor theme={null} npx skills add https://docs.fastino.ai --skill fastino-glide -a cursor -y ``` ```bash Claude Code theme={null} npx skills add https://docs.fastino.ai --skill fastino-glide -a claude-code -y ``` ```bash Codex theme={null} npx skills add https://docs.fastino.ai --skill fastino-glide -a codex -y ``` ```text Any agent theme={null} "Install the Fastino GLiDE agent skill. Follow the installation instructions in Fastino's documentation at https://docs.fastino.ai/concepts/glide-agent-skill. Use one installation method appropriate for your agent environment. Then use the Fastino GLiDE skill when working on this project, especially for classification, routing, and scoring decisions with calibrated probabilities instead of generated text." ``` For Cursor, Claude Code, and Codex, the `-a` option selects the target agent and `-y` accepts the installation prompts, making those commands suitable for scripts and CI. ## Migrating from TypeSafe? Install the GLiDE skill, then copy the prompt below into your coding agent: ```text title="Copy this prompt" theme={null} Use the Fastino GLiDE skill to migrate this project from TypeSafe/Jev to Fastino GLiDE. Find every TypeSafe API and SDK integration, then: 1. Change the endpoint to https://api.fastino.ai/v1/systemone. 2. Replace TYPESAFE_API_KEY with FASTINO_API_KEY and send it as X-API-Key. 3. Replace jev-latest with fastino/GLiDE. 4. Expect the response model field to be glide. 5. Preserve state, question names, and primitive types. State may be empty when the question contains all the context. 6. Make every instruction a non-empty string or JSON object. GLiDE serializes objects to compact JSON text. Make Noul true/false criteria strings, and use ordered arrays for Score criteria where possible. 7. Remove unsupported top-level request fields. 8. Replace TypeSafe SDK calls with direct HTTP requests. Remove typesafe-sdk or @typesafe-ai/sdk dependencies and imports after replacing all TypeSafeClient, AsyncTypeSafeClient, question-constructor, and typed-response usage. 9. Convert SDK object access to decoded JSON access. Check non-2xx responses and use a read timeout of at least 300 seconds. 10. Where code uses TypeSafe's floating-point score, read GLiDE's expected_level. Use GLiDE's score only for the integer winning level. 11. Handle Score probabilities and legend as string-keyed maps, and expect legend values to be strings. 12. Replace 529 retry handling with bounded retries for transport failures, 425, and 503. Keep bounded backoff for 429 and honor Retry-After. 13. Update tests, model assertions, telemetry, and caches. Revalidate all decision thresholds on representative data. Do not change unrelated business logic. Show me every changed integration point and any behavior that could not be migrated mechanically. Follow https://docs.fastino.ai/inference/systemone for the canonical contract. ``` The request structure is similar, but Score semantics are different. See [Migrating from TypeSafe](/inference/systemone#migrating-from-typesafe) for more details. > **[View the skill](https://docs.fastino.ai/.well-known/agent-skills/fastino-glide/SKILL.md)** > > Review the complete instructions before installing. # GLiDE Capabilities Source: https://docs.fastino.ai/concepts/glide-capabilities Review GLiDE decision behavior, confidence, context limits, and unsupported request shapes. GLiDE evaluates caller-defined outcomes instead of generating prose. This page summarizes its technical behavior and boundaries. For a first request, start with [Call GLiDE](/inference/systemone). ## Decision capabilities * Evaluate a string, object, or array supplied as shared `state`. * Ask one or more named questions against that state. * Use [Noul](/concepts/glide-noul) for yes/no probabilities. * Use [Choice](/concepts/glide-choice) for one unordered option from a caller-defined set. * Use [Score](/concepts/glide-score) for one level on an ordered rubric. * Receive probabilities and confidence for every answer. * Evaluate decisions that depend on arithmetic, code traces, dates, policies, exceptions, and related facts in the supplied state. Each question is evaluated independently against the same state. ## Confidence and uncertainty The answer tells you what GLiDE concluded. `confidence` tells you how clearly the leading outcome separated from the alternatives. | Question type | Confidence formula | Range | | - | - | - | | Noul | Absolute value of `2 × noul − 1` | `0` at maximum uncertainty to `1` at either extreme | | Choice | `top1 − top2` | `0` for a tie to `1` for a dominant option | | Score | `top1 − top2` | `0` for a tie to `1` for a dominant level | A low-confidence answer is not necessarily incorrect. It means probability mass is spread across outcomes. Tune action and fallback thresholds on representative data rather than assuming a universal cutoff. ## Limits * Each rendered prompt—`state` plus one question—must fit within **65,536 tokens**. * Choice requires **2 to 255 options**. * Score accepts up to **255 levels**. * Every question is single-label. There is no multi-label primitive. * One request evaluates one shared `state`; multiple questions belong under `questions`. * `usage.input_tokens` sums internal passes across questions and can exceed 65,536 even when each rendered prompt fits. * An array `state` accepts up to **4 images** as `image_url` parts. * Each image must be JPEG, PNG, GIF, or WebP, at most **3.75 MiB** (3,932,160 bytes), and at most **25,000,000 pixels**. * Image URLs must be HTTPS on a public host, with no redirects. You can also send a base64 data URL. * GLiDE resizes each image to between 65,536 and 1,048,576 pixels, so each image adds 64 to 1,024 input tokens per question. See [Image input](/inference/systemone#image-input) for examples and error handling. ## Unsupported request shapes * `/v1/systemone` does not stream. * It does not accept a batch of independent states. * It does not currently accept fine-tuned deployment IDs. * Extra top-level request fields are rejected. * Choice cannot contain only one option. ## Evaluation On Decision Index 0.2.1, GLiDE scored **64.81** compared with Jev's published **57.91**, leading all five evaluation areas and 31 of 38 benchmarks. > **[Call GLiDE](/inference/systemone)** > > Review the complete request, response, error handling, and migration guidance. # Choice Source: https://docs.fastino.ai/concepts/glide-choice Ask GLiDE to select one caller-defined option and return the full probability distribution. A **Choice** question asks GLiDE to pick one option from a fixed, caller-defined set of 2 to 255 named options. The response includes the selected option, a confidence value, and a full probability distribution over every option you defined. Use a Choice when the answer is one of several unordered categories: which team should handle a ticket, which category a product belongs to, which language a snippet is written in. ## Request **type** `string` *required* Always `"choice"`. **instructions** `string | object` *required* The question to evaluate, as a non-empty string or non-empty JSON object. An object is serialized to compact JSON text. **criteria** `object` *required* An object mapping 2 to 255 option keys to description strings, e.g. `{"billing": "Payment or charge disputes", "returns": "Refund or return requests"}`. A single option is invalid because it cannot represent a decision or meaningful confidence margin. Both the option names and their descriptions are sent to the model, so write descriptions that separate similar-sounding options from each other. ```bash cURL theme={null} curl -s https://api.fastino.ai/v1/systemone \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "fastino/GLiDE", "state": "Refund request: the receipt is attached, the purchase was 10 days ago, and refunds are allowed within 30 days.", "questions": { "department": { "type": "choice", "instructions": "Which team should handle this request?", "criteria": { "billing": "Payment or charge disputes", "returns": "Refund or return requests", "shipping": "Delivery or shipping issues" } } } }' ``` ## Answer object The matching entry inside `answers` is: ```json theme={null} { "department": { "type": "choice", "choice": "returns", "confidence": 0.9992611288391886, "probabilities": { "billing": 0.00031500429476013744, "returns": 0.9995761331339488, "shipping": 0.00010886257129113499 } } } ``` * `choice` - the option with the highest probability. * `probabilities` - the full distribution across every option you defined; keys match your `criteria` keys and sum to \~1. * `confidence` - `top1 − top2`, the probability margin between the best and second-best option, from `0` (two options tied) to `1` (one option has \~all the probability mass). See [confidence and uncertainty](/concepts/glide-capabilities#confidence-and-uncertainty) for how to act on it. ## Using the result ```python theme={null} answer = response["answers"]["department"] queue_map = {"billing": "billing-team", "returns": "returns-desk", "shipping": "logistics"} target_queue = queue_map[answer["choice"]] if answer["confidence"] < 0.5: notify("routing uncertain - runner-up may also apply") ``` ## Ask every question you need in one call Evaluate several Choice questions against the same `state` in a single request rather than one request per question - they're answered independently, so adding a question costs tokens but barely changes latency. A support-triage call might ask `department`, `urgency`, and `tone` together instead of three round trips; your code can act on `department` and ignore the rest until it needs them. See [Combining multiple questions](/inference/systemone#combining-multiple-questions) for a worked example. Give the model the full list of real options rather than a shortlist - a Choice question accepts 2 to 255 options, and each one costs only a few tokens. Add an `other` or `none of the above` option when the input might not cover every case, so GLiDE has somewhere to put the probability mass instead of forcing a bad match onto one of your named options. # Noul Source: https://docs.fastino.ai/concepts/glide-noul Ask GLiDE a yes-or-no question and receive the calibrated probability of true. A **Noul** question asks a yes/no question and returns a single calibrated probability between `0` and `1` - the probability the answer is "yes." There's no separate label field; you threshold the probability yourself to make a binary decision. Use a Noul when the probability itself is the useful signal, not just a boolean. "Does this request qualify for a refund?" might return `0.999` (clearly yes) or `0.52` (genuinely ambiguous) - a plain `true`/`false` would hide that difference. > [!TIP] > > Noul vs. Score: a Noul at `0.5` means maximum uncertainty between yes and no - it doesn't express degree. If you need to measure degree (urgency, severity, frustration), use [Score](/concepts/glide-score) with defined levels instead. ## Request **type** `string` *required* Always `"noul"`. **instructions** `string | object` *required* The yes/no question to evaluate, as a non-empty string or non-empty JSON object. An object is serialized to compact JSON text. **criteria** `object` Optional labels for the outcomes, with `true` and `false` description keys, e.g. `{"true": "Qualifies", "false": "Does not qualify"}`. Omit it to use `"Yes"` and `"No"`. ```bash cURL theme={null} curl -s https://api.fastino.ai/v1/systemone \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "fastino/GLiDE", "state": "Refund request: the receipt is attached, the purchase was 10 days ago, and refunds are allowed within 30 days.", "questions": { "refund_allowed": { "type": "noul", "instructions": "Does this request qualify for a refund?", "criteria": { "true": "Qualifies", "false": "Does not qualify" } } } }' ``` ## Answer object The matching entry inside `answers` is: ```json theme={null} { "refund_allowed": { "type": "noul", "noul": 0.99767683794902, "confidence": 0.9953536758980399 } } ``` * `noul` - the probability the answer is "yes." `0.999` is a strong qualifying signal. * `confidence` - `|2 × noul − 1|`, from `0` (maximum uncertainty, `noul = 0.5`) to `1` (fully certain, `noul = 0` or `1`). See [confidence and uncertainty](/concepts/glide-capabilities#confidence-and-uncertainty) for how to act on it. ## Using the result ```python theme={null} answer = response["answers"]["refund_allowed"] if answer["noul"] > 0.8: action = "auto_approve" elif answer["noul"] < 0.2: action = "auto_deny" else: action = "human_review" # genuinely ambiguous - don't force a threshold here ``` Tune the thresholds (`0.8` / `0.2` above) on real data for your use case rather than assuming they transfer - probability and confidence are calibrated per model, not guaranteed to map onto any particular business tolerance for ambiguity. # Score Source: https://docs.fastino.ai/concepts/glide-score Ask GLiDE to evaluate an ordered rubric and return discrete and continuous results. A **Score** question rates a situation on an ordered scale you define. It returns a discrete `score` (the winning level index) plus `expected_level`, a probability-weighted continuous estimate across all levels, per-level `probabilities`, and a `legend` echoing your level descriptions back by index. Use a Score when the answer is a position on a scale with defined levels - urgency, severity, sentiment intensity - rather than an unordered category. > [!TIP] > > Score vs. Noul: if you just need a binary gate, use [Noul](/concepts/glide-noul) instead - it's simpler and returns a single probability rather than a distribution over levels. ## Request **type** `string` *required* Always `"score"`. **instructions** `string | object` *required* The question to evaluate, as a non-empty string or non-empty JSON object. An object is serialized to compact JSON text. **criteria** `string[] | object` *required* An ordered array of level descriptions, index `0` is the lowest level: `["low urgency, can wait", "medium urgency, handle soon", "high urgency, handle immediately"]`. Also accepts an object with numeric-string keys (e.g. `{"1": "...", "3": "...", "5": "..."}`) - keys are sorted and then discarded, and the response is always re-indexed `0..N-1` regardless of the keys you used. Supply between 1 and 255 levels. ```bash cURL theme={null} curl -s https://api.fastino.ai/v1/systemone \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "fastino/GLiDE", "state": "Refund request: the receipt is attached, the purchase was 10 days ago, and refunds are allowed within 30 days.", "questions": { "urgency": { "type": "score", "instructions": "How urgent is this request?", "criteria": [ "low urgency, can wait", "medium urgency, handle soon", "high urgency, handle immediately" ] } } }' ``` ## Answer object The matching entry inside `answers` is: ```json theme={null} { "urgency": { "type": "score", "score": 0, "expected_level": 0.27621539375795195, "confidence": 0.4999999998141525, "probabilities": { "0": 0.7412615353520668, "1": 0.24126153553791435, "2": 0.017476929110018805 }, "legend": { "0": "low urgency, can wait", "1": "medium urgency, handle soon", "2": "high urgency, handle immediately" } } } ``` * `score` - a discrete integer index, the argmax level. * `expected_level` - `Σ(level × probability)`, the continuous, probability-weighted position across all levels. Use it when you want finer-grained thresholds than the discrete index provides. * `legend` isn't generated by the model - the API builds it from your own `criteria`, indexed. * `confidence` - `top1 − top2`, same formula as Choice, from `0` (two adjacent levels tied) to `1` (one level has \~all the probability mass). See [confidence and uncertainty](/concepts/glide-capabilities#confidence-and-uncertainty) for how to act on it. ## Using the result ```python theme={null} answer = response["answers"]["urgency"] if answer["score"] >= 2: action = "page_oncall" elif answer["expected_level"] >= 1.5: action = "escalate" # closer to the next level up than a clean 1 else: action = "standard_queue" ``` # GLiNER2.5 Source: https://docs.fastino.ai/concepts/gliner Learn when and how to use GLiNER2.5 Multi for multilingual, schema-driven information extraction. GLiNER2.5 Multi is Fastino's multilingual, multi-task information-extraction model. Use one schema to extract entities, classify text, build structured records, identify relations, and attach attributes to spans. ## When to use GLiNER 2.5 Use GLiNER2.5 Multi when extraction or multilingual coverage is central to the task: * **Entity extraction** - pull people, organizations, products, locations, or domain-specific entities (medications, dosages, clauses) out of free text, with character offsets and confidence scores. * **Structured records** - turn "Alice bought apples and Bob bought oranges" into `[{"buyer": "Alice", "item": "apples"}, {"buyer": "Bob", "item": "oranges"}]`, keeping each instance's fields linked. * **Relation and knowledge-graph extraction** - extract typed entity-relation graphs (`works_for`, `located_in`) for agent memory or a knowledge base. * **Span attributes** - tag each extracted entity with an attribute, such as per-person sentiment, in the same pass as extraction. * **Long documents** - process an encoded context of up to 4,096 tokens, with chunking and offset remapping for longer documents. * **Multiple tasks at once** - combine entities, classification, structures, and relations in a single schema-constrained call instead of chaining several model requests. * **Consistent outputs** - use constrained classification or joint entity-relation decoding when labels and relation endpoints must agree. GLiNER2.5 Multi also supports classification. Choose [GLiNER-2.5-Decide](/concepts/gliner-2-5-decide) when the input is English and classification itself—intent, routing, sentiment, priority, moderation, or scoring—is the primary workload. ## How to use GLiNER 2.5 Call the multilingual checkpoint through Fastino's OpenAI-compatible inference endpoint. Put the text in a user message and describe the task in `schema`: ```bash theme={null} curl -X POST "https://api.fastino.ai/v1/chat/completions" \ -H "Authorization: Bearer $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "fastino/gliner2.5-multi-v1", "messages": [ { "role": "user", "content": "Apple CEO Tim Cook unveiled the iPhone 15 Pro in Cupertino." } ], "schema": { "entities": [ { "name": "person", "description": "named individual" }, { "name": "organization", "description": "business or institution name" }, { "name": "product", "description": "named commercial product" }, { "name": "location", "description": "city, region, or place" } ] } }' ``` Add `classifications`, `structures`, or `relations` keys to the same `schema` to run several tasks over the same text in one call. See the [Inference API](/inference/chat-completions) reference for the full request and response contract, including structured records and relation schemas. ## Constrained classification with GLiNER2.5 Multi Use constrained classification when several answers must form one valid decision. Unlike classic `classifications`, which selects each task independently, the constrained decoder searches for a joint assignment that satisfies declared rules. GLiNER2.5 Multi supports three task shapes: | Task shape | Selection rule | Typical use | | - | - | - | | Single answer | Select exactly one permitted answer | Intent, route, or policy verdict | | Multiple answers | Select zero or more answers, optionally with minimum and maximum counts | Topics, effects, or detected harms | | Ordinal | Select exactly one answer from a low-to-high ordered scale | Severity, urgency, or rating | Each task can include answer descriptions, an instruction, and labeled examples. These fields give the encoder context for scoring while keeping output restricted to the declared answers. Constraints connect those task results: | Constraint | Meaning | | - | - | | Implication | Selecting one answer requires another answer or condition | | Exclusion | Two answers cannot both be selected | | Cardinality | Require or limit how many answers a task selects | | Ordinal bound | Require an exact, minimum, maximum, or bounded level | The result contains each task's selected answer, answer probabilities, confidence, and `_meta.feasible`. Constraints can select a lower-probability answer when the independent top choices would violate a rule. They enforce consistency; they do not increase or recalibrate probabilities or confidence. For single-answer and ordinal tasks, confidence is the selected answer's probability. For multiple-answer tasks, it is the geometric mean of each selected answer's probability and each unselected answer's complement (`1 - probability`). An empty multiple-answer result without a default has no confidence value. See the [constrained-classification API example](/inference/chat-completions#constrained-classification-schema) for the complete hosted request, supported schema fields, constraints, and response. > **[Explore GLiNER2.5](https://fastino.ai/models/gliner2-5)** > > Read about the architecture, benchmarks, and use cases. > **[GLiNER-2.5-Decide](/concepts/gliner-2-5-decide)** > > Use the classification-tuned English model for operational decisions. > **[View the model catalog](/concepts/models)** > > Browse Fastino models and their model IDs. > **[Inference API reference](/inference/chat-completions)** > > Full request and response contract, including structured records and relations. # GLiNER 2.5 Decide for schema-defined text classification Source: https://docs.fastino.ai/concepts/gliner-2-5-decide Learn when to use GLiNER 2.5 Decide for fast, schema-defined English text classification. GLiNER 2.5 Decide is Fastino's 340M-parameter, English decision model for schema-defined classification. Supply labels at request time and receive structured answers, probabilities, and confidence without prompting a generative model. > [!NOTE] > > Decide selects from labels declared in your schema. It does not produce explanations, conversations, or open-ended answers. ## Why use GLiNER 2.5 Decide * **Predictable outputs** — the model chooses from labels you define, so downstream code does not parse generated prose. * **Actionable uncertainty** — probabilities and confidence support thresholds, fallback handling, and human review. * **Related judgments in one pass** — classify intent, urgency, route, and handoff from the same input. * **Flexible schemas** — change labels at request time instead of retraining for every taxonomy change. ## When to use it Use GLiNER 2.5 Decide when classification is the primary task: * **Intent and routing** — send messages or requests to the correct workflow. * **Single-label classification** — select exactly one category. * **Multi-label classification** — select every applicable tag. * **Operational gates** — decide whether an agent finished, a human should take over, or content violates a rule. * **Custom taxonomies** — define task-specific labels at request time. * **Several decisions per input** — classify multiple independent aspects of the same text in one request. Classic classification labels are unordered. Listing severity or rating labels from low to high does not create ordinal constraints. Use [GLiNER 2.5 Multi](/concepts/gliner) when extraction, multilingual coverage, or hard relationships between classification tasks are primary. ## Start building > **[Call GLiNER 2.5 Decide](/concepts/gliner-2-5-decide-call)** > > Authenticate and make a first schema-defined classification request. > **[Classification](/concepts/gliner-2-5-decide-schema)** > > Configure tasks and labels, then consume single-label and multi-label results. > **[Evaluation & Train](/concepts/gliner-2-5-decide-thresholds)** > > Evaluate Decide, select thresholds, and train it for your domain. > **[Capabilities](/concepts/gliner-2-5-decide-capabilities)** > > Review language, schema behavior, limits, and unsupported patterns. # Call GLiNER 2.5 Decide Source: https://docs.fastino.ai/concepts/gliner-2-5-decide-call Authenticate and make a first schema-defined classification request with GLiNER 2.5 Decide. Call GLiNER 2.5 Decide through Fastino's OpenAI-compatible Chat Completions endpoint. Put the text to classify in a user message and define the permitted labels in a `classifications` schema. ```text theme={null} POST https://api.fastino.ai/v1/chat/completions ``` ## Set up your API key Create a key in [Fastino Settings](https://agent.fastino.ai/api-keys), then expose it to your process: ```bash macOS/Linux theme={null} export FASTINO_API_KEY="your_api_key_here" ``` ```powershell Windows theme={null} setx FASTINO_API_KEY "your_api_key_here" ``` ## Make a classification request ```bash theme={null} curl -X POST "https://api.fastino.ai/v1/chat/completions" \ -H "Authorization: Bearer $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "fastino/GLiNER-2.5-Decide", "messages": [ { "role": "user", "content": "My subscription renewed after I cancelled it. Please refund the charge." } ], "schema": { "classifications": [ { "task": "intent", "labels": ["refund_request", "cancel_subscription", "login_problem"], "multi_label": false } ] }, "store": false }' ``` Every classification task requires at least one label. With `multi_label: false`, Decide returns the highest-scoring label. ## Read the response A successful response uses the Chat Completions envelope. The classification result is a JSON string inside `choices[0].message.content`: ```json theme={null} { "model": "fastino/GLiNER-2.5-Decide", "choices": [ { "message": { "role": "assistant", "content": "{\"intent\": {\"label\": \"refund_request\", \"confidence\": 0.999862551689148}}" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 13, "completion_tokens": 22, "total_tokens": 35 }, "token_usage": 35 } ``` Parse the message content before reading the task result: ```python theme={null} import json # `body` is the decoded JSON response body. result = json.loads(body["choices"][0]["message"]["content"]) intent = result["intent"]["label"] confidence = result["intent"]["confidence"] ``` ## Next steps > **[Classification](/concepts/gliner-2-5-decide-schema)** > > Add multi-label behavior and multiple tasks, then consume their result shapes. > **[API reference](/api-reference/inference/chat-completions)** > > Inspect the exhaustive `POST /v1/chat/completions` contract. # GLiNER 2.5 Decide Capabilities Source: https://docs.fastino.ai/concepts/gliner-2-5-decide-capabilities Review GLiNER 2.5 Decide language, classification behavior, schema limits, and unsupported patterns. GLiNER 2.5 Decide is a compact, 340M-parameter English model optimized for schema-defined classification. ## Classification capabilities * Define labels at request time without retraining for every taxonomy change. * Run single-label classification when exactly one label should win. * Run multi-label classification when several labels may apply. * Evaluate several independently named classification tasks in one forward pass. * Return a selected label or labels with confidence. * Use `cls_threshold` to control selection in multi-label tasks. * Use a catalog-default classification task when both `schema` and `response_format` are omitted. Common workloads include intent, routing, sentiment, priority, moderation, tags, operational gates, and custom text taxonomies. ## Schema limits * Every task requires at least one label. * `labels` must be an array of strings. * Label-description objects are not supported. * A classification task accepts only `task`, `labels`, `multi_label`, `cls_threshold`, and `top_k`. * `top_k` is accepted but currently has no effect. * `cls_threshold` affects multi-label selection only. * Single-label tasks always return the highest-scoring label. ## Decision limits * Classic classification labels are unordered. Label order does not create an ordinal scale. * Tasks in the same request are independent. * Classic classification does not enforce implications, exclusions, cardinality relationships, or ordinal bounds between tasks. * Decide does not generate explanations, conversations, or open-ended text. Use [GLiNER 2.5 Multi](/concepts/gliner) when extraction, multilingual coverage, label descriptions, or constrained relationships between tasks are primary requirements. Use [GLiDE Score](/concepts/glide-score) when your application needs an explicitly ordered rubric. > **[Classification](/concepts/gliner-2-5-decide-schema)** > > Define labels and tasks, then consume their result shapes. > **[Evaluate and train](/concepts/gliner-2-5-decide-thresholds)** > > Measure quality, tune thresholds, and adapt the model for your domain. # GLiNER 2.5 Decide Classification Source: https://docs.fastino.ai/concepts/gliner-2-5-decide-schema Define Decide classification tasks and consume their single-label, multi-label, and multi-task results. Add a top-level `schema.classifications` array to define one or more classification tasks. Each task accepts exactly these keys: **task** `string` *required* A stable name for the classification task. The same name appears in the parsed result. **labels** `string[]` *required* At least one permitted label. Decide does not accept label-description objects. **multi\_label** `boolean` (default: false) When `false`, return the single highest-scoring label. When `true`, return every label that reaches `cls_threshold`. **cls\_threshold** `number` An inference-time cutoff from `0` to `1` for multi-label tasks. It does not affect training and does not change single-label selection. **top\_k** `integer` Accepted for compatibility, but currently has no effect on GLiNER 2.5 Decide. ## Parse classification results GLiNER 2.5 Decide returns a standard Chat Completions envelope. The classification result is serialized as JSON inside `choices[0].message.content`: ```python theme={null} import json body = response.json() result = json.loads(body["choices"][0]["message"]["content"]) ``` Do not read classification tasks directly from `choices[0]`; parse `message.content` first. ## Single-label classification ```json theme={null} { "classifications": [ { "task": "intent", "labels": ["refund_request", "cancel_subscription", "login_problem"], "multi_label": false } ] } ``` Single-label tasks always return the highest-scoring label: ```json theme={null} { "intent": { "label": "refund_request", "confidence": 0.999862551689148 } } ``` `label` is one of the strings supplied in the task's `labels` array. `confidence` is the model's confidence for the selected label, from `0` to `1`. Labels are unordered; listing `low`, `medium`, and `high` in that order does not create an ordinal scale. ## Multi-label classification ```json theme={null} { "classifications": [ { "task": "tags", "labels": ["technical_issue", "login_problem", "urgent", "human_handoff"], "multi_label": true, "cls_threshold": 0.2 } ] } ``` Multi-label tasks return an array containing each selected label and its confidence: ```json theme={null} { "tags": [ {"label": "technical_issue", "confidence": 0.4421546757221222}, {"label": "login_problem", "confidence": 0.21206879615783691}, {"label": "urgent", "confidence": 0.4834045469760895}, {"label": "human_handoff", "confidence": 0.8267117738723755} ] } ``` Only labels meeting the task's `cls_threshold` are selected. Increase `cls_threshold` to favor precision; decrease it to favor recall. A stricter threshold can produce a shorter array or no selected labels. ## Run multiple tasks in one request ```json theme={null} { "classifications": [ { "task": "intent", "labels": ["refund_request", "cancel_subscription", "login_problem"], "multi_label": false }, { "task": "urgency", "labels": ["low", "normal", "high", "critical"], "multi_label": false } ] } ``` Tasks are scored in one forward pass but remain independent. Classic classification does not enforce implications, exclusions, cardinality rules, or ordinal relationships between tasks. The parsed result is keyed by the `task` names: ```json theme={null} { "intent": { "label": "refund_request", "confidence": 0.99 }, "urgency": { "label": "normal", "confidence": 0.82 } } ``` ## Default schema If you omit both `schema` and `response_format`, Decide uses its catalog-default `intent` task with `book`, `cancel`, `change`, and `status`. The response reports `x_fastino.default_schema_applied: true` when that default is used. ## Common validation mistakes | Invalid input | Use instead | | - | - | | `"labels": {"book": "user wants to book"}` | `"labels": ["book", "cancel"]` | | A `label_descriptions` key | Remove it and keep labels as strings | | A `description` key on a task | Remove it | | `"threshold": 0.5` inside a task | `"cls_threshold": 0.5` with `"multi_label": true` | | An empty `labels` array | Supply at least one label | > **[Evaluate and train](/concepts/gliner-2-5-decide-thresholds)** > > Measure quality, tune thresholds, and adapt the model for your domain. > **[API reference](/api-reference/inference/chat-completions)** > > Inspect the complete Chat Completions response schema. # Evaluate and Train GLiNER 2.5 Decide Source: https://docs.fastino.ai/concepts/gliner-2-5-decide-thresholds Evaluate classification quality, select multi-label thresholds, and fine-tune GLiNER 2.5 Decide for your domain. Evaluate the exact `classifications` schema your application will send to `fastino/GLiNER-2.5-Decide`. Change the labels or task settings only between evaluation runs so results remain comparable. ## Evaluate a Decide schema Start with a fixed task: ```json theme={null} { "task": "support_tags", "labels": ["billing", "technical", "account", "security"], "multi_label": true, "cls_threshold": 0.5 } ``` Build a held-out set with the same label names. Include: * Positive and negative examples for every label * Inputs where several labels should be returned * Inputs where no label should clear the threshold * Ambiguous and out-of-domain text Send every example through `POST /v1/chat/completions` with the same Decide model ID and schema. Parse the JSON string in `choices[0].message.content` before scoring the task result. For single-label Decide tasks, measure top-1 accuracy and per-label confusion. For multi-label tasks, measure precision, recall, and F1 per label and across the task. If one request contains several tasks, evaluate each task independently because Decide does not enforce relationships between them. ## Select `cls_threshold` `cls_threshold` only affects tasks with `multi_label: true`. Decide returns labels that meet the threshold and omits the rest: * Raise it to return fewer labels and generally favor precision. * Lower it to return more labels and generally favor recall. * Single-label tasks always return the highest-scoring label. * Thresholds affect inference only; they do not change training. Rerun the held-out set for every candidate threshold because the response contains only the labels selected at that threshold. Choose a threshold per task when false positives and false negatives have different costs. Do not treat `0.5` as a universal default. For labels that trigger consequential actions, require a stricter threshold or route low-confidence results to review. ## Train GLiNER 2.5 Decide Train only when the base model still misses your domain after you have clarified the label taxonomy and tuned multi-label thresholds. The live base-model catalog currently advertises: ```json theme={null} { "id": "fastino/GLiNER-2.5-Decide", "supports_training": true, "training_types": ["lora"] } ``` Check `GET /v1/base-models?supports_training=true` before creating a job because catalog availability can change. Use `fastino/GLiNER-2.5-Decide` as `base_model` and `lora` as `training_type`. ### Prepare Decide classification data Use the public classification JSONL format. Each line contains `text` and either one `label` or several `labels`: ```jsonl theme={null} {"text":"I was charged twice for the same invoice.","label":"billing"} {"text":"I cannot sign in and suspect my account was compromised.","labels":["account","security"]} ``` The dataset labels must use the same stable strings that you pass in the Decide inference schema. Do not mix single-label and multi-label row shapes in one dataset, and keep the held-out evaluation set out of the training upload. > **[Upload the classification dataset](/concepts/datasets)** > > Create, upload, process, and version the JSONL dataset used by the Decide training job. ### Create the Decide training job Submit the ready dataset against the Decide base model: ```bash theme={null} curl -X POST https://api.fastino.ai/v1/training/jobs \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model_name": "support-decide", "base_model": "fastino/GLiNER-2.5-Decide", "datasets": [{"name": "support-decide-training"}], "training_type": "lora", "validation_data_percentage": 0.2 }' ``` Omit learning rate, batch size, and LoRA parameters unless you have evidence to override the Decide training recipe. Save the returned training-job ID and poll until the artifact is deployable. ### Compare and deploy Run the base model and trained checkpoint against the same held-out set with the same `classifications` schema. Compare: * Per-label errors for single-label tasks * Per-label precision, recall, and F1 for multi-label tasks * Empty and over-selected multi-label results * The threshold required for each task Deploy a checkpoint only when it improves the application-level errors you care about. After deployment, rerun threshold selection; fine-tuning can change Decide confidence values even when predicted labels stay the same. > **[Training jobs](/training)** > > Monitor the Decide job, checkpoints, and deployability status. > **[Training API reference](/api-reference/training/overview)** > > Inspect the exact dataset and training-job contracts. # GLiNER Agent Skill Source: https://docs.fastino.ai/concepts/gliner-agent-skill Install Fastino's hosted GLiNER skill for Cursor, Claude Code, and Codex. The [Fastino GLiNER agent skill](https://docs.fastino.ai/.well-known/agent-skills/fastino-gliner/SKILL.md) helps Cursor, Claude Code, and Codex use Fastino's hosted APIs for extraction, classification, dataset preparation, fine-tuning, evaluation, and inference. ## Install Run this command from your project: ```bash theme={null} npx skills add https://docs.fastino.ai --skill fastino-gliner ``` The installer lets you choose which supported agents receive the skill. Before using the skill, expose your Fastino API key to the agent's environment: ```bash theme={null} export FASTINO_API_KEY="..." ``` Then invoke it explicitly with `/fastino-gliner`, or ask your agent for a hosted GLiNER extraction, classification, fine-tuning, evaluation, or inference workflow. ## Non-interactive installation Use the command for your agent to install the skill into the current project without prompts: ```bash Cursor theme={null} npx skills add https://docs.fastino.ai --skill fastino-gliner -a cursor -y ``` ```bash Claude Code theme={null} npx skills add https://docs.fastino.ai --skill fastino-gliner -a claude-code -y ``` ```bash Codex theme={null} npx skills add https://docs.fastino.ai --skill fastino-gliner -a codex -y ``` ```text Any agent theme={null} "Install the Fastino GLiNER agent skill. Follow the installation instructions in Fastino's documentation at https://docs.fastino.ai/concepts/gliner-agent-skill. Use one installation method appropriate for your agent environment. Then use the Fastino GLiNER skill when working on this project, especially for schema-driven information extraction, entity extraction, classification, and relation extraction" ``` For Cursor, Claude Code, and Codex, the `-a` option selects the target agent and `-y` accepts the installation prompts, making those commands suitable for scripts and CI. > **[View the skill](https://docs.fastino.ai/.well-known/agent-skills/fastino-gliner/SKILL.md)** > > Review the complete instructions before installing. # Model catalog Source: https://docs.fastino.ai/concepts/models Compare models available for inference and training, including model IDs, specifications, pricing, and training workflows. ## Trainable models Call `GET /v1/base-models?supports_training=true` with your API key for the current trainable models and their capabilities. The endpoint is the source of truth for availability. Without a key it lists only encoders, because decoders appear only for teams that can train them. ### Encoders Train these with a managed [`config` job](/api-reference/training-jobs/create) and an uploaded dataset: | Model | Training price | | - | - | | **GLiNER2 Base** `fastino/gliner2-base-v1` | \$0.07 / GPU-minute \$4.20 / GPU-hour | | **GLiNER-2.5-Decide** `fastino/GLiNER-2.5-Decide` | \$0.07 / GPU-minute \$4.20 / GPU-hour | ### Decoders Train these step by step with an application-controlled [`interactive` job](/api-reference/training-jobs/interactive/create-model): Interactive-training context limits are operation-specific capabilities. They can differ from a base model's catalog `context_window` and from an inference endpoint's request limit. | Model | Callable ID | Prefill, not cached / 1M | Prefill, cached / 1M | Sample / 1M | Train / 1M | | - | - | - | - | - | - | | Nemotron 3.5 Super VL | `nvidia/NVIDIA-Nemotron-3.5-Super-VL-120B-A12B-NVFP4` | \$0.16 | \$0.04 | \$0.65 | \$0.65 | | Nemotron 3.5 Lightning | `nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16` | \$0.05 | \$0.01 | \$0.35 | \$0.30 | | Qwen3.6-35B-A3B | `Qwen/Qwen3.6-35B-A3B` | \$0.08 | \$0.01 | \$0.44 | \$0.44 | Nemotron 3.5 Super VL is the product display name; use the callable IDs shown in the table in training requests. Interactive checkpoint storage is \$0.05 per GB-month. A decoder's sampler checkpoint downloads as a standard Hugging Face PEFT adapter for the public base model, so you can load it with `PeftModel.from_pretrained`. See [Load a decoder adapter](/api-reference/training-jobs/download-checkpoint#load-a-decoder-adapter). See the [Training API](/training) to choose a workflow and start a job. ## Inference models Call `GET /v1/base-models?supports_inference=true` for current inference availability and capabilities. ### Nemotron 3.5 Super VL This model ID supports both inference and interactive training. | Model ID | Model | Parameters | Context Window | Input / 1M tokens | Output / 1M tokens | | - | - | - | - | - | - | | `nvidia/NVIDIA-Nemotron-3.5-Super-VL-120B-A12B-NVFP4` | Nemotron 3.5 Super VL | 120B total / 12B active | 262,144 tokens | \$0.08 | \$0.45 | ### GLiDE The limit below is the `/v1/systemone` rendered-prompt limit, not a claim about the underlying model's catalog context window. | Model ID | Model | Parameters | SystemOne rendered-prompt limit | Input / 1M tokens | Output / 1M tokens | | - | - | - | - | - | - | | `fastino/GLiDE` | GLiDE | Not publicly disclosed | 65,536 tokens | \$0.04 | \$0 | ### GLiNER-2.5-Decide | Model ID | Model | Parameters | Context Window | Input / 1M tokens | Output / 1M tokens | | - | - | - | - | - | - | | `fastino/GLiNER-2.5-Decide` | GLiNER-2.5-Decide | 340M | 8,192 tokens | \$0.03 | \$0 | ### GLiNER 2.5 | Model ID | Model | Parameters | Context Window | Input / 1M tokens | Output / 1M tokens | | - | - | - | - | - | - | | `fastino/gliner2.5-base-v1` | GLiNER 2.5 Base | 194M | 4,096 tokens | \$0.03 | \$0 | | `fastino/gliner2.5-multi-v1` | GLiNER 2.5 Multilingual | 287M | 4,096 tokens | \$0.03 | \$0 | ### GLiNER2 | Model ID | Model | Parameters | Context Window | Input / 1M tokens | Output / 1M tokens | | - | - | - | - | - | - | | `fastino/gliner2-base-v1` | GLiNER2 Base | 205M | 8,192 tokens | \$0.03 | \$0 | | `fastino/gliner2-large-v1` | GLiNER2 Large | 340M | 8,192 tokens | \$0.03 | \$0 | | `fastino/gliner2-multi-v1` | GLiNER2 Multilingual | \~205M | 8,192 tokens | \$0.03 | \$0 | | `fastino/gliner2-multi-large-v1` | GLiNER2 Multilingual Large | Not publicly disclosed | 8,192 tokens | \$0.03 | \$0 | ### GLiGuard | Model ID | Model | Parameters | Context Window | Input / 1M tokens | Output / 1M tokens | | - | - | - | - | - | - | | `fastino/gliguard-LLMGuardrails-300M` | GLiGuard LLM Guardrails | 300M | 8,192 tokens | \$0.15 | \$0.15 | ### PII Models | Model ID | Model | Parameters | Context Window | Input / 1M tokens | Output / 1M tokens | | - | - | - | - | - | - | | `fastino/gliner2-privacy-filter-PII-multi` | GLiNER2 Privacy Filter PII | 300M | 8,192 tokens | \$0.03 | \$0 | | `fastino/gliguard-PII-multi` | GLiGuard PII Multilingual | 300M | 8,192 tokens | \$0.15 | \$0.15 | Prices are per 1M tokens. See [Pricing](/pricing) for training rates and credit details. ## API model catalogs > **[Inference models](/api-reference/inference/models)** > **[Trainable models](/api-reference/training/base-models)** # Cookbook: Gate an agent's next move Source: https://docs.fastino.ai/cookbooks/glide-gate-agent-actions Check an agent's proposed action against your policy and decide whether it acts, asks the user first, or keeps looking. An agent about to spend money or change data should check the move against your rules first. Put the goal, the proposed action, and the policy in `state`, then ask GLiDE what the agent should do next. Your code, not the model, carries out the decision. ## Request ```bash theme={null} curl -X POST https://api.fastino.ai/v1/systemone \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "fastino/GLiDE", "state": { "goal": "Book the cheapest flight to Lisbon next Friday", "proposed_action": "Book TAP 1:05 PM for $212. The fare is non-refundable.", "policy": "Confirm with the user before any non-refundable purchase over $100.", "last_user_message": "just get it done, thanks!" }, "questions": { "next_step": { "type": "choice", "instructions": "What should the agent do next?", "criteria": { "confirm": "Check with the user before acting", "book": "Book it now", "search": "Keep searching for other options" } }, "reversible": { "type": "noul", "instructions": "Can the proposed action be undone after it runs?", "criteria": { "true": "It can be undone", "false": "It cannot be undone" } } } }' ``` ## Request schema | Field | Type | In this recipe | | - | - | - | | `model` | string | `fastino/GLiDE`. | | `state.goal` | string | What the user asked the agent to do. | | `state.proposed_action` | string | The exact action the agent is about to take, with the facts that matter (price, refundability). | | `state.policy` | string | The rule that applies. GLiDE weighs it against the user's message. | | `state.last_user_message` | string | What the user said most recently. | | `questions.next_step` | [Choice](/concepts/glide-choice) | One outcome per branch your agent can take. | | `questions.reversible` | [Noul](/concepts/glide-noul) | A second, independent check you can log or combine with `next_step`. | ## Response Measured against `https://api.fastino.ai`. Confidence values vary slightly between calls. ```json theme={null} { "model": "glide_v2", "answers": { "next_step": { "type": "choice", "choice": "confirm", "confidence": 0.934, "probabilities": { "confirm": 0.964, "book": 0.03, "search": 0.005 } }, "reversible": { "type": "noul", "noul": 0.028, "confidence": 0.945 } }, "usage": { "input_tokens": 280, "output_tokens": 0 } } ``` The user said "just get it done", but the policy requires confirmation for a non-refundable purchase over \$100, so GLiDE picks `confirm`. Remove the `policy` line and the same request returns `book`. Put the rule in `state` whenever it should win. ## Response schema | Field | Type | Meaning | | - | - | - | | `answers.next_step.choice` | string | `confirm`, `book`, or `search`. | | `answers.next_step.confidence` | number | How certain GLiDE is, from 0 to 1. | | `answers.next_step.probabilities` | object | Probability for every outcome. | | `answers.reversible.noul` | number | Probability that the action can be undone. Here it is close to 0. | ## Act on the answer ```python theme={null} answers = response.json()["answers"] step = answers["next_step"] reversible = answers["reversible"]["noul"] >= 0.5 if step["choice"] == "book" and step["confidence"] >= 0.8 and reversible: agent.run(proposed_action) elif step["choice"] == "search": agent.keep_searching() else: agent.ask_user(f"Before I go ahead: {proposed_action} OK?") ``` Only the safest path, asking the user, is the fallback. An uncertain or irreversible answer never executes on its own. ## Adapt it * Make each `criteria` key a branch your agent already supports, such as `run`, `ask_user`, `escalate`, or `abort`. * Quote the policy text exactly. GLiDE applies the rule you supply; it does not know your policies otherwise. * Include the facts the policy depends on (amount, recipient, refundability) in `proposed_action`. * Keep the final check in code. For example, never let a spend over a hard limit run, whatever the answer. > [!WARNING] > > Use GLiDE as decision support, not as the only safeguard for irreversible or high-impact actions. Validate on representative cases and keep a human-review path. > **[Policy and safety guide](/guides/glide-policy-safety)** > > Design gates that fail safely on uncertainty. > **[GLiDE API reference](/api-reference/inference/systemone)** > > Every field, limit, and error for `POST /v1/systemone`. # Cookbook: Catch a prompt injection Source: https://docs.fastino.ai/cookbooks/glide-prompt-injection Spot hidden instructions in content your agent reads, before the agent obeys them. Web pages, emails, and documents can hide instructions aimed at your agent, such as a comment telling it to email your customer list somewhere. Screen untrusted content with GLiDE before it reaches the agent's context, and drop or quarantine anything that tries to give orders. ## Request Pass the content and the tools the agent could misuse. Listing the tools helps GLiDE judge how much damage the content could do. ```bash theme={null} curl -X POST https://api.fastino.ai/v1/systemone \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "fastino/GLiDE", "state": { "source": "Web page the agent just fetched", "visible_text": "EU shipping rates: 4.90 EUR standard, 12 EUR express.", "hidden_text": "", "agent_tools": [ "web_search", "send_email" ] }, "questions": { "threat": { "type": "choice", "instructions": "What is this content trying to do?", "criteria": { "injection": "Give the agent new instructions", "phishing": "Trick a person into acting", "safe": "Just information" } }, "risk": { "type": "score", "instructions": "How bad would it be if the agent followed this content?", "criteria": [ "Low: nothing sensitive could happen", "Medium: a minor, reversible mistake", "High: data or money could be affected", "Critical: private data could leave the company" ] }, "exfiltration": { "type": "noul", "instructions": "Does the content try to send data outside the company?", "criteria": { "true": "It tries to send data outside", "false": "It does not try to send data outside" } } } }' ``` ## Request schema | Field | Type | In this recipe | | - | - | - | | `model` | string | `fastino/GLiDE`. | | `state.source` | string | Where the content came from. | | `state.visible_text` | string | What a person would see. | | `state.hidden_text` | string | Markup, comments, or metadata a person would not see. Send it; that is where injections hide. | | `state.agent_tools` | array | Tools the agent can call if it obeys the content. | | `questions.threat` | [Choice](/concepts/glide-choice) | What the content is trying to do. | | `questions.risk` | [Score](/concepts/glide-score) | How bad it would be if the agent followed it, lowest level first. | | `questions.exfiltration` | [Noul](/concepts/glide-noul) | Whether it tries to send data outside the company. | ## Response Measured against `https://api.fastino.ai`. Confidence values vary slightly between calls. ```json theme={null} { "model": "glide_v2", "answers": { "threat": { "type": "choice", "choice": "injection", "confidence": 0.996, "probabilities": { "injection": 0.998, "phishing": 0.001, "safe": 0.002 } }, "risk": { "type": "score", "score": 3, "expected_level": 2.992, "confidence": 0.989, "probabilities": { "0": 0.001, "1": 0.001, "2": 0.005, "3": 0.994 }, "legend": { "0": "Low: nothing sensitive could happen", "1": "Medium: a minor, reversible mistake", "2": "High: data or money could be affected", "3": "Critical: private data could leave the company" } }, "exfiltration": { "type": "noul", "noul": 0.995, "confidence": 0.989 } }, "usage": { "input_tokens": 441, "output_tokens": 0 } } ``` `risk.score` is `3`, the fourth level counted from `0`: "Critical: private data could leave the company". ## Response schema | Field | Type | Meaning | | - | - | - | | `answers.threat.choice` | string | `injection`, `phishing`, or `safe`. | | `answers.risk.score` | integer | Index of the winning risk level, counted from `0`. | | `answers.risk.legend` | object | Your level descriptions, keyed by index. | | `answers.exfiltration.noul` | number | Probability that the content tries to send data out, from 0 to 1. | | `answers.*.confidence` | number | How certain GLiDE is about that answer, from 0 to 1. | ## Act on the answer ```python theme={null} answers = response.json()["answers"] threat = answers["threat"] risk = answers["risk"]["score"] exfiltration = answers["exfiltration"]["noul"] >= 0.5 is_safe = threat["choice"] == "safe" and threat["confidence"] >= 0.9 if is_safe and risk == 0 and not exfiltration: agent.add_to_context(page.visible_text) else: quarantine(page, reason=threat["choice"], risk=risk) agent.add_to_context("[Content removed: it contained instructions for the assistant.]") ``` The bar to pass content through is high on purpose. A false alarm costs one page; a missed injection can leak data. ## Adapt it * Screen every untrusted source: fetched pages, inbound email, uploaded files, and tool results. * Send hidden text as well as visible text. HTML comments, alt text, and white-on-white text are common hiding places. * List the agent's real tools in `state.agent_tools`, so `risk` reflects what the agent could actually do. * Add a `phishing` path if people read the same content, and route it to your security team. > [!WARNING] > > Screening reduces injection risk but does not remove it. Also limit the agent's permissions, and require confirmation before it sends data or money. > **[Policy and safety guide](/guides/glide-policy-safety)** > > Design gates that fail safely on uncertainty. > **[GLiDE API reference](/api-reference/inference/systemone)** > > Every field, limit, and error for `POST /v1/systemone`. # Cookbook: Triage a support ticket Source: https://docs.fastino.ai/cookbooks/glide-support-ticket-triage Route a support ticket to a queue, rate its urgency, and decide whether a person should reply, in one GLiDE call. A new ticket needs three decisions before anyone reads it: which queue owns it, how fast it needs an answer, and whether an automated reply is good enough. GLiDE answers all three from one request, using criteria you write in plain language. ## Request Send the ticket as `state` and ask one question per decision. The question names (`queue`, `urgency`, `needs_human`) are yours; they come back as keys under `answers`. ```bash theme={null} curl -X POST https://api.fastino.ai/v1/systemone \ -H "X-API-Key: $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "fastino/GLiDE", "state": { "subject": "Charged twice this month??", "plan": "Pro, 14 seats", "message": "Our card was billed $1,190 twice on Oct 1. Finance wants it fixed today before they freeze the card. The invoice download button just spins, too." }, "questions": { "queue": { "type": "choice", "instructions": "Which support queue should this ticket go to?", "criteria": { "billing": "Charges, refunds, and invoices", "technical": "Something in the product is broken", "account": "Logins, seats, and permissions" } }, "urgency": { "type": "score", "instructions": "How urgent is this ticket?", "criteria": [ "Low: no deadline or business impact", "Normal: needs an answer within a few days", "High: blocks money or work today", "Urgent: an outage or a security incident" ] }, "needs_human": { "type": "noul", "instructions": "Should a person reply instead of an automated assistant?", "criteria": { "true": "A person should reply", "false": "An automated reply is enough" } } } }' ``` ## Request schema | Field | Type | In this recipe | | - | - | - | | `model` | string | `fastino/GLiDE`. | | `state` | string, object, or array | The ticket. An object keeps the subject, plan, and message clearly labeled. | | `questions.queue` | [Choice](/concepts/glide-choice) | `criteria` is an object. Each key is an outcome and each value says when it applies. | | `questions.urgency` | [Score](/concepts/glide-score) | `criteria` is an ordered array, lowest level first. | | `questions.needs_human` | [Noul](/concepts/glide-noul) | A yes or no question. `criteria` describes the `true` and `false` sides. | | `questions.*.instructions` | non-empty string or object | The question GLiDE answers about `state`; objects are serialized to compact JSON text. | ## Response Measured against `https://api.fastino.ai`. Confidence values vary slightly between calls. ```json theme={null} { "model": "glide_v2", "answers": { "queue": { "type": "choice", "choice": "billing", "confidence": 0.993, "probabilities": { "billing": 0.996, "technical": 0.004, "account": 0.0 } }, "urgency": { "type": "score", "score": 2, "expected_level": 2.001, "confidence": 0.991, "probabilities": { "0": 0.0, "1": 0.002, "2": 0.994, "3": 0.004 }, "legend": { "0": "Low: no deadline or business impact", "1": "Normal: needs an answer within a few days", "2": "High: blocks money or work today", "3": "Urgent: an outage or a security incident" } }, "needs_human": { "type": "noul", "noul": 0.987, "confidence": 0.974 } }, "usage": { "input_tokens": 422, "output_tokens": 0 } } ``` ## Response schema | Field | Type | Meaning | | - | - | - | | `answers.queue.choice` | string | The winning `criteria` key. Here, `billing`. | | `answers.queue.probabilities` | object | Probability for every outcome. They sum to 1. | | `answers.urgency.score` | integer | Index of the winning level, counted from `0`. Here, `2` is "High". | | `answers.urgency.expected_level` | number | Probability-weighted level, for finer thresholds than `score`. | | `answers.urgency.legend` | object | Your level descriptions, keyed by index. | | `answers.needs_human.noul` | number | Probability that the `true` side holds, from 0 to 1. | | `answers.*.confidence` | number | How certain GLiDE is about that answer, from 0 to 1. | | `usage.input_tokens` | integer | Tokens billed for the request. | ## Act on the answer ```python theme={null} import os import requests response = requests.post( "https://api.fastino.ai/v1/systemone", headers={"X-API-Key": os.environ["FASTINO_API_KEY"]}, json=body, # the request body above timeout=300, ) response.raise_for_status() answers = response.json()["answers"] queue = answers["queue"] urgency = answers["urgency"]["score"] needs_human = answers["needs_human"]["noul"] >= 0.5 if queue["confidence"] < 0.7: queue_name = "general" # let a person pick the queue else: queue_name = queue["choice"] priority = {0: "low", 1: "normal", 2: "high", 3: "urgent"}[urgency] assign(ticket, queue=queue_name, priority=priority, auto_reply=not needs_human) ``` Treat the `0.7` and `0.5` thresholds as starting points. Check them against a sample of your own tickets. ## Adapt it * Use your real queue names as `criteria` keys and describe what each queue handles. The descriptions do the work. * Add or remove urgency levels freely. The response always indexes them from `0` in the order you sent them. * Put customer facts GLiDE should weigh, such as plan, contract tier, or open incidents, into `state`. * Ask more questions in the same request, such as `language` or `sentiment`. Each one adds an entry to `answers`. > **[Classification guide](/guides/glide-classification)** > > Design choice questions and handle uncertain labels. > **[GLiDE API reference](/api-reference/inference/systemone)** > > Every field, limit, and error for `POST /v1/systemone`. # Cookbook: Extract entities from multilingual text Source: https://docs.fastino.ai/cookbooks/gliner-entity-extraction Pull people, organizations, places, and dates out of text in any supported language with GLiNER 2.5 Multi. Entity extraction is the most common GLiNER 2.5 Multi workload. You name the labels you want in English, send text in any supported language, and get back each match with its exact character offsets. No training is needed. ## Request The text below is German. The labels stay in English. ```bash theme={null} curl -X POST https://api.fastino.ai/v1/chat/completions \ -H "Authorization: Bearer $FASTINO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "fastino/gliner2.5-multi-v1", "messages": [ { "role": "user", "content": "Dr. María Fernández, Finanzvorständin der Banco Santander, traf sich am 3. März 2026 in München mit Siemens, um den Liefervertrag zu unterzeichnen." } ], "schema": { "entities": [ { "name": "person", "description": "full name of a person" }, { "name": "organization", "description": "company, bank, or institution" }, { "name": "location", "description": "city, region, or country" }, { "name": "date", "description": "calendar date" } ] }, "threshold": 0.5, "store": false }' ``` ## Request schema | Field | Type | In this recipe | | - | - | - | | `model` | string | `fastino/gliner2.5-multi-v1`. | | `messages` | array | One `user` message holding the text to read. | | `schema.entities` | array | One object per label. `name` is the key in the result; `description` tells GLiNER what counts. | | `threshold` | number | Minimum confidence for a match to be returned, from 0 to 1. Default `0.5`. | | `store` | boolean | Defaults to `true`, which saves the inference. `false` opts out. | ## Response GLiNER returns the result as a JSON string in `choices[0].message.content`. Parsed, it looks like this. Measured against `https://api.fastino.ai`; confidence values vary slightly between calls. ```json theme={null} { "entities": { "person": [ { "text": "María Fernández", "confidence": 0.949, "start": 4, "end": 19 } ], "organization": [ { "text": "Banco Santander", "confidence": 0.996, "start": 42, "end": 57 }, { "text": "Siemens", "confidence": 0.992, "start": 100, "end": 107 } ], "location": [ { "text": "München", "confidence": 1.0, "start": 88, "end": 95 } ], "date": [ { "text": "3. März 2026", "confidence": 0.996, "start": 72, "end": 84 } ] } } ``` ## Response schema | Field | Type | Meaning | | - | - | - | | `entities` | object | One key per label you asked for. | | `entities.